Compare commits

...
73 Commits
Author SHA1 Message Date
Matsv c095a51f7c 1.10 support and version bump 2016-06-08 16:35:06 +02:00
Matsv 5e62b7001e Merge branch 'master' of https://github.com/MylesIsCool/ViaVersion into 1.10 2016-06-08 15:35:55 +02:00
Mats 8cc4ba168a Patch EchoPet wrong metadata value (#419) 2016-06-08 11:29:08 +01:00
Matsv 264a21d092 Merge branch 'master' of https://github.com/MylesIsCool/ViaVersion into 1.10 2016-06-08 11:37:23 +02:00
Mats e2585db350 Make the main class cleaner by giving the config his own class (#418) 2016-06-07 19:18:48 +02:00
Matsv a2f7a52d31 Support for 1.10-pre2 2016-06-07 17:29:30 +02:00
Matsv d04121202d Modify the config comments to & 1.10 2016-06-07 09:11:33 +02:00
Matsv 95517ade2c Merge branch 'master' of https://github.com/MylesIsCool/ViaVersion into 1.10 2016-06-03 22:18:28 +02:00
Matsv c9441de7e4 Change from info to severe 2016-06-03 21:15:53 +02:00
Matsv dc946cb845 An amazing feature. 2016-06-03 20:49:06 +02:00
Myles 5fa30d9adb Merge branch 'master' into 1.10 2016-06-03 18:52:52 +01:00
Myles a7043424ec Support ProtocolLib + late-bind, also it now tells you the plugin to blame if it goes wrong. How nice! 2016-06-03 18:52:25 +01:00
Matsv e1b3d21732 Woops, the sounds were still broken. Now it should be fixed. no lies this time 2016-06-02 21:19:48 +02:00
Matsv 8ffc056a7e Cleanup and change class/package names from 1.9.3 2016-06-02 21:00:18 +02:00
Matsv 7c274fb03d Handle new sounds 2016-06-02 20:52:55 +02:00
Matsv 3b533b5138 Compatibility with 1.10-pre1 (number 2, git didn't push everything for some reason) 2016-06-02 18:37:05 +02:00
Matsv 5665510f7e Compatibility with 1.10-pre1 2016-06-02 18:34:04 +02:00
Matsv 47faa21ef4 Add latest build to readme & auto-build test 2016-05-27 19:44:21 +02:00
Myles 575f457830 0.8.5 SNAPSHOT 2016-05-27 18:37:34 +01:00
Matsv d5bf7909e8 Sync with master 2016-05-27 19:16:22 +02:00
Myles fdf90b7931 0.8.4 Release 2016-05-27 18:05:46 +01:00
Myles e3305e4eae Automatically buffer unknown entities, removes 2 config values and deprecate api 2016-05-27 01:00:01 +01:00
Matsv 15fe8d394e Support for 16w21b 2016-05-26 19:02:06 +02:00
Matsv 082db38c40 Merge branch 'master' of https://github.com/MylesIsCool/ViaVersion into 1.10 2016-05-26 17:03:40 +02:00
Myles be54dc41d1 Add SkinRestorer to plugin.yml unsure if this will fix anything 2016-05-26 14:27:27 +01:00
Myles 487e79c043 Fix javadocs 2016-05-26 13:54:22 +01:00
Matsv ef6390a0b8 Update version for the buildserver 2016-05-26 11:16:12 +02:00
Matsv 9d9fc65633 Support for 16w21a, how fun. A snapshot without packet changes 2016-05-25 16:44:20 +02:00
Matsv 6eac61c912 Sync with master 2016-05-24 21:17:30 +02:00
Matsv d89362a271 Sync with master 2016-05-24 21:13:28 +02:00
Matsv 0a407069fa Add Burger to sources :) 2016-05-24 21:09:04 +02:00
Myles 661fdb1127 Bump version 2016-05-22 11:42:53 +01:00
Myles 9e6c0f72a8 Update version to be 1.9.3/4 2016-05-22 11:41:59 +01:00
Myles 70ad2613f1 Update config to look a bit more nicer, doesn't have the extra space when generated by bukkit. 2016-05-22 11:41:27 +01:00
Myles 9052946c45 Merge branch 'master' into 1.10 2016-05-21 22:12:10 +01:00
Myles 3ddc43bf7b Implement isSpigot() in the API and make it so xray does not activate if they do not use spigot. 2016-05-21 22:07:20 +01:00
Matsv cdb757eae5 Implement Myles idea to just use templates instead of defining compatibility 2016-05-21 21:19:20 +02:00
Matsv 50a3e03649 Possibility to add 'isCompatible' with other types. Fixes crashes on a 1.8 server 2016-05-21 20:54:26 +02:00
Matsv 957284930e Fix sounds 2016-05-21 16:19:12 +02:00
Matsv 198a24371c Sync with master 2016-05-21 15:01:25 +02:00
Mats bcc994b0dd Add possibility to get the supported versions from the api and status response (#402)
* Possibility  to send the Supported versions inside the status response packet

* Make lowercase
2016-05-19 18:56:42 +01:00
Matsv f870bd5a32 Transform pitch correctly 2016-05-19 13:07:51 +02:00
Matsv a14abd6f4f Handle the new Metadata value for 16w20a 2016-05-19 12:18:04 +02:00
Matsv 2456c3cf17 Basic support for the new 1.10 snapshot 16w20a 2016-05-18 16:43:57 +02:00
Myles 9828e4ae1d Add maven default goal.
Requested by our lord and saviour @Aikar
2016-05-17 23:40:00 +01:00
Myles 030aa887c7 Version bump to 0.8.3-SNAPSHOT #hype 2016-05-17 22:56:52 +01:00
Myles ba624a2b48 1.9.4 backport (#399)
Allow 1.9.4 spigot to handle 1.9, 1.9.1, 1.9.2
2016-05-17 22:48:56 +01:00
Myles e7582cb1ec Change license to be more appropriate, this one is more open and allows much more creativity. 2016-05-11 14:19:30 +01:00
Mats 82bf11fcbc Fix anti-xray for 1.9 (#393)
* Fix anti-xray for 1.9

* Bye NMS.

* Perform

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

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

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

* Remove canceling drop item
2016-04-20 18:31:18 +01:00
68 changed files with 1827 additions and 356 deletions

No files matched your search

+22 -1
View File
@@ -1,3 +1,24 @@
License:
--------
You may modify this work, all rights are still owned by myself excluding any files in the spacebase package as they belong to the respected contributors. Please credit the original author (myself) when forking etc. (or if it helped you understand the new protocol or netty!)
MIT License
Copyright (c) 2016
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+11 -10
View File
@@ -1,15 +1,16 @@
# ViaVersion 0.7.7
# ViaVersion 0.8.4
[![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)
## This is an experimental branch for 1.10, we do not recommend you to use this on a production server
**Direct download link:** [Latest builds](https://ci.viaversion.com/job/ViaVersion%201.10%20DEV/)
**Allows the connection of 1.9 clients to 1.8**
This plugin modifies netty to allow connection of 1.9 clients to 1.8,
###*Don't use late bind*
This uses our new API, we currently don't have javadocs yet but look at one of our protocols on how to get started then use ProtocolRegistry.registerProtocol()
This took 100s hours of work, so if you enjoy this consider looking into contacting me and supporting my projects.
**Contributor Chat:** https://gitter.im/MylesIsCool/ViaVersion
@@ -20,6 +21,8 @@ Sources:
**wiki.vg** (Protocol info, though I did have to find a lot myself)
**Burger** We use this tool to get protocol and other useful information for new / undocumented Minecraft versions
**OpenNBT** (used for slot rewriting)
@@ -54,20 +57,18 @@ https://www.spigotmc.org/resources/viaversion.19254/history
----------
You can find unofficial dev builds here:
You can find official dev builds here:
**fillefilip8's Build Server:** http://build.fillecraft.com:8080/job/ViaVersion
**Jenkins:** https://ci.viaversion.com
**sgdc3's Build Server:** http://ci.xephi.fr/job/ViaVersion/
**sgdc3's Maven:** http://ci.xephi.fr/plugin/repository/everything/
**JavaDocs:** https://jd.viaversion.com
**JavaDocs:** https://jd.matsv.nl/
**Maven Repo:** https://repo.viaversion.com
License:
--------
You may modify this work, all rights are still owned by myself excluding any files in the spacebase package as they belong to the respected contributors. Please credit the original author (myself) when forking etc. (or if it helped you understand the new protocol or netty!)
MIT License, see LICENSE for more details.
Thanks!
+28 -1
View File
@@ -6,7 +6,7 @@
<groupId>us.myles</groupId>
<artifactId>viaversion</artifactId>
<version>0.7.8-SNAPSHOT</version>
<version>0.9.0</version>
<packaging>jar</packaging>
<name>ViaVersion</name>
@@ -33,6 +33,7 @@
<build>
<finalName>${project.name}-${project.version}</finalName>
<sourceDirectory>src/main/java</sourceDirectory>
<defaultGoal>clean install</defaultGoal>
<!-- <testSourceDirectory>src/test/java</testSourceDirectory> -->
<resources>
@@ -105,6 +106,10 @@
<pattern>com.google.gson</pattern>
<shadedPattern>us.myles.viaversion.libs.gson</shadedPattern>
</relocation>
<relocation>
<pattern>org.javassist</pattern>
<shadedPattern>us.myles.viaversion.libs.javassist</shadedPattern>
</relocation>
</relocations>
</configuration>
<executions>
@@ -131,6 +136,12 @@
<id>spacehq-repo</id>
<url>https://repo.spacehq.org/content/repositories/releases/</url>
</repository>
<!-- Bungee repo -->
<repository>
<id>bungeecord-repo</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</repository>
</repositories>
<dependencies>
@@ -157,6 +168,15 @@
</exclusions>
</dependency>
<!-- Javassist (Bytecode Library) -->
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.20.0-GA</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<!-- NBT Edit Library -->
<dependency>
<groupId>org.spacehq</groupId>
@@ -191,5 +211,12 @@
<version>1.16.6</version>
<scope>provided</scope>
</dependency>
<!--Bungeecord-->
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<version>1.9-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,18 @@
package us.myles.ViaVersion;
import net.md_5.bungee.api.plugin.Plugin;
import static net.md_5.bungee.api.ChatColor.RED;
public class Bungee extends Plugin {
@Override
public void onEnable() {
getLogger().severe(RED + "===============================================");
getLogger().severe(RED + "ViaVersion is NOT a Bungeecord plugin");
getLogger().severe(RED + "Install this plugin on all your spigot/bukkit");
getLogger().severe(RED + "servers and use the latest Bungeecord version");
getLogger().severe(RED + "to make ViaVersion work with BungeeCord.");
getLogger().severe(RED + "===============================================");
}
}
@@ -0,0 +1,157 @@
package us.myles.ViaVersion;
import us.myles.ViaVersion.api.ViaVersionConfig;
import us.myles.ViaVersion.util.Configuration;
import java.io.File;
public class ViaConfig implements ViaVersionConfig {
private final ViaVersionPlugin plugin;
public ViaConfig(ViaVersionPlugin plugin) {
this.plugin = plugin;
generateConfig();
}
public void generateConfig() {
File file = new File(plugin.getDataFolder(), "config.yml");
if (file.exists()) {
// Update conf options
Configuration oldConfig = new Configuration(file);
oldConfig.reload(false); // Load current options from conf
file.delete(); // Delete old conf
plugin.saveDefaultConfig(); // Generate new conf
Configuration newConfig = new Configuration(file);
newConfig.reload(true); // Load default options
for (String key : oldConfig.getKeys(false)) {
// Set option in new conf if exists
if (newConfig.contains(key)) {
newConfig.set(key, oldConfig.get(key));
}
}
newConfig.save();
} else {
plugin.saveDefaultConfig();
}
}
@Override
public boolean isCheckForUpdates() {
return plugin.getConfig().getBoolean("checkforupdates", true);
}
@Override
public boolean isPreventCollision() {
return plugin.getConfig().getBoolean("prevent-collision", true);
}
@Override
public boolean isNewEffectIndicator() {
return plugin.getConfig().getBoolean("use-new-effect-indicator", true);
}
@Override
public boolean isShowNewDeathMessages() {
return plugin.getConfig().getBoolean("use-new-deathmessages", false);
}
@Override
public boolean isSuppressMetadataErrors() {
return plugin.getConfig().getBoolean("suppress-metadata-errors", false);
}
@Override
public boolean isShieldBlocking() {
return plugin.getConfig().getBoolean("shield-blocking", true);
}
@Override
public boolean isHologramPatch() {
return plugin.getConfig().getBoolean("hologram-patch", false);
}
@Override
public boolean isBossbarPatch() {
return plugin.getConfig().getBoolean("bossbar-patch", true);
}
@Override
public boolean isBossbarAntiflicker() {
return plugin.getConfig().getBoolean("bossbar-anti-flicker", false);
}
@Override
public boolean isUnknownEntitiesSuppressed() {
return false;
}
@Override
public double getHologramYOffset() {
return plugin.getConfig().getDouble("hologram-y", -1D);
}
@Override
public boolean isBlockBreakPatch() {
return false;
}
@Override
public int getMaxPPS() {
return plugin.getConfig().getInt("max-pps", 140);
}
@Override
public String getMaxPPSKickMessage() {
return plugin.getConfig().getString("max-pps-kick-msg", "Sending packets too fast? lag?");
}
@Override
public int getTrackingPeriod() {
return plugin.getConfig().getInt("tracking-period", 6);
}
@Override
public int getWarningPPS() {
return plugin.getConfig().getInt("tracking-warning-pps", 120);
}
@Override
public int getMaxWarnings() {
return plugin.getConfig().getInt("tracking-max-warnings", 3);
}
@Override
public String getMaxWarningsKickMessage() {
return plugin.getConfig().getString("tracking-max-kick-msg", "You are sending too many packets, :(");
}
@Override
public boolean isAntiXRay() {
return plugin.getConfig().getBoolean("anti-xray-patch", true);
}
@Override
public boolean isSendSupportedVersions() {
return plugin.getConfig().getBoolean("send-supported-versions", false);
}
@Override
public boolean isStimulatePlayerTick() {
return plugin.getConfig().getBoolean("simulate-pt", true);
}
@Override
public boolean isItemCache() {
return plugin.getConfig().getBoolean("item-cache", true);
}
@Override
public boolean isNMSPlayerTicking() {
return plugin.getConfig().getBoolean("nms-player-ticking", true);
}
public boolean isAutoTeam() {
// Collision has to be enabled first
return isPreventCollision() && plugin.getConfig().getBoolean("auto-team", true);
}
}
@@ -5,14 +5,15 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import lombok.Getter;
import lombok.NonNull;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.java.JavaPlugin;
import us.myles.ViaVersion.api.Pair;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.ViaVersionAPI;
import us.myles.ViaVersion.api.ViaVersionConfig;
import us.myles.ViaVersion.api.boss.BossBar;
import us.myles.ViaVersion.api.boss.BossColor;
import us.myles.ViaVersion.api.boss.BossStyle;
@@ -20,39 +21,42 @@ import us.myles.ViaVersion.api.command.ViaVersionCommand;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
import us.myles.ViaVersion.boss.ViaBossBar;
import us.myles.ViaVersion.classgenerator.ClassGenerator;
import us.myles.ViaVersion.commands.ViaCommandHandler;
import us.myles.ViaVersion.handlers.ViaVersionInitializer;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.update.UpdateListener;
import us.myles.ViaVersion.update.UpdateUtil;
import us.myles.ViaVersion.util.Configuration;
import us.myles.ViaVersion.util.ListWrapper;
import us.myles.ViaVersion.util.ReflectionUtil;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVersionConfig {
public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
private final Map<UUID, UserConnection> portedPlayers = new ConcurrentHashMap<>();
private List<ChannelFuture> injectedFutures = new ArrayList<>();
private List<Pair<Field, Object>> injectedLists = new ArrayList<>();
private ViaCommandHandler commandHandler;
private boolean debug = false;
private boolean compatSpigotBuild = false;
private boolean spigot = true;
private boolean lateBind = false;
@Getter
private ViaConfig conf;
@Override
public void onLoad() {
// Config magic
conf = new ViaConfig(this);
ViaVersion.setInstance(this);
generateConfig();
// Handle reloads
if (System.getProperty("ViaVersion") != null) {
if (Bukkit.getPluginManager().getPlugin("ProtocolLib") != null) {
getLogger().severe("ViaVersion is already loaded, we're going to kick all the players... because otherwise we'll crash because of ProtocolLib.");
@@ -65,14 +69,32 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
}
}
// 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 = ReflectionUtil.nms("PacketEncoder").getDeclaredField("version") != null;
} catch (Exception e) {
compatSpigotBuild = false;
}
// Generate classes needed (only works if it's compat)
ClassGenerator.generate();
lateBind = !isBinded();
getLogger().info("ViaVersion " + getDescription().getVersion() + " is now loaded, injecting.");
injectPacketHandler();
getLogger().info("ViaVersion " + getDescription().getVersion() + (compatSpigotBuild ? "compat" : "") + " is now loaded" + (lateBind ? ", waiting for boot. (late-bind)" : ", injecting!"));
if (!lateBind)
injectPacketHandler();
}
@Override
public void onEnable() {
if (isCheckForUpdates())
if (lateBind)
injectPacketHandler();
if (conf.isCheckForUpdates())
UpdateUtil.sendUpdateMessage(this);
// Gather version :)
Bukkit.getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
@@ -86,6 +108,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
getLogger().warning("ViaVersion will not function on the current protocol.");
}
}
ProtocolRegistry.refreshVersions();
}
});
@@ -97,6 +120,11 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
// Register Protocol Listeners
ProtocolRegistry.registerListeners();
// 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!");
}
}
@Override
@@ -152,42 +180,25 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
}
}
public void generateConfig() {
File file = new File(getDataFolder(), "config.yml");
if (file.exists()) {
// Update config options
Configuration oldConfig = new Configuration(file);
oldConfig.reload(false); // Load current options from config
file.delete(); // Delete old config
saveDefaultConfig(); // Generate new config
Configuration newConfig = new Configuration(file);
newConfig.reload(true); // Load default options
for (String key : oldConfig.getKeys(false)) {
// Set option in new config if exists
if (newConfig.contains(key)) {
newConfig.set(key, oldConfig.get(key));
public Object getServerConnection() throws Exception {
Class<?> serverClazz = ReflectionUtil.nms("MinecraftServer");
Object server = ReflectionUtil.invokeStatic(serverClazz, "getServer");
Object connection = null;
for (Method m : serverClazz.getDeclaredMethods()) {
if (m.getReturnType() != null) {
if (m.getReturnType().getSimpleName().equals("ServerConnection")) {
if (m.getParameterTypes().length == 0) {
connection = m.invoke(server);
}
}
}
newConfig.save();
} else {
saveDefaultConfig();
}
return connection;
}
public void injectPacketHandler() {
try {
Class<?> serverClazz = ReflectionUtil.nms("MinecraftServer");
Object server = ReflectionUtil.invokeStatic(serverClazz, "getServer");
Object connection = null;
for (Method m : serverClazz.getDeclaredMethods()) {
if (m.getReturnType() != null) {
if (m.getReturnType().getSimpleName().equals("ServerConnection")) {
if (m.getParameterTypes().length == 0) {
connection = m.invoke(server);
}
}
}
}
Object connection = getServerConnection();
if (connection == null) {
getLogger().warning("We failed to find the ServerConnection? :( What server are you running?");
return;
@@ -228,6 +239,33 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
}
}
public 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;
}
private void inject(ChannelFuture future) {
try {
ChannelHandler bootstrapAcceptor = future.channel().pipeline().first();
@@ -238,11 +276,18 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
ReflectionUtil.set(bootstrapAcceptor, "childHandler", newInit);
injectedFutures.add(future);
} catch (NoSuchFieldException e) {
// field not found
throw new Exception("Unable to find childHandler, blame " + bootstrapAcceptor.getClass().getName());
// 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 childHandler, weird server version? " + bootstrapAcceptor.getClass().getName());
}
}
} catch (Exception e) {
getLogger().severe("Have you got late-bind enabled with something else? (ProtocolLib?)");
getLogger().severe("Have you got late-bind enabled with something else?");
e.printStackTrace();
}
}
@@ -348,88 +393,19 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
return commandHandler;
}
public boolean isCheckForUpdates() {
return getConfig().getBoolean("checkforupdates", true);
}
public boolean isPreventCollision() {
return getConfig().getBoolean("prevent-collision", true);
}
public boolean isNewEffectIndicator() {
return getConfig().getBoolean("use-new-effect-indicator", true);
@Override
public boolean isCompatSpigotBuild() {
return compatSpigotBuild;
}
@Override
public boolean isShowNewDeathMessages() {
return getConfig().getBoolean("use-new-deathmessages", false);
}
public boolean isSuppressMetadataErrors() {
return getConfig().getBoolean("suppress-metadata-errors", false);
}
public boolean isShieldBlocking() {
return getConfig().getBoolean("shield-blocking", true);
}
public boolean isHologramPatch() {
return getConfig().getBoolean("hologram-patch", false);
}
public boolean isBossbarPatch() {
return getConfig().getBoolean("bossbar-patch", true);
}
public boolean isBossbarAntiflicker() {
return getConfig().getBoolean("bossbar-anti-flicker", false);
}
public boolean isUnknownEntitiesSuppressed() {
return getConfig().getBoolean("suppress-entityid-errors", false);
}
public double getHologramYOffset() {
return getConfig().getDouble("hologram-y", -1D);
}
public boolean isBlockBreakPatch() {
return getConfig().getBoolean("block-break-patch", true);
public SortedSet<Integer> getSupportedVersions() {
return ProtocolRegistry.getSupportedVersions();
}
@Override
public int getMaxPPS() {
return getConfig().getInt("max-pps", 140);
}
@Override
public String getMaxPPSKickMessage() {
return getConfig().getString("max-pps-kick-msg", "Sending packets too fast? lag?");
}
@Override
public int getTrackingPeriod() {
return getConfig().getInt("tracking-period", 6);
}
@Override
public int getWarningPPS() {
return getConfig().getInt("tracking-warning-pps", 120);
}
@Override
public int getMaxWarnings() {
return getConfig().getInt("tracking-max-warnings", 3);
}
@Override
public String getMaxWarningsKickMessage() {
return getConfig().getString("tracking-max-kick-msg", "You are sending too many packets, :(");
}
public boolean isAutoTeam() {
// Collision has to be enabled first
return isPreventCollision() && getConfig().getBoolean("auto-team", true);
public boolean isSpigot() {
return this.spigot;
}
public void addPortedClient(UserConnection info) {
@@ -465,27 +441,27 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
public boolean handlePPS(UserConnection info) {
// Max PPS Checker
if (getMaxPPS() > 0) {
if (info.getPacketsPerSecond() >= getMaxPPS()) {
info.disconnect(getMaxPPSKickMessage());
if (conf.getMaxPPS() > 0) {
if (info.getPacketsPerSecond() >= conf.getMaxPPS()) {
info.disconnect(conf.getMaxPPSKickMessage());
return true; // don't send current packet
}
}
// Tracking PPS Checker
if (getMaxWarnings() > 0 && getTrackingPeriod() > 0) {
if (info.getSecondsObserved() > getTrackingPeriod()) {
if (conf.getMaxWarnings() > 0 && conf.getTrackingPeriod() > 0) {
if (info.getSecondsObserved() > conf.getTrackingPeriod()) {
// Reset
info.setWarnings(0);
info.setSecondsObserved(1);
} else {
info.setSecondsObserved(info.getSecondsObserved() + 1);
if (info.getPacketsPerSecond() >= getWarningPPS()) {
if (info.getPacketsPerSecond() >= conf.getWarningPPS()) {
info.setWarnings(info.getWarnings() + 1);
}
if (info.getWarnings() >= getMaxWarnings()) {
info.disconnect(getMaxWarningsKickMessage());
if (info.getWarnings() >= conf.getMaxWarnings()) {
info.disconnect(conf.getMaxWarningsKickMessage());
return true; // don't send current packet
}
}
@@ -38,8 +38,10 @@ public class PacketWrapper {
* Get a part from the output
*
* @param type The type of the part you wish to get.
* @param <T> The return type of the type you wish to get.
* @param index The index of the part (relative to the type)
* @return The requested type or throws ArrayIndexOutOfBounds
* @throws Exception If it fails to find it, an exception will be thrown.
*/
public <T> T get(Type<T> type, int index) throws Exception {
int currentIndex = 0;
@@ -80,8 +82,10 @@ public class PacketWrapper {
* Set a currently existing part in the output
*
* @param type The type of the part you wish to set.
* @param <T> The return type of the type you wish to set.
* @param index The index of the part (relative to the type)
* @param value The value of the part you wish to set it to.
* @throws Exception If it fails to set it, an exception will be thrown.
*/
public <T> void set(Type<T> type, int index, T value) throws Exception {
int currentIndex = 0;
@@ -102,6 +106,7 @@ public class PacketWrapper {
* Read a type from the input.
*
* @param type The type you wish to read
* @param <T> The return type of the type you wish to read.
* @return The requested type
* @throws Exception If it fails to read
*/
@@ -117,7 +122,7 @@ public class PacketWrapper {
}
} else {
Pair<Type, Object> read = readableObjects.poll();
if (read.getKey().equals(type)) {
if (read.getKey().equals(type) || (type.getBaseClass().equals(read.getKey().getBaseClass()) && type.getOutputClass().equals(read.getKey().getOutputClass()))) {
return (T) read.getValue();
} else {
if (type == Type.NOTHING) {
@@ -134,6 +139,7 @@ public class PacketWrapper {
* Write a type to the output.
*
* @param type The type to write.
* @param <T> The return type of the type you wish to write.
* @param value The value of the type to write.
*/
public <T> void write(Type<T> type, T value) {
@@ -154,6 +160,7 @@ public class PacketWrapper {
* Take a value from the input and write to the output.
*
* @param type The type to read and write.
* @param <T> The return type of the type you wish to pass through.
* @return The type which was read/written.
* @throws Exception If it failed to read or write
*/
@@ -163,6 +170,21 @@ public class PacketWrapper {
return value;
}
/**
* Take all the inputs and write them to the output.
*
* @throws Exception If it failed to read or write
*/
public void passthroughAll() throws Exception {
// Copy previous objects
packetValues.addAll(readableObjects);
readableObjects.clear();
// If the buffer has readable bytes, copy them.
if (inputBuffer.readableBytes() > 0) {
passthrough(Type.REMAINING_BYTES);
}
}
/**
* Write the current output to a buffer.
*
@@ -209,6 +231,14 @@ public class PacketWrapper {
readableObjects.clear(); // :(
}
/**
* Clear the packet, used if you have to change the packet completely
*/
public void clearPacket() {
clearInputBuffer();
packetValues.clear();
}
private void writeRemaining(ByteBuf output) {
if (inputBuffer != null) {
output.writeBytes(inputBuffer);
@@ -303,4 +333,13 @@ public class PacketWrapper {
PipelineUtil.getContextBefore("decompress", user().getChannel().pipeline()).fireChannelRead(output);
}
}
@Override
public String toString() {
return "PacketWrapper{" +
"packetValues=" + packetValues +
", readableObjects=" + readableObjects +
", id=" + id +
'}';
}
}
@@ -14,6 +14,6 @@ public class ViaVersion {
public static void setInstance(ViaVersionPlugin plugin) {
Validate.isTrue(instance == null, "Instance is already set");
ViaVersion.instance = plugin;
ViaVersion.config = plugin;
ViaVersion.config = plugin.getConf();
}
}
@@ -7,6 +7,7 @@ import us.myles.ViaVersion.api.boss.BossColor;
import us.myles.ViaVersion.api.boss.BossStyle;
import us.myles.ViaVersion.api.command.ViaVersionCommand;
import java.util.SortedSet;
import java.util.UUID;
public interface ViaVersionAPI {
@@ -37,7 +38,7 @@ public interface ViaVersionAPI {
/**
* Is player using 1.9?
*
* @param playerUUID
* @param playerUUID UUID of a player
* @return True if the client is on 1.9
*/
boolean isPorted(UUID playerUUID);
@@ -101,4 +102,27 @@ public interface ViaVersionAPI {
* @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
*
* @return a list of protocol versions
*/
SortedSet<Integer> getSupportedVersions();
/**
* Gets if the server uses spigot
*
* Note: Will only work after ViaVersion load
* @return True if spigot
*/
boolean isSpigot();
}
@@ -2,13 +2,6 @@ package us.myles.ViaVersion.api;
public interface ViaVersionConfig {
/**
* Get if global debug is enabled
*
* @return true if debug is enabled
*/
boolean isDebug();
/**
* Get if the plugin should check for updates
*
@@ -24,14 +17,14 @@ public interface ViaVersionConfig {
boolean isPreventCollision();
/**
* Get if 1.9 clients are shown the new effect indicator in the top-right corner
* Get if 1.9 & 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 clients are shown the new death message on the death screen
* Get if 1.9 & 1.10 clients are shown the new death message on the death screen
*
* @return true if enabled
*/
@@ -45,28 +38,28 @@ public interface ViaVersionConfig {
boolean isSuppressMetadataErrors();
/**
* Get if blocking in 1.9 appears as a player holding a shield
* Get if blocking in 1.9 & 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
* Get if armor stand positions are fixed so holograms show up at the correct height in 1.9 & 1.10
*
* @return true if hologram patching is enabled
*/
boolean isHologramPatch();
/**
* Get if boss bars are fixed for 1.9 clients
* Get if boss bars are fixed for 1.9 & 1.10 clients
*
* @return true if boss bar patching is enabled
*/
boolean isBossbarPatch();
/**
* Get if the boss bars for 1.9 clients are being stopped from flickering
* Get if the boss bars for 1.9 & 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
@@ -78,6 +71,7 @@ public interface ViaVersionConfig {
*
* @return true if boss bar patching is enabled
*/
@Deprecated
boolean isUnknownEntitiesSuppressed();
/**
@@ -99,6 +93,7 @@ public interface ViaVersionConfig {
*
* @return true if it is enabled.
*/
@Deprecated
boolean isBlockBreakPatch();
/**
@@ -111,7 +106,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 '&'
* @return Kick message, with colour codes using '&amp;'
*/
String getMaxPPSKickMessage();
@@ -139,7 +134,42 @@ 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 '&'
* @return Kick message, with colour codes using '&amp;'
*/
String getMaxWarningsKickMessage();
/**
* Is anti-xray enabled?
*
* @return A boolean
*/
boolean isAntiXRay();
/**
* Send supported versions in the status response packet
*
* @return If true, enabled
*/
boolean isSendSupportedVersions();
/**
* Stimulate the player tick
*
* @return if true, enabled
*/
boolean isStimulatePlayerTick();
/**
* Use the item cache to prevent high resource usage
*
* @return if true, enabled
*/
boolean isItemCache();
/**
* Use the NMS player ticking
*
* @return if true, enabled
*/
boolean isNMSPlayerTicking();
}
@@ -17,6 +17,7 @@ public interface BossBar {
* Change the title
*
* @param title Title can be in either JSON or just text
* @return The BossBar object
*/
BossBar setTitle(String title);
@@ -31,13 +32,14 @@ public interface BossBar {
* Change the health
*
* @param health this float has to be between 0F - 1F
* @return The BossBar object
*/
BossBar setHealth(float health);
/**
* Get the bossbar color
*
* @return
* @return The colour
*/
BossColor getColor();
@@ -45,6 +47,7 @@ public interface BossBar {
* Yay colors!
*
* @param color Whatever color you want!
* @return The BossBar object
*/
BossBar setColor(BossColor color);
@@ -59,48 +62,61 @@ public interface BossBar {
* Change the bosbar style
*
* @param style BossStyle
* @return The BossBar object
*/
BossBar setStyle(BossStyle style);
/**
* Show the bossbar to a player.
*
* @param player
* @param player The player
* @return The BossBar object
*/
BossBar addPlayer(Player player);
/**
* Show the bossbar to a player (uuid)
*
* @param player uuid of the player
* @return The BossBar object
*/
BossBar addPlayer(UUID player);
/**
* add multiple players
*
* @param players list of players
* @return the bossbar instance
* @return The BossBar object
*/
BossBar addPlayers(Player... players);
/**
* Remove the bossbar from a player
*
* @param player
* @param player The player
* @return The BossBar object
*/
BossBar removePlayer(Player player);
/**
* Add flags
*
* @param flag
* @param flag The flag to add
* @return The BossBar object
*/
BossBar addFlag(BossFlag flag);
/**
* Remove flags.
*
* @param flag
* @param flag The flag to remove
* @return The BossBar object
*/
BossBar removeFlag(BossFlag flag);
/**
* @param flag
* @return
* @param flag The flag to check against
* @return True if it has the flag
*/
boolean hasFlag(BossFlag flag);
@@ -113,11 +129,15 @@ public interface BossBar {
/**
* Show the bossbar to everyone (In the getPlayer set)
*
* @return The BossBar object
*/
BossBar show();
/**
* Hide the bossbar from everyone (In the getPlayer set)
*
* @return The BossBar object
*/
BossBar hide();
@@ -10,14 +10,14 @@ public abstract class ViaSubCommand {
/**
* Subcommand name
*
* @return your input
* @return The command name
*/
public abstract String name();
/**
* subcommand description, this'll show in /viaversion list
*
* @return your input
* @return The command description
*/
public abstract String description();
@@ -25,7 +25,7 @@ public abstract class ViaSubCommand {
* Usage example:
* "playerversion [name]"
*
* @return your input
* @return The command usage
*/
public String usage() {
return name();
@@ -34,7 +34,7 @@ public abstract class ViaSubCommand {
/**
* Permission, null for everyone
*
* @return
* @return The permission required to use the command
*/
public String permission() {
return "viaversion.admin";
@@ -59,7 +59,7 @@ public abstract class ViaSubCommand {
public List<String> onTabComplete(CommandSender sender, String[] args) {
return Collections.emptyList();
}
public String color(String s) {
return ViaCommandHandler.color(s);
}
@@ -1,12 +1,9 @@
package us.myles.ViaVersion.api.data;
import com.google.gson.Gson;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.socket.SocketChannel;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
@@ -42,6 +39,7 @@ public class UserConnection {
* Get an object from the storage
*
* @param objectClass The class of the object to get
* @param <T> The type of the class you want to get.
* @return The requested object
*/
public <T extends StoredObject> T get(Class<T> objectClass) {
@@ -105,6 +103,8 @@ public class UserConnection {
/**
* Used for incrementing the number of packets received from the client
*
* @return True if the interval has reset
*/
public boolean incrementReceived() {
// handle stats
@@ -128,8 +128,8 @@ public class UserConnection {
* @param reason The reason to use, not used if player is not active.
*/
public void disconnect(final String reason) {
if(!getChannel().isOpen()) return;
if(pendingDisconnect) return;
if (!getChannel().isOpen()) return;
if (pendingDisconnect) return;
pendingDisconnect = true;
if (get(ProtocolInfo.class).getUuid() != null) {
final UUID uuid = get(ProtocolInfo.class).getUuid();
@@ -157,6 +157,7 @@ public class ChunkSection {
* Get expected size of this chunk section.
*
* @return Amount of bytes sent by this section
* @throws Exception If it failed to calculate bits properly
*/
public int getExpectedSize() throws Exception {
int bitsPerBlock = palette.size() > 255 ? 16 : 8;
@@ -7,17 +7,16 @@ import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.packets.Direction;
import us.myles.ViaVersion.packets.PacketType;
import us.myles.ViaVersion.packets.State;
import us.myles.ViaVersion.protocols.base.BaseProtocol;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
public class ProtocolPipeline extends Protocol {
LinkedList<Protocol> protocolList;
List<Protocol> protocolList;
private UserConnection userConnection;
public ProtocolPipeline(UserConnection userConnection) {
@@ -27,9 +26,9 @@ public class ProtocolPipeline extends Protocol {
@Override
protected void registerPackets() {
protocolList = new LinkedList<>();
protocolList = new CopyOnWriteArrayList<>();
// This is a pipeline so we register basic pipes
protocolList.addLast(new BaseProtocol());
protocolList.add(ProtocolRegistry.BASE_PROTOCOL);
}
@Override
@@ -55,7 +54,7 @@ public class ProtocolPipeline extends Protocol {
*/
public void add(Protocol protocol) {
if (protocolList != null) {
protocolList.addLast(protocol);
protocolList.add(protocol);
protocol.init(userConnection);
} else {
throw new NullPointerException("Tried to add protocol to early");
@@ -83,21 +82,17 @@ public class ProtocolPipeline extends Protocol {
// For 1.8/1.9 server version, eventually we'll probably get an API for this...
if (ProtocolRegistry.SERVER_PROTOCOL >= ProtocolVersion.v1_8.getId() &&
ProtocolRegistry.SERVER_PROTOCOL <= ProtocolVersion.v1_9_2.getId()) {
ProtocolRegistry.SERVER_PROTOCOL <= ProtocolVersion.v1_9_3.getId()) {
PacketType type;
if (ProtocolRegistry.SERVER_PROTOCOL == ProtocolVersion.v1_8.getId()) {
if (ProtocolRegistry.SERVER_PROTOCOL <= ProtocolVersion.v1_8.getId()) {
if (direction == Direction.INCOMING) {
type = PacketType.findNewPacket(state, direction, originalID);
} else {
type = PacketType.findOldPacket(state, direction, originalID);
}
} else {
if (direction == Direction.INCOMING) {
type = PacketType.findOldPacket(state, direction, originalID);
} else {
type = PacketType.findNewPacket(state, direction, originalID);
}
type = PacketType.findNewPacket(state, direction, originalID);
}
// Filter :) This would be not hard coded too, sorry :(
@@ -116,13 +111,19 @@ public class ProtocolPipeline extends Protocol {
}
String name = packet + "[" + userConnection.get(ProtocolInfo.class).getProtocolVersion() + "]";
ViaVersionPlugin plugin = (ViaVersionPlugin) ViaVersion.getInstance();
plugin.getLogger().log(Level.INFO, "{0}: {1} {2} -> {3} [{4}]",
String actualUsername = packetWrapper.user().get(ProtocolInfo.class).getUsername();
String username = actualUsername != null ? actualUsername + " " : "";
plugin.getLogger().log(Level.INFO, "{0}{1}: {2} {3} -> {4} [{5}] Value: {6}",
new Object[]{
username,
direction,
state,
originalID,
packetWrapper.getId(),
name
name,
packetWrapper
});
}
}
@@ -158,4 +159,8 @@ public class ProtocolPipeline extends Protocol {
return false;
}
public List<Protocol> pipes() {
return protocolList;
}
}
@@ -1,23 +1,41 @@
package us.myles.ViaVersion.api.protocol;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.bukkit.Bukkit;
import us.myles.ViaVersion.api.Pair;
import us.myles.ViaVersion.protocols.base.BaseProtocol;
import us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4.Protocol1_9_1_2TO1_9_3_4;
import us.myles.ViaVersion.protocols.protocol1_9_1to1_9.Protocol1_9_1TO1_9;
import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.Protocol1_9_3TO1_9_1_2;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
import us.myles.ViaVersion.protocols.protocol1_9to1_9_1.Protocol1_9TO1_9_1;
import us.myles.ViaVersion.protocols.protocolsnapshotto1_9_3.ProtocolSnapshotTo1_9_3_4;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class ProtocolRegistry {
public static final Protocol BASE_PROTOCOL = new BaseProtocol();
public static int SERVER_PROTOCOL = -1;
// Input Version -> Output Version & Protocol (Allows fast lookup)
private static Map<Integer, Map<Integer, Protocol>> registryMap = new HashMap<>();
private static Map<Pair<Integer, Integer>, List<Pair<Integer, Protocol>>> pathCache = new HashMap<>();
private static List<Protocol> registerList = new ArrayList<>();
private static Map<Integer, Map<Integer, Protocol>> registryMap = new ConcurrentHashMap<>();
private static Map<Pair<Integer, Integer>, List<Pair<Integer, Protocol>>> pathCache = new ConcurrentHashMap<>();
private static List<Protocol> registerList = Lists.newCopyOnWriteArrayList();
private static Set<Integer> supportedVersions = Sets.newConcurrentHashSet();
static {
// Base Protocol
registerProtocol(BASE_PROTOCOL, Arrays.<Integer>asList(), -1);
// Register built in protocols
registerProtocol(new Protocol1_9TO1_8(), Collections.singletonList(ProtocolVersion.v1_9.getId()), ProtocolVersion.v1_8.getId());
registerProtocol(new Protocol1_9_1TO1_9(), Arrays.asList(ProtocolVersion.v1_9_1.getId(), ProtocolVersion.v1_9_2.getId()), ProtocolVersion.v1_9.getId());
registerProtocol(new Protocol1_9_3TO1_9_1_2(), Arrays.asList(ProtocolVersion.v1_9_3.getId()), ProtocolVersion.v1_9_2.getId());
// Only supported for 1.9.4 server to 1.9 (nothing else)
registerProtocol(new Protocol1_9TO1_9_1(), Arrays.asList(ProtocolVersion.v1_9.getId()), ProtocolVersion.v1_9_2.getId());
registerProtocol(new Protocol1_9_1_2TO1_9_3_4(), Arrays.asList(ProtocolVersion.v1_9_1.getId(), ProtocolVersion.v1_9_2.getId()), ProtocolVersion.v1_9_3.getId());
registerProtocol(new ProtocolSnapshotTo1_9_3_4(), Collections.singletonList(ProtocolVersion.SNAPSHOT.getId()), ProtocolVersion.v1_9_3.getId());
}
/**
@@ -42,11 +60,29 @@ public class ProtocolRegistry {
if (Bukkit.getPluginManager().getPlugin("ViaVersion").isEnabled()) {
protocol.registerListeners();
refreshVersions();
} else {
registerList.add(protocol);
}
}
public static void refreshVersions() {
supportedVersions.clear();
supportedVersions.add(ProtocolRegistry.SERVER_PROTOCOL);
for (ProtocolVersion versions : ProtocolVersion.getProtocols()) {
List<Pair<Integer, Protocol>> paths = getProtocolPath(versions.getId(), ProtocolRegistry.SERVER_PROTOCOL);
if (paths == null) continue;
supportedVersions.add(versions.getId());
for (Pair<Integer, Protocol> path : paths)
supportedVersions.add(path.getKey());
}
}
public static SortedSet<Integer> getSupportedVersions() {
return Collections.unmodifiableSortedSet(new TreeSet<>(supportedVersions));
}
/**
* Check if this plugin is useful to the server.
*
@@ -78,6 +114,7 @@ public class ProtocolRegistry {
* @return The path which has been generated, null if failed.
*/
private static List<Pair<Integer, Protocol>> getProtocolPath(List<Pair<Integer, Protocol>> current, int clientVersion, int serverVersion) {
if (clientVersion == serverVersion) return null; // We're already there
if (current.size() > 50) return null; // Fail safe, protocol too complicated.
// First check if there is any protocols for this
@@ -91,6 +128,8 @@ public class ProtocolRegistry {
return current; // Easy solution
}
// There might be a more advanced solution... So we'll see if any of the others can get us there
List<Pair<Integer, Protocol>> shortest = null;
for (Map.Entry<Integer, Protocol> entry : inputMap.entrySet()) {
// Ensure it wasn't caught by the other loop
if (!entry.getKey().equals(serverVersion)) {
@@ -103,13 +142,16 @@ public class ProtocolRegistry {
// Calculate the rest of the protocol using the current
newCurrent = getProtocolPath(newCurrent, entry.getKey(), serverVersion);
if (newCurrent != null) {
return newCurrent;
// If it's shorter then choose it
if (shortest == null || shortest.size() > newCurrent.size()) {
shortest = newCurrent;
}
}
}
}
}
return null;
return shortest; // null if none found
}
/**
@@ -15,6 +15,8 @@ public class ProtocolVersion {
public static final ProtocolVersion v1_9;
public static final ProtocolVersion v1_9_1;
public static final ProtocolVersion v1_9_2;
public static final ProtocolVersion v1_9_3;
public static final ProtocolVersion SNAPSHOT;
private final int id;
private final String name;
@@ -26,6 +28,8 @@ public class ProtocolVersion {
register(v1_9 = new ProtocolVersion(107, "1.9"));
register(v1_9_1 = new ProtocolVersion(108, "1.9.1"));
register(v1_9_2 = new ProtocolVersion(109, "1.9.2"));
register(v1_9_3 = new ProtocolVersion(110, "1.9.3/4"));
register(SNAPSHOT = new ProtocolVersion(210, "1.10"));
}
public static void register(@NonNull ProtocolVersion protocol) {
@@ -37,10 +41,14 @@ public class ProtocolVersion {
}
public static ProtocolVersion getProtocol(int id) {
return versions.get(id);
if (versions.containsKey(id)) {
return versions.get(id);
} else {
return new ProtocolVersion(id, "Unknown (" + id + ")");
}
}
public static List<ProtocolVersion> getProtocols() {
return Collections.unmodifiableList(new ArrayList<ProtocolVersion>(versions.values()));
return Collections.unmodifiableList(new ArrayList<>(versions.values()));
}
}
@@ -39,7 +39,9 @@ public abstract class PacketRemapper {
* Map a type from an old type to a transformed new type.
*
* @param oldType The old type
* @param <T1> The old return type.
* @param transformer The transformer to use to produce the new type.
* @param <T2> The new return type.
*/
public <T1, T2> void map(Type<T1> oldType, ValueTransformer<T1, T2> transformer) {
map(new TypeRemapper(oldType), transformer);
@@ -49,7 +51,8 @@ public abstract class PacketRemapper {
* Map a type using a basic ValueReader to a ValueWriter
*
* @param inputReader The reader to read with.
* @param outputWriter The writer to write with.
* @param outputWriter The writer to write with
* @param <T> The return type
*/
public <T> void map(ValueReader<T> inputReader, ValueWriter<T> outputWriter) {
valueRemappers.add(new Pair<ValueReader, ValueWriter>(inputReader, outputWriter));
@@ -10,6 +10,8 @@ import us.myles.ViaVersion.api.minecraft.item.Item;
import us.myles.ViaVersion.api.type.types.*;
import us.myles.ViaVersion.api.type.types.minecraft.*;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
@Getter
@@ -61,12 +63,14 @@ public abstract class Type<T> implements ByteBufReader<T>, ByteBufWriter<T> {
public static final Type<CompoundTag> NBT = new NBTType();
public static final Type<UUID> OPTIONAL_UUID = new OptUUIDType();
public static final Type<Position> OPTIONAL_POSITION = new OptPositionType();
public static final Type<Item> ITEM = new ItemType();
public static final Type<Item[]> ITEM_ARRAY = new ItemArrayType();
/* Actual Class */
private final Class<? super T> outputClass;
private final Set<Class<? extends Type>> compatibilities;
private final String typeName;
public Type(Class<? super T> outputClass) {
@@ -76,6 +80,11 @@ public abstract class Type<T> implements ByteBufReader<T>, ByteBufWriter<T> {
public Type(String typeName, Class<? super T> outputClass) {
this.outputClass = outputClass;
this.typeName = typeName;
this.compatibilities = new HashSet<>();
}
public Class<? extends Type> getBaseClass() {
return this.getClass();
}
@Override
@@ -0,0 +1,17 @@
package us.myles.ViaVersion.api.type.types.minecraft;
import us.myles.ViaVersion.api.minecraft.metadata.Metadata;
import us.myles.ViaVersion.api.type.Type;
import java.util.List;
public abstract class MetaListTypeTemplate extends Type<List<Metadata>> {
public MetaListTypeTemplate() {
super("MetaData List", List.class);
}
@Override
public Class<? extends Type> getBaseClass() {
return MetaListTypeTemplate.class;
}
}
@@ -0,0 +1,15 @@
package us.myles.ViaVersion.api.type.types.minecraft;
import us.myles.ViaVersion.api.minecraft.metadata.Metadata;
import us.myles.ViaVersion.api.type.Type;
public abstract class MetaTypeTemplate extends Type<Metadata> {
public MetaTypeTemplate() {
super("Metadata type", Metadata.class);
}
@Override
public Class<? extends Type> getBaseClass() {
return MetaTypeTemplate.class;
}
}
@@ -0,0 +1,25 @@
package us.myles.ViaVersion.api.type.types.minecraft;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.minecraft.Position;
import us.myles.ViaVersion.api.type.Type;
public class OptPositionType extends Type<Position> {
public OptPositionType() {
super(Position.class);
}
@Override
public Position read(ByteBuf buffer) throws Exception {
boolean present = buffer.readBoolean();
if (!present) return null;
return Type.POSITION.read(buffer);
}
@Override
public void write(ByteBuf buffer, Position object) throws Exception {
buffer.writeBoolean(object != null);
if (object != null)
Type.POSITION.write(buffer, object);
}
}
@@ -78,10 +78,15 @@ public class ViaBossBar implements BossBar {
@Override
public BossBar addPlayer(@NonNull Player player) {
if (!players.contains(player.getUniqueId())) {
players.add(player.getUniqueId());
return addPlayer(player.getUniqueId());
}
@Override
public BossBar addPlayer(UUID player) {
if (!players.contains(player)) {
players.add(player);
if (visible)
sendPacket(player.getUniqueId(), getPacket(UpdateAction.ADD));
sendPacket(player, getPacket(UpdateAction.ADD));
}
return this;
}
@@ -0,0 +1,19 @@
package us.myles.ViaVersion.classgenerator;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.handlers.ViaDecodeHandler;
import us.myles.ViaVersion.handlers.ViaEncodeHandler;
public class BasicHandlerConstructor implements HandlerConstructor {
@Override
public ViaEncodeHandler newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {
return new ViaEncodeHandler(info, minecraftEncoder);
}
@Override
public ViaDecodeHandler newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {
return new ViaDecodeHandler(info, minecraftDecoder);
}
}
@@ -0,0 +1,88 @@
package us.myles.ViaVersion.classgenerator;
import javassist.*;
import javassist.expr.ConstructorCall;
import javassist.expr.ExprEditor;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.handlers.ViaDecodeHandler;
import us.myles.ViaVersion.handlers.ViaEncodeHandler;
import us.myles.ViaVersion.util.ReflectionUtil;
public class ClassGenerator {
private static HandlerConstructor constructor = new BasicHandlerConstructor();
public static HandlerConstructor getConstructor() {
return constructor;
}
public static void generate() {
if(!ViaVersion.getInstance().isCompatSpigotBuild()) return; // Use Basic Handler as not needed.
try {
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new LoaderClassPath(ClassGenerator.class.getClassLoader()));
// Generate the classes
transformSuperclass(pool, ViaDecodeHandler.class, ReflectionUtil.nms("PacketDecoder"));
transformSuperclass(pool, ViaEncodeHandler.class, ReflectionUtil.nms("PacketEncoder"));
// Implement Constructor
CtClass generated = pool.makeClass("us.myles.ViaVersion.classgenerator.generated.GeneratedConstructor");
CtClass handlerInterface = pool.get(HandlerConstructor.class.getName());
generated.setInterfaces(new CtClass[]{handlerInterface});
// Import required classes
pool.importPackage("us.myles.ViaVersion.classgenerator.generated");
pool.importPackage("us.myles.ViaVersion.classgenerator");
pool.importPackage("us.myles.ViaVersion.api.data");
pool.importPackage("io.netty.handler.codec");
// Implement Methods
generated.addMethod(CtMethod.make("public MessageToByteEncoder newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {\n" +
" return new ViaEncodeHandler(info, minecraftEncoder);\n" +
" }", generated));
generated.addMethod(CtMethod.make("public ByteToMessageDecoder newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {\n" +
" return new ViaDecodeHandler(info, minecraftDecoder);\n" +
" }", generated));
constructor = (HandlerConstructor) generated.toClass(HandlerConstructor.class.getClassLoader()).newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (CannotCompileException e) {
e.printStackTrace();
} catch (NotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
private static Class transformSuperclass(ClassPool pool, Class input, Class superclass) {
String newName = "us.myles.ViaVersion.classgenerator.generated." + input.getSimpleName();
try {
CtClass toExtend = pool.get(superclass.getName());
CtClass generated = pool.getAndRename(input.getName(), newName);
generated.setSuperclass(toExtend);
// Modify constructor to call super
if(generated.getConstructors().length != 0) {
generated.getConstructors()[0].instrument(new ExprEditor() {
@Override
public void edit(ConstructorCall c) throws CannotCompileException {
if (c.isSuper()) {
// Constructor for both has a stats thing.
c.replace("super(null);");
}
super.edit(c);
}
});
}
return generated.toClass(HandlerConstructor.class.getClassLoader());
} catch (NotFoundException e) {
e.printStackTrace();
} catch (CannotCompileException e) {
e.printStackTrace();
}
return null;
}
}
@@ -0,0 +1,10 @@
package us.myles.ViaVersion.classgenerator;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import us.myles.ViaVersion.api.data.UserConnection;
public interface HandlerConstructor {
public MessageToByteEncoder newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder);
public ByteToMessageDecoder newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder);
}
@@ -20,7 +20,7 @@ public class AutoTeamSubCmd extends ViaSubCommand {
public boolean execute(CommandSender sender, String[] args) {
ViaVersionPlugin plugin = (ViaVersionPlugin) ViaVersion.getInstance();
boolean newValue = !plugin.isAutoTeam();
boolean newValue = !ViaVersion.getConfig().isAutoTeam();
plugin.getConfig().set("auto-team", newValue);
plugin.saveConfig();
sendMessage(sender, "&6We will %s", (newValue ? "&aautomatically team players" : "&cno longer auto team players"));
@@ -20,7 +20,7 @@ public class DontBugMeSubCmd extends ViaSubCommand {
public boolean execute(CommandSender sender, String[] args) {
ViaVersionPlugin plugin = (ViaVersionPlugin) ViaVersion.getInstance();
boolean newValue = !plugin.isCheckForUpdates();
boolean newValue = !ViaVersion.getConfig().isCheckForUpdates();
plugin.getConfig().set("checkforupdates", newValue);
plugin.saveConfig();
sendMessage(sender, "&6We will %snotify you about updates.", (newValue ? "&a" : "&cnot "));
@@ -35,6 +35,8 @@ public class PPSSubCmd extends ViaSubCommand {
long max = 0;
for (Player p : Bukkit.getOnlinePlayers()) {
if (!ViaVersion.getInstance().isPorted(p))
continue;
int playerVersion = ViaVersion.getInstance().getPlayerVersion(p);
if (!playerVersions.containsKey(playerVersion))
playerVersions.put(playerVersion, new HashSet<String>());
@@ -20,7 +20,7 @@ public class ReloadSubCmd extends ViaSubCommand {
public boolean execute(CommandSender sender, String[] args) {
ViaVersionPlugin plugin = (ViaVersionPlugin) ViaVersion.getInstance();
plugin.generateConfig();
plugin.getConf().generateConfig();
sendMessage(sender, "&6Configuration successfully reloaded! Some features may need a restart.");
return true;
}
@@ -39,7 +39,7 @@ public class ViaDecodeHandler extends ByteToMessageDecoder {
boolean second = info.incrementReceived();
// Check PPS
if(second) {
if (((ViaVersionPlugin) ViaVersion.getConfig()).handlePPS(info))
if (((ViaVersionPlugin) ViaVersion.getInstance()).handlePPS(info))
return;
}
@@ -4,6 +4,7 @@ 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.ViaVersion;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.exception.CancelException;
@@ -11,6 +12,7 @@ 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 ViaEncodeHandler extends MessageToByteEncoder {
@@ -25,6 +27,11 @@ public class ViaEncodeHandler extends MessageToByteEncoder {
@Override
protected void encode(final ChannelHandlerContext ctx, Object o, final ByteBuf bytebuf) throws Exception {
if (ViaVersion.getInstance().isCompatSpigotBuild()) {
Field ver = minecraftEncoder.getClass().getDeclaredField("version");
ver.setAccessible(true);
ver.set(minecraftEncoder, ver.get(this));
}
// handle the packet type
if (!(o instanceof ByteBuf)) {
// call minecraft encoder
@@ -7,6 +7,8 @@ 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 java.lang.reflect.Method;
@@ -36,9 +38,11 @@ public class ViaVersionInitializer extends ChannelInitializer<SocketChannel> {
new ProtocolPipeline(info);
// Add originals
this.method.invoke(this.original, socketChannel);
HandlerConstructor constructor = ClassGenerator.getConstructor();
// Add our transformers
ViaEncodeHandler encoder = new ViaEncodeHandler(info, (MessageToByteEncoder) socketChannel.pipeline().get("encoder"));
ViaDecodeHandler decoder = new ViaDecodeHandler(info, (ByteToMessageDecoder) socketChannel.pipeline().get("decoder"));
MessageToByteEncoder encoder = constructor.newEncodeHandler(info, (MessageToByteEncoder) socketChannel.pipeline().get("encoder"));
ByteToMessageDecoder decoder = constructor.newDecodeHandler(info, (ByteToMessageDecoder) socketChannel.pipeline().get("decoder"));
ViaPacketHandler chunkHandler = new ViaPacketHandler(info);
socketChannel.pipeline().replace("encoder", "encoder", encoder);
@@ -1,5 +1,6 @@
package us.myles.ViaVersion.protocols.base;
import org.apache.commons.lang.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@@ -22,6 +23,7 @@ import us.myles.ViaVersion.packets.State;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
public class BaseProtocol extends Protocol {
@@ -40,6 +42,8 @@ public class BaseProtocol extends Protocol {
try {
JSONObject json = (JSONObject) new JSONParser().parse(originalStatus);
JSONObject version = (JSONObject) json.get("version");
if (ViaVersion.getConfig().isSendSupportedVersions())
version.put("supportedVersions", ViaVersion.getInstance().getSupportedVersions());
if (ProtocolRegistry.SERVER_PROTOCOL == -1) {
Long original = (Long) version.get("protocol");
ProtocolRegistry.SERVER_PROTOCOL = original.intValue();
@@ -83,6 +87,15 @@ public class BaseProtocol extends Protocol {
info.setUsername(wrapper.get(Type.STRING, 1));
// Add to ported clients
((ViaVersionPlugin) ViaVersion.getInstance()).addPortedClient(wrapper.user());
if (ViaVersion.getInstance().isDebug()) {
// Print out the route to console
((ViaVersionPlugin) ViaVersion.getInstance()).getLogger().log(Level.INFO, "{0} logged in with protocol {1}, Route: {2}",
new Object[]{
wrapper.get(Type.STRING, 1),
info.getProtocolVersion(),
StringUtils.join(info.getPipeline().pipes(), ", ")
});
}
}
});
}
@@ -0,0 +1,88 @@
package us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4;
import lombok.Getter;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.minecraft.Position;
import us.myles.ViaVersion.api.type.Type;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class BlockEntity {
@Getter
private static final Map<String, Integer> types = new ConcurrentHashMap<>();
static {
types.put("MobSpawner", 1);
types.put("Control", 2);
types.put("Beacon", 3);
types.put("Skull", 4);
types.put("FlowerPot", 5);
types.put("Banner", 6);
types.put("UNKNOWN", 7);
types.put("EndGateway", 8);
types.put("Sign", 9);
//I didn't see anything that didn't work about chests
// types.put("Chest", -1);
}
public static void handle(List<CompoundTag> tags, UserConnection connection) {
for (CompoundTag tag : tags) {
try {
if (!tag.contains("id"))
throw new Exception("NBT tag not handled because the id key is missing");
String id = (String) tag.get("id").getValue();
if (!types.containsKey(id))
throw new Exception("Not handled id: " + id);
int newId = types.get(id);
if (newId == -1)
continue;
int x = (int) tag.get("x").getValue();
int y = (int) tag.get("y").getValue();
int z = (int) tag.get("z").getValue();
Position pos = new Position((long) x, (long) y, (long) z);
//Sorry, the PacketWrapper class wil handle this in the future
//TODO let the packetwrapper class handle it
if (newId != 9) {
updateBlockEntity(pos, (short) newId, tag, connection);
} else {
String[] lines = new String[4];
for (int i = 1; i < 5; i++)
lines[i - 1] = (String) tag.get("Text" + i).getValue();
updateSign(pos, lines, connection);
}
} catch (Exception e) {
if(ViaVersion.getInstance().isDebug()) {
System.out.println("Block Entity: " + e.getMessage() + ": " + tag);
}
}
}
}
private static void updateBlockEntity(Position pos, short id, CompoundTag tag, UserConnection connection) throws Exception {
PacketWrapper wrapper = new PacketWrapper(0x09, null, connection);
wrapper.write(Type.POSITION, pos);
wrapper.write(Type.UNSIGNED_BYTE, id);
wrapper.write(Type.NBT, tag);
wrapper.send();
}
private static void updateSign(Position pos, String[] lines, UserConnection connection) throws Exception {
PacketWrapper wrapper = new PacketWrapper(0x46, null, connection);
wrapper.write(Type.POSITION, pos);
for (String s : lines)
wrapper.write(Type.STRING, s);
wrapper.send();
}
}
@@ -0,0 +1,19 @@
package us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
import java.util.List;
@Data
@AllArgsConstructor
public class Chunk1_9_3_4 {
private int x;
private int z;
private boolean groundUp;
private int bitmask;
private byte[] sections;
List<CompoundTag> blockEntities;
}
@@ -0,0 +1,48 @@
package us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4;
import io.netty.buffer.ByteBuf;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
import us.myles.ViaVersion.api.type.Type;
import java.util.ArrayList;
import java.util.List;
public class Chunk1_9_3_4Type extends Type<Chunk1_9_3_4> {
public Chunk1_9_3_4Type() {
super("1.9.3 Chunk", Chunk1_9_3_4.class);
}
@Override
public Chunk1_9_3_4 read(ByteBuf input) throws Exception {
int chunkX = input.readInt();
int chunkZ = input.readInt();
boolean groundUp = input.readBoolean();
int primaryBitmask = Type.VAR_INT.read(input);
int size = Type.VAR_INT.read(input);
byte[] sections = new byte[size];
input.readBytes(sections);
int blockEntities = Type.VAR_INT.read(input);
List<CompoundTag> nbtData = new ArrayList<>();
for (int i = 0; i < blockEntities; i++) {
nbtData.add(Type.NBT.read(input));
}
return new Chunk1_9_3_4(chunkX, chunkZ, groundUp, primaryBitmask, sections, nbtData);
}
@Override
public void write(ByteBuf buffer, Chunk1_9_3_4 chunk) throws Exception {
buffer.writeInt(chunk.getX());
buffer.writeInt(chunk.getZ());
buffer.writeBoolean(chunk.isGroundUp());
Type.VAR_INT.write(buffer, chunk.getBitmask());
Type.VAR_INT.write(buffer, chunk.getSections().length);
buffer.writeBytes(chunk.getSections());
// no block entities as it's earlier
}
}
@@ -0,0 +1,71 @@
package us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.minecraft.Position;
import us.myles.ViaVersion.api.protocol.Protocol;
import us.myles.ViaVersion.api.remapper.PacketHandler;
import us.myles.ViaVersion.api.remapper.PacketRemapper;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.packets.State;
public class Protocol1_9_1_2TO1_9_3_4 extends Protocol {
public static Type<Chunk1_9_3_4> CHUNK = new Chunk1_9_3_4Type();
@Override
protected void registerPackets() {
//Unchanged packet structure
registerOutgoing(State.PLAY, 0x46, 0x47); //Sound effect
registerOutgoing(State.PLAY, 0x47, 0x48); //Player list header and footer
registerOutgoing(State.PLAY, 0x48, 0x49); //Collect item
registerOutgoing(State.PLAY, 0x49, 0x4A); //Entity teleport
registerOutgoing(State.PLAY, 0x4A, 0x4B); //Entity properties
registerOutgoing(State.PLAY, 0x4B, 0x4C); //Entity effect
//Update block entity
registerOutgoing(State.PLAY, 0x09, 0x09, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.POSITION); //Position
map(Type.UNSIGNED_BYTE); //Type
map(Type.NBT); //NBT
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
if (wrapper.get(Type.UNSIGNED_BYTE, 0) == 9) {
Position position = wrapper.get(Type.POSITION, 0);
CompoundTag tag = wrapper.get(Type.NBT, 0);
wrapper.clearPacket(); //Clear the packet
wrapper.setId(0x46); //Update sign packet
wrapper.write(Type.POSITION, position); // Position
for (int i = 1; i < 5; i++)
wrapper.write(Type.STRING, (String) tag.get("Text" + i).getValue()); // Sign line
}
}
});
}
});
registerOutgoing(State.PLAY, 0x20, 0x20, new PacketRemapper() {
@Override
public void registerMap() {
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
Chunk1_9_3_4 chunk = wrapper.passthrough(CHUNK);
BlockEntity.handle(chunk.getBlockEntities(), wrapper.user());
}
});
}
});
}
@Override
public void init(UserConnection userConnection) {
}
}
@@ -9,7 +9,7 @@ import us.myles.ViaVersion.packets.State;
public class Protocol1_9_1TO1_9 extends Protocol {
@Override
protected void registerPackets() {
// Currently supports 1.9.1 PRE 2
// Currently supports 1.9.1 and 1.9.2
// Join Game Packet
registerOutgoing(State.PLAY, 0x23, 0x23, new PacketRemapper() {
@Override
@@ -0,0 +1,81 @@
package us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
import org.spacehq.opennbt.tag.builtin.IntTag;
import org.spacehq.opennbt.tag.builtin.StringTag;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.minecraft.Position;
import us.myles.ViaVersion.api.protocol.Protocol;
import us.myles.ViaVersion.api.remapper.PacketHandler;
import us.myles.ViaVersion.api.remapper.PacketRemapper;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.packets.State;
public class Protocol1_9_3TO1_9_1_2 extends Protocol {
@Override
protected void registerPackets() {
//Unchanged packet structure
registerOutgoing(State.PLAY, 0x47, 0x46); //Sound effect
registerOutgoing(State.PLAY, 0x48, 0x47); //Player list header and footer
registerOutgoing(State.PLAY, 0x49, 0x48); //Collect item
registerOutgoing(State.PLAY, 0x4A, 0x49); //Entity teleport
registerOutgoing(State.PLAY, 0x4B, 0x4A); //Entity properties
registerOutgoing(State.PLAY, 0x4C, 0x4B); //Entity effect
//Sign update
registerOutgoing(State.PLAY, 0x46, -1, new PacketRemapper() {
@Override
public void registerMap() {
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
//read data
Position position = wrapper.read(Type.POSITION);
String[] lines = new String[4];
for (int i = 0; i < 4; i++)
lines[i] = wrapper.read(Type.STRING);
wrapper.clearInputBuffer();
//write data
wrapper.setId(0x09); //Update block entity
wrapper.write(Type.POSITION, position); //Block location
wrapper.write(Type.UNSIGNED_BYTE, (short) 9); //Action type (9 update sign)
//Create nbt
CompoundTag tag = new CompoundTag("");
tag.put(new StringTag("id", "Sign"));
tag.put(new IntTag("x", position.getX().intValue()));
tag.put(new IntTag("y", position.getY().intValue()));
tag.put(new IntTag("z", position.getZ().intValue()));
for (int i = 0; i < lines.length; i++)
tag.put(new StringTag("Text" + (i + 1), lines[i]));
wrapper.write(Type.NBT, tag);
}
});
}
});
registerOutgoing(State.PLAY, 0x20, 0x20, new PacketRemapper() {
@Override
public void registerMap() {
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
wrapper.passthroughAll();
wrapper.write(Type.VAR_INT, 0);
}
});
}
});
}
@Override
public void init(UserConnection userConnection) {
}
}
@@ -16,10 +16,7 @@ import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.listeners.*;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.packets.*;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.ClientChunks;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.EntityTracker;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.InventoryTracker;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.MovementTracker;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.*;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.types.MetadataListType;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.types.MetadataType;
@@ -62,9 +59,9 @@ public class Protocol1_9TO1_8 extends Protocol {
}
public static Item getHandItem(final UserConnection info) {
if(HandItemCache.CACHE){
if (HandItemCache.CACHE) {
return HandItemCache.getHandItem(info.get(ProtocolInfo.class).getUuid());
}else {
} else {
try {
return Bukkit.getScheduler().callSyncMethod(Bukkit.getPluginManager().getPlugin("ViaVersion"), new Callable<Item>() {
@Override
@@ -105,9 +102,9 @@ public class Protocol1_9TO1_8 extends Protocol {
plugin.getLogger().info("Enabling PaperSpigot patch: Fixes block placement.");
Bukkit.getPluginManager().registerEvents(new PaperPatch(), plugin);
}
if (plugin.getConfig().getBoolean("simulate-pt", true))
new ViaIdleThread(plugin.getPortedPlayers()).runTaskTimerAsynchronously(plugin, 1L, 1L); // Updates player's idle status
if (plugin.getConfig().getBoolean("item-cache", true)) {
if (plugin.getConf().isStimulatePlayerTick())
new ViaIdleThread(plugin.getPortedPlayers()).runTaskTimer(plugin, 1L, 1L); // Updates player's idle status
if (plugin.getConf().isItemCache()) {
new HandItemCache().runTaskTimerAsynchronously(plugin, 2L, 2L); // Updates player's items :)
HandItemCache.CACHE = true;
}
@@ -133,5 +130,7 @@ public class Protocol1_9TO1_8 extends Protocol {
userConnection.put(new MovementTracker(userConnection));
// Inventory tracker
userConnection.put(new InventoryTracker(userConnection));
// Place block tracker
userConnection.put(new PlaceBlockTracker(userConnection));
}
}
@@ -1,7 +1,10 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8;
import io.netty.channel.ChannelHandlerContext;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.MovementTracker;
@@ -9,18 +12,33 @@ import us.myles.ViaVersion.util.PipelineUtil;
import us.myles.ViaVersion.util.ReflectionUtil;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.UUID;
public class ViaIdleThread extends BukkitRunnable {
private static boolean USE_NMS = true;
private final Map<UUID, UserConnection> portedPlayers;
private final Object idlePacket;
private final Object idlePacket2;
// Used for packet mode
private Object idlePacket;
private Object idlePacket2;
// Use for nms
private Method getHandle;
private Field connection;
private Method handleFlying;
public ViaIdleThread(Map<UUID, UserConnection> portedPlayers) {
USE_NMS = ViaVersion.getConfig().isNMSPlayerTicking();
this.portedPlayers = portedPlayers;
Class<?> idlePacketClass;
try {
idlePacketClass = ReflectionUtil.nms("PacketPlayInFlying");
} catch (ClassNotFoundException e) {
throw new RuntimeException("Couldn't find idle packet, help!", e);
}
try {
Class<?> idlePacketClass = ReflectionUtil.nms("PacketPlayInFlying");
idlePacket = idlePacketClass.newInstance();
idlePacket2 = idlePacketClass.newInstance();
@@ -28,8 +46,27 @@ public class ViaIdleThread extends BukkitRunnable {
flying.setAccessible(true);
flying.set(idlePacket2, true);
} catch (NoSuchFieldException | InstantiationException | IllegalArgumentException | IllegalAccessException | ClassNotFoundException e) {
throw new RuntimeException("Couldn't find/make player idle packet, help!", e);
} catch (NoSuchFieldException | InstantiationException | IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException("Couldn't make player idle packet, help!", e);
}
if (USE_NMS) {
try {
getHandle = ReflectionUtil.obc("entity.CraftPlayer").getDeclaredMethod("getHandle");
} catch (NoSuchMethodException | ClassNotFoundException e) {
throw new RuntimeException("Couldn't find CraftPlayer", e);
}
try {
connection = ReflectionUtil.nms("EntityPlayer").getDeclaredField("playerConnection");
} catch (NoSuchFieldException | ClassNotFoundException e) {
throw new RuntimeException("Couldn't find Player Connection", e);
}
try {
handleFlying = ReflectionUtil.nms("PlayerConnection").getDeclaredMethod("a", idlePacketClass);
} catch (NoSuchMethodException | ClassNotFoundException e) {
throw new RuntimeException("Couldn't find CraftPlayer", e);
}
}
}
@@ -39,15 +76,34 @@ public class ViaIdleThread extends BukkitRunnable {
if (info.get(ProtocolInfo.class).getPipeline().contains(Protocol1_9TO1_8.class)) {
long nextIdleUpdate = info.get(MovementTracker.class).getNextIdlePacket();
if (nextIdleUpdate <= System.currentTimeMillis()) {
ChannelHandlerContext context = PipelineUtil.getContextBefore("decoder", info.getChannel().pipeline());
if (info.getChannel().isOpen()) {
if (context != null) {
if (info.get(MovementTracker.class).isGround()) {
context.fireChannelRead(idlePacket2);
} else {
context.fireChannelRead(idlePacket);
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 {
// Old method using packets.
ChannelHandlerContext context = PipelineUtil.getContextBefore("decoder", info.getChannel().pipeline());
if (context != null) {
if (info.get(MovementTracker.class).isGround()) {
context.fireChannelRead(idlePacket2);
} else {
context.fireChannelRead(idlePacket);
}
info.get(MovementTracker.class).incrementIdlePacket();
}
info.get(MovementTracker.class).incrementIdlePacket();
}
}
}
@@ -0,0 +1,25 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8.chat;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.EntityTracker;
public class ChatRewriter {
public static void toClient(JsonObject obj, UserConnection user) {
//Check gamemode change
if (obj.get("translate") != null && obj.get("translate").getAsString().equals("gameMode.changed")) {
String gameMode = user.get(EntityTracker.class).getGameMode().getText();
JsonObject gameModeObject = new JsonObject();
gameModeObject.addProperty("text", gameMode);
gameModeObject.addProperty("color", "gray");
gameModeObject.addProperty("italic", true);
JsonArray array = new JsonArray();
array.add(gameModeObject);
obj.add("with", array);
}
}
}
@@ -0,0 +1,23 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8.chat;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Getter
public enum GameMode {
SURVIVAL(0, "Survival Mode"),
CREATIVE(1, "Creative Mode"),
ADVENTURE(2, "Adventure Mode"),
SPECTATOR(3, "Spectator Mode");
private final int id;
private final String text;
public static GameMode getById(int id) {
for (GameMode gm : GameMode.values())
if (gm.getId() == id)
return gm;
return null;
}
}
@@ -19,6 +19,7 @@ import org.bukkit.inventory.CraftingInventory;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.ArmorType;
@@ -39,9 +40,12 @@ public class ArmorListener implements Listener {
if (!userConnection.get(ProtocolInfo.class).getPipeline().contains(Protocol1_9TO1_8.class)) return;
int armor = ArmorType.calculateArmorPoints(player.getInventory().getArmorContents());
int protocol = userConnection.get(ProtocolInfo.class).getProtocolVersion();
ByteBuf buf = Unpooled.buffer();
try {
ByteBuf buf = Unpooled.buffer();
Type.VAR_INT.write(buf, 0x4B); // Entity Properties
//TODO possibility to send packets by Protocol version, to let the transformer do the work
Type.VAR_INT.write(buf, (protocol >= ProtocolVersion.v1_9_3.getId()) ? 0x4A : 0x4B); // Entity Properties
Type.VAR_INT.write(buf, player.getEntityId());
buf.writeInt(1); // only 1 property
Type.STRING.write(buf, "generic.armor");
@@ -53,6 +57,7 @@ public class ArmorListener implements Listener {
ViaVersion.getInstance().sendRawPacket(player, buf);
} catch (Exception ignored) {
buf.release();
}
}
@@ -10,6 +10,7 @@ import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
@@ -22,7 +23,7 @@ public class DeathListener implements Listener {
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onDeath(PlayerDeathEvent e) {
Player p = e.getEntity();
if (plugin.isShowNewDeathMessages() && checkGamerule(p.getWorld()) && e.getDeathMessage() != null && checkPipeline(p)) {
if (ViaVersion.getConfig().isShowNewDeathMessages() && checkGamerule(p.getWorld()) && e.getDeathMessage() != null && checkPipeline(p)) {
sendPacket(p, e.getDeathMessage());
}
}
@@ -38,7 +39,7 @@ public class DeathListener implements Listener {
public boolean checkGamerule(World w) {
try {
return Boolean.parseBoolean(w.getGameRuleValue("showDeathMessage"));
return Boolean.parseBoolean(w.getGameRuleValue("showDeathMessages"));
} catch (Exception e) {
return false;
}
@@ -157,7 +157,7 @@ public enum MetaIndex {
}
public static MetaIndex getIndex(EntityType type, int index) {
Class<? extends org.bukkit.entity.Entity> entityClass = type.getEntityClass();
Class<? extends org.bukkit.entity.Entity> entityClass = type == null ? LivingEntity.class : type.getEntityClass();
if (entityClass == null) {
System.out.println("Could not get entity class for " + type);
return null;
@@ -2,25 +2,31 @@ package us.myles.ViaVersion.protocols.protocol1_9to1_8.metadata;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import us.myles.ViaVersion.api.type.Type;
@RequiredArgsConstructor
@Getter
public enum NewType {
Byte(0),
VarInt(1),
Float(2),
String(3),
Chat(4),
Slot(5),
Boolean(6),
Vector3F(7),
Position(8),
OptPosition(9),
Direction(10),
OptUUID(11),
BlockID(12),
Discontinued(99);
Byte(0, Type.BYTE),
VarInt(1, Type.VAR_INT),
Float(2, Type.FLOAT),
String(3, Type.STRING),
Chat(4, Type.STRING),
Slot(5, Type.ITEM),
Boolean(6, Type.BOOLEAN),
Vector3F(7, Type.ROTATION),
Position(8, Type.POSITION),
OptPosition(9, Type.OPTIONAL_POSITION),
Direction(10, Type.VAR_INT),
OptUUID(11, Type.OPTIONAL_UUID),
BlockID(12, Type.VAR_INT),
Discontinued(99, null);
private final int typeID;
private final Type type;
public static NewType byId(int id) {
return values()[id];
}
}
@@ -184,9 +184,10 @@ public class EntityPackets {
EntityTracker tracker = wrapper.user().get(EntityTracker.class);
if (tracker.getClientEntityTypes().containsKey(entityID)) {
MetadataRewriter.transform(tracker.getClientEntityTypes().get(entityID), metadataList);
} else if (!ViaVersion.getConfig().isUnknownEntitiesSuppressed() || ViaVersion.getInstance().isDebug()) {
System.out.println("Unable to find entity for metadata, entity ID: " + entityID);
metadataList.clear();
} else {
// Buffer
tracker.addMetadataToBuffer(entityID, metadataList);
wrapper.cancel();
}
}
});
@@ -207,8 +208,9 @@ public class EntityPackets {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
List<Metadata> metadataList = wrapper.get(Protocol1_9TO1_8.METADATA_LIST, 0);
if (metadataList.size() == 0)
if (metadataList.size() == 0) {
wrapper.cancel();
}
}
});
}
@@ -243,9 +245,6 @@ public class EntityPackets {
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
// int id = wrapper.read(Type.VAR_INT);
// CompoundTag tag = wrapper.read(Type.NBT);
// System.out.println(id + " - " + tag);
wrapper.cancel();
}
});
@@ -1,5 +1,7 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8.packets;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
import us.myles.ViaVersion.ViaVersionPlugin;
@@ -13,8 +15,11 @@ import us.myles.ViaVersion.api.remapper.ValueCreator;
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.ItemRewriter;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.PlayerMovementMapper;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.chat.ChatRewriter;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.chat.GameMode;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.ClientChunks;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.EntityTracker;
@@ -26,6 +31,19 @@ public class PlayerPackets {
public void registerMap() {
map(Type.STRING, Protocol1_9TO1_8.FIX_JSON); // 0 - Chat Message (json)
map(Type.BYTE); // 1 - Chat Positon
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
try {
JsonObject obj = (JsonObject) new JsonParser().parse(wrapper.get(Type.STRING, 0));
ChatRewriter.toClient(obj, wrapper.user());
wrapper.set(Type.STRING, 0, obj.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
});
@@ -159,6 +177,14 @@ public class PlayerPackets {
map(Type.UNSIGNED_BYTE); // 4 - Max Players (Tab)
map(Type.STRING); // 5 - Level Type
map(Type.BOOLEAN); // 6 - Reduced Debug info
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
EntityTracker tracker = wrapper.user().get(EntityTracker.class);
tracker.setGameMode(GameMode.getById(wrapper.get(Type.UNSIGNED_BYTE, 0))); //Set player gamemode
}
});
}
});
@@ -228,6 +254,31 @@ public class PlayerPackets {
wrapper.passthrough(Type.REMAINING_BYTES); // This is so ugly, :(
wrapper.write(Type.VAR_INT, 0);
}
if (name.equalsIgnoreCase("MC|TrList")) {
wrapper.passthrough(Type.INT); // ID
Short size = wrapper.passthrough(Type.UNSIGNED_BYTE);
for (int i = 0; i < size; ++i) {
Item item1 = wrapper.passthrough(Type.ITEM);
ItemRewriter.toClient(item1);
Item item2 = wrapper.passthrough(Type.ITEM);
ItemRewriter.toClient(item2);
boolean present = wrapper.passthrough(Type.BOOLEAN);
if (present) {
Item item3 = wrapper.passthrough(Type.ITEM);
ItemRewriter.toClient(item3);
}
wrapper.passthrough(Type.BOOLEAN);
wrapper.passthrough(Type.INT);
wrapper.passthrough(Type.INT);
}
}
}
});
}
@@ -257,6 +308,11 @@ public class PlayerPackets {
protocol.registerOutgoing(State.PLAY, 0x07, 0x33, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.INT); // 0 - Dimension
map(Type.UNSIGNED_BYTE); // 1 - Difficulty
map(Type.UNSIGNED_BYTE); // 2 - GameMode
map(Type.STRING); // 3 - Level Type
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
@@ -264,6 +320,28 @@ public class PlayerPackets {
ClientChunks cc = wrapper.user().get(ClientChunks.class);
cc.getBulkChunks().clear();
cc.getLoadedChunks().clear();
int gamemode = wrapper.get(Type.UNSIGNED_BYTE, 0);
wrapper.user().get(EntityTracker.class).setGameMode(GameMode.getById(gamemode));
}
});
}
});
// Change Game State Packet
protocol.registerOutgoing(State.PLAY, 0x2B, 0x1E, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.UNSIGNED_BYTE); //0 - Reason
map(Type.FLOAT); //1 - Value
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
if (wrapper.get(Type.UNSIGNED_BYTE, 0) == 3) { //Change gamemode
int gamemode = wrapper.get(Type.FLOAT, 0).intValue();
wrapper.user().get(EntityTracker.class).setGameMode(GameMode.getById(gamemode));
}
}
});
}
@@ -307,7 +385,6 @@ public class PlayerPackets {
protocol.registerOutgoing(State.PLAY, 0x00, 0x1F); // Keep Alive Packet
protocol.registerOutgoing(State.PLAY, 0x48, 0x32); // Resource Pack Send Packet
protocol.registerOutgoing(State.PLAY, 0x43, 0x36); // Camera Packet
protocol.registerOutgoing(State.PLAY, 0x2B, 0x1E); // Change Game State Packet
protocol.registerOutgoing(State.PLAY, 0x3D, 0x38); // Display Scoreboard Packet
protocol.registerOutgoing(State.PLAY, 0x3B, 0x3F); // Scoreboard Objective Packet
@@ -55,6 +55,7 @@ public class SpawnPackets {
int typeID = wrapper.get(Type.BYTE, 0);
EntityTracker tracker = wrapper.user().get(EntityTracker.class);
tracker.getClientEntityTypes().put(entityID, EntityUtil.getTypeFromID(typeID, true));
tracker.sendMetadataBuffer(entityID);
}
});
@@ -129,6 +130,7 @@ public class SpawnPackets {
int entityID = wrapper.get(Type.VAR_INT, 0);
EntityTracker tracker = wrapper.user().get(EntityTracker.class);
tracker.getClientEntityTypes().put(entityID, EntityType.EXPERIENCE_ORB);
tracker.sendMetadataBuffer(entityID);
}
});
@@ -154,6 +156,7 @@ public class SpawnPackets {
int entityID = wrapper.get(Type.VAR_INT, 0);
EntityTracker tracker = wrapper.user().get(EntityTracker.class);
tracker.getClientEntityTypes().put(entityID, EntityType.LIGHTNING);
tracker.sendMetadataBuffer(entityID);
}
});
@@ -187,6 +190,7 @@ public class SpawnPackets {
int typeID = wrapper.get(Type.UNSIGNED_BYTE, 0);
EntityTracker tracker = wrapper.user().get(EntityTracker.class);
tracker.getClientEntityTypes().put(entityID, EntityUtil.getTypeFromID(typeID, false));
tracker.sendMetadataBuffer(entityID);
}
});
@@ -243,6 +247,7 @@ public class SpawnPackets {
int entityID = wrapper.get(Type.VAR_INT, 0);
EntityTracker tracker = wrapper.user().get(EntityTracker.class);
tracker.getClientEntityTypes().put(entityID, EntityType.PAINTING);
tracker.sendMetadataBuffer(entityID);
}
});
@@ -276,6 +281,7 @@ public class SpawnPackets {
int entityID = wrapper.get(Type.VAR_INT, 0);
EntityTracker tracker = wrapper.user().get(EntityTracker.class);
tracker.getClientEntityTypes().put(entityID, EntityType.PLAYER);
tracker.sendMetadataBuffer(entityID);
}
});
@@ -6,6 +6,7 @@ import org.spacehq.opennbt.tag.builtin.StringTag;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.minecraft.Position;
import us.myles.ViaVersion.api.minecraft.chunks.Chunk;
import us.myles.ViaVersion.api.minecraft.item.Item;
import us.myles.ViaVersion.api.protocol.Protocol;
import us.myles.ViaVersion.api.remapper.PacketHandler;
@@ -13,13 +14,13 @@ import us.myles.ViaVersion.api.remapper.PacketRemapper;
import us.myles.ViaVersion.api.remapper.ValueCreator;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.packets.State;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.ArmorType;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.ItemRewriter;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.sounds.Effect;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.sounds.SoundEffect;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.ClientChunks;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.EntityTracker;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.PlaceBlockTracker;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.types.ChunkType;
public class WorldPackets {
@@ -114,7 +115,10 @@ public class WorldPackets {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
ClientChunks clientChunks = wrapper.user().get(ClientChunks.class);
wrapper.passthrough(new ChunkType(clientChunks));
Chunk chunk = wrapper.passthrough(new ChunkType(clientChunks));
if (chunk.isUnloadPacket())
wrapper.setId(0x1D);
// eat any other data (Usually happens with unload packets)
wrapper.read(Type.REMAINING_BYTES);
}
@@ -217,7 +221,7 @@ public class WorldPackets {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
int status = wrapper.get(Type.UNSIGNED_BYTE, 0);
if (status == 4)
if (status == 6)
wrapper.cancel();
}
});
@@ -226,7 +230,7 @@ public class WorldPackets {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
int status = wrapper.get(Type.UNSIGNED_BYTE, 0);
if (status == 4) {
if (status == 5 || status == 4 || status == 3) {
EntityTracker entityTracker = wrapper.user().get(EntityTracker.class);
if (entityTracker.isBlocking()) {
entityTracker.setBlocking(false);
@@ -345,32 +349,12 @@ public class WorldPackets {
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
Item item = wrapper.get(Type.ITEM, 0);
if (item != null) {
Material m = Material.getMaterial(item.getId());
if (m != null) {
// Prevent special items from sending certain info
// Books
boolean special = m == Material.WRITTEN_BOOK;
// Buckets
special = special || m == Material.WATER_BUCKET || m == Material.LAVA_BUCKET || m == Material.BUCKET;
// Food
special = special || m.isEdible();
// Potions
special = special || m == Material.POTION || m == Material.GLASS_BOTTLE;
// Projectiles
special = special || m == Material.BOW;
special = special || m == Material.SNOW_BALL || m == Material.EGG || m == Material.EXP_BOTTLE || m == Material.ENDER_PEARL || m == Material.EYE_OF_ENDER;
// Armour
special = special || ArmorType.isArmor(m);
// Don't send data if special
if (special && m != Material.AIR) {
EntityTracker tracker = wrapper.user().get(EntityTracker.class);
tracker.setLastPlaceBlock(wrapper.user().getReceivedPackets());
}
}
}
Position position = wrapper.get(Type.POSITION, 0);
PlaceBlockTracker tracker = wrapper.user().get(PlaceBlockTracker.class);
if (tracker.getLastPlacedPosition() != null && tracker.getLastPlacedPosition().equals(position) && !tracker.isExpired(50))
wrapper.cancel();
tracker.updateTime();
tracker.setLastPlacedPosition(position);
}
});
@@ -4,10 +4,12 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import lombok.Getter;
import org.bukkit.Bukkit;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.data.StoredObject;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.util.ReflectionUtil;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
@@ -17,11 +19,15 @@ public class ClientChunks extends StoredObject {
// 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"));
obfuscateRef = Class.forName("org.spigotmc.AntiXray").getMethod("obfuscate", int.class, int.class, int.class, byte[].class, ReflectionUtil.nms("World"));
worldRef = ReflectionUtil.nms("World");
} catch (Exception e) {
Bukkit.getLogger().log(Level.WARNING, "Failed to initialise chunk reflection", e);
}
@@ -44,6 +50,24 @@ public class ClientChunks extends StoredObject {
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
try {
Object world = mapChunkBulkRef.getFieldValue("world", packet, 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);
Object b = ReflectionUtil.get(chunkMaps[i], "b", Object.class);
Object a = ReflectionUtil.get(chunkMaps[i], "a", Object.class);
obfuscateRef.invoke(antiXrayInstance, xcoords[i], zcoords[i], b, a, world);
}
} catch (Exception e) {
// not spigot, or it failed.
}
}
for (int i = 0; i < chunkMaps.length; i++) {
int x = xcoords[i];
int z = zcoords[i];
@@ -2,14 +2,12 @@ package us.myles.ViaVersion.protocols.protocol1_9to1_8.storage;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Sets;
import io.netty.buffer.ByteBuf;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.boss.BossBar;
@@ -22,19 +20,24 @@ import us.myles.ViaVersion.api.minecraft.item.Item;
import us.myles.ViaVersion.api.minecraft.metadata.Metadata;
import us.myles.ViaVersion.api.type.Type;
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.chat.GameMode;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.metadata.MetadataRewriter;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.metadata.NewType;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@Getter
public class EntityTracker extends StoredObject {
private final Map<Integer, UUID> uuidMap = new HashMap<>();
private final Map<Integer, EntityType> clientEntityTypes = new HashMap<>();
private final Map<Integer, Integer> vehicleMap = new HashMap<>();
private final Map<Integer, BossBar> bossBarMap = new HashMap<>();
private final Set<Integer> validBlocking = new HashSet<>();
private final Set<Integer> knownHolograms = new HashSet<>();
private final Map<Integer, UUID> uuidMap = new ConcurrentHashMap<>();
private final Map<Integer, EntityType> clientEntityTypes = new ConcurrentHashMap<>();
private final Map<Integer, List<Metadata>> metadataBuffer = new ConcurrentHashMap<>();
private final Map<Integer, Integer> vehicleMap = new ConcurrentHashMap<>();
private final Map<Integer, BossBar> bossBarMap = new ConcurrentHashMap<>();
private final Set<Integer> validBlocking = Sets.newConcurrentHashSet();
private final Set<Integer> knownHolograms = Sets.newConcurrentHashSet();
private final Cache<Position, Material> blockInteractions = CacheBuilder.newBuilder().maximumSize(10).expireAfterAccess(250, TimeUnit.MILLISECONDS).build();
@Setter
private boolean blocking = false;
@@ -47,6 +50,8 @@ public class EntityTracker extends StoredObject {
@Setter
private Position currentlyDigging = null;
private boolean teamExists = false;
@Setter
private GameMode gameMode;
public EntityTracker(UserConnection user) {
super(user);
@@ -84,6 +89,7 @@ public class EntityTracker extends StoredObject {
uuidMap.remove(entityID);
validBlocking.remove(entityID);
knownHolograms.remove(entityID);
metadataBuffer.remove(entityID);
BossBar bar = bossBarMap.remove(entityID);
if (bar != null) {
@@ -110,7 +116,9 @@ public class EntityTracker extends StoredObject {
}
public void handleMetadata(int entityID, List<Metadata> metadataList) {
if (!clientEntityTypes.containsKey(entityID)) return;
if (!clientEntityTypes.containsKey(entityID)) {
return;
}
EntityType type = clientEntityTypes.get(entityID);
for (Metadata metadata : new ArrayList<>(metadataList)) {
@@ -135,11 +143,18 @@ public class EntityTracker extends StoredObject {
}
}
//ECHOPET Patch
if (type == EntityType.HORSE) {
// Wrong metadata value from EchoPet, patch since it's discontinued. (https://github.com/DSH105/EchoPet/blob/06947a8b08ce40be9a518c2982af494b3b99d140/modules/API/src/main/java/com/dsh105/echopet/compat/api/entity/HorseArmour.java#L22)
if (metadata.getId() == 16 && (int) metadata.getValue() == Integer.MIN_VALUE)
metadata.setValue(0);
}
if (type == EntityType.PLAYER) {
if (metadata.getId() == 0) {
// Byte
byte data = (byte) metadata.getValue();
if (entityID != getEntityID() && ((ViaVersionPlugin) ViaVersion.getInstance()).isShieldBlocking()) {
if (entityID != getEntityID() && ViaVersion.getConfig().isShieldBlocking()) {
if ((data & 0x10) == 0x10) {
if (validBlocking.contains(entityID)) {
Item shield = new Item((short) 442, (byte) 1, (short) 0, null);
@@ -151,7 +166,7 @@ public class EntityTracker extends StoredObject {
}
}
}
if (type == EntityType.ARMOR_STAND && ((ViaVersionPlugin) ViaVersion.getInstance()).isHologramPatch()) {
if (type == EntityType.ARMOR_STAND && ViaVersion.getConfig().isHologramPatch()) {
if (metadata.getId() == 0 && getMetaByIndex(metadataList, 10) != null) {
Metadata meta = getMetaByIndex(metadataList, 10); //Only happens if the armorstand is small
byte data = (byte) metadata.getValue();
@@ -166,7 +181,7 @@ public class EntityTracker extends StoredObject {
Type.VAR_INT.write(buf, 0x25); // Relative Move Packet
Type.VAR_INT.write(buf, entityID);
buf.writeShort(0);
buf.writeShort((short) (128D * (((ViaVersionPlugin) ViaVersion.getInstance()).getHologramYOffset() * 32D)));
buf.writeShort((short) (128D * (ViaVersion.getConfig().getHologramYOffset() * 32D)));
buf.writeShort(0);
buf.writeBoolean(true);
getUser().sendRawPacket(buf, false);
@@ -176,9 +191,9 @@ public class EntityTracker extends StoredObject {
}
}
}
Player player = Bukkit.getPlayer(getUser().get(ProtocolInfo.class).getUuid());
UUID uuid = getUser().get(ProtocolInfo.class).getUuid();
// Boss bar
if (((ViaVersionPlugin) ViaVersion.getInstance()).isBossbarPatch()) {
if (ViaVersion.getConfig().isBossbarPatch()) {
if (type == EntityType.ENDER_DRAGON || type == EntityType.WITHER) {
if (metadata.getId() == 2) {
BossBar bar = bossBarMap.get(entityID);
@@ -187,12 +202,12 @@ public class EntityTracker extends StoredObject {
if (bar == null) {
bar = ViaVersion.getInstance().createBossBar(title, BossColor.PINK, BossStyle.SOLID);
bossBarMap.put(entityID, bar);
bar.addPlayer(player);
bar.addPlayer(uuid);
bar.show();
} else {
bar.setTitle(title);
}
} else if (metadata.getId() == 6 && !((ViaVersionPlugin) ViaVersion.getInstance()).isBossbarAntiflicker()) { // If anti flicker is enabled, don't update health
} else if (metadata.getId() == 6 && !ViaVersion.getConfig().isBossbarAntiflicker()) { // If anti flicker is enabled, don't update health
BossBar bar = bossBarMap.get(entityID);
// Make health range between 0 and 1
float maxHealth = type == EntityType.ENDER_DRAGON ? 200.0f : 300.0f;
@@ -201,7 +216,7 @@ public class EntityTracker extends StoredObject {
String title = type == EntityType.ENDER_DRAGON ? "Ender Dragon" : "Wither";
bar = ViaVersion.getInstance().createBossBar(title, health, BossColor.PINK, BossStyle.SOLID);
bossBarMap.put(entityID, bar);
bar.addPlayer(player);
bar.addPlayer(uuid);
bar.show();
} else {
bar.setHealth(health);
@@ -248,4 +263,30 @@ public class EntityTracker extends StoredObject {
e.printStackTrace();
}
}
public void addMetadataToBuffer(int entityID, List<Metadata> metadataList) {
if (metadataBuffer.containsKey(entityID)) {
metadataBuffer.get(entityID).addAll(metadataList);
} else {
metadataBuffer.put(entityID, metadataList);
}
}
public void sendMetadataBuffer(int entityID) {
if (metadataBuffer.containsKey(entityID)) {
PacketWrapper wrapper = new PacketWrapper(0x39, null, getUser());
wrapper.write(Type.VAR_INT, entityID);
wrapper.write(Protocol1_9TO1_8.METADATA_LIST, metadataBuffer.get(entityID));
MetadataRewriter.transform(getClientEntityTypes().get(entityID), metadataBuffer.get(entityID));
handleMetadata(entityID, metadataBuffer.get(entityID));
if (metadataBuffer.get(entityID).size() > 0) {
try {
wrapper.send();
} catch (Exception e) {
e.printStackTrace();
}
}
metadataBuffer.remove(entityID);
}
}
}
@@ -0,0 +1,26 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8.storage;
import lombok.Getter;
import lombok.Setter;
import us.myles.ViaVersion.api.data.StoredObject;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.minecraft.Position;
@Getter
public class PlaceBlockTracker extends StoredObject {
private long lastPlaceTimestamp = System.currentTimeMillis();
@Setter
private Position lastPlacedPosition = null;
public PlaceBlockTracker(UserConnection user) {
super(user);
}
public boolean isExpired(int ms) {
return System.currentTimeMillis() > (lastPlaceTimestamp + ms);
}
public void updateTime() {
lastPlaceTimestamp = System.currentTimeMillis();
}
}
@@ -128,11 +128,6 @@ public class ChunkType extends PartialType<Chunk, ClientChunks> {
@Override
public void write(ByteBuf output, ClientChunks param, Chunk chunk) throws Exception {
if (chunk.isUnloadPacket()) {
output.clear();
Type.VAR_INT.write(output, 0x1D); // Unload packet ID
}
// Write primary info
output.writeInt(chunk.getX());
output.writeInt(chunk.getZ());
@@ -2,16 +2,13 @@ package us.myles.ViaVersion.protocols.protocol1_9to1_8.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.minecraft.metadata.Metadata;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.api.type.types.minecraft.MetaListTypeTemplate;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
import java.util.ArrayList;
import java.util.List;
public class MetadataListType extends Type<List<Metadata>> {
public MetadataListType() {
super("Metadata List", List.class);
}
public class MetadataListType extends MetaListTypeTemplate {
@Override
public List<Metadata> read(ByteBuf buffer) throws Exception {
@@ -3,14 +3,10 @@ package us.myles.ViaVersion.protocols.protocol1_9to1_8.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.minecraft.metadata.Metadata;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.api.type.types.minecraft.MetaTypeTemplate;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.metadata.MetadataTypes;
public class MetadataType extends Type<Metadata> {
public MetadataType() {
super(Metadata.class);
}
public class MetadataType extends MetaTypeTemplate {
@Override
public Metadata read(ByteBuf buffer) throws Exception {
@@ -0,0 +1,33 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_9_1;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.protocol.Protocol;
import us.myles.ViaVersion.api.remapper.PacketRemapper;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.packets.State;
public class Protocol1_9TO1_9_1 extends Protocol {
@Override
protected void registerPackets() {
// Currently supports 1.9.1 and 1.9.2
// Join Game Packet
registerOutgoing(State.PLAY, 0x23, 0x23, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.INT); // 0 - Player ID
map(Type.UNSIGNED_BYTE); // 1 - Player Gamemode
// 1.9.1 PRE 2 Changed this
map(Type.INT, Type.BYTE); // 2 - Player Dimension
map(Type.UNSIGNED_BYTE); // 3 - World Difficulty
map(Type.UNSIGNED_BYTE); // 4 - Max Players (Tab)
map(Type.STRING); // 5 - Level Type
map(Type.BOOLEAN); // 6 - Reduced Debug info
}
});
}
@Override
public void init(UserConnection userConnection) {
}
}
@@ -0,0 +1,163 @@
package us.myles.ViaVersion.protocols.protocolsnapshotto1_9_3;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.minecraft.metadata.Metadata;
import us.myles.ViaVersion.api.protocol.Protocol;
import us.myles.ViaVersion.api.remapper.PacketHandler;
import us.myles.ViaVersion.api.remapper.PacketRemapper;
import us.myles.ViaVersion.api.remapper.ValueTransformer;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.packets.State;
import us.myles.ViaVersion.protocols.protocolsnapshotto1_9_3.storage.ResourcePackTracker;
import us.myles.ViaVersion.protocols.protocolsnapshotto1_9_3.types.MetaListSnapshotType;
import us.myles.ViaVersion.protocols.protocolsnapshotto1_9_3.types.MetaSnapshotType;
import java.util.List;
public class ProtocolSnapshotTo1_9_3_4 extends Protocol {
public static final Type<List<Metadata>> METADATA_LIST = new MetaListSnapshotType();
public static final Type<Metadata> METADATA = new MetaSnapshotType();
public static ValueTransformer<Short, Float> toNewPitch = new ValueTransformer<Short, Float>(Type.FLOAT) {
@Override
public Float transform(PacketWrapper wrapper, Short inputValue) throws Exception {
return inputValue / 63.5F;
}
};
@Override
protected void registerPackets() {
// Named sound effect
registerOutgoing(State.PLAY, 0x19, 0x19, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.STRING); // 0 - Sound name
map(Type.VAR_INT); // 1 - Sound Category
map(Type.INT); // 2 - x
map(Type.INT); // 3 - y
map(Type.INT); // 4 - z
map(Type.FLOAT); // 5 - Volume
map(Type.UNSIGNED_BYTE, toNewPitch); // 6 - Pitch
}
});
// Sound effect
registerOutgoing(State.PLAY, 0x46, 0x46, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.VAR_INT); // 0 - Sound name
map(Type.VAR_INT); // 1 - Sound Category
map(Type.INT); // 2 - x
map(Type.INT); // 3 - y
map(Type.INT); // 4 - z
map(Type.FLOAT); // 5 - Volume
map(Type.UNSIGNED_BYTE, toNewPitch); // 6 - Pitch
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
int id = wrapper.get(Type.VAR_INT, 0);
wrapper.set(Type.VAR_INT, 0, getNewSoundId(id));
}
});
}
});
// Metadata packet
registerOutgoing(State.PLAY, 0x39, 0x39, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.VAR_INT); // 0 - Entity ID
map(METADATA_LIST); // 1 - Metadata list
}
});
// Spawn Mob
registerOutgoing(State.PLAY, 0x03, 0x03, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.VAR_INT); // 0 - Entity id
map(Type.UUID); // 1 - UUID
map(Type.UNSIGNED_BYTE); // 2 - Entity Type
map(Type.DOUBLE); // 3 - X
map(Type.DOUBLE); // 4 - Y
map(Type.DOUBLE); // 5 - Z
map(Type.BYTE); // 6 - Yaw
map(Type.BYTE); // 7 - Pitch
map(Type.BYTE); // 8 - Head Pitch
map(Type.SHORT); // 9 - Velocity X
map(Type.SHORT); // 10 - Velocity Y
map(Type.SHORT); // 11 - Velocity Z
map(METADATA_LIST); // 12 - Metadata
}
});
// Spawn Player
registerOutgoing(State.PLAY, 0x05, 0x05, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.VAR_INT); // 0 - Entity ID
map(Type.UUID); // 1 - Player UUID
map(Type.DOUBLE); // 2 - X
map(Type.DOUBLE); // 3 - Y
map(Type.DOUBLE); // 4 - Z
map(Type.BYTE); // 5 - Yaw
map(Type.BYTE); // 6 - Pitch
map(METADATA_LIST); // 7 - Metadata list
}
});
// Packet Send ResourcePack
registerOutgoing(State.PLAY, 0x32, 0x32, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.STRING); // 0 - URL
map(Type.STRING); // 1 - Hash
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
ResourcePackTracker tracker = wrapper.user().get(ResourcePackTracker.class);
tracker.setLastHash(wrapper.get(Type.STRING, 1)); // Store the hash for resourcepack status
}
});
}
});
// Packet ResourcePack status
registerIncoming(State.PLAY, 0x16, 0x16, new PacketRemapper() {
@Override
public void registerMap() {
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
ResourcePackTracker tracker = wrapper.user().get(ResourcePackTracker.class);
wrapper.write(Type.STRING, tracker.getLastHash());
wrapper.write(Type.VAR_INT, wrapper.read(Type.VAR_INT));
}
});
}
});
}
public int getNewSoundId(int id) { //TODO Make it better, suggestions are welcome. It's ugly and hardcoded now.
int newId = id;
if (id >= 24) //Blame the enchantment table sound
newId += 1;
if (id >= 248) //Blame the husk
newId += 4;
if (id >= 296) //Blame the polar bear
newId += 6;
if (id >= 354) //Blame the stray
newId += 4;
if (id >= 372) //Blame the wither skeleton
newId += 4;
return newId;
}
@Override
public void init(UserConnection userConnection) {
userConnection.put(new ResourcePackTracker(userConnection));
}
}
@@ -0,0 +1,18 @@
package us.myles.ViaVersion.protocols.protocolsnapshotto1_9_3.storage;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import us.myles.ViaVersion.api.data.StoredObject;
import us.myles.ViaVersion.api.data.UserConnection;
@Getter
@Setter
@ToString
public class ResourcePackTracker extends StoredObject {
private String lastHash = "";
public ResourcePackTracker(UserConnection user) {
super(user);
}
}
@@ -0,0 +1,41 @@
package us.myles.ViaVersion.protocols.protocolsnapshotto1_9_3.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.minecraft.metadata.Metadata;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.api.type.types.minecraft.MetaListTypeTemplate;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.metadata.NewType;
import us.myles.ViaVersion.protocols.protocolsnapshotto1_9_3.ProtocolSnapshotTo1_9_3_4;
import java.util.ArrayList;
import java.util.List;
public class MetaListSnapshotType extends MetaListTypeTemplate {
@Override
public List<Metadata> read(ByteBuf buffer) throws Exception {
List<Metadata> list = new ArrayList<>();
Metadata meta;
do {
meta = ProtocolSnapshotTo1_9_3_4.METADATA.read(buffer);
if (meta != null)
list.add(meta);
} while (meta != null);
return list;
}
@Override
public void write(ByteBuf buffer, List<Metadata> object) throws Exception {
for (Metadata m : object) {
if (m.getId() >= 5)
m.setId(m.getId() + 1);
if (m.getId() == 4)
ProtocolSnapshotTo1_9_3_4.METADATA.write(buffer, new Metadata(5, NewType.Boolean.getTypeID(), Type.BOOLEAN, false)); // No gravity metadata
ProtocolSnapshotTo1_9_3_4.METADATA.write(buffer, m);
}
// Write end of list
ProtocolSnapshotTo1_9_3_4.METADATA.write(buffer, null);
}
}
@@ -0,0 +1,30 @@
package us.myles.ViaVersion.protocols.protocolsnapshotto1_9_3.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.minecraft.metadata.Metadata;
import us.myles.ViaVersion.api.type.types.minecraft.MetaTypeTemplate;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.metadata.NewType;
public class MetaSnapshotType extends MetaTypeTemplate {
@Override
public Metadata read(ByteBuf buffer) throws Exception {
short index = buffer.readUnsignedByte();
if (index == 0xff) return null; //End of metadata
NewType type = NewType.byId(buffer.readByte());
return new Metadata(index, type.getTypeID(), type.getType(), type.getType().read(buffer));
}
@Override
public void write(ByteBuf buffer, Metadata object) throws Exception {
if (object == null) {
buffer.writeByte(255);
} else {
buffer.writeByte(object.getId());
buffer.writeByte(object.getTypeID());
object.getType().write(buffer, object.getValue());
}
}
}
@@ -5,6 +5,7 @@ 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 {
@@ -14,7 +15,7 @@ public class UpdateListener implements Listener {
@EventHandler
public void onJoin(PlayerJoinEvent e) {
if (e.getPlayer().hasPermission("viaversion.update")
&& plugin.isCheckForUpdates()) {
&& ViaVersion.getConfig().isCheckForUpdates()) {
UpdateUtil.sendUpdateMessage(e.getPlayer().getUniqueId(), plugin);
}
}
@@ -60,6 +60,13 @@ public class ReflectionUtil {
return (T) field.get(o);
}
public static <T> T getPublic(Object o, String f, Class<T> t) throws NoSuchFieldException, IllegalAccessException {
Field field = o.getClass().getField(f);
field.setAccessible(true);
return (T) field.get(o);
}
public static void set(Object o, String f, Object value) throws NoSuchFieldException, IllegalAccessException {
Field field = o.getClass().getDeclaredField(f);
field.setAccessible(true);
+4
View File
@@ -0,0 +1,4 @@
name: ViaVersion
main: us.myles.ViaVersion.Bungee
author: _MylesC
version: ${project.version}
+53 -32
View File
@@ -1,36 +1,22 @@
# Thanks for downloading ViaVersion
# Ensure you look through all these options
# If you need help:
# viaversion.com - Discussion tab
# IRC - https://elmer.spi.gt/iris/?nick=&channels=viaversion #viaversion on irc.spi.gt
#
#----------------------------------------------------------#
# GLOBAL OPTIONS #
#----------------------------------------------------------#
#
# Should ViaVersion check for updates?
checkforupdates: true
# No collide options, these allow you to configure how collision works.
# Do you want us to prevent collision?
prevent-collision: true
# If the above is true, should we automatically team players until you do?
auto-team: true
# When enabled if certain metadata can't be read we won't tell you about it
suppress-metadata-errors: false
# When enabled 1.9 will be able to block by using shields
shield-blocking: true
# Should we enable our hologram patch?
# If they're in the wrong place enable this
hologram-patch: false
# This is the offset, should work as default when enabled.
hologram-y: -1
# Enable player tick simulation, this fixes eating, drinking, nether portals.
simulate-pt: true
# Should we patch boss bars so they work? (Default: true, disable if you're having issues)
bossbar-patch: true
# If your boss bar flickers on 1.9, set this to 'true'. It will keep all boss bars on 100% (not recommended)
bossbar-anti-flicker: false
# This will show the new effect indicator in the top-right corner for 1.9 players.
use-new-effect-indicator: true
# Show the new death messages for 1.9 on the death screen
use-new-deathmessages: false
# This will suppress the following error: 'Unable to get entity for ID: xxxx'
# This error message means one of you plugins is sending bad packets!
suppress-entityid-errors: false
# Our patch for block breaking issue, if you have issues with block updates then disable this.
block-break-patch: true
# Should we cache our items, this will prevent server from being lagged out, however the cost is a constant task caching items
item-cache: true
# Send the supported versions with the Status (Ping) response packet
send-supported-versions: false
#
#----------------------------------------------------------#
# GLOBAL PACKET LIMITER #
#----------------------------------------------------------#
#
# Anti-Cheat, Packets Per Second (PPS) limiter
# Clients by default send around 20-90 packets per second.
@@ -49,4 +35,39 @@ tracking-warning-pps: 120
# How many warnings over the interval can we have
# This can never be higher than "tracking-interval"
tracking-max-warnings: 4
tracking-max-kick-msg: "You are sending too many packets, :("
tracking-max-kick-msg: "You are sending too many packets, :("
#
#----------------------------------------------------------#
# 1.9 & 1.10 CLIENTS ON 1.8 SERVERS OPTIONS #
#----------------------------------------------------------#
#
# No collide options, these allow you to configure how collision works.
# Do you want us to prevent collision?
prevent-collision: true
# If the above is true, should we automatically team players until you do?
auto-team: true
# When enabled if certain metadata can't be read we won't tell you about it
suppress-metadata-errors: false
# When enabled 1.9 & 1.10 will be able to block by using shields
shield-blocking: true
# Should we enable our hologram patch?
# If they're in the wrong place enable this
hologram-patch: false
# This is the offset, should work as default when enabled.
hologram-y: -1
# Enable player tick simulation, this fixes eating, drinking, nether portals.
simulate-pt: true
# Should we use nms player to simulate packets, (may fix anti-cheat issues)
nms-player-ticking: true
# Should we patch boss bars so they work? (Default: true, disable if you're having issues)
bossbar-patch: true
# If your boss bar flickers on 1.9 & 1.10, set this to 'true'. It will keep all boss bars on 100% (not recommended)
bossbar-anti-flicker: false
# This will show the new effect indicator in the top-right corner for 1.9 & 1.10 players.
use-new-effect-indicator: true
# Show the new death messages for 1.9 & 1.10 on the death screen
use-new-deathmessages: false
# Should we cache our items, this will prevent server from being lagged out, however the cost is a constant task caching items
item-cache: true
# Patch the Anti xray to work on 1.9 & 1.10 (If your server is 1.8) This can cost more performance, so disable it if you don't use it.
anti-xray-patch: true
+2 -2
View File
@@ -2,8 +2,8 @@ name: ViaVersion
main: us.myles.ViaVersion.ViaVersionPlugin
author: _MylesC
version: ${project.version}
load: startup
loadbefore: [ProtocolLib, ProxyPipe, SpigotLib, PacketListenerApi]
load: postworld
loadbefore: [ProtocolLib, ProxyPipe, SpigotLib, PacketListenerApi, SkinRestorer]
commands:
viaversion:
description: Shows ViaVersion Version and more.