Compare commits

...
486 Commits
Author SHA1 Message Date
Myles 030aa887c7 Version bump to 0.8.3-SNAPSHOT #hype 2016-05-17 22:56:52 +01:00
Myles ba624a2b48 1.9.4 backport (#399)
Allow 1.9.4 spigot to handle 1.9, 1.9.1, 1.9.2
2016-05-17 22:48:56 +01:00
Myles e7582cb1ec Change license to be more appropriate, this one is more open and allows much more creativity. 2016-05-11 14:19:30 +01:00
Mats 82bf11fcbc Fix anti-xray for 1.9 (#393)
* Fix anti-xray for 1.9

* Bye NMS.

* Perform

* Add config option
2016-05-10 19:53:37 +01:00
Myles ac6e8b1709 Bump version 2016-05-10 15:03:55 +01:00
Myles 00cc545795 Using javassist add compatibility for Spigot builds with protocol compatibility (eg. 1.9.1 & 1.9.2)
Also fix issue with protocol passthrough
*whew*
2016-05-10 14:37:31 +01:00
Myles c7ee816aba Merge branch 'master' of https://github.com/MylesIsCool/ViaVersion 2016-05-10 10:27:32 +01:00
Myles e7f85e67f6 Change our data structures to use concurrent equivalents, netty is multi-threaded. 2016-05-10 10:26:49 +01:00
Mats d239d2f967 Stop depending the bossbar metadata rewriter on the bukkit api (#391)
* Don't depend the bossbar metadata rewriter on the bukkit api

* Rename field
2016-05-09 17:44:10 +01:00
Myles 63970c6d82 Version bump 2016-05-08 22:45:46 +01:00
Mats 4cffdd4f64 Don't call PlayerInteractEvent twice and fix the gamemode message (#390)
* Experimental feature to fix the 'Your gamemode has been updated to ' message

* Don't fire PlayerInteractEvent twice, fix #326
2016-05-08 19:49:13 +01:00
Mats cb3f0291b7 Well, this feature never worked. (#389) 2016-05-04 20:03:48 +01:00
Mats edaffad045 1.9.3 support 2016-05-04 17:32:38 +02:00
Myles 172f89940a Implement passthroughAll to make it easier for adding things to the end of a packet. 2016-05-03 21:09:48 +01:00
Myles fb4bc397c6 Add fallback to metaindex to living entity. 2016-04-30 20:40:09 +01:00
Myles e595344941 Implement rewriting for villager trade info. 2016-04-29 17:09:24 +01:00
Myles 05dbc53fd0 Add javassist to the libraries for future use. Apologies for the like extra 600kb :( 2016-04-27 21:57:13 +01:00
Mats 0374da573b Check if the player is ported, fix NullPointerException post 876 on spigotmc.org (#374) 2016-04-24 12:29:52 +01:00
Myles 8e64fb8c21 Add magical unknown protocol version, so that if it's not registered it doesn't NPE. 2016-04-23 20:39:16 +01:00
Myles 0f55402171 Version bump 2016-04-22 17:17:40 +01:00
Myles acb7372eb7 Ensure that the player is online. 2016-04-22 13:36:10 +01:00
Myles 057ab050ea Make it so base protocol actually registers its listeners Credit to @jollyolbrits for finding this silly one. 2016-04-22 13:28:54 +01:00
Myles a01997fe53 Typo 2016-04-21 23:12:40 +01:00
Myles e4adbf4a1a Add terorbility build server and remove filip's since it's dead for now. 2016-04-21 22:47:01 +01:00
Myles 261d68c58e Fix blocking shield not going away :P 2016-04-21 21:13:10 +01:00
Myles 38617d1f61 Version bump 2016-04-21 16:20:45 +01:00
Myles cc5bcb8a64 Allow NMS packet receiving 2016-04-21 16:19:29 +01:00
Mats b6794f5597 Cancel swap item, fix #364 (#365)
* Cancel swap item, fix #364

* Remove canceling drop item
2016-04-20 18:31:18 +01:00
Myles 18f77308f5 Bump version to .0.7.8-SNAPSHOT 2016-04-20 15:59:23 +01:00
Myles 6bb473ea8d Change PlayerMovementMapper to a handler and fix the mappings so it works. 2016-04-20 01:33:01 +01:00
Myles 7984f6400c Clean up not used code 2016-04-20 01:25:00 +01:00
Myles 3498d093b0 Thanks @jollyolbrits for debugging, fix the issue with ground not being sent properly for movement.
Fixes anti-cheat issues.
Placement issues.
Probably 100 billion other issues.
Fix me being an idiot and changing numbers.
2016-04-20 01:22:58 +01:00
Myles a3db32758c Add new is feature to PacketWrapper :) 2016-04-20 01:09:39 +01:00
Myles 45952d3759 Move Idle thread. 2016-04-20 00:50:44 +01:00
Myles c552b12696 Merge branch 'master' of https://github.com/MylesIsCool/ViaVersion 2016-04-19 22:53:48 +01:00
Myles 0ae9d9dbbf Fix bossbars so they send correctly, credits to @jollyolbrits for detailed reporting of where the issue may take place. 2016-04-19 22:53:27 +01:00
Mats 8852e3b3a3 Change item from main hand, not offhand. Fixes #329 (#363) 2016-04-19 16:32:03 +01:00
Myles a496b2d3a8 This branch would be better here as it won't be applicable if elsewhere. 2016-04-17 12:59:01 +01:00
Myles 6198dbfe70 Change to match the config 2016-04-17 12:55:34 +01:00
Myles a81d52a54f Implement a packet limiting system,
This means that if a client sends more than a maximum, it will be disconnected.
It also means if a client goes over a threshold multiple times over a period of time, it will be disconnected.

Improvements are welcome, it's mostly down to how the user configures it.
(Some values are higher so that we don't kill every server with a tiny bit of lag)
2016-04-17 12:55:18 +01:00
Myles cf20e8ac5f Bump version 2016-04-17 00:53:49 +01:00
Myles 4f8a248c6b Add item-cache as a less expensive way of getting items. (Will rewrite eventually to not depend on Bukkit) 2016-04-17 00:52:35 +01:00
Mats 57d58db35e Fix item showing twice, one in the new slot (#359) 2016-04-15 18:48:28 +01:00
Mats c214ca02e8 Make commandblocks compatible with all 1.8 spigot/craftbukkit versions, fix #355 (#356) 2016-04-14 12:59:23 +01:00
Myles 6b8b0e1771 Bump version to 0.7.6-SNAPSHOT 2016-04-13 19:42:53 +01:00
Myles e6671513f2 Improve an issue to do with block breaking ghosting back, note this is not a fully fix, but improves the issue quite a bit. 2016-04-13 16:54:18 +01:00
Myles 4c7b50d6fb Fix chunk sending order, Fixes #338, #292 (I believe.) 2016-04-13 15:05:50 +01:00
Mats 1c9229a2fc Don't unload the chunks twice (#350) 2016-04-13 12:25:41 +01:00
Mats d11c18c024 Remove MCProtocolLib (#349) 2016-04-12 12:40:12 +01:00
Mats dc4b5b4d35 Possibility to show the new 1.9 death messages (#348) 2016-04-12 12:01:37 +01:00
Mats 517299d673 Show skeletons' bow like 1.8, not down as 1.9 without target (#347) 2016-04-12 11:18:58 +01:00
Mats a8baa7af50 Transform Combat packet (#346) 2016-04-12 11:18:51 +01:00
Myles a1f847c905 Patch respawn packet to reset bulk / loaded cache. 2016-04-11 20:17:48 +01:00
Mats f3ea43b1eb Reformat / optimize imports (#344) 2016-04-10 18:43:08 +01:00
Mats 551b5d0654 Rewrite effect ids (#342)
* Rewrite effect ids

* Remove test line

* Remove Lombok unused thingy

* No need to check.
2016-04-10 14:29:25 +01:00
Mats 9f39662df6 Check if custom name is visible and if custom name is not empty. Fix …
* Check if custom name is visible and if custom name is not empty. Fix #327

* Fix typo
2016-04-06 13:50:09 +01:00
Myles 7ea2156f37 Bump version 2016-04-05 14:31:40 +01:00
Mats 5032e7d07e Only apply the 'Hologram patch' to small entities since it only happens to them.
Only apply the 'Hologram patch' to small entities (Doesn't fix issue but hey)
2016-04-04 15:55:48 +01:00
Myles c7c6ee9fbc Delay registration of protocols until the plugin has loaded to prevent it being done at the wrong time, #323 #316 Fixed 2016-04-03 23:30:10 +01:00
Mats 4431ca63c2 Fix viaversion list command 2016-04-03 11:26:27 +01:00
Myles 1fa7211cf0 Construct List properly, Fix #314 2016-04-03 01:51:38 +01:00
Myles de576795dc Blame @Matsv 2016-04-02 22:59:40 +01:00
Myles f6286bcc25 Bump version 2016-04-02 22:13:30 +01:00
Myles 8276b212e9 Merge pull request #313 from Matsv/master
Stop allowing everyone to change the instance
2016-04-02 21:32:46 +01:00
Matsv aabd9247a6 Stop allowing everyone to change the instance 2016-04-02 21:45:24 +02:00
Myles 997c2ad6a1 Fix Potions: ThrownPotion is now correct, and the particles are too.
Fixes #223
Also changes a tiny bit of javadoc :)
2016-04-02 14:46:30 +01:00
Myles 233a2ba5df Merge pull request #312 from Matsv/dev
Fix custom NBT for potions / spawneggs
2016-04-02 14:09:00 +01:00
Matsv ed0d5a7cfb Fix NBT for potions 2016-04-02 15:06:10 +02:00
Matsv 87f083460c Fix custom named spawneggs 2016-04-02 15:02:41 +02:00
Myles 2d6dedefb8 Add some packet plugins to loadbefore to ensure it works better with them. 2016-04-02 13:50:21 +01:00
Myles 8adbf36a3a Merge pull request #311 from Matsv/dev
Make command sender messages cleaner
2016-04-02 13:30:10 +01:00
Matsv 8c706b665c Don't format if no args are given 2016-04-02 11:58:15 +02:00
Matsv 2e3677a592 Make command sender messages cleaner 2016-04-02 11:51:17 +02:00
Myles 3602c5087b Don't send a meta data packet when list is empty. #288 2016-04-01 18:13:23 +01:00
Myles 5c84b3d8cc Merge pull request #309 from HugoDaBosss/master
Implement subcommand to reload the config
2016-04-01 16:41:03 +01:00
Hugo Kerstens 7defe7129f Implement subcommand to reload the config 2016-04-01 17:31:44 +02:00
Myles 995dc135b8 Merge pull request #308 from Matsv/boss
Cleanup BossBar class & add new bossbar api method, addPlayers()
2016-04-01 15:07:04 +01:00
Matsv 3f64fb7d5f Cleanup BossBar class & add new bossbar api method, addPlayers() 2016-04-01 16:03:56 +02:00
Myles ac8f7a00ae Merge pull request #305 from HugoDaBosss/master
Implement new protocol version registry
2016-03-31 22:45:39 +01:00
Myles 6893f34289 Support reloading to some extent, if you use protocol lib it will kick all your players... (So you probably should just get a PluginManager...)
One day i'll fully patch to work... (If I don't kick the players it ends up that ProtocolLib implodes and nobody can connect.)
2016-03-31 22:45:15 +01:00
Hugo Kerstens 0a69d62cbe Fixed typo (blame Mats) 2016-03-31 23:26:13 +02:00
Myles 5e0096aa2c Merge pull request #307 from Matsv/master
Woops use the same instance
2016-03-31 21:49:42 +01:00
Matsv 7326205495 Woops use the same instance 2016-03-31 22:48:20 +02:00
Myles a8212db7f2 Merge pull request #306 from Matsv/tabcomplete
Tabcomplete
2016-03-31 19:55:11 +01:00
Matsv 2905d77206 Reformatting moved color to the top ;( 2016-03-31 20:53:03 +02:00
Matsv cb8ec2ce20 Add tab-complete possibility and help subcommand 2016-03-31 20:50:22 +02:00
Hugo Kerstens 09f484f956 Implement new protocol version registry 2016-03-31 19:50:04 +02:00
Myles c48922eb3e Merge pull request #304 from Matsv/cmd
Implement new command API
2016-03-31 17:56:08 +01:00
Matsv b701a0ef67 Change debug mode subcmd description 2016-03-31 18:55:05 +02:00
Matsv eb50f4e907 Merge branch 'master' of https://github.com/Matsv/ViaVersion into cmd 2016-03-31 17:53:12 +02:00
Matsv 6480ea34fc Changed javadoc 2016-03-31 17:52:06 +02:00
Matsv 511941462f Add javadoc 2016-03-31 17:51:30 +02:00
Matsv 34cc783cac Fix missing description, add javadocs, make sure subcommand is valid, check permission 2016-03-31 17:48:15 +02:00
Matsv ecc79b4f49 Command API to keep it clean and make it possible for developers to add their own viaversion subcommands if they want to. 2016-03-31 17:22:42 +02:00
Myles 76f10c463f Merge pull request #301 from Matsv/master
Handle discontinued player item in hand, fixes #299
2016-03-31 15:49:24 +01:00
Matsv 41d5144b57 Handle discontinued player item in hand, fixes #299 2016-03-31 16:28:56 +02:00
Myles de196f2e4f Merge pull request #300 from HugoDaBosss/master
Small optimization in join packet
2016-03-31 14:10:52 +01:00
Hugo Kerstens 0acc2f95fb Remove unneeded code 2016-03-31 15:08:19 +02:00
Myles d16eb9b27e Version bump 2016-03-30 17:46:00 +01:00
Myles 8760b53a0a Fix Disconnect Issue (It's not really harmful but still) 2016-03-30 17:45:24 +01:00
Myles a40182186f Fix debug issue with 1.9.2 2016-03-30 17:34:13 +01:00
Myles ef2b173749 Merge pull request #295 from Matsv/master
Rename 1_9_1 PRE to just 1_9_1
2016-03-30 17:33:15 +01:00
Matsv 75c9284cda Rename 1_9_1 PRE to just 1_9_1 2016-03-30 18:23:52 +02:00
Myles 2abecba7bf Bump version 2016-03-30 16:54:49 +01:00
Myles fb6055cbfe 1.9.2 support (no protocol changes from what I've seen) 2016-03-30 16:51:55 +01:00
Myles 639c9ea8c1 Fix 1.8R0.1 not working, ensure flying packets are sent from right place in pipeline, should fix #273 2016-03-30 16:43:01 +01:00
Myles 1872845d2b Add additional information when packets aren't sent correctly. 2016-03-30 15:58:31 +01:00
Myles 93755c6732 Move patch to update health so it works better and is applied upon login. 2016-03-29 18:22:40 +01:00
Myles 68973fd136 Merge pull request #291 from Matsv/gitter
Add Gitter badge to README.md
2016-03-29 16:08:43 +01:00
Matsv 1a0bd37a01 Add gitter badge to ReadMe 2016-03-29 16:43:42 +02:00
Myles 3551779600 Merge pull request #290 from Matsv/master
Add JavaDocs link to README.md
2016-03-29 15:39:40 +01:00
Matsv b8deddcd2c Add JavaDocs link to README.md 2016-03-29 16:36:21 +02:00
Myles c49bf89ead Merge pull request #289 from Matsv/debug
Show all errors on debug
2016-03-29 15:03:36 +01:00
Myles 4ff4fe2ab2 Merge branch 'master' of https://github.com/MylesIsCool/ViaVersion 2016-03-29 15:02:04 +01:00
Myles 1b99e2cf57 Move EntityNBT to different file and fix the issue to do with respawn chunks unloading. #287 2016-03-29 15:01:38 +01:00
Matsv 55830b0dfb Show all errors on debug 2016-03-29 16:00:56 +02:00
Myles e61f56b2e0 Merge pull request #283 from Matsv/slpfix
Woops the new api broke ServerListPlus custom outdated message again …
2016-03-28 12:04:06 +01:00
Mats 95ea95be13 Woops the new api broke ServerListPlus custom outdated message again fixes #282 2016-03-28 11:52:29 +02:00
Myles d72b7fc4df Fix shields not being configurable 2016-03-27 23:52:57 +01:00
Myles 0992c74351 Improve block placing a bit 2016-03-27 23:40:32 +01:00
Myles 081c23ad8b Small Javadocs 2016-03-27 22:45:25 +01:00
Myles 258f0fc636 Change the README back ;) 2016-03-27 21:50:49 +01:00
Myles c4e3864fc0 Pom pom 2016-03-27 21:46:11 +01:00
Myles 405b6e8047 Merge pull request #280 from HugoDaBosss/apiv2
Make BossBar API easier to use
2016-03-27 21:37:14 +01:00
Hugo Kerstens 9847912128 Make BossBar API easier to use 2016-03-27 21:30:31 +02:00
Myles d89a34cca3 Allow packets to be written to the server using passthrouh ID, shouldn't break anything I also updated comment on why interaction is half broken 2016-03-27 19:13:19 +01:00
Myles 6197138380 Merge pull request #279 from HugoDaBosss/apiv2
Update BossBar API to use protocol version and add protocol version check by uuid API method
2016-03-27 18:31:17 +01:00
Hugo Kerstens f5f4876182 Add check for isPorted because server can be using 1.9 2016-03-27 18:05:04 +01:00
Hugo Kerstens 293c1229ff Update BossBar API to use protocol version and add protocol version by uuid API method 2016-03-27 17:58:31 +01:00
Myles ba60f10744 Match the source for SPIGOT-1.8 2016-03-27 16:37:42 +01:00
Myles c0493de4df Does not fix armour issue completely but improves right click armour items (it's still bugged, working on it) 2016-03-27 14:57:13 +01:00
Myles 46b2f69b01 Fix healing potion :) 2016-03-27 14:06:55 +01:00
Myles f926113c66 Improve paper patch to allow for latency in towering up. 2016-03-27 13:56:06 +01:00
Myles 0e4df51613 Better placement detection 2016-03-26 23:29:09 +00:00
Myles c5f72dc728 Wrong way oops 2016-03-26 22:22:19 +00:00
Myles cee5b1ee42 Improve the patch to check the pipe and to handle above head placement. 2016-03-26 15:55:13 +00:00
Myles f1b9cd2e56 Add PaperSpigot patch to fix block placement (Applies to all protocols for now, until someone finds an issue with this) 2016-03-26 15:28:42 +00:00
Myles 7807e6d9c4 Merge pull request #275 from HugoDaBosss/apiv2
Fix for block place sounds
2016-03-26 14:51:55 +00:00
Hugo Kerstens 4b354f806d Check if user is indeed using 1.9 to 1.8 protocol conversion 2016-03-26 15:38:15 +01:00
Hugo Kerstens 41707ca867 Not needed 2016-03-26 15:22:23 +01:00
Hugo Kerstens 5bca3a97ec Merge remote-tracking branch 'origin/apiv2' into apiv2 2016-03-26 15:18:39 +01:00
Hugo Kerstens 3679aa618f Fix for block place sounds 2016-03-26 15:17:00 +01:00
Myles e9d96f2daf Fix hologram offset. 2016-03-26 14:08:23 +00:00
Myles f371419396 Fix shields not being for the right entity >.> and also print out value for metadata 2016-03-26 13:07:06 +00:00
Myles f32d3211ed Fix issue with Bukkit materials which aren't found by ID 2016-03-26 12:33:22 +00:00
Hugo Kerstens 45f99d4c31 Small fixes and formatting 2016-03-25 23:34:02 +01:00
Myles 71a9c90fe9 Fix team packet 2016-03-25 22:02:25 +00:00
Myles 406500b0bd Fix type conversion not being instant, (causes issue when reading later on)
Introduce packet ID counting (so we can mark something for the next packet etc)
Move USE Item
Add patch to handle placement properly and not break items yay. (Requires a list of special items >.>)
(And lastplaceblock packet index)
2016-03-24 15:45:16 +00:00
Myles 9257298e17 Handle not found metadata properly, and register the player as a type.
Fixes #270
2016-03-23 17:56:02 +00:00
Myles 0376602894 Update TODO list, add pipeline cache 2016-03-23 14:00:48 +00:00
Myles 95ceabb495 Merge fix for duplicated events for placement 2016-03-23 13:41:11 +00:00
Myles 6c8ccb1b1e Don't send place block twice (1.9 will use use_item to handle items), fixes #244 (may fix more) 2016-03-23 13:37:45 +00:00
Myles f351dd03e7 Merge pull request #269 from Matsv/effectapiv2
Reimplementing the effect indicator
2016-03-23 12:43:20 +00:00
Myles c1e77a49b6 Merge branch 'master' into apiv2 2016-03-23 12:40:08 +00:00
Myles 9adf6040fa Optimise ViaIdleThread, use 1 object for all packets. (Quite a big speed up) 2016-03-23 12:35:38 +00:00
Mats 3e320618f9 Merge branch 'apiv2' of https://github.com/MylesIsCool/ViaVersion into apiv2 2016-03-23 13:13:33 +01:00
Myles 6c1de57d32 Merge pull request #268 from Matsv/apiv2
Fix small teampacket bug
2016-03-23 12:12:19 +00:00
Mats 7694d311d1 Reimplement effect indicator 2016-03-23 12:42:03 +01:00
Mats eee1fd941e Fix small teampacket bug 2016-03-23 11:34:13 +01:00
Hugo Kerstens 9c5c181389 Small fixes and formatting 2016-03-23 00:26:38 +01:00
Myles b4b85b1602 Merge pull request #266 from HugoDaBosss/apiv2
Implement new Config API at some more places
2016-03-22 23:23:50 +00:00
Hugo Kerstens f6bb1b48f5 Implement new Config API at some more places 2016-03-22 23:35:01 +01:00
Myles 4ce846a899 Make more errors informative :) 2016-03-22 19:37:15 +00:00
Myles ef08117f34 oops ;) better read the tin better 2016-03-22 19:28:37 +00:00
Myles 4b582a7279 Make PacketWrapper exceptions more informative :) 2016-03-22 19:27:27 +00:00
Myles ad53c1ed7f Merge pull request #265 from HugoDaBosss/apiv2
Optimise SoundEffect searching
2016-03-22 19:25:33 +00:00
Hugo Kerstens 6e46d018a4 Removed import? 2016-03-22 20:18:07 +01:00
Myles 6beacf9804 Merge pull request #264 from HugoDaBosss/apiv2
Removed some debug code
2016-03-22 19:17:28 +00:00
Hugo Kerstens e15c8d7257 Optimise sound searching 2016-03-22 20:16:39 +01:00
Hugo Kerstens 3518804cbf Remove some debug code 2016-03-22 20:11:24 +01:00
Myles 101f86c8cd Merge pull request #263 from HugoDaBosss/apiv2
Fixed spawn experience orb packet
2016-03-22 18:32:42 +00:00
Hugo Kerstens 22c2435656 Fixed spawn experience orb packet 2016-03-22 19:30:24 +01:00
Myles af53275ab9 JavaDoc for quite a lot of the API classes... yay 2016-03-22 18:02:46 +00:00
Myles eccbb567e8 Clean up some code in Base and MetaIndex 2016-03-22 16:56:36 +00:00
Myles bae3599388 Update DEBUG to work in APIv2, also fix a few usages to the config API (may need more) 2016-03-22 16:53:07 +00:00
Myles 88ab4e53a7 Merge pull request #261 from HugoDaBosss/apiv2
Add config option to suppress 'Unable to get entity for ID' errors (apiv2)
2016-03-22 16:48:13 +00:00
Hugo Kerstens 25fa2eabbb Small update for descriptions 2016-03-22 17:22:49 +01:00
Hugo Kerstens e12d8ec466 Add descriptions for the new Config API 2016-03-22 17:17:13 +01:00
Hugo Kerstens a7022bddf8 Small typo 2016-03-22 17:00:13 +01:00
Hugo Kerstens 523c27237d Small changes for the new Config API 2016-03-22 16:55:58 +01:00
Hugo Kerstens 147891f76b Implement config to the API 2016-03-22 16:53:53 +01:00
Myles a5ba52ce05 Rename ChunkHandler
Introduce Packet Filtering
2016-03-22 15:36:11 +00:00
Hugo Kerstens ccb2a4756f Add config option to suppress 'Unable to get entity for ID' errors 2016-03-22 16:27:39 +01:00
Myles f5a96b791d Move listeners to respectful classes to be registered. 2016-03-22 15:03:02 +00:00
Myles c628a8a23f Merge pull request #257 from HugoDaBosss/apiv2
Fix armorstands moving incorrectly when using relative movement packets (apiv2)
2016-03-22 14:38:33 +00:00
Myles 80f63d79ef Merge pull request #258 from HugoDaBosss/master
Fix armorstands moving incorrectly when using relative movement packets
2016-03-22 14:37:40 +00:00
Hugo Kerstens b225afe6ef Fix armorstands moving incorrectly when using relative movement packets 2016-03-22 15:28:00 +01:00
Hugo Kerstens 4e1625b017 Merge pull request #14 from MylesIsCool/master
Update from master
2016-03-22 15:27:12 +01:00
Hugo Kerstens 5c4867365e Fix armorstands moving incorrectly when using relative movement packets 2016-03-22 15:22:21 +01:00
Myles 3549a823cb Don't move when relative 2016-03-22 12:07:43 +00:00
Myles 23a00d2555 Match master 2016-03-21 22:30:05 +00:00
Myles 57931e7231 Patch inventory shield bug 2016-03-21 22:28:11 +00:00
Myles 9e19e0c8af Patch inventory sword bug 2016-03-21 22:24:03 +00:00
Myles 74461609c1 Change to use maps, much better for optimisation. 2016-03-21 19:42:52 +00:00
Myles 7d3e6bc7cb This is why people should read over code :)) 2016-03-21 19:13:55 +00:00
Myles 175606f320 Version bump 2016-03-20 16:40:03 +00:00
Myles b226e94981 Patch the other mem leak fix across 2016-03-19 23:49:26 +00:00
Myles 7d0687aa4a Fix chance of another leak happening... 2016-03-19 23:47:03 +00:00
Myles d152b8b9e1 Merge branch 'master' into apiv2 2016-03-19 22:05:57 +00:00
Myles 1fbd561aec Oops, fix 1.8 clients 2016-03-19 22:04:17 +00:00
Myles a8295c9de0 Merge pull request #254 from Matsv/ifremoveifremoveif
Remove unnecessary if statement, this is always true.
2016-03-19 21:37:04 +00:00
Mats e894a3c733 Remove unnecessary if statement, this is always true. 2016-03-19 21:53:26 +01:00
Myles a2f8f28010 Fix memory leak, add command. Merge from master 2016-03-19 20:51:23 +00:00
Myles 704c876772 One line of code can make holes in the world, one line can fix them. (Fixes packet mem leak, also adds useful secret displayleaks command :) ) 2016-03-19 20:45:07 +00:00
Myles 0233e2ab27 Merge pull request #250 from HugoDaBosss/apiv2
Change protocol constants to final fields
2016-03-19 20:25:32 +00:00
BuildTools 5ae8a35740 Change protocol constants to final fields 2016-03-19 01:11:16 +01:00
Myles ed766eb656 Merge pull request #247 from HugoDaBosss/apiv2
Small optimization for armor searching
2016-03-18 22:04:05 +00:00
Myles b1b35fe025 Bump version 2016-03-18 21:59:13 +00:00
HugoDaBosss 9b6a9fca3d Small optimization for armor searching 2016-03-18 22:57:16 +01:00
Myles 615128eba2 Bongo bongo bongo 2016-03-18 21:25:41 +00:00
Myles 8f3b938e39 Update readme so I don't forget 2016-03-18 21:24:16 +00:00
Myles 625a1d2191 Eventually we should have some sort of handler for this, but this is fine for now 2016-03-18 21:22:09 +00:00
Myles 8a35c0235e Move everything into the right package.
Clean up a lot of code.
Remove PacketUtil (evil laugh)
Add Pipeline Util
Organise listeners, and add protocol pipe checks
2016-03-18 21:18:48 +00:00
Myles 69e8ddcbf6 Update to match master and all current fixes 2016-03-18 20:22:38 +00:00
Myles ce8a504750 Merge from other branch to ensure we don't have to redo some of these patches 2016-03-18 18:25:58 +00:00
Myles 11f3844d63 Use GSON instead, should fix memory leak issue with JSON. Also make sure that we use a copy of players for the bossbar. 2016-03-18 18:14:58 +00:00
Myles 56d5f8eec6 Add protocol registry.
Fix some issues with PacketWrapper
Add 1.9.1 port
Add ProtocolVersion detection on boot
Add more type converters
Implement Pipeline properly
2016-03-17 21:24:25 +00:00
Myles 7a98cdd28f Remove more debug code
Correct casting detector in packet wrapper.
Re-order some packets
Implement Plugin Message Transformers
Implement Sound Transformer
Implement Block Entity Transformer
2016-03-17 13:58:49 +00:00
Mats d40c5851e9 Merge pull request #239 from Matsv/master
Add api method to get player's protocol id
2016-03-17 12:38:51 +01:00
Myles ccda9f11c8 Remove some debug info, make it so StoredObject protects user.
Implement rewriting of Slot in rewriter.
Implement Enchanting Patch
Implement Brewing Patch
Implement Auto-Team Patch
Implement Inventory Tracker
Remove some TODOs
Implement Item Throwing on elytra
(Should just be plugin channels and a few packets + sounds left)
2016-03-16 23:34:03 +00:00
Myles 7e133a0be8 Include UserConnection in StoredObject
Handle Blocking
Handle BossBars, Holograms
2016-03-16 21:52:00 +00:00
Mats d0e573613b Add api method to get player's protocol id, 2016-03-16 21:01:04 +01:00
Myles 2197b938f8 Implement ItemRewritter
Upgrade ViaIdleThread to new system
Add new method to ProtocolPipeline
Implement Use Item
2016-03-16 19:46:16 +00:00
Myles 0d3ba67233 Remove compress / decompress, rethrow errors if they occur from another handler, Fixes #233 2016-03-16 13:42:17 +00:00
Myles 9d57521b29 Bump Version 2016-03-15 21:57:38 +00:00
Myles d98d4ff466 Merge pull request #236 from Matsv/meta11
Discountinue player metadata 11.
2016-03-15 21:06:37 +00:00
Myles 71e27b4799 Merge pull request #232 from Matsv/dropcreative
Throw items when you try to put things in your second hand in creative.
2016-03-15 21:06:04 +00:00
Myles f1354edf20 Merge pull request #231 from Matsv/effect
Make it possible to use the new effect indicators in 1.9
2016-03-15 21:05:55 +00:00
Mats 4d82112286 Discountinue metadata 11. 2016-03-15 21:42:40 +01:00
Mats ba5a44d2d2 Remove debug message 2016-03-15 20:40:26 +01:00
Mats 597ddc7f82 Throw items when you try to put things in your second hand in creative. 2016-03-15 20:37:45 +01:00
Mats 6a7bd209a3 Make it possible to use the new effect indicators in 1.9 2016-03-15 20:20:39 +01:00
Myles 722f28f086 Merge pull request #228 from Matsv/slp
Make compatible with ServerListPlus custom outdated message. Fix #227
2016-03-15 17:51:56 +00:00
Mats daed15d61f Make compatible with ServerListPlus custom outdated message. Fix #227 2016-03-15 14:14:10 +01:00
Myles c300c47a14 Implement Optional UUIDs
Implement Meta Rewriting
Implement Type Converters

Implement System so it can be tested.

Most of it works excluding the missing packets, also fixes some stupid mistakes :)
2016-03-15 00:34:20 +00:00
Myles 89427cb2da PacketWrapper now has an ID attached and can be reset so that it can be read from stored values.
Removed some parameters from protocol, the ID will now be attached to the PacketWrapper (made more sense)
BaseProtocol doesn't handle ProtocolInfo anymore
Implement ProtocolPipeline (WIP)
2016-03-14 18:05:29 +00:00
Myles fce7f1740e Add packet cancelling, implement quite a few of the todo's 2016-03-14 16:51:56 +00:00
Myles 0357d8e6aa Implement Partial Types (Types which require constructing with info), Implement Items, Implement NBT, add exceptions so they go down the tree! 2016-03-14 16:09:50 +00:00
Myles 55335944e3 Update apiv2 to match master 2016-03-14 12:59:15 +00:00
Myles c0b2985343 Just a reminder :) 2016-03-14 12:55:17 +00:00
Myles 91ae5990b1 Almost forgot response handler woops, also allow PacketWrapper to be modifier :) 2016-03-14 12:48:05 +00:00
Myles 33f1a8975c Another quite big update:
Implement Unsigned Short
Implement Most of the Incoming Packets (Still need to implement a few, when I add some sort of packet sending / id changing and packet cancelling)
Implement a base protocol

Still need to do plugin messaging (I will probably forget)
2016-03-14 12:40:23 +00:00
Myles 7cfba0b602 Merge pull request #210 from Matsv/fixarmortjes
Fix #209 woops my fault
2016-03-13 17:02:07 +00:00
Myles 9b28129187 Using PacketType as a checklist, implement most of the base outgoing packets.
Add new REMAINING_BYTES type.
Add an outline of what ItemType will be like
Add a passthrough option to PacketWrapper to make it easy to passthrough and grab the type.
By default passthrough all the bytes :)
2016-03-13 17:01:36 +00:00
Mats 78ab7c840a Fix #209 woops my fault 2016-03-13 16:48:07 +01:00
Myles 669ec3f453 Merge pull request #208 from Matsv/drop
Drop SpaceHQ mcprotocol
2016-03-13 15:17:20 +00:00
Mats dd32b46055 Remove unused imports 2016-03-13 16:13:45 +01:00
Mats 7daa43146e Drop spacehq MC protocol since it's no longer used 2016-03-13 16:12:31 +01:00
Myles 89d5f2cc4f Merge pull request #207 from Matsv/armorattfix
Fix armor not showing on Respawn (With keepinventory true) & world change
2016-03-13 14:30:56 +00:00
Mats 53fb753284 Fix armor not showing on Respawn (With keepinventory true) & world change 2016-03-13 15:22:23 +01:00
Myles 81d89d3839 Rename methods in UserConnection, add new PacketHandler.
Change the protection of some methods to be appropriate.
Actually register packets
Save entity types
2016-03-13 13:40:53 +00:00
Myles 469d81df72 Merge pull request #206 from Matsv/cmdfix
Fix unable to open commandblock after respawn/world change
2016-03-13 13:18:22 +00:00
Mats 7d7f5a0bda Fix unable to open commandblock after respawn/world change 2016-03-13 14:02:10 +01:00
Myles 9954195a8f Merge pull request #205 from Matsv/master
Fix commandblocks not able to change command on update
2016-03-13 12:26:40 +00:00
Mats 62d210de68 Fix commandblocks not able to change command on every-tick commandblock update 2016-03-13 11:06:18 +01:00
Myles e19a2920b9 API: Work towards rewriting metadata, (This is nowhere near finished and I need to work on Item and NBT), Also change the names of a few classes to be more appropriate and implement transformation of the doubles.
(I probably messed up somewhere, nothing is tested as this is essentially API design)
2016-03-12 22:33:43 +00:00
Myles 8d2189cb8e Bump versions 2016-03-12 20:52:46 +00:00
Myles 44a044848f Fix ServerConnection #198 2016-03-12 20:48:04 +00:00
Myles 4f133366e1 Add limitation to NBT data, we'll stick with this for now. I don't see this easily being beaten. 2016-03-12 20:41:04 +00:00
Myles 7c66507960 Merge pull request #200 from lenis0012/chunks
Implement new chunk transformer
2016-03-12 20:27:44 +00:00
Lennart ten Wolde e436988303 transform chunk bulk packets 2016-03-12 15:47:35 +01:00
Lennart ten Wolde 8b65efc4bd Implement new chunk transformer 2016-03-12 13:58:10 +01:00
Myles 7cff20f218 Intitial APIv2, this does not work. Type conversion is not implemented, as well as quite a few things, most things will probably change. 2016-03-11 23:07:13 +00:00
Myles 131517105e Change README 2016-03-11 23:05:47 +00:00
Myles ae2592f3d1 Update to 1.9.1 PRE 2 :) 2016-03-11 16:20:15 +00:00
Myles c009827622 Merge pull request #192 from HugoDaBosss/optimize2
Optimize packet searching
2016-03-11 12:55:15 +00:00
HugoDaBosss afe18379e0 Optimize packet searching 2016-03-11 11:48:42 +01:00
Myles 5ac61fa71d Must of missed this ;) 0.6.3 in desc 2016-03-10 22:52:29 +00:00
HugoDaBosss 3511f9a7b2 Optimized packet searching 2016-03-10 23:13:23 +01:00
Myles e3f7493616 Merge pull request #191 from Matsv/master
Fix Bungeecord "Team viaversion already exists in this scoreboard" and might fix #172
2016-03-10 19:47:43 +00:00
Mats a769599448 Fix Bungeecord "Team viaversion already exists in this scoreboard" and might fix #86 2016-03-10 20:33:32 +01:00
Myles 5df8a1e8e7 Bump version 2016-03-10 16:47:52 +00:00
Myles a3d124b552 Merge pull request #190 from lenis0012/master
Add config wrapper to update config
2016-03-10 16:44:20 +00:00
Lennart ten Wolde 6d95af3963 Add config wrapper to update config
Configuration reads old config and moves it's values over to a new
config copied from the resources directory.

normally, when you save it would delete the comments, but they are
written back in to the new config by this wrapper

now people their config files will actually update
2016-03-10 17:40:40 +01:00
Myles c08a38ff21 Merge pull request #189 from lenis0012/master
fix metadata type mismatch
2016-03-10 16:21:02 +00:00
Lennart ten Wolde 4a804bae7c fix metadata type mismatch & add anti-flicker 2016-03-10 16:52:31 +01:00
Myles fd42c7eba6 Merge pull request #188 from lenis0012/master
fixed default boss title
2016-03-10 14:15:30 +00:00
Lennart ten Wolde 1af86d1354 fixed default boss title 2016-03-10 15:14:27 +01:00
Myles 1b77e1c89f Fix BarAPI, (adds new metaindex, and change colour to be right and remove debug) 2016-03-10 14:07:27 +00:00
Myles c42b9351b8 Remove sync-chunks 2016-03-10 13:25:49 +00:00
Myles ab8c8cd7c8 Merge pull request #187 from lenis0012/chunks
Add chunk handler to netty pipeline. Fixes #48
2016-03-10 13:22:48 +00:00
Myles 83518b92fe Make bossbar patch a configurable option 2016-03-10 13:22:32 +00:00
Myles 1bf1e8981c Merge pull request #186 from lenis0012/master
Add support for 1.8 boss bars. Fixes #41
2016-03-10 13:13:55 +00:00
Lennart ten Wolde b1f076936d Add chunk handler to netty pipeline. FIxes #48 2016-03-10 12:47:09 +01:00
Lennart ten Wolde 319e793cd6 Add support for 1.8 boss bars
Automatically converts legacy boss bars to 1.9 ones using ViaVersions's
boss API.

I suggest you add a config option
Note: also fixed crash on wither/dragon spawn
2016-03-10 03:14:30 +01:00
Myles c9e1360951 Version bump 2016-03-09 21:40:11 +00:00
Myles c11ad7930f Tiny cleanup allow it to be disabled via config and add lenis0012 to contributors <3 2016-03-09 21:30:43 +00:00
Myles 7b36a9de51 Merge pull request #185 from lenis0012/master
Manually perform idle updates. Fixed #160 #99
2016-03-09 21:21:59 +00:00
Lennart ten Wolde d5e9170109 Manually perform idle updates. Fixed #160 #99
Manually performs idle updates by keeping track of the player's
movement.
It compensates for the missing idle packets attempting to get a ratio of
20 movement related packets per second.
2016-03-09 22:17:17 +01:00
Myles 47b447f195 Add the option to use a hologram patch to fix invisible holograms being in wrong place, by default disabled. 2016-03-09 21:08:50 +00:00
Myles e2d27df1a8 Add another build server 2016-03-09 14:37:21 +00:00
Myles 9a781d940f Bump version 2016-03-09 14:29:30 +00:00
Myles fed36c9487 synchronize all the things! 2016-03-09 14:12:50 +00:00
Myles 463327c2a7 Bump version to 0.6.1 snapshot 2016-03-09 12:09:24 +00:00
Myles b0050d4a8d Add config option for blocking and fix crash due to synchronization 2016-03-09 12:08:21 +00:00
Myles a743895c3f Bump version to 0.6.0-SNAPSHOT 2016-03-09 01:13:24 +00:00
Myles f65666b7a6 Better support for ServerConnection detection, and also adding injectors. (Basic late-bind support is now available, but does not work with ProtocolLib due to it injecting first.) 2016-03-09 00:51:50 +00:00
Myles 3a217503fc Merge pull request #179 from HugoDaBosss/master
Stop error fetching hand item spamming console.
2016-03-08 21:24:47 +00:00
Myles c71b75e13b Oops 2016-03-08 21:23:57 +00:00
HugoDaBosss 0c890c3a30 Print errors while in debug mode 2016-03-08 22:23:36 +01:00
HugoDaBosss f38bb0ca22 Stop error fetching hand item spamming console. 2016-03-08 22:20:52 +01:00
Myles 2144fa1837 Handle any exception so it doesn't implode. (Still prints to the console.) 2016-03-08 21:16:34 +00:00
Myles fc4a617da7 Don't send chunk packets with no chunks :) 2016-03-08 21:13:15 +00:00
Myles 126ee6e03f Formatting 2016-03-08 20:54:03 +00:00
Myles 498867032f Merge pull request #178 from HugoDaBosss/master
Fix animation for bows
2016-03-08 20:51:02 +00:00
HugoDaBosss aef8eca790 Fix animation for bows 2016-03-08 21:48:21 +01:00
Myles d8bbb51721 Merge branch 'master' of https://github.com/MylesIsCool/ViaVersion 2016-03-08 19:27:24 +00:00
Myles 6e4fd5a63b Only show blocking if it knows that we're blocking #176 2016-03-08 19:27:04 +00:00
Myles e7bd6245c2 Merge pull request #175 from Matsv/master
Reimplement bossbar methods
2016-03-08 14:02:18 +00:00
Mats 6242cb0b47 Merge remote-tracking branch 'origin/master' 2016-03-08 13:48:20 +01:00
Mats bf5072e1cf Add removed bossbar methods 2016-03-08 13:48:03 +01:00
Mats c24b673550 Add removed bossbar methods 2016-03-08 13:46:30 +01:00
Myles dfc1e1cf51 Merge pull request #174 from Matsv/master
Add /viaversion debug to the commandlist
2016-03-08 12:42:16 +00:00
Mats c600ab6dd1 Add /viaversion debug to the commandlist 2016-03-08 13:30:53 +01:00
Myles 29754c0787 Bump version 2016-03-07 23:53:15 +00:00
Myles 9144980474 Read full dig packet 2016-03-07 23:52:12 +00:00
Myles 6a449f8db1 Allow the suppressing of metadata errors. 2016-03-07 22:55:57 +00:00
Myles 3780210f76 Merge branch 'master' of https://github.com/MylesIsCool/ViaVersion 2016-03-07 22:21:47 +00:00
Myles 67bad0dec8 Add it so when you're on 1.9 you can block using shields. Also change ConnectionInfo to use lombok. 2016-03-07 22:21:32 +00:00
Hugo Kerstens 79291fd7d9 Merge pull request #171 from Matsv/jukeboxfixje
Fix jukebox
2016-03-07 23:10:23 +01:00
Mats ee9d8d6365 Add comment for other people 2016-03-07 23:08:34 +01:00
Mats cc354db464 Formatting 2016-03-07 23:07:17 +01:00
Mats 2b29d27b0d Fix jukebox 2016-03-07 23:04:24 +01:00
Myles 75db62ee6f Merge pull request #167 from rj0495/patch-1
Added fallback options on CommandHandler
2016-03-07 20:53:11 +00:00
Myles 7cd7b5ba24 Be nice and set a user agent for updater 2016-03-07 20:13:01 +00:00
Ryan James a3bfcefdca Added fallback options on CommandHandler 2016-03-07 19:39:10 +00:00
Myles 098b787355 Update to 0.5.8-SNAPSHOT 2016-03-07 19:36:47 +00:00
Myles abb9665813 Merge pull request #166 from StamBoom/master
Change DataInputStream / DataOutputStream to readNBT / writeNBT
2016-03-07 19:30:41 +00:00
Myles 012eec47b5 Temp arrays are evil, (memory optimisation) 2016-03-07 19:19:14 +00:00
Mats 2d40afa3a1 Change DataInputstream / Outputstream to readNBT / writeNBT 2016-03-07 19:58:07 +01:00
Myles a92a7d6e02 Merge pull request #165 from StamBoom/savedthehorses
Fixed horses inventory/elytra exception
2016-03-07 18:52:11 +00:00
Myles fc7cdb4244 Clear bytes instead of reading them, close streams when done. (May fix a few memory leaks) 2016-03-07 18:51:18 +00:00
Mats d5b375b264 Fixed horses inventory/elytra exception 2016-03-07 19:45:00 +01:00
Myles 99eadbe343 Update readme 2016-03-07 16:50:50 +00:00
Myles 38d33dba16 Remove more methods (Sorry last one didn't build!) 2016-03-07 16:44:55 +00:00
Myles b3de4de0cd Remove us.myles.ViaVersion.chunks, I must have looked past this but it's not used. 2016-03-07 16:34:22 +00:00
Myles 6b5c166a22 Merge pull request #162 from phenomax/master
General code improvements
2016-03-07 16:28:04 +00:00
Phenomax 1aea00036f [~] smaller bugfixes]
[~] switched back to jdk 7
2016-03-07 16:22:11 +01:00
Phenomax 1262847a0e [+] added lombok in order to smaller code by removing unnecessary getter, setter and constructors
[~] switched to bytecode version 1.8 (lambda expressions)
[~] general code cleanup (lambda expressions, for each, collapsed catch blocks, diamond maps)
2016-03-07 15:43:31 +01:00
Myles 21cfb1297f Fix powered minecart data 2016-03-07 11:51:51 +00:00
Myles 0b1cb61986 Send team at difficulty to avoid any issues with bungee #161 2016-03-07 11:31:04 +00:00
Myles 44907b3e8d Add /viaversion autoteam to toggle auto teaming for 1.8 colliding. 2016-03-07 11:09:43 +00:00
Myles dac616d72c Bump snapshot version up 2016-03-06 23:42:27 +00:00
Myles 528b234d5a Add collision options, fixes #95. (By default auto teams players until they're added to a team so you can't push!) 2016-03-06 23:22:45 +00:00
HugoDaBosss e4288383f4 Merge pull request #159 from HugoDaBosss/patch
Change package name from bossbarapi to lowercase.
2016-03-06 23:39:52 +01:00
BuildTools bb17eb01b8 Update 2016-03-06 23:17:51 +01:00
Myles ca6638c740 return null if the item is null :) 2016-03-06 21:40:15 +00:00
Myles d8ce66ce29 Merge pull request #158 from StamBoom/bossbar
Implement 1.9 BossBarAPI for developers
2016-03-06 18:35:55 +00:00
Mats 8460c157a5 Commit API 2016-03-06 19:27:26 +01:00
Mats 0b807569ad Implement 1.9 BossBarAPI for developers 2016-03-06 19:20:39 +01:00
Myles 75d001d09b Merge pull request #157 from rj0495/patch-3
Travis Build Status
2016-03-06 17:37:37 +00:00
Ryan James 2118379cf7 Travis Build Status 2016-03-06 17:35:54 +00:00
Myles cd2441ee52 Update README.md 2016-03-06 17:22:56 +00:00
Myles ffb4fb5c5a Merge pull request #155 from sgdc3/master
Improve POM and fix dead code
2016-03-06 16:48:41 +00:00
Myles c404f2206c Blame a class when the childHandler doesn't inject 2016-03-06 16:16:26 +00:00
Gabriele C aec5aa48da Bump 2016-03-06 16:38:58 +01:00
Gabriele C b63051a796 Improve POM and fix dead code 2016-03-06 16:36:54 +01:00
Myles ea4650000e Bump to 0.5.5 2016-03-06 15:16:36 +00:00
Myles 2d2018b8d0 Disable latest feature due to it breaking signs (no more sync chunks for now) 2016-03-06 15:10:54 +00:00
HugoDaBosss 736a853a85 Merge pull request #153 from HugoDaBosss/patch
Make Metadata Rewriter exception output more clear
2016-03-06 16:00:50 +01:00
HugoDaBosss dfd4c5f93e Formatting 2016-03-06 15:55:53 +01:00
HugoDaBosss 2ac87acc8a Make Metadata Rewriter exception output more clear 2016-03-06 15:52:06 +01:00
Myles 3c5a6a3b7b Fix README, also change a bit of the fixJson so that it can handle quotes on signs. 2016-03-06 14:40:23 +00:00
Myles 6efb5c1b64 Merge pull request #151 from HugoDaBosss/patch
Fix checkforupdates changing from false to true
2016-03-06 14:20:45 +00:00
HugoDaBosss 91de7e5a22 Fix checkforupdates changing from false to true
FIXED:
When starting the server when checkforupdates is false, it won't register the listener.
So when you enable checkforupdates using /viaversion dontbugme it won't send you messages until a restart.
2016-03-06 15:11:36 +01:00
Myles 1c42ae1ee8 Update version to 0.5.4 2016-03-06 13:52:38 +00:00
Myles c5ac3c9b3d Don't freeze current thread when sending chunks 2016-03-06 13:49:33 +00:00
Myles 0ea32b3318 Merge pull request #150 from HugoDaBosss/patch
Fix mob spawners when no EntityId is given
2016-03-06 13:45:56 +00:00
Myles 8afc850ed3 Add new config option "sync-chunks", chunks will now be sent in sync with the MC thread when true, this fixes timings (paper spigot mostly issue) 2016-03-06 13:45:26 +00:00
HugoDaBosss 3c6dcfe5bf Update OutgoingTransformer.java 2016-03-06 14:42:50 +01:00
HugoDaBosss 59d637e0f5 More formatting (stupid eclipse) 2016-03-06 14:42:22 +01:00
HugoDaBosss 923f3088c0 Formatting 2016-03-06 14:40:52 +01:00
HugoDaBosss 4f8aff9c01 Forgot to remove debug message 2016-03-06 14:37:51 +01:00
HugoDaBosss 99ceb9ae79 Fix mob spawners when no EntityId is given 2016-03-06 14:32:57 +01:00
Myles 6e0554f4a4 Fix enchanting tooltips 2016-03-06 13:22:56 +00:00
Myles 36879f8d02 Fix small issue with updater 2016-03-06 13:02:54 +00:00
Myles fe77df1434 Fix brewing #141 2016-03-06 12:25:54 +00:00
Myles 713361f973 Merge pull request #148 from StamBoom/master
Fix commandblock minecarts
2016-03-06 11:20:50 +00:00
Mats a314b86f57 Fix commandblock minecarts 2016-03-06 12:18:18 +01:00
Myles 840c90f871 Don't use GSON >.> 2016-03-06 11:03:41 +00:00
Myles 2a247595c8 Handle invalid version numbers 2016-03-06 10:49:21 +00:00
Myles 4124c3454e Change it so when there is no connection we don't bug them. Also change it to use http instead of https, as https requires certain certificate info by linux. 2016-03-06 10:46:38 +00:00
HugoDaBosss c4185e3056 Merge pull request #147 from fillefilip8/patch-4
Made the config use the default bukkit config methods insteed.
2016-03-06 10:56:07 +01:00
fillefilip8 d6403d495d Opps :) Github likes me :D Removed the new api methods from this branch :D 2016-03-06 10:42:26 +01:00
fillefilip8 d7f54048ff Made the config use the default bukkit config methods insteed. 2016-03-06 10:39:58 +01:00
Myles e487eeb395 Update to 0.5.3, add inventory title tracking so we're working towards some of the inventory bugs with new ones. 2016-03-06 00:25:24 +00:00
Myles 0d0e1c16ea Fix issue with formatting :) (fixes quotes) 2016-03-05 23:24:23 +00:00
Myles f462ff9e8a Fix weird closedchannel bug 2016-03-05 22:16:43 +00:00
Myles 5582556d8a Fix issue with biomes on chunks, #125 2016-03-05 22:05:17 +00:00
Myles ef6214a442 Fix getHandItem across reloads, though half the things will still break on reload :( 2016-03-05 21:23:14 +00:00
Myles 369710333c Change updating so it doesn't tell you on current version up to date but warns if you're on a newer version than expected / older one in console. 2016-03-05 21:15:51 +00:00
Myles 30c4fea044 Add new /viaversion dontbugme, change method if the version looks like it's custom / debug (not compiled by maven) 2016-03-05 20:54:35 +00:00
Myles eccc5091b5 Merge pull request #139 from HugoDaBosss/master
Added proper update message (based on checkplys)
2016-03-05 20:40:48 +00:00
HugoDaBosss 65770d7c5b Added proper update message 2016-03-05 21:37:12 +01:00
Myles 715e873bae Bump version to 0.5.2 2016-03-05 20:21:21 +00:00
Myles eced599818 Merge pull request #138 from StamBoom/master
Fix commandblocks
2016-03-05 20:06:54 +00:00
Mats 6db7755633 Fix commandblocks 2016-03-05 20:36:06 +01:00
Myles 653c3d3984 Merge pull request #131 from StamBoom/patch
Fix book formatting and invalid book tag at empty book
2016-03-05 19:18:39 +00:00
HugoDaBosss 5ca841837d Added BungeeCord to the Issue Template 2016-03-05 20:04:16 +01:00
HugoDaBosss 554e037044 Merge pull request #133 from fillefilip8/patch-2
Fixed some maven warnings.
2016-03-05 19:48:26 +01:00
fillefilip8 457d7e4777 Fixed some maven warnings. 2016-03-05 14:37:01 +01:00
Mats b3dc465498 Remove debug message 2016-03-05 11:35:32 +01:00
Mats c56109a64c Fix book formatting and invalid book tag at empty book 2016-03-05 11:30:17 +01:00
Myles d5e720fe09 Merge pull request #130 from HugoDaBosss/patch-8
Fix spawners showing the correct mob
2016-03-05 00:28:24 +00:00
HugoDaBosss a42526bb88 Small formatting 2016-03-05 01:24:15 +01:00
HugoDaBosss bd5f44b477 Fixed spawners showing the correct mob 2016-03-05 01:21:37 +01:00
Myles d5d8881677 Add debug to show metadata ID on error 2016-03-04 23:30:37 +00:00
Myles ac2178a247 Add debug mode so we can analyse packets 2016-03-04 23:10:07 +00:00
Myles 24fa8aec35 Removed channel closed exception 2016-03-04 23:07:22 +00:00
Myles 2ba92a0d47 Merge pull request #126 from HugoDaBosss/herobrine
Removed Herobrine.
2016-03-04 23:03:45 +00:00
HugoDaBosss ace178834e Removed Herobrine. 2016-03-05 00:00:50 +01:00
HugoDaBosss 9c88d0a37f Merge pull request #10 from MylesIsCool/master
Update from master
2016-03-04 23:54:38 +01:00
Myles bafc1b6799 Merge pull request #122 from HugoDaBosss/patch-7
Fixed double flint and steel sound and added support to ignore sounds in 1.9
2016-03-04 22:29:39 +00:00
HugoDaBosss c9a575f45d Merge pull request #9 from MylesIsCool/master
Update Version I accidentally deployed debug version - 0.5.1
2016-03-04 23:23:44 +01:00
HugoDaBosss c071c895e7 Fixed double flint and steel sound and added support to ignore sounds in
1.9
2016-03-04 22:58:40 +01:00
Myles a8799bd493 Update Version I accidentally deployed debug version - 0.5.1 2016-03-04 21:51:56 +00:00
HugoDaBosss 20d4a94792 Merge pull request #8 from MylesIsCool/master
Update from master
2016-03-04 22:33:12 +01:00
Myles 89e0948f97 Updated version to 0.5.0 :) 2016-03-04 21:21:51 +00:00
Myles 6fe3c15f7d Remove 1.9 chunk unloading, should fix #38 2016-03-04 21:16:12 +00:00
Myles fb5dace6a6 Add armour, based on HugoDaBoss code but modified to work correctly with shift click. Also fix small issue from last commit. 2016-03-04 20:03:46 +00:00
Myles f71e51c85e Add packet sending to API 2016-03-04 19:24:44 +00:00
HugoDaBosss 0dd530a593 Merge pull request #7 from MylesIsCool/master
Update from master
2016-03-04 14:43:10 +01:00
Myles 12df86a142 As per wiki.vg only unload if bitmask = 0 and full chunk (not sure if this fixes chunk issue) 2016-03-04 10:09:06 +00:00
Myles 963f021226 Fix books, also makes ItemSlotRewriter.ItemStack fields public 2016-03-04 10:04:50 +00:00
Myles cb4a8b24d4 Merge pull request #113 from fillefilip8/patch-1
Some README.md fixes.
2016-03-04 09:10:05 +00:00
fillefilip8 76c908b132 Update README.md 2016-03-04 10:05:44 +01:00
Myles 89311af76a Small issue with README 2016-03-04 09:05:05 +00:00
fillefilip8 1ecf515006 Fixed README formatting. 2016-03-04 09:58:31 +01:00
Myles 5c18028577 Bump version to 0.4.9 2016-03-04 08:14:26 +00:00
Myles 678a7de664 Correct README 2016-03-04 01:02:35 +00:00
Myles 0aa190353e Add potions, including splash. 2016-03-04 01:01:04 +00:00
Myles a42b113618 Use new JSONParsers or they all implode. 2016-03-03 23:40:09 +00:00
Myles 2704611977 Cancel sounds properly, fixes block placing issue on bungee. Updated version to 0.4.8 2016-03-03 22:48:17 +00:00
Myles be6245e693 Bump version 0.4.7 2016-03-03 22:46:17 +00:00
Myles d7b7c4916a Read any remaining bytes, not sure if this fixes any errors but we ideally should to prevent issues. 2016-03-03 22:01:49 +00:00
Myles caae4e4cca Merge pull request #108 from gigosaurus/patch-2
Fix some MalformedJsonExceptions
2016-03-03 21:33:57 +00:00
gigosaurus ee58fbedbe Fix some MalformedJsonExceptions
This should fix the last possible cause of issue #70
2016-03-03 21:28:40 +00:00
Myles a84b45f5dd Add new contributor, make format of output match spigot 2016-03-03 21:15:20 +00:00
Myles c2edf45846 Change package for slot rewriter. 2016-03-03 21:06:36 +00:00
Myles 88ff4ee9ca Merge pull request #96 from Mystalion/spawnegg-and-potions
support for rewriting SpawnEggs
2016-03-03 21:03:50 +00:00
Paulomart fd704f6a29 Merge remote-tracking branch 'origin/spawnegg-and-potions'
Conflicts:
	src/main/java/us/myles/ViaVersion/transformers/OutgoingTransformer.java
	src/main/java/us/myles/ViaVersion/util/PacketUtil.java
2016-03-03 21:38:16 +01:00
Paulomart c97b443cf2 I dont even Java. 2016-03-03 21:32:01 +01:00
Paulomart 00df80e6fd Replace nms code with fancy library and own code. 2016-03-03 21:31:56 +01:00
Paulomart 64c2ba243f Basic support for rewriting SpawnEggs and Potions, still needs more work 2016-03-03 21:31:50 +01:00
Myles 0ad2e6478d Merge pull request #103 from StamBoom/master
Fix skin overlay
2016-03-03 19:56:55 +00:00
Myles ab9f786999 Don't send a signed byte for digging. 2016-03-03 19:56:00 +00:00
Mats e826b339f6 Fixed missing Player metadata 2016-03-03 20:49:29 +01:00
Mats f06851f57a Fix skin overlay 2016-03-03 20:37:46 +01:00
Myles 1a90f0eb28 Use new method for finding cause, might need updating with disconnect. Can't replicate disconnect spam on any version on my machine. Also move to JSON for all because older versions don't have GSON :( in main package 2016-03-03 19:24:37 +00:00
Myles fee986d215 Make the injectors work in any 1.8 version. Now looks through fields for suitable in case of different field names also construct slot using known arguments. 2016-03-03 18:12:10 +00:00
fillefilip8 9108e78491 Added more yml info and remove author name from the message in the command. 2016-03-03 18:30:13 +01:00
Myles 1b75526892 Implement changes to entity effect 2016-03-03 18:30:00 +01:00
fillefilip8 5930a83765 Added a command and a new API function "getVersion()" 2016-03-03 18:29:59 +01:00
fillefilip8 ef118a3a64 * One JavaDoc to the api XD
* Added faster way to change version number.
2016-03-03 17:33:47 +01:00
fillefilip8 bb42cda4a8 . 2016-03-03 17:33:28 +01:00
fillefilip8 121bc9de6c * Modifyed that fancy message when 1.9 clients try to enter a Minecart or a Boat :)
* Renamed the listener to something better.
2016-03-03 17:33:27 +01:00
fillefilip8 1e873c123c Added that fancy message when 1.9 clients try to enter a Minecart :) 2016-03-03 17:33:27 +01:00
Myles c704b3709a Implement changes to entity effect 2016-03-03 15:17:31 +00:00
HugoDaBosss 618e09b202 Merge pull request #6 from MylesIsCool/master
Update from master
2016-03-03 14:13:41 +01:00
Myles fd0bd53826 Bump version to 0.4.6 2016-03-03 13:07:57 +00:00
Myles e11c8320f0 Merge pull request #83 from StamBoom/master
Fix unmount
2016-03-03 12:56:54 +00:00
Myles 624595e9f6 Merge pull request #84 from HugoDaBosss/patch-4
Fix animals appearing as babies instead of parents
2016-03-03 12:56:37 +00:00
HugoDaBosss cc813545d8 Formatting 2016-03-03 12:22:54 +01:00
HugoDaBosss e1ba6e07c2 Fix animals appearing as babies instead of parent 2016-03-03 12:20:19 +01:00
Mats 1bf49b1f0b Fix unmount 2016-03-03 12:18:23 +01:00
HugoDaBosss 5e34fda7e4 Merge pull request #4 from MylesIsCool/master
Merge from master
2016-03-03 12:17:06 +01:00
Myles aa70ab8b78 Extra line 2016-03-03 10:37:43 +00:00
Myles 186ba22dc8 Update README with chat, and change issue template 2016-03-03 10:37:10 +00:00
Myles b10aa30d9b Change error correction to use super, should restore default functionality to errors. 2016-03-03 10:24:01 +00:00
Myles 615b9f847c Merge pull request #77 from HugoDaBosss/patch-2
Don't send malformed JSON anymore, preventing kicks.
2016-03-03 10:04:54 +00:00
Myles 8f132fed14 Merge pull request #64 from HugoDaBosss/master
Fixed double placing sound and small packet finding optimization. (I suck at github)
2016-03-03 10:04:33 +00:00
HugoDaBosss 854e24f8fc More formatting 2016-03-03 10:47:22 +01:00
HugoDaBosss ff0544f29a Eclipse is changing my bracket markup x.x 2016-03-03 10:46:38 +01:00
HugoDaBosss 72ae12bc77 Don't send malformed JSON anymore, preventing kicks. 2016-03-03 10:44:57 +01:00
HugoDaBosss 29d2334ef0 Fixed bracket markup ;) 2016-03-03 10:09:38 +01:00
HugoDaBosss afb96c4878 Fixed double break sound 2016-03-03 10:06:24 +01:00
HugoDaBosss e4346611c9 Small optimization 2016-03-03 01:40:24 +01:00
BuildTools f15e11272a Merge branch 'master' of https://github.com/HugoDaBosss/ViaVersion 2016-03-03 01:37:25 +01:00
HugoDaBosss 8764d24a16 Merge pull request #3 from MylesIsCool/master
Update from Fork
2016-03-03 01:37:25 +01:00
Myles 86d543d700 Add new contributor, update version to 0.4.5 :) 2016-03-03 00:13:53 +00:00
Myles 99fd01c359 Merge pull request #63 from gigosaurus/patch-1
Fix player entity meta data
2016-03-03 00:12:03 +00:00
gigosaurus 573dcc10b1 Fix player entity meta data
I'm not 100% confident that what I'm doing here is correct, but looking at http://wiki.vg/Pre-release_protocol#Spawn_Player I think I'm doing it right.

fixes #58
2016-03-03 00:06:13 +00:00
Myles 3e30d989a0 Print out stack traces instead of throwing them move. 2016-03-02 23:20:57 +00:00
Myles fc00dd2b38 Merge pull request #56 from gigosaurus/master
Fix PLAY_USE_BED's old ID
2016-03-02 23:08:57 +00:00
gigosaurus 2e9987373d Fix PLAY_USE_BED's old ID 2016-03-02 22:16:58 +00:00
HugoDaBosss b6c2a46a86 Merge pull request #2 from MylesIsCool/master
Update From Original #2
2016-03-02 11:44:24 +01:00
154 changed files with 11146 additions and 2966 deletions

No files matched your search

+115 -2
View File
@@ -1,3 +1,116 @@
target/
.idea/
### Java files ###
*.class
# Package Files
#*.jar
*.war
*.ear
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
# Ignore project files
*.iml
# Ignore IDEA directory
.idea/*
# Include the project's code style settings file
!.idea/codeStyleSettings.xml
# Include the project's dictionary
!.idea/dictionaries/
!.idea/dictionaries/*
# File-based project format:
*.ipr
*.iws
### Plugin-specific files: ###
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
### Eclipse ###
*.pydevproject
.metadata
.gradle
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
# Eclipse Core
.project
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# JDT-specific (Eclipse Java Development Tools)
.classpath
# PDT-specific
.buildpath
# sbteclipse plugin
.target
# TeXlipse plugin
.texlipse
### Maven ###
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
### NetBeans ###
nbproject/private/
build/
nbbuild/
dist/
nbdist/
nbactions.xml
nb-configuration.xml
.nb-gradle/
### Git ###
# Don't exclude the .gitignore itself
!.gitignore
+12
View File
@@ -0,0 +1,12 @@
sudo: false
language: java
jdk: oraclejdk7
cache:
directories:
- '$HOME/.m2/repository'
script:
- mvn dependency:purge-local-repository -DactTransitively=false -DreResolve=false
- mvn clean install -B -U
+12
View File
@@ -0,0 +1,12 @@
### What version of ViaVersion are you using? Type /ver viaversion
### What version of Spigot are you using? Type /ver
### What plugins are you using? Type /plugins
### Are you using any additional software like BungeeCord? If so, what software and version? (Please list your plugins as well)
### How does this error happen? login? Using an item?
### Is there an error in the console? Use pastebin.com. Is there a kick message?
+24
View File
@@ -0,0 +1,24 @@
License:
--------
MIT License
Copyright (c) 2016
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+39 -15
View File
@@ -1,20 +1,16 @@
# ViaVersion 0.4.4
**Allows the connection of 1.8 clients to 1.9**
# ViaVersion 0.8.2
[![Build Status](https://travis-ci.org/MylesIsCool/ViaVersion.svg?branch=master)](https://travis-ci.org/MylesIsCool/ViaVersion)
[![Gitter](https://badges.gitter.im/MylesIsCool/ViaVersion.svg)](https://gitter.im/MylesIsCool/ViaVersion)
**Allows the connection of 1.9 clients to 1.8**
This plugin modifies netty to allow connection of 1.9 clients to 1.8,
**Don't use late bind*
###*Don't use late bind*
**As of this point it doesn't have everything, I need to fix:**
This took 100s hours of work, so if you enjoy this consider looking into contacting me and supporting my projects.
Attempt to make boats nicer when they don't work
Remap spawn eggs
If you have a bug with entities, please report the full stack trace
This took hours of work, so if you enjoy this consider looking into contacting me and supporting my projects.
**Contributor Chat:** https://gitter.im/MylesIsCool/ViaVersion
Sources:
@@ -22,7 +18,9 @@ Sources:
**wiki.vg** (Protocol info, though I did have to find a lot myself)
**MCProtocolLib** (used for chunk reading & some of writing.)
**OpenNBT** (used for slot rewriting)
Contributors:
--------
@@ -37,10 +35,36 @@ Contributors:
**Paulomart**
**gigosaurus**
**fillefilip8**
**lenis0012**
Releases / Dev Builds:
--------
You can find official releases here:
https://www.spigotmc.org/resources/viaversion.19254/history
----------
You can find unofficial dev builds here:
**Terrobility's Build Server:** https://ci.terrocidepvp.net/job/ViaVersion/
**sgdc3's Build Server:** http://ci.xephi.fr/job/ViaVersion/
**sgdc3's Maven:** http://ci.xephi.fr/plugin/repository/everything/
**JavaDocs:** https://jd.matsv.nl/
License:
--------
You may modify this work, all rights are still owned by myself excluding any files in the spacebase package as they belong to the respected contributors. Please credit the original author (myself) when forking etc. (or if it helped you understand the new protocol or netty!)
MIT License, see LICENSE for more details.
Thanks!
Thanks!
+11
View File
@@ -0,0 +1,11 @@
machine:
java:
version: oraclejdk7
general:
artifacts:
- "target/*.jar"
test:
override:
- mvn clean install -B
post:
- cp ./target/*.jar $CIRCLE_ARTIFACTS
+176 -22
View File
@@ -1,54 +1,208 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
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>us.myles</groupId>
<artifactId>ViaVersion</artifactId>
<version>1.0-SNAPSHOT</version>
<artifactId>viaversion</artifactId>
<version>0.8.3-SNAPSHOT</version>
<packaging>jar</packaging>
<name>ViaVersion</name>
<description>Allow 1.8 clients to join 1.9 bukkit servers!</description>
<inceptionYear>2016</inceptionYear>
<url>https://www.spigotmc.org/resources/viaversion.19254/</url>
<prerequisites>
<maven>3.3.3</maven>
</prerequisites>
<properties>
<!-- Project Properties -->
<projectEncoding>UTF-8</projectEncoding>
<project.build.sourceEncoding>${projectEncoding}</project.build.sourceEncoding>
<project.build.outputEncoding>${projectEncoding}</project.build.outputEncoding>
<jdkVersion>1.7</jdkVersion>
<!-- <testJreVersion>1.7</testJreVersion> -->
<!-- Change Bukkit Version HERE! -->
<bukkitVersion>1.8.8-R0.1-SNAPSHOT</bukkitVersion>
</properties>
<build>
<finalName>${project.name}-${project.version}</finalName>
<sourceDirectory>src/main/java</sourceDirectory>
<!-- <testSourceDirectory>src/test/java</testSourceDirectory> -->
<resources>
<resource>
<targetPath>.</targetPath>
<filtering>false</filtering>
<directory>.</directory>
<includes>
<include>LICENSE</include>
</includes>
</resource>
<resource>
<targetPath>.</targetPath>
<filtering>true</filtering>
<directory>src/main/resources/</directory>
<includes>
<include>*</include>
</includes>
</resource>
</resources>
<!--
<testResources>
<testResource>
<directory>src/test/resources</directory>
</testResource>
</testResources>
-->
<plugins>
<!-- Maven Java Compiler -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<source>${jdkVersion}</source>
<target>${jdkVersion}</target>
<!--
<testSource>${testJreVersion}</testSource>
<testTarget>${testJreVersion}</testTarget>
-->
</configuration>
</plugin>
<!-- Unit Test Plugin
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<argLine>-Dfile.encoding=${projectEncoding} ${argLine}</argLine>
</configuration>
</plugin>
-->
<!-- Libs Shading and Relocation -->
<plugin>
<!--Relocate all lib we use in order to fix class loading errors if we use different versions
than already loaded libs (i.e. by Mojang -> gson)-->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<minimizeJar>false</minimizeJar>
<relocations>
<relocation>
<pattern>org.spacehq.opennbt</pattern>
<shadedPattern>us.myles.viaversion.libs.opennbt</shadedPattern>
</relocation>
<relocation>
<pattern>com.google.gson</pattern>
<shadedPattern>us.myles.viaversion.libs.gson</shadedPattern>
</relocation>
<relocation>
<pattern>org.javassist</pattern>
<shadedPattern>us.myles.viaversion.libs.javassist</shadedPattern>
</relocation>
</relocations>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<!-- SpigotMC Repo (Bukkit API) -->
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots</url>
</repository>
<!-- SpaceHQ Repo-->
<repository>
<id>spacehq-repo</id>
<url>https://repo.spacehq.org/content/repositories/releases/</url>
</repository>
</repositories>
<dependencies>
<!-- Bukkit API, http://www.spigotmc.org/ or http://bukkit.org/ -->
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.8.8-R0.1-SNAPSHOT</version>
<version>${bukkitVersion}</version>
<scope>provided</scope>
<optional>true</optional>
<exclusions>
<exclusion>
<artifactId>junit</artifactId>
<groupId>junit</groupId>
</exclusion>
<exclusion>
<artifactId>gson</artifactId>
<groupId>com.google.code.gson</groupId>
</exclusion>
<exclusion>
<artifactId>persistence-api</artifactId>
<groupId>javax.persistence</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- Javassist (Bytecode Library) -->
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.20.0-GA</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<!-- NBT Edit Library -->
<dependency>
<groupId>org.spacehq</groupId>
<artifactId>opennbt</artifactId>
<version>1.0</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<!-- GSON (JSON Library) -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.6.2</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<!-- Netty (Network Library) -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.0.20.Final</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.6</version>
<scope>provided</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
</repositories>
</project>
@@ -1,126 +0,0 @@
package org.spacehq.mc.protocol.data.game.chunk;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.util.PacketUtil;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class BlockStorage {
private int bitsPerEntry;
private List<Integer> states;
private FlexibleStorage storage;
public BlockStorage() {
this.bitsPerEntry = 4;
this.states = new ArrayList<Integer>();
this.states.add(0);
this.storage = new FlexibleStorage(this.bitsPerEntry, 4096);
}
public BlockStorage(ByteBuf in) throws IOException {
this.bitsPerEntry = in.readUnsignedByte();
this.states = new ArrayList<Integer>();
int stateCount = PacketUtil.readVarInt(in);
for (int i = 0; i < stateCount; i++) {
this.states.add(PacketUtil.readVarInt(in));
}
this.storage = new FlexibleStorage(this.bitsPerEntry, PacketUtil.readLongs(PacketUtil.readVarInt(in), in));
}
public void write(ByteBuf out) throws IOException {
out.writeByte(this.bitsPerEntry);
PacketUtil.writeVarInt(this.states.size(), out);
for (int state : this.states) {
PacketUtil.writeVarInt(state, out);
}
long[] data = this.storage.getData();
PacketUtil.writeVarInt(data.length, out);
PacketUtil.writeLongs(data, out);
}
public int getBitsPerEntry() {
return this.bitsPerEntry;
}
public List<Integer> getStates() {
return Collections.unmodifiableList(this.states);
}
public FlexibleStorage getStorage() {
return this.storage;
}
public int get(int x, int y, int z) {
int id = this.storage.get(index(x, y, z));
return this.bitsPerEntry <= 8 ? (id >= 0 && id < this.states.size() ? this.states.get(id) : 0) : id;
}
public void set(int x, int y, int z, int state) {
set(index(x, y, z), state);
}
public void set(int ind, int state) {
int id = this.bitsPerEntry <= 8 ? this.states.indexOf(state) : state;
if (id == -1) {
this.states.add(state);
if (this.states.size() > 1 << this.bitsPerEntry) {
this.bitsPerEntry++;
List<Integer> oldStates = this.states;
if (this.bitsPerEntry > 8) {
oldStates = new ArrayList<Integer>(this.states);
this.states.clear();
this.bitsPerEntry = 13;
}
FlexibleStorage oldStorage = this.storage;
this.storage = new FlexibleStorage(this.bitsPerEntry, this.storage.getSize());
for (int index = 0; index < this.storage.getSize(); index++) {
int value = oldStorage.get(index);
this.storage.set(index, this.bitsPerEntry <= 8 ? value : oldStates.get(value));
}
}
id = this.bitsPerEntry <= 8 ? this.states.indexOf(state) : state;
}
this.storage.set(ind, id);
}
public boolean isEmpty() {
for (int index = 0; index < this.storage.getSize(); index++) {
if (this.storage.get(index) != 0) {
return false;
}
}
return true;
}
private static int index(int x, int y, int z) {
return y << 8 | z << 4 | x;
}
@Override
public boolean equals(Object o) {
return this == o || (o instanceof BlockStorage && this.bitsPerEntry == ((BlockStorage) o).bitsPerEntry && this.states.equals(((BlockStorage) o).states) && this.storage.equals(((BlockStorage) o).storage));
}
@Override
public int hashCode() {
int result = this.bitsPerEntry;
result = 31 * result + this.states.hashCode();
result = 31 * result + this.storage.hashCode();
return result;
}
}
@@ -1,46 +0,0 @@
package org.spacehq.mc.protocol.data.game.chunk;
public class Chunk {
private BlockStorage blocks;
private NibbleArray3d blocklight;
private NibbleArray3d skylight;
public Chunk(boolean skylight) {
this(new BlockStorage(), new NibbleArray3d(2048), skylight ? new NibbleArray3d(2048) : null);
}
public Chunk(BlockStorage blocks, NibbleArray3d blocklight, NibbleArray3d skylight) {
this.blocks = blocks;
this.blocklight = blocklight;
this.skylight = skylight;
}
public BlockStorage getBlocks() {
return this.blocks;
}
public NibbleArray3d getBlockLight() {
return this.blocklight;
}
public NibbleArray3d getSkyLight() {
return this.skylight;
}
public boolean isEmpty() {
return this.blocks.isEmpty();
}
@Override
public boolean equals(Object o) {
return this == o || (o instanceof Chunk && this.blocks.equals(((Chunk) o).blocks) && this.blocklight.equals(((Chunk) o).blocklight) && ((this.skylight == null && (((Chunk) o).skylight == null)) || (this.skylight != null && this.skylight.equals(((Chunk) o).skylight))));
}
@Override
public int hashCode() {
int result = this.blocks.hashCode();
result = 31 * result + this.blocklight.hashCode();
result = 31 * result + (this.skylight != null ? this.skylight.hashCode() : 0);
return result;
}
}
@@ -1,69 +0,0 @@
package org.spacehq.mc.protocol.data.game.chunk;
public class Column {
private int x;
private int z;
private Chunk chunks[];
private byte biomeData[];
private boolean skylight;
public Column(int x, int z, Chunk chunks[]) {
this(x, z, chunks, null);
}
public Column(int x, int z, Chunk chunks[], byte biomeData[]) {
if(chunks.length != 16) {
throw new IllegalArgumentException("Chunk array length must be 16.");
}
if(biomeData != null && biomeData.length != 256) {
throw new IllegalArgumentException("Biome data array length must be 256.");
}
this.skylight = false;
boolean noSkylight = false;
for(int index = 0; index < chunks.length; index++) {
if(chunks[index] != null) {
if(chunks[index].getSkyLight() == null) {
noSkylight = true;
} else {
this.skylight = true;
}
}
}
if(noSkylight && this.skylight) {
throw new IllegalArgumentException("Either all chunks must have skylight values or none must have them.");
}
this.x = x;
this.z = z;
this.chunks = chunks;
this.biomeData = biomeData;
}
public int getX() {
return this.x;
}
public int getZ() {
return this.z;
}
public Chunk[] getChunks() {
return this.chunks;
}
public boolean hasBiomeData() {
return this.biomeData != null;
}
public byte[] getBiomeData() {
return this.biomeData;
}
public boolean hasSkylight() {
return this.skylight;
}
}
@@ -1,104 +0,0 @@
package org.spacehq.mc.protocol.data.game.chunk;
import java.util.Arrays;
public class FlexibleStorage {
private final long[] data;
private final int bitsPerEntry;
private final int size;
private final long maxEntryValue;
public FlexibleStorage(int bitsPerEntry, int size) {
this(bitsPerEntry, new long[roundToNearest(size * bitsPerEntry, 64) / 64]);
}
public FlexibleStorage(int bitsPerEntry, long[] data) {
if(bitsPerEntry < 1 || bitsPerEntry > 32) {
throw new IllegalArgumentException("BitsPerEntry cannot be outside of accepted range.");
}
this.bitsPerEntry = bitsPerEntry;
this.data = data;
this.size = this.data.length * 64 / this.bitsPerEntry;
this.maxEntryValue = (1L << this.bitsPerEntry) - 1;
}
public long[] getData() {
return this.data;
}
public int getBitsPerEntry() {
return this.bitsPerEntry;
}
public int getSize() {
return this.size;
}
public int get(int index) {
if(index < 0 || index > this.size - 1) {
throw new IndexOutOfBoundsException();
}
int bitIndex = index * this.bitsPerEntry;
int startIndex = bitIndex / 64;
int endIndex = ((index + 1) * this.bitsPerEntry - 1) / 64;
int startBitSubIndex = bitIndex % 64;
if(startIndex == endIndex) {
return (int) (this.data[startIndex] >>> startBitSubIndex & this.maxEntryValue);
} else {
int endBitSubIndex = 64 - startBitSubIndex;
return (int) ((this.data[startIndex] >>> startBitSubIndex | this.data[endIndex] << endBitSubIndex) & this.maxEntryValue);
}
}
public void set(int index, int value) {
if(index < 0 || index > this.size - 1) {
throw new IndexOutOfBoundsException();
}
if(value < 0 || value > this.maxEntryValue) {
throw new IllegalArgumentException("Value cannot be outside of accepted range.");
}
int bitIndex = index * this.bitsPerEntry;
int startIndex = bitIndex / 64;
int endIndex = ((index + 1) * this.bitsPerEntry - 1) / 64;
int startBitSubIndex = bitIndex % 64;
this.data[startIndex] = this.data[startIndex] & ~(this.maxEntryValue << startBitSubIndex) | ((long) value & this.maxEntryValue) << startBitSubIndex;
if(startIndex != endIndex) {
int endBitSubIndex = 64 - startBitSubIndex;
this.data[endIndex] = this.data[endIndex] >>> endBitSubIndex << endBitSubIndex | ((long) value & this.maxEntryValue) >> endBitSubIndex;
}
}
private static int roundToNearest(int value, int roundTo) {
if(roundTo == 0) {
return 0;
} else if(value == 0) {
return roundTo;
} else {
if(value < 0) {
roundTo *= -1;
}
int remainder = value % roundTo;
return remainder != 0 ? value + roundTo - remainder : value;
}
}
@Override
public boolean equals(Object o) {
return this == o || (o instanceof FlexibleStorage && Arrays.equals(this.data, ((FlexibleStorage) o).data) && this.bitsPerEntry == ((FlexibleStorage) o).bitsPerEntry && this.size == ((FlexibleStorage) o).size && this.maxEntryValue == ((FlexibleStorage) o).maxEntryValue);
}
@Override
public int hashCode() {
int result = Arrays.hashCode(this.data);
result = 31 * result + this.bitsPerEntry;
result = 31 * result + this.size;
result = 31 * result + (int) this.maxEntryValue;
return result;
}
}
@@ -1,71 +0,0 @@
package org.spacehq.mc.protocol.data.game.chunk;
import io.netty.buffer.ByteBuf;
import java.io.IOException;
import java.util.Arrays;
public class NibbleArray3d {
private byte[] data;
public NibbleArray3d(int size) {
this.data = new byte[size];
}
public NibbleArray3d(byte[] array) {
this.data = array;
}
public NibbleArray3d(ByteBuf in, int size) throws IOException {
this.data = new byte[size];
in.readBytes(this.data);
}
public void write(ByteBuf out) throws IOException {
out.writeBytes(this.data);
}
public byte[] getData() {
return this.data;
}
public int get(int x, int y, int z) {
int key = y << 8 | z << 4 | x;
int index = key >> 1;
int part = key & 1;
return part == 0 ? this.data[index] & 15 : this.data[index] >> 4 & 15;
}
public void set(int x, int y, int z, int val) {
int key = y << 8 | z << 4 | x;
int index = key >> 1;
int part = key & 1;
if(part == 0) {
this.data[index] = (byte) (this.data[index] & 240 | val & 15);
} else {
this.data[index] = (byte) (this.data[index] & 15 | (val & 15) << 4);
}
}
public void fill(int val) {
for(int index = 0; index < this.data.length << 1; index++) {
int ind = index >> 1;
int part = index & 1;
if(part == 0) {
this.data[ind] = (byte) (this.data[ind] & 240 | val & 15);
} else {
this.data[ind] = (byte) (this.data[ind] & 15 | (val & 15) << 4);
}
}
}
@Override
public boolean equals(Object o) {
return this == o || (o instanceof NibbleArray3d && Arrays.equals(this.data, ((NibbleArray3d) o).data));
}
@Override
public int hashCode() {
return Arrays.hashCode(this.data);
}
}
@@ -1,114 +0,0 @@
package org.spacehq.mc.protocol.util;
import io.netty.buffer.ByteBuf;
import org.spacehq.mc.protocol.data.game.chunk.Chunk;
import org.spacehq.mc.protocol.data.game.chunk.Column;
import org.spacehq.mc.protocol.data.game.chunk.NibbleArray3d;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ShortBuffer;
/* From https://github.com/Steveice10/MCProtocolLib/ */
/* No credit taken for writing this code, and used accordance to it's license
Original by Steveice10, modified to suit this plugin.
*/
public class NetUtil {
public static int writeNewColumn(ByteBuf out, Column column, boolean fullChunk, boolean hasSkylight) throws IOException {
int mask = 0;
Chunk chunks[] = column.getChunks();
for(int index = 0; index < chunks.length; index++) {
Chunk chunk = chunks[index];
if(chunk != null && (!fullChunk || !chunk.isEmpty())) {
mask |= 1 << index;
chunk.getBlocks().write(out);
chunk.getBlockLight().write(out);
if(hasSkylight || column.hasSkylight()) {
chunk.getSkyLight().write(out); // TODO: Make a PR to original lib to correct this
}
}
}
if(fullChunk) {
out.writeBytes(column.getBiomeData());
}
return mask;
}
public static Column readOldChunkData(int x, int z, boolean isFullChunk, int bitmask, byte[] input, boolean checkForSky, boolean hasSkyLight) {
int pos = 0;
int expected = isFullChunk ? 256 : 0;
boolean sky = false;
ShortBuffer buf = ByteBuffer.wrap(input).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
// 0 = Calculate expected length and determine if the packet has skylight.
// 1 = Create chunks from mask and get blocks.
// 2 = Get block light.
// 3 = Get sky light.
Chunk[] chunks = new Chunk[16];
for(int pass = 0; pass < 4; pass++) {
for(int ind = 0; ind < 16; ind++) {
if((bitmask & 1 << ind) != 0) {
if(pass == 0) {
// Block length + Blocklight length
expected += (4096 * 2) + 2048;
}
if(pass == 1) {
chunks[ind] = new Chunk(sky || hasSkyLight);
buf.position(pos / 2);
short[] tempData = new short[4096];
buf.get(tempData, 0, tempData.length);
// convert short array to new one
int index = 0;
for(short ss:tempData){
// s is 16 bits, 12 bits id and 4 bits data
int data = ss & 0xF;
int id = (ss >> 4) << 4 | data;
int newCombined = id ; // test
chunks[ind].getBlocks().set(index, newCombined);
index++;
}
pos += tempData.length * 2;
}
if(pass == 2) {
NibbleArray3d blocklight = chunks[ind].getBlockLight();
System.arraycopy(input, pos, blocklight.getData(), 0, blocklight.getData().length);
pos += blocklight.getData().length;
}
if(pass == 3) {
if(sky) {
NibbleArray3d skylight = chunks[ind].getSkyLight();
System.arraycopy(input, pos, skylight.getData(), 0, skylight.getData().length);
pos += skylight.getData().length;
}
}
}
}
if(pass == 0) {
// If we have more data than blocks and blocklight combined, there must be skylight data as well.
if(input.length > expected) {
sky = checkForSky;
}
}
}
byte biomeData[] = null;
if(isFullChunk) {
biomeData = new byte[256];
System.arraycopy(input, pos, biomeData, 0, biomeData.length);
}
Column column = new Column(x, z, chunks, biomeData);
return column;
}
}
@@ -1,4 +0,0 @@
package us.myles.ViaVersion;
public class CancelException extends Exception{
}
@@ -1,78 +0,0 @@
package us.myles.ViaVersion;
import io.netty.channel.socket.SocketChannel;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import us.myles.ViaVersion.packets.State;
import java.util.UUID;
public class ConnectionInfo {
private final SocketChannel channel;
private Object lastPacket;
private java.util.UUID UUID;
private State state = State.HANDSHAKE;
private int protocol = 0;
private int compression = 0;
private boolean active = true;
public ConnectionInfo(SocketChannel socketChannel) {
this.channel = socketChannel;
}
public int getProtocol() {
return protocol;
}
public void setProtocol(int protocol) {
this.protocol = protocol;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public void setCompression(int compression) {
this.compression = compression;
}
public int getCompression() {
return compression;
}
public void setLastPacket(Object lastPacket) {
this.lastPacket = lastPacket;
}
public Object getLastPacket() {
return lastPacket;
}
public void setUUID(UUID UUID) {
this.UUID = UUID;
}
public java.util.UUID getUUID() {
return UUID;
}
public Player getPlayer() {
return UUID == null ? null : Bukkit.getPlayer(UUID);
}
public SocketChannel getChannel() {
return channel;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
}
@@ -1,106 +1,515 @@
package us.myles.ViaVersion;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import lombok.NonNull;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.java.JavaPlugin;
import us.myles.ViaVersion.api.Pair;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.ViaVersionAPI;
import us.myles.ViaVersion.api.ViaVersionConfig;
import us.myles.ViaVersion.api.boss.BossBar;
import us.myles.ViaVersion.api.boss.BossColor;
import us.myles.ViaVersion.api.boss.BossStyle;
import us.myles.ViaVersion.api.command.ViaVersionCommand;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
import us.myles.ViaVersion.boss.ViaBossBar;
import us.myles.ViaVersion.classgenerator.ClassGenerator;
import us.myles.ViaVersion.commands.ViaCommandHandler;
import us.myles.ViaVersion.handlers.ViaVersionInitializer;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.update.UpdateListener;
import us.myles.ViaVersion.update.UpdateUtil;
import us.myles.ViaVersion.util.Configuration;
import us.myles.ViaVersion.util.ListWrapper;
import us.myles.ViaVersion.util.ReflectionUtil;
import java.util.Collections;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVersionConfig {
private final Set<UUID> portedPlayers = Collections.newSetFromMap(new ConcurrentHashMap<UUID, Boolean>());
private final Map<UUID, UserConnection> portedPlayers = new ConcurrentHashMap<>();
private List<ChannelFuture> injectedFutures = new ArrayList<>();
private List<Pair<Field, Object>> injectedLists = new ArrayList<>();
private ViaCommandHandler commandHandler;
private boolean debug = false;
private boolean compatSpigotBuild = false;
@Override
public void onLoad() {
ViaVersion.setInstance(this);
generateConfig();
if (System.getProperty("ViaVersion") != null) {
if (Bukkit.getPluginManager().getPlugin("ProtocolLib") != null) {
getLogger().severe("ViaVersion is already loaded, we're going to kick all the players... because otherwise we'll crash because of ProtocolLib.");
for (Player player : Bukkit.getOnlinePlayers()) {
player.kickPlayer("Server reload, please rejoin!");
}
} else {
getLogger().severe("ViaVersion is already loaded, this should work fine... Otherwise reboot the server!!!");
}
}
// Check if it's a spigot build with a protocol mod
try {
compatSpigotBuild = ReflectionUtil.nms("PacketEncoder").getDeclaredField("version") != null;
} catch (Exception e){
compatSpigotBuild = false;
}
// Generate classes needed (only works if it's compat)
ClassGenerator.generate();
getLogger().info("ViaVersion " + getDescription().getVersion() + (compatSpigotBuild ? "compat" : "") + " is now loaded, injecting.");
injectPacketHandler();
}
@Override
public void onEnable() {
ViaVersion.setInstance(this);
if(System.getProperty("ViaVersion") != null){
getLogger().severe("ViaVersion is already loaded, we don't support reloads. Please reboot if you wish to update.");
return;
}
if (isCheckForUpdates())
UpdateUtil.sendUpdateMessage(this);
// Gather version :)
Bukkit.getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
@Override
public void run() {
gatherProtocolVersion();
// Check if there are any pipes to this version
if (ProtocolRegistry.SERVER_PROTOCOL != -1) {
getLogger().info("ViaVersion detected protocol version: " + ProtocolRegistry.SERVER_PROTOCOL);
if (!ProtocolRegistry.isWorkingPipe()) {
getLogger().warning("ViaVersion will not function on the current protocol.");
}
}
}
});
getLogger().info("ViaVersion enabled, injecting. (Allows 1.8 to be accessed via 1.9)");
Bukkit.getPluginManager().registerEvents(new UpdateListener(this), this);
getCommand("viaversion").setExecutor(commandHandler = new ViaCommandHandler());
getCommand("viaversion").setTabCompleter(commandHandler);
// Register Protocol Listeners
ProtocolRegistry.registerListeners();
}
@Override
public void onDisable() {
getLogger().info("ViaVersion is disabling, if this is a reload it may not work.");
uninject();
}
public void gatherProtocolVersion() {
try {
injectPacketHandler();
Class<?> serverClazz = ReflectionUtil.nms("MinecraftServer");
Object server = ReflectionUtil.invokeStatic(serverClazz, "getServer");
Class<?> pingClazz = ReflectionUtil.nms("ServerPing");
Object ping = null;
// Search for ping method
for (Field f : serverClazz.getDeclaredFields()) {
if (f.getType() != null) {
if (f.getType().getSimpleName().equals("ServerPing")) {
f.setAccessible(true);
ping = f.get(server);
}
}
}
if (ping != null) {
Object serverData = null;
for (Field f : pingClazz.getDeclaredFields()) {
if (f.getType() != null) {
if (f.getType().getSimpleName().endsWith("ServerData")) {
f.setAccessible(true);
serverData = f.get(ping);
}
}
}
if (serverData != null) {
int protocolVersion = -1;
for (Field f : serverData.getClass().getDeclaredFields()) {
if (f.getType() != null) {
if (f.getType() == int.class) {
f.setAccessible(true);
protocolVersion = (int) f.get(serverData);
}
}
}
if (protocolVersion != -1) {
ProtocolRegistry.SERVER_PROTOCOL = protocolVersion;
return;
}
}
}
} catch (Exception e) {
e.printStackTrace();
// We couldn't work it out... We'll just use ping and hope for the best...
}
}
public void generateConfig() {
File file = new File(getDataFolder(), "config.yml");
if (file.exists()) {
// Update config options
Configuration oldConfig = new Configuration(file);
oldConfig.reload(false); // Load current options from config
file.delete(); // Delete old config
saveDefaultConfig(); // Generate new config
Configuration newConfig = new Configuration(file);
newConfig.reload(true); // Load default options
for (String key : oldConfig.getKeys(false)) {
// Set option in new config if exists
if (newConfig.contains(key)) {
newConfig.set(key, oldConfig.get(key));
}
}
newConfig.save();
} else {
saveDefaultConfig();
}
}
public void injectPacketHandler() {
try {
Class<?> serverClazz = ReflectionUtil.nms("MinecraftServer");
Object server = ReflectionUtil.invokeStatic(serverClazz, "getServer");
Object connection = null;
for (Method m : serverClazz.getDeclaredMethods()) {
if (m.getReturnType() != null) {
if (m.getReturnType().getSimpleName().equals("ServerConnection")) {
if (m.getParameterTypes().length == 0) {
connection = m.invoke(server);
}
}
}
}
if (connection == null) {
getLogger().warning("We failed to find the ServerConnection? :( What server are you running?");
return;
}
for (Field field : connection.getClass().getDeclaredFields()) {
field.setAccessible(true);
final Object value = field.get(connection);
if (value instanceof List) {
// Inject the list
List wrapper = new ListWrapper((List) value) {
@Override
public synchronized void handleAdd(Object o) {
synchronized (this) {
if (o instanceof ChannelFuture) {
inject((ChannelFuture) o);
}
}
}
};
injectedLists.add(new Pair<>(field, connection));
field.set(connection, wrapper);
// Iterate through current list
synchronized (wrapper) {
for (Object o : (List) value) {
if (o instanceof ChannelFuture) {
inject((ChannelFuture) o);
} else {
break; // not the right list.
}
}
}
}
}
System.setProperty("ViaVersion", getDescription().getVersion());
} catch (Exception e) {
getLogger().severe("Unable to inject handlers, are you on 1.8? ");
e.printStackTrace();
}
Bukkit.getPluginManager().registerEvents(new Listener() {
@EventHandler
public void onPlayerQuit(PlayerQuitEvent e) {
setPorted(e.getPlayer().getUniqueId(), false);
}
}, this);
}
public void injectPacketHandler() throws Exception {
Class<?> serverClazz = ReflectionUtil.nms("MinecraftServer");
Object server = ReflectionUtil.invokeStatic(serverClazz, "getServer");
Object connection = serverClazz.getDeclaredMethod("getServerConnection").invoke(server);
private void inject(ChannelFuture future) {
try {
ChannelHandler bootstrapAcceptor = future.channel().pipeline().first();
try {
ChannelInitializer<SocketChannel> oldInit = ReflectionUtil.get(bootstrapAcceptor, "childHandler", ChannelInitializer.class);
ChannelInitializer newInit = new ViaVersionInitializer(oldInit);
List<ChannelFuture> futures = ReflectionUtil.get(connection, "g", List.class);
if (futures.size() == 0) {
throw new Exception("Could not find server to inject (Please ensure late-bind in your spigot.yml is false)");
ReflectionUtil.set(bootstrapAcceptor, "childHandler", newInit);
injectedFutures.add(future);
} catch (NoSuchFieldException e) {
// field not found
throw new Exception("Unable to find childHandler, blame " + bootstrapAcceptor.getClass().getName());
}
} catch (Exception e) {
getLogger().severe("Have you got late-bind enabled with something else? (ProtocolLib?)");
e.printStackTrace();
}
}
private void uninject() {
// TODO: Uninject from players currently online to prevent protocol lib issues.
for (ChannelFuture future : injectedFutures) {
ChannelHandler bootstrapAcceptor = future.channel().pipeline().first();
try {
ChannelInitializer<SocketChannel> oldInit = ReflectionUtil.get(bootstrapAcceptor, "childHandler", ChannelInitializer.class);
if (oldInit instanceof ViaVersionInitializer) {
ReflectionUtil.set(bootstrapAcceptor, "childHandler", ((ViaVersionInitializer) oldInit).getOriginal());
}
} catch (Exception e) {
System.out.println("Failed to remove injection... reload won't work with connections sorry");
}
}
injectedFutures.clear();
for (Pair<Field, Object> pair : injectedLists) {
try {
Object o = pair.getKey().get(pair.getValue());
if (o instanceof ListWrapper) {
pair.getKey().set(pair.getValue(), ((ListWrapper) o).getOriginalList());
}
} catch (IllegalAccessException e) {
System.out.println("Failed to remove injection... reload might not work with connections sorry");
}
}
for (ChannelFuture future : futures) {
ChannelPipeline pipeline = future.channel().pipeline();
ChannelHandler bootstrapAcceptor = pipeline.first();
ChannelInitializer<SocketChannel> oldInit = ReflectionUtil.get(bootstrapAcceptor, "childHandler", ChannelInitializer.class);
ChannelInitializer newInit = new ViaVersionInitializer(oldInit);
ReflectionUtil.set(bootstrapAcceptor, "childHandler", newInit);
}
injectedLists.clear();
}
@Override
public boolean isPorted(Player player) {
return portedPlayers.contains(player.getUniqueId());
return isPorted(player.getUniqueId());
}
public void setPorted(UUID id, boolean value) {
if (value) {
portedPlayers.add(id);
} else {
portedPlayers.remove(id);
}
@Override
public int getPlayerVersion(@NonNull Player player) {
if (!isPorted(player))
return ProtocolRegistry.SERVER_PROTOCOL;
return portedPlayers.get(player.getUniqueId()).get(ProtocolInfo.class).getProtocolVersion();
}
public static ItemStack getHandItem(final ConnectionInfo info) {
@Override
public int getPlayerVersion(@NonNull UUID uuid) {
if (!isPorted(uuid))
return ProtocolRegistry.SERVER_PROTOCOL;
return portedPlayers.get(uuid).get(ProtocolInfo.class).getProtocolVersion();
}
@Override
public boolean isPorted(UUID playerUUID) {
return portedPlayers.containsKey(playerUUID);
}
@Override
public String getVersion() {
return getDescription().getVersion();
}
public UserConnection getConnection(UUID playerUUID) {
return portedPlayers.get(playerUUID);
}
public UserConnection getConnection(Player player) {
return portedPlayers.get(player.getUniqueId());
}
public void sendRawPacket(Player player, ByteBuf packet) throws IllegalArgumentException {
sendRawPacket(player.getUniqueId(), packet);
}
@Override
public void sendRawPacket(UUID uuid, ByteBuf packet) throws IllegalArgumentException {
if (!isPorted(uuid)) throw new IllegalArgumentException("This player is not controlled by ViaVersion!");
UserConnection ci = portedPlayers.get(uuid);
ci.sendRawPacket(packet);
}
@Override
public BossBar createBossBar(String title, BossColor color, BossStyle style) {
return new ViaBossBar(title, 1F, color, style);
}
@Override
public BossBar createBossBar(String title, float health, BossColor color, BossStyle style) {
return new ViaBossBar(title, health, color, style);
}
@Override
public boolean isDebug() {
return this.debug;
}
public void setDebug(boolean value) {
this.debug = value;
}
@Override
public ViaVersionCommand getCommandHandler() {
return commandHandler;
}
@Override
public boolean isCompatSpigotBuild() {
return compatSpigotBuild;
}
public boolean isCheckForUpdates() {
return getConfig().getBoolean("checkforupdates", true);
}
public boolean isPreventCollision() {
return getConfig().getBoolean("prevent-collision", true);
}
public boolean isNewEffectIndicator() {
return getConfig().getBoolean("use-new-effect-indicator", true);
}
@Override
public boolean isShowNewDeathMessages() {
return getConfig().getBoolean("use-new-deathmessages", false);
}
public boolean isSuppressMetadataErrors() {
return getConfig().getBoolean("suppress-metadata-errors", false);
}
public boolean isShieldBlocking() {
return getConfig().getBoolean("shield-blocking", true);
}
public boolean isHologramPatch() {
return getConfig().getBoolean("hologram-patch", false);
}
public boolean isBossbarPatch() {
return getConfig().getBoolean("bossbar-patch", true);
}
public boolean isBossbarAntiflicker() {
return getConfig().getBoolean("bossbar-anti-flicker", false);
}
public boolean isUnknownEntitiesSuppressed() {
return getConfig().getBoolean("suppress-entityid-errors", false);
}
public double getHologramYOffset() {
return getConfig().getDouble("hologram-y", -1D);
}
public boolean isBlockBreakPatch() {
return getConfig().getBoolean("block-break-patch", true);
}
@Override
public int getMaxPPS() {
return getConfig().getInt("max-pps", 140);
}
@Override
public String getMaxPPSKickMessage() {
return getConfig().getString("max-pps-kick-msg", "Sending packets too fast? lag?");
}
@Override
public int getTrackingPeriod() {
return getConfig().getInt("tracking-period", 6);
}
@Override
public int getWarningPPS() {
return getConfig().getInt("tracking-warning-pps", 120);
}
@Override
public int getMaxWarnings() {
return getConfig().getInt("tracking-max-warnings", 3);
}
@Override
public String getMaxWarningsKickMessage() {
return getConfig().getString("tracking-max-kick-msg", "You are sending too many packets, :(");
}
@Override
public boolean isAntiXRay() {
return getConfig().getBoolean("anti-xray-patch", true);
}
public boolean isAutoTeam() {
// Collision has to be enabled first
return isPreventCollision() && getConfig().getBoolean("auto-team", true);
}
public void addPortedClient(UserConnection info) {
portedPlayers.put(info.get(ProtocolInfo.class).getUuid(), info);
}
public void removePortedClient(UUID clientID) {
portedPlayers.remove(clientID);
}
public void run(final Runnable runnable, boolean wait) {
try {
return Bukkit.getScheduler().callSyncMethod(getPlugin(ViaVersionPlugin.class), new Callable<ItemStack>() {
Future f = Bukkit.getScheduler().callSyncMethod(Bukkit.getPluginManager().getPlugin("ViaVersion"), new Callable<Boolean>() {
@Override
public ItemStack call() throws Exception {
if (info.getPlayer() != null) {
return info.getPlayer().getItemInHand();
}
return null;
public Boolean call() throws Exception {
runnable.run();
return true;
}
}).get(10, TimeUnit.SECONDS);
});
if (wait) {
f.get(10, TimeUnit.SECONDS);
}
} catch (Exception e) {
System.out.println("Error fetching hand item ");
e.printStackTrace();
return null;
System.out.println("Failed to run task: " + e.getClass().getName());
if (ViaVersion.getInstance().isDebug())
e.printStackTrace();
}
}
public Map<UUID, UserConnection> getPortedPlayers() {
return portedPlayers;
}
public boolean handlePPS(UserConnection info) {
// Max PPS Checker
if (getMaxPPS() > 0) {
if (info.getPacketsPerSecond() >= getMaxPPS()) {
info.disconnect(getMaxPPSKickMessage());
return true; // don't send current packet
}
}
// Tracking PPS Checker
if (getMaxWarnings() > 0 && getTrackingPeriod() > 0) {
if (info.getSecondsObserved() > getTrackingPeriod()) {
// Reset
info.setWarnings(0);
info.setSecondsObserved(1);
} else {
info.setSecondsObserved(info.getSecondsObserved() + 1);
if (info.getPacketsPerSecond() >= getWarningPPS()) {
info.setWarnings(info.getWarnings() + 1);
}
if (info.getWarnings() >= getMaxWarnings()) {
info.disconnect(getMaxWarningsKickMessage());
return true; // don't send current packet
}
}
}
return false;
}
}
@@ -0,0 +1,338 @@
package us.myles.ViaVersion.api;
import com.google.common.base.Preconditions;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.Getter;
import lombok.Setter;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.remapper.ValueCreator;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.api.type.TypeConverter;
import us.myles.ViaVersion.exception.InformativeException;
import us.myles.ViaVersion.handlers.ViaDecodeHandler;
import us.myles.ViaVersion.util.PipelineUtil;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class PacketWrapper {
private final ByteBuf inputBuffer;
private final UserConnection userConnection;
private boolean send = true;
@Setter
@Getter
private int id = -1;
private LinkedList<Pair<Type, Object>> readableObjects = new LinkedList<>();
private List<Pair<Type, Object>> packetValues = new ArrayList<>();
public PacketWrapper(int packetID, ByteBuf inputBuffer, UserConnection userConnection) {
this.id = packetID;
this.inputBuffer = inputBuffer;
this.userConnection = userConnection;
}
/**
* Get a part from the output
*
* @param type The type of the part you wish to get.
* @param index The index of the part (relative to the type)
* @return The requested type or throws ArrayIndexOutOfBounds
*/
public <T> T get(Type<T> type, int index) throws Exception {
int currentIndex = 0;
for (Pair<Type, Object> packetValue : packetValues) {
if (packetValue.getKey() == type) { // Ref check
if (currentIndex == index) {
return (T) packetValue.getValue();
}
currentIndex++;
}
}
Exception e = new ArrayIndexOutOfBoundsException("Could not find type " + type.getTypeName() + " at " + index);
throw new InformativeException(e).set("Type", type.getTypeName()).set("Index", index).set("Packet ID", getId()).set("Data", packetValues);
}
/**
* Check if a type is at an index
*
* @param type The type of the part you wish to get.
* @param index The index of the part (relative to the type)
* @return True if the type is at the index
*/
public boolean is(Type type, int index) {
int currentIndex = 0;
for (Pair<Type, Object> packetValue : packetValues) {
if (packetValue.getKey() == type) { // Ref check
if (currentIndex == index) {
return true;
}
currentIndex++;
}
}
return false;
}
/**
* Set a currently existing part in the output
*
* @param type The type of the part you wish to set.
* @param index The index of the part (relative to the type)
* @param value The value of the part you wish to set it to.
*/
public <T> void set(Type<T> type, int index, T value) throws Exception {
int currentIndex = 0;
for (Pair<Type, Object> packetValue : packetValues) {
if (packetValue.getKey() == type) { // Ref check
if (currentIndex == index) {
packetValue.setValue(value);
return;
}
currentIndex++;
}
}
Exception e = new ArrayIndexOutOfBoundsException("Could not find type " + type.getTypeName() + " at " + index);
throw new InformativeException(e).set("Type", type.getTypeName()).set("Index", index).set("Packet ID", getId());
}
/**
* Read a type from the input.
*
* @param type The type you wish to read
* @return The requested type
* @throws Exception If it fails to read
*/
public <T> T read(Type<T> type) throws Exception {
if (type == Type.NOTHING) return null;
if (readableObjects.isEmpty()) {
Preconditions.checkNotNull(inputBuffer, "This packet does not have an input buffer.");
// We could in the future log input read values, but honestly for things like bulk maps, mem waste D:
try {
return type.read(inputBuffer);
} catch (Exception e) {
throw new InformativeException(e).set("Type", type.getTypeName()).set("Packet ID", getId()).set("Data", packetValues);
}
} else {
Pair<Type, Object> read = readableObjects.poll();
if (read.getKey().equals(type)) {
return (T) read.getValue();
} else {
if (type == Type.NOTHING) {
return read(type); // retry
} else {
Exception e = new IOException("Unable to read type " + type.getTypeName() + ", found " + read.getKey().getTypeName());
throw new InformativeException(e).set("Type", type.getTypeName()).set("Packet ID", getId()).set("Data", packetValues);
}
}
}
}
/**
* Write a type to the output.
*
* @param type The type to write.
* @param value The value of the type to write.
*/
public <T> void write(Type<T> type, T value) {
if (value != null) {
if (!type.getOutputClass().isAssignableFrom(value.getClass())) {
// attempt conversion
if (type instanceof TypeConverter) {
value = (T) ((TypeConverter) type).from(value);
} else {
System.out.println("Possible type mismatch: " + value.getClass().getName() + " -> " + type.getOutputClass());
}
}
}
packetValues.add(new Pair<Type, Object>(type, value));
}
/**
* Take a value from the input and write to the output.
*
* @param type The type to read and write.
* @return The type which was read/written.
* @throws Exception If it failed to read or write
*/
public <T> T passthrough(Type<T> type) throws Exception {
T value = read(type);
write(type, value);
return value;
}
/**
* Take all the inputs and write them to the output.
*
* @throws Exception If it failed to read or write
*/
public void passthroughAll() throws Exception {
// Copy previous objects
packetValues.addAll(readableObjects);
readableObjects.clear();
// If the buffer has readable bytes, copy them.
if(inputBuffer.readableBytes() > 0){
passthrough(Type.REMAINING_BYTES);
}
}
/**
* Write the current output to a buffer.
*
* @param buffer The buffer to write to.
* @throws Exception Throws an exception if it fails to write a value.
*/
public void writeToBuffer(ByteBuf buffer) throws Exception {
if (id != -1) {
Type.VAR_INT.write(buffer, id);
}
if (readableObjects.size() > 0) {
packetValues.addAll(readableObjects);
}
int index = 0;
for (Pair<Type, Object> packetValue : packetValues) {
try {
Object value = packetValue.getValue();
if (value != null) {
if (!packetValue.getKey().getOutputClass().isAssignableFrom(value.getClass())) {
// attempt conversion
if (packetValue.getKey() instanceof TypeConverter) {
value = ((TypeConverter) packetValue.getKey()).from(value);
} else {
System.out.println("Possible type mismatch: " + value.getClass().getName() + " -> " + packetValue.getKey().getOutputClass());
}
}
}
packetValue.getKey().write(buffer, value);
} catch (Exception e) {
throw new InformativeException(e).set("Index", index).set("Type", packetValue.getKey().getTypeName()).set("Packet ID", getId()).set("Data", packetValues);
}
index++;
}
writeRemaining(buffer);
}
/**
* Clear the input buffer / readable objects
*/
public void clearInputBuffer() {
if (inputBuffer != null)
inputBuffer.clear();
readableObjects.clear(); // :(
}
/**
* Clear the packet, used if you have to change the packet completely
*/
public void clearPacket() {
clearInputBuffer();
packetValues.clear();
}
private void writeRemaining(ByteBuf output) {
if (inputBuffer != null) {
output.writeBytes(inputBuffer);
}
}
/**
* Send this packet to the associated user.
* Be careful not to send packets twice.
* (Sends it after current)
*
* @throws Exception if it fails to write
*/
public void send() throws Exception {
if (!isCancelled()) {
ByteBuf output = inputBuffer == null ? Unpooled.buffer() : inputBuffer.alloc().buffer();
writeToBuffer(output);
user().sendRawPacket(output);
}
}
/**
* Create a new packet for the target of this packet.
*
* @param packetID The ID of the new packet
* @return The newly created packet wrapper
*/
public PacketWrapper create(int packetID) {
return new PacketWrapper(packetID, null, user());
}
/**
* Create a new packet with values.
*
* @param packetID The ID of the new packet
* @param init A ValueCreator to write to the packet.
* @return The newly created packet wrapper
* @throws Exception If it failed to write the values from the ValueCreator.
*/
public PacketWrapper create(int packetID, ValueCreator init) throws Exception {
PacketWrapper wrapper = create(packetID);
init.write(wrapper);
return wrapper;
}
/**
* Cancel this packet from sending
*/
public void cancel() {
this.send = false;
}
/**
* Check if this packet is cancelled.
*
* @return True if the packet won't be sent.
*/
public boolean isCancelled() {
return !this.send;
}
/**
* Get the user associated with this Packet
*
* @return The user
*/
public UserConnection user() {
return this.userConnection;
}
/**
* Reset the reader, so that it can be read again.
*/
public void resetReader() {
this.readableObjects.addAll(packetValues);
this.packetValues.clear();
}
/**
* Send the current packet to the server.
* (Ensure the ID is suitable for the server version)
*
* @throws Exception If it failed to write
*/
public void sendToServer() throws Exception {
if (!isCancelled()) {
ByteBuf output = inputBuffer == null ? Unpooled.buffer() : inputBuffer.alloc().buffer();
Type.VAR_INT.write(output, ViaDecodeHandler.PASSTHROUGH_ID); // Pass through
writeToBuffer(output);
PipelineUtil.getContextBefore("decompress", user().getChannel().pipeline()).fireChannelRead(output);
}
}
@Override
public String toString() {
return "PacketWrapper{" +
"packetValues=" + packetValues +
", readableObjects=" + readableObjects +
", id=" + id +
'}';
}
}
@@ -0,0 +1,23 @@
package us.myles.ViaVersion.api;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@EqualsAndHashCode
public class Pair<X, Y> {
private X key;
private Y value;
public Pair(X key, Y value) {
this.key = key;
this.value = value;
}
@Override
public String toString() {
return "Pair{" + key + ", " + value + '}';
}
}
@@ -1,17 +1,19 @@
package us.myles.ViaVersion.api;
import lombok.Getter;
import org.apache.commons.lang.Validate;
import us.myles.ViaVersion.ViaVersionPlugin;
public class ViaVersion {
private static ViaVersionAPI INSTANCE;
@Getter
private static ViaVersionAPI instance;
@Getter
private static ViaVersionConfig config;
public static void setInstance(ViaVersionAPI api) {
if (INSTANCE != null) {
throw new IllegalStateException("Instance already set.");
}
INSTANCE = api;
}
public static ViaVersionAPI getInstance() {
return INSTANCE;
public static void setInstance(ViaVersionPlugin plugin) {
Validate.isTrue(instance == null, "Instance is already set");
ViaVersion.instance = plugin;
ViaVersion.config = plugin;
}
}
@@ -1,8 +1,112 @@
package us.myles.ViaVersion.api;
import io.netty.buffer.ByteBuf;
import org.bukkit.entity.Player;
import us.myles.ViaVersion.api.boss.BossBar;
import us.myles.ViaVersion.api.boss.BossColor;
import us.myles.ViaVersion.api.boss.BossStyle;
import us.myles.ViaVersion.api.command.ViaVersionCommand;
import java.util.UUID;
public interface ViaVersionAPI {
/**
* Is the player connection modified by ViaVersion?
*
* @param player Bukkit player object
* @return True if the client is modified (At the moment it also means version 1.9 and higher)
*/
boolean isPorted(Player player);
/**
* Get protocol number from a player
*
* @param player Bukkit player object
* @return Protocol ID, For example (47=1.8-1.8.8, 107=1.9, 108=1.9.1)
*/
int getPlayerVersion(Player player);
/**
* Get protocol number from a player
*
* @param uuid UUID of a player
* @return Protocol ID, For example (47=1.8-1.8.8, 107=1.9, 108=1.9.1)
*/
int getPlayerVersion(UUID uuid);
/**
* Is player using 1.9?
*
* @param playerUUID
* @return True if the client is on 1.9
*/
boolean isPorted(UUID playerUUID);
/**
* Get the version of the plugin
*
* @return Plugin version
*/
String getVersion();
/**
* Send a raw packet to the player (Use new IDs)
*
* @param player The player to send packet
* @param packet The packet, you need a VarInt ID then the packet contents.
* @throws IllegalArgumentException If not on 1.9 throws IllegalArg
*/
void sendRawPacket(Player player, ByteBuf packet) throws IllegalArgumentException;
/**
* Send a raw packet to the player (Use new IDs)
*
* @param uuid The uuid from the player to send packet
* @param packet The packet, you need a VarInt ID then the packet contents.
* @throws IllegalArgumentException If not on 1.9 throws IllegalArg
*/
void sendRawPacket(UUID uuid, ByteBuf packet) throws IllegalArgumentException;
/**
* Create a new bossbar instance
*
* @param title The title
* @param color The color
* @param style The style
* @return Bossbar instance
*/
BossBar createBossBar(String title, BossColor color, BossStyle style);
/**
* Create a new bossbar instance
*
* @param title The title
* @param health Number between 0 and 1
* @param color The color
* @param style The style
* @return Bossbar instance
*/
BossBar createBossBar(String title, float health, BossColor color, BossStyle style);
/**
* Get if global debug is enabled
*
* @return true if debug is enabled
*/
boolean isDebug();
/**
* Get ViaVersions command handler
*
* @return command handler
*/
ViaVersionCommand getCommandHandler();
/**
* Get if this version is a compatibility build for spigot.
* Eg. 1.9.1 / 1.9.2 allow certain versions to connect
*
* @return True if it is
*/
boolean isCompatSpigotBuild();
}
@@ -0,0 +1,152 @@
package us.myles.ViaVersion.api;
public interface ViaVersionConfig {
/**
* Get if global debug is enabled
*
* @return true if debug is enabled
*/
boolean isDebug();
/**
* Get if the plugin should check for updates
*
* @return true if update checking is enabled
*/
boolean isCheckForUpdates();
/**
* Get if collision preventing for players is enabled
*
* @return true if collision preventing is enabled
*/
boolean isPreventCollision();
/**
* Get if 1.9 clients are shown the new effect indicator in the top-right corner
*
* @return true if the using of the new effect indicator is enabled
*/
boolean isNewEffectIndicator();
/**
* Get if 1.9 clients are shown the new death message on the death screen
*
* @return true if enabled
*/
boolean isShowNewDeathMessages();
/**
* Get if metadata errors will be suppressed
*
* @return true if metadata errors suppression is enabled
*/
boolean isSuppressMetadataErrors();
/**
* Get if blocking in 1.9 appears as a player holding a shield
*
* @return true if shield blocking is enabled
*/
boolean isShieldBlocking();
/**
* Get if armor stand positions are fixed so holograms show up at the correct height in 1.9
*
* @return true if hologram patching is enabled
*/
boolean isHologramPatch();
/**
* Get if boss bars are fixed for 1.9 clients
*
* @return true if boss bar patching is enabled
*/
boolean isBossbarPatch();
/**
* Get if the boss bars for 1.9 clients are being stopped from flickering
* This will keep all boss bars on 100% (not recommended)
*
* @return true if boss bar anti flickering is enabled
*/
boolean isBossbarAntiflicker();
/**
* Get if unknown entity errors will be suppressed
*
* @return true if boss bar patching is enabled
*/
boolean isUnknownEntitiesSuppressed();
/**
* Get the vertical offset armor stands are being moved with when the hologram patch is enabled
*
* @return the vertical offset holograms will be moved with
*/
double getHologramYOffset();
/**
* Get if players will be automatically put in the same team when collision preventing is enabled
*
* @return true if automatic teaming is enabled
*/
boolean isAutoTeam();
/**
* Get if our block break patch is enabled to prevent weird ghost glitches.
*
* @return true if it is enabled.
*/
boolean isBlockBreakPatch();
/**
* Get the maximum number of packets a client can send per second.
*
* @return The number of packets a client can send per second.
*/
int getMaxPPS();
/**
* Get the kick message sent if the user hits the max packets per second.
*
* @return Kick message, with colour codes using '&'
*/
String getMaxPPSKickMessage();
/**
* The time in seconds that should be tracked for warnings
*
* @return Time in seconds that should be tracked for warnings
*/
int getTrackingPeriod();
/**
* The number of packets per second to count as a warning
*
* @return The number of packets per second to count as a warning.
*/
int getWarningPPS();
/**
* Get the maximum number of warnings the client can have in the interval
*
* @return The number of packets a client can send per second.
*/
int getMaxWarnings();
/**
* Get the kick message sent if the user goes over the warnings in the interval
*
* @return Kick message, with colour codes using '&'
*/
String getMaxWarningsKickMessage();
/**
* Is anti-xray enabled?
*
* @return A boolean
*/
boolean isAntiXRay();
}
@@ -0,0 +1,138 @@
package us.myles.ViaVersion.api.boss;
import org.bukkit.entity.Player;
import java.util.Set;
import java.util.UUID;
public interface BossBar {
/**
* Get the current title
*
* @return the title
*/
String getTitle();
/**
* Change the title
*
* @param title Title can be in either JSON or just text
*/
BossBar setTitle(String title);
/**
* Get the health
*
* @return float between 0F - 1F
*/
float getHealth();
/**
* Change the health
*
* @param health this float has to be between 0F - 1F
*/
BossBar setHealth(float health);
/**
* Get the bossbar color
*
* @return
*/
BossColor getColor();
/**
* Yay colors!
*
* @param color Whatever color you want!
*/
BossBar setColor(BossColor color);
/**
* Get the bosbar style
*
* @return BossStyle
*/
BossStyle getStyle();
/**
* Change the bosbar style
*
* @param style BossStyle
*/
BossBar setStyle(BossStyle style);
/**
* Show the bossbar to a player.
*
* @param player
*/
BossBar addPlayer(Player player);
/**
* Show the bossbar to a player (uuid)
*
* @param player uuid of the player
* @return the BossBar instance
*/
BossBar addPlayer(UUID player);
/**
* add multiple players
*
* @param players list of players
* @return the bossbar instance
*/
BossBar addPlayers(Player... players);
/**
* Remove the bossbar from a player
*
* @param player
*/
BossBar removePlayer(Player player);
/**
* Add flags
*
* @param flag
*/
BossBar addFlag(BossFlag flag);
/**
* Remove flags.
*
* @param flag
*/
BossBar removeFlag(BossFlag flag);
/**
* @param flag
* @return
*/
boolean hasFlag(BossFlag flag);
/**
* Get players
*
* @return UUIDS from players (sorry I lied)
*/
Set<UUID> getPlayers();
/**
* Show the bossbar to everyone (In the getPlayer set)
*/
BossBar show();
/**
* Hide the bossbar from everyone (In the getPlayer set)
*/
BossBar hide();
/**
* Is it visible?
*
* @return visibility changable with show() and hide()
*/
boolean isVisible();
}
@@ -0,0 +1,18 @@
package us.myles.ViaVersion.api.boss;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Getter
public enum BossColor {
PINK(0),
BLUE(1),
RED(2),
GREEN(3),
YELLOW(4),
PURPLE(5),
WHITE(6);
private final int id;
}
@@ -0,0 +1,13 @@
package us.myles.ViaVersion.api.boss;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Getter
public enum BossFlag {
DARKEN_SKY(1),
PLAY_BOSS_MUSIC(2);
private final int id;
}
@@ -0,0 +1,16 @@
package us.myles.ViaVersion.api.boss;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Getter
public enum BossStyle {
SOLID(0),
SEGMENTED_6(1),
SEGMENTED_10(2),
SEGMENTED_12(3),
SEGMENTED_20(4);
private final int id;
}
@@ -0,0 +1,77 @@
package us.myles.ViaVersion.api.command;
import org.bukkit.command.CommandSender;
import us.myles.ViaVersion.commands.ViaCommandHandler;
import java.util.Collections;
import java.util.List;
public abstract class ViaSubCommand {
/**
* Subcommand name
*
* @return your input
*/
public abstract String name();
/**
* subcommand description, this'll show in /viaversion list
*
* @return your input
*/
public abstract String description();
/**
* Usage example:
* "playerversion [name]"
*
* @return your input
*/
public String usage() {
return name();
}
/**
* Permission, null for everyone
*
* @return
*/
public String permission() {
return "viaversion.admin";
}
/**
* Gets triggered on execution
*
* @param sender Command sender
* @param args Arguments
* @return command executed succesfully if false, show usage
*/
public abstract boolean execute(CommandSender sender, String[] args);
/**
* Yay, possibility to implement tab-completion
*
* @param sender Command sender
* @param args args
* @return tab complete possibilities
*/
public List<String> onTabComplete(CommandSender sender, String[] args) {
return Collections.emptyList();
}
public String color(String s) {
return ViaCommandHandler.color(s);
}
/**
* Send message formatted / colored
*
* @param sender command sender
* @param message string message
* @param args optional objects
*/
public void sendMessage(CommandSender sender, String message, Object... args) {
ViaCommandHandler.sendMessage(sender, message, args);
}
}
@@ -0,0 +1,27 @@
package us.myles.ViaVersion.api.command;
public interface ViaVersionCommand {
/**
* Register your own subcommand inside ViaVersion
*
* @param command Your own SubCommand instance to handle it.
* @throws Exception throws an exception when the subcommand already exists or if it's not valid, example: spacee
*/
void registerSubCommand(ViaSubCommand command) throws Exception;
/**
* Check if a subcommand is registered.
*
* @param name Subcommand name
* @return true if it exists
*/
boolean hasSubCommand(String name);
/**
* Get subcommand instance by name
*
* @param name subcommand name
* @return ViaSubCommand instance
*/
ViaSubCommand getSubCommand(String name);
}
@@ -0,0 +1,11 @@
package us.myles.ViaVersion.api.data;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter(AccessLevel.PROTECTED)
@AllArgsConstructor
public class StoredObject {
private UserConnection user;
}
@@ -0,0 +1,147 @@
package us.myles.ViaVersion.api.data;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.socket.SocketChannel;
import lombok.Data;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@Data
public class UserConnection {
private final SocketChannel channel;
Map<Class, StoredObject> storedObjects = new ConcurrentHashMap<>();
private boolean active = true;
private boolean pendingDisconnect = false;
private Object lastPacket;
private long sentPackets = 0L;
private long receivedPackets = 0L;
// Used for tracking pps
private long startTime = 0L;
private long intervalPackets = 0L;
private long packetsPerSecond = -1L;
// Used for handling warnings (over time)
private int secondsObserved = 0;
private int warnings = 0;
public UserConnection(SocketChannel socketChannel) {
this.channel = socketChannel;
}
/**
* Get an object from the storage
*
* @param objectClass The class of the object to get
* @return The requested object
*/
public <T extends StoredObject> T get(Class<T> objectClass) {
return (T) storedObjects.get(objectClass);
}
/**
* Check if the storage has an object
*
* @param objectClass The object class to check
* @return True if the object is in the storage
*/
public boolean has(Class<? extends StoredObject> objectClass) {
return storedObjects.containsKey(objectClass);
}
/**
* Put an object into the stored objects based on class
*
* @param object The object to store.
*/
public void put(StoredObject object) {
storedObjects.put(object.getClass(), object);
}
/**
* Send a raw packet to the player
*
* @param packet The raw packet to send
* @param currentThread Should it run in the same thread
*/
public void sendRawPacket(final ByteBuf packet, boolean currentThread) {
final ChannelHandler handler = channel.pipeline().get("encoder");
if (currentThread) {
channel.pipeline().context(handler).writeAndFlush(packet);
} else {
channel.eventLoop().submit(new Runnable() {
@Override
public void run() {
channel.pipeline().context(handler).writeAndFlush(packet);
}
});
}
}
/**
* Send a raw packet to the player (netty thread)
*
* @param packet The packet to send
*/
public void sendRawPacket(final ByteBuf packet) {
sendRawPacket(packet, false);
}
/**
* Used for incrementing the number of packets sent to the client
*/
public void incrementSent() {
this.sentPackets++;
}
/**
* Used for incrementing the number of packets received from the client
*/
public boolean incrementReceived() {
// handle stats
Long diff = System.currentTimeMillis() - startTime;
if (diff >= 1000) {
packetsPerSecond = intervalPackets;
startTime = System.currentTimeMillis();
intervalPackets = 1;
return true;
} else {
intervalPackets++;
}
// increase total
this.receivedPackets++;
return false;
}
/**
* Disconnect a connection
*
* @param reason The reason to use, not used if player is not active.
*/
public void disconnect(final String reason) {
if(!getChannel().isOpen()) return;
if(pendingDisconnect) return;
pendingDisconnect = true;
if (get(ProtocolInfo.class).getUuid() != null) {
final UUID uuid = get(ProtocolInfo.class).getUuid();
if (Bukkit.getPlayer(uuid) != null) {
Bukkit.getScheduler().runTask(Bukkit.getPluginManager().getPlugin("ViaVersion"), new Runnable() {
@Override
public void run() {
Player player = Bukkit.getPlayer(uuid);
if (player != null)
player.kickPlayer(ChatColor.translateAlternateColorCodes('&', reason));
}
});
return;
}
}
getChannel().close(); // =)
}
}
@@ -0,0 +1,16 @@
package us.myles.ViaVersion.api.minecraft;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
@AllArgsConstructor
@Getter
@ToString
@EqualsAndHashCode
public class Position {
private Long x;
private Long y;
private Long z;
}
@@ -0,0 +1,38 @@
package us.myles.ViaVersion.api.minecraft.chunks;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
@RequiredArgsConstructor
@Getter
@ToString
public class Chunk {
private final int x;
private final int z;
private final boolean groundUp;
private final int primaryBitmask;
private final ChunkSection[] sections;
private final byte[] biomeData;
private boolean unloadPacket = false;
/**
* Chunk unload.
*
* @param x coord
* @param z coord
*/
public Chunk(int x, int z) {
this(x, z, true, 0, new ChunkSection[16], null);
this.unloadPacket = true;
}
/**
* Does this chunk have biome data
*
* @return True if the chunk has biome data
*/
public boolean hasBiomeData() {
return biomeData != null && groundUp;
}
}
@@ -0,0 +1,190 @@
package us.myles.ViaVersion.api.minecraft.chunks;
import com.google.common.collect.Lists;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import us.myles.ViaVersion.api.type.Type;
import java.util.List;
public class ChunkSection {
/**
* Size (dimensions) of blocks in a chunk section.
*/
public static final int SIZE = 16 * 16 * 16; // width * depth * height
/**
* Length of the sky and block light nibble arrays.
*/
public static final int LIGHT_LENGTH = 16 * 16 * 16 / 2; // size * size * size / 2 (nibble bit count)
/**
* Length of the block data array.
*/
private final List<Integer> palette = Lists.newArrayList();
private final int[] blocks;
private final NibbleArray blockLight;
private NibbleArray skyLight;
public ChunkSection() {
this.blocks = new int[SIZE];
this.blockLight = new NibbleArray(SIZE);
palette.add(0); // AIR
}
/**
* Set a block in the chunk
*
* @param x Block X
* @param y Block Y
* @param z Block Z
* @param type The type of the block
* @param data The data value of the block
*/
public void setBlock(int x, int y, int z, int type, int data) {
setBlock(index(x, y, z), type, data);
}
/**
* Set a block in the chunk based on the index
*
* @param idx Index
* @param type The type of the block
* @param data The data value of the block
*/
public void setBlock(int idx, int type, int data) {
int hash = type << 4 | (data & 0xF);
int index = palette.indexOf(hash);
if (index == -1) {
index = palette.size();
palette.add(hash);
}
blocks[idx] = index;
}
/**
* Set the block light array
*
* @param data The value to set the block light to
*/
public void setBlockLight(byte[] data) {
blockLight.setHandle(data);
}
/**
* Set the sky light array
*
* @param data The value to set the sky light to
*/
public void setSkyLight(byte[] data) {
if (data.length != LIGHT_LENGTH) throw new IllegalArgumentException("Data length != " + LIGHT_LENGTH);
this.skyLight = new NibbleArray(data);
}
private int index(int x, int y, int z) {
return z << 8 | y << 4 | x;
}
/**
* Write the blocks to a buffer.
*
* @param output The buffer to write to.
* @throws Exception Throws if it failed to write.
*/
public void writeBlocks(ByteBuf output) throws Exception {
// Write bits per block
int bitsPerBlock = 4;
while (palette.size() > 1 << bitsPerBlock) {
bitsPerBlock += 1;
}
long maxEntryValue = (1L << bitsPerBlock) - 1;
output.writeByte(bitsPerBlock);
// Write pallet (or not)
Type.VAR_INT.write(output, palette.size());
for (int mappedId : palette) {
Type.VAR_INT.write(output, mappedId);
}
int length = (int) Math.ceil(SIZE * bitsPerBlock / 64.0);
Type.VAR_INT.write(output, length);
long[] data = new long[length];
for (int index = 0; index < blocks.length; index++) {
int value = blocks[index];
int bitIndex = index * bitsPerBlock;
int startIndex = bitIndex / 64;
int endIndex = ((index + 1) * bitsPerBlock - 1) / 64;
int startBitSubIndex = bitIndex % 64;
data[startIndex] = data[startIndex] & ~(maxEntryValue << startBitSubIndex) | ((long) value & maxEntryValue) << startBitSubIndex;
if (startIndex != endIndex) {
int endBitSubIndex = 64 - startBitSubIndex;
data[endIndex] = data[endIndex] >>> endBitSubIndex << endBitSubIndex | ((long) value & maxEntryValue) >> endBitSubIndex;
}
}
for (long l : data) {
Type.LONG.write(output, l);
}
}
/**
* Write the block light to a buffer
*
* @param output The buffer to write to
*/
public void writeBlockLight(ByteBuf output) {
output.writeBytes(blockLight.getHandle());
}
/**
* Write the sky light to a buffer
*
* @param output The buffer to write to
*/
public void writeSkyLight(ByteBuf output) {
output.writeBytes(skyLight.getHandle());
}
/**
* Check if sky light is present
*
* @return True if skylight is present
*/
public boolean hasSkyLight() {
return skyLight != null;
}
/**
* Get expected size of this chunk section.
*
* @return Amount of bytes sent by this section
*/
public int getExpectedSize() throws Exception {
int bitsPerBlock = palette.size() > 255 ? 16 : 8;
int bytes = 1; // bits per block
bytes += paletteBytes(); // palette
bytes += countBytes(bitsPerBlock == 16 ? SIZE * 2 : SIZE); // block data length
bytes += (palette.size() > 255 ? 2 : 1) * SIZE; // block data
bytes += LIGHT_LENGTH; // block light
bytes += hasSkyLight() ? LIGHT_LENGTH : 0; // sky light
return bytes;
}
private int paletteBytes() throws Exception {
// Count bytes used by pallet
int bytes = countBytes(palette.size());
for (int mappedId : palette) {
bytes += countBytes(mappedId);
}
return bytes;
}
private int countBytes(int value) throws Exception {
// Count amount of bytes that would be sent if the value were sent as a VarInt
ByteBuf buf = Unpooled.buffer();
Type.VAR_INT.write(buf, value);
buf.readerIndex(0);
int bitCount = buf.readableBytes();
buf.release();
return bitCount;
}
}
@@ -0,0 +1,127 @@
package us.myles.ViaVersion.api.minecraft.chunks;
import java.util.Arrays;
public class NibbleArray {
private final byte[] handle;
public NibbleArray(int length) {
if (length == 0 || length % 2 != 0) {
throw new IllegalArgumentException("Length of nibble array must be a positive number dividable by 2!");
}
this.handle = new byte[length / 2];
}
public NibbleArray(byte[] handle) {
if (handle.length == 0 || handle.length % 2 != 0) {
throw new IllegalArgumentException("Length of nibble array must be a positive number dividable by 2!");
}
this.handle = handle;
}
/**
* Get the value at a desired X, Y, Z
*
* @param x Block X
* @param y Block Y
* @param z Block Z
* @return The value at the given XYZ
*/
public byte get(int x, int y, int z) {
return get(y << 8 | z << 4 | x);
}
/**
* Get the value at an index
*
* @param index The index to lookup
* @return The value at that index.
*/
public byte get(int index) {
byte value = handle[index / 2];
if (index % 2 == 0) {
return (byte) (value & 0xF);
} else {
return (byte) ((value >> 4) & 0xF);
}
}
/**
* Set the value based on an x, y, z
*
* @param x Block X
* @param y Block Y
* @param z Block Z
* @param value Desired Value
*/
public void set(int x, int y, int z, int value) {
set(y << 8 | z << 4 | x, value);
}
/**
* Set a value at an index
*
* @param index The index to set the value at.
* @param value The desired value
*/
public void set(int index, int value) {
index /= 2;
if (index % 2 == 0) {
handle[index] = (byte) (handle[index] & 0xF0 | value & 0xF);
} else {
handle[index] = (byte) (handle[index] & 0xF | (value & 0xF) << 4);
}
}
/**
* The size of this nibble
*
* @return The size as an int of the nibble
*/
public int size() {
return handle.length * 2;
}
/**
* Get the actual number of bytes
*
* @return The number of bytes based on the handle.
*/
public int actualSize() {
return handle.length;
}
/**
* Fill the array with a value
*
* @param value Value to fill with
*/
public void fill(byte value) {
value &= 0xF; // Max nibble size (= 16)
Arrays.fill(handle, (byte) ((value << 4) | value));
}
/**
* Get the byte array behind this nibble
*
* @return The byte array
*/
public byte[] getHandle() {
return handle;
}
/**
* Copy a byte array into this nibble
*
* @param handle The byte array to copy in.
*/
public void setHandle(byte[] handle) {
if (handle.length != this.handle.length) {
throw new IllegalArgumentException("Length of handle must equal to size of nibble array!");
}
System.arraycopy(handle, 0, this.handle, 0, handle.length);
}
}
@@ -0,0 +1,28 @@
package us.myles.ViaVersion.api.minecraft.item;
import lombok.*;
import org.bukkit.inventory.ItemStack;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Item {
private short id;
private byte amount;
private short data;
private CompoundTag tag;
/**
* Create an item from a bukkit stack (doesn't save NBT)
*
* @param stack The stack to convert from
* @return The output stack
*/
public static Item getItem(ItemStack stack) {
if (stack == null) return null;
return new Item((short) stack.getTypeId(), (byte) stack.getAmount(), stack.getDurability(), null);
}
}
@@ -0,0 +1,26 @@
package us.myles.ViaVersion.api.minecraft.metadata;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import us.myles.ViaVersion.api.type.Type;
@AllArgsConstructor
@Getter
@Setter
public class Metadata {
private int id;
private int typeID;
private Type type;
private Object value;
@Override
public String toString() {
return "Metadata{" +
"id=" + id +
", typeID=" + typeID +
", type=" + type +
", value=" + value +
'}';
}
}
@@ -0,0 +1,156 @@
package us.myles.ViaVersion.api.protocol;
import lombok.AllArgsConstructor;
import lombok.Getter;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.Pair;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.remapper.PacketRemapper;
import us.myles.ViaVersion.exception.CancelException;
import us.myles.ViaVersion.packets.Direction;
import us.myles.ViaVersion.packets.State;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public abstract class Protocol {
private Map<Pair<State, Integer>, ProtocolPacket> incoming = new HashMap<>();
private Map<Pair<State, Integer>, ProtocolPacket> outgoing = new HashMap<>();
public Protocol() {
registerPackets();
}
/**
* Should this protocol filter an object packet from this class.
* Default: false
*
* @param packetClass The class of the current input
* @return True if it should handle the filtering
*/
public boolean isFiltered(Class packetClass) {
return false;
}
/**
* Filter a packet into the output
*
* @param info The current user connection
* @param packet The input packet as an object (NMS)
* @param output The list to put the object into.
* @throws Exception Throws exception if cancelled / error.
*/
protected void filterPacket(UserConnection info, Object packet, List output) throws Exception {
output.add(packet);
}
/**
* Register listeners for this protocol
*/
protected void registerListeners() {
}
/**
* Register the packets for this protocol
*/
protected abstract void registerPackets();
/**
* Initialise a user for this protocol setting up objects.
*
* @param userConnection The user to initialise
*/
public abstract void init(UserConnection userConnection);
/**
* Register an incoming packet, with simple id transformation.
*
* @param state The state which the packet is sent in.
* @param oldPacketID The old packet ID
* @param newPacketID The new packet ID
*/
public void registerIncoming(State state, int oldPacketID, int newPacketID) {
registerIncoming(state, oldPacketID, newPacketID, null);
}
/**
* Register an incoming packet, with id transformation and remapper.
*
* @param state The state which the packet is sent in.
* @param oldPacketID The old packet ID
* @param newPacketID The new packet ID
* @param packetRemapper The remapper to use for the packet
*/
public void registerIncoming(State state, int oldPacketID, int newPacketID, PacketRemapper packetRemapper) {
ProtocolPacket protocolPacket = new ProtocolPacket(state, oldPacketID, newPacketID, packetRemapper);
incoming.put(new Pair<>(state, newPacketID), protocolPacket);
}
/**
* Register an outgoing packet, with simple id transformation.
*
* @param state The state which the packet is sent in.
* @param oldPacketID The old packet ID
* @param newPacketID The new packet ID
*/
public void registerOutgoing(State state, int oldPacketID, int newPacketID) {
registerOutgoing(state, oldPacketID, newPacketID, null);
}
/**
* Register an outgoing packet, with id transformation and remapper.
*
* @param state The state which the packet is sent in.
* @param oldPacketID The old packet ID
* @param newPacketID The new packet ID
* @param packetRemapper The remapper to use for the packet
*/
public void registerOutgoing(State state, int oldPacketID, int newPacketID, PacketRemapper packetRemapper) {
ProtocolPacket protocolPacket = new ProtocolPacket(state, oldPacketID, newPacketID, packetRemapper);
outgoing.put(new Pair<>(state, oldPacketID), protocolPacket);
}
/**
* Transform a packet using this protocol
*
* @param direction The direction the packet is going in
* @param state The current protocol state
* @param packetWrapper The packet wrapper to transform
* @throws Exception Throws exception if it fails to transform
*/
public void transform(Direction direction, State state, PacketWrapper packetWrapper) throws Exception {
Pair<State, Integer> statePacket = new Pair<>(state, packetWrapper.getId());
Map<Pair<State, Integer>, ProtocolPacket> packetMap = (direction == Direction.OUTGOING ? outgoing : incoming);
ProtocolPacket protocolPacket;
if (packetMap.containsKey(statePacket)) {
protocolPacket = packetMap.get(statePacket);
} else {
return;
}
// write packet id
int newID = direction == Direction.OUTGOING ? protocolPacket.getNewID() : protocolPacket.getOldID();
packetWrapper.setId(newID);
// remap
if (protocolPacket.getRemapper() != null) {
protocolPacket.getRemapper().remap(packetWrapper);
if (packetWrapper.isCancelled())
throw new CancelException();
}
}
@Override
public String toString() {
return "Protocol:" + getClass().getSimpleName();
}
@AllArgsConstructor
@Getter
class ProtocolPacket {
State state;
int oldID;
int newID;
PacketRemapper remapper;
}
}
@@ -0,0 +1,166 @@
package us.myles.ViaVersion.api.protocol;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.packets.Direction;
import us.myles.ViaVersion.packets.PacketType;
import us.myles.ViaVersion.packets.State;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
public class ProtocolPipeline extends Protocol {
List<Protocol> protocolList;
private UserConnection userConnection;
public ProtocolPipeline(UserConnection userConnection) {
super();
init(userConnection);
}
@Override
protected void registerPackets() {
protocolList = new CopyOnWriteArrayList<>();
// This is a pipeline so we register basic pipes
protocolList.add(ProtocolRegistry.BASE_PROTOCOL);
}
@Override
public void init(UserConnection userConnection) {
this.userConnection = userConnection;
ProtocolInfo protocolInfo = new ProtocolInfo(userConnection);
protocolInfo.setPipeline(this);
userConnection.put(protocolInfo);
/* Init through all our pipes */
for (Protocol protocol : protocolList) {
protocol.init(userConnection);
}
}
/**
* Add a protocol to the current pipeline
* This will call the .init method.
*
* @param protocol The protocol to add to the end
*/
public void add(Protocol protocol) {
if (protocolList != null) {
protocolList.add(protocol);
protocol.init(userConnection);
} else {
throw new NullPointerException("Tried to add protocol to early");
}
}
@Override
public void transform(Direction direction, State state, PacketWrapper packetWrapper) throws Exception {
int originalID = packetWrapper.getId();
List<Protocol> protocols = new ArrayList<>(protocolList);
// Other way if outgoing
if (direction == Direction.OUTGOING)
Collections.reverse(protocols);
for (Protocol protocol : protocols) { // Copy to prevent from removal.
protocol.transform(direction, state, packetWrapper);
// Reset the reader for the packetWrapper (So it can be recycled across packets)
packetWrapper.resetReader();
}
super.transform(direction, state, packetWrapper);
if (ViaVersion.getInstance().isDebug()) {
// Debug packet
String packet = "UNKNOWN";
// For 1.8/1.9 server version, eventually we'll probably get an API for this...
if (ProtocolRegistry.SERVER_PROTOCOL >= ProtocolVersion.v1_8.getId() &&
ProtocolRegistry.SERVER_PROTOCOL <= ProtocolVersion.v1_9_3.getId()) {
PacketType type;
if (ProtocolRegistry.SERVER_PROTOCOL <= ProtocolVersion.v1_8.getId()) {
if (direction == Direction.INCOMING) {
type = PacketType.findNewPacket(state, direction, originalID);
} else {
type = PacketType.findOldPacket(state, direction, originalID);
}
} else {
type = PacketType.findNewPacket(state, direction, originalID);
}
// Filter :) This would be not hard coded too, sorry :(
if (type == PacketType.PLAY_CHUNK_DATA) return;
if (type == PacketType.PLAY_TIME_UPDATE) return;
if (type == PacketType.PLAY_KEEP_ALIVE) return;
if (type == PacketType.PLAY_KEEP_ALIVE_REQUEST) return;
if (type == PacketType.PLAY_ENTITY_LOOK_MOVE) return;
if (type == PacketType.PLAY_ENTITY_LOOK) return;
if (type == PacketType.PLAY_ENTITY_RELATIVE_MOVE) return;
if (type == PacketType.PLAY_PLAYER_POSITION_LOOK_REQUEST) return;
if (type == PacketType.PLAY_PLAYER_LOOK_REQUEST) return;
if (type == PacketType.PLAY_PLAYER_POSITION_REQUEST) return;
packet = type.name();
}
String name = packet + "[" + userConnection.get(ProtocolInfo.class).getProtocolVersion() + "]";
ViaVersionPlugin plugin = (ViaVersionPlugin) ViaVersion.getInstance();
String actualUsername = packetWrapper.user().get(ProtocolInfo.class).getUsername();
String username = actualUsername != null ? actualUsername + " " : "";
plugin.getLogger().log(Level.INFO, "{0}{1}: {2} {3} -> {4} [{5}] Value: {6}",
new Object[]{
username,
direction,
state,
originalID,
packetWrapper.getId(),
name,
packetWrapper
});
}
}
/**
* Check if the pipeline contains a protocol
*
* @param pipeClass The class to check
* @return True if the protocol class is in the pipeline
*/
public boolean contains(Class<? extends Protocol> pipeClass) {
for (Protocol protocol : protocolList) {
if (protocol.getClass().equals(pipeClass)) return true;
}
return false;
}
/**
* Use the pipeline to filter a NMS packet
*
* @param o The NMS packet object
* @param list The output list to write to
* @return If it should not write the input object to te list.
* @throws Exception If it failed to convert / packet cancelld.
*/
public boolean filter(Object o, List list) throws Exception {
for (Protocol protocol : protocolList) {
if (protocol.isFiltered(o.getClass())) {
protocol.filterPacket(userConnection, o, list);
return true;
}
}
return false;
}
public List<Protocol> pipes() {
return protocolList;
}
}
@@ -0,0 +1,154 @@
package us.myles.ViaVersion.api.protocol;
import org.bukkit.Bukkit;
import us.myles.ViaVersion.api.Pair;
import us.myles.ViaVersion.protocols.base.BaseProtocol;
import us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3.Protocol1_9_1_2TO1_9_3;
import us.myles.ViaVersion.protocols.protocol1_9_1to1_9.Protocol1_9_1TO1_9;
import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.Protocol1_9_3TO1_9_1_2;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
import us.myles.ViaVersion.protocols.protocol1_9to1_9_1.Protocol1_9TO1_9_1;
import java.util.*;
public class ProtocolRegistry {
public static int SERVER_PROTOCOL = -1;
// Input Version -> Output Version & Protocol (Allows fast lookup)
private static Map<Integer, Map<Integer, Protocol>> registryMap = new HashMap<>();
private static Map<Pair<Integer, Integer>, List<Pair<Integer, Protocol>>> pathCache = new HashMap<>();
private static List<Protocol> registerList = new ArrayList<>();
public static final Protocol BASE_PROTOCOL = new BaseProtocol();
static {
// Base Protocol
registerProtocol(BASE_PROTOCOL, Arrays.<Integer>asList(), -1);
// Register built in protocols
registerProtocol(new Protocol1_9TO1_8(), Collections.singletonList(ProtocolVersion.v1_9.getId()), ProtocolVersion.v1_8.getId());
registerProtocol(new Protocol1_9_1TO1_9(), Arrays.asList(ProtocolVersion.v1_9_1.getId(), ProtocolVersion.v1_9_2.getId()), ProtocolVersion.v1_9.getId());
registerProtocol(new Protocol1_9_3TO1_9_1_2(), Arrays.asList(ProtocolVersion.v1_9_3.getId()), ProtocolVersion.v1_9_2.getId());
// Only supported for 1.9.4 server to 1.9 (nothing else)
registerProtocol(new Protocol1_9TO1_9_1(), Arrays.asList(ProtocolVersion.v1_9.getId()), ProtocolVersion.v1_9_2.getId());
registerProtocol(new Protocol1_9_1_2TO1_9_3(), Arrays.asList(ProtocolVersion.v1_9_1.getId(), ProtocolVersion.v1_9_2.getId()), ProtocolVersion.v1_9_3.getId());
}
/**
* Register a protocol
*
* @param protocol The protocol to register.
* @param supported Supported client versions.
* @param output The output server version it converts to.
*/
public static void registerProtocol(Protocol protocol, List<Integer> supported, Integer output) {
// Clear cache as this may make new routes.
if (pathCache.size() > 0)
pathCache.clear();
for (Integer version : supported) {
if (!registryMap.containsKey(version)) {
registryMap.put(version, new HashMap<Integer, Protocol>());
}
registryMap.get(version).put(output, protocol);
}
if (Bukkit.getPluginManager().getPlugin("ViaVersion").isEnabled()) {
protocol.registerListeners();
} else {
registerList.add(protocol);
}
}
/**
* Check if this plugin is useful to the server.
*
* @return True if there is a useful pipe
*/
public static boolean isWorkingPipe() {
for (Map<Integer, Protocol> maps : registryMap.values()) {
if (maps.containsKey(SERVER_PROTOCOL)) return true;
}
return false; // No destination for protocol
}
/**
* Called when the server is enabled, to register any non registered listeners.
*/
public static void registerListeners() {
for (Protocol protocol : registerList) {
protocol.registerListeners();
}
registerList.clear();
}
/**
* Calculate a path to get from an input protocol to the servers protocol.
*
* @param current The current items in the path
* @param clientVersion The current input version
* @param serverVersion The desired output version
* @return The path which has been generated, null if failed.
*/
private static List<Pair<Integer, Protocol>> getProtocolPath(List<Pair<Integer, Protocol>> current, int clientVersion, int serverVersion) {
if(clientVersion == serverVersion) return null; // We're already there
if (current.size() > 50) return null; // Fail safe, protocol too complicated.
// First check if there is any protocols for this
if (!registryMap.containsKey(clientVersion)) {
return null; // Not supported
}
// Next check there isn't an obvious path
Map<Integer, Protocol> inputMap = registryMap.get(clientVersion);
if (inputMap.containsKey(serverVersion)) {
current.add(new Pair<>(serverVersion, inputMap.get(serverVersion)));
return current; // Easy solution
}
// There might be a more advanced solution... So we'll see if any of the others can get us there
List<Pair<Integer, Protocol>> shortest = null;
for (Map.Entry<Integer, Protocol> entry : inputMap.entrySet()) {
// Ensure it wasn't caught by the other loop
if (!entry.getKey().equals(serverVersion)) {
Pair<Integer, Protocol> pair = new Pair<>(entry.getKey(), entry.getValue());
// Ensure no recursion
if (!current.contains(pair)) {
// Create a copy
List<Pair<Integer, Protocol>> newCurrent = new ArrayList<>(current);
newCurrent.add(pair);
// Calculate the rest of the protocol using the current
newCurrent = getProtocolPath(newCurrent, entry.getKey(), serverVersion);
if (newCurrent != null) {
// If it's shorter then choose it
if (shortest == null || shortest.size() > newCurrent.size()) {
shortest = newCurrent;
}
}
}
}
}
return shortest; // null if none found
}
/**
* Calculate a path from a client version to server version
*
* @param clientVersion The input client version
* @param serverVersion The desired output server version
* @return The path it generated, null if it failed.
*/
public static List<Pair<Integer, Protocol>> getProtocolPath(int clientVersion, int serverVersion) {
Pair<Integer, Integer> protocolKey = new Pair<>(clientVersion, serverVersion);
// Check cache
if (pathCache.containsKey(protocolKey)) {
return pathCache.get(protocolKey);
}
// Generate path
List<Pair<Integer, Protocol>> outputPath = getProtocolPath(new ArrayList<Pair<Integer, Protocol>>(), clientVersion, serverVersion);
// If it found a path, cache it.
if (outputPath != null) {
pathCache.put(protocolKey, outputPath);
}
return outputPath;
}
}
@@ -0,0 +1,52 @@
package us.myles.ViaVersion.api.protocol;
import lombok.Data;
import lombok.NonNull;
import java.util.*;
@Data
public class ProtocolVersion {
private static final Map<Integer, ProtocolVersion> versions = new HashMap<>();
public static final ProtocolVersion v1_7_1;
public static final ProtocolVersion v1_7_6;
public static final ProtocolVersion v1_8;
public static final ProtocolVersion v1_9;
public static final ProtocolVersion v1_9_1;
public static final ProtocolVersion v1_9_2;
public static final ProtocolVersion v1_9_3;
private final int id;
private final String name;
static {
register(v1_7_1 = new ProtocolVersion(4, "1.7-1.7.5"));
register(v1_7_6 = new ProtocolVersion(5, "1.7.6-1.7.10"));
register(v1_8 = new ProtocolVersion(47, "1.8.x"));
register(v1_9 = new ProtocolVersion(107, "1.9"));
register(v1_9_1 = new ProtocolVersion(108, "1.9.1"));
register(v1_9_2 = new ProtocolVersion(109, "1.9.2"));
register(v1_9_3 = new ProtocolVersion(110, "1.9.3"));
}
public static void register(@NonNull ProtocolVersion protocol) {
versions.put(protocol.getId(), protocol);
}
public static boolean isRegistered(int id) {
return versions.containsKey(id);
}
public static ProtocolVersion getProtocol(int id) {
if (versions.containsKey(id)) {
return versions.get(id);
} else {
return new ProtocolVersion(id, "Unknown (" + id + ")");
}
}
public static List<ProtocolVersion> getProtocols() {
return Collections.unmodifiableList(new ArrayList<ProtocolVersion>(versions.values()));
}
}
@@ -0,0 +1,24 @@
package us.myles.ViaVersion.api.remapper;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.exception.InformativeException;
public abstract class PacketHandler implements ValueWriter {
/**
* Handle a packet
*
* @param wrapper The associated wrapper
* @throws Exception Throws exception if it failed to handle the packet
*/
public abstract void handle(PacketWrapper wrapper) throws Exception;
@Override
public void write(PacketWrapper writer, Object inputValue) throws Exception {
try {
handle(writer);
} catch (InformativeException e) {
e.addSource(this.getClass());
throw e;
}
}
}
@@ -0,0 +1,101 @@
package us.myles.ViaVersion.api.remapper;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.Pair;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.exception.InformativeException;
import java.util.ArrayList;
import java.util.List;
public abstract class PacketRemapper {
private List<Pair<ValueReader, ValueWriter>> valueRemappers = new ArrayList<>();
public PacketRemapper() {
registerMap();
}
/**
* Map a type to the same type.
*
* @param type Type to map
*/
public void map(Type type) {
TypeRemapper remapper = new TypeRemapper(type);
map(remapper, remapper);
}
/**
* Map a type from an old type to a new type
*
* @param oldType The old type
* @param newType The new type
*/
public void map(Type oldType, Type newType) {
map(new TypeRemapper(oldType), new TypeRemapper(newType));
}
/**
* Map a type from an old type to a transformed new type.
*
* @param oldType The old type
* @param transformer The transformer to use to produce the new type.
*/
public <T1, T2> void map(Type<T1> oldType, ValueTransformer<T1, T2> transformer) {
map(new TypeRemapper(oldType), transformer);
}
/**
* Map a type using a basic ValueReader to a ValueWriter
*
* @param inputReader The reader to read with.
* @param outputWriter The writer to write with.
*/
public <T> void map(ValueReader<T> inputReader, ValueWriter<T> outputWriter) {
valueRemappers.add(new Pair<ValueReader, ValueWriter>(inputReader, outputWriter));
}
/**
* Create a value
*
* @param creator The creator to used to make the value(s).
*/
public void create(ValueCreator creator) {
map(new TypeRemapper(Type.NOTHING), creator);
}
/**
* Create a handler
*
* @param handler The handler to use to handle the current packet.
*/
public void handler(PacketHandler handler) {
map(new TypeRemapper(Type.NOTHING), handler);
}
/**
* Register the mappings for this packet
*/
public abstract void registerMap();
/**
* Remap a packet wrapper
*
* @param packetWrapper The wrapper to remap
* @throws Exception Throws if it fails to write / read to the packet.
*/
public void remap(PacketWrapper packetWrapper) throws Exception {
try {
// Read all the current values
for (Pair<ValueReader, ValueWriter> valueRemapper : valueRemappers) {
Object object = valueRemapper.getKey().read(packetWrapper);
// Convert object to write type :O!!!
valueRemapper.getValue().write(packetWrapper, object);
}
// If we had handlers we'd put them here
} catch (InformativeException e) {
e.addSource(this.getClass());
throw e;
}
}
}
@@ -0,0 +1,22 @@
package us.myles.ViaVersion.api.remapper;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.type.Type;
public class TypeRemapper<T> implements ValueReader<T>, ValueWriter<T> {
private final Type<T> type;
public TypeRemapper(Type<T> type) {
this.type = type;
}
@Override
public T read(PacketWrapper wrapper) throws Exception {
return wrapper.read(type);
}
@Override
public void write(PacketWrapper output, T inputValue) {
output.write(type, inputValue);
}
}
@@ -0,0 +1,24 @@
package us.myles.ViaVersion.api.remapper;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.exception.InformativeException;
public abstract class ValueCreator implements ValueWriter {
/**
* Write new values to a Packet.
*
* @param wrapper The packet to write to
* @throws Exception Throws exception if it fails to write.
*/
public abstract void write(PacketWrapper wrapper) throws Exception;
@Override
public void write(PacketWrapper writer, Object inputValue) throws Exception {
try {
write(writer);
} catch (InformativeException e) {
e.addSource(this.getClass());
throw e;
}
}
}
@@ -0,0 +1,14 @@
package us.myles.ViaVersion.api.remapper;
import us.myles.ViaVersion.api.PacketWrapper;
public interface ValueReader<T> {
/**
* Reads value from a PacketWrapper
*
* @param wrapper The wrapper to read from
* @return Returns the desired type
* @throws Exception Throws exception if it fails to read
*/
T read(PacketWrapper wrapper) throws Exception;
}
@@ -0,0 +1,33 @@
package us.myles.ViaVersion.api.remapper;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.exception.InformativeException;
public abstract class ValueTransformer<T1, T2> implements ValueWriter<T1> {
private final Type<T2> outputType;
public ValueTransformer(Type<T2> outputType) {
this.outputType = outputType;
}
/**
* Transform a value from one type to another
*
* @param wrapper The current packet
* @param inputValue The input value
* @return The value to write to the wrapper
* @throws Exception Throws exception if it fails to transform a value
*/
public abstract T2 transform(PacketWrapper wrapper, T1 inputValue) throws Exception;
@Override
public void write(PacketWrapper writer, T1 inputValue) throws Exception {
try {
writer.write(outputType, transform(writer, inputValue));
} catch (InformativeException e) {
e.addSource(this.getClass());
throw e;
}
}
}
@@ -0,0 +1,14 @@
package us.myles.ViaVersion.api.remapper;
import us.myles.ViaVersion.api.PacketWrapper;
public interface ValueWriter<T> {
/**
* Write a value to a packet
*
* @param writer The packet wrapper to write to
* @param inputValue The value to write
* @throws Exception Throws exception if it fails to write
*/
void write(PacketWrapper writer, T inputValue) throws Exception;
}
@@ -0,0 +1,14 @@
package us.myles.ViaVersion.api.type;
import io.netty.buffer.ByteBuf;
public interface ByteBufReader<T> {
/**
* Read a value from a ByteBuf
*
* @param buffer The buffer to read from.
* @return The type based on the class type.
* @throws Exception Throws exception if it failed reading.
*/
T read(ByteBuf buffer) throws Exception;
}
@@ -0,0 +1,14 @@
package us.myles.ViaVersion.api.type;
import io.netty.buffer.ByteBuf;
public interface ByteBufWriter<T> {
/**
* Write an object to a type to a ByteBuf
*
* @param buffer The buffer to write to
* @param object The object to write
* @throws Exception Throws if it failed to write
*/
void write(ByteBuf buffer, T object) throws Exception;
}
@@ -0,0 +1,26 @@
package us.myles.ViaVersion.api.type;
import io.netty.buffer.ByteBuf;
public abstract class PartialType<T, X> extends Type<T> {
private final X param;
public PartialType(X param, Class<T> type) {
super(type);
this.param = param;
}
public abstract T read(ByteBuf buffer, X param) throws Exception;
public abstract void write(ByteBuf buffer, X param, T object) throws Exception;
@Override
public T read(ByteBuf buffer) throws Exception {
return read(buffer, this.param);
}
@Override
public void write(ByteBuf buffer, T object) throws Exception {
write(buffer, this.param, object);
}
}
@@ -0,0 +1,85 @@
package us.myles.ViaVersion.api.type;
import lombok.Getter;
import org.bukkit.util.EulerAngle;
import org.bukkit.util.Vector;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
import us.myles.ViaVersion.api.minecraft.Position;
import us.myles.ViaVersion.api.minecraft.item.Item;
import us.myles.ViaVersion.api.type.types.*;
import us.myles.ViaVersion.api.type.types.minecraft.*;
import java.util.UUID;
@Getter
public abstract class Type<T> implements ByteBufReader<T>, ByteBufWriter<T> {
/* Defined Types */
public static final Type<Byte> BYTE = new ByteType();
public static final Type<Byte[]> BYTE_ARRAY = new ArrayType<>(Type.BYTE);
public static final Type<byte[]> REMAINING_BYTES = new RemainingBytesType();
public static final Type<Short> UNSIGNED_BYTE = new UnsignedByteType();
public static final Type<Short[]> UNSIGNED_BYTE_ARRAY = new ArrayType<>(Type.UNSIGNED_BYTE);
public static final Type<Boolean> BOOLEAN = new BooleanType();
public static final Type<Boolean[]> BOOLEAN_ARRAY = new ArrayType<>(Type.BOOLEAN);
/* Number Types */
public static final Type<Integer> INT = new IntType();
public static final Type<Integer[]> INT_ARRAY = new ArrayType<>(Type.INT);
public static final Type<Double> DOUBLE = new DoubleType();
public static final Type<Double[]> DOUBLE_ARRAY = new ArrayType<>(Type.DOUBLE);
public static final Type<Long> LONG = new LongType();
public static final Type<Long[]> LONG_ARRAY = new ArrayType<>(Type.LONG);
public static final Type<Float> FLOAT = new FloatType();
public static final Type<Float[]> FLOAT_ARRAY = new ArrayType<>(Type.FLOAT);
public static final Type<Short> SHORT = new ShortType();
public static final Type<Short[]> SHORT_ARRAY = new ArrayType<>(Type.SHORT);
public static final Type<Integer> UNSIGNED_SHORT = new UnsignedShortType();
public static final Type<Integer[]> UNSIGNED_SHORT_ARRAY = new ArrayType<>(Type.UNSIGNED_SHORT);
/* Other Types */
public static final Type<String> STRING = new StringType();
public static final Type<String[]> STRING_ARRAY = new ArrayType<>(Type.STRING);
public static final Type<UUID> UUID = new UUIDType();
public static final Type<UUID[]> UUID_ARRAY = new ArrayType<>(Type.UUID);
/* Variable Types */
public static final Type<Integer> VAR_INT = new VarIntType();
public static final Type<Integer[]> VAR_INT_ARRAY = new ArrayType<>(Type.VAR_INT);
/* Special Types */
public static final Type<Void> NOTHING = new VoidType(); // This is purely used for remapping.
/* MC Types */
public static final Type<Position> POSITION = new PositionType();
public static final Type<EulerAngle> ROTATION = new EulerAngleType();
public static final Type<Vector> VECTOR = new VectorType();
public static final Type<CompoundTag> NBT = new NBTType();
public static final Type<UUID> OPTIONAL_UUID = new OptUUIDType();
public static final Type<Item> ITEM = new ItemType();
public static final Type<Item[]> ITEM_ARRAY = new ItemArrayType();
/* Actual Class */
private final Class<? super T> outputClass;
private final String typeName;
public Type(Class<? super T> outputClass) {
this(outputClass.getSimpleName(), outputClass);
}
public Type(String typeName, Class<? super T> outputClass) {
this.outputClass = outputClass;
this.typeName = typeName;
}
@Override
public String toString() {
return "Type|" + getTypeName();
}
}
@@ -0,0 +1,11 @@
package us.myles.ViaVersion.api.type;
public interface TypeConverter<T> {
/**
* Convert from a type to the current type
*
* @param o The input object
* @return The converted type as an object
*/
T from(Object o);
}
@@ -0,0 +1,68 @@
package us.myles.ViaVersion.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.type.Type;
import java.lang.reflect.Array;
public class ArrayType<T> extends Type<T[]> {
private final Type<T> elementType;
public ArrayType(Type<T> type) {
super(type.getTypeName() + " Array", (Class<T[]>) getArrayClass(type.getOutputClass()));
this.elementType = type;
}
/* Taken from http://stackoverflow.com/questions/4901128/obtaining-the-array-class-of-a-component-type */
public static Class<?> getArrayClass(Class<?> componentType) {
ClassLoader classLoader = componentType.getClassLoader();
String name;
if (componentType.isArray()) {
// just add a leading "["
name = "[" + componentType.getName();
} else if (componentType == boolean.class) {
name = "[Z";
} else if (componentType == byte.class) {
name = "[B";
} else if (componentType == char.class) {
name = "[C";
} else if (componentType == double.class) {
name = "[D";
} else if (componentType == float.class) {
name = "[F";
} else if (componentType == int.class) {
name = "[I";
} else if (componentType == long.class) {
name = "[J";
} else if (componentType == short.class) {
name = "[S";
} else {
// must be an object non-array class
name = "[L" + componentType.getName() + ";";
}
try {
return classLoader != null ? classLoader.loadClass(name) : Class.forName(name);
} catch (ClassNotFoundException e) {
return null; // oh
}
}
@Override
public T[] read(ByteBuf buffer) throws Exception {
int amount = Type.VAR_INT.read(buffer);
T[] array = (T[]) Array.newInstance(elementType.getOutputClass(), amount);
for (int i = 0; i < amount; i++) {
array[i] = elementType.read(buffer);
}
return array;
}
@Override
public void write(ByteBuf buffer, T[] object) throws Exception {
Type.VAR_INT.write(buffer, object.length);
for (T o : object) {
elementType.write(buffer, o);
}
}
}
@@ -0,0 +1,30 @@
package us.myles.ViaVersion.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.api.type.TypeConverter;
public class BooleanType extends Type<Boolean> implements TypeConverter<Boolean> {
public BooleanType() {
super(Boolean.class);
}
@Override
public Boolean read(ByteBuf buffer) {
return buffer.readBoolean();
}
@Override
public void write(ByteBuf buffer, Boolean object) {
buffer.writeBoolean(object);
}
@Override
public Boolean from(Object o) {
if (o instanceof Number) {
return ((Number) o).intValue() == 1;
}
return (Boolean) o;
}
}
@@ -0,0 +1,33 @@
package us.myles.ViaVersion.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.api.type.TypeConverter;
public class ByteType extends Type<Byte> implements TypeConverter<Byte> {
public ByteType() {
super(Byte.class);
}
@Override
public Byte read(ByteBuf buffer) {
return buffer.readByte();
}
@Override
public void write(ByteBuf buffer, Byte object) {
buffer.writeByte(object);
}
@Override
public Byte from(Object o) {
if (o instanceof Number) {
return ((Number) o).byteValue();
}
if (o instanceof Boolean) {
return (Boolean) o ? (byte) 1 : 0;
}
return (Byte) o;
}
}
@@ -0,0 +1,32 @@
package us.myles.ViaVersion.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.api.type.TypeConverter;
public class DoubleType extends Type<Double> implements TypeConverter<Double> {
public DoubleType() {
super(Double.class);
}
@Override
public Double read(ByteBuf buffer) {
return buffer.readDouble();
}
@Override
public void write(ByteBuf buffer, Double object) {
buffer.writeDouble(object);
}
@Override
public Double from(Object o) {
if (o instanceof Number) {
return ((Number) o).doubleValue();
}
if (o instanceof Boolean) {
return (Boolean) o ? (byte) 1D : 0D;
}
return (Double) o;
}
}
@@ -0,0 +1,33 @@
package us.myles.ViaVersion.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.api.type.TypeConverter;
public class FloatType extends Type<Float> implements TypeConverter<Float> {
public FloatType() {
super(Float.class);
}
@Override
public Float read(ByteBuf buffer) {
return buffer.readFloat();
}
@Override
public void write(ByteBuf buffer, Float object) {
buffer.writeFloat(object);
}
@Override
public Float from(Object o) {
if (o instanceof Number) {
return ((Number) o).floatValue();
}
if (o instanceof Boolean) {
return ((Boolean) o) ? 1F : 0;
}
return (Float) o;
}
}
@@ -0,0 +1,32 @@
package us.myles.ViaVersion.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.api.type.TypeConverter;
public class IntType extends Type<Integer> implements TypeConverter<Integer> {
public IntType() {
super(Integer.class);
}
@Override
public Integer read(ByteBuf buffer) {
return buffer.readInt();
}
@Override
public void write(ByteBuf buffer, Integer object) {
buffer.writeInt(object);
}
@Override
public Integer from(Object o) {
if (o instanceof Number) {
return ((Number) o).intValue();
}
if (o instanceof Boolean) {
return ((Boolean) o) ? 1 : 0;
}
return (Integer) o;
}
}
@@ -0,0 +1,33 @@
package us.myles.ViaVersion.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.api.type.TypeConverter;
public class LongType extends Type<Long> implements TypeConverter<Long> {
public LongType() {
super(Long.class);
}
@Override
public Long read(ByteBuf buffer) {
return buffer.readLong();
}
@Override
public void write(ByteBuf buffer, Long object) {
buffer.writeLong(object);
}
@Override
public Long from(Object o) {
if (o instanceof Number) {
return ((Number) o).longValue();
}
if (o instanceof Boolean) {
return ((Boolean) o) ? 1L : 0;
}
return (Long) o;
}
}
@@ -0,0 +1,22 @@
package us.myles.ViaVersion.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.type.Type;
public class RemainingBytesType extends Type<byte[]> {
public RemainingBytesType() {
super(byte[].class);
}
@Override
public byte[] read(ByteBuf buffer) {
byte[] array = new byte[buffer.readableBytes()];
buffer.readBytes(array);
return array;
}
@Override
public void write(ByteBuf buffer, byte[] object) {
buffer.writeBytes(object);
}
}
@@ -0,0 +1,32 @@
package us.myles.ViaVersion.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.api.type.TypeConverter;
public class ShortType extends Type<Short> implements TypeConverter<Short> {
public ShortType() {
super(Short.class);
}
@Override
public Short read(ByteBuf buffer) {
return buffer.readShort();
}
@Override
public void write(ByteBuf buffer, Short object) {
buffer.writeShort(object);
}
@Override
public Short from(Object o) {
if (o instanceof Number) {
return ((Number) o).shortValue();
}
if (o instanceof Boolean) {
return ((Boolean) o) ? (short) 1 : 0;
}
return (short) o;
}
}
@@ -0,0 +1,32 @@
package us.myles.ViaVersion.api.type.types;
import com.google.common.base.Charsets;
import com.google.common.base.Preconditions;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.type.Type;
public class StringType extends Type<String> {
public StringType() {
super(String.class);
}
@Override
public String read(ByteBuf buffer) throws Exception {
int len = Type.VAR_INT.read(buffer);
Preconditions.checkArgument(len <= Short.MAX_VALUE, "Cannot receive string longer than Short.MAX_VALUE (got %s characters)", len);
byte[] b = new byte[len];
buffer.readBytes(b);
return new String(b, Charsets.UTF_8);
}
@Override
public void write(ByteBuf buffer, String object) throws Exception {
Preconditions.checkArgument(object.length() <= Short.MAX_VALUE, "Cannot send string longer than Short.MAX_VALUE (got %s characters)", object.length());
byte[] b = object.getBytes(Charsets.UTF_8);
Type.VAR_INT.write(buffer, b.length);
buffer.writeBytes(b);
}
}
@@ -0,0 +1,23 @@
package us.myles.ViaVersion.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.type.Type;
import java.util.UUID;
public class UUIDType extends Type<UUID> {
public UUIDType() {
super(UUID.class);
}
@Override
public UUID read(ByteBuf buffer) {
return new UUID(buffer.readLong(), buffer.readLong());
}
@Override
public void write(ByteBuf buffer, UUID object) {
buffer.writeLong(object.getMostSignificantBits());
buffer.writeLong(object.getLeastSignificantBits());
}
}
@@ -0,0 +1,32 @@
package us.myles.ViaVersion.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.api.type.TypeConverter;
public class UnsignedByteType extends Type<Short> implements TypeConverter<Short> {
public UnsignedByteType() {
super(Short.class);
}
@Override
public Short read(ByteBuf buffer) {
return buffer.readUnsignedByte();
}
@Override
public void write(ByteBuf buffer, Short object) {
buffer.writeByte(object);
}
@Override
public Short from(Object o) {
if (o instanceof Number) {
return ((Number) o).shortValue();
}
if (o instanceof Boolean) {
return ((Boolean) o) ? (short) 1 : 0;
}
return (short) o;
}
}
@@ -0,0 +1,32 @@
package us.myles.ViaVersion.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.api.type.TypeConverter;
public class UnsignedShortType extends Type<Integer> implements TypeConverter<Integer> {
public UnsignedShortType() {
super(Integer.class);
}
@Override
public Integer read(ByteBuf buffer) {
return buffer.readUnsignedShort();
}
@Override
public void write(ByteBuf buffer, Integer object) {
buffer.writeShort(object);
}
@Override
public Integer from(Object o) {
if (o instanceof Number) {
return ((Number) o).intValue();
}
if (o instanceof Boolean) {
return ((Boolean) o) ? 1 : 0;
}
return (Integer) o;
}
}
@@ -0,0 +1,65 @@
package us.myles.ViaVersion.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.api.type.TypeConverter;
public class VarIntType extends Type<Integer> implements TypeConverter<Integer> {
public VarIntType() {
super("VarInt", Integer.class);
}
@Override
public void write(ByteBuf buffer, Integer object) {
int part;
while (true) {
part = object & 0x7F;
object >>>= 7;
if (object != 0) {
part |= 0x80;
}
buffer.writeByte(part);
if (object == 0) {
break;
}
}
}
@Override
public Integer read(ByteBuf buffer) {
int out = 0;
int bytes = 0;
byte in;
while (true) {
in = buffer.readByte();
out |= (in & 0x7F) << (bytes++ * 7);
if (bytes > 5) { // 5 is maxBytes
throw new RuntimeException("VarInt too big");
}
if ((in & 0x80) != 0x80) {
break;
}
}
return out;
}
@Override
public Integer from(Object o) {
if (o instanceof Number) {
return ((Number) o).intValue();
}
if (o instanceof Boolean) {
return ((Boolean) o) ? 1 : 0;
}
return (Integer) o;
}
}
@@ -0,0 +1,26 @@
package us.myles.ViaVersion.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.api.type.TypeConverter;
public class VoidType extends Type<Void> implements TypeConverter<Void> {
public VoidType() {
super(Void.class);
}
@Override
public Void read(ByteBuf buffer) {
return null;
}
@Override
public void write(ByteBuf buffer, Void object) {
}
@Override
public Void from(Object o) {
return null;
}
}
@@ -0,0 +1,27 @@
package us.myles.ViaVersion.api.type.types.minecraft;
import io.netty.buffer.ByteBuf;
import org.bukkit.util.EulerAngle;
import us.myles.ViaVersion.api.type.Type;
public class EulerAngleType extends Type<EulerAngle> {
public EulerAngleType() {
super(EulerAngle.class);
}
@Override
public EulerAngle read(ByteBuf buffer) throws Exception {
float x = Type.FLOAT.read(buffer);
float y = Type.FLOAT.read(buffer);
float z = Type.FLOAT.read(buffer);
return new EulerAngle(x, y, z);
}
@Override
public void write(ByteBuf buffer, EulerAngle object) throws Exception {
Type.FLOAT.write(buffer, (float) object.getX());
Type.FLOAT.write(buffer, (float) object.getY());
Type.FLOAT.write(buffer, (float) object.getZ());
}
}
@@ -0,0 +1,30 @@
package us.myles.ViaVersion.api.type.types.minecraft;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.minecraft.item.Item;
import us.myles.ViaVersion.api.type.Type;
public class ItemArrayType extends Type<Item[]> {
public ItemArrayType() {
super("Item Array", Item[].class);
}
@Override
public Item[] read(ByteBuf buffer) throws Exception {
int amount = Type.SHORT.read(buffer);
Item[] array = new Item[amount];
for (int i = 0; i < amount; i++) {
array[i] = Type.ITEM.read(buffer);
}
return array;
}
@Override
public void write(ByteBuf buffer, Item[] object) throws Exception {
Type.SHORT.write(buffer, (short) object.length);
for (Item o : object) {
Type.ITEM.write(buffer, o);
}
}
}
@@ -0,0 +1,38 @@
package us.myles.ViaVersion.api.type.types.minecraft;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.minecraft.item.Item;
import us.myles.ViaVersion.api.type.Type;
public class ItemType extends Type<Item> {
public ItemType() {
super(Item.class);
}
@Override
public Item read(ByteBuf buffer) throws Exception {
short id = buffer.readShort();
if (id < 0) {
return null;
} else {
Item item = new Item();
item.setId(id);
item.setAmount(buffer.readByte());
item.setData(buffer.readShort());
item.setTag(Type.NBT.read(buffer));
return item;
}
}
@Override
public void write(ByteBuf buffer, Item object) throws Exception {
if (object == null) {
buffer.writeShort(-1);
} else {
buffer.writeShort(object.getId());
buffer.writeByte(object.getAmount());
buffer.writeShort(object.getData());
Type.NBT.write(buffer, object.getTag());
}
}
}
@@ -0,0 +1,49 @@
package us.myles.ViaVersion.api.type.types.minecraft;
import com.google.common.base.Preconditions;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.ByteBufOutputStream;
import org.spacehq.opennbt.NBTIO;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
import us.myles.ViaVersion.api.type.Type;
import java.io.DataInputStream;
import java.io.DataOutputStream;
public class NBTType extends Type<CompoundTag> {
public NBTType() {
super(CompoundTag.class);
}
@Override
public CompoundTag read(ByteBuf buffer) throws Exception {
Preconditions.checkArgument(buffer.readableBytes() <= 2097152, "Cannot read NBT (got %s bytes)", buffer.readableBytes());
int readerIndex = buffer.readerIndex();
byte b = buffer.readByte();
if (b == 0) {
return null;
} else {
buffer.readerIndex(readerIndex);
ByteBufInputStream bytebufStream = new ByteBufInputStream(buffer);
try (DataInputStream dataInputStream = new DataInputStream(bytebufStream)) {
return (CompoundTag) NBTIO.readTag(dataInputStream);
}
}
}
@Override
public void write(ByteBuf buffer, CompoundTag object) throws Exception {
if (object == null) {
buffer.writeByte(0);
} else {
ByteBufOutputStream bytebufStream = new ByteBufOutputStream(buffer);
DataOutputStream dataOutputStream = new DataOutputStream(bytebufStream);
NBTIO.writeTag(dataOutputStream, object);
dataOutputStream.close();
}
}
}
@@ -0,0 +1,30 @@
package us.myles.ViaVersion.api.type.types.minecraft;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.type.Type;
import java.util.UUID;
public class OptUUIDType extends Type<UUID> {
public OptUUIDType() {
super(UUID.class);
}
@Override
public UUID read(ByteBuf buffer) {
boolean present = buffer.readBoolean();
if (!present) return null;
return new UUID(buffer.readLong(), buffer.readLong());
}
@Override
public void write(ByteBuf buffer, UUID object) {
if (object == null) {
buffer.writeBoolean(false);
} else {
buffer.writeBoolean(true);
buffer.writeLong(object.getMostSignificantBits());
buffer.writeLong(object.getLeastSignificantBits());
}
}
}
@@ -0,0 +1,27 @@
package us.myles.ViaVersion.api.type.types.minecraft;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.minecraft.Position;
import us.myles.ViaVersion.api.type.Type;
public class PositionType extends Type<Position> {
public PositionType() {
super(Position.class);
}
@Override
public Position read(ByteBuf buffer) {
long val = buffer.readLong();
long x = (val >> 38); // signed
long y = (val >> 26) & 0xfff; // unsigned
// this shifting madness is used to preserve sign
long z = (val << 38) >> 38; // signed
return new Position(x, y, z);
}
@Override
public void write(ByteBuf buffer, Position object) {
buffer.writeLong(((object.getX() & 0x3ffffff) << 38) | ((object.getY() & 0xfff) << 26) | (object.getZ() & 0x3ffffff));
}
}
@@ -0,0 +1,27 @@
package us.myles.ViaVersion.api.type.types.minecraft;
import io.netty.buffer.ByteBuf;
import org.bukkit.util.Vector;
import us.myles.ViaVersion.api.type.Type;
public class VectorType extends Type<Vector> {
public VectorType() {
super(Vector.class);
}
@Override
public Vector read(ByteBuf buffer) throws Exception {
int x = Type.INT.read(buffer);
int y = Type.INT.read(buffer);
int z = Type.INT.read(buffer);
return new Vector(x, y, z);
}
@Override
public void write(ByteBuf buffer, Vector object) throws Exception {
Type.INT.write(buffer, object.getBlockX());
Type.INT.write(buffer, object.getBlockY());
Type.INT.write(buffer, object.getBlockZ());
}
}
@@ -0,0 +1,237 @@
package us.myles.ViaVersion.boss;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang.Validate;
import org.bukkit.entity.Player;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.boss.BossBar;
import us.myles.ViaVersion.api.boss.BossColor;
import us.myles.ViaVersion.api.boss.BossFlag;
import us.myles.ViaVersion.api.boss.BossStyle;
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
import java.util.*;
@Getter
public class ViaBossBar implements BossBar {
private UUID uuid;
private String title;
private float health;
private BossColor color;
private BossStyle style;
private Set<UUID> players;
private boolean visible;
private Set<BossFlag> flags;
public ViaBossBar(String title, float health, BossColor color, BossStyle style) {
Validate.notNull(title, "Title cannot be null");
Validate.isTrue((health >= 0 && health <= 1), "Health must be between 0 and 1");
this.uuid = UUID.randomUUID();
this.title = title;
this.health = health;
this.color = color == null ? BossColor.PURPLE : color;
this.style = style == null ? BossStyle.SOLID : style;
this.players = new HashSet<>();
this.flags = new HashSet<>();
visible = true;
}
@Override
public BossBar setTitle(@NonNull String title) {
this.title = title;
sendPacket(UpdateAction.UPDATE_TITLE);
return this;
}
@Override
public BossBar setHealth(float health) {
Validate.isTrue((health >= 0 && health <= 1), "Health must be between 0 and 1");
this.health = health;
sendPacket(UpdateAction.UPDATE_HEALTH);
return this;
}
@Override
public BossColor getColor() {
return color;
}
@Override
public BossBar setColor(@NonNull BossColor color) {
this.color = color;
sendPacket(UpdateAction.UPDATE_STYLE);
return this;
}
@Override
public BossBar setStyle(@NonNull BossStyle style) {
this.style = style;
sendPacket(UpdateAction.UPDATE_STYLE);
return this;
}
@Override
public BossBar addPlayer(@NonNull Player player) {
return addPlayer(player.getUniqueId());
}
@Override
public BossBar addPlayer(UUID player) {
if (!players.contains(player)) {
players.add(player);
if (visible)
sendPacket(player, getPacket(UpdateAction.ADD));
}
return this;
}
@Override
public BossBar removePlayer(@NonNull Player player) {
if (players.contains(player.getUniqueId())) {
players.remove(player.getUniqueId());
sendPacket(player.getUniqueId(), getPacket(UpdateAction.REMOVE));
}
return this;
}
@Override
public BossBar addPlayers(@NonNull Player... players) {
for (Player p : players)
addPlayer(p);
return this;
}
@Override
public BossBar addFlag(@NonNull BossFlag flag) {
if (!hasFlag(flag))
flags.add(flag);
sendPacket(UpdateAction.UPDATE_FLAGS);
return this;
}
@Override
public BossBar removeFlag(@NonNull BossFlag flag) {
if (hasFlag(flag))
flags.remove(flag);
sendPacket(UpdateAction.UPDATE_FLAGS);
return this;
}
@Override
public boolean hasFlag(@NonNull BossFlag flag) {
return flags.contains(flag);
}
@Override
public Set<UUID> getPlayers() {
return Collections.unmodifiableSet(players);
}
@Override
public BossBar show() {
setVisible(true);
return this;
}
@Override
public BossBar hide() {
setVisible(false);
return this;
}
@Override
public boolean isVisible() {
return visible;
}
private void setVisible(boolean value) {
if (visible != value) {
visible = value;
sendPacket(value ? UpdateAction.ADD : UpdateAction.REMOVE);
}
}
private void sendPacket(UpdateAction action) {
for (UUID uuid : new ArrayList<>(players)) {
ByteBuf buf = getPacket(action);
sendPacket(uuid, buf);
}
}
private void sendPacket(UUID uuid, ByteBuf buf) {
if (!ViaVersion.getInstance().isPorted(uuid) || !(ViaVersion.getInstance().getPlayerVersion(uuid) >= ProtocolVersion.v1_9.getId())) {
players.remove(uuid);
buf.release();
return;
}
ViaVersion.getInstance().sendRawPacket(uuid, buf);
}
private ByteBuf getPacket(UpdateAction action) {
try {
ByteBuf buf = Unpooled.buffer();
Type.VAR_INT.write(buf, 0x0C); // Boss bar packet
Type.UUID.write(buf, uuid);
Type.VAR_INT.write(buf, action.getId());
switch (action) {
case ADD:
Type.STRING.write(buf, fixJson(title));
buf.writeFloat(health);
Type.VAR_INT.write(buf, color.getId());
Type.VAR_INT.write(buf, style.getId());
buf.writeByte(flagToBytes());
break;
case REMOVE:
break;
case UPDATE_HEALTH:
buf.writeFloat(health);
break;
case UPDATE_TITLE:
Type.STRING.write(buf, fixJson(title));
break;
case UPDATE_STYLE:
Type.VAR_INT.write(buf, color.getId());
Type.VAR_INT.write(buf, style.getId());
break;
case UPDATE_FLAGS:
buf.writeByte(flagToBytes());
break;
}
return buf;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private int flagToBytes() {
int bitmask = 0;
for (BossFlag flag : flags)
bitmask |= flag.getId();
return bitmask;
}
private String fixJson(String text) {
return Protocol1_9TO1_8.fixJson(text);
}
@RequiredArgsConstructor
@Getter
private enum UpdateAction {
ADD(0),
REMOVE(1),
UPDATE_HEALTH(2),
UPDATE_TITLE(3),
UPDATE_STYLE(4),
UPDATE_FLAGS(5);
private final int id;
}
}
@@ -1,52 +0,0 @@
package us.myles.ViaVersion.chunks;
public class ByteWriter {
private final byte[] bytes;
private int byteIndex;
private int bitIndex;
public ByteWriter(int size) {
this.bytes = new byte[size];
this.byteIndex = 0;
this.bitIndex = 0;
}
public byte[] getOutput() {
return this.bytes;
}
public void writeFullByte(int b){
writeByte(b, 8);
}
public void writeByte(int b, int length) {
byte current = getCurrentByte();
byte byteB = (byte)(int)((b) & 0xff);
System.out.println("Input: " + byteB);
System.out.println(Integer.toBinaryString(byteB));
int space = (8 - bitIndex);
int written = space > length ? length : space;
System.out.println("Written is " + written);
bytes[byteIndex] = (byte) (current | (extractRange(byteB, 0, written) >> (bitIndex - 1)));
System.out.println("output value: " + bytes[byteIndex]);
this.bitIndex += length;
if(this.bitIndex >= 8) {
this.byteIndex += 1;
this.bitIndex = bitIndex - 8;
// write remaining into this
System.out.println("Writing from " + written + " to " + (written + bitIndex));
System.out.println("Value: " + extractRange(byteB, written, written + bitIndex));
bytes[byteIndex] = (byte) (extractRange(byteB, written, written + bitIndex) << written);
}
}
private byte extractRange(int in, int begin, int end){
return (byte) ((in >> begin) & ((1 << (end - begin)) - 1));
}
public byte getCurrentByte() {
if(byteIndex == bytes.length) throw new RuntimeException("ByteWriter overflow!");
return bytes[byteIndex];
}
}
@@ -1,16 +0,0 @@
package us.myles.ViaVersion.chunks;
import java.util.BitSet;
public class MagicBitSet extends BitSet{
private final int initLength;
public MagicBitSet(int nbits) {
super(nbits);
this.initLength = nbits;
}
public int getTrueLength() {
return length() == 0 ? initLength : length();
}
}
@@ -1,19 +0,0 @@
package us.myles.ViaVersion.chunks;
public class PacketChunk {
private PacketChunkData[] chunkData;
private byte[] biomeData;
public PacketChunk(PacketChunkData[] chunkData, byte[] biomeData) {
this.chunkData = chunkData;
this.biomeData = biomeData;
}
public PacketChunkData[] getChunkData() {
return chunkData;
}
public byte[] getBiomeData() {
return biomeData;
}
}
@@ -1,25 +0,0 @@
package us.myles.ViaVersion.chunks;
public class PacketChunkData {
private short[] blocks = new short[4096];
private byte[] blockLight = new byte[2048];
private byte[] skyLight;
public PacketChunkData(boolean isSkyLightData) {
if(isSkyLightData){
skyLight = new byte[2048];
}
}
public short[] getBlocks() {
return this.blocks;
}
public byte[] getBlockLight() {
return this.blockLight;
}
public byte[] getSkyLight() {
return this.skyLight;
}
}
@@ -0,0 +1,20 @@
package us.myles.ViaVersion.classgenerator;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.classgenerator.HandlerConstructor;
import us.myles.ViaVersion.handlers.ViaDecodeHandler;
import us.myles.ViaVersion.handlers.ViaEncodeHandler;
public class BasicHandlerConstructor implements HandlerConstructor {
@Override
public ViaEncodeHandler newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {
return new ViaEncodeHandler(info, minecraftEncoder);
}
@Override
public ViaDecodeHandler newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {
return new ViaDecodeHandler(info, minecraftDecoder);
}
}
@@ -0,0 +1,88 @@
package us.myles.ViaVersion.classgenerator;
import javassist.*;
import javassist.expr.ConstructorCall;
import javassist.expr.ExprEditor;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.handlers.ViaDecodeHandler;
import us.myles.ViaVersion.handlers.ViaEncodeHandler;
import us.myles.ViaVersion.util.ReflectionUtil;
public class ClassGenerator {
private static HandlerConstructor constructor = new BasicHandlerConstructor();
public static HandlerConstructor getConstructor() {
return constructor;
}
public static void generate() {
if(!ViaVersion.getInstance().isCompatSpigotBuild()) return; // Use Basic Handler as not needed.
try {
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new LoaderClassPath(ClassGenerator.class.getClassLoader()));
// Generate the classes
transformSuperclass(pool, ViaDecodeHandler.class, ReflectionUtil.nms("PacketDecoder"));
transformSuperclass(pool, ViaEncodeHandler.class, ReflectionUtil.nms("PacketEncoder"));
// Implement Constructor
CtClass generated = pool.makeClass("us.myles.ViaVersion.classgenerator.generated.GeneratedConstructor");
CtClass handlerInterface = pool.get(HandlerConstructor.class.getName());
generated.setInterfaces(new CtClass[]{handlerInterface});
// Import required classes
pool.importPackage("us.myles.ViaVersion.classgenerator.generated");
pool.importPackage("us.myles.ViaVersion.classgenerator");
pool.importPackage("us.myles.ViaVersion.api.data");
pool.importPackage("io.netty.handler.codec");
// Implement Methods
generated.addMethod(CtMethod.make("public MessageToByteEncoder newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {\n" +
" return new ViaEncodeHandler(info, minecraftEncoder);\n" +
" }", generated));
generated.addMethod(CtMethod.make("public ByteToMessageDecoder newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {\n" +
" return new ViaDecodeHandler(info, minecraftDecoder);\n" +
" }", generated));
constructor = (HandlerConstructor) generated.toClass(HandlerConstructor.class.getClassLoader()).newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (CannotCompileException e) {
e.printStackTrace();
} catch (NotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
private static Class transformSuperclass(ClassPool pool, Class input, Class superclass) {
String newName = "us.myles.ViaVersion.classgenerator.generated." + input.getSimpleName();
try {
CtClass toExtend = pool.get(superclass.getName());
CtClass generated = pool.getAndRename(input.getName(), newName);
generated.setSuperclass(toExtend);
// Modify constructor to call super
if(generated.getConstructors().length != 0) {
generated.getConstructors()[0].instrument(new ExprEditor() {
@Override
public void edit(ConstructorCall c) throws CannotCompileException {
if (c.isSuper()) {
// Constructor for both has a stats thing.
c.replace("super(null);");
}
super.edit(c);
}
});
}
return generated.toClass(HandlerConstructor.class.getClassLoader());
} catch (NotFoundException e) {
e.printStackTrace();
} catch (CannotCompileException e) {
e.printStackTrace();
}
return null;
}
}
@@ -0,0 +1,10 @@
package us.myles.ViaVersion.classgenerator;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import us.myles.ViaVersion.api.data.UserConnection;
public interface HandlerConstructor {
public MessageToByteEncoder newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder);
public ByteToMessageDecoder newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder);
}
@@ -0,0 +1,153 @@
package us.myles.ViaVersion.commands;
import lombok.NonNull;
import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.command.ViaSubCommand;
import us.myles.ViaVersion.api.command.ViaVersionCommand;
import us.myles.ViaVersion.commands.defaultsubs.*;
import java.util.*;
public class ViaCommandHandler implements ViaVersionCommand, CommandExecutor, TabCompleter {
private Map<String, ViaSubCommand> commandMap;
public ViaCommandHandler() {
commandMap = new HashMap<>();
try {
registerDefaults();
} catch (Exception e) {
//ignore never throws exception because it doesn't exists
}
}
@Override
public void registerSubCommand(@NonNull ViaSubCommand command) throws Exception {
Validate.isTrue(command.name().matches("^[a-z0-9_-]{3,15}$"), command.name() + " is not a valid subcommand name");
if (hasSubCommand(command.name()))
throw new Exception("ViaSubCommand " + command.name() + " does already exists!"); //Maybe another exception later.
commandMap.put(command.name().toLowerCase(), command);
}
@Override
public boolean hasSubCommand(String name) {
return commandMap.containsKey(name.toLowerCase());
}
@Override
public ViaSubCommand getSubCommand(String name) {
return commandMap.get(name.toLowerCase());
}
@Override
public boolean onCommand(CommandSender sender, Command cmd, String arg, String[] args) {
if (args.length == 0) {
showHelp(sender);
return false;
}
if (!hasSubCommand(args[0])) {
sender.sendMessage(color("&cThis command is not found"));
showHelp(sender);
return false;
}
ViaSubCommand handler = getSubCommand(args[0]);
if (!hasPermission(sender, handler.permission())) {
sender.sendMessage(color("&cYou are not allowed to use this command!"));
return false;
}
String[] subArgs = Arrays.copyOfRange(args, 1, args.length);
boolean result = handler.execute(sender, subArgs);
if (!result)
sender.sendMessage("Usage: /viaversion " + handler.usage());
return result;
}
@Override
public List<String> onTabComplete(CommandSender sender, Command command, String arg, String[] args) {
Set<ViaSubCommand> allowed = calculateAllowedCommands(sender);
List<String> output = new ArrayList<>();
//SubCommands tabcomplete
if (args.length == 1) {
if (!args[0].equals("")) {
for (ViaSubCommand sub : allowed)
if (sub.name().toLowerCase().startsWith(args[0].toLowerCase()))
output.add(sub.name());
} else {
for (ViaSubCommand sub : allowed)
output.add(sub.name());
}
}
//Let the SubCommand handle it
else if (args.length >= 2) {
if (getSubCommand(args[0]) != null) {
ViaSubCommand sub = getSubCommand(args[0]);
if (!allowed.contains(sub))
return output;
String[] subArgs = Arrays.copyOfRange(args, 1, args.length);
List<String> tab = sub.onTabComplete(sender, subArgs);
Collections.sort(tab);
return tab;
}
}
return output;
}
public void showHelp(CommandSender sender) {
Set<ViaSubCommand> allowed = calculateAllowedCommands(sender);
if (allowed.size() == 0) {
sender.sendMessage(color("&cYou are not allowed to use this command!"));
return;
}
sender.sendMessage(color("&aViaVersion &c" + ViaVersion.getInstance().getVersion()));
sender.sendMessage(color("&6Commands:"));
for (ViaSubCommand cmd : allowed)
sender.sendMessage(color(String.format("&2/viaversion %s &7- &6%s", cmd.usage(), cmd.description())));
allowed.clear();
}
private Set<ViaSubCommand> calculateAllowedCommands(CommandSender sender) {
Set<ViaSubCommand> cmds = new HashSet<>();
for (ViaSubCommand sub : commandMap.values())
if (hasPermission(sender, sub.permission()))
cmds.add(sub);
return cmds;
}
private boolean hasPermission(CommandSender sender, String permission) {
return permission == null || sender.hasPermission(permission);
}
private void registerDefaults() throws Exception {
registerSubCommand(new ListSubCmd());
registerSubCommand(new PPSSubCmd());
registerSubCommand(new DebugSubCmd());
registerSubCommand(new DisplayLeaksSubCmd());
registerSubCommand(new DontBugMeSubCmd());
registerSubCommand(new AutoTeamSubCmd());
registerSubCommand(new HelpSubCmd());
registerSubCommand(new ReloadSubCmd());
}
public static String color(String string) {
try {
string = ChatColor.translateAlternateColorCodes('&', string); //Dont replace all & with $ like we did before.
} catch (Exception ignored) {
}
return string;
}
public static void sendMessage(@NonNull CommandSender sender, String message, Object... args) {
sender.sendMessage(color(args == null ? message : String.format(message, args)));
}
}
@@ -0,0 +1,31 @@
package us.myles.ViaVersion.commands.defaultsubs;
import org.bukkit.command.CommandSender;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.command.ViaSubCommand;
public class AutoTeamSubCmd extends ViaSubCommand {
@Override
public String name() {
return "autoteam";
}
@Override
public String description() {
return "Toggle automatically teaming to prevent colliding.";
}
@Override
public boolean execute(CommandSender sender, String[] args) {
ViaVersionPlugin plugin = (ViaVersionPlugin) ViaVersion.getInstance();
boolean newValue = !plugin.isAutoTeam();
plugin.getConfig().set("auto-team", newValue);
plugin.saveConfig();
sendMessage(sender, "&6We will %s", (newValue ? "&aautomatically team players" : "&cno longer auto team players"));
sendMessage(sender, "&6All players will need to re-login for the change to take place.");
return true;
}
}
@@ -0,0 +1,27 @@
package us.myles.ViaVersion.commands.defaultsubs;
import org.bukkit.command.CommandSender;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.command.ViaSubCommand;
public class DebugSubCmd extends ViaSubCommand {
@Override
public String name() {
return "debug";
}
@Override
public String description() {
return "Toggle debug mode";
}
@Override
public boolean execute(CommandSender sender, String[] args) {
ViaVersionPlugin plugin = (ViaVersionPlugin) ViaVersion.getInstance();
plugin.setDebug(!plugin.isDebug());
sendMessage(sender, "&6Debug mode is now %s", (plugin.isDebug() ? "&aenabled" : "&cdisabled"));
return true;
}
}
@@ -0,0 +1,28 @@
package us.myles.ViaVersion.commands.defaultsubs;
import io.netty.util.ResourceLeakDetector;
import org.bukkit.command.CommandSender;
import us.myles.ViaVersion.api.command.ViaSubCommand;
public class DisplayLeaksSubCmd extends ViaSubCommand {
@Override
public String name() {
return "displayleaks";
}
@Override
public String description() {
return "Try to hunt memory leaks!";
}
@Override
public boolean execute(CommandSender sender, String[] args) {
if (ResourceLeakDetector.getLevel() != ResourceLeakDetector.Level.ADVANCED)
ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.ADVANCED);
else
ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.DISABLED);
sendMessage(sender, "&6Leak detector is now %s", (ResourceLeakDetector.getLevel() == ResourceLeakDetector.Level.ADVANCED ? "&aenabled" : "&cdisabled"));
return true;
}
}
@@ -0,0 +1,30 @@
package us.myles.ViaVersion.commands.defaultsubs;
import org.bukkit.command.CommandSender;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.command.ViaSubCommand;
public class DontBugMeSubCmd extends ViaSubCommand {
@Override
public String name() {
return "dontbugme";
}
@Override
public String description() {
return "Toggle checking for updates";
}
@Override
public boolean execute(CommandSender sender, String[] args) {
ViaVersionPlugin plugin = (ViaVersionPlugin) ViaVersion.getInstance();
boolean newValue = !plugin.isCheckForUpdates();
plugin.getConfig().set("checkforupdates", newValue);
plugin.saveConfig();
sendMessage(sender, "&6We will %snotify you about updates.", (newValue ? "&a" : "&cnot "));
return true;
}
}
@@ -0,0 +1,27 @@
package us.myles.ViaVersion.commands.defaultsubs;
import org.bukkit.command.CommandSender;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.command.ViaSubCommand;
import us.myles.ViaVersion.commands.ViaCommandHandler;
public class HelpSubCmd extends ViaSubCommand {
@Override
public String name() {
return "help";
}
@Override
public String description() {
return "You are looking at it right now!";
}
@Override
public boolean execute(CommandSender sender, String[] args) {
ViaVersionPlugin plugin = (ViaVersionPlugin) ViaVersion.getInstance();
((ViaCommandHandler) plugin.getCommandHandler()).showHelp(sender);
return true;
}
}
@@ -0,0 +1,45 @@
package us.myles.ViaVersion.commands.defaultsubs;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.command.ViaSubCommand;
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
import java.util.*;
public class ListSubCmd extends ViaSubCommand {
@Override
public String name() {
return "list";
}
@Override
public String description() {
return "Shows lists of the versions from logged in players";
}
@Override
public String usage() {
return "list";
}
@Override
public boolean execute(CommandSender sender, String[] args) {
Map<Integer, Set<String>> playerVersions = new HashMap<>();
for (Player p : Bukkit.getOnlinePlayers()) {
int playerVersion = ViaVersion.getInstance().getPlayerVersion(p);
if (!playerVersions.containsKey(playerVersion))
playerVersions.put(playerVersion, new HashSet<String>());
playerVersions.get(playerVersion).add(p.getName());
}
Map<Integer, Set<String>> sorted = new TreeMap<>(playerVersions);
for (Map.Entry<Integer, Set<String>> entry : sorted.entrySet())
sendMessage(sender, "&8[&6%s&8]: &b%s", ProtocolVersion.getProtocol(entry.getKey()).getName(), entry.getValue());
sorted.clear();
return true;
}
}
@@ -0,0 +1,64 @@
package us.myles.ViaVersion.commands.defaultsubs;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.command.ViaSubCommand;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
import java.util.*;
public class PPSSubCmd extends ViaSubCommand {
@Override
public String name() {
return "pps";
}
@Override
public String description() {
return "Shows the packets per second of online players";
}
@Override
public String usage() {
return "pps";
}
@Override
public boolean execute(CommandSender sender, String[] args) {
Map<Integer, Set<String>> playerVersions = new HashMap<>();
int totalPackets = 0;
int clients = 0;
long max = 0;
for (Player p : Bukkit.getOnlinePlayers()) {
if (!ViaVersion.getInstance().isPorted(p))
continue;
int playerVersion = ViaVersion.getInstance().getPlayerVersion(p);
if (!playerVersions.containsKey(playerVersion))
playerVersions.put(playerVersion, new HashSet<String>());
UserConnection uc = ((ViaVersionPlugin) ViaVersion.getInstance()).getConnection(p);
if (uc.getPacketsPerSecond() > -1) {
playerVersions.get(playerVersion).add(p.getName() + " (" + uc.getPacketsPerSecond() + " PPS)");
totalPackets += uc.getPacketsPerSecond();
if (uc.getPacketsPerSecond() > max) {
max = uc.getPacketsPerSecond();
}
clients++;
}
}
Map<Integer, Set<String>> sorted = new TreeMap<>(playerVersions);
sendMessage(sender, "&4Live Packets Per Second");
if (clients > 1) {
sendMessage(sender, "&cAverage: &f" + (totalPackets / clients));
sendMessage(sender, "&cHighest: &f" + max);
}
for (Map.Entry<Integer, Set<String>> entry : sorted.entrySet())
sendMessage(sender, "&8[&6%s&8]: &b%s", ProtocolVersion.getProtocol(entry.getKey()).getName(), entry.getValue());
sorted.clear();
return true;
}
}
@@ -0,0 +1,27 @@
package us.myles.ViaVersion.commands.defaultsubs;
import org.bukkit.command.CommandSender;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.command.ViaSubCommand;
public class ReloadSubCmd extends ViaSubCommand {
@Override
public String name() {
return "reload";
}
@Override
public String description() {
return "Reload the config from the disk";
}
@Override
public boolean execute(CommandSender sender, String[] args) {
ViaVersionPlugin plugin = (ViaVersionPlugin) ViaVersion.getInstance();
plugin.generateConfig();
sendMessage(sender, "&6Configuration successfully reloaded! Some features may need a restart.");
return true;
}
}
@@ -0,0 +1,4 @@
package us.myles.ViaVersion.exception;
public class CancelException extends Exception {
}
@@ -0,0 +1,50 @@
package us.myles.ViaVersion.exception;
import java.util.HashMap;
import java.util.Map;
public class InformativeException extends Exception {
Map<String, Object> info = new HashMap<>();
int sources = 0;
public InformativeException(Throwable cause) {
super(cause);
}
public InformativeException set(String key, Object value) {
info.put(key, value);
return this;
}
public InformativeException addSource(Class<?> sourceClazz) {
return set("Source #" + sources++, getSource(sourceClazz));
}
private String getSource(Class<?> sourceClazz) {
if (sourceClazz.isAnonymousClass()) {
return sourceClazz.getName() + " (Anonymous)";
} else {
return sourceClazz.getName();
}
}
@Override
public String getMessage() {
StringBuilder builder = new StringBuilder();
builder.append("Please post this error to http://github.com/MylesIsCool/ViaVersion/issues\n{");
int i = 0;
for (Map.Entry<String, Object> entry : info.entrySet()) {
builder.append((i == 0 ? "" : ", ") + entry.getKey() + ": " + entry.getValue().toString());
i++;
}
builder.append("}\nActual Error: ");
return builder.toString();
}
@Override
public synchronized Throwable fillInStackTrace() {
// Don't record this stack
return this;
}
}
@@ -3,59 +3,90 @@ package us.myles.ViaVersion.handlers;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import us.myles.ViaVersion.CancelException;
import us.myles.ViaVersion.ConnectionInfo;
import us.myles.ViaVersion.transformers.IncomingTransformer;
import us.myles.ViaVersion.util.PacketUtil;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.exception.CancelException;
import us.myles.ViaVersion.packets.Direction;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.util.PipelineUtil;
import java.nio.channels.ClosedChannelException;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
public class ViaDecodeHandler extends ByteToMessageDecoder {
private final IncomingTransformer incomingTransformer;
private final ByteToMessageDecoder minecraftDecoder;
private final ConnectionInfo info;
public ViaDecodeHandler(ConnectionInfo info, ByteToMessageDecoder minecraftDecoder) {
private final ByteToMessageDecoder minecraftDecoder;
private final UserConnection info;
public static int PASSTHROUGH_ID = 1000;
public ViaDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {
this.info = info;
this.minecraftDecoder = minecraftDecoder;
this.incomingTransformer = new IncomingTransformer(info);
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> list) throws Exception {
// use transformers
if (bytebuf.readableBytes() > 0) {
// Ignore if pending disconnect
if (info.isPendingDisconnect()) {
return;
}
// Increment received
boolean second = info.incrementReceived();
// Check PPS
if(second) {
if (((ViaVersionPlugin) ViaVersion.getConfig()).handlePPS(info))
return;
}
if (info.isActive()) {
int id = PacketUtil.readVarInt(bytebuf);
// Handle ID
int id = Type.VAR_INT.read(bytebuf);
// Transform
ByteBuf newPacket = ctx.alloc().buffer();
try {
incomingTransformer.transform(id, bytebuf, newPacket);
if (id == ViaDecodeHandler.PASSTHROUGH_ID) {
newPacket.writeBytes(bytebuf);
} else {
PacketWrapper wrapper = new PacketWrapper(id, bytebuf, info);
ProtocolInfo protInfo = info.get(ProtocolInfo.class);
protInfo.getPipeline().transform(Direction.INCOMING, protInfo.getState(), wrapper);
wrapper.writeToBuffer(newPacket);
}
bytebuf.clear();
bytebuf = newPacket;
} catch (CancelException e) {
bytebuf.readBytes(bytebuf.readableBytes());
} catch (Exception e) {
// Clear Buffer
bytebuf.clear();
// Release Packet, be free!
newPacket.release();
throw e;
}
}
// call minecraft decoder
list.addAll(PacketUtil.callDecode(this.minecraftDecoder, ctx, bytebuf));
try {
list.addAll(PipelineUtil.callDecode(this.minecraftDecoder, ctx, bytebuf));
} catch (InvocationTargetException e) {
if (e.getCause() instanceof Exception) {
throw (Exception) e.getCause();
}
} finally {
if (info.isActive()) {
bytebuf.release();
}
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (!(cause.getCause().getCause() instanceof CancelException)
&& !(cause.getCause().getCause() instanceof ClosedChannelException)) {
if (!(cause.getCause() instanceof CancelException)
&& !(cause.getCause() instanceof ClosedChannelException)) {
if (!(cause instanceof CancelException)
&& !(cause instanceof ClosedChannelException)) {
if (cause instanceof Exception)
throw (Exception) cause;
}
}
}
if (PipelineUtil.containsCause(cause, CancelException.class)) return;
super.exceptionCaught(ctx, cause);
}
}
@@ -3,66 +3,65 @@ package us.myles.ViaVersion.handlers;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import us.myles.ViaVersion.CancelException;
import us.myles.ViaVersion.ConnectionInfo;
import us.myles.ViaVersion.transformers.OutgoingTransformer;
import us.myles.ViaVersion.util.PacketUtil;
import us.myles.ViaVersion.util.ReflectionUtil;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.exception.CancelException;
import us.myles.ViaVersion.packets.Direction;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.util.PipelineUtil;
import java.lang.reflect.Constructor;
import java.nio.channels.ClosedChannelException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class ViaEncodeHandler extends MessageToByteEncoder {
private final ConnectionInfo info;
private final UserConnection info;
private final MessageToByteEncoder minecraftEncoder;
private final OutgoingTransformer outgoingTransformer;
public ViaEncodeHandler(ConnectionInfo info, MessageToByteEncoder minecraftEncoder) {
public ViaEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {
this.info = info;
this.minecraftEncoder = minecraftEncoder;
this.outgoingTransformer = new OutgoingTransformer(info);
}
@Override
protected void encode(ChannelHandlerContext ctx, Object o, ByteBuf bytebuf) throws Exception {
protected void encode(final ChannelHandlerContext ctx, Object o, final ByteBuf bytebuf) throws Exception {
if (ViaVersion.getInstance().isCompatSpigotBuild()) {
Field ver = minecraftEncoder.getClass().getDeclaredField("version");
ver.setAccessible(true);
ver.set(minecraftEncoder, ver.get(this));
}
// handle the packet type
if (!(o instanceof ByteBuf)) {
info.setLastPacket(o);
/* This transformer is more for fixing issues which we find hard at packet level :) */
if (o.getClass().getName().endsWith("PacketPlayOutMapChunkBulk") && info.isActive()) {
int[] locX = ReflectionUtil.get(o, "a", int[].class);
int[] locZ = ReflectionUtil.get(o, "b", int[].class);
Object world = ReflectionUtil.get(o, "world", ReflectionUtil.nms("World"));
Class<?> mapChunk = ReflectionUtil.nms("PacketPlayOutMapChunk");
Constructor constructor = mapChunk.getDeclaredConstructor(ReflectionUtil.nms("Chunk"), boolean.class, int.class);
for (int i = 0; i < locX.length; i++) {
int x = locX[i];
int z = locZ[i];
// world invoke function
Object chunk = ReflectionUtil.nms("World").getDeclaredMethod("getChunkAt", int.class, int.class).invoke(world, x, z);
Object packet = constructor.newInstance(chunk, true, 65535);
ctx.pipeline().writeAndFlush(packet);
}
bytebuf.readBytes(bytebuf.readableBytes());
throw new CancelException();
}
// call minecraft encoder
PacketUtil.callEncode(this.minecraftEncoder, ctx, o, bytebuf);
try {
PipelineUtil.callEncode(this.minecraftEncoder, ctx, o, bytebuf);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof Exception) {
throw (Exception) e.getCause();
}
}
}
if (bytebuf.readableBytes() == 0) {
throw new CancelException();
}
// Increment sent
info.incrementSent();
if (info.isActive()) {
int id = PacketUtil.readVarInt(bytebuf);
// Handle ID
int id = Type.VAR_INT.read(bytebuf);
// Transform
ByteBuf oldPacket = bytebuf.copy();
bytebuf.clear();
try {
outgoingTransformer.transform(id, oldPacket, bytebuf);
} catch (CancelException e) {
bytebuf.readBytes(bytebuf.readableBytes());
PacketWrapper wrapper = new PacketWrapper(id, oldPacket, info);
ProtocolInfo protInfo = info.get(ProtocolInfo.class);
protInfo.getPipeline().transform(Direction.OUTGOING, protInfo.getState(), wrapper);
wrapper.writeToBuffer(bytebuf);
} catch (Exception e) {
bytebuf.clear();
throw e;
} finally {
oldPacket.release();
@@ -72,16 +71,7 @@ public class ViaEncodeHandler extends MessageToByteEncoder {
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (!(cause.getCause().getCause() instanceof CancelException)
&& !(cause.getCause().getCause() instanceof ClosedChannelException)) {
if (!(cause.getCause() instanceof CancelException)
&& !(cause.getCause() instanceof ClosedChannelException)) {
if (!(cause instanceof CancelException)
&& !(cause instanceof ClosedChannelException)) {
if (cause instanceof Exception)
throw (Exception) cause;
}
}
}
if (PipelineUtil.containsCause(cause, CancelException.class)) return;
super.exceptionCaught(ctx, cause);
}
}
@@ -0,0 +1,35 @@
package us.myles.ViaVersion.handlers;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import java.util.List;
public class ViaPacketHandler extends MessageToMessageEncoder {
private final UserConnection info;
public ViaPacketHandler(UserConnection info) {
this.info = info;
}
@Override
protected void encode(ChannelHandlerContext ctx, Object o, List list) throws Exception {
// Split chunk bulk packet up in to single chunk packets before it reached the encoder.
// This will prevent issues with several plugins and other protocol handlers due to the chunk being sent twice.
// It also sends the chunk in the right order possible resolving some issues with added chunk/block/entity data.
if (!(o instanceof ByteBuf)) {
info.setLastPacket(o);
/* This transformer is more for fixing issues which we find hard at packet level :) */
if (info.isActive()) {
if (info.get(ProtocolInfo.class).getPipeline().filter(o, list)) {
return;
}
}
}
list.add(o);
}
}
@@ -5,16 +5,20 @@ import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import us.myles.ViaVersion.ConnectionInfo;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.protocol.ProtocolPipeline;
import us.myles.ViaVersion.classgenerator.ClassGenerator;
import us.myles.ViaVersion.classgenerator.HandlerConstructor;
import java.lang.reflect.Method;
public class ViaVersionInitializer extends ChannelInitializer<SocketChannel> {
private final ChannelInitializer<SocketChannel> oldInit;
private final ChannelInitializer<SocketChannel> original;
private Method method;
public ViaVersionInitializer(ChannelInitializer<SocketChannel> oldInit) {
this.oldInit = oldInit;
this.original = oldInit;
try {
this.method = ChannelInitializer.class.getDeclaredMethod("initChannel", Channel.class);
this.method.setAccessible(true);
@@ -23,16 +27,26 @@ public class ViaVersionInitializer extends ChannelInitializer<SocketChannel> {
}
}
public ChannelInitializer<SocketChannel> getOriginal() {
return original;
}
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ConnectionInfo info = new ConnectionInfo(socketChannel);
UserConnection info = new UserConnection(socketChannel);
// init protocol
new ProtocolPipeline(info);
// Add originals
this.method.invoke(this.oldInit, socketChannel);
this.method.invoke(this.original, socketChannel);
HandlerConstructor constructor = ClassGenerator.getConstructor();
// Add our transformers
ViaEncodeHandler encoder = new ViaEncodeHandler(info, (MessageToByteEncoder) socketChannel.pipeline().get("encoder"));
ViaDecodeHandler decoder = new ViaDecodeHandler(info, (ByteToMessageDecoder) socketChannel.pipeline().get("decoder"));
MessageToByteEncoder encoder = constructor.newEncodeHandler(info, (MessageToByteEncoder) socketChannel.pipeline().get("encoder"));
ByteToMessageDecoder decoder = constructor.newDecodeHandler(info, (ByteToMessageDecoder) socketChannel.pipeline().get("decoder"));
ViaPacketHandler chunkHandler = new ViaPacketHandler(info);
socketChannel.pipeline().replace("encoder", "encoder", encoder);
socketChannel.pipeline().replace("decoder", "decoder", decoder);
socketChannel.pipeline().addAfter("packet_handler", "viaversion_packet_handler", chunkHandler);
}
}
@@ -1,183 +0,0 @@
package us.myles.ViaVersion.metadata;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import org.bukkit.entity.EntityType;
import org.bukkit.util.EulerAngle;
import org.bukkit.util.Vector;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.util.PacketUtil;
public class MetadataRewriter {
public static void writeMetadata1_9(EntityType type, List<Entry> list, ByteBuf output) {
short id = -1;
int data = -1;
Iterator<Entry> iterator = list.iterator();
while (iterator.hasNext()) {
Entry entry = iterator.next(); //
MetaIndex metaIndex = entry.index;
try {
if (metaIndex.getNewType() != NewType.Discontinued) {
if (metaIndex.getNewType() != NewType.BlockID || id != -1 && data == -1 || id == -1 && data != -1) { // block ID is only written if we have both parts
output.writeByte(metaIndex.getNewIndex());
output.writeByte(metaIndex.getNewType().getTypeID());
}
Object value = entry.value;
switch (metaIndex.getNewType()) {
case Byte:
// convert from int, byte
if (metaIndex.getOldType() == Type.Byte) {
output.writeByte(((Byte) value).byteValue());
}
if (metaIndex.getOldType() == Type.Int) {
output.writeByte(((Integer) value).byteValue());
}
break;
case OptUUID:
String owner = (String) value;
UUID toWrite = null;
if (owner.length() != 0) {
try {
toWrite = UUID.fromString(owner);
} catch (Exception ignored) {
}
}
output.writeBoolean(toWrite != null);
if (toWrite != null)
PacketUtil.writeUUID((UUID) toWrite, output);
break;
case BlockID:
// if we have both sources :))
if (metaIndex.getOldType() == Type.Byte) {
data = ((Byte) value).byteValue();
}
if (metaIndex.getOldType() == Type.Short) {
id = ((Short) value).shortValue();
}
if (id != -1 && data != -1) {
int combined = id << 4 | data;
data = -1;
id = -1;
PacketUtil.writeVarInt(combined, output);
}
break;
case VarInt:
// convert from int, short, byte
if (metaIndex.getOldType() == Type.Byte) {
PacketUtil.writeVarInt(((Byte) value).intValue(), output);
}
if (metaIndex.getOldType() == Type.Short) {
PacketUtil.writeVarInt(((Short) value).intValue(), output);
}
if (metaIndex.getOldType() == Type.Int) {
PacketUtil.writeVarInt(((Integer) value).intValue(), output);
}
break;
case Float:
output.writeFloat(((Float) value).floatValue());
break;
case String:
PacketUtil.writeString((String) value, output);
break;
case Boolean:
output.writeBoolean(((Byte) value).byteValue() != 0);
break;
case Slot:
PacketUtil.writeItem(value, output);
break;
case Position:
Vector vector = (Vector) value;
output.writeInt((int) vector.getX());
output.writeInt((int) vector.getY());
output.writeInt((int) vector.getZ());
break;
case Vector3F:
EulerAngle angle = (EulerAngle) value;
output.writeFloat((float) angle.getX());
output.writeFloat((float) angle.getY());
output.writeFloat((float) angle.getZ());
break;
default:
System.out.println("[Out] Unhandled MetaDataType: " + metaIndex.getNewType());
break;
}
}
} catch (Exception e) {
if (type != null) {
System.out.println("An error occurred with entity meta data for " + type);
if (metaIndex != null) {
System.out.println("Old ID: " + metaIndex.getIndex() + " New ID: " + metaIndex.getNewIndex());
System.out.println("Old Type: " + metaIndex.getOldType() + " New Type: " + metaIndex.getNewType());
}
}
e.printStackTrace();
}
}
output.writeByte(255);
}
public static List<Entry> readMetadata1_8(EntityType entityType, ByteBuf buf) {
List<Entry> entries = new ArrayList<>();
byte item;
while ((item = buf.readByte()) != 127) {
Type type = Type.byId((item & 0xE0) >> 5);
int id = item & 0x1F;
MetaIndex index = MetaIndex.getIndex(entityType, id);
switch (type) {
case Byte:
entries.add(new Entry(index, buf.readByte()));
break;
case Short:
entries.add(new Entry(index, buf.readShort()));
break;
case Int:
entries.add(new Entry(index, buf.readInt()));
break;
case Float:
entries.add(new Entry(index, buf.readFloat()));
break;
case String:
entries.add(new Entry(index, PacketUtil.readString(buf)));
break;
case Slot:
entries.add(new Entry(index, PacketUtil.readItem(buf)));
break;
case Position: {
int x = buf.readInt();
int y = buf.readInt();
int z = buf.readInt();
entries.add(new Entry(index, new Vector(x, y, z)));
break;
}
case Rotation: {
float x = buf.readFloat();
float y = buf.readFloat();
float z = buf.readFloat();
entries.add(new Entry(index, new EulerAngle(x, y, z)));
break;
}
default:
System.out.println("[Out] Unhandled MetaDataType: " + type);
break;
}
}
return entries;
}
public static class Entry {
private MetaIndex index;
private Object value;
private Entry(MetaIndex index, Object value) {
this.index = index;
this.value = value;
}
}
}
@@ -1,200 +1,208 @@
package us.myles.ViaVersion.packets;
public enum PacketType {
/* Handshake serverbound */
HANDSHAKE(State.HANDSHAKE, Direction.INCOMING, 0x00),
/* Login serverbound */
LOGIN_START(State.LOGIN, Direction.INCOMING, 0x00),
LOGIN_ENCRYPTION_RESPONSE(State.LOGIN, Direction.INCOMING, 0x01),
/* Login clientbound */
LOGIN_DISCONNECT(State.LOGIN, Direction.OUTGOING, 0x00),
LOGIN_ENCRYPTION_REQUEST(State.LOGIN, Direction.OUTGOING, 0x01),
LOGIN_SUCCESS(State.LOGIN, Direction.OUTGOING, 0x02),
LOGIN_SETCOMPRESSION(State.LOGIN, Direction.OUTGOING, 0x03),
/* Status serverbound */
STATUS_REQUEST(State.STATUS, Direction.INCOMING, 0x00),
STATUS_PING(State.STATUS, Direction.INCOMING, 0x01),
/* Status clientbound */
STATUS_RESPONSE(State.STATUS, Direction.OUTGOING, 0x00),
STATUS_PONG(State.STATUS, Direction.OUTGOING, 0x01),
/* Play serverbound */
PLAY_TP_CONFIRM(State.PLAY, Direction.INCOMING, -1, 0x00),
PLAY_TAB_COMPLETE_REQUEST(State.PLAY, Direction.INCOMING, 0x14, 0x01),
PLAY_CHAT_MESSAGE_CLIENT(State.PLAY, Direction.INCOMING, 0x01, 0x02),
PLAY_CLIENT_STATUS(State.PLAY, Direction.INCOMING, 0x16, 0x03),
PLAY_CLIENT_SETTINGS(State.PLAY, Direction.INCOMING, 0x15, 0x04),
PLAY_CONFIRM_TRANS(State.PLAY, Direction.INCOMING, 0x0F, 0x05),
PLAY_ENCHANT_ITEM(State.PLAY, Direction.INCOMING, 0x11, 0x06),
PLAY_CLICK_WINDOW(State.PLAY, Direction.INCOMING, 0x0E, 0x07),
PLAY_CLOSE_WINDOW_REQUEST(State.PLAY, Direction.INCOMING, 0x0D, 0x08),
PLAY_PLUGIN_MESSAGE_REQUEST(State.PLAY, Direction.INCOMING, 0x17, 0x09),
PLAY_USE_ENTITY(State.PLAY, Direction.INCOMING, 0x02, 0x0A),
PLAY_KEEP_ALIVE_REQUEST(State.PLAY, Direction.INCOMING, 0x00, 0x0B),
PLAY_PLAYER_POSITION_REQUEST(State.PLAY, Direction.INCOMING, 0x04, 0x0C),
PLAY_PLAYER_POSITION_LOOK_REQUEST(State.PLAY, Direction.INCOMING, 0x06, 0x0D),
PLAY_PLAYER_LOOK_REQUEST(State.PLAY, Direction.INCOMING, 0x05, 0x0E),
PLAY_PLAYER(State.PLAY, Direction.INCOMING, 0x03, 0x0F),
PLAY_VEHICLE_MOVE_REQUEST(State.PLAY, Direction.INCOMING, -1, 0x10),
PLAY_STEER_BOAT(State.PLAY, Direction.INCOMING, -1, 0x11),
PLAY_PLAYER_ABILITIES_REQUEST(State.PLAY, Direction.INCOMING, 0x13, 0x12),
PLAY_PLAYER_DIGGING(State.PLAY, Direction.INCOMING, 0x07, 0x13),
PLAY_ENTITY_ACTION(State.PLAY, Direction.INCOMING, 0x0B, 0x14),
PLAY_STEER_VEHICLE(State.PLAY, Direction.INCOMING, 0x0C, 0x15),
PLAY_RESOURCE_PACK_STATUS(State.PLAY, Direction.INCOMING, 0x19, 0x16),
PLAY_HELD_ITEM_CHANGE_REQUEST(State.PLAY, Direction.INCOMING, 0x09, 0x17),
PLAY_CREATIVE_INVENTORY_ACTION(State.PLAY, Direction.INCOMING, 0x10, 0x18),
PLAY_UPDATE_SIGN_REQUEST(State.PLAY, Direction.INCOMING, 0x12, 0x19),
PLAY_ANIMATION_REQUEST(State.PLAY, Direction.INCOMING, 0x0A, 0x1A),
PLAY_SPECTATE(State.PLAY, Direction.INCOMING, 0x18, 0x1B),
PLAY_PLAYER_BLOCK_PLACEMENT(State.PLAY, Direction.INCOMING, 0x08, 0x1C),
PLAY_USE_ITEM(State.PLAY, Direction.INCOMING, -1, 0x1D),
/* Play clientbound */
PLAY_SPAWN_OBJECT(State.PLAY, Direction.OUTGOING, 0x0E, 0x00),
PLAY_SPAWN_XP_ORB(State.PLAY, Direction.OUTGOING, 0x11, 0x01),
PLAY_SPAWN_GLOBAL_ENTITY(State.PLAY, Direction.OUTGOING, 0x2C, 0x02),
PLAY_SPAWN_MOB(State.PLAY, Direction.OUTGOING, 0x0F, 0x03),
PLAY_SPAWN_PAINTING(State.PLAY, Direction.OUTGOING, 0x10, 0x04),
PLAY_SPAWN_PLAYER(State.PLAY, Direction.OUTGOING, 0x0C, 0x05),
PLAY_ANIMATION(State.PLAY, Direction.OUTGOING, 0x0B, 0x06),
PLAY_STATS(State.PLAY, Direction.OUTGOING, 0x37, 0x07),
PLAY_BLOCK_BREAK_ANIMATION(State.PLAY, Direction.OUTGOING, 0x25, 0x08),
PLAY_UPDATE_BLOCK_ENTITY(State.PLAY, Direction.OUTGOING, 0x35, 0x09),
PLAY_BLOCK_ACTION(State.PLAY, Direction.OUTGOING, 0x24, 0x0A),
PLAY_BLOCK_CHANGE(State.PLAY, Direction.OUTGOING, 0x23, 0x0B),
PLAY_BOSS_BAR(State.PLAY, Direction.OUTGOING, -1, 0x0C),
PLAY_SERVER_DIFFICULTY(State.PLAY, Direction.OUTGOING, 0x41, 0x0D),
PLAY_TAB_COMPLETE(State.PLAY, Direction.OUTGOING, 0x3A, 0x0E),
PLAY_CHAT_MESSAGE(State.PLAY, Direction.OUTGOING, 0x02, 0x0F),
PLAY_MULTI_BLOCK_CHANGE(State.PLAY, Direction.OUTGOING, 0x22, 0x10),
PLAY_CONFIRM_TRANSACTION(State.PLAY, Direction.OUTGOING, 0x32, 0x11),
PLAY_CLOSE_WINDOW(State.PLAY, Direction.OUTGOING, 0x2E, 0x12),
PLAY_OPEN_WINDOW(State.PLAY, Direction.OUTGOING, 0x2D, 0x13),
PLAY_WINDOW_ITEMS(State.PLAY, Direction.OUTGOING, 0x30, 0x14),
PLAY_WINDOW_PROPERTY(State.PLAY, Direction.OUTGOING, 0x31, 0x15),
PLAY_SET_SLOT(State.PLAY, Direction.OUTGOING, 0x2F, 0x16),
PLAY_SET_COOLDOWN(State.PLAY, Direction.OUTGOING, -1, 0x17),
PLAY_PLUGIN_MESSAGE(State.PLAY, Direction.OUTGOING, 0x3F, 0x18),
PLAY_NAMED_SOUND_EFFECT(State.PLAY, Direction.OUTGOING, 0x29, 0x19),
PLAY_DISCONNECT(State.PLAY, Direction.OUTGOING, 0x40, 0x1A),
PLAY_ENTITY_STATUS(State.PLAY, Direction.OUTGOING, 0x1A, 0x1B),
PLAY_EXPLOSION(State.PLAY, Direction.OUTGOING, 0x27, 0x1C),
PLAY_UNLOAD_CHUNK(State.PLAY, Direction.OUTGOING, -1, 0x1D),
PLAY_CHANGE_GAME_STATE(State.PLAY, Direction.OUTGOING, 0x2B, 0x1E),
PLAY_KEEP_ALIVE(State.PLAY, Direction.OUTGOING, 0x00, 0x1F),
PLAY_CHUNK_DATA(State.PLAY, Direction.OUTGOING, 0x21, 0x20),
PLAY_EFFECT(State.PLAY, Direction.OUTGOING, 0x28, 0x21),
PLAY_PARTICLE(State.PLAY, Direction.OUTGOING, 0x2A, 0x22),
PLAY_JOIN_GAME(State.PLAY, Direction.OUTGOING, 0x01, 0x23),
PLAY_MAP(State.PLAY, Direction.OUTGOING, 0x34, 0x24),
PLAY_ENTITY_RELATIVE_MOVE(State.PLAY, Direction.OUTGOING, 0x15, 0x25),
PLAY_ENTITY_LOOK_MOVE(State.PLAY, Direction.OUTGOING, 0x17, 0x26),
PLAY_ENTITY_LOOK(State.PLAY, Direction.OUTGOING, 0x16, 0x27),
PLAY_ENTITY(State.PLAY, Direction.OUTGOING, 0x14, 0x28),
PLAY_VEHICLE_MOVE(State.PLAY, Direction.OUTGOING, -1, 0x29),
PLAY_OPEN_SIGN_EDITOR(State.PLAY, Direction.OUTGOING, 0x36, 0x2A),
PLAY_PLAYER_ABILITIES(State.PLAY, Direction.OUTGOING, 0x39, 0x2B),
PLAY_COMBAT_EVENT(State.PLAY, Direction.OUTGOING, 0x42, 0x2C),
PLAY_PLAYER_LIST_ITEM(State.PLAY, Direction.OUTGOING, 0x38, 0x2D),
PLAY_PLAYER_POSITION_LOOK(State.PLAY, Direction.OUTGOING, 0x08, 0x2E),
PLAY_USE_BED(State.PLAY, Direction.OUTGOING, 0x2F, 0x2F),
PLAY_DESTROY_ENTITIES(State.PLAY, Direction.OUTGOING, 0x13, 0x30),
PLAY_REMOVE_ENTITY_EFFECT(State.PLAY, Direction.OUTGOING, 0x1E, 0x31),
PLAY_RESOURCE_PACK_SEND(State.PLAY, Direction.OUTGOING, 0x48, 0x32),
PLAY_RESPAWN(State.PLAY, Direction.OUTGOING, 0x07, 0x33),
PLAY_ENTITY_HEAD_LOOK(State.PLAY, Direction.OUTGOING, 0x19, 0x34),
PLAY_WORLD_BORDER(State.PLAY, Direction.OUTGOING, 0x44, 0x35),
PLAY_CAMERA(State.PLAY, Direction.OUTGOING, 0x43, 0x36),
PLAY_HELD_ITEM_CHANGE(State.PLAY, Direction.OUTGOING, 0x09, 0x37),
PLAY_DISPLAY_SCOREBOARD(State.PLAY, Direction.OUTGOING, 0x3D, 0x38),
PLAY_ENTITY_METADATA(State.PLAY, Direction.OUTGOING, 0x1C, 0x39),
PLAY_ATTACH_ENTITY(State.PLAY, Direction.OUTGOING, 0x1B, 0x3A),
PLAY_ENTITY_VELOCITY(State.PLAY, Direction.OUTGOING, 0x12, 0x3B),
PLAY_ENTITY_EQUIPMENT(State.PLAY, Direction.OUTGOING, 0x04, 0x3C),
PLAY_SET_XP(State.PLAY, Direction.OUTGOING, 0x1F, 0x3D),
PLAY_UPDATE_HEALTH(State.PLAY, Direction.OUTGOING, 0x06, 0x3E),
PLAY_SCOREBOARD_OBJ(State.PLAY, Direction.OUTGOING, 0x3B, 0x3F),
PLAY_SET_PASSENGERS(State.PLAY, Direction.OUTGOING, -1, 0x40),
PLAY_TEAM(State.PLAY, Direction.OUTGOING, 0x3E, 0x41),
PLAY_UPDATE_SCORE(State.PLAY, Direction.OUTGOING, 0x3C, 0x42),
PLAY_SPAWN_POSITION(State.PLAY, Direction.OUTGOING, 0x05, 0x43),
PLAY_TIME_UPDATE(State.PLAY, Direction.OUTGOING, 0x03, 0x44),
PLAY_TITLE(State.PLAY, Direction.OUTGOING, 0x45, 0x45),
PLAY_UPDATE_SIGN(State.PLAY, Direction.OUTGOING, 0x33, 0x46),
PLAY_SOUND_EFFECT(State.PLAY, Direction.OUTGOING, -1, 0x47),
PLAY_PLAYER_LIST_HEADER_FOOTER(State.PLAY, Direction.OUTGOING, 0x47, 0x48),
PLAY_COLLECT_ITEM(State.PLAY, Direction.OUTGOING, 0x0D, 0x49),
PLAY_ENTITY_TELEPORT(State.PLAY, Direction.OUTGOING, 0x18, 0x4A),
PLAY_ENTITY_PROPERTIES(State.PLAY, Direction.OUTGOING, 0x20, 0x4B),
PLAY_ENTITY_EFFECT(State.PLAY, Direction.OUTGOING, 0x1D, 0x4C),
PLAY_MAP_CHUNK_BULK(State.PLAY, Direction.OUTGOING, 0x26, -1),
PLAY_SET_COMPRESSION(State.PLAY, Direction.OUTGOING, 0x46, -1),
PLAY_UPDATE_ENTITY_NBT(State.PLAY, Direction.OUTGOING, 0x49, -1),;
private State state;
private Direction direction;
private int packetID;
private int newPacketID = -1;
PacketType(State state, Direction direction, int packetID) {
this.state = state;
this.direction = direction;
this.packetID = packetID;
this.newPacketID = packetID;
}
PacketType(State state, Direction direction, int packetID, int newPacketID) {
this.state = state;
this.direction = direction;
this.packetID = packetID;
this.newPacketID = newPacketID;
}
public State getState() {
return state;
}
public Direction getDirection() {
return direction;
}
public int getPacketID() {
return packetID;
}
public int getNewPacketID() {
return newPacketID;
}
public static PacketType findNewPacket(State state, Direction direction, int id) {
if(id == -1)
return null;
for (PacketType pt : values()) {
if (pt.getNewPacketID() == id && id != -1
&& pt.getState() == state
&& pt.getDirection() == direction)
return pt;
}
return null;
}
public static PacketType findOldPacket(State state, Direction direction, int id) {
if(id == -1)
return null;
for (PacketType pt : values()) {
if (pt.getPacketID() == id && id != -1
&& pt.getState() == state
&& pt.getDirection() == direction)
return pt;
}
return null;
}
public static PacketType getIncomingPacket(State state, int id) {
return findNewPacket(state, Direction.INCOMING, id);
}
public static PacketType getOutgoingPacket(State state, int id) {
return findOldPacket(state, Direction.OUTGOING, id);
}
}
package us.myles.ViaVersion.packets;
import java.util.HashMap;
@Deprecated
public enum PacketType {
/* Handshake serverbound */
HANDSHAKE(State.HANDSHAKE, Direction.INCOMING, 0x00), // Mapped
/* Login serverbound */
LOGIN_START(State.LOGIN, Direction.INCOMING, 0x00), // Mapped
LOGIN_ENCRYPTION_RESPONSE(State.LOGIN, Direction.INCOMING, 0x01), // Mapped
/* Login clientbound */
LOGIN_DISCONNECT(State.LOGIN, Direction.OUTGOING, 0x00), // Mapped
LOGIN_ENCRYPTION_REQUEST(State.LOGIN, Direction.OUTGOING, 0x01), // Mapped
LOGIN_SUCCESS(State.LOGIN, Direction.OUTGOING, 0x02), // Mapped
LOGIN_SETCOMPRESSION(State.LOGIN, Direction.OUTGOING, 0x03), // Mapped
/* Status serverbound */
STATUS_REQUEST(State.STATUS, Direction.INCOMING, 0x00), // Mapped
STATUS_PING(State.STATUS, Direction.INCOMING, 0x01), // Mapped
/* Status clientbound */
STATUS_RESPONSE(State.STATUS, Direction.OUTGOING, 0x00),
STATUS_PONG(State.STATUS, Direction.OUTGOING, 0x01),
/* Play serverbound */
PLAY_TP_CONFIRM(State.PLAY, Direction.INCOMING, -1, 0x00), // Mapped
PLAY_TAB_COMPLETE_REQUEST(State.PLAY, Direction.INCOMING, 0x14, 0x01), // Mapped
PLAY_CHAT_MESSAGE_CLIENT(State.PLAY, Direction.INCOMING, 0x01, 0x02), // Mapped
PLAY_CLIENT_STATUS(State.PLAY, Direction.INCOMING, 0x16, 0x03), // Mapped
PLAY_CLIENT_SETTINGS(State.PLAY, Direction.INCOMING, 0x15, 0x04), // Mapped
PLAY_CONFIRM_TRANS(State.PLAY, Direction.INCOMING, 0x0F, 0x05), // Mapped
PLAY_ENCHANT_ITEM(State.PLAY, Direction.INCOMING, 0x11, 0x06), // Mapped
PLAY_CLICK_WINDOW(State.PLAY, Direction.INCOMING, 0x0E, 0x07), // Mapped
PLAY_CLOSE_WINDOW_REQUEST(State.PLAY, Direction.INCOMING, 0x0D, 0x08), // Mapped
PLAY_PLUGIN_MESSAGE_REQUEST(State.PLAY, Direction.INCOMING, 0x17, 0x09),
PLAY_USE_ENTITY(State.PLAY, Direction.INCOMING, 0x02, 0x0A), // Mapped
PLAY_KEEP_ALIVE_REQUEST(State.PLAY, Direction.INCOMING, 0x00, 0x0B), // Mapped
PLAY_PLAYER_POSITION_REQUEST(State.PLAY, Direction.INCOMING, 0x04, 0x0C), // Mapped
PLAY_PLAYER_POSITION_LOOK_REQUEST(State.PLAY, Direction.INCOMING, 0x06, 0x0D), // Mapped
PLAY_PLAYER_LOOK_REQUEST(State.PLAY, Direction.INCOMING, 0x05, 0x0E), // Mapped
PLAY_PLAYER(State.PLAY, Direction.INCOMING, 0x03, 0x0F), // Mapped
PLAY_VEHICLE_MOVE_REQUEST(State.PLAY, Direction.INCOMING, -1, 0x10), // Mapped
PLAY_STEER_BOAT(State.PLAY, Direction.INCOMING, -1, 0x11), // Mapped
PLAY_PLAYER_ABILITIES_REQUEST(State.PLAY, Direction.INCOMING, 0x13, 0x12), // Mapped
PLAY_PLAYER_DIGGING(State.PLAY, Direction.INCOMING, 0x07, 0x13), // Mapped
PLAY_ENTITY_ACTION(State.PLAY, Direction.INCOMING, 0x0B, 0x14), // Mapped
PLAY_STEER_VEHICLE(State.PLAY, Direction.INCOMING, 0x0C, 0x15), // Mapped
PLAY_RESOURCE_PACK_STATUS(State.PLAY, Direction.INCOMING, 0x19, 0x16), // Mapped
PLAY_HELD_ITEM_CHANGE_REQUEST(State.PLAY, Direction.INCOMING, 0x09, 0x17), // Mapped
PLAY_CREATIVE_INVENTORY_ACTION(State.PLAY, Direction.INCOMING, 0x10, 0x18), // Mapped
PLAY_UPDATE_SIGN_REQUEST(State.PLAY, Direction.INCOMING, 0x12, 0x19), // Mapped
PLAY_ANIMATION_REQUEST(State.PLAY, Direction.INCOMING, 0x0A, 0x1A), // Mapped
PLAY_SPECTATE(State.PLAY, Direction.INCOMING, 0x18, 0x1B), // Mapped
PLAY_PLAYER_BLOCK_PLACEMENT(State.PLAY, Direction.INCOMING, 0x08, 0x1C), // Mapped
PLAY_USE_ITEM(State.PLAY, Direction.INCOMING, -1, 0x1D), // Mapped
/* Play clientbound */
PLAY_SPAWN_OBJECT(State.PLAY, Direction.OUTGOING, 0x0E, 0x00), // Mapped
PLAY_SPAWN_XP_ORB(State.PLAY, Direction.OUTGOING, 0x11, 0x01), // Mapped
PLAY_SPAWN_GLOBAL_ENTITY(State.PLAY, Direction.OUTGOING, 0x2C, 0x02), // Mapped
PLAY_SPAWN_MOB(State.PLAY, Direction.OUTGOING, 0x0F, 0x03), // Mapped
PLAY_SPAWN_PAINTING(State.PLAY, Direction.OUTGOING, 0x10, 0x04), // Mapped
PLAY_SPAWN_PLAYER(State.PLAY, Direction.OUTGOING, 0x0C, 0x05), // Mapped
PLAY_ANIMATION(State.PLAY, Direction.OUTGOING, 0x0B, 0x06), // Mapped
PLAY_STATS(State.PLAY, Direction.OUTGOING, 0x37, 0x07), // Mapped
PLAY_BLOCK_BREAK_ANIMATION(State.PLAY, Direction.OUTGOING, 0x25, 0x08), // Mapped
PLAY_UPDATE_BLOCK_ENTITY(State.PLAY, Direction.OUTGOING, 0x35, 0x09), // Mapped
PLAY_BLOCK_ACTION(State.PLAY, Direction.OUTGOING, 0x24, 0x0A), // Mapped
PLAY_BLOCK_CHANGE(State.PLAY, Direction.OUTGOING, 0x23, 0x0B), // Mapped
PLAY_BOSS_BAR(State.PLAY, Direction.OUTGOING, -1, 0x0C),
PLAY_SERVER_DIFFICULTY(State.PLAY, Direction.OUTGOING, 0x41, 0x0D), // Mapped
PLAY_TAB_COMPLETE(State.PLAY, Direction.OUTGOING, 0x3A, 0x0E), // Mapped
PLAY_CHAT_MESSAGE(State.PLAY, Direction.OUTGOING, 0x02, 0x0F), // Mapped
PLAY_MULTI_BLOCK_CHANGE(State.PLAY, Direction.OUTGOING, 0x22, 0x10), // Mapped
PLAY_CONFIRM_TRANSACTION(State.PLAY, Direction.OUTGOING, 0x32, 0x11), // Mapped
PLAY_CLOSE_WINDOW(State.PLAY, Direction.OUTGOING, 0x2E, 0x12), // Mapped
PLAY_OPEN_WINDOW(State.PLAY, Direction.OUTGOING, 0x2D, 0x13), // Mapped
PLAY_WINDOW_ITEMS(State.PLAY, Direction.OUTGOING, 0x30, 0x14), // Mapped
PLAY_WINDOW_PROPERTY(State.PLAY, Direction.OUTGOING, 0x31, 0x15), // Mapped
PLAY_SET_SLOT(State.PLAY, Direction.OUTGOING, 0x2F, 0x16), // Mapped
PLAY_SET_COOLDOWN(State.PLAY, Direction.OUTGOING, -1, 0x17),
PLAY_PLUGIN_MESSAGE(State.PLAY, Direction.OUTGOING, 0x3F, 0x18), // Mapped
PLAY_NAMED_SOUND_EFFECT(State.PLAY, Direction.OUTGOING, 0x29, 0x19), // Mapped
PLAY_DISCONNECT(State.PLAY, Direction.OUTGOING, 0x40, 0x1A), // Mapped
PLAY_ENTITY_STATUS(State.PLAY, Direction.OUTGOING, 0x1A, 0x1B), // Mapped
PLAY_EXPLOSION(State.PLAY, Direction.OUTGOING, 0x27, 0x1C), // Mapped
PLAY_UNLOAD_CHUNK(State.PLAY, Direction.OUTGOING, -1, 0x1D),
PLAY_CHANGE_GAME_STATE(State.PLAY, Direction.OUTGOING, 0x2B, 0x1E),
PLAY_KEEP_ALIVE(State.PLAY, Direction.OUTGOING, 0x00, 0x1F), // Mapped
PLAY_CHUNK_DATA(State.PLAY, Direction.OUTGOING, 0x21, 0x20), // Mapped
PLAY_EFFECT(State.PLAY, Direction.OUTGOING, 0x28, 0x21), // Mapped
PLAY_PARTICLE(State.PLAY, Direction.OUTGOING, 0x2A, 0x22), // Mapped
PLAY_JOIN_GAME(State.PLAY, Direction.OUTGOING, 0x01, 0x23), // Mapped
PLAY_MAP(State.PLAY, Direction.OUTGOING, 0x34, 0x24), // Mapped
PLAY_ENTITY_RELATIVE_MOVE(State.PLAY, Direction.OUTGOING, 0x15, 0x25), // Mapped
PLAY_ENTITY_LOOK_MOVE(State.PLAY, Direction.OUTGOING, 0x17, 0x26), // Mapped
PLAY_ENTITY_LOOK(State.PLAY, Direction.OUTGOING, 0x16, 0x27), // Mapped
PLAY_ENTITY(State.PLAY, Direction.OUTGOING, 0x14, 0x28), // Mapped
PLAY_VEHICLE_MOVE(State.PLAY, Direction.OUTGOING, -1, 0x29),
PLAY_OPEN_SIGN_EDITOR(State.PLAY, Direction.OUTGOING, 0x36, 0x2A), // Mapped
PLAY_PLAYER_ABILITIES(State.PLAY, Direction.OUTGOING, 0x39, 0x2B), // Mapped
PLAY_COMBAT_EVENT(State.PLAY, Direction.OUTGOING, 0x42, 0x2C), // Mapped
PLAY_PLAYER_LIST_ITEM(State.PLAY, Direction.OUTGOING, 0x38, 0x2D), // Mapped
PLAY_PLAYER_POSITION_LOOK(State.PLAY, Direction.OUTGOING, 0x08, 0x2E), // Mapped
PLAY_USE_BED(State.PLAY, Direction.OUTGOING, 0x0A, 0x2F), // Mapped
PLAY_DESTROY_ENTITIES(State.PLAY, Direction.OUTGOING, 0x13, 0x30), // Mapped
PLAY_REMOVE_ENTITY_EFFECT(State.PLAY, Direction.OUTGOING, 0x1E, 0x31), // Mapped
PLAY_RESOURCE_PACK_SEND(State.PLAY, Direction.OUTGOING, 0x48, 0x32), // Mapped
PLAY_RESPAWN(State.PLAY, Direction.OUTGOING, 0x07, 0x33), // Mapped
PLAY_ENTITY_HEAD_LOOK(State.PLAY, Direction.OUTGOING, 0x19, 0x34), // Mapped
PLAY_WORLD_BORDER(State.PLAY, Direction.OUTGOING, 0x44, 0x35), // Mapped
PLAY_CAMERA(State.PLAY, Direction.OUTGOING, 0x43, 0x36), // Mapped
PLAY_HELD_ITEM_CHANGE(State.PLAY, Direction.OUTGOING, 0x09, 0x37), // Mapped
PLAY_DISPLAY_SCOREBOARD(State.PLAY, Direction.OUTGOING, 0x3D, 0x38), // Mapped
PLAY_ENTITY_METADATA(State.PLAY, Direction.OUTGOING, 0x1C, 0x39), // Mapped
PLAY_ATTACH_ENTITY(State.PLAY, Direction.OUTGOING, 0x1B, 0x3A), // Mapped
PLAY_ENTITY_VELOCITY(State.PLAY, Direction.OUTGOING, 0x12, 0x3B), // Mapped
PLAY_ENTITY_EQUIPMENT(State.PLAY, Direction.OUTGOING, 0x04, 0x3C), // Mapped
PLAY_SET_XP(State.PLAY, Direction.OUTGOING, 0x1F, 0x3D), // Mapped
PLAY_UPDATE_HEALTH(State.PLAY, Direction.OUTGOING, 0x06, 0x3E), // Mapped
PLAY_SCOREBOARD_OBJ(State.PLAY, Direction.OUTGOING, 0x3B, 0x3F), // Mapped
PLAY_SET_PASSENGERS(State.PLAY, Direction.OUTGOING, -1, 0x40),
PLAY_TEAM(State.PLAY, Direction.OUTGOING, 0x3E, 0x41), // Mapped
PLAY_UPDATE_SCORE(State.PLAY, Direction.OUTGOING, 0x3C, 0x42), // Mapped
PLAY_SPAWN_POSITION(State.PLAY, Direction.OUTGOING, 0x05, 0x43), // Mapped
PLAY_TIME_UPDATE(State.PLAY, Direction.OUTGOING, 0x03, 0x44), // Mapped
PLAY_TITLE(State.PLAY, Direction.OUTGOING, 0x45, 0x45), // Mapped
PLAY_UPDATE_SIGN(State.PLAY, Direction.OUTGOING, 0x33, 0x46), // Mapped
PLAY_SOUND_EFFECT(State.PLAY, Direction.OUTGOING, -1, 0x47),
PLAY_PLAYER_LIST_HEADER_FOOTER(State.PLAY, Direction.OUTGOING, 0x47, 0x48), // Mapped
PLAY_COLLECT_ITEM(State.PLAY, Direction.OUTGOING, 0x0D, 0x49), // Mapped
PLAY_ENTITY_TELEPORT(State.PLAY, Direction.OUTGOING, 0x18, 0x4A), // Mapped
PLAY_ENTITY_PROPERTIES(State.PLAY, Direction.OUTGOING, 0x20, 0x4B), // Mapped
PLAY_ENTITY_EFFECT(State.PLAY, Direction.OUTGOING, 0x1D, 0x4C), // Mapped
PLAY_MAP_CHUNK_BULK(State.PLAY, Direction.OUTGOING, 0x26, -1),
PLAY_SET_COMPRESSION(State.PLAY, Direction.OUTGOING, 0x46, -1),
PLAY_UPDATE_ENTITY_NBT(State.PLAY, Direction.OUTGOING, 0x49, -1);
private static HashMap<Short, PacketType> oldids = new HashMap<>();
private static HashMap<Short, PacketType> newids = new HashMap<>();
static {
for (PacketType pt : PacketType.values()) {
oldids.put(toShort((short) pt.getPacketID(), (short) pt.getDirection().ordinal(), (short) pt.getState().ordinal()), pt);
newids.put(toShort((short) pt.getNewPacketID(), (short) pt.getDirection().ordinal(), (short) pt.getState().ordinal()), pt);
}
}
private State state;
private Direction direction;
private int packetID;
private int newPacketID = -1;
PacketType(State state, Direction direction, int packetID) {
this.state = state;
this.direction = direction;
this.packetID = packetID;
this.newPacketID = packetID;
}
PacketType(State state, Direction direction, int packetID, int newPacketID) {
this.state = state;
this.direction = direction;
this.packetID = packetID;
this.newPacketID = newPacketID;
}
public static PacketType findNewPacket(State state, Direction direction, int id) {
return newids.get(toShort((short) id, (short) direction.ordinal(), (short) state.ordinal()));
}
public static PacketType findOldPacket(State state, Direction direction, int id) {
return oldids.get(toShort((short) id, (short) direction.ordinal(), (short) state.ordinal()));
}
public static PacketType getIncomingPacket(State state, int id) {
return findNewPacket(state, Direction.INCOMING, id);
}
public static PacketType getOutgoingPacket(State state, int id) {
return findOldPacket(state, Direction.OUTGOING, id);
}
private static short toShort(short id, short direction, short state) {
return (short) ((id & 0x00FF) | (direction << 8) & 0x0F00 | (state << 12) & 0xF000);
}
public State getState() {
return state;
}
public Direction getDirection() {
return direction;
}
public int getPacketID() {
return packetID;
}
public int getNewPacketID() {
return newPacketID;
}
}
@@ -0,0 +1,171 @@
package us.myles.ViaVersion.protocols.base;
import org.apache.commons.lang.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.Pair;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.protocol.Protocol;
import us.myles.ViaVersion.api.protocol.ProtocolPipeline;
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
import us.myles.ViaVersion.api.remapper.PacketHandler;
import us.myles.ViaVersion.api.remapper.PacketRemapper;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.packets.State;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
public class BaseProtocol extends Protocol {
@Override
protected void registerPackets() {
/* Outgoing Packets */
registerOutgoing(State.STATUS, 0x00, 0x00, new PacketRemapper() { // Status Response Packet
@Override
public void registerMap() {
map(Type.STRING);
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
ProtocolInfo info = wrapper.user().get(ProtocolInfo.class);
String originalStatus = wrapper.get(Type.STRING, 0);
try {
JSONObject json = (JSONObject) new JSONParser().parse(originalStatus);
JSONObject version = (JSONObject) json.get("version");
if (ProtocolRegistry.SERVER_PROTOCOL == -1) {
Long original = (Long) version.get("protocol");
ProtocolRegistry.SERVER_PROTOCOL = original.intValue();
}
List<Pair<Integer, Protocol>> protocols = ProtocolRegistry.getProtocolPath(info.getProtocolVersion(), ProtocolRegistry.SERVER_PROTOCOL);
if (protocols != null) {
if ((long) version.get("protocol") != 9999) //Fix serverlistplus
version.put("protocol", info.getProtocolVersion());
} else {
// not compatible :(, *plays very sad violin*
wrapper.user().setActive(false);
}
wrapper.set(Type.STRING, 0, json.toJSONString()); // Update value
} catch (ParseException e) {
e.printStackTrace();
}
}
});
}
});
registerOutgoing(State.STATUS, 0x01, 0x01); // Status Pong Packet
registerOutgoing(State.LOGIN, 0x00, 0x00); // Login Disconnect Packet
registerOutgoing(State.LOGIN, 0x01, 0x01); // Encryption Request Packet
// Login Success Packet
registerOutgoing(State.LOGIN, 0x02, 0x02, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.STRING); // 0 - UUID as String
map(Type.STRING); // 1 - Player Username
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
ProtocolInfo info = wrapper.user().get(ProtocolInfo.class);
info.setState(State.PLAY);
// Save other info
UUID uuid = UUID.fromString(wrapper.get(Type.STRING, 0));
info.setUuid(uuid);
info.setUsername(wrapper.get(Type.STRING, 1));
// Add to ported clients
((ViaVersionPlugin) ViaVersion.getInstance()).addPortedClient(wrapper.user());
if (ViaVersion.getInstance().isDebug()) {
// Print out the route to console
((ViaVersionPlugin) ViaVersion.getInstance()).getLogger().log(Level.INFO, "{0} logged in with protocol {1}, Route: {2}",
new Object[]{
wrapper.get(Type.STRING, 1),
info.getProtocolVersion(),
StringUtils.join(info.getPipeline().pipes(), ", ")
});
}
}
});
}
});
registerOutgoing(State.LOGIN, 0x03, 0x03); // Login Set Compression Packet
/* Incoming Packets */
// Handshake Packet
registerIncoming(State.HANDSHAKE, 0x00, 0x00, new PacketRemapper() {
@Override
public void registerMap() {
// select right protocol
map(Type.VAR_INT); // 0 - Client Protocol Version
map(Type.STRING); // 1 - Server Address
map(Type.UNSIGNED_SHORT); // 2 - Server Port
map(Type.VAR_INT); // 3 - Next State
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
int protVer = wrapper.get(Type.VAR_INT, 0);
int state = wrapper.get(Type.VAR_INT, 1);
ProtocolInfo info = wrapper.user().get(ProtocolInfo.class);
info.setProtocolVersion(protVer);
// Choose the pipe
List<Pair<Integer, Protocol>> protocols = ProtocolRegistry.getProtocolPath(info.getProtocolVersion(), ProtocolRegistry.SERVER_PROTOCOL);
ProtocolPipeline pipeline = wrapper.user().get(ProtocolInfo.class).getPipeline();
if (protocols != null) {
for (Pair<Integer, Protocol> prot : protocols) {
pipeline.add(prot.getValue());
}
wrapper.set(Type.VAR_INT, 0, ProtocolRegistry.SERVER_PROTOCOL);
} else {
if (state == 2) {
// not compatible :(, *plays very sad violin*
wrapper.user().setActive(false);
}
}
// Change state
if (state == 1) {
info.setState(State.STATUS);
}
if (state == 2) {
info.setState(State.LOGIN);
}
}
});
}
});
registerIncoming(State.STATUS, 0x00, 0x00); // Status Request Packet
registerIncoming(State.STATUS, 0x01, 0x01); // Status Ping Packet
registerIncoming(State.LOGIN, 0x00, 0x00); // Login Start Packet
registerIncoming(State.LOGIN, 0x01, 0x01); // Encryption Response Packet
}
@Override
public void init(UserConnection userConnection) {
// Nothing gets added, ProtocolPipeline handles ProtocolInfo
}
@Override
protected void registerListeners() {
final ViaVersionPlugin plugin = (ViaVersionPlugin) Bukkit.getPluginManager().getPlugin("ViaVersion");
Bukkit.getPluginManager().registerEvents(new Listener() {
@EventHandler
public void onPlayerQuit(PlayerQuitEvent e) {
plugin.removePortedClient(e.getPlayer().getUniqueId());
}
}, plugin);
}
}
@@ -0,0 +1,24 @@
package us.myles.ViaVersion.protocols.base;
import lombok.Getter;
import lombok.Setter;
import us.myles.ViaVersion.api.data.StoredObject;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.protocol.ProtocolPipeline;
import us.myles.ViaVersion.packets.State;
import java.util.UUID;
@Getter
@Setter
public class ProtocolInfo extends StoredObject {
private State state = State.HANDSHAKE;
private int protocolVersion = -1;
private String username;
private UUID uuid;
private ProtocolPipeline pipeline;
public ProtocolInfo(UserConnection user) {
super(user);
}
}
Loaded 100 of 154 files, more files were not shown because too many files have changed in this diff. Show more