Compare commits

..
195 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
Matsv d815c0e682 Merge branch 'master' of https://github.com/MylesIsCool/ViaVersion into 1.11-DEV 2016-08-24 16:46:47 +02: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 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
288 changed files with 10126 additions and 3446 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?
+7 -3
View File
@@ -1,12 +1,16 @@
# ViaVersion 0.9.9
# 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://buzz.spi.gt/iris/?channels=viaversion) on irc.spi.gt for Support.
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/
+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,143 +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)
* @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 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.
*
* @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();
}
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,4 +1,4 @@
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.HumanEntity;
@@ -12,16 +12,18 @@ 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.ViaListener;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.type.Type;
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;
public class ArmorListener extends ViaListener {
public class ArmorListener extends ViaBukkitListener {
private static final UUID ARMOR_ATTRIBUTE = UUID.fromString("2AD3F246-FEE1-4E67-B886-69FD380BB150");
@@ -33,7 +35,11 @@ public class ArmorListener extends ViaListener {
// Ensure that the player is on our pipe
if (!isOnPipe(player)) return;
int armor = ArmorType.calculateArmorPoints(player.getInventory().getArmorContents());
int armor = 0;
for (ItemStack stack : player.getInventory().getArmorContents()) {
armor += ArmorType.findById(stack.getTypeId()).getArmorPoints();
}
PacketWrapper wrapper = new PacketWrapper(0x4B, null, getUserConnection(player));
try {
@@ -58,7 +64,7 @@ public class ArmorListener extends ViaListener {
if (human instanceof Player && e.getInventory() instanceof CraftingInventory) {
final Player player = (Player) human;
if (e.getCurrentItem() != null) {
if (ArmorType.isArmor(e.getCurrentItem().getType())) {
if (ArmorType.isArmor(e.getCurrentItem().getTypeId())) {
sendDelayedArmorUpdate(player);
return;
}
@@ -102,7 +108,7 @@ public class ArmorListener extends ViaListener {
public void sendDelayedArmorUpdate(final Player player) {
if (!isOnPipe(player)) return; // Don't start a task if the player is not on the pipe
Bukkit.getScheduler().scheduleSyncDelayedTask(getPlugin(), new Runnable() {
Via.getPlatform().runSync(new Runnable() {
@Override
public void run() {
sendArmorUpdate(player);
@@ -1,16 +1,16 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8.listeners;
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.ViaListener;
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 ViaListener {
public class BlockListener extends ViaBukkitListener {
public BlockListener(ViaVersionPlugin plugin) {
super(plugin, Protocol1_9TO1_8.class);
@@ -1,6 +1,5 @@
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.World;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -8,12 +7,13 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.PlayerDeathEvent;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.ViaListener;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.bukkit.listeners.ViaBukkitListener;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
public class DeathListener extends ViaListener {
public class DeathListener extends ViaBukkitListener {
public DeathListener(ViaVersionPlugin plugin) {
super(plugin, Protocol1_9TO1_8.class);
}
@@ -34,7 +34,7 @@ public class DeathListener extends ViaListener {
}
private void sendPacket(final Player p, final String msg) {
Bukkit.getScheduler().runTask(getPlugin(), new Runnable() {
Via.getPlatform().runSync(new Runnable() {
@Override
public void run() {
PacketWrapper wrapper = new PacketWrapper(0x2C, null, getUserConnection(p));
@@ -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,4 +1,4 @@
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;
@@ -6,10 +6,10 @@ import org.bukkit.block.BlockFace;
import org.bukkit.event.EventHandler;
import org.bukkit.event.block.BlockPlaceEvent;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaListener;
import us.myles.ViaVersion.bukkit.listeners.ViaBukkitListener;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
public class PaperPatch extends ViaListener {
public class PaperPatch extends ViaBukkitListener {
public PaperPatch(ViaVersionPlugin plugin) {
super(plugin, Protocol1_9TO1_8.class);
@@ -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;
@@ -1,11 +1,12 @@
name: ViaVersion
main: us.myles.ViaVersion.ViaVersionPlugin
author: _MylesC
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]
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());
}
}
}
@@ -283,9 +283,23 @@ public class PacketWrapper {
* @throws Exception if it fails to write
*/
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()) {
ByteBuf output = constructPacket(packetProtocol, skipCurrentPipeline);
user().sendRawPacket(output);
user().sendRawPacket(output, currentThread);
}
}
@@ -356,8 +370,7 @@ public class PacketWrapper {
* 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
*/
@@ -403,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.
@@ -454,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();
@@ -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;
}
@@ -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 288 files, more files were not shown because too many files have changed in this diff. Show more