Compare commits

...
230 Commits
Author SHA1 Message Date
Myles f256309487 Bump version to 1.0.2 2016-12-20 16:07:37 +00:00
Myles 462abb1ef9 Update to snapshot 1.11.1 2016-12-15 15:39:38 +00:00
Myles a35408d14f New config option for disabling piston animation for 1.11 clients #570 2016-12-15 15:32:54 +00:00
Myles 81d4deaea7 Fix block metadata #580 2016-11-28 23:47:49 +00:00
Myles 9103f89aff 1.0.2-SNAPSHOT 2016-11-16 19:58:59 +00:00
Myles 8e4c2648a3 1.0.1 Release 2016-11-16 19:57:20 +00:00
Myles ad020ec329 Fix wrong packet format for 1.8 brewing #562 2016-11-16 18:14:47 +00:00
Matsv df3be302af Send the chunkbulk packets immediately. Fixes #535 2016-11-16 17:15:36 +01:00
Gianluca Falcomer 8e3b8cb572 Update ViaCommandHandler.java (#558) 2016-11-16 16:15:24 +01:00
Myles ff1554556e Fixed 1.7 UUID, oops. Thanks @MineTheCube 2016-11-15 21:17:39 +00:00
Myles b15c93c416 Use length for UUID compat as contains is expensive 2016-11-15 19:53:22 +00:00
Myles 071b42c9e0 Fix 1.7.2 support when used with ProtocolSupport 2016-11-15 19:11:40 +00:00
Matsv 304f9b34fd Send empty metadata flags on server switch to prevent an Elytra glitch on 1.8 fixes #555 2016-11-15 18:10:14 +01:00
Myles c817a0e9cb Add null check to hand patch 2016-11-15 17:07:31 +00:00
Myles 744252d492 Don't handle null users 2016-11-15 17:01:22 +00:00
Myles 9186361a29 Change ConcurrentHashMaps to just Maps for Java 7 support 2016-11-15 15:17:16 +00:00
Myles bf01c9ea0e Fix getting connection twice 2016-11-15 08:17:15 +00:00
Myles bee260e2b4 Ignore null users 2016-11-14 23:42:29 +00:00
Myles 21811991f1 Correct elytra dropping, fixes #545 2016-11-14 23:35:47 +00:00
Myles a2809f8d5c Add count to /viaver list, #540 2016-11-14 22:38:39 +00:00
Myles 95f2b597da This is billy, he got lost on his way to the last commit, apologies. 2016-11-14 22:20:08 +00:00
Myles fa348fbc23 Fix villager trading on 1.11 #534 2016-11-14 22:17:23 +00:00
Matsv d277701caa Ignore if the setMainHand doesn't exist 2016-11-14 21:13:18 +01:00
Matsv 9b7f68a888 Store the mainHand and change it on serverChange for Bungee, fixes #536 2016-11-14 20:59:06 +01:00
Myles 7e837ef9db Ensure we don't save and load config at same time 2016-11-14 18:46:27 +00:00
Myles eb78fe4bfc Better flexibility with number loading 2016-11-14 18:29:45 +00:00
Matsv 689f0fd5db Back to the snapshots 2016-11-14 19:17:20 +01:00
Myles 32316cf3ab Fix character limit to 100 for messages, #530 2016-11-14 18:14:49 +00:00
Matsv d450c9b4d6 1.11 and bump version 2016-11-14 16:15:20 +01:00
Myles 622673d1d3 Small javadoc tweaks 2016-11-14 13:21:06 +00:00
Myles 1209beb47d Allow servers to manually be probed with API 2016-11-14 12:38:39 +00:00
Myles f4eeb94a2e Better support for malformed json packets #528 2016-11-14 12:03:22 +00:00
Myles fac7eab59e Prepare for 1.0.0 2016-11-13 14:04:56 +00:00
Myles e430bfce06 Fix uninjection when different handler order 2016-11-13 13:34:22 +00:00
Matsv dd55cc3cf2 Merge branch '1.11-DEV' of https://github.com/MylesIsCool/ViaVersion into 1.11-DEV 2016-11-13 14:26:21 +01:00
Matsv 9937a173d1 Use the correct platform name and version for Sponge 2016-11-13 14:26:04 +01:00
Myles 1c584040ca Use logger instead of System.out 2016-11-13 13:25:56 +00:00
Myles 10a2df5a7d Use plugin description from project pom.xml and fix sponge.
This disables the sponge plugin annotation processor and uses our own mcmod.info
2016-11-13 13:15:26 +00:00
Matsv 1bec3cf1d0 Change the metadata transformer fail message 2016-11-13 13:36:03 +01:00
Matsv 4142797380 Implement PlatformVersion for better dump output 2016-11-13 12:36:48 +01:00
Matsv 68fc884d2a Change the platform name to the full name that includes the version 2016-11-12 13:16:27 +01:00
Matsv 2872bdd1c3 Update the snapshot comment to 1.11-pre1 2016-11-08 16:09:00 +01:00
Matsv 7d29a0c0af 1.11-pre1 2016-11-08 16:02:11 +01:00
Matsv dd6423de06 Remove event-based commandblock listeners 2016-11-06 11:30:28 +01:00
Matsv 52bbf1affe Handle the actionbar packet change 2016-11-06 10:37:26 +01:00
Matsv cfaded6cf8 Make CommandBlocks work on BungeeCord with 1.8.8 child servers 2016-11-02 18:14:57 +01:00
Matsv 69e444f83d Fix Bungee constant entity ids 2016-11-02 18:07:21 +01:00
Matsv c896ed5f63 Move the Bungee server switch handler to an event instead of inside the encoder, this will also make ViaBackwards work correctly 2016-11-02 17:17:41 +01:00
Myles 9f8456a336 16w43a compatibility 2016-10-27 13:23:30 +01:00
Myles bd11c98e45 Better support for ChannelInitializer detection (incase they do something funny, fixes latest PS dev) 2016-10-26 17:34:09 +01:00
Myles 55fccba711 Support for new PS when package isn't found 2016-10-26 17:33:16 +01:00
Matsv 783542401b Update sounds to 16w42a 2016-10-25 19:31:32 +02:00
Matsv 2424057536 Translate messages from legacy, fix #521 2016-10-25 18:34:20 +02:00
Myles b6dbe82d16 Fix lower version support (default to client version if we can't port it instead of server) #519 2016-10-23 21:18:18 +01:00
Max Qian f92b7e5b80 Tell ProtocolSupport to decode MINECRAFT_FUTURE packets using the default decoder (for 1.9.4) 2016-10-19 14:44:25 +01:00
Myles 8093c424e2 WIP fix, ping works but it still doesn't connect 2016-10-19 14:44:25 +01:00
Matsv 839d46f5ed Merge remote-tracking branch 'upstream/1.11-DEV' into 1.11-DEV 2016-10-19 15:31:45 +02:00
Matsv de0b9a2a68 16w42a 2016-10-19 15:31:29 +02:00
Myles c3bd45cd58 Better naming for version info 2016-10-17 23:05:21 +01:00
Myles c4bab6c9af Optimise reflection in some cases where method isn't cached. 2016-10-16 16:25:53 +01:00
Myles f33d22531b Merge branch 'master' into 1.11-DEV 2016-10-14 23:07:50 +01:00
Myles 9ccbdb69c5 Fix #515 Disconnect Message not being fixed json 2016-10-14 23:06:11 +01:00
Myles e9008923eb Revert "Add json fixing to login disconnect #515"
This reverts commit 301e84d698.
2016-10-14 23:03:40 +01:00
Myles 301e84d698 Add json fixing to login disconnect #515 2016-10-14 23:02:11 +01:00
Matsv 5aad3306eb 16w41a 2016-10-13 17:01:04 +02:00
Matsv d30bbcd4a3 16w40a 2016-10-06 16:40:47 +02:00
Matsv 003197b476 Change circle.yml to java 8 since Sponge uses Java 8 2016-10-05 20:10:22 +02:00
Myles a3e15bce4d Use correct tags for javadocs 2016-10-04 21:57:14 +01:00
Matsv e43026231e Move sponge-legacy up 2016-10-04 21:20:59 +02:00
Matsv f100f6e3f0 Rename Snapshot to 1.11 2016-10-04 20:04:49 +02:00
Mats 8ae2842e5f Merge pull request #509 from MylesIsCool/modular
Merge modular into 1.11
2016-10-04 19:57:24 +02:00
Matsv 54be03bf77 Merge branches '1.11-DEV' and 'modular' of https://github.com/MylesIsCool/ViaVersion into modular 2016-10-04 19:35:48 +02:00
Matsv 27fc4dd684 Rewrite sounds, thanks @Pokechu22 for open-sourcing your forks of Hamburglar & Burger Vitrine :) 2016-10-04 19:35:20 +02:00
Myles 2a1f0f812b Move Sponge to API 5, add legacy support module 2016-10-04 00:26:27 +01:00
Myles 64cde13ea7 Ensure order is kept with maps & yaml (as well as concurrency with maps) 2016-10-02 20:50:34 +01:00
Matsv 7d23b12f85 Implement the UpdateListener for Bungee 2016-10-02 21:35:54 +02:00
Myles 4b3f757881 Rename scan servers to probe 2016-10-02 19:45:55 +01:00
Myles d0e7f05d50 Remove commented line 2016-10-02 19:41:02 +01:00
Myles 21c957b8d5 Config for protocol versions
Also make config concurrent
2016-10-02 19:40:38 +01:00
Matsv 3fe25f68b1 Fix another infinite loop, @MylesIsCool and I are great at creating them ;) 2016-10-02 12:03:56 +02:00
Matsv 3354a46283 Remove some more debug messages 2016-10-02 11:41:18 +02:00
Matsv 975743c76f Merge branch 'modular' of https://github.com/MylesIsCool/ViaVersion into modular 2016-10-02 11:28:10 +02:00
Matsv d3b214965b Add server info to the dump (#505) 2016-10-02 11:27:45 +02:00
Myles eb8065ad20 Tab complete for bungee 2016-10-01 21:30:39 +01:00
Matsv 7d3548956e Fix 16w39c 2016-10-01 20:56:14 +02:00
Matsv 3de961f641 Remove infinite loop 2016-10-01 20:26:04 +02:00
Matsv 59620f7f93 Add a command to force search versions @ Bungee 2016-10-01 15:38:53 +02:00
Matsv ba3aa4566e Remove some debug messages that prevent Jenkins from building. 2016-10-01 14:56:08 +02:00
Matsv 8445a6d9db Fix wrong handling if the client and child server have the same protocol id 2016-10-01 14:27:39 +02:00
Matsv f53c8c67e2 Fix Bukkit config NPE, only change the protocol id if ViaVersion can support it and support unsupported Bungee protocol ids (Not working correctly yet) 2016-10-01 13:31:14 +02:00
Myles b4976bd302 Merge branch 'modular' of https://github.com/MylesIsCool/ViaVersion into modular 2016-10-01 00:11:08 +01:00
Myles ec848d7201 Reflection for Bungee stuffs 2016-10-01 00:10:54 +01:00
Matsv 8c03a296c2 Merge branch 'modular' of https://github.com/MylesIsCool/ViaVersion into modular 2016-10-01 00:59:56 +02:00
Matsv 65a6e25f1b Remove debug message 2016-10-01 00:59:42 +02:00
Myles 178b625ca0 Merge branch 'modular' of https://github.com/MylesIsCool/ViaVersion into modular 2016-09-30 23:55:21 +01:00
Matsv 152993f749 Get bungee protocol version detection working. Still some odd issues. 2016-10-01 00:53:50 +02:00
Matsv ca246f9d95 Merge branch 'modular' of https://github.com/MylesIsCool/ViaVersion into modular 2016-09-30 23:02:53 +02:00
Matsv f1d53bb7ac Start working on Bungee protocol id detection. 2016-09-30 23:02:34 +02:00
Myles 30950a7d74 Don't include guava in the jar & go for lower version for bukkit compatibility 2016-09-30 20:51:01 +01:00
Myles 305f6b7ce2 Implement Hand Item Cache for Sponge 2016-09-30 20:48:02 +01:00
Matsv 313b794285 Merge branch 'modular' of https://github.com/MylesIsCool/ViaVersion into modular 2016-09-30 20:09:03 +02:00
Matsv 7031d431da Implement 1_11 entity / parent class structure and patch holograms the other way around! Thanks for fixing Mojang :-) #482 2016-09-30 20:08:39 +02:00
Myles 655e14b36e Make dumping pretty print + add Bungee dumping 2016-09-30 16:30:28 +01:00
Matsv f881f3d484 Merge branches '1.11-DEV' and 'modular' of https://github.com/MylesIsCool/ViaVersion into modular
# Conflicts:
#	pom.xml
2016-09-30 17:19:51 +02:00
Matsv 4d3302a926 Support for 16w39c 2016-09-30 17:14:14 +02:00
Matsv b2df970af5 Implement removePortedClient on Bungee 2016-09-30 16:20:29 +02:00
Myles b7b322a525 Full config api for all platforms using snakeyaml + comments 2016-09-30 00:34:16 +01:00
Myles 771c00b146 Implement Task Ids 2016-09-29 22:55:08 +01:00
Myles 23f1589c28 Update commands to add new platform specific command also add platform to updater. 2016-09-29 22:35:51 +01:00
Myles eb72db9a5f Update TODO 2016-09-29 21:30:09 +01:00
Myles 10fc8f846d Fix PacketWrapper sending and implement Movement Transmitter for Bungee 2016-09-29 21:29:58 +01:00
Myles 31c9332e56 Fix chunks for BungeeCord 2016-09-29 20:46:31 +01:00
Myles b0d64bfebd Fix a bug in chunks (still not working fully)
Also remove bungeecord-proxy
2016-09-29 20:40:58 +01:00
Matsv ffbd399993 16w39b 2016-09-29 18:43:13 +02:00
Matsv aeec7e5f95 Start working on packet-level chunk bulks 2016-09-29 16:33:14 +02:00
Myles 36301a595b Fix Bungee Support (Excluding Chunks) + Rename Handlers 2016-09-29 15:25:18 +01:00
Matsv a864bf7c18 Support for 16w39a 2016-09-28 16:14:52 +02:00
Matsv 0454169588 Add viaver alias 2016-09-27 19:38:13 +02:00
Matsv 8ea3623a79 Stop using new Gson() everywhere (#505) 2016-09-27 19:15:39 +02:00
Myles 866e494d3c Remove Commons 2016-09-27 17:48:56 +01:00
Myles d5108061c1 Implement World Change 2016-09-27 17:38:56 +01:00
Myles 396998c7fc Factor & Javadoc update 2016-09-27 17:31:10 +01:00
Matsv ff3d76a387 Move the todo list to #505 2016-09-26 22:45:54 +02:00
Matsv 51c469882b Port Bukkit listeners to Sponge 2016-09-26 22:30:59 +02:00
Myles 8b9a1750de Basic Config API for sponge, need to do comments 2016-09-26 20:12:34 +01:00
Myles 3411c3d144 Add encoder name 2016-09-26 17:57:36 +01:00
Myles cdab5b3f5b Inject into Bungee, (does not get past login from when i've tested)
Also add commands
2016-09-26 14:48:46 +01:00
Myles 42edffb309 Change reflection to NMSUtil, and start work on Bungee (doesn't work) 2016-09-26 13:50:20 +01:00
Matsv 42efc736c3 Cleanup metadata 2016-09-26 14:36:10 +02:00
Myles 30bb91fc8a Revert Mats moving the repo 2016-09-26 13:14:38 +01:00
Myles 14daca5fea Fix 1.9.4+ support and also fix sponge support to work better.
Tested on SpongeVanilla + SpongeForge
(1.8.8 & 1.9.4)
2016-09-26 13:11:46 +01:00
Matsv 8396c5a3e3 Merge branch 'modular' of https://github.com/MylesIsCool/ViaVersion into modular 2016-09-26 13:25:47 +02:00
Matsv e136d1db94 Basic Bungee structure 2016-09-26 13:25:28 +02:00
Myles 90dabce0d2 Sponge: Fix dump, add load message, move loading, handle reload
And fix travis
2016-09-26 11:48:06 +01:00
Matsv 9a8a6e5b16 Implement PPS for Sponge 2016-09-26 11:16:20 +02:00
Matsv 4840db095c Fix metadata 2016-09-26 11:02:54 +02:00
Myles b371c14a27 Add Sponge Support 2016-09-26 01:44:21 +01:00
Myles a1fbca11f0 Queue tasks & Fix PPS 2016-09-25 21:02:12 +01:00
Myles 0fe9ccf4a8 Make pom.xml better 2016-09-25 20:43:32 +01:00
Matsv 08713947b7 Add BukkitViaLoader to the builder and limit the builder methods 2016-09-25 21:42:22 +02:00
Matsv e56bce2f31 Create builder for ViaManager 2016-09-25 21:33:47 +02:00
Matsv 573374866b Optimize imports & reformat code 2016-09-25 21:17:09 +02:00
Matsv 32afa2a9a3 Fix building and change versions 2016-09-25 21:10:41 +02:00
Myles 669cbcd142 Fix maven so it compiles 2016-09-25 20:05:58 +01:00
Myles 471076cbe1 Update Changelog 2016-09-25 19:44:05 +01:00
Matsv 79d353d458 Basic configuration api and add platform specific dump info 2016-09-25 20:41:34 +02:00
Myles 30d477c6d2 Add Bulk Chunks, need to do full packet reading as a fallback though 2016-09-25 19:34:24 +01:00
Myles d3f5ebdba7 Update TODO 2016-09-25 18:52:37 +01:00
Matsv 4b94c8ad02 Map all entity and object ids / parents and fix metadata searcher 2016-09-25 19:50:50 +02:00
Myles 7a7c3f15d8 Add required provider for movement (for reflection caching) 2016-09-25 18:26:14 +01:00
Myles 52610f7c66 Use HandItemProvider for 1.8 hand items 2016-09-25 18:06:04 +01:00
Matsv 84ee4410a6 Use generics for bossbars 2016-09-25 18:20:42 +02:00
Myles 49d51de263 Start moving listeners away 2016-09-25 17:17:07 +01:00
Myles 848b0cf113 Make ViaCommandSender better, fix quite a few of the commands. 2016-09-25 16:03:03 +01:00
Myles c4ffdc1b7c Migrate to our own types + use ids instead of materials 2016-09-25 15:40:30 +01:00
Myles 49b602994a Migrate Environment to our own type (todo javadocs for it) 2016-09-25 15:00:05 +01:00
Myles 05930ad791 Add ViaManager and abstraction / Add todo list 2016-09-25 14:39:37 +01:00
Matsv e7ab232b28 Merge branch 'master' of https://github.com/MylesIsCool/ViaVersion into modular 2016-09-25 12:49:22 +02:00
Matsv 3f88a16c6c Merge branches '1.11-DEV' and 'master' of https://github.com/MylesIsCool/ViaVersion into 1.11-DEV 2016-09-25 12:48:22 +02:00
Matsv 1a6b98deca Cancel second-hand packets to prevent double interact Fix #502 2016-09-25 12:19:23 +02:00
Matsv 598863d43a Add onCommand and onTabComplete to the interface 2016-09-24 20:12:12 +02:00
Matsv b146257b1a Abstract the BossBar for multi-platform support 2016-09-24 19:31:41 +02:00
Myles dc01fb59b8 Doesn't compile but start work towards seperating into modules... (with legacy support hopefully for basic API) 2016-09-23 18:49:59 +01:00
Myles 58ed2c0d9e Merge branch 'master' into 1.11-DEV 2016-09-23 15:55:47 +01:00
Matsv 3762a9d3b1 Actually fix #500, mode changed to VarIntEnum at 1.8->1.9 but we never changed it. 2016-09-21 15:26:06 +02:00
Matsv 5a88963929 Fix #500 2016-09-21 15:14:31 +02:00
Nick 1b69243326 Update README.md (#498) 2016-09-20 19:23:21 +01:00
Matsv 3e2a391348 Looks like Intellij didn't commit the 16w38a changes 2016-09-20 16:53:01 +02:00
Matsv a330d2b148 Compatibility for 16w38a and sync with master 2016-09-20 16:43:42 +02:00
Nick 573f769825 Update Bungee.java (#494) 2016-09-13 18:56:26 +02:00
Myles 9de49176fb Add Matsv to authors 2016-09-12 17:59:15 +01:00
Mats e6220f39e5 Support for 16w36a 2016-09-08 18:31:27 +02:00
Myles 8f656d9dac Fix ListWrapper, I'm not even sure why I did this... but hey! 2016-09-05 12:24:33 +01:00
Matsv 15bcf3f065 Support for 16w35a 2016-09-01 15:57:25 +02:00
Myles 536e2e33e0 Update Description & Don't use BungeeCord ChatColor 2016-08-28 11:38:38 +01:00
Mats ae58f0c1ab Update the issue template 2016-08-25 18:00:16 +02:00
Myles 7d9cd5bfbf We're gonna use 0.9.10 until 1.11 release which we'll use 1.0.0 2016-08-25 16:56:01 +01:00
Myles 25a7915c7f 0.9.9 Version 2016-08-25 16:52:34 +01:00
Myles 822d582074 Deprecate isPorted, we port all players use getPlayerVersion instead. 2016-08-24 20:40:53 +01:00
Matsv d815c0e682 Merge branch 'master' of https://github.com/MylesIsCool/ViaVersion into 1.11-DEV 2016-08-24 16:46:47 +02:00
Matsv f8a73d5fc2 Merge branch 'master' of https://github.com/Matsv/ViaVersion into upmaster 2016-08-22 21:38:19 +02:00
Matsv a0ad97947d Add the configuration to the dump command, also add a toString method to the ProtocolVersion class. 2016-08-22 21:37:51 +02:00
Myles 6ea5d0849d Missed a bit off the README 2016-08-21 15:52:59 +01:00
Myles eba512ef0b Update README with IRC 2016-08-21 15:51:21 +01:00
Matsv 725ab0f713 Merge branch 'master' of https://github.com/MylesIsCool/ViaVersion into 1.11-DEV 2016-08-20 16:29:01 +02:00
Matsv 0f96c24c78 Merge branch 'master' of https://github.com/Matsv/ViaVersion into dumpthemall 2016-08-20 16:21:19 +02:00
Matsv f2e4c37cd9 Add ViaVersion dump command to get all the relevant info we need by bug reports. 2016-08-20 16:19:44 +02:00
Myles f159a2250c SemVer compatibility, also change up the messages a bit. 2016-08-20 13:47:09 +01:00
Myles ed311e4059 Clean up some messages to be more understandable. 2016-08-20 12:03:23 +01:00
AlfieC 6aae98a8a9 typo (#485) 2016-08-17 23:32:21 +02:00
Matsv 99f9cf3340 Support for 16w33a 2016-08-17 16:45:33 +02:00
Matsv 2074039285 Merge branch '1.11-DEV' of https://github.com/MylesIsCool/ViaVersion into 1.11-DEV 2016-08-11 17:07:57 +02:00
Matsv b438ff61a2 Support for 16w32b 2016-08-11 17:07:35 +02:00
Myles c36e43b573 Remove unused imports 2016-08-10 20:36:34 +01:00
Matsv be383a524c Woops, remove ; 2016-08-10 21:34:13 +02:00
Matsv 9c6cd22817 Gotta catch them all 2016-08-10 21:33:32 +02:00
Myles 85de7c35ea Fix metadata :) 2016-08-10 20:23:13 +01:00
Matsv 0dd8c33aa9 Handle villager profession 2016-08-10 20:48:45 +02:00
Myles 8cc2538e6c Push type converting to new entity types. 2016-08-10 19:38:59 +01:00
Matsv 04d87ebba7 Merge branch '1.11-DEV' of https://github.com/MylesIsCool/ViaVersion into 1.11-DEV
# Conflicts:
#	src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_10/ProtocolSnapshotTo1_10.java
2016-08-10 20:14:11 +02:00
Matsv 8c4b5b613c Fix spawneggs 2016-08-10 20:12:27 +02:00
Myles 6add512fe1 Start work on Remapping Types 2016-08-10 19:10:05 +01:00
Myles 73b8a2fc9a Start support for entity type id tracking 2016-08-10 18:54:56 +01:00
Myles 03cc48c991 Use constant of 1 for collect, (Tested). 2016-08-10 16:11:39 +01:00
Matsv 44544925a1 map packet changes. 2016-08-10 15:59:13 +02:00
Matsv 7cadf832f5 Preparations for the snapshot. 2016-08-10 14:51:32 +02:00
Matsv 0f3daa5dc4 Merge branch 'chunkFix' of https://github.com/Matsv/ViaVersion into upmaster 2016-08-08 18:00:40 +02:00
Matsv f258cf8c89 Stop depending on versions for the ChunkTypes. fix cast exceptions by using a ChunkType in front of it. 2016-08-08 17:38:11 +02:00
Matsv ca759c056e Add some missing sounds 2016-08-07 17:53:08 +02:00
Matsv d715607826 Implement 1_8 writing 2016-08-05 20:17:39 +02:00
inventivetalent afca92d122 update requests to use /v2 (#479) 2016-08-04 20:42:03 +01:00
Myles ae37b34692 Snapshot 2016-08-01 14:07:33 +01:00
Myles 9e42a368e0 Merge branch 'master' of https://github.com/MylesIsCool/ViaVersion 2016-08-01 14:06:11 +01:00
Myles 27982efd29 Bump version to 0.9.8 2016-08-01 14:05:07 +01:00
Mason c3b343fbc8 Allow non-solid blocks to be placed at feet (#472) 2016-07-22 21:06:51 +01:00
Matsv 9bedb6c741 Move some classes to other packages 2016-07-17 12:00:46 +02:00
Matsv 873f4dd298 Give it some protection 2016-07-11 22:06:00 +02:00
Matsv 693990644f Rename the Meta(List)1_9_1_10Type to Metadata(List)1_9Type and cleanup the listeners 2016-07-11 20:27:44 +02:00
Matsv b2680d76a6 WIP cleanup 2016-07-11 15:52:06 +02:00
Matsv db935b454f Make the Metadata types version based and remove the NoGravity tag init since it doesn't seem needed. 2016-07-11 13:48:48 +02:00
Myles c207a9bfff Count other worlds as nether instead of imploding. 2016-07-10 12:35:46 +01:00
Myles f5bd041c7b Fix PacketListenerAPI load to be before Via, fixes #463. Tested with NickNamer 2016-07-09 15:21:17 +01:00
Myles 07d89b24af Custom reload message #459 2016-07-09 14:41:07 +01:00
Myles 1d0c0c527c Snapshot 2016-07-08 12:56:34 +01:00
Myles 7a9cb86563 0.9.7 release 2016-07-08 12:55:05 +01:00
Myles 87b1919863 Let the normal send go through the event loop. Fix signs are sent before the chunks on a 1.9.4 server with a 1.9-1.9.2 client (#460) 2016-07-03 12:05:32 +01:00
Myles d164e413c2 Snapshot 2016-07-02 23:34:31 +01:00
Myles 76d7db044f Version bump + small dead code fix 2016-07-02 23:28:54 +01:00
Myles 046ebb8ecc Fix chunk bug 2016-07-02 23:22:44 +01:00
Myles bccde04ace Back to snapshot 2016-07-02 22:37:29 +01:00
294 changed files with 10996 additions and 3676 deletions

No files matched your search

-3
View File
@@ -19,9 +19,6 @@ hs_err_pid*
# Ignore IDEA directory
.idea/*
# Include the project's code style settings file
!.idea/codeStyleSettings.xml
# Include the project's dictionary
!.idea/dictionaries/
!.idea/dictionaries/*
+1 -1
View File
@@ -1,7 +1,7 @@
sudo: false
language: java
jdk: oraclejdk7
jdk: oraclejdk8
cache:
directories:
+3 -4
View File
@@ -1,12 +1,11 @@
### What version of ViaVersion are you using? Type /ver viaversion
### What is the output link of /viaversion dump?
### 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?
+11 -31
View File
@@ -1,10 +1,16 @@
# ViaVersion 0.9.5
# ViaVersion 1.0.0 - Spigot, Sponge, BungeeCord
[![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)
IRC: [#viaversion](http://irc.spi.gt/iris/?channels=viaversion) on irc.spi.gt for Support.
**Allows the connection of higher client versions to lower server versions**
Allows 1.10, 1.9 on 1.8 server and 1.10 on a 1.9 server.
Supported Versions:
[![Table] (http://i.imgur.com/SVVhFQ4.png)](http://i.imgur.com/SVVhFQ4.png)
On Bukkit you may also use ProtocolSupport, but ensure you have the right build for your server version.
**User Docs:** https://docs.viaversion.com/display/VIAVERSION/
@@ -14,40 +20,14 @@ Allows 1.10, 1.9 on 1.8 server and 1.10 on a 1.9 server.
Sources:
--------
**wiki.vg** (Used for various information, we also contribute back)
**wiki.vg** (Protocol info, though I did have to find a lot myself)
**Burger** We use this tool to get protocol and other useful information for new / undocumented Minecraft versions
**Burger** (See [PAaaS](https://github.com/Matsv/Paaas))
**OpenNBT** (used for slot rewriting)
All Time Contributors:
--------
**Myself** (harhar)
**Matsv**
**HugoDaBosss**
**SanderGielisse**
**Paulomart**
**gigosaurus**
**fillefilip8**
**lenis0012**
**fuzzy_bot**
**joserobjr**
Releases / Dev Builds:
--------
You can find official releases here:
@@ -70,5 +50,5 @@ License:
MIT License, see LICENSE for more details.
Thanks!
Special thanks to all our [Contributors](https://github.com/MylesIsCool/ViaVersion/graphs/contributors)
+64
View File
@@ -0,0 +1,64 @@
<?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"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>viaversion-parent</artifactId>
<groupId>us.myles</groupId>
<version>1.0.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>viaversion-bukkit</artifactId>
<properties>
<!-- Change Bukkit Version HERE! -->
<bukkitVersion>1.8.8-R0.1-SNAPSHOT</bukkitVersion>
</properties>
<build>
<resources>
<resource>
<targetPath>.</targetPath>
<filtering>true</filtering>
<directory>src/main/resources/</directory>
<includes>
<include>*</include>
</includes>
</resource>
</resources>
</build>
<dependencies>
<!-- Common Module -->
<dependency>
<groupId>us.myles</groupId>
<artifactId>viaversion-common</artifactId>
<version>${project.parent.version}</version>
<scope>provided</scope>
</dependency>
<!-- Bukkit API, http://www.spigotmc.org/ or http://bukkit.org/ -->
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<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>
</dependencies>
</project>
@@ -0,0 +1,256 @@
package us.myles.ViaVersion;
import com.google.gson.JsonObject;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.ViaAPI;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.command.ViaCommandSender;
import us.myles.ViaVersion.api.configuration.ConfigurationProvider;
import us.myles.ViaVersion.api.platform.TaskId;
import us.myles.ViaVersion.api.platform.ViaPlatform;
import us.myles.ViaVersion.bukkit.classgenerator.ClassGenerator;
import us.myles.ViaVersion.bukkit.commands.BukkitCommandHandler;
import us.myles.ViaVersion.bukkit.commands.BukkitCommandSender;
import us.myles.ViaVersion.bukkit.platform.*;
import us.myles.ViaVersion.bukkit.util.NMSUtil;
import us.myles.ViaVersion.dump.PluginInfo;
import us.myles.ViaVersion.util.GsonUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class ViaVersionPlugin extends JavaPlugin implements ViaPlatform {
private BukkitCommandHandler commandHandler;
private boolean compatSpigotBuild = false;
private boolean spigot = true;
private boolean lateBind = false;
private boolean protocolSupport = false;
@Getter
private BukkitConfigAPI conf;
@Getter
private ViaAPI<Player> api = new BukkitViaAPI(this);
private List<Runnable> queuedTasks = new ArrayList<>();
private List<Runnable> asyncQueuedTasks = new ArrayList<>();
public ViaVersionPlugin() {
// Command handler
commandHandler = new BukkitCommandHandler();
// Init platform
Via.init(ViaManager.builder()
.platform(this)
.commandHandler(commandHandler)
.injector(new BukkitViaInjector())
.loader(new BukkitViaLoader(this))
.build());
// Config magic
conf = new BukkitConfigAPI();
// For compatibility
ViaVersion.setInstance(this);
// Check if we're using protocol support too
protocolSupport = Bukkit.getPluginManager().getPlugin("ProtocolSupport") != null;
if (protocolSupport) {
getLogger().info("Hooking into ProtocolSupport, to prevent issues!");
try {
BukkitViaInjector.patchLists();
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public void onLoad() {
// Spigot detector
try {
Class.forName("org.spigotmc.SpigotConfig");
} catch (ClassNotFoundException e) {
spigot = false;
}
// Check if it's a spigot build with a protocol mod
try {
compatSpigotBuild = NMSUtil.nms("PacketEncoder").getDeclaredField("version") != null;
} catch (Exception e) {
compatSpigotBuild = false;
}
// Generate classes needed (only works if it's compat or ps)
ClassGenerator.generate();
lateBind = !BukkitViaInjector.isBinded();
getLogger().info("ViaVersion " + getDescription().getVersion() + (compatSpigotBuild ? "compat" : "") + " is now loaded" + (lateBind ? ", waiting for boot. (late-bind)" : ", injecting!"));
if (!lateBind) {
Via.getManager().init();
}
}
@Override
public void onEnable() {
if (lateBind) {
Via.getManager().init();
}
getCommand("viaversion").setExecutor(commandHandler);
getCommand("viaversion").setTabCompleter(commandHandler);
// Warn them if they have anti-xray on and they aren't using spigot
if (conf.isAntiXRay() && !spigot) {
getLogger().info("You have anti-xray on in your config, since you're not using spigot it won't fix xray!");
}
// Run queued tasks
for (Runnable r : queuedTasks) {
Bukkit.getScheduler().runTask(this, r);
}
queuedTasks.clear();
// Run async queued tasks
for (Runnable r : asyncQueuedTasks) {
Bukkit.getScheduler().runTaskAsynchronously(this, r);
}
asyncQueuedTasks.clear();
}
@Override
public void onDisable() {
Via.getManager().destroy();
}
public boolean isCompatSpigotBuild() {
return compatSpigotBuild;
}
public boolean isSpigot() {
return this.spigot;
}
public boolean isProtocolSupport() {
return protocolSupport;
}
@Override
public String getPlatformName() {
return Bukkit.getServer().getName();
}
@Override
public String getPlatformVersion() {
return Bukkit.getServer().getVersion();
}
@Override
public String getPluginVersion() {
return getDescription().getVersion();
}
@Override
public TaskId runAsync(Runnable runnable) {
if (isPluginEnabled()) {
return new BukkitTaskId(getServer().getScheduler().runTaskAsynchronously(this, runnable).getTaskId());
} else {
asyncQueuedTasks.add(runnable);
return new BukkitTaskId(null);
}
}
@Override
public TaskId runSync(Runnable runnable) {
if (isPluginEnabled()) {
return new BukkitTaskId(getServer().getScheduler().runTask(this, runnable).getTaskId());
} else {
queuedTasks.add(runnable);
return new BukkitTaskId(null);
}
}
@Override
public TaskId runRepeatingSync(Runnable runnable, Long ticks) {
return new BukkitTaskId(getServer().getScheduler().runTaskTimer(this, runnable, ticks, 0).getTaskId());
}
@Override
public void cancelTask(TaskId taskId) {
if (taskId == null) return;
if (taskId.getObject() == null) return;
if (taskId instanceof BukkitTaskId) {
getServer().getScheduler().cancelTask((Integer) taskId.getObject());
}
}
@Override
public ViaCommandSender[] getOnlinePlayers() {
ViaCommandSender[] array = new ViaCommandSender[Bukkit.getOnlinePlayers().size()];
int i = 0;
for (Player player : Bukkit.getOnlinePlayers()) {
array[i++] = new BukkitCommandSender(player);
}
return array;
}
@Override
public void sendMessage(UUID uuid, String message) {
Player player = Bukkit.getPlayer(uuid);
if (player != null) {
player.sendMessage(message);
}
}
@Override
public boolean kickPlayer(UUID uuid, String message) {
Player player = Bukkit.getPlayer(uuid);
if (player != null) {
player.kickPlayer(message);
return true;
} else {
return false;
}
}
@Override
public boolean isPluginEnabled() {
return Bukkit.getPluginManager().getPlugin("ViaVersion").isEnabled();
}
@Override
public ConfigurationProvider getConfigurationProvider() {
return conf;
}
@Override
public void onReload() {
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(ChatColor.translateAlternateColorCodes('&', getConf().getReloadDisconnectMsg()));
}
} else {
getLogger().severe("ViaVersion is already loaded, this should work fine. If you get any console errors, try rebooting.");
}
}
@Override
public JsonObject getDump() {
JsonObject platformSpecific = new JsonObject();
List<PluginInfo> plugins = new ArrayList<>();
for (Plugin p : Bukkit.getPluginManager().getPlugins())
plugins.add(new PluginInfo(p.isEnabled(), p.getDescription().getName(), p.getDescription().getVersion(), p.getDescription().getMain(), p.getDescription().getAuthors()));
platformSpecific.add("plugins", GsonUtil.getGson().toJsonTree(plugins));
// TODO more? ProtocolLib things etc?
return platformSpecific;
}
}
@@ -1,19 +1,19 @@
package us.myles.ViaVersion.api;
import lombok.Getter;
import org.apache.commons.lang.Validate;
import us.myles.ViaVersion.ViaVersionPlugin;
public class ViaVersion {
@Getter
private static ViaVersionAPI instance;
@Getter
private static ViaVersionConfig config;
public static void setInstance(ViaVersionPlugin plugin) {
Validate.isTrue(instance == null, "Instance is already set");
ViaVersion.instance = plugin;
ViaVersion.config = plugin.getConf();
}
}
package us.myles.ViaVersion.api;
import lombok.Getter;
import org.apache.commons.lang.Validate;
import us.myles.ViaVersion.ViaVersionPlugin;
@Deprecated
public class ViaVersion {
@Getter
private static ViaVersionAPI instance;
@Getter
private static ViaVersionConfig config;
public static void setInstance(ViaVersionPlugin plugin) {
Validate.isTrue(instance == null, "Instance is already set");
ViaVersion.instance = (ViaVersionAPI) plugin.getApi();
ViaVersion.config = plugin.getConf();
}
}
@@ -1,140 +1,144 @@
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 us.myles.ViaVersion.api.protocol.ProtocolRegistry;
import java.util.SortedSet;
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
* Will also retrieve version from ProtocolSupport if it's being used.
*
* @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 UUID of a player
* @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();
/**
* Get the supported protocol versions
* This method removes any blocked protocol versions.
* @see ProtocolRegistry#getSupportedVersions() for full list.
*
* @return a list of protocol versions
*/
SortedSet<Integer> getSupportedVersions();
/**
* Gets if the server uses spigot
* <p>
* Note: Will only work after ViaVersion load
*
* @return True if spigot
*/
boolean isSpigot();
/**
* Gets if protocol support is also being used.
*
* @return True if it is being used.
*/
boolean isProtocolSupport();
}
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 us.myles.ViaVersion.api.protocol.ProtocolRegistry;
import java.util.SortedSet;
import java.util.UUID;
@Deprecated
public interface ViaVersionAPI extends ViaAPI<Player> {
/**
* 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)
* @deprecated As of 0.9.9, because all players are ported use {@link #getPlayerVersion(Player)}
*/
boolean isPorted(Player player);
/**
* Get protocol number from a player
* Will also retrieve version from ProtocolSupport if it's being used.
*
* @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 UUID of a player
* @return True if the client is on 1.9
* @deprecated As of 0.9.9, because all players are ported use {@link #getPlayerVersion(UUID)}
*/
@Deprecated
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 commands handler
*
* @return commands 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();
/**
* Get the supported protocol versions
* This method removes any blocked protocol versions.
*
* @return a list of protocol versions
* @see ProtocolRegistry#getSupportedVersions() for full list.
*/
SortedSet<Integer> getSupportedVersions();
/**
* Gets if the server uses spigot
* <p>
* Note: Will only work after ViaVersion load
*
* @return True if spigot
*/
boolean isSpigot();
/**
* Gets if protocol support is also being used.
*
* @return True if it is being used.
*/
boolean isProtocolSupport();
}
@@ -0,0 +1,34 @@
package us.myles.ViaVersion.boss;
import lombok.Getter;
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;
@Getter
public class ViaBossBar extends CommonBoss<Player> {
public ViaBossBar(String title, float health, BossColor color, BossStyle style) {
super(title, health, color, style);
}
@Override
public BossBar addPlayer(Player player) {
addPlayer(player.getUniqueId());
return this;
}
@Override
public BossBar addPlayers(Player... players) {
for (Player p : players)
addPlayer(p);
return this;
}
@Override
public BossBar removePlayer(Player player) {
removePlayer(player.getUniqueId());
return this;
}
}
@@ -0,0 +1,19 @@
package us.myles.ViaVersion.bukkit.classgenerator;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.bukkit.handlers.BukkitDecodeHandler;
import us.myles.ViaVersion.bukkit.handlers.BukkitEncodeHandler;
public class BasicHandlerConstructor implements HandlerConstructor {
@Override
public BukkitEncodeHandler newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {
return new BukkitEncodeHandler(info, minecraftEncoder);
}
@Override
public BukkitDecodeHandler newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {
return new BukkitDecodeHandler(info, minecraftDecoder);
}
}
@@ -1,4 +1,4 @@
package us.myles.ViaVersion.classgenerator;
package us.myles.ViaVersion.bukkit.classgenerator;
import javassist.*;
import javassist.expr.ConstructorCall;
@@ -6,9 +6,9 @@ import javassist.expr.ExprEditor;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.handlers.ViaDecodeHandler;
import us.myles.ViaVersion.handlers.ViaEncodeHandler;
import us.myles.ViaVersion.util.ReflectionUtil;
import us.myles.ViaVersion.bukkit.handlers.BukkitDecodeHandler;
import us.myles.ViaVersion.bukkit.handlers.BukkitEncodeHandler;
import us.myles.ViaVersion.bukkit.util.NMSUtil;
public class ClassGenerator {
private static HandlerConstructor constructor = new BasicHandlerConstructor();
@@ -27,17 +27,17 @@ public class ClassGenerator {
}
if (ViaVersion.getInstance().isCompatSpigotBuild()) {
Class decodeSuper = ReflectionUtil.nms("PacketDecoder");
Class encodeSuper = ReflectionUtil.nms("PacketEncoder");
Class decodeSuper = NMSUtil.nms("PacketDecoder");
Class encodeSuper = NMSUtil.nms("PacketEncoder");
// Generate the classes
addSpigotCompatibility(pool, ViaDecodeHandler.class, decodeSuper);
addSpigotCompatibility(pool, ViaEncodeHandler.class, encodeSuper);
addSpigotCompatibility(pool, BukkitDecodeHandler.class, decodeSuper);
addSpigotCompatibility(pool, BukkitEncodeHandler.class, encodeSuper);
} else {
Class decodeSuper = Class.forName(getPSPackage() + ".wrapped.WrappedDecoder");
Class encodeSuper = Class.forName(getPSPackage() + ".wrapped.WrappedEncoder");
Class decodeSuper = Class.forName(getPSPackage().equals("unknown") ? "protocolsupport.protocol.pipeline.common.PacketDecoder" : getPSPackage() + ".wrapped.WrappedDecoder");
Class encodeSuper = Class.forName(getPSPackage().equals("unknown") ? "protocolsupport.protocol.pipeline.common.PacketEncoder" : getPSPackage() + ".wrapped.WrappedEncoder");
// Generate the classes
addPSCompatibility(pool, ViaDecodeHandler.class, decodeSuper);
addPSCompatibility(pool, ViaEncodeHandler.class, encodeSuper);
addPSCompatibility(pool, BukkitDecodeHandler.class, decodeSuper);
addPSCompatibility(pool, BukkitEncodeHandler.class, encodeSuper);
}
@@ -53,10 +53,10 @@ public class ClassGenerator {
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" +
" return new BukkitEncodeHandler(info, minecraftEncoder);\n" +
" }", generated));
generated.addMethod(CtMethod.make("public ByteToMessageDecoder newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {\n" +
" return new ViaDecodeHandler(info, minecraftDecoder);\n" +
" return new BukkitDecodeHandler(info, minecraftDecoder);\n" +
" }", generated));
constructor = (HandlerConstructor) generated.toClass(HandlerConstructor.class.getClassLoader()).newInstance();
@@ -110,6 +110,7 @@ public class ClassGenerator {
}
private static Class addPSCompatibility(ClassPool pool, Class input, Class superclass) {
boolean newPS = getPSPackage().equals("unknown");
String newName = "us.myles.ViaVersion.classgenerator.generated." + input.getSimpleName();
try {
@@ -118,23 +119,34 @@ public class ClassGenerator {
CtClass toExtend = pool.get(superclass.getName());
generated.setSuperclass(toExtend);
// Override setRealEncoder / setRealDecoder
pool.importPackage(getPSPackage());
pool.importPackage(getPSPackage() + ".wrapped");
if (superclass.getName().endsWith("Decoder")) {
// Decoder
generated.addMethod(CtMethod.make("public void setRealDecoder(IPacketDecoder dec) {\n" +
" WrappedDecoder decoder = new WrappedDecoder();" +
" decoder.setRealDecoder(dec);\n" +
" this.minecraftDecoder = decoder;\n" +
" }", generated));
} else {
// Encoder
generated.addMethod(CtMethod.make("public void setRealEncoder(IPacketEncoder enc) {\n" +
" WrappedEncoder encoder = new WrappedEncoder();" +
" encoder.setRealEncoder(enc);\n" +
" this.minecraftEncoder = encoder;\n" +
" }", generated));
if (!newPS) {
// Override setRealEncoder / setRealDecoder
pool.importPackage(getPSPackage());
pool.importPackage(getPSPackage() + ".wrapped");
if (superclass.getName().endsWith("Decoder")) {
// Decoder
generated.addMethod(CtMethod.make("public void setRealDecoder(IPacketDecoder dec) {\n" +
" ((WrappedDecoder) this.minecraftDecoder).setRealDecoder(dec);\n" +
" }", generated));
} else {
// Encoder
pool.importPackage("protocolsupport.api");
pool.importPackage("java.lang.reflect");
generated.addMethod(CtMethod.make("public void setRealEncoder(IPacketEncoder enc) {\n" +
" try {\n" +
// Tell ProtocolSupport to decode MINECRAFT_FUTURE packets using the default decoder (for 1.9.4)
" Field field = enc.getClass().getDeclaredField(\"version\");\n" +
" field.setAccessible(true);\n" +
" ProtocolVersion version = (ProtocolVersion) field.get(enc);\n" +
" if (version == ProtocolVersion.MINECRAFT_FUTURE) enc = enc.getClass().getConstructor(\n" +
" new Class[]{ProtocolVersion.class}).newInstance(new Object[] {ProtocolVersion.getLatest()});\n" +
" } catch (Exception e) {\n" +
// I guess we're not on 1.9.4
" }\n" +
" ((WrappedEncoder) this.minecraftEncoder).setRealEncoder(enc);\n" +
" }", generated));
}
}
}
return generated.toClass(HandlerConstructor.class.getClassLoader());
@@ -1,4 +1,4 @@
package us.myles.ViaVersion.classgenerator;
package us.myles.ViaVersion.bukkit.classgenerator;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
@@ -0,0 +1,21 @@
package us.myles.ViaVersion.bukkit.commands;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
import us.myles.ViaVersion.commands.ViaCommandHandler;
import java.util.List;
public class BukkitCommandHandler extends ViaCommandHandler implements CommandExecutor, TabExecutor {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
return onCommand(new BukkitCommandSender(sender), args);
}
@Override
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
return onTabComplete(new BukkitCommandSender(sender), args);
}
}
@@ -0,0 +1,37 @@
package us.myles.ViaVersion.bukkit.commands;
import lombok.AllArgsConstructor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import us.myles.ViaVersion.api.command.ViaCommandSender;
import java.util.UUID;
@AllArgsConstructor
public class BukkitCommandSender implements ViaCommandSender {
private CommandSender sender;
@Override
public boolean hasPermission(String permission) {
return sender.hasPermission(permission);
}
@Override
public void sendMessage(String msg) {
sender.sendMessage(msg);
}
@Override
public UUID getUUID() {
if (sender instanceof Player) {
return ((Player) sender).getUniqueId();
} else {
return UUID.fromString(getName());
}
}
@Override
public String getName() {
return sender.getName();
}
}
@@ -1,4 +1,4 @@
package us.myles.ViaVersion.handlers;
package us.myles.ViaVersion.bukkit.handlers;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
@@ -7,17 +7,17 @@ import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
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 us.myles.ViaVersion.bukkit.classgenerator.ClassGenerator;
import us.myles.ViaVersion.bukkit.classgenerator.HandlerConstructor;
import java.lang.reflect.Method;
public class ViaVersionInitializer extends ChannelInitializer<SocketChannel> {
public class BukkitChannelInitializer extends ChannelInitializer<SocketChannel> {
private final ChannelInitializer<SocketChannel> original;
private Method method;
public ViaVersionInitializer(ChannelInitializer<SocketChannel> oldInit) {
public BukkitChannelInitializer(ChannelInitializer<SocketChannel> oldInit) {
this.original = oldInit;
try {
this.method = ChannelInitializer.class.getDeclaredMethod("initChannel", Channel.class);
@@ -43,7 +43,7 @@ public class ViaVersionInitializer extends ChannelInitializer<SocketChannel> {
// Add our transformers
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);
BukkitPacketHandler chunkHandler = new BukkitPacketHandler(info);
socketChannel.pipeline().replace("encoder", "encoder", encoder);
socketChannel.pipeline().replace("decoder", "decoder", decoder);
@@ -1,11 +1,9 @@
package us.myles.ViaVersion.handlers;
package us.myles.ViaVersion.bukkit.handlers;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
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;
@@ -16,13 +14,12 @@ import us.myles.ViaVersion.util.PipelineUtil;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
public class ViaDecodeHandler extends ByteToMessageDecoder {
public class BukkitDecodeHandler extends ByteToMessageDecoder {
private final ByteToMessageDecoder minecraftDecoder;
private final UserConnection info;
public static int PASSTHROUGH_ID = 1000;
public ViaDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {
public BukkitDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {
this.info = info;
this.minecraftDecoder = minecraftDecoder;
}
@@ -39,7 +36,7 @@ public class ViaDecodeHandler extends ByteToMessageDecoder {
boolean second = info.incrementReceived();
// Check PPS
if (second) {
if (((ViaVersionPlugin) ViaVersion.getInstance()).handlePPS(info))
if (info.handlePPS())
return;
}
@@ -49,7 +46,7 @@ public class ViaDecodeHandler extends ByteToMessageDecoder {
// Transform
ByteBuf newPacket = ctx.alloc().buffer();
try {
if (id == ViaDecodeHandler.PASSTHROUGH_ID) {
if (id == PacketWrapper.PASSTHROUGH_ID) {
newPacket.writeBytes(bytebuf);
} else {
PacketWrapper wrapper = new PacketWrapper(id, bytebuf, info);
@@ -0,0 +1,93 @@
package us.myles.ViaVersion.bukkit.handlers;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.bukkit.util.NMSUtil;
import us.myles.ViaVersion.exception.CancelException;
import us.myles.ViaVersion.handlers.ChannelHandlerContextWrapper;
import us.myles.ViaVersion.handlers.ViaHandler;
import us.myles.ViaVersion.packets.Direction;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.util.PipelineUtil;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class BukkitEncodeHandler extends MessageToByteEncoder implements ViaHandler {
private static Field versionField = null;
static {
try {
versionField = NMSUtil.nms("PacketEncoder").getDeclaredField("version");
versionField.setAccessible(true);
} catch (Exception e) {
// Not compat version
}
}
private final UserConnection info;
private final MessageToByteEncoder minecraftEncoder;
public BukkitEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {
this.info = info;
this.minecraftEncoder = minecraftEncoder;
}
@Override
protected void encode(final ChannelHandlerContext ctx, Object o, final ByteBuf bytebuf) throws Exception {
if (versionField != null) {
versionField.set(minecraftEncoder, versionField.get(this));
}
// handle the packet type
if (!(o instanceof ByteBuf)) {
// call minecraft encoder
try {
PipelineUtil.callEncode(this.minecraftEncoder, new ChannelHandlerContextWrapper(ctx, this), o, bytebuf);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof Exception) {
throw (Exception) e.getCause();
}
}
}
transform(bytebuf);
}
public void transform(ByteBuf bytebuf) throws Exception {
if (bytebuf.readableBytes() == 0) {
return; // Someone Already Decoded It!
}
// Increment sent
info.incrementSent();
if (info.isActive()) {
// Handle ID
int id = Type.VAR_INT.read(bytebuf);
// Transform
ByteBuf oldPacket = bytebuf.copy();
bytebuf.clear();
try {
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();
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (PipelineUtil.containsCause(cause, CancelException.class)) return;
super.exceptionCaught(ctx, cause);
}
}
@@ -1,4 +1,4 @@
package us.myles.ViaVersion.handlers;
package us.myles.ViaVersion.bukkit.handlers;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
@@ -8,10 +8,10 @@ import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import java.util.List;
public class ViaPacketHandler extends MessageToMessageEncoder {
public class BukkitPacketHandler extends MessageToMessageEncoder {
private final UserConnection info;
public ViaPacketHandler(UserConnection info) {
public BukkitPacketHandler(UserConnection info) {
this.info = info;
}
@@ -1,23 +1,18 @@
package us.myles.ViaVersion.update;
import lombok.RequiredArgsConstructor;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaVersion;
@RequiredArgsConstructor
public class UpdateListener implements Listener {
private final ViaVersionPlugin plugin;
@EventHandler
public void onJoin(PlayerJoinEvent e) {
if (e.getPlayer().hasPermission("viaversion.update")
&& ViaVersion.getConfig().isCheckForUpdates()) {
UpdateUtil.sendUpdateMessage(e.getPlayer().getUniqueId(), plugin);
}
}
}
package us.myles.ViaVersion.bukkit.listeners;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.update.UpdateUtil;
public class UpdateListener implements Listener {
@EventHandler
public void onJoin(PlayerJoinEvent e) {
if (e.getPlayer().hasPermission("viaversion.update")
&& Via.getConfig().isCheckForUpdates()) {
UpdateUtil.sendUpdateMessage(e.getPlayer().getUniqueId());
}
}
}
@@ -0,0 +1,53 @@
package us.myles.ViaVersion.bukkit.listeners;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NonNull;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaListener;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.protocol.Protocol;
@Getter(AccessLevel.PROTECTED)
public class ViaBukkitListener extends ViaListener implements Listener {
private final Plugin plugin;
public ViaBukkitListener(ViaVersionPlugin plugin, Class<? extends Protocol> requiredPipeline) {
super(requiredPipeline);
this.plugin = plugin;
}
/**
* Get the UserConnection from a player
*
* @param player Player object
* @return The UserConnection
*/
protected UserConnection getUserConnection(@NonNull Player player) {
return getUserConnection(player.getUniqueId());
}
/**
* Checks if the player is on the selected pipe
*
* @param player Player Object
* @return True if on pipe
*/
protected boolean isOnPipe(Player player) {
return isOnPipe(player.getUniqueId());
}
/**
* Register as Bukkit event
*/
@Override
public void register() {
if (isRegistered()) return;
plugin.getServer().getPluginManager().registerEvents(this, plugin);
setRegistered(true);
}
}
@@ -1,12 +1,10 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8.listeners;
package us.myles.ViaVersion.bukkit.listeners.protocol1_9to1_8;
import lombok.RequiredArgsConstructor;
import org.bukkit.Bukkit;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.PlayerChangedWorldEvent;
@@ -14,32 +12,36 @@ import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.inventory.CraftingInventory;
import org.bukkit.inventory.ItemStack;
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.Via;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.bukkit.listeners.ViaBukkitListener;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.ArmorType;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
import java.util.UUID;
@RequiredArgsConstructor
public class ArmorListener implements Listener {
public class ArmorListener extends ViaBukkitListener {
private static final UUID ARMOR_ATTRIBUTE = UUID.fromString("2AD3F246-FEE1-4E67-B886-69FD380BB150");
private final ViaVersionPlugin plugin;
public static void sendArmorUpdate(Player player) {
public ArmorListener(ViaVersionPlugin plugin) {
super(plugin, Protocol1_9TO1_8.class);
}
public void sendArmorUpdate(Player player) {
// Ensure that the player is on our pipe
UserConnection userConnection = ((ViaVersionPlugin) ViaVersion.getInstance()).getConnection(player);
if (userConnection == null) return;
if (!userConnection.get(ProtocolInfo.class).getPipeline().contains(Protocol1_9TO1_8.class)) return;
if (!isOnPipe(player)) return;
int armor = ArmorType.calculateArmorPoints(player.getInventory().getArmorContents());
PacketWrapper wrapper = new PacketWrapper(0x4B, null, userConnection);
int armor = 0;
for (ItemStack stack : player.getInventory().getArmorContents()) {
armor += ArmorType.findById(stack.getTypeId()).getArmorPoints();
}
PacketWrapper wrapper = new PacketWrapper(0x4B, null, getUserConnection(player));
try {
wrapper.write(Type.VAR_INT, player.getEntityId()); // Player ID
wrapper.write(Type.INT, 1); // only 1 property
@@ -61,17 +63,15 @@ public class ArmorListener implements Listener {
HumanEntity human = e.getWhoClicked();
if (human instanceof Player && e.getInventory() instanceof CraftingInventory) {
final Player player = (Player) human;
if (ViaVersion.getInstance().isPorted(player)) {
if (e.getCurrentItem() != null) {
if (ArmorType.isArmor(e.getCurrentItem().getType())) {
sendDelayedArmorUpdate(player);
return;
}
}
if (e.getRawSlot() >= 5 && e.getRawSlot() <= 8) {
if (e.getCurrentItem() != null) {
if (ArmorType.isArmor(e.getCurrentItem().getTypeId())) {
sendDelayedArmorUpdate(player);
return;
}
}
if (e.getRawSlot() >= 5 && e.getRawSlot() <= 8) {
sendDelayedArmorUpdate(player);
}
}
}
@@ -81,12 +81,10 @@ public class ArmorListener implements Listener {
if (e.getAction() == Action.RIGHT_CLICK_AIR || e.getAction() == Action.RIGHT_CLICK_BLOCK) {
final Player player = e.getPlayer();
// Due to odd bugs it's 3 ticks later
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
Bukkit.getScheduler().scheduleSyncDelayedTask(getPlugin(), new Runnable() {
@Override
public void run() {
if (ViaVersion.getInstance().isPorted(player)) {
sendArmorUpdate(player);
}
sendArmorUpdate(player);
}
}, 3L);
}
@@ -100,23 +98,20 @@ public class ArmorListener implements Listener {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onRespawn(PlayerRespawnEvent e) {
if (ViaVersion.getInstance().isPorted(e.getPlayer()))
sendDelayedArmorUpdate(e.getPlayer());
sendDelayedArmorUpdate(e.getPlayer());
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onWorldChange(PlayerChangedWorldEvent e) {
if (ViaVersion.getInstance().isPorted(e.getPlayer()))
sendArmorUpdate(e.getPlayer());
sendArmorUpdate(e.getPlayer());
}
public void sendDelayedArmorUpdate(final Player player) {
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
if (!isOnPipe(player)) return; // Don't start a task if the player is not on the pipe
Via.getPlatform().runSync(new Runnable() {
@Override
public void run() {
if (ViaVersion.getInstance().isPorted(player)) {
sendArmorUpdate(player);
}
sendArmorUpdate(player);
}
});
}
@@ -0,0 +1,28 @@
package us.myles.ViaVersion.bukkit.listeners.protocol1_9to1_8;
import org.bukkit.block.Block;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockPlaceEvent;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.minecraft.Position;
import us.myles.ViaVersion.bukkit.listeners.ViaBukkitListener;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.EntityTracker;
public class BlockListener extends ViaBukkitListener {
public BlockListener(ViaVersionPlugin plugin) {
super(plugin, Protocol1_9TO1_8.class);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void placeBlock(BlockPlaceEvent e) {
if (isOnPipe(e.getPlayer())) {
Block b = e.getBlockPlaced();
getUserConnection(e.getPlayer())
.get(EntityTracker.class)
.addBlockInteraction(new Position((long) b.getX(), (long) b.getY(), (long) b.getZ()));
}
}
}
@@ -1,40 +1,28 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8.listeners;
package us.myles.ViaVersion.bukkit.listeners.protocol1_9to1_8;
import lombok.RequiredArgsConstructor;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.bukkit.listeners.ViaBukkitListener;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
@RequiredArgsConstructor
public class DeathListener implements Listener {
private final ViaVersionPlugin plugin;
public class DeathListener extends ViaBukkitListener {
public DeathListener(ViaVersionPlugin plugin) {
super(plugin, Protocol1_9TO1_8.class);
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onDeath(PlayerDeathEvent e) {
Player p = e.getEntity();
if (ViaVersion.getConfig().isShowNewDeathMessages() && checkGamerule(p.getWorld()) && e.getDeathMessage() != null && checkPipeline(p)) {
if (isOnPipe(p) && ViaVersion.getConfig().isShowNewDeathMessages() && checkGamerule(p.getWorld()) && e.getDeathMessage() != null)
sendPacket(p, e.getDeathMessage());
}
}
public boolean checkPipeline(Player p) {
UserConnection userConnection = plugin.getConnection(p);
return userConnection != null && userConnection.get(ProtocolInfo.class).getPipeline().contains(Protocol1_9TO1_8.class);
}
private UserConnection getUserConnection(Player p) {
return plugin.getConnection(p);
}
public boolean checkGamerule(World w) {
@@ -46,19 +34,19 @@ public class DeathListener implements Listener {
}
private void sendPacket(final Player p, final String msg) {
Bukkit.getScheduler().runTask(plugin, new Runnable() {
Via.getPlatform().runSync(new Runnable() {
@Override
public void run() {
PacketWrapper wrapper = new PacketWrapper(0x2C, null, getUserConnection(p));
try {
wrapper.write(Type.VAR_INT, 2);
wrapper.write(Type.VAR_INT, p.getEntityId());
wrapper.write(Type.INT, p.getEntityId());
Protocol1_9TO1_8.FIX_JSON.write(wrapper, msg);
wrapper.write(Type.VAR_INT, 2); // Event - Entity dead
wrapper.write(Type.VAR_INT, p.getEntityId()); // Player ID
wrapper.write(Type.INT, p.getEntityId()); // Entity ID
Protocol1_9TO1_8.FIX_JSON.write(wrapper, msg); // Message
wrapper.send(Protocol1_9TO1_8.class);
} catch (Exception e) {
e.printStackTrace();
wrapper.clearInputBuffer();
}
}
});
@@ -1,18 +1,17 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8.listeners;
package us.myles.ViaVersion.bukkit.listeners.protocol1_9to1_8;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitRunnable;
import us.myles.ViaVersion.api.minecraft.item.Item;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class HandItemCache extends BukkitRunnable {
public static boolean CACHE = false;
private static ConcurrentHashMap<UUID, Item> handCache = new ConcurrentHashMap<>();
private static Map<UUID, Item> handCache = new ConcurrentHashMap<>();
public static Item getHandItem(UUID player) {
if (!handCache.containsKey(player))
@@ -25,7 +24,7 @@ public class HandItemCache extends BukkitRunnable {
List<UUID> players = new ArrayList<>(handCache.keySet());
for (Player p : Bukkit.getOnlinePlayers()) {
handCache.put(p.getUniqueId(), Item.getItem(p.getItemInHand()));
handCache.put(p.getUniqueId(), convert(p.getItemInHand()));
players.remove(p.getUniqueId());
}
// Remove offline players
@@ -33,4 +32,9 @@ public class HandItemCache extends BukkitRunnable {
handCache.remove(uuid);
}
}
public static Item convert(ItemStack itemInHand) {
if (itemInHand == null) return new Item((short) 0, (byte) 0, (short) 0, null);
return new Item((short) itemInHand.getTypeId(), (byte) itemInHand.getAmount(), itemInHand.getDurability(), null);
}
}
@@ -1,32 +1,35 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8.listeners;
package us.myles.ViaVersion.bukkit.listeners.protocol1_9to1_8;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.bukkit.listeners.ViaBukkitListener;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
public class PaperPatch implements Listener {
public class PaperPatch extends ViaBukkitListener {
public PaperPatch(ViaVersionPlugin plugin) {
super(plugin, Protocol1_9TO1_8.class);
}
/*
This patch is applied when Paper is detected.
I'm unsure of what causes this but essentially,
placing blocks where your standing works?
placing blocks where you're standing works?
If there is a better fix then we'll replace this.
*/
@EventHandler(ignoreCancelled = true)
public void onPlace(BlockPlaceEvent e) {
if (ViaVersion.getInstance().isPorted(e.getPlayer())) {
UserConnection userConnection = ((ViaVersionPlugin) ViaVersion.getInstance()).getConnection(e.getPlayer());
if (userConnection == null) return;
if (!userConnection.get(ProtocolInfo.class).getPipeline().contains(Protocol1_9TO1_8.class)) return;
if (isOnPipe(e.getPlayer())) {
Location diff = e.getPlayer().getLocation().subtract(e.getBlock().getLocation().add(0.5D, 0, 0.5D));
Material block = e.getBlockPlaced().getType();
if (!block.isSolid()) {
return;
}
if (e.getPlayer().getLocation().getBlock().equals(e.getBlock())) {
e.setCancelled(true);
} else {
@@ -0,0 +1,184 @@
package us.myles.ViaVersion.bukkit.platform;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.ViaVersionConfig;
import us.myles.ViaVersion.util.Config;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class BukkitConfigAPI extends Config implements ViaVersionConfig {
private static List<String> UNSUPPORTED = Arrays.asList("bungee-ping-interval", "bungee-ping-save", "bungee-servers");
public BukkitConfigAPI() {
super(new File(((ViaVersionPlugin) Via.getPlatform()).getDataFolder(), "config.yml"));
}
@Override
public boolean isCheckForUpdates() {
return getBoolean("checkforupdates", true);
}
@Override
public boolean isPreventCollision() {
return getBoolean("prevent-collision", true);
}
@Override
public boolean isNewEffectIndicator() {
return getBoolean("use-new-effect-indicator", true);
}
@Override
public boolean isShowNewDeathMessages() {
return getBoolean("use-new-deathmessages", true);
}
@Override
public boolean isSuppressMetadataErrors() {
return getBoolean("suppress-metadata-errors", false);
}
@Override
public boolean isShieldBlocking() {
return getBoolean("shield-blocking", true);
}
@Override
public boolean isHologramPatch() {
return getBoolean("hologram-patch", false);
}
@Override
public boolean isPistonAnimationPatch() {
return getBoolean("piston-animation-patch", false);
}
@Override
public boolean isBossbarPatch() {
return getBoolean("bossbar-patch", true);
}
@Override
public boolean isBossbarAntiflicker() {
return getBoolean("bossbar-anti-flicker", false);
}
@Override
public boolean isUnknownEntitiesSuppressed() {
return false;
}
@Override
public double getHologramYOffset() {
return getDouble("hologram-y", -0.96D);
}
@Override
public boolean isBlockBreakPatch() {
return false;
}
@Override
public int getMaxPPS() {
return getInt("max-pps", 800);
}
@Override
public String getMaxPPSKickMessage() {
return getString("max-pps-kick-msg", "Sending packets too fast? lag?");
}
@Override
public int getTrackingPeriod() {
return getInt("tracking-period", 6);
}
@Override
public int getWarningPPS() {
return getInt("tracking-warning-pps", 120);
}
@Override
public int getMaxWarnings() {
return getInt("tracking-max-warnings", 3);
}
@Override
public String getMaxWarningsKickMessage() {
return getString("tracking-max-kick-msg", "You are sending too many packets, :(");
}
@Override
public boolean isAntiXRay() {
return getBoolean("anti-xray-patch", true);
}
@Override
public boolean isSendSupportedVersions() {
return getBoolean("send-supported-versions", false);
}
@Override
public boolean isStimulatePlayerTick() {
return getBoolean("simulate-pt", true);
}
@Override
public boolean isItemCache() {
return getBoolean("item-cache", true);
}
@Override
public boolean isNMSPlayerTicking() {
return getBoolean("nms-player-ticking", true);
}
@Override
public boolean isReplacePistons() {
return getBoolean("replace-pistons", false);
}
@Override
public int getPistonReplacementId() {
return getInt("replacement-piston-id", 0);
}
public boolean isAutoTeam() {
// Collision has to be enabled first
return isPreventCollision() && getBoolean("auto-team", true);
}
@Override
public boolean isForceJsonTransform() {
return getBoolean("force-json-transform", false);
}
@Override
public List<Integer> getBlockedProtocols() {
return getIntegerList("block-protocols");
}
@Override
public String getBlockedDisconnectMsg() {
return getString("block-disconnect-msg", "You are using an unsupported Minecraft version!");
}
@Override
public String getReloadDisconnectMsg() {
return getString("reload-disconnect-msg", "Server reload, please rejoin!");
}
@Override
protected void handleConfig(Map<String, Object> config) {
// Nothing currently
}
@Override
public List<String> getUnsupportedOptions() {
return UNSUPPORTED;
}
}
@@ -0,0 +1,11 @@
package us.myles.ViaVersion.bukkit.platform;
import lombok.AllArgsConstructor;
import lombok.Getter;
import us.myles.ViaVersion.api.platform.TaskId;
@Getter
@AllArgsConstructor
public class BukkitTaskId implements TaskId {
private Integer object;
}
@@ -0,0 +1,127 @@
package us.myles.ViaVersion.bukkit.platform;
import io.netty.buffer.ByteBuf;
import lombok.AllArgsConstructor;
import lombok.NonNull;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.ViaAPI;
import us.myles.ViaVersion.api.ViaVersionAPI;
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.bukkit.util.ProtocolSupportUtil;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.UUID;
@AllArgsConstructor
public class BukkitViaAPI implements ViaAPI<Player>, ViaVersionAPI {
private ViaVersionPlugin plugin;
@Override
public int getPlayerVersion(@NonNull Player player) {
if (!isPorted(player))
return getExternalVersion(player);
return getPortedPlayers().get(player.getUniqueId()).get(ProtocolInfo.class).getProtocolVersion();
}
@Override
public int getPlayerVersion(@NonNull UUID uuid) {
if (!isPorted(uuid))
return getExternalVersion(Bukkit.getPlayer(uuid));
return getPortedPlayers().get(uuid).get(ProtocolInfo.class).getProtocolVersion();
}
private int getExternalVersion(Player player) {
if (!isProtocolSupport()) {
return ProtocolRegistry.SERVER_PROTOCOL;
} else {
return ProtocolSupportUtil.getProtocolVersion(player);
}
}
@Override
public boolean isPorted(Player player) {
return isPorted(player.getUniqueId());
}
@Override
public boolean isPorted(UUID playerUUID) {
return getPortedPlayers().containsKey(playerUUID);
}
@Override
public String getVersion() {
return plugin.getDescription().getVersion();
}
@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 = getPortedPlayers().get(uuid);
ci.sendRawPacket(packet);
}
@Override
public void sendRawPacket(Player player, ByteBuf packet) throws IllegalArgumentException {
sendRawPacket(player.getUniqueId(), 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 Via.getManager().isDebug();
}
@Override
public ViaVersionCommand getCommandHandler() {
return Via.getManager().getCommandHandler();
}
@Override
public SortedSet<Integer> getSupportedVersions() {
SortedSet<Integer> outputSet = new TreeSet<>(ProtocolRegistry.getSupportedVersions());
outputSet.removeAll(Via.getPlatform().getConf().getBlockedProtocols());
return outputSet;
}
@Override
public boolean isCompatSpigotBuild() {
return plugin.isCompatSpigotBuild();
}
@Override
public boolean isSpigot() {
return plugin.isSpigot();
}
@Override
public boolean isProtocolSupport() {
return plugin.isProtocolSupport();
}
public Map<UUID, UserConnection> getPortedPlayers() {
return Via.getManager().getPortedPlayers();
}
}
@@ -0,0 +1,280 @@
package us.myles.ViaVersion.bukkit.platform;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import org.bukkit.plugin.PluginDescriptionFile;
import us.myles.ViaVersion.api.Pair;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.platform.ViaInjector;
import us.myles.ViaVersion.bukkit.handlers.BukkitChannelInitializer;
import us.myles.ViaVersion.bukkit.util.NMSUtil;
import us.myles.ViaVersion.util.ConcurrentList;
import us.myles.ViaVersion.util.ListWrapper;
import us.myles.ViaVersion.util.ReflectionUtil;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class BukkitViaInjector implements ViaInjector {
private List<ChannelFuture> injectedFutures = new ArrayList<>();
private List<Pair<Field, Object>> injectedLists = new ArrayList<>();
@Override
public void inject() throws Exception {
try {
Object connection = getServerConnection();
if (connection == null) {
throw new Exception("We failed to find the core component 'ServerConnection', please file an issue on our GitHub.");
}
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) {
try {
injectChannelFuture((ChannelFuture) o);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
};
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) {
injectChannelFuture((ChannelFuture) o);
} else {
break; // not the right list.
}
}
}
}
}
} catch (Exception e) {
Via.getPlatform().getLogger().severe("Unable to inject ViaVersion, please post these details on our GitHub and ensure you're using a compatible server version.");
throw e;
}
}
private void injectChannelFuture(ChannelFuture future) throws Exception {
try {
List<String> names = future.channel().pipeline().names();
ChannelHandler bootstrapAcceptor = null;
// Pick best
for (String name : names) {
ChannelHandler handler = future.channel().pipeline().get(name);
try {
ReflectionUtil.get(handler, "childHandler", ChannelInitializer.class);
bootstrapAcceptor = handler;
} catch (Exception e) {
// Not this one
}
}
// Default to first (Also allows blame to work)
if (bootstrapAcceptor == null) {
bootstrapAcceptor = future.channel().pipeline().first();
}
try {
ChannelInitializer<SocketChannel> oldInit = ReflectionUtil.get(bootstrapAcceptor, "childHandler", ChannelInitializer.class);
ChannelInitializer newInit = new BukkitChannelInitializer(oldInit);
ReflectionUtil.set(bootstrapAcceptor, "childHandler", newInit);
injectedFutures.add(future);
} catch (NoSuchFieldException e) {
// let's find who to blame!
ClassLoader cl = bootstrapAcceptor.getClass().getClassLoader();
if (cl.getClass().getName().equals("org.bukkit.plugin.java.PluginClassLoader")) {
PluginDescriptionFile yaml = ReflectionUtil.get(cl, "description", PluginDescriptionFile.class);
throw new Exception("Unable to inject, due to " + bootstrapAcceptor.getClass().getName() + ", try without the plugin " + yaml.getName() + "?");
} else {
throw new Exception("Unable to find core component 'childHandler', please check your plugins. issue: " + bootstrapAcceptor.getClass().getName());
}
}
} catch (Exception e) {
Via.getPlatform().getLogger().severe("We failed to inject ViaVersion, have you got late-bind enabled with something else?");
throw e;
}
}
@Override
public void uninject() {
// TODO: Uninject from players currently online to prevent protocol lib issues.
for (ChannelFuture future : injectedFutures) {
List<String> names = future.channel().pipeline().names();
ChannelHandler bootstrapAcceptor = null;
// Pick best
for (String name : names) {
ChannelHandler handler = future.channel().pipeline().get(name);
try {
ChannelInitializer<SocketChannel> oldInit = ReflectionUtil.get(handler, "childHandler", ChannelInitializer.class);
if (oldInit instanceof BukkitChannelInitializer) {
bootstrapAcceptor = handler;
}
} catch (Exception e) {
// Not this one
}
}
// Default to first
if (bootstrapAcceptor == null) {
bootstrapAcceptor = future.channel().pipeline().first();
}
try {
ChannelInitializer<SocketChannel> oldInit = ReflectionUtil.get(bootstrapAcceptor, "childHandler", ChannelInitializer.class);
if (oldInit instanceof BukkitChannelInitializer) {
ReflectionUtil.set(bootstrapAcceptor, "childHandler", ((BukkitChannelInitializer) oldInit).getOriginal());
}
} catch (Exception e) {
Via.getPlatform().getLogger().severe("Failed to remove injection handler, reload won't work with connections, please reboot!");
}
}
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) {
Via.getPlatform().getLogger().severe("Failed to remove injection, reload won't work with connections, please reboot!");
}
}
injectedLists.clear();
}
@Override
public int getServerProtocolVersion() throws Exception {
try {
Class<?> serverClazz = NMSUtil.nms("MinecraftServer");
Object server = ReflectionUtil.invokeStatic(serverClazz, "getServer");
Class<?> pingClazz = NMSUtil.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) {
return protocolVersion;
}
}
}
} catch (Exception e) {
throw new Exception("Failed to get server", e);
}
throw new Exception("Failed to get server");
}
@Override
public String getEncoderName() {
return "encoder";
}
@Override
public String getDecoderName() {
return "decoder";
}
public static Object getServerConnection() throws Exception {
Class<?> serverClazz = NMSUtil.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);
}
}
}
}
return connection;
}
public static void patchLists() throws Exception {
Object connection = getServerConnection();
if (connection == null) {
Via.getPlatform().getLogger().warning("We failed to find the core component 'ServerConnection', please file an issue on our GitHub.");
return;
}
for (Field field : connection.getClass().getDeclaredFields()) {
field.setAccessible(true);
final Object value = field.get(connection);
if (value instanceof List) {
if (!(value instanceof ConcurrentList)) {
ConcurrentList list = new ConcurrentList();
list.addAll((List) value);
field.set(connection, list);
}
}
}
}
public static boolean isBinded() {
try {
Object connection = getServerConnection();
if (connection == null) {
return false;
}
for (Field field : connection.getClass().getDeclaredFields()) {
field.setAccessible(true);
final Object value = field.get(connection);
if (value instanceof List) {
// Inject the list
synchronized (value) {
for (Object o : (List) value) {
if (o instanceof ChannelFuture) {
return true;
} else {
break; // not the right list.
}
}
}
}
}
} catch (Exception e) {
}
return false;
}
}
@@ -0,0 +1,91 @@
package us.myles.ViaVersion.bukkit.platform;
import lombok.AllArgsConstructor;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.minecraft.item.Item;
import us.myles.ViaVersion.api.platform.ViaPlatformLoader;
import us.myles.ViaVersion.bukkit.listeners.UpdateListener;
import us.myles.ViaVersion.bukkit.listeners.protocol1_9to1_8.*;
import us.myles.ViaVersion.bukkit.providers.BukkitViaBulkChunkTranslator;
import us.myles.ViaVersion.bukkit.providers.BukkitViaMovementTransmitter;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.BulkChunkTranslatorProvider;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.HandItemProvider;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
@AllArgsConstructor
public class BukkitViaLoader implements ViaPlatformLoader {
private ViaVersionPlugin plugin;
@Override
public void load() {
// Update Listener
Bukkit.getPluginManager().registerEvents(new UpdateListener(), plugin);
/* Base Protocol */
final ViaVersionPlugin plugin = (ViaVersionPlugin) Bukkit.getPluginManager().getPlugin("ViaVersion");
Bukkit.getPluginManager().registerEvents(new Listener() {
@EventHandler
public void onPlayerQuit(PlayerQuitEvent e) {
Via.getManager().removePortedClient(e.getPlayer().getUniqueId());
}
}, plugin);
/* 1.9 client to 1.8 server */
new ArmorListener(plugin).register();
new DeathListener(plugin).register();
new BlockListener(plugin).register();
if (Bukkit.getVersion().toLowerCase().contains("paper") || Bukkit.getVersion().toLowerCase().contains("taco")) {
plugin.getLogger().info("Enabling PaperSpigot/TacoSpigot patch: Fixes block placement.");
new PaperPatch(plugin).register();
}
if (plugin.getConf().isItemCache()) {
new HandItemCache().runTaskTimerAsynchronously(plugin, 2L, 2L); // Updates player's items :)
HandItemCache.CACHE = true;
}
/* Providers */
Via.getManager().getProviders().use(BulkChunkTranslatorProvider.class, new BukkitViaBulkChunkTranslator());
Via.getManager().getProviders().use(MovementTransmitterProvider.class, new BukkitViaMovementTransmitter());
Via.getManager().getProviders().use(HandItemProvider.class, new HandItemProvider() {
@Override
public Item getHandItem(final UserConnection info) {
if (HandItemCache.CACHE) {
return HandItemCache.getHandItem(info.get(ProtocolInfo.class).getUuid());
} else {
try {
return Bukkit.getScheduler().callSyncMethod(Bukkit.getPluginManager().getPlugin("ViaVersion"), new Callable<Item>() {
@Override
public Item call() throws Exception {
UUID playerUUID = info.get(ProtocolInfo.class).getUuid();
if (Bukkit.getPlayer(playerUUID) != null) {
return HandItemCache.convert(Bukkit.getPlayer(playerUUID).getItemInHand());
}
return null;
}
}).get(10, TimeUnit.SECONDS);
} catch (Exception e) {
Via.getPlatform().getLogger().severe("Error fetching hand item: " + e.getClass().getName());
if (Via.getManager().isDebug())
e.printStackTrace();
return null;
}
}
}
});
}
}
@@ -1,69 +1,53 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8.storage;
package us.myles.ViaVersion.bukkit.providers;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.WorldType;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.data.StoredObject;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.bukkit.util.NMSUtil;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.BulkChunkTranslatorProvider;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.ClientChunks;
import us.myles.ViaVersion.util.ReflectionUtil;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
@Getter
public class ClientChunks extends StoredObject {
public class BukkitViaBulkChunkTranslator extends BulkChunkTranslatorProvider {
// Reflection
private static ReflectionUtil.ClassReflection mapChunkBulkRef;
private static ReflectionUtil.ClassReflection mapChunkRef;
private static Method obfuscateRef;
private static Class<?> worldRef;
static {
try {
mapChunkBulkRef = new ReflectionUtil.ClassReflection(ReflectionUtil.nms("PacketPlayOutMapChunkBulk"));
mapChunkRef = new ReflectionUtil.ClassReflection(ReflectionUtil.nms("PacketPlayOutMapChunk"));
if (ViaVersion.getInstance().isSpigot()) {
obfuscateRef = Class.forName("org.spigotmc.AntiXray").getMethod("obfuscate", int.class, int.class, int.class, byte[].class, ReflectionUtil.nms("World"));
worldRef = ReflectionUtil.nms("World");
mapChunkBulkRef = new ReflectionUtil.ClassReflection(NMSUtil.nms("PacketPlayOutMapChunkBulk"));
mapChunkRef = new ReflectionUtil.ClassReflection(NMSUtil.nms("PacketPlayOutMapChunk"));
if (((ViaVersionPlugin) Via.getPlatform()).isSpigot()) {
obfuscateRef = Class.forName("org.spigotmc.AntiXray").getMethod("obfuscate", int.class, int.class, int.class, byte[].class, NMSUtil.nms("World"));
}
} catch (ClassNotFoundException e) {
// Ignore as server is probably 1.9+
} catch (Exception e) {
Bukkit.getLogger().log(Level.WARNING, "Failed to initialise chunks reflection", e);
Via.getPlatform().getLogger().log(Level.WARNING, "Failed to initialise chunks reflection", e);
}
}
private final Set<Long> loadedChunks = Sets.newConcurrentHashSet();
private final Set<Long> bulkChunks = Sets.newConcurrentHashSet();
public ClientChunks(UserConnection user) {
super(user);
}
private static long toLong(int msw, int lsw) {
return ((long) msw << 32) + lsw - -2147483648L;
}
public List<Object> transformMapChunkBulk(Object packet) {
@Override
public List<Object> transformMapChunkBulk(Object packet, ClientChunks clientChunks) {
List<Object> list = Lists.newArrayList();
try {
int[] xcoords = mapChunkBulkRef.getFieldValue("a", packet, int[].class);
int[] zcoords = mapChunkBulkRef.getFieldValue("b", packet, int[].class);
Object[] chunkMaps = mapChunkBulkRef.getFieldValue("c", packet, Object[].class);
if (ViaVersion.getConfig().isAntiXRay() && ViaVersion.getInstance().isSpigot()) { //Spigot anti-xray patch
if (Via.getConfig().isAntiXRay() && ((ViaVersionPlugin) Via.getPlatform()).isSpigot()) { //Spigot anti-xray patch
try {
Object world = mapChunkBulkRef.getFieldValue("world", packet, Object.class);
Object spigotConfig = ReflectionUtil.getPublic(world, "spigotConfig", Object.class);
Object antiXrayInstance = ReflectionUtil.getPublic(spigotConfig, "antiXrayInstance", Object.class);
for (int i = 0; i < xcoords.length; ++i) {
Object spigotConfig = ReflectionUtil.getPublic(world, "spigotConfig", Object.class);
Object antiXrayInstance = ReflectionUtil.getPublic(spigotConfig, "antiXrayInstance", Object.class);
// TODO: Possibly optimise this
Object b = ReflectionUtil.get(chunkMaps[i], "b", Object.class);
Object a = ReflectionUtil.get(chunkMaps[i], "a", Object.class);
@@ -82,12 +66,22 @@ public class ClientChunks extends StoredObject {
mapChunkRef.setFieldValue("b", chunkPacket, z);
mapChunkRef.setFieldValue("c", chunkPacket, chunkMap);
mapChunkRef.setFieldValue("d", chunkPacket, true); // Chunk bulk chunks are always ground-up
bulkChunks.add(toLong(x, z)); // Store for later
clientChunks.getBulkChunks().add(ClientChunks.toLong(x, z)); // Store for later
list.add(chunkPacket);
}
} catch (Exception e) {
Bukkit.getLogger().log(Level.WARNING, "Failed to transform chunks bulk", e);
Via.getPlatform().getLogger().log(Level.WARNING, "Failed to transform chunks bulk", e);
}
return list;
}
@Override
public boolean isFiltered(Class<?> packetClass) {
return packetClass.getName().endsWith("PacketPlayOutMapChunkBulk");
}
@Override
public boolean isPacketLevel() {
return false;
}
}
@@ -0,0 +1,103 @@
package us.myles.ViaVersion.bukkit.providers;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.bukkit.util.NMSUtil;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.MovementTracker;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class BukkitViaMovementTransmitter extends MovementTransmitterProvider {
private static boolean USE_NMS = true;
// Used for packet mode
private Object idlePacket;
private Object idlePacket2;
// Use for nms
private Method getHandle;
private Field connection;
private Method handleFlying;
public BukkitViaMovementTransmitter() {
USE_NMS = Via.getConfig().isNMSPlayerTicking();
Class<?> idlePacketClass;
try {
idlePacketClass = NMSUtil.nms("PacketPlayInFlying");
} catch (ClassNotFoundException e) {
return; // We'll hope this is 1.9.4+
}
try {
idlePacket = idlePacketClass.newInstance();
idlePacket2 = idlePacketClass.newInstance();
Field flying = idlePacketClass.getDeclaredField("f");
flying.setAccessible(true);
flying.set(idlePacket2, true);
} catch (NoSuchFieldException | InstantiationException | IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException("Couldn't make player idle packet, help!", e);
}
if (USE_NMS) {
try {
getHandle = NMSUtil.obc("entity.CraftPlayer").getDeclaredMethod("getHandle");
} catch (NoSuchMethodException | ClassNotFoundException e) {
throw new RuntimeException("Couldn't find CraftPlayer", e);
}
try {
connection = NMSUtil.nms("EntityPlayer").getDeclaredField("playerConnection");
} catch (NoSuchFieldException | ClassNotFoundException e) {
throw new RuntimeException("Couldn't find Player Connection", e);
}
try {
handleFlying = NMSUtil.nms("PlayerConnection").getDeclaredMethod("a", idlePacketClass);
} catch (NoSuchMethodException | ClassNotFoundException e) {
throw new RuntimeException("Couldn't find CraftPlayer", e);
}
}
}
@Override
public Object getFlyingPacket() {
if (idlePacket == null)
throw new NullPointerException("Could not locate flying packet");
return idlePacket2;
}
@Override
public Object getGroundPacket() {
if (idlePacket == null)
throw new NullPointerException("Could not locate flying packet");
return idlePacket;
}
@Override
public void sendPlayer(UserConnection info) {
if (USE_NMS) {
Player player = Bukkit.getPlayer(info.get(ProtocolInfo.class).getUuid());
if (player != null) {
try {
// Tick player
Object entityPlayer = getHandle.invoke(player);
Object pc = connection.get(entityPlayer);
if (pc != null) {
handleFlying.invoke(pc, (info.get(MovementTracker.class).isGround() ? idlePacket2 : idlePacket));
// Tick world
info.get(MovementTracker.class).incrementIdlePacket();
}
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
} else {
super.sendPlayer(info);
}
}
}
@@ -0,0 +1,20 @@
package us.myles.ViaVersion.bukkit.util;
import org.bukkit.Bukkit;
public class NMSUtil {
private static String BASE = Bukkit.getServer().getClass().getPackage().getName();
private static String NMS = BASE.replace("org.bukkit.craftbukkit", "net.minecraft.server");
public static Class<?> nms(String className) throws ClassNotFoundException {
return Class.forName(NMS + "." + className);
}
public static Class<?> obc(String className) throws ClassNotFoundException {
return Class.forName(BASE + "." + className);
}
public static String getVersion() {
return BASE.substring(BASE.lastIndexOf('.') + 1);
}
}
@@ -1,4 +1,4 @@
package us.myles.ViaVersion.util;
package us.myles.ViaVersion.bukkit.util;
import org.bukkit.entity.Player;
+12
View File
@@ -0,0 +1,12 @@
name: ViaVersion
main: us.myles.ViaVersion.ViaVersionPlugin
authors: [_MylesC, Matsv]
version: ${project.version}
description: ${project.description}
load: postworld
loadbefore: [ProtocolLib, ProxyPipe, SpigotLib, SkinRestorer]
softdepend: [ProtocolSupport, PacketListenerApi]
commands:
viaversion:
description: Shows ViaVersion Version and more.
aliases: [viaver, vvbukkit]
+43
View File
@@ -0,0 +1,43 @@
<?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"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>viaversion-parent</artifactId>
<groupId>us.myles</groupId>
<version>1.0.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>viaversion-bungee</artifactId>
<build>
<resources>
<resource>
<targetPath>.</targetPath>
<filtering>true</filtering>
<directory>src/main/resources/</directory>
<includes>
<include>*</include>
</includes>
</resource>
</resources>
</build>
<dependencies>
<!-- BungeeCord API -->
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<version>1.10-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!-- Common Module -->
<dependency>
<groupId>us.myles</groupId>
<artifactId>viaversion-common</artifactId>
<version>1.0.2</version>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,162 @@
package us.myles.ViaVersion;
import com.google.gson.JsonObject;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.event.EventHandler;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.ViaAPI;
import us.myles.ViaVersion.api.command.ViaCommandSender;
import us.myles.ViaVersion.api.configuration.ConfigurationProvider;
import us.myles.ViaVersion.api.platform.TaskId;
import us.myles.ViaVersion.api.platform.ViaPlatform;
import us.myles.ViaVersion.bungee.commands.BungeeCommand;
import us.myles.ViaVersion.bungee.commands.BungeeCommandHandler;
import us.myles.ViaVersion.bungee.commands.BungeeCommandSender;
import us.myles.ViaVersion.bungee.platform.*;
import us.myles.ViaVersion.bungee.service.ProtocolDetectorService;
import us.myles.ViaVersion.dump.PluginInfo;
import us.myles.ViaVersion.util.GsonUtil;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
public class BungeePlugin extends Plugin implements ViaPlatform, Listener {
private BungeeViaAPI api;
private BungeeConfigAPI config;
private BungeeCommandHandler commandHandler;
@Override
public void onLoad() {
api = new BungeeViaAPI();
config = new BungeeConfigAPI(getDataFolder());
commandHandler = new BungeeCommandHandler();
ProxyServer.getInstance().getPluginManager().registerCommand(this, new BungeeCommand(commandHandler));
// Init platform
Via.init(ViaManager.builder()
.platform(this)
.injector(new BungeeViaInjector())
.loader(new BungeeViaLoader(this))
.commandHandler(commandHandler)
.build());
}
@Override
public void onEnable() {
// Inject
Via.getManager().init();
}
@Override
public String getPlatformName() {
return getProxy().getName();
}
@Override
public String getPlatformVersion() {
return getProxy().getVersion();
}
@Override
public String getPluginVersion() {
return getDescription().getVersion();
}
@Override
public TaskId runAsync(Runnable runnable) {
return new BungeeTaskId(getProxy().getScheduler().runAsync(this, runnable).getId());
}
@Override
public TaskId runSync(Runnable runnable) {
return runAsync(runnable);
}
@Override
public TaskId runRepeatingSync(Runnable runnable, Long ticks) {
return new BungeeTaskId(getProxy().getScheduler().schedule(this, runnable, 0, ticks * 50, TimeUnit.MILLISECONDS).getId());
}
@Override
public void cancelTask(TaskId taskId) {
if (taskId == null) return;
if (taskId.getObject() == null) return;
if (taskId instanceof BungeeTaskId) {
getProxy().getScheduler().cancel((Integer) taskId.getObject());
}
}
@Override
public ViaCommandSender[] getOnlinePlayers() {
ViaCommandSender[] array = new ViaCommandSender[getProxy().getPlayers().size()];
int i = 0;
for (ProxiedPlayer player : getProxy().getPlayers()) {
array[i++] = new BungeeCommandSender(player);
}
return array;
}
@Override
public void sendMessage(UUID uuid, String message) {
getProxy().getPlayer(uuid).sendMessage(TextComponent.fromLegacyText(message));
}
@Override
public boolean kickPlayer(UUID uuid, String message) {
if (getProxy().getPlayer(uuid) != null) {
getProxy().getPlayer(uuid).disconnect(TextComponent.fromLegacyText(message));
return true;
}
return false;
}
@Override
public boolean isPluginEnabled() {
return true;
}
@Override
public ViaAPI getApi() {
return api;
}
@Override
public BungeeConfigAPI getConf() {
return config;
}
@Override
public ConfigurationProvider getConfigurationProvider() {
return config;
}
@Override
public void onReload() {
// Injector prints a message <3
}
@Override
public JsonObject getDump() {
JsonObject platformSpecific = new JsonObject();
List<PluginInfo> plugins = new ArrayList<>();
for (Plugin p : ProxyServer.getInstance().getPluginManager().getPlugins())
plugins.add(new PluginInfo(true, p.getDescription().getName(), p.getDescription().getVersion(), p.getDescription().getMain(), Arrays.asList(p.getDescription().getAuthor())));
platformSpecific.add("plugins", GsonUtil.getGson().toJsonTree(plugins));
platformSpecific.add("servers", GsonUtil.getGson().toJsonTree(ProtocolDetectorService.getDetectedIds()));
return platformSpecific;
}
@EventHandler
public void onQuit(PlayerDisconnectEvent e) {
Via.getManager().removePortedClient(e.getPlayer().getUniqueId());
}
}
@@ -0,0 +1,24 @@
package us.myles.ViaVersion.bungee.commands;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.TabExecutor;
public class BungeeCommand extends Command implements TabExecutor {
private final BungeeCommandHandler handler;
public BungeeCommand(BungeeCommandHandler handler) {
super("viaversion", "", "viaver", "vvbungee"); // The CommandHandler will handle the permission
this.handler = handler;
}
@Override
public void execute(CommandSender commandSender, String[] strings) {
handler.onCommand(new BungeeCommandSender(commandSender), strings);
}
@Override
public Iterable<String> onTabComplete(CommandSender commandSender, String[] strings) {
return handler.onTabComplete(new BungeeCommandSender(commandSender), strings);
}
}
@@ -0,0 +1,16 @@
package us.myles.ViaVersion.bungee.commands;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.bungee.commands.subs.ProbeSubCmd;
import us.myles.ViaVersion.commands.ViaCommandHandler;
public class BungeeCommandHandler extends ViaCommandHandler {
public BungeeCommandHandler() {
try {
registerSubCommand(new ProbeSubCmd());
} catch (Exception e) {
Via.getPlatform().getLogger().severe("Failed to register Bungee subcommands");
e.printStackTrace();
}
}
}
@@ -0,0 +1,38 @@
package us.myles.ViaVersion.bungee.commands;
import lombok.AllArgsConstructor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import us.myles.ViaVersion.api.command.ViaCommandSender;
import java.util.UUID;
@AllArgsConstructor
public class BungeeCommandSender implements ViaCommandSender {
private CommandSender sender;
@Override
public boolean hasPermission(String permission) {
return sender.hasPermission(permission);
}
@Override
public void sendMessage(String msg) {
sender.sendMessage(TextComponent.fromLegacyText(msg));
}
@Override
public UUID getUUID() {
if (sender instanceof ProxiedPlayer) {
return ((ProxiedPlayer) sender).getUniqueId();
} else {
return UUID.fromString(getName());
}
}
@Override
public String getName() {
return sender.getName();
}
}
@@ -0,0 +1,28 @@
package us.myles.ViaVersion.bungee.commands.subs;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.command.ViaCommandSender;
import us.myles.ViaVersion.api.command.ViaSubCommand;
import us.myles.ViaVersion.bungee.platform.BungeeConfigAPI;
import us.myles.ViaVersion.bungee.service.ProtocolDetectorService;
public class ProbeSubCmd extends ViaSubCommand {
@Override
public String name() {
return "probe";
}
@Override
public String description() {
return "Forces ViaVersion to scan server protocol versions " +
(((BungeeConfigAPI) Via.getConfig()).getBungeePingInterval() == -1 ?
"" : "(Also happens at an interval)");
}
@Override
public boolean execute(ViaCommandSender sender, String[] args) {
ProtocolDetectorService.getInstance().run();
sendMessage(sender, "&6Started searching for protocol versions");
return true;
}
}
@@ -0,0 +1,41 @@
package us.myles.ViaVersion.bungee.handlers;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.protocol.ProtocolPipeline;
import java.lang.reflect.Method;
public class BungeeChannelInitializer extends ChannelInitializer<SocketChannel> {
private final ChannelInitializer<Channel> original;
private Method method;
public BungeeChannelInitializer(ChannelInitializer<Channel> oldInit) {
this.original = oldInit;
try {
this.method = ChannelInitializer.class.getDeclaredMethod("initChannel", Channel.class);
this.method.setAccessible(true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
UserConnection info = new UserConnection(socketChannel);
// init protocol
new ProtocolPipeline(info);
// Add originals
this.method.invoke(this.original, socketChannel);
// Add our transformers
BungeeEncodeHandler encoder = new BungeeEncodeHandler(info);
BungeeDecodeHandler decoder = new BungeeDecodeHandler(info);
socketChannel.pipeline().addBefore("packet-encoder", "via-encoder", encoder);
socketChannel.pipeline().addBefore("packet-decoder", "via-decoder", decoder);
}
}
@@ -0,0 +1,79 @@
package us.myles.ViaVersion.bungee.handlers;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import us.myles.ViaVersion.api.PacketWrapper;
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.util.List;
@ChannelHandler.Sharable
public class BungeeDecodeHandler extends MessageToMessageDecoder<ByteBuf> {
private final UserConnection info;
public BungeeDecodeHandler(UserConnection info) {
this.info = info;
}
@Override
protected void decode(final ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> out) 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 (info.handlePPS())
return;
}
if (info.isActive()) {
// Handle ID
int id = Type.VAR_INT.read(bytebuf);
// Transform
ByteBuf newPacket = ctx.alloc().buffer();
try {
if (id == PacketWrapper.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 (Exception e) {
// Clear Buffer
bytebuf.clear();
// Release Packet, be free!
newPacket.release();
throw e;
}
} else {
bytebuf.retain();
}
out.add(bytebuf);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (PipelineUtil.containsCause(cause, CancelException.class)) return;
super.exceptionCaught(ctx, cause);
}
}
@@ -0,0 +1,82 @@
package us.myles.ViaVersion.bungee.handlers;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.bungee.util.BungeePipelineUtil;
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.util.List;
@ChannelHandler.Sharable
public class BungeeEncodeHandler extends MessageToMessageEncoder<ByteBuf> {
private final UserConnection info;
private boolean handledCompression = false;
public BungeeEncodeHandler(UserConnection info) {
this.info = info;
}
@Override
protected void encode(final ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> out) throws Exception {
if (bytebuf.readableBytes() == 0) {
throw new CancelException();
}
boolean needsCompress = false;
if (!handledCompression) {
if (ctx.pipeline().names().indexOf("compress") > ctx.pipeline().names().indexOf("via-encoder")) {
// Need to decompress this packet due to bad order
bytebuf = BungeePipelineUtil.decompress(ctx, bytebuf);
ChannelHandler encoder = ctx.pipeline().get("via-decoder");
ChannelHandler decoder = ctx.pipeline().get("via-encoder");
ctx.pipeline().remove(encoder);
ctx.pipeline().remove(decoder);
ctx.pipeline().addAfter("decompress", "via-decoder", encoder);
ctx.pipeline().addAfter("compress", "via-encoder", decoder);
needsCompress = true;
handledCompression = true;
}
}
// Increment sent
info.incrementSent();
if (info.isActive()) {
// Handle ID
int id = Type.VAR_INT.read(bytebuf);
// Transform
ByteBuf oldPacket = bytebuf.copy();
bytebuf.clear();
try {
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();
}
}
if (needsCompress) {
bytebuf = BungeePipelineUtil.compress(ctx, bytebuf);
}
out.add(bytebuf.retain());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (PipelineUtil.containsCause(cause, CancelException.class)) return;
super.exceptionCaught(ctx, cause);
}
}
@@ -0,0 +1,128 @@
package us.myles.ViaVersion.bungee.handlers;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.ServerConnectEvent;
import net.md_5.bungee.api.event.ServerConnectedEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.event.EventPriority;
import us.myles.ViaVersion.api.Pair;
import us.myles.ViaVersion.api.Via;
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.bungee.service.ProtocolDetectorService;
import us.myles.ViaVersion.bungee.storage.BungeeStorage;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
public class BungeeServerHandler implements Listener {
private static Method getPendingConnection;
private static Method getHandshake;
private static Method setProtocol;
private static Method getEntityMap = null;
private static Method setVersion = null;
private static Field entityRewrite = null;
private static Field channelWrapper = null;
static {
try {
getPendingConnection = Class.forName("net.md_5.bungee.UserConnection").getDeclaredMethod("getPendingConnection");
getHandshake = Class.forName("net.md_5.bungee.connection.InitialHandler").getDeclaredMethod("getHandshake");
setProtocol = Class.forName("net.md_5.bungee.protocol.packet.Handshake").getDeclaredMethod("setProtocolVersion", int.class);
getEntityMap = Class.forName("net.md_5.bungee.entitymap.EntityMap").getDeclaredMethod("getEntityMap", int.class);
setVersion = Class.forName("net.md_5.bungee.netty.ChannelWrapper").getDeclaredMethod("setVersion", int.class);
channelWrapper = Class.forName("net.md_5.bungee.UserConnection").getDeclaredField("ch");
channelWrapper.setAccessible(true);
entityRewrite = Class.forName("net.md_5.bungee.UserConnection").getDeclaredField("entityRewrite");
entityRewrite.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
// Set the handshake version every time someone connects to any server
@EventHandler
public void onServerConnect(ServerConnectEvent e) {
UserConnection user = Via.getManager().getConnection(e.getPlayer().getUniqueId());
if (user == null) return;
if (!user.has(BungeeStorage.class)) {
user.put(new BungeeStorage(user, e.getPlayer()));
}
int protocolId = ProtocolDetectorService.getProtocolId(e.getTarget().getName());
List<Pair<Integer, Protocol>> protocols = ProtocolRegistry.getProtocolPath(user.get(ProtocolInfo.class).getProtocolVersion(), protocolId);
// Check if ViaVersion can support that version
try {
Object pendingConnection = getPendingConnection.invoke(e.getPlayer());
Object handshake = getHandshake.invoke(pendingConnection);
setProtocol.invoke(handshake, protocols == null ? user.get(ProtocolInfo.class).getProtocolVersion() : protocolId);
} catch (InvocationTargetException | IllegalAccessException e1) {
e1.printStackTrace();
}
}
@EventHandler(priority = EventPriority.LOWEST)
public void onServerConnected(ServerConnectedEvent e) {
try {
checkServerChange(e, Via.getManager().getConnection(e.getPlayer().getUniqueId()));
} catch (Exception e1) {
e1.printStackTrace();
}
}
public void checkServerChange(ServerConnectedEvent e, UserConnection user) throws Exception {
if (user == null) return;
if (user.has(BungeeStorage.class)) {
BungeeStorage storage = user.get(BungeeStorage.class);
ProxiedPlayer player = storage.getPlayer();
if (e.getServer() != null) {
if (!e.getServer().getInfo().getName().equals(storage.getCurrentServer())) {
String serverName = e.getServer().getInfo().getName();
storage.setCurrentServer(serverName);
int protocolId = ProtocolDetectorService.getProtocolId(serverName);
ProtocolInfo info = user.get(ProtocolInfo.class);
// Refresh the pipes
List<Pair<Integer, Protocol>> protocols = ProtocolRegistry.getProtocolPath(info.getProtocolVersion(), protocolId);
ProtocolPipeline pipeline = user.get(ProtocolInfo.class).getPipeline();
user.clearStoredObjects();
pipeline.cleanPipes();
if (protocols == null) {
// TODO Check Bungee Supported Protocols? *shrugs*
protocolId = info.getProtocolVersion();
} else {
for (Pair<Integer, Protocol> prot : protocols) {
pipeline.add(prot.getValue());
}
}
user.put(info);
user.put(storage);
user.setActive(protocols != null);
// Init all protocols TODO check if this can get moved up to the previous for loop, and doesn't require the pipeline to already exist.
for (Protocol protocol : pipeline.pipes()) {
protocol.init(user);
}
Object wrapper = channelWrapper.get(player);
setVersion.invoke(wrapper, protocolId);
Object entityMap = getEntityMap.invoke(null, protocolId);
entityRewrite.set(player, entityMap);
}
}
}
}
}
@@ -0,0 +1,45 @@
package us.myles.ViaVersion.bungee.listeners;
import net.md_5.bungee.api.event.ServerConnectedEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.event.EventPriority;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.minecraft.metadata.Metadata;
import us.myles.ViaVersion.api.minecraft.metadata.types.MetaType1_9;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.api.type.types.version.Types1_9;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.EntityTracker;
import java.util.Collections;
/*
* This patches https://github.com/MylesIsCool/ViaVersion/issues/555
*/
public class ElytraPatch implements Listener {
@EventHandler(priority = EventPriority.HIGH)
public void onServerConnected(ServerConnectedEvent event) {
UserConnection user = Via.getManager().getConnection(event.getPlayer().getUniqueId());
if (user == null) return;
try {
if (user.get(ProtocolInfo.class).getPipeline().contains(Protocol1_9TO1_8.class)) {
int entityId = user.get(EntityTracker.class).getProvidedEntityId();
PacketWrapper wrapper = new PacketWrapper(0x39, null, user);
wrapper.write(Type.VAR_INT, entityId);
wrapper.write(Types1_9.METADATA_LIST, Collections.singletonList(new Metadata(0, MetaType1_9.Byte, (byte) 0)));
wrapper.send(Protocol1_9TO1_8.class);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,47 @@
package us.myles.ViaVersion.bungee.listeners;
import net.md_5.bungee.api.event.ServerConnectEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.EntityTracker;
import java.lang.reflect.Method;
/*
This solves the wrong mainhand issue when you join with BungeeCord on a 1.8 server, and switch to a 1.9 or higher.
*/
public class MainHandPatch implements Listener {
private static Method getSettings = null;
private static Method setMainHand = null;
static {
try {
getSettings = Class.forName("net.md_5.bungee.UserConnection").getDeclaredMethod("getSettings");
setMainHand = Class.forName("net.md_5.bungee.protocol.packet.ClientSettings").getDeclaredMethod("setMainHand", int.class);
} catch (Exception ignored) {
}
}
@EventHandler
public void onServerConnect(ServerConnectEvent event) {
// Ignore if it doesn't exist (Like BungeeCord 1.8)
if (setMainHand == null)
return;
UserConnection user = Via.getManager().getConnection(event.getPlayer().getUniqueId());
if(user == null) return;
try {
if (user.get(ProtocolInfo.class).getPipeline().contains(Protocol1_9TO1_8.class)) {
Object settings = getSettings.invoke(event.getPlayer());
setMainHand.invoke(settings, user.get(EntityTracker.class).getMainHand());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,18 @@
package us.myles.ViaVersion.bungee.listeners;
import net.md_5.bungee.api.event.PostLoginEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.update.UpdateUtil;
public class UpdateListener implements Listener {
@EventHandler
public void onJoin(PostLoginEvent e) {
if (e.getPlayer().hasPermission("viaversion.update")
&& Via.getConfig().isCheckForUpdates()) {
UpdateUtil.sendUpdateMessage(e.getPlayer().getUniqueId());
}
}
}
@@ -0,0 +1,34 @@
package us.myles.ViaVersion.bungee.platform;
import net.md_5.bungee.api.connection.ProxiedPlayer;
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.boss.CommonBoss;
public class BungeeBossBar extends CommonBoss<ProxiedPlayer> {
public BungeeBossBar(String title, float health, BossColor color, BossStyle style) {
super(title, health, color, style);
}
@Override
public BossBar addPlayer(ProxiedPlayer player) {
addPlayer(player.getUniqueId());
return this;
}
@Override
public BossBar addPlayers(ProxiedPlayer... players) {
for (ProxiedPlayer p : players)
addPlayer(p);
return this;
}
@Override
public BossBar removePlayer(ProxiedPlayer player) {
removePlayer(player.getUniqueId());
return this;
}
}
@@ -0,0 +1,237 @@
package us.myles.ViaVersion.bungee.platform;
import us.myles.ViaVersion.api.ViaVersionConfig;
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
import us.myles.ViaVersion.bungee.providers.BungeeVersionProvider;
import us.myles.ViaVersion.util.Config;
import java.io.File;
import java.util.*;
public class BungeeConfigAPI extends Config implements ViaVersionConfig {
private static List<String> UNSUPPORTED = Arrays.asList("nms-player-ticking", "item-cache", "anti-xray-patch");
public BungeeConfigAPI(File configFile) {
super(new File(configFile, "config.yml"));
}
@Override
protected void handleConfig(Map<String, Object> config) {
// Parse servers
Map<String, Object> servers;
if (!(config.get("bungee-servers") instanceof Map)) {
servers = new HashMap<>();
} else {
servers = (Map) config.get("bungee-servers");
}
// Convert any bad Protocol Ids
for (Map.Entry<String, Object> entry : new HashSet<>(servers.entrySet())) {
if (!(entry.getValue() instanceof Integer)) {
if (entry.getValue() instanceof String) {
ProtocolVersion found = ProtocolVersion.getClosest((String) entry.getValue());
if (found != null) {
servers.put(entry.getKey(), found.getId());
} else {
servers.remove(entry.getKey()); // Remove!
}
} else {
servers.remove(entry.getKey()); // Remove!
}
}
}
// Ensure default exists
if (!servers.containsKey("default")) {
servers.put("default", BungeeVersionProvider.getLowestSupportedVersion());
}
// Put back
config.put("bungee-servers", servers);
}
@Override
public List<String> getUnsupportedOptions() {
return UNSUPPORTED;
}
public boolean isCheckForUpdates() {
return getBoolean("checkforupdates", true);
}
@Override
public boolean isPreventCollision() {
return getBoolean("prevent-collision", true);
}
@Override
public boolean isNewEffectIndicator() {
return getBoolean("use-new-effect-indicator", true);
}
@Override
public boolean isShowNewDeathMessages() {
return getBoolean("use-new-deathmessages", true);
}
@Override
public boolean isSuppressMetadataErrors() {
return getBoolean("suppress-metadata-errors", false);
}
@Override
public boolean isShieldBlocking() {
return getBoolean("shield-blocking", true);
}
@Override
public boolean isHologramPatch() {
return getBoolean("hologram-patch", false);
}
@Override
public boolean isPistonAnimationPatch() {
return getBoolean("piston-animation-patch", false);
}
@Override
public boolean isBossbarPatch() {
return getBoolean("bossbar-patch", true);
}
@Override
public boolean isBossbarAntiflicker() {
return getBoolean("bossbar-anti-flicker", false);
}
@Override
public boolean isUnknownEntitiesSuppressed() {
return false;
}
@Override
public double getHologramYOffset() {
return getDouble("hologram-y", -0.96D);
}
@Override
public boolean isBlockBreakPatch() {
return false;
}
@Override
public int getMaxPPS() {
return getInt("max-pps", 800);
}
@Override
public String getMaxPPSKickMessage() {
return getString("max-pps-kick-msg", "Sending packets too fast? lag?");
}
@Override
public int getTrackingPeriod() {
return getInt("tracking-period", 6);
}
@Override
public int getWarningPPS() {
return getInt("tracking-warning-pps", 120);
}
@Override
public int getMaxWarnings() {
return getInt("tracking-max-warnings", 3);
}
@Override
public String getMaxWarningsKickMessage() {
return getString("tracking-max-kick-msg", "You are sending too many packets, :(");
}
@Override
public boolean isAntiXRay() {
return false;
}
@Override
public boolean isSendSupportedVersions() {
return getBoolean("send-supported-versions", false);
}
@Override
public boolean isStimulatePlayerTick() {
return getBoolean("simulate-pt", true);
}
@Override
public boolean isItemCache() {
return false;
}
@Override
public boolean isNMSPlayerTicking() {
return false;
}
@Override
public boolean isReplacePistons() {
return getBoolean("replace-pistons", false);
}
@Override
public int getPistonReplacementId() {
return getInt("replacement-piston-id", 0);
}
public boolean isAutoTeam() {
// Collision has to be enabled first
return isPreventCollision() && getBoolean("auto-team", true);
}
@Override
public boolean isForceJsonTransform() {
return getBoolean("force-json-transform", false);
}
@Override
public List<Integer> getBlockedProtocols() {
return getIntegerList("block-protocols");
}
@Override
public String getBlockedDisconnectMsg() {
return getString("block-disconnect-msg", "You are using an unsupported Minecraft version!");
}
@Override
public String getReloadDisconnectMsg() {
return getString("reload-disconnect-msg", "Server reload, please rejoin!");
}
/**
* What is the interval for checking servers via ping
* -1 for disabled
*
* @return Ping interval in seconds
*/
public int getBungeePingInterval() {
return getInt("bungee-ping-interval", 60);
}
/**
* Should the bungee ping be saved to the config on change.
*
* @return True if it should save
*/
public boolean isBungeePingSave() {
return getBoolean("bungee-ping-save", true);
}
/**
* Get the listed server protocols in the config.
* default will be listed as default.
*
* @return Map of String, Integer
*/
public Map<String, Integer> getBungeeServerProtocols() {
return get("bungee-servers", Map.class, new HashMap<>());
}
}
@@ -0,0 +1,11 @@
package us.myles.ViaVersion.bungee.platform;
import lombok.AllArgsConstructor;
import lombok.Getter;
import us.myles.ViaVersion.api.platform.TaskId;
@Getter
@AllArgsConstructor
public class BungeeTaskId implements TaskId {
private Integer object;
}
@@ -0,0 +1,89 @@
package us.myles.ViaVersion.bungee.platform;
import io.netty.buffer.ByteBuf;
import lombok.NonNull;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.ViaAPI;
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.data.UserConnection;
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
import us.myles.ViaVersion.bungee.service.ProtocolDetectorService;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.UUID;
public class BungeeViaAPI implements ViaAPI<ProxiedPlayer> {
@Override
public int getPlayerVersion(@NonNull ProxiedPlayer player) {
if (!isPorted(player.getUniqueId()))
return ProtocolRegistry.SERVER_PROTOCOL;
return getPortedPlayers().get(player.getUniqueId()).get(ProtocolInfo.class).getProtocolVersion();
}
@Override
public int getPlayerVersion(@NonNull UUID uuid) {
if (!isPorted(uuid))
return ProtocolRegistry.SERVER_PROTOCOL;
return getPortedPlayers().get(uuid).get(ProtocolInfo.class).getProtocolVersion();
}
@Override
public boolean isPorted(UUID playerUUID) {
return getPortedPlayers().containsKey(playerUUID);
}
@Override
public String getVersion() {
return Via.getPlatform().getPluginVersion();
}
@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 = getPortedPlayers().get(uuid);
ci.sendRawPacket(packet);
}
@Override
public void sendRawPacket(ProxiedPlayer player, ByteBuf packet) throws IllegalArgumentException {
sendRawPacket(player.getUniqueId(), packet);
}
@Override
public BossBar createBossBar(String title, BossColor color, BossStyle style) {
return new BungeeBossBar(title, 1F, color, style);
}
@Override
public BossBar createBossBar(String title, float health, BossColor color, BossStyle style) {
return new BungeeBossBar(title, health, color, style);
}
@Override
public SortedSet<Integer> getSupportedVersions() {
SortedSet<Integer> outputSet = new TreeSet<>(ProtocolRegistry.getSupportedVersions());
outputSet.removeAll(Via.getPlatform().getConf().getBlockedProtocols());
return outputSet;
}
public Map<UUID, UserConnection> getPortedPlayers() {
return Via.getManager().getPortedPlayers();
}
/**
* Forces ViaVersion to probe a server
*
* @param serverInfo The serverinfo to probe
*/
public void probeServer(ServerInfo serverInfo) {
ProtocolDetectorService.probeServer(serverInfo);
}
}
@@ -0,0 +1,59 @@
package us.myles.ViaVersion.bungee.platform;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.platform.ViaInjector;
import us.myles.ViaVersion.bungee.handlers.BungeeChannelInitializer;
import us.myles.ViaVersion.util.ReflectionUtil;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.List;
public class BungeeViaInjector implements ViaInjector {
@Override
public void inject() throws Exception {
try {
try {
Class<?> pipelineUtils = Class.forName("net.md_5.bungee.netty.PipelineUtils");
Field field = pipelineUtils.getDeclaredField("SERVER_CHILD");
field.setAccessible(true);
// Remove any final stuff
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
BungeeChannelInitializer newInit = new BungeeChannelInitializer((ChannelInitializer<Channel>) field.get(null));
field.set(null, newInit);
} catch (NoSuchFieldException e) {
throw new Exception("Unable to find core component 'childHandler', please check your plugins. issue: ");
}
} catch (Exception e) {
Via.getPlatform().getLogger().severe("Unable to inject ViaVersion, please post these details on our GitHub and ensure you're using a compatible server version.");
throw e;
}
}
@Override
public void uninject() {
Via.getPlatform().getLogger().severe("ViaVersion cannot remove itself from Bungee without a reboot!");
}
@Override
public int getServerProtocolVersion() throws Exception {
return (int) ReflectionUtil.getStatic(Class.forName("net.md_5.bungee.protocol.ProtocolConstants"), "SUPPORTED_VERSION_IDS", List.class).get(0);
}
@Override
public String getEncoderName() {
return "via-encoder";
}
@Override
public String getDecoderName() {
return "via-decoder";
}
}
@@ -0,0 +1,43 @@
package us.myles.ViaVersion.bungee.platform;
import lombok.AllArgsConstructor;
import net.md_5.bungee.api.ProxyServer;
import us.myles.ViaVersion.BungeePlugin;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.platform.ViaPlatformLoader;
import us.myles.ViaVersion.bungee.handlers.BungeeServerHandler;
import us.myles.ViaVersion.bungee.listeners.ElytraPatch;
import us.myles.ViaVersion.bungee.listeners.MainHandPatch;
import us.myles.ViaVersion.bungee.listeners.UpdateListener;
import us.myles.ViaVersion.bungee.providers.BungeeEntityIdProvider;
import us.myles.ViaVersion.bungee.providers.BungeeMovementTransmitter;
import us.myles.ViaVersion.bungee.providers.BungeeVersionProvider;
import us.myles.ViaVersion.bungee.service.ProtocolDetectorService;
import us.myles.ViaVersion.protocols.base.VersionProvider;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.EntityIdProvider;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider;
import java.util.concurrent.TimeUnit;
@AllArgsConstructor
public class BungeeViaLoader implements ViaPlatformLoader {
private BungeePlugin plugin;
@Override
public void load() {
// Listeners
ProxyServer.getInstance().getPluginManager().registerListener(plugin, plugin);
ProxyServer.getInstance().getPluginManager().registerListener(plugin, new UpdateListener());
ProxyServer.getInstance().getPluginManager().registerListener(plugin, new BungeeServerHandler());
ProxyServer.getInstance().getPluginManager().registerListener(plugin, new MainHandPatch());
ProxyServer.getInstance().getPluginManager().registerListener(plugin, new ElytraPatch());
// Providers
Via.getManager().getProviders().use(MovementTransmitterProvider.class, new BungeeMovementTransmitter());
Via.getManager().getProviders().use(VersionProvider.class, new BungeeVersionProvider());
Via.getManager().getProviders().use(EntityIdProvider.class, new BungeeEntityIdProvider());
if (plugin.getConf().getBungeePingInterval() > 0) {
plugin.getProxy().getScheduler().schedule(plugin, new ProtocolDetectorService(plugin), 0, plugin.getConf().getBungeePingInterval(), TimeUnit.SECONDS);
}
}
}
@@ -0,0 +1,28 @@
package us.myles.ViaVersion.bungee.providers;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.bungee.storage.BungeeStorage;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.EntityIdProvider;
import java.lang.reflect.Method;
public class BungeeEntityIdProvider extends EntityIdProvider {
private static Method getClientEntityId;
static {
try {
getClientEntityId = Class.forName("net.md_5.bungee.UserConnection").getDeclaredMethod("getClientEntityId");
} catch (NoSuchMethodException | ClassNotFoundException e) {
e.printStackTrace();
}
}
@Override
public int getEntityId(UserConnection user) throws Exception {
BungeeStorage storage = user.get(BungeeStorage.class);
ProxiedPlayer player = storage.getPlayer();
return (int) getClientEntityId.invoke(player);
}
}
@@ -0,0 +1,34 @@
package us.myles.ViaVersion.bungee.providers;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.packets.State;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.MovementTracker;
public class BungeeMovementTransmitter extends MovementTransmitterProvider {
@Override
public Object getFlyingPacket() {
return null;
}
@Override
public Object getGroundPacket() {
return null;
}
public void sendPlayer(UserConnection userConnection) {
if (userConnection.get(ProtocolInfo.class).getState() == State.PLAY) {
PacketWrapper wrapper = new PacketWrapper(0x03, null, userConnection);
wrapper.write(Type.BOOLEAN, userConnection.get(MovementTracker.class).isGround());
try {
wrapper.sendToServer();
} catch (Exception e) {
e.printStackTrace();
}
// PlayerPackets will increment idle
}
}
}
@@ -0,0 +1,66 @@
package us.myles.ViaVersion.bungee.providers;
import com.google.common.collect.Lists;
import net.md_5.bungee.api.ProxyServer;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.protocols.base.VersionProvider;
import us.myles.ViaVersion.util.ReflectionUtil;
import java.util.List;
public class BungeeVersionProvider extends VersionProvider {
private static Class<?> ref;
static {
try {
ref = Class.forName("net.md_5.bungee.protocol.ProtocolConstants");
} catch (Exception e) {
Via.getPlatform().getLogger().severe("Could not detect the ProtocolConstants class");
e.printStackTrace();
}
}
@Override
public int getServerProtocol(UserConnection user) throws Exception {
if (ref == null)
return super.getServerProtocol(user);
// TODO Have one constant list forever until restart? (Might limit plugins if they change this)
List<Integer> list = ReflectionUtil.getStatic(ref, "SUPPORTED_VERSION_IDS", List.class);
ProtocolInfo info = user.get(ProtocolInfo.class);
// Bungee supports it
if (list.contains(info.getProtocolVersion()))
return info.getProtocolVersion();
// Older than bungee supports, get the lowest version
if (info.getProtocolVersion() < list.get(0)) {
return getLowestSupportedVersion();
}
// Loop through all protocols to get the closest protocol id that bungee supports
for (Integer protocol : Lists.reverse(list)) {
if (info.getProtocolVersion() > protocol)
return protocol;
}
Via.getPlatform().getLogger().severe("Panic, no protocol id found for " + info.getProtocolVersion());
return info.getProtocolVersion();
}
public static int getLowestSupportedVersion() {
List<Integer> list;
try {
list = ReflectionUtil.getStatic(ref, "SUPPORTED_VERSION_IDS", List.class);
return list.get(0);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
// Fallback
return ProxyServer.getInstance().getProtocolVersion();
}
}
@@ -0,0 +1,80 @@
package us.myles.ViaVersion.bungee.service;
import lombok.Getter;
import net.md_5.bungee.api.Callback;
import net.md_5.bungee.api.ServerPing;
import net.md_5.bungee.api.config.ServerInfo;
import us.myles.ViaVersion.BungeePlugin;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.bungee.platform.BungeeConfigAPI;
import us.myles.ViaVersion.bungee.providers.BungeeVersionProvider;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ProtocolDetectorService implements Runnable {
private static final Map<String, Integer> detectedProtocolIds = new ConcurrentHashMap<>();
private BungeePlugin plugin;
@Getter
private static ProtocolDetectorService instance;
public ProtocolDetectorService(BungeePlugin plugin) {
this.plugin = plugin;
instance = this;
}
public static Integer getProtocolId(String serverName) {
// Step 1. Check Config
Map<String, Integer> servers = ((BungeeConfigAPI) Via.getConfig()).getBungeeServerProtocols();
if (servers.containsKey(serverName)) {
return servers.get(serverName);
}
// Step 2. Check Detected
if (detectedProtocolIds.containsKey(serverName)) {
return detectedProtocolIds.get(serverName);
}
// Step 3. Use Default
if (servers.containsKey("default")) {
return servers.get("default");
}
// Step 4: Use bungee lowest supported... *cries*
return BungeeVersionProvider.getLowestSupportedVersion();
}
@Override
public void run() {
for (final Map.Entry<String, ServerInfo> lists : plugin.getProxy().getServers().entrySet()) {
probeServer(lists.getValue());
}
}
public static void probeServer(final ServerInfo serverInfo) {
final String key = serverInfo.getName();
serverInfo.ping(new Callback<ServerPing>() {
@Override
public void done(ServerPing serverPing, Throwable throwable) {
if (throwable == null) {
detectedProtocolIds.put(key, serverPing.getVersion().getProtocol());
if (((BungeeConfigAPI) Via.getConfig()).isBungeePingSave()) {
Map<String, Integer> servers = ((BungeeConfigAPI) Via.getConfig()).getBungeeServerProtocols();
if (servers.containsKey(key)) {
if (servers.get(key) == serverPing.getVersion().getProtocol()) {
return;
}
}
// Save Server
servers.put(key, serverPing.getVersion().getProtocol());
// Save
Via.getPlatform().getConfigurationProvider().saveConfig();
}
}
}
});
}
public static Map<String, Integer> getDetectedIds() {
return new HashMap<>(detectedProtocolIds);
}
}
@@ -0,0 +1,20 @@
package us.myles.ViaVersion.bungee.storage;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import us.myles.ViaVersion.api.data.StoredObject;
import us.myles.ViaVersion.api.data.UserConnection;
@Data
@EqualsAndHashCode(callSuper = true)
public class BungeeStorage extends StoredObject {
private ProxiedPlayer player;
private String currentServer;
public BungeeStorage(UserConnection user, ProxiedPlayer player) {
super(user);
this.player = player;
this.currentServer = "";
}
}
@@ -0,0 +1,70 @@
package us.myles.ViaVersion.bungee.util;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.handler.codec.MessageToMessageDecoder;
import us.myles.ViaVersion.api.Via;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class BungeePipelineUtil {
private static Method DECODE_METHOD;
private static Method ENCODE_METHOD;
static {
try {
DECODE_METHOD = MessageToMessageDecoder.class.getDeclaredMethod("decode", ChannelHandlerContext.class, Object.class, List.class);
DECODE_METHOD.setAccessible(true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
ENCODE_METHOD = MessageToByteEncoder.class.getDeclaredMethod("encode", ChannelHandlerContext.class, Object.class, ByteBuf.class);
ENCODE_METHOD.setAccessible(true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
public static List<Object> callDecode(MessageToMessageDecoder decoder, ChannelHandlerContext ctx, ByteBuf input) throws InvocationTargetException {
List<Object> output = new ArrayList<>();
try {
BungeePipelineUtil.DECODE_METHOD.invoke(decoder, ctx, input, output);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return output;
}
public static ByteBuf callEncode(MessageToByteEncoder encoder, ChannelHandlerContext ctx, ByteBuf input) throws InvocationTargetException {
ByteBuf output = ctx.alloc().buffer();
try {
BungeePipelineUtil.ENCODE_METHOD.invoke(encoder, ctx, input, output);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return output;
}
public static ByteBuf decompress(ChannelHandlerContext ctx, ByteBuf bytebuf) {
try {
return (ByteBuf) callDecode((MessageToMessageDecoder) ctx.pipeline().get("decompress"), ctx.pipeline().context("decompress"), bytebuf).get(0);
} catch (InvocationTargetException e) {
e.printStackTrace();
return ctx.alloc().buffer();
}
}
public static ByteBuf compress(ChannelHandlerContext ctx, ByteBuf bytebuf) {
try {
return callEncode((MessageToByteEncoder) ctx.pipeline().get("compress"), ctx.pipeline().context("compress"), bytebuf);
} catch (InvocationTargetException e) {
e.printStackTrace();
return ctx.alloc().buffer();
}
}
}
+5
View File
@@ -0,0 +1,5 @@
name: ViaVersion
main: us.myles.ViaVersion.BungeePlugin
description: ${project.description}
author: _MylesC, Matsv
version: ${project.version}
+1 -1
View File
@@ -1,6 +1,6 @@
machine:
java:
version: oraclejdk7
version: oraclejdk8
general:
artifacts:
- "target/*.jar"
+24
View File
@@ -0,0 +1,24 @@
<?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"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>viaversion-parent</artifactId>
<groupId>us.myles</groupId>
<version>1.0.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>viaversion-common</artifactId>
<dependencies>
<!-- Snake YAML -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.18-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,117 @@
package us.myles.ViaVersion;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.platform.ViaInjector;
import us.myles.ViaVersion.api.platform.ViaPlatform;
import us.myles.ViaVersion.api.platform.ViaPlatformLoader;
import us.myles.ViaVersion.api.platform.providers.ViaProviders;
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
import us.myles.ViaVersion.commands.ViaCommandHandler;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.update.UpdateUtil;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@Getter
public class ViaManager {
private final Map<UUID, UserConnection> portedPlayers = new ConcurrentHashMap<>();
private ViaPlatform platform;
private ViaProviders providers = new ViaProviders();
@Setter
private boolean debug = false;
// Internals
private ViaInjector injector;
private ViaCommandHandler commandHandler;
private ViaPlatformLoader loader;
@Builder
public ViaManager(ViaPlatform platform, ViaInjector injector, ViaCommandHandler commandHandler, ViaPlatformLoader loader) {
this.platform = platform;
this.injector = injector;
this.commandHandler = commandHandler;
this.loader = loader;
}
public void init() {
if (System.getProperty("ViaVersion") != null) {
// Reload?
platform.onReload();
}
// Check for updates
if (platform.getConf().isCheckForUpdates())
UpdateUtil.sendUpdateMessage();
// Inject
try {
injector.inject();
} catch (Exception e) {
getPlatform().getLogger().severe("ViaVersion failed to inject:");
e.printStackTrace();
return;
}
// Mark as injected
System.setProperty("ViaVersion", getPlatform().getPluginVersion());
// If successful
platform.runSync(new Runnable() {
@Override
public void run() {
onServerLoaded();
}
});
}
public void onServerLoaded() {
// Load Server Protocol
try {
ProtocolRegistry.SERVER_PROTOCOL = injector.getServerProtocolVersion();
} catch (Exception e) {
getPlatform().getLogger().severe("ViaVersion failed to get the server protocol!");
e.printStackTrace();
}
// Check if there are any pipes to this version
if (ProtocolRegistry.SERVER_PROTOCOL != -1) {
getPlatform().getLogger().info("ViaVersion detected server version: " + ProtocolVersion.getProtocol(ProtocolRegistry.SERVER_PROTOCOL));
if (!ProtocolRegistry.isWorkingPipe()) {
getPlatform().getLogger().warning("ViaVersion does not have any compatible versions for this server version, please read our resource page carefully.");
}
}
// Load Listeners / Tasks
ProtocolRegistry.onServerLoaded();
// Load Platform
loader.load();
// Refresh Versions
ProtocolRegistry.refreshVersions();
}
public void destroy() {
// Uninject
getPlatform().getLogger().info("ViaVersion is disabling, if this is a reload and you experience issues consider rebooting.");
try {
injector.uninject();
} catch (Exception e) {
getPlatform().getLogger().severe("ViaVersion failed to uninject:");
e.printStackTrace();
}
}
public void addPortedClient(UserConnection info) {
portedPlayers.put(info.get(ProtocolInfo.class).getUuid(), info);
}
public void removePortedClient(UUID clientID) {
portedPlayers.remove(clientID);
}
public UserConnection getConnection(UUID playerUUID) {
return portedPlayers.get(playerUUID);
}
}
@@ -12,11 +12,9 @@ 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.packets.Direction;
import us.myles.ViaVersion.packets.State;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.util.PipelineUtil;
import java.io.IOException;
import java.util.ArrayList;
@@ -25,14 +23,16 @@ import java.util.LinkedList;
import java.util.List;
public class PacketWrapper {
public static final int PASSTHROUGH_ID = 1000;
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<>();
private final LinkedList<Pair<Type, Object>> readableObjects = new LinkedList<>();
private final List<Pair<Type, Object>> packetValues = new ArrayList<>();
public PacketWrapper(int packetID, ByteBuf inputBuffer, UserConnection userConnection) {
this.id = packetID;
@@ -176,7 +176,7 @@ public class PacketWrapper {
if (type instanceof TypeConverter) {
value = (T) ((TypeConverter) type).from(value);
} else {
System.out.println("Possible type mismatch: " + value.getClass().getName() + " -> " + type.getOutputClass());
Via.getPlatform().getLogger().warning("Possible type mismatch: " + value.getClass().getName() + " -> " + type.getOutputClass());
}
}
}
@@ -237,7 +237,7 @@ public class PacketWrapper {
if (packetValue.getKey() instanceof TypeConverter) {
value = ((TypeConverter) packetValue.getKey()).from(value);
} else {
System.out.println("Possible type mismatch: " + value.getClass().getName() + " -> " + packetValue.getKey().getOutputClass());
Via.getPlatform().getLogger().warning("Possible type mismatch: " + value.getClass().getName() + " -> " + packetValue.getKey().getOutputClass());
}
}
}
@@ -282,31 +282,58 @@ public class PacketWrapper {
* @param skipCurrentPipeline - Skip the current pipeline
* @throws Exception if it fails to write
*/
public ChannelFuture send(Class<? extends Protocol> packetProtocol, boolean skipCurrentPipeline) throws Exception {
public void send(Class<? extends Protocol> packetProtocol, boolean skipCurrentPipeline) throws Exception {
send(packetProtocol, skipCurrentPipeline, false);
}
/**
* Send this packet to the associated user.
* Be careful not to send packets twice.
* (Sends it after current)
*
* @param packetProtocol - The protocol version of the packet.
* @param skipCurrentPipeline - Skip the current pipeline
* @param currentThread - Run in the same thread
* @throws Exception if it fails to write
*/
public void send(Class<? extends Protocol> packetProtocol, boolean skipCurrentPipeline, boolean currentThread) throws Exception {
if (!isCancelled()) {
// Apply current pipeline
List<Protocol> protocols = new ArrayList<>(user().get(ProtocolInfo.class).getPipeline().pipes());
// Other way if outgoing
Collections.reverse(protocols);
int index = 0;
for (int i = 0; i < protocols.size(); i++) {
if (protocols.get(i).getClass().equals(packetProtocol)) {
index = skipCurrentPipeline ? (i + 1) : (i);
break;
}
}
// Reset reader before we start
resetReader();
// Apply other protocols
apply(Direction.OUTGOING, user().get(ProtocolInfo.class).getState(), index, protocols);
// Send
ByteBuf output = inputBuffer == null ? Unpooled.buffer() : inputBuffer.alloc().buffer();
writeToBuffer(output);
return user().sendRawPacketFuture(output);
ByteBuf output = constructPacket(packetProtocol, skipCurrentPipeline);
user().sendRawPacket(output, currentThread);
}
return user().getChannel().newFailedFuture(new Exception("Cancelled packet"));
}
/**
* Let the packet go through the protocol pipes and write it to ByteBuf
*
* @param packetProtocol - The protocol version of the packet.
* @param skipCurrentPipeline - Skip the current pipeline
* @return Packet buffer
* @throws Exception if it fails to write
*/
private ByteBuf constructPacket(Class<? extends Protocol> packetProtocol, boolean skipCurrentPipeline) throws Exception {
// Apply current pipeline
List<Protocol> protocols = new ArrayList<>(user().get(ProtocolInfo.class).getPipeline().pipes());
// Other way if outgoing
Collections.reverse(protocols);
int index = 0;
for (int i = 0; i < protocols.size(); i++) {
if (protocols.get(i).getClass().equals(packetProtocol)) {
index = skipCurrentPipeline ? (i + 1) : (i);
break;
}
}
// Reset reader before we start
resetReader();
// Apply other protocols
apply(Direction.OUTGOING, user().get(ProtocolInfo.class).getState(), index, protocols);
// Send
ByteBuf output = inputBuffer == null ? Unpooled.buffer() : inputBuffer.alloc().buffer();
writeToBuffer(output);
return output;
}
/**
@@ -332,15 +359,18 @@ public class PacketWrapper {
* @throws Exception if it fails to write
*/
public ChannelFuture sendFuture(Class<? extends Protocol> packetProtocol) throws Exception {
return send(packetProtocol, true);
if (!isCancelled()) {
ByteBuf output = constructPacket(packetProtocol, true);
return user().sendRawPacketFuture(output);
}
return user().getChannel().newFailedFuture(new Exception("Cancelled packet"));
}
/**
* Send this packet to the associated user.
* Be careful not to send packets twice.
* (Sends it after current)
* <br />
* <b>This method is no longer used, it's favoured to use send(Protocol) as it will handle the pipeline properly.</b>
* <b>This method is no longer used, it's favoured to use {@link #send(Class)} as it will handle the pipeline properly.</b>
*
* @throws Exception if it fails to write
*/
@@ -386,7 +416,7 @@ public class PacketWrapper {
* @param index The index to start from
* @param pipeline The pipeline
* @return The current packetwrapper
* @throws Exception
* @throws Exception If it fails to transform a packet, exception will be thrown
*/
public PacketWrapper apply(Direction direction, State state, int index, List<Protocol> pipeline) throws Exception {
for (int i = index; i < pipeline.size(); i++) { // Copy to prevent from removal.
@@ -437,18 +467,16 @@ public class PacketWrapper {
/**
* Send the current packet to the server.
* (Ensure the ID is suitable for the server version)
* (Ensure the ID is suitable for viaversion)
*
* @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);
user().getChannel().pipeline().context(Via.getManager().getInjector().getDecoderName()).fireChannelRead(output);
}
}
@@ -0,0 +1,45 @@
package us.myles.ViaVersion.api;
import com.google.common.base.Preconditions;
import lombok.Getter;
import us.myles.ViaVersion.ViaManager;
import us.myles.ViaVersion.api.platform.ViaPlatform;
public class Via {
@Getter
private static ViaPlatform platform;
@Getter
private static ViaManager manager;
/**
* Register the ViaManager associated with the platform.
*
* @param viaManager The ViaManager
*/
public static void init(ViaManager viaManager) {
Preconditions.checkArgument(manager == null, "ViaManager is already set");
Via.platform = viaManager.getPlatform();
Via.manager = viaManager;
}
/**
* Get the API associated with the current platform.
*
* @return API instance
*/
public static ViaAPI getAPI() {
Preconditions.checkArgument(platform != null, "ViaVersion has not loaded the Platform");
return Via.platform.getApi();
}
/**
* Get the config associated with the current platform.
*
* @return Config instance
*/
public static ViaVersionConfig getConfig() {
Preconditions.checkArgument(platform != null, "ViaVersion has not loaded the Platform");
return Via.platform.getConf();
}
}
@@ -0,0 +1,99 @@
package us.myles.ViaVersion.api;
import io.netty.buffer.ByteBuf;
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.protocol.ProtocolRegistry;
import java.util.SortedSet;
import java.util.UUID;
/**
* Represents the ViaAPI
*
* @param <T> The player type for the specific platform, for bukkit it's {@code ViaAPI<Player>}
*/
public interface ViaAPI<T> {
/**
* Get protocol number from a player
* Will also retrieve version from ProtocolSupport if it's being used.
*
* @param player Platform player object, eg. Bukkit this is Player
* @return Protocol ID, For example (47=1.8-1.8.8, 107=1.9, 108=1.9.1)
*/
int getPlayerVersion(T 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 UUID of a player
* @return True if the client is on 1.9
* @deprecated As of 0.9.9, because all players are ported use {@link #getPlayerVersion(UUID)}
*/
@Deprecated
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 Platform player object, eg. Bukkit this is Player
* @param packet The packet, you need a VarInt ID then the packet contents.
* @throws IllegalArgumentException If not on 1.9 throws IllegalArg
*/
void sendRawPacket(T 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 the supported protocol versions
* This method removes any blocked protocol versions.
*
* @return a list of protocol versions
* @see ProtocolRegistry#getSupportedVersions() for full list.
*/
SortedSet<Integer> getSupportedVersions();
}
@@ -0,0 +1,43 @@
package us.myles.ViaVersion.api;
import lombok.*;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.protocol.Protocol;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import java.util.UUID;
@Getter(AccessLevel.PROTECTED)
@Setter(AccessLevel.PROTECTED)
@RequiredArgsConstructor
public abstract class ViaListener {
private final Class<? extends Protocol> requiredPipeline;
private boolean registered = false;
/**
* Get the UserConnection from an UUID
*
* @param uuid UUID object
* @return The UserConnection
*/
protected UserConnection getUserConnection(@NonNull UUID uuid) {
return Via.getManager().getConnection(uuid);
}
/**
* Checks if the UUID is on the selected pipe
*
* @param uuid UUID Object
* @return True if on pipe
*/
protected boolean isOnPipe(UUID uuid) {
UserConnection userConnection = getUserConnection(uuid);
return userConnection != null &&
userConnection.get(ProtocolInfo.class).getPipeline().contains(requiredPipeline);
}
/**
* Register the event
*/
public abstract void register();
}
@@ -19,14 +19,14 @@ public interface ViaVersionConfig {
boolean isPreventCollision();
/**
* Get if 1.9 & 1.10 clients are shown the new effect indicator in the top-right corner
* Get if 1.9 &amp; 1.10 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 & 1.10 clients are shown the new death message on the death screen
* Get if 1.9 &amp; 1.10 clients are shown the new death message on the death screen
*
* @return true if enabled
*/
@@ -40,28 +40,35 @@ public interface ViaVersionConfig {
boolean isSuppressMetadataErrors();
/**
* Get if blocking in 1.9 & 1.10 appears as a player holding a shield
* Get if blocking in 1.9 &amp; 1.10 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 & 1.10
* Get if armor stand positions are fixed so holograms show up at the correct height in 1.9 &amp; 1.10
*
* @return true if hologram patching is enabled
*/
boolean isHologramPatch();
/**
* Get if boss bars are fixed for 1.9 & 1.10 clients
* Get if the 1.11 piston animation patch is enabled
*
* @return true if the piston patch is enabled.
*/
boolean isPistonAnimationPatch();
/**
* Get if boss bars are fixed for 1.9 &amp; 1.10 clients
*
* @return true if boss bar patching is enabled
*/
boolean isBossbarPatch();
/**
* Get if the boss bars for 1.9 & 1.10 clients are being stopped from flickering
* Get if the boss bars for 1.9 &amp; 1.10 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
@@ -108,7 +115,7 @@ public interface ViaVersionConfig {
/**
* Get the kick message sent if the user hits the max packets per second.
*
* @return Kick message, with colour codes using '&amp;'
* @return Kick message, with colour codes using '&amp;amp;'
*/
String getMaxPPSKickMessage();
@@ -136,7 +143,7 @@ public interface ViaVersionConfig {
/**
* Get the kick message sent if the user goes over the warnings in the interval
*
* @return Kick message, with colour codes using '&amp;'
* @return Kick message, with colour codes using '&amp;amp;'
*/
String getMaxWarningsKickMessage();
@@ -209,4 +216,12 @@ public interface ViaVersionConfig {
* @return Disconnect message
*/
String getBlockedDisconnectMsg();
/**
* Get the message sent to players being kicked on reload.
* Players are kicked to stop the server crashing
*
* @return Disconnect message
*/
String getReloadDisconnectMsg();
}
@@ -1,17 +1,17 @@
package us.myles.ViaVersion.api.boss;
import org.bukkit.entity.Player;
import us.myles.ViaVersion.api.Via;
import java.util.Set;
import java.util.UUID;
public interface BossBar {
public abstract class BossBar<T> {
/**
* Get the current title
*
* @return the title
*/
String getTitle();
public abstract String getTitle();
/**
* Change the title
@@ -19,14 +19,14 @@ public interface BossBar {
* @param title Title can be in either JSON or just text
* @return The BossBar object
*/
BossBar setTitle(String title);
public abstract BossBar setTitle(String title);
/**
* Get the health
*
* @return float between 0F - 1F
*/
float getHealth();
public abstract float getHealth();
/**
* Change the health
@@ -34,14 +34,14 @@ public interface BossBar {
* @param health this float has to be between 0F - 1F
* @return The BossBar object
*/
BossBar setHealth(float health);
public abstract BossBar setHealth(float health);
/**
* Get the bossbar color
*
* @return The colour
*/
BossColor getColor();
public abstract BossColor getColor();
/**
* Yay colors!
@@ -49,14 +49,14 @@ public interface BossBar {
* @param color Whatever color you want!
* @return The BossBar object
*/
BossBar setColor(BossColor color);
public abstract BossBar setColor(BossColor color);
/**
* Get the bosbar style
*
* @return BossStyle
*/
BossStyle getStyle();
public abstract BossStyle getStyle();
/**
* Change the bosbar style
@@ -64,15 +64,19 @@ public interface BossBar {
* @param style BossStyle
* @return The BossBar object
*/
BossBar setStyle(BossStyle style);
public abstract BossBar setStyle(BossStyle style);
/**
* Show the bossbar to a player.
*
* @param player The player
* @return The BossBar object
* @deprecated Deprecated use UUID's instead of Player objects {@link #addPlayer(UUID)}
*/
BossBar addPlayer(Player player);
@Deprecated
public BossBar addPlayer(T player) {
throw new UnsupportedOperationException("This method is not implemented for the platform " + Via.getPlatform().getPlatformName());
}
/**
* Show the bossbar to a player (uuid)
@@ -80,23 +84,39 @@ public interface BossBar {
* @param player uuid of the player
* @return The BossBar object
*/
BossBar addPlayer(UUID player);
public abstract BossBar addPlayer(UUID player);
/**
* add multiple players
*
* @param players list of players
* @return The BossBar object
* @deprecated Deprecated use UUID's instead of Player objects {@link #addPlayer(UUID)}
*/
BossBar addPlayers(Player... players);
@Deprecated
public BossBar addPlayers(T... players) {
throw new UnsupportedOperationException("This method is not implemented for the platform " + Via.getPlatform().getPlatformName());
}
/**
* Remove the bossbar from a player
*
* @param player The player
* @return The BossBar object
* @deprecated Deprecated use UUID's instead of Player objects {@link #removePlayer(UUID)}
*/
BossBar removePlayer(Player player);
@Deprecated
public BossBar removePlayer(T player) {
throw new UnsupportedOperationException("This method is not implemented for the platform " + Via.getPlatform().getPlatformName());
}
/**
* Removes the bossbar from a player
*
* @param uuid The platers YYUD
* @return The BossBar object
*/
public abstract BossBar removePlayer(UUID uuid);
/**
* Add flags
@@ -104,7 +124,7 @@ public interface BossBar {
* @param flag The flag to add
* @return The BossBar object
*/
BossBar addFlag(BossFlag flag);
public abstract BossBar addFlag(BossFlag flag);
/**
* Remove flags.
@@ -112,39 +132,39 @@ public interface BossBar {
* @param flag The flag to remove
* @return The BossBar object
*/
BossBar removeFlag(BossFlag flag);
public abstract BossBar removeFlag(BossFlag flag);
/**
* @param flag The flag to check against
* @return True if it has the flag
*/
boolean hasFlag(BossFlag flag);
public abstract boolean hasFlag(BossFlag flag);
/**
* Get players
*
* @return UUIDS from players (sorry I lied)
*/
Set<UUID> getPlayers();
public abstract Set<UUID> getPlayers();
/**
* Show the bossbar to everyone (In the getPlayer set)
*
* @return The BossBar object
*/
BossBar show();
public abstract BossBar show();
/**
* Hide the bossbar from everyone (In the getPlayer set)
*
* @return The BossBar object
*/
BossBar hide();
public abstract BossBar hide();
/**
* Is it visible?
*
* @return visibility changable with show() and hide()
*/
boolean isVisible();
public abstract boolean isVisible();
}
@@ -0,0 +1,34 @@
package us.myles.ViaVersion.api.command;
import java.util.UUID;
public interface ViaCommandSender {
/**
* Check if the sender has a permission.
*
* @param permission Permission string eg. viaversion.admin
* @return True if the sender has the permission
*/
boolean hasPermission(String permission);
/**
* Send a message to the sender
*
* @param msg The message to send
*/
void sendMessage(String msg);
/**
* Get the senders UUID.
*
* @return The senders UUID
*/
UUID getUUID();
/**
* Get the senders name.
*
* @return The senders name
*/
String getName();
}
@@ -1,6 +1,5 @@
package us.myles.ViaVersion.api.command;
import org.bukkit.command.CommandSender;
import us.myles.ViaVersion.commands.ViaCommandHandler;
import java.util.Collections;
@@ -10,14 +9,14 @@ public abstract class ViaSubCommand {
/**
* Subcommand name
*
* @return The command name
* @return The commands name
*/
public abstract String name();
/**
* subcommand description, this'll show in /viaversion list
*
* @return The command description
* @return The commands description
*/
public abstract String description();
@@ -25,7 +24,7 @@ public abstract class ViaSubCommand {
* Usage example:
* "playerversion [name]"
*
* @return The command usage
* @return The commands usage
*/
public String usage() {
return name();
@@ -34,7 +33,7 @@ public abstract class ViaSubCommand {
/**
* Permission, null for everyone
*
* @return The permission required to use the command
* @return The permission required to use the commands
*/
public String permission() {
return "viaversion.admin";
@@ -45,9 +44,9 @@ public abstract class ViaSubCommand {
*
* @param sender Command sender
* @param args Arguments
* @return command executed succesfully if false, show usage
* @return commands executed succesfully if false, show usage
*/
public abstract boolean execute(CommandSender sender, String[] args);
public abstract boolean execute(ViaCommandSender sender, String[] args);
/**
* Yay, possibility to implement tab-completion
@@ -56,7 +55,7 @@ public abstract class ViaSubCommand {
* @param args args
* @return tab complete possibilities
*/
public List<String> onTabComplete(CommandSender sender, String[] args) {
public List<String> onTabComplete(ViaCommandSender sender, String[] args) {
return Collections.emptyList();
}
@@ -67,11 +66,11 @@ public abstract class ViaSubCommand {
/**
* Send message formatted / colored
*
* @param sender command sender
* @param sender commands sender
* @param message string message
* @param args optional objects
*/
public void sendMessage(CommandSender sender, String message, Object... args) {
public void sendMessage(ViaCommandSender sender, String message, Object... args) {
ViaCommandHandler.sendMessage(sender, message, args);
}
}
@@ -1,5 +1,7 @@
package us.myles.ViaVersion.api.command;
import java.util.List;
public interface ViaVersionCommand {
/**
* Register your own subcommand inside ViaVersion
@@ -24,4 +26,22 @@ public interface ViaVersionCommand {
* @return ViaSubCommand instance
*/
ViaSubCommand getSubCommand(String name);
/**
* Executed when the Command sender executes the commands
*
* @param sender Sender object
* @param args arguments provided
* @return was successful
*/
boolean onCommand(ViaCommandSender sender, String[] args);
/**
* Executed when the Command sender tab-completes
*
* @param sender Sender object
* @param args arguments provided
* @return was successful
*/
List<String> onTabComplete(ViaCommandSender sender, String[] args);
}
@@ -0,0 +1,31 @@
package us.myles.ViaVersion.api.configuration;
import java.util.Map;
public interface ConfigurationProvider {
/**
* Sets the specified path to the given value.
*
* @param path Path of the object to set.
* @param value New value to set the path to
*/
void set(String path, Object value);
/**
* Saves the config
*/
void saveConfig();
/**
* Reloads the config
*/
void reloadConfig();
/**
* Get all the configuration values
*
* @return Map with key-values
*/
Map<String, Object> getValues();
}
@@ -5,9 +5,9 @@ import io.netty.channel.ChannelFuture;
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 net.md_5.bungee.api.ChatColor;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.ViaVersionConfig;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import java.util.Map;
@@ -66,6 +66,14 @@ public class UserConnection {
storedObjects.put(object.getClass(), object);
}
/**
* Clear all the stored objects
* Used for bungee when switching servers.
*/
public void clearStoredObjects() {
storedObjects.clear();
}
/**
* Send a raw packet to the player
*
@@ -73,7 +81,7 @@ public class UserConnection {
* @param currentThread Should it run in the same thread
*/
public void sendRawPacket(final ByteBuf packet, boolean currentThread) {
final ChannelHandler handler = channel.pipeline().get("encoder");
final ChannelHandler handler = channel.pipeline().get(Via.getManager().getInjector().getEncoderName());
if (currentThread) {
channel.pipeline().context(handler).writeAndFlush(packet);
} else {
@@ -93,7 +101,7 @@ public class UserConnection {
* @return ChannelFuture of the packet being sent
*/
public ChannelFuture sendRawPacketFuture(final ByteBuf packet) {
final ChannelHandler handler = channel.pipeline().get("encoder");
final ChannelHandler handler = channel.pipeline().get(Via.getManager().getInjector().getEncoderName());
return channel.pipeline().context(handler).writeAndFlush(packet);
}
@@ -134,6 +142,37 @@ public class UserConnection {
return false;
}
public boolean handlePPS() {
ViaVersionConfig conf = Via.getConfig();
// Max PPS Checker
if (conf.getMaxPPS() > 0) {
if (getPacketsPerSecond() >= conf.getMaxPPS()) {
disconnect(conf.getMaxPPSKickMessage().replace("%pps", ((Long) getPacketsPerSecond()).intValue() + ""));
return true; // don't send current packet
}
}
// Tracking PPS Checker
if (conf.getMaxWarnings() > 0 && conf.getTrackingPeriod() > 0) {
if (getSecondsObserved() > conf.getTrackingPeriod()) {
// Reset
setWarnings(0);
setSecondsObserved(1);
} else {
setSecondsObserved(getSecondsObserved() + 1);
if (getPacketsPerSecond() >= conf.getWarningPPS()) {
setWarnings(getWarnings() + 1);
}
if (getWarnings() >= conf.getMaxWarnings()) {
disconnect(conf.getMaxWarningsKickMessage().replace("%pps", ((Long) getPacketsPerSecond()).intValue() + ""));
return true; // don't send current packet
}
}
}
return false;
}
/**
* Disconnect a connection
*
@@ -145,18 +184,15 @@ public class UserConnection {
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));
Via.getPlatform().runSync(new Runnable() {
@Override
public void run() {
if (!Via.getPlatform().kickPlayer(uuid, ChatColor.translateAlternateColorCodes('&', reason))) {
getChannel().close(); // =)
}
});
return;
}
}
});
}
getChannel().close(); // =)
}
}
@@ -0,0 +1,187 @@
package us.myles.ViaVersion.api.entities;
import com.google.common.base.Optional;
import lombok.AllArgsConstructor;
import lombok.Getter;
import us.myles.ViaVersion.api.Via;
// 1.10 Entity / Object ids
public class Entity1_10Types {
public static EntityType getTypeFromId(int typeID, boolean isObject) {
Optional<EntityType> type;
if (isObject)
type = ObjectTypes.getPCEntity(typeID);
else
type = EntityType.findById(typeID);
if (!type.isPresent()) {
Via.getPlatform().getLogger().severe("Could not find type id " + typeID + " isObject=" + isObject);
return EntityType.ENTITY; // Fall back to the basic ENTITY
}
return type.get();
}
@AllArgsConstructor
@Getter
public enum EntityType {
ENTITY(-1),
DROPPED_ITEM(1, EntityType.ENTITY),
EXPERIENCE_ORB(2, EntityType.ENTITY),
LEASH_HITCH(8, EntityType.ENTITY), // Actually entity hanging but it doesn't make a lot of difference for metadata
PAINTING(9, EntityType.ENTITY), // Actually entity hanging but it doesn't make a lot of difference for metadata
ARROW(10, EntityType.ENTITY),
SNOWBALL(11, EntityType.ENTITY), // Actually EntityProjectile
FIREBALL(12, EntityType.ENTITY),
SMALL_FIREBALL(13, EntityType.ENTITY),
ENDER_PEARL(14, EntityType.ENTITY), // Actually EntityProjectile
ENDER_SIGNAL(15, EntityType.ENTITY),
THROWN_EXP_BOTTLE(17, EntityType.ENTITY),
ITEM_FRAME(18, EntityType.ENTITY), // Actually EntityHanging
WITHER_SKULL(19, EntityType.ENTITY),
PRIMED_TNT(20, EntityType.ENTITY),
FALLING_BLOCK(21, EntityType.ENTITY),
FIREWORK(22, EntityType.ENTITY),
TIPPED_ARROW(23, EntityType.ARROW),
SPECTRAL_ARROW(24, EntityType.ARROW),
SHULKER_BULLET(25, EntityType.ENTITY),
DRAGON_FIREBALL(26, EntityType.FIREBALL),
ENTITY_LIVING(-1, ENTITY),
ENTITY_INSENTIENT(-1, ENTITY_LIVING),
ENTITY_AGEABLE(-1, ENTITY_INSENTIENT),
ENTITY_TAMEABLE_ANIMAL(-1, ENTITY_AGEABLE),
ENTITY_HUMAN(-1, ENTITY_LIVING),
ARMOR_STAND(30, EntityType.ENTITY_LIVING),
// Vehicles
MINECART_ABSTRACT(-1, ENTITY),
MINECART_COMMAND(40, MINECART_ABSTRACT),
BOAT(41, ENTITY),
MINECART_RIDEABLE(42, MINECART_ABSTRACT),
MINECART_CHEST(43, MINECART_ABSTRACT),
MINECART_FURNACE(44, MINECART_ABSTRACT),
MINECART_TNT(45, MINECART_ABSTRACT),
MINECART_HOPPER(46, MINECART_ABSTRACT),
MINECART_MOB_SPAWNER(47, MINECART_ABSTRACT),
CREEPER(50, ENTITY_INSENTIENT),
SKELETON(51, ENTITY_INSENTIENT),
SPIDER(52, ENTITY_INSENTIENT),
GIANT(53, ENTITY_INSENTIENT),
ZOMBIE(54, ENTITY_INSENTIENT),
SLIME(55, ENTITY_INSENTIENT),
GHAST(56, ENTITY_INSENTIENT),
PIG_ZOMBIE(57, ZOMBIE),
ENDERMAN(58, ENTITY_INSENTIENT),
CAVE_SPIDER(59, SPIDER),
SILVERFISH(60, ENTITY_INSENTIENT),
BLAZE(61, ENTITY_INSENTIENT),
MAGMA_CUBE(62, SLIME),
ENDER_DRAGON(63, ENTITY_INSENTIENT),
WITHER(64, ENTITY_INSENTIENT),
BAT(65, ENTITY_INSENTIENT),
WITCH(66, ENTITY_INSENTIENT),
ENDERMITE(67, ENTITY_INSENTIENT),
GUARDIAN(68, ENTITY_INSENTIENT),
IRON_GOLEM(99, ENTITY_INSENTIENT), // moved up to avoid illegal forward references
SHULKER(69, EntityType.IRON_GOLEM),
PIG(90, ENTITY_AGEABLE),
SHEEP(91, ENTITY_AGEABLE),
COW(92, ENTITY_AGEABLE),
CHICKEN(93, ENTITY_AGEABLE),
SQUID(94, ENTITY_INSENTIENT),
WOLF(95, ENTITY_TAMEABLE_ANIMAL),
MUSHROOM_COW(96, COW),
SNOWMAN(97, EntityType.IRON_GOLEM),
OCELOT(98, ENTITY_TAMEABLE_ANIMAL),
HORSE(100, ENTITY_AGEABLE),
RABBIT(101, ENTITY_AGEABLE),
POLAR_BEAR(102, ENTITY_AGEABLE),
VILLAGER(120, ENTITY_AGEABLE),
ENDER_CRYSTAL(200, ENTITY),
SPLASH_POTION(-1, ENTITY),
LINGERING_POTION(-1, SPLASH_POTION),
AREA_EFFECT_CLOUD(-1, ENTITY),
EGG(-1, ENTITY),
FISHING_HOOK(-1, ENTITY),
LIGHTNING(-1, ENTITY),
WEATHER(-1, ENTITY),
PLAYER(-1, ENTITY_HUMAN),
COMPLEX_PART(-1, ENTITY);
private final int id;
private final EntityType parent;
EntityType(int id) {
this.id = id;
this.parent = null;
}
public static Optional<EntityType> findById(int id) {
if (id == -1) // Check if this is called
return Optional.absent();
for (EntityType ent : EntityType.values())
if (ent.getId() == id)
return Optional.of(ent);
return Optional.absent();
}
}
@AllArgsConstructor
@Getter
public enum ObjectTypes {
BOAT(1, EntityType.BOAT),
ITEM(2, EntityType.DROPPED_ITEM),
AREA_EFFECT_CLOUD(3, EntityType.AREA_EFFECT_CLOUD),
MINECART(10, EntityType.MINECART_ABSTRACT),
TNT_PRIMED(50, EntityType.PRIMED_TNT),
ENDER_CRYSTAL(51, EntityType.ENDER_CRYSTAL),
TIPPED_ARROW(60, EntityType.TIPPED_ARROW),
SNOWBALL(61, EntityType.SNOWBALL),
EGG(62, EntityType.EGG),
FIREBALL(63, EntityType.FIREBALL),
SMALL_FIREBALL(64, EntityType.SMALL_FIREBALL),
ENDER_PEARL(65, EntityType.ENDER_PEARL),
WITHER_SKULL(66, EntityType.WITHER_SKULL),
SHULKER_BULLET(67, EntityType.SHULKER_BULLET),
FALLING_BLOCK(70, EntityType.FALLING_BLOCK),
ITEM_FRAME(71, EntityType.ITEM_FRAME),
ENDER_SIGNAL(72, EntityType.ENDER_SIGNAL),
POTION(73, EntityType.SPLASH_POTION),
THROWN_EXP_BOTTLE(75, EntityType.THROWN_EXP_BOTTLE),
FIREWORK(76, EntityType.FIREWORK),
LEASH(77, EntityType.LEASH_HITCH),
ARMOR_STAND(78, EntityType.ARMOR_STAND),
FISHIHNG_HOOK(90, EntityType.FISHING_HOOK),
SPECTRAL_ARROW(91, EntityType.SPECTRAL_ARROW),
DRAGON_FIREBALL(93, EntityType.DRAGON_FIREBALL);
private final int id;
private final EntityType type;
public static Optional<ObjectTypes> findById(int id) {
if (id == -1)
return Optional.absent();
for (ObjectTypes ent : ObjectTypes.values())
if (ent.getId() == id)
return Optional.of(ent);
return Optional.absent();
}
public static Optional<EntityType> getPCEntity(int id) {
Optional<ObjectTypes> output = findById(id);
if (!output.isPresent())
return Optional.absent();
return Optional.of(output.get().getType());
}
}
}
@@ -0,0 +1,241 @@
package us.myles.ViaVersion.api.entities;
import com.google.common.base.Optional;
import lombok.AllArgsConstructor;
import lombok.Getter;
import us.myles.ViaVersion.api.Via;
// 1.11 Entity / Object ids TODO maybe in the future instead of copying it, some api.
public class Entity1_11Types {
public static EntityType getTypeFromId(int typeID, boolean isObject) {
Optional<EntityType> type;
if (isObject)
type = ObjectTypes.getPCEntity(typeID);
else
type = EntityType.findById(typeID);
if (!type.isPresent()) {
Via.getPlatform().getLogger().severe("Could not find type id " + typeID + " isObject=" + isObject);
return EntityType.ENTITY; // Fall back to the basic ENTITY
}
return type.get();
}
@AllArgsConstructor
@Getter
public enum EntityType {
ENTITY(-1),
DROPPED_ITEM(1, ENTITY),
EXPERIENCE_ORB(2, ENTITY),
LEASH_HITCH(8, ENTITY), // Actually entity hanging but it doesn't make a lot of difference for metadata
PAINTING(9, ENTITY), // Actually entity hanging but it doesn't make a lot of difference for metadata
ARROW(10, ENTITY),
SNOWBALL(11, ENTITY), // Actually EntityProjectile
FIREBALL(12, ENTITY),
SMALL_FIREBALL(13, ENTITY),
ENDER_PEARL(14, ENTITY), // Actually EntityProjectile
ENDER_SIGNAL(15, ENTITY),
THROWN_EXP_BOTTLE(17, ENTITY),
ITEM_FRAME(18, ENTITY), // Actually EntityHanging
WITHER_SKULL(19, ENTITY),
PRIMED_TNT(20, ENTITY),
FALLING_BLOCK(21, ENTITY),
FIREWORK(22, ENTITY),
TIPPED_ARROW(23, ARROW),
SPECTRAL_ARROW(24, ARROW),
SHULKER_BULLET(25, ENTITY),
DRAGON_FIREBALL(26, FIREBALL),
EVOCATION_FANGS(33, ENTITY),
ENTITY_LIVING(-1, ENTITY),
ENTITY_INSENTIENT(-1, ENTITY_LIVING),
ENTITY_AGEABLE(-1, ENTITY_INSENTIENT),
ENTITY_TAMEABLE_ANIMAL(-1, ENTITY_AGEABLE),
ENTITY_HUMAN(-1, ENTITY_LIVING),
ARMOR_STAND(30, ENTITY_LIVING),
EVOCATION_ILLAGER(34, ENTITY_INSENTIENT),
VEX(35, ENTITY_INSENTIENT),
VINDICATION_ILLAGER(36, ENTITY_INSENTIENT),
// Vehicles
MINECART_ABSTRACT(-1, ENTITY),
MINECART_COMMAND(40, MINECART_ABSTRACT),
BOAT(41, ENTITY),
MINECART_RIDEABLE(42, MINECART_ABSTRACT),
MINECART_CHEST(43, MINECART_ABSTRACT),
MINECART_FURNACE(44, MINECART_ABSTRACT),
MINECART_TNT(45, MINECART_ABSTRACT),
MINECART_HOPPER(46, MINECART_ABSTRACT),
MINECART_MOB_SPAWNER(47, MINECART_ABSTRACT),
CREEPER(50, ENTITY_INSENTIENT),
ABSTRACT_SKELETON(-1, ENTITY_INSENTIENT),
SKELETON(51, ABSTRACT_SKELETON),
WITHER_SKELETON(5, ABSTRACT_SKELETON),
STRAY(6, ABSTRACT_SKELETON),
SPIDER(52, ENTITY_INSENTIENT),
GIANT(53, ENTITY_INSENTIENT),
ZOMBIE(54, ENTITY_INSENTIENT),
HUSK(23, ZOMBIE),
ZOMBIE_VILLAGER(27, ZOMBIE),
SLIME(55, ENTITY_INSENTIENT),
GHAST(56, ENTITY_INSENTIENT),
PIG_ZOMBIE(57, ZOMBIE),
ENDERMAN(58, ENTITY_INSENTIENT),
CAVE_SPIDER(59, SPIDER),
SILVERFISH(60, ENTITY_INSENTIENT),
BLAZE(61, ENTITY_INSENTIENT),
MAGMA_CUBE(62, SLIME),
ENDER_DRAGON(63, ENTITY_INSENTIENT),
WITHER(64, ENTITY_INSENTIENT),
BAT(65, ENTITY_INSENTIENT),
WITCH(66, ENTITY_INSENTIENT),
ENDERMITE(67, ENTITY_INSENTIENT),
GUARDIAN(68, ENTITY_INSENTIENT),
ELDER_GUARDIAN(4, EntityType.GUARDIAN), // Moved down to avoid illegal forward reference
IRON_GOLEM(99, ENTITY_INSENTIENT), // moved up to avoid illegal forward references
SHULKER(69, EntityType.IRON_GOLEM),
PIG(90, ENTITY_AGEABLE),
SHEEP(91, ENTITY_AGEABLE),
COW(92, ENTITY_AGEABLE),
CHICKEN(93, ENTITY_AGEABLE),
SQUID(94, ENTITY_INSENTIENT),
WOLF(95, ENTITY_TAMEABLE_ANIMAL),
MUSHROOM_COW(96, COW),
SNOWMAN(97, EntityType.IRON_GOLEM),
OCELOT(98, ENTITY_TAMEABLE_ANIMAL),
ABSTRACT_HORSE(-1, ENTITY_AGEABLE),
HORSE(100, ABSTRACT_HORSE),
SKELETON_HORSE(28, ABSTRACT_HORSE),
ZOMBIE_HORSE(29, ABSTRACT_HORSE),
CHESTED_HORSE(-1, ABSTRACT_HORSE),
DONKEY(31, CHESTED_HORSE),
MULE(32, CHESTED_HORSE),
LIAMA(103, CHESTED_HORSE),
RABBIT(101, ENTITY_AGEABLE),
POLAR_BEAR(102, ENTITY_AGEABLE),
VILLAGER(120, ENTITY_AGEABLE),
ENDER_CRYSTAL(200, ENTITY),
SPLASH_POTION(-1, ENTITY),
LINGERING_POTION(-1, SPLASH_POTION),
AREA_EFFECT_CLOUD(-1, ENTITY),
EGG(-1, ENTITY),
FISHING_HOOK(-1, ENTITY),
LIGHTNING(-1, ENTITY),
WEATHER(-1, ENTITY),
PLAYER(-1, ENTITY_HUMAN),
COMPLEX_PART(-1, ENTITY),
LIAMA_SPIT(-1, ENTITY);
private final int id;
private final EntityType parent;
EntityType(int id) {
this.id = id;
this.parent = null;
}
public static Optional<EntityType> findById(int id) {
if (id == -1) // Check if this is called
return Optional.absent();
for (EntityType ent : EntityType.values())
if (ent.getId() == id)
return Optional.of(ent);
return Optional.absent();
}
public boolean is(EntityType... types) {
for (EntityType type : types)
if (is(type))
return true;
return false;
}
public boolean is(EntityType type) {
return this == type;
}
public boolean isOrHasParent(EntityType type) {
EntityType parent = this;
do {
if (parent.equals(type))
return true;
parent = parent.getParent();
} while (parent != null);
return false;
}
}
@AllArgsConstructor
@Getter
public enum ObjectTypes {
BOAT(1, EntityType.BOAT),
ITEM(2, EntityType.DROPPED_ITEM),
AREA_EFFECT_CLOUD(3, EntityType.AREA_EFFECT_CLOUD),
MINECART(10, EntityType.MINECART_ABSTRACT),
TNT_PRIMED(50, EntityType.PRIMED_TNT),
ENDER_CRYSTAL(51, EntityType.ENDER_CRYSTAL),
TIPPED_ARROW(60, EntityType.TIPPED_ARROW),
SNOWBALL(61, EntityType.SNOWBALL),
EGG(62, EntityType.EGG),
FIREBALL(63, EntityType.FIREBALL),
SMALL_FIREBALL(64, EntityType.SMALL_FIREBALL),
ENDER_PEARL(65, EntityType.ENDER_PEARL),
WITHER_SKULL(66, EntityType.WITHER_SKULL),
SHULKER_BULLET(67, EntityType.SHULKER_BULLET),
LIAMA_SPIT(68, EntityType.LIAMA_SPIT),
FALLING_BLOCK(70, EntityType.FALLING_BLOCK),
ITEM_FRAME(71, EntityType.ITEM_FRAME),
ENDER_SIGNAL(72, EntityType.ENDER_SIGNAL),
POTION(73, EntityType.SPLASH_POTION),
THROWN_EXP_BOTTLE(75, EntityType.THROWN_EXP_BOTTLE),
FIREWORK(76, EntityType.FIREWORK),
LEASH(77, EntityType.LEASH_HITCH),
ARMOR_STAND(78, EntityType.ARMOR_STAND),
EVOCATION_FANGS(39, EntityType.EVOCATION_FANGS),
FISHIHNG_HOOK(90, EntityType.FISHING_HOOK),
SPECTRAL_ARROW(91, EntityType.SPECTRAL_ARROW),
DRAGON_FIREBALL(93, EntityType.DRAGON_FIREBALL);
private final int id;
private final EntityType type;
public static Optional<ObjectTypes> findById(int id) {
if (id == -1)
return Optional.absent();
for (ObjectTypes ent : ObjectTypes.values())
if (ent.getId() == id)
return Optional.of(ent);
return Optional.absent();
}
public static Optional<EntityType> getPCEntity(int id) {
Optional<ObjectTypes> output = findById(id);
if (!output.isPresent())
return Optional.absent();
return Optional.of(output.get().getType());
}
}
}
@@ -0,0 +1,32 @@
package us.myles.ViaVersion.api.minecraft;
import java.util.HashMap;
import java.util.Map;
public enum Environment {
NORMAL(0),
NETHER(-1),
END(1);
private final int id;
private static final Map<Integer, Environment> lookup = new HashMap<>();
static {
for (Environment env : values()) {
lookup.put(env.getId(), env);
}
}
Environment(int id) {
this.id = id;
}
public int getId() {
return id;
}
public static Environment getEnvironmentById(int id) {
return lookup.get(id);
}
}
@@ -0,0 +1,12 @@
package us.myles.ViaVersion.api.minecraft;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class EulerAngle {
private float x;
private float y;
private float z;
}
@@ -0,0 +1,12 @@
package us.myles.ViaVersion.api.minecraft;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class Vector {
private int blockX;
private int blockY;
private int blockZ;
}
@@ -1,5 +1,9 @@
package us.myles.ViaVersion.api.minecraft.chunks;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
import java.util.List;
public interface Chunk {
int getX();
@@ -14,4 +18,6 @@ public interface Chunk {
byte[] getBiomeData();
int getBitmask();
List<CompoundTag> getBlockEntities();
}
@@ -0,0 +1,16 @@
package us.myles.ViaVersion.api.minecraft.item;
import lombok.*;
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;
}
@@ -0,0 +1,20 @@
package us.myles.ViaVersion.api.minecraft.metadata;
import us.myles.ViaVersion.api.type.Type;
public interface MetaType {
/**
* Get the write/read type
*
* @return Type instance
*/
Type getType();
/**
* Get type id from the specific MetaDataType
*
* @return Type id as an integer
*/
int getTypeID();
}
@@ -0,0 +1,12 @@
package us.myles.ViaVersion.api.minecraft.metadata;
import lombok.AllArgsConstructor;
import lombok.Data;
@AllArgsConstructor
@Data
public class Metadata {
private int id;
private MetaType metaType;
private Object value;
}
@@ -1,12 +1,13 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8.metadata;
package us.myles.ViaVersion.api.minecraft.metadata.types;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import us.myles.ViaVersion.api.minecraft.metadata.MetaType;
import us.myles.ViaVersion.api.type.Type;
@RequiredArgsConstructor
@Getter
public enum MetadataTypes {
public enum MetaType1_8 implements MetaType {
Byte(0, Type.BYTE),
Short(1, Type.SHORT),
Int(2, Type.INT),
@@ -20,7 +21,7 @@ public enum MetadataTypes {
private final int typeID;
private final Type type;
public static MetadataTypes byId(int id) {
public static MetaType1_8 byId(int id) {
return values()[id];
}
}
@@ -1,12 +1,13 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8.metadata;
package us.myles.ViaVersion.api.minecraft.metadata.types;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import us.myles.ViaVersion.api.minecraft.metadata.MetaType;
import us.myles.ViaVersion.api.type.Type;
@RequiredArgsConstructor
@Getter
public enum NewType {
public enum MetaType1_9 implements MetaType {
Byte(0, Type.BYTE),
VarInt(1, Type.VAR_INT),
Float(2, Type.FLOAT),
@@ -25,7 +26,7 @@ public enum NewType {
private final int typeID;
private final Type type;
public static NewType byId(int id) {
public static MetaType1_9 byId(int id) {
return values()[id];
}
@@ -0,0 +1,11 @@
package us.myles.ViaVersion.api.platform;
public interface TaskId {
/**
* Returns the actual object represented by this TaskId
* Null if task cannot be cancelled.
*
* @return Platform based Object (don't assume)
*/
Object getObject();
}
@@ -0,0 +1,39 @@
package us.myles.ViaVersion.api.platform;
public interface ViaInjector {
/**
* Inject into the current Platform
*
* @throws Exception If there is an error with injecting
*/
void inject() throws Exception;
/**
* Uninject into the current Platform
*
* @throws Exception If there is an error with uninjecting
*/
void uninject() throws Exception;
/**
* Get the server protocol version
*
* @return The server protocol integer
* @throws Exception If there is an error with getting this info, eg. not binded.
*/
int getServerProtocolVersion() throws Exception;
/**
* Get the name of the encoder for then netty pipeline for this platform.
*
* @return The name
*/
String getEncoderName();
/**
* Get the name of the decoder for then netty pipeline for this platform.
*
* @return The name
*/
String getDecoderName();
}
@@ -0,0 +1,143 @@
package us.myles.ViaVersion.api.platform;
import com.google.gson.JsonObject;
import us.myles.ViaVersion.api.ViaAPI;
import us.myles.ViaVersion.api.ViaVersionConfig;
import us.myles.ViaVersion.api.command.ViaCommandSender;
import us.myles.ViaVersion.api.configuration.ConfigurationProvider;
import java.util.UUID;
import java.util.logging.Logger;
/**
* ViaPlatform represents a platform ViaVersion runs on
*
* @param <T> - The player type for the platform, used for API related methods
*/
public interface ViaPlatform<T> {
/**
* Get the logger for this platform
*
* @return Java Logger (may be a wrapper)
*/
Logger getLogger();
/**
* Get the platform name
*
* @return Platform Name (simply its name)
*/
String getPlatformName();
/**
* Get the platform version
*
* @return Platforn version
*/
String getPlatformVersion();
/**
* Get the plugin version
*
* @return Plugin version as a semver string
*/
String getPluginVersion();
/**
* Run a task Async
*
* @param runnable The task to run
* @return The Task ID
*/
TaskId runAsync(Runnable runnable);
/**
* Run a task Sync
*
* @param runnable The task to run
* @return The Task ID
*/
TaskId runSync(Runnable runnable);
/**
* Run a task at a repeating interval.
* Initial interval is the same as repeat.
*
* @param runnable The task to run
* @param ticks The interval to run it at
* @return The Task ID
*/
TaskId runRepeatingSync(Runnable runnable, Long ticks);
/**
* Cancel a task
*
* @param taskId The task ID to cancel
*/
void cancelTask(TaskId taskId);
/**
* Get the online players
*
* @return Array of ViaCommandSender
*/
ViaCommandSender[] getOnlinePlayers();
/**
* Send a message to a player
*
* @param uuid The player's UUID
* @param message The message to send
*/
void sendMessage(UUID uuid, String message);
/**
* Kick a player for a reason
*
* @param uuid The player's UUID
* @param message The message to kick them with
* @return True if it was successful
*/
boolean kickPlayer(UUID uuid, String message);
/**
* Check if the plugin is enabled.
*
* @return True if it is enabled
*/
boolean isPluginEnabled();
/**
* Get the API for this platform
*
* @return The API for the platform
*/
ViaAPI<T> getApi();
/**
* Get the config API for this platform
*
* @return The config API
*/
ViaVersionConfig getConf();
/**
* Get the backend configuration provider for this platform.
* (On some platforms this returns the same as getConf())
*
* @return The configuration provider
*/
ConfigurationProvider getConfigurationProvider();
/**
* Called when a reload happens
*/
void onReload();
/**
* Get the JSON data required for /viaversion dump
*
* @return The json data
*/
JsonObject getDump();
}
@@ -0,0 +1,8 @@
package us.myles.ViaVersion.api.platform;
public interface ViaPlatformLoader {
/**
* Initialise the loading for a platform, eg. registering listeners / providers / events etc.
*/
void load();
}
@@ -0,0 +1,4 @@
package us.myles.ViaVersion.api.platform.providers;
public interface Provider {
}
@@ -0,0 +1,37 @@
package us.myles.ViaVersion.api.platform.providers;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ViaProviders {
private final Map<Class<? extends Provider>, Provider> providers = new HashMap<>();
private final List<Class<? extends Provider>> lonelyProviders = new ArrayList<>();
public void require(Class<? extends Provider> provider) {
lonelyProviders.add(provider);
}
public <T extends Provider> void register(Class<T> provider, T value) {
providers.put(provider, value);
}
public <T extends Provider> void use(Class<T> provider, T value) {
if (lonelyProviders.contains(provider)) {
lonelyProviders.remove(provider);
}
providers.put(provider, value);
}
public <T extends Provider> T get(Class<T> provider) {
if (providers.containsKey(provider)) {
return (T) providers.get(provider);
} else {
if (lonelyProviders.contains(provider)) {
throw new IllegalStateException("There was no provider for " + provider + ", one is required!");
}
return null;
}
}
}
Loaded 100 of 294 files, more files were not shown because too many files have changed in this diff. Show more