Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f91fcb4ea8 | ||
|
|
b3060e0dc8 | ||
|
|
808a9a7d82 | ||
|
|
32c43e6023 | ||
|
|
4c9c50f939 | ||
|
|
ac1b35379e | ||
|
|
b743589d77 | ||
|
|
9dad0a0d5e | ||
|
|
f5b49bc9ce | ||
|
|
b3612a68b0 | ||
|
|
7385db02c2 | ||
|
|
501d2ec3a2 | ||
|
|
1217a9b7e2 | ||
|
|
6740c5c6dc | ||
|
|
44e8056fb3 | ||
|
|
d1da412cf7 | ||
|
|
6534a5414e | ||
|
|
91344a0b50 | ||
|
|
cdd9ff4469 | ||
|
|
d88b76db85 | ||
|
|
bc1d57853c | ||
|
|
27d6c12556 | ||
|
|
a76dd1ba49 | ||
|
|
1a4388b3e7 | ||
|
|
f1b81f77d6 | ||
|
|
d6edec3a55 | ||
|
|
094f4c6d58 | ||
|
|
c57d0f60f9 | ||
|
|
dd5cd1ca48 | ||
|
|
ab4a565700 | ||
|
|
f8ac54e237 | ||
|
|
089e07fe49 | ||
|
|
1d3b8f802c | ||
|
|
27283e48a2 | ||
|
|
d22584afbc | ||
|
|
249ab01425 | ||
|
|
851097de44 | ||
|
|
c095a51f7c | ||
|
|
5e62b7001e | ||
|
|
8cc4ba168a | ||
|
|
264a21d092 | ||
|
|
e2585db350 | ||
|
|
a2f7a52d31 | ||
|
|
d04121202d | ||
|
|
95517ade2c | ||
|
|
c9441de7e4 | ||
|
|
dc946cb845 | ||
|
|
5fa30d9adb | ||
|
|
a7043424ec | ||
|
|
e1b3d21732 | ||
|
|
8ffc056a7e | ||
|
|
7c274fb03d | ||
|
|
3b533b5138 | ||
|
|
5665510f7e | ||
|
|
47faa21ef4 | ||
|
|
575f457830 | ||
|
|
d5bf7909e8 | ||
|
|
fdf90b7931 | ||
|
|
e3305e4eae | ||
|
|
15fe8d394e | ||
|
|
082db38c40 | ||
|
|
be54dc41d1 | ||
|
|
487e79c043 | ||
|
|
ef6390a0b8 | ||
|
|
9d9fc65633 | ||
|
|
6eac61c912 | ||
|
|
d89362a271 | ||
|
|
0a407069fa | ||
|
|
661fdb1127 | ||
|
|
9e6c0f72a8 | ||
|
|
70ad2613f1 | ||
|
|
9052946c45 | ||
|
|
3ddc43bf7b | ||
|
|
cdb757eae5 | ||
|
|
50a3e03649 | ||
|
|
957284930e | ||
|
|
198a24371c | ||
|
|
bcc994b0dd | ||
|
|
f870bd5a32 | ||
|
|
a14abd6f4f | ||
|
|
2456c3cf17 | ||
|
|
9828e4ae1d | ||
|
|
030aa887c7 | ||
|
|
ba624a2b48 | ||
|
|
e7582cb1ec | ||
|
|
82bf11fcbc | ||
|
|
ac6e8b1709 | ||
|
|
00cc545795 | ||
|
|
c7ee816aba | ||
|
|
e7f85e67f6 | ||
|
|
d239d2f967 |
No files matched your search
@@ -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.
|
||||
@@ -1,14 +1,9 @@
|
||||
# ViaVersion 0.8.0
|
||||
# ViaVersion 0.9.3
|
||||
[](https://travis-ci.org/MylesIsCool/ViaVersion)
|
||||
[](https://gitter.im/MylesIsCool/ViaVersion)
|
||||
|
||||
**Allows the connection of 1.9 clients to 1.8**
|
||||
|
||||
This plugin modifies netty to allow connection of 1.9 clients to 1.8,
|
||||
|
||||
###*Don't use late bind*
|
||||
|
||||
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()
|
||||
**1.10 clients on 1.8 / 1.9 servers**
|
||||
|
||||
This took 100s hours of work, so if you enjoy this consider looking into contacting me and supporting my projects.
|
||||
|
||||
@@ -20,6 +15,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 +51,18 @@ https://www.spigotmc.org/resources/viaversion.19254/history
|
||||
|
||||
----------
|
||||
|
||||
You can find unofficial dev builds here:
|
||||
You can find official dev builds here:
|
||||
|
||||
**Terrobility's Build Server:** https://ci.terrocidepvp.net/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!
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>us.myles</groupId>
|
||||
<artifactId>viaversion</artifactId>
|
||||
<version>0.8.1-SNAPSHOT</version>
|
||||
<version>0.9.4</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>
|
||||
@@ -135,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>
|
||||
@@ -204,5 +211,13 @@
|
||||
<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>
|
||||
<scope>provided</scope>
|
||||
</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", -0.96D);
|
||||
}
|
||||
|
||||
@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,45 @@ 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.ProtocolSupportUtil;
|
||||
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;
|
||||
private boolean protocolSupport = 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.");
|
||||
@@ -66,13 +73,37 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
|
||||
}
|
||||
}
|
||||
|
||||
getLogger().info("ViaVersion " + getDescription().getVersion() + " is now loaded, injecting.");
|
||||
injectPacketHandler();
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Check if we're using protocol support too
|
||||
protocolSupport = Bukkit.getPluginManager().getPlugin("ProtocolSupport") != null;
|
||||
|
||||
// Generate classes needed (only works if it's compat or ps)
|
||||
ClassGenerator.generate();
|
||||
lateBind = !isBinded();
|
||||
|
||||
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 +117,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
|
||||
getLogger().warning("ViaVersion will not function on the current protocol.");
|
||||
}
|
||||
}
|
||||
ProtocolRegistry.refreshVersions();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -97,6 +129,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 +189,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 +248,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 +285,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();
|
||||
}
|
||||
}
|
||||
@@ -284,17 +338,25 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
|
||||
@Override
|
||||
public int getPlayerVersion(@NonNull Player player) {
|
||||
if (!isPorted(player))
|
||||
return ProtocolRegistry.SERVER_PROTOCOL;
|
||||
return getExternalVersion(player);
|
||||
return portedPlayers.get(player.getUniqueId()).get(ProtocolInfo.class).getProtocolVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPlayerVersion(@NonNull UUID uuid) {
|
||||
if (!isPorted(uuid))
|
||||
return ProtocolRegistry.SERVER_PROTOCOL;
|
||||
return getExternalVersion(Bukkit.getPlayer(uuid));
|
||||
return portedPlayers.get(uuid).get(ProtocolInfo.class).getProtocolVersion();
|
||||
}
|
||||
|
||||
private int getExternalVersion(Player player) {
|
||||
if (!isProtocolSupport()) {
|
||||
return ProtocolRegistry.SERVER_PROTOCOL;
|
||||
} else {
|
||||
return ProtocolSupportUtil.getProtocolVersion(player);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPorted(UUID playerUUID) {
|
||||
return portedPlayers.containsKey(playerUUID);
|
||||
@@ -348,88 +410,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) {
|
||||
@@ -459,33 +452,37 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isProtocolSupport() {
|
||||
return protocolSupport;
|
||||
}
|
||||
|
||||
public Map<UUID, UserConnection> getPortedPlayers() {
|
||||
return portedPlayers;
|
||||
}
|
||||
|
||||
public boolean handlePPS(UserConnection info) {
|
||||
// Max PPS Checker
|
||||
if (getMaxPPS() > 0) {
|
||||
if (info.getPacketsPerSecond() >= getMaxPPS()) {
|
||||
info.disconnect(getMaxPPSKickMessage());
|
||||
if (conf.getMaxPPS() > 0) {
|
||||
if (info.getPacketsPerSecond() >= conf.getMaxPPS()) {
|
||||
info.disconnect(conf.getMaxPPSKickMessage().replace("%pps", ((Long) info.getPacketsPerSecond()).intValue() + ""));
|
||||
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().replace("%pps", ((Long) info.getPacketsPerSecond()).intValue() + ""));
|
||||
return true; // don't send current packet
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,15 +6,20 @@ import io.netty.buffer.Unpooled;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.protocol.Protocol;
|
||||
import us.myles.ViaVersion.api.remapper.ValueCreator;
|
||||
import us.myles.ViaVersion.api.type.Type;
|
||||
import us.myles.ViaVersion.api.type.TypeConverter;
|
||||
import us.myles.ViaVersion.exception.InformativeException;
|
||||
import us.myles.ViaVersion.handlers.ViaDecodeHandler;
|
||||
import us.myles.ViaVersion.packets.Direction;
|
||||
import us.myles.ViaVersion.packets.State;
|
||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||
import us.myles.ViaVersion.util.PipelineUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -38,8 +43,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;
|
||||
@@ -76,12 +83,35 @@ public class PacketWrapper {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a type is at an index
|
||||
*
|
||||
* @param type The type of the part you wish to get.
|
||||
* @param index The index of the part (relative to the type)
|
||||
* @return True if the type is at the index
|
||||
*/
|
||||
public boolean isReadable(Type type, int index) {
|
||||
int currentIndex = 0;
|
||||
for (Pair<Type, Object> packetValue : readableObjects) {
|
||||
if (packetValue.getKey().getBaseClass() == type.getBaseClass()) { // Ref check
|
||||
if (currentIndex == index) {
|
||||
return true;
|
||||
}
|
||||
currentIndex++;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a currently existing part in the output
|
||||
*
|
||||
* @param type The type of the part you wish to set.
|
||||
* @param <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 +132,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 +148,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 +165,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 +186,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
|
||||
*/
|
||||
@@ -173,8 +206,8 @@ public class PacketWrapper {
|
||||
packetValues.addAll(readableObjects);
|
||||
readableObjects.clear();
|
||||
// If the buffer has readable bytes, copy them.
|
||||
if(inputBuffer.readableBytes() > 0){
|
||||
read(Type.REMAINING_BYTES);
|
||||
if (inputBuffer.readableBytes() > 0) {
|
||||
passthrough(Type.REMAINING_BYTES);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,6 +257,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);
|
||||
@@ -235,10 +276,44 @@ public class PacketWrapper {
|
||||
* Be careful not to send packets twice.
|
||||
* (Sends it after current)
|
||||
*
|
||||
* @param packetProtocol - The protocol version of the packet.
|
||||
* @throws Exception if it fails to write
|
||||
*/
|
||||
public void send(Class<? extends Protocol> packetProtocol) throws Exception {
|
||||
if (!isCancelled()) {
|
||||
// Apply current pipeline
|
||||
List<Protocol> protocols = new ArrayList<>(user().get(ProtocolInfo.class).getPipeline().pipes());
|
||||
// Other way if outgoing
|
||||
Collections.reverse(protocols);
|
||||
int index = 0;
|
||||
for (int i = 0; i < protocols.size(); i++) {
|
||||
if (protocols.get(i).getClass().equals(packetProtocol)) {
|
||||
index = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Apply other protocols
|
||||
apply(Direction.OUTGOING, user().get(ProtocolInfo.class).getState(), index, protocols);
|
||||
// Send
|
||||
ByteBuf output = inputBuffer == null ? Unpooled.buffer() : inputBuffer.alloc().buffer();
|
||||
writeToBuffer(output);
|
||||
user().sendRawPacket(output);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send this packet to the associated user.
|
||||
* Be careful not to send packets twice.
|
||||
* (Sends it after current)
|
||||
* <br />
|
||||
* <b>This method is no longer used, it's favoured to use send(Protocol) as it will handle the pipeline properly.</b>
|
||||
*
|
||||
* @throws Exception if it fails to write
|
||||
*/
|
||||
@Deprecated
|
||||
public void send() throws Exception {
|
||||
if (!isCancelled()) {
|
||||
// Send
|
||||
ByteBuf output = inputBuffer == null ? Unpooled.buffer() : inputBuffer.alloc().buffer();
|
||||
writeToBuffer(output);
|
||||
user().sendRawPacket(output);
|
||||
@@ -269,6 +344,26 @@ public class PacketWrapper {
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a pipeline from an index to the wrapper
|
||||
*
|
||||
* @param direction The direction
|
||||
* @param state The state
|
||||
* @param index The index to start from
|
||||
* @param pipeline The pipeline
|
||||
* @return The current packetwrapper
|
||||
* @throws Exception
|
||||
*/
|
||||
public PacketWrapper apply(Direction direction, State state, int index, List<Protocol> pipeline) throws Exception {
|
||||
for (int i = index; i < pipeline.size(); i++) { // Copy to prevent from removal.
|
||||
pipeline.get(i).transform(direction, state, this);
|
||||
// Reset the reader for the packetWrapper (So it can be recycled across packets)
|
||||
resetReader();
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel this packet from sending
|
||||
*/
|
||||
@@ -318,4 +413,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 {
|
||||
@@ -20,6 +21,7 @@ public interface ViaVersionAPI {
|
||||
|
||||
/**
|
||||
* Get protocol number from a player
|
||||
* Will also retrieve version from ProtocolSupport if it's being used.
|
||||
*
|
||||
* @param player Bukkit player object
|
||||
* @return Protocol ID, For example (47=1.8-1.8.8, 107=1.9, 108=1.9.1)
|
||||
@@ -37,7 +39,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 +103,35 @@ 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
|
||||
* <p>
|
||||
* Note: Will only work after ViaVersion load
|
||||
*
|
||||
* @return True if spigot
|
||||
*/
|
||||
boolean isSpigot();
|
||||
|
||||
/**
|
||||
* Gets if protocol support is also being used.
|
||||
*
|
||||
* @return True if it is being used.
|
||||
*/
|
||||
boolean isProtocolSupport();
|
||||
}
|
||||
@@ -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 '&'
|
||||
*/
|
||||
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 '&'
|
||||
*/
|
||||
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";
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -1,38 +1,4 @@
|
||||
package us.myles.ViaVersion.api.minecraft.chunks;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.ToString;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
@ToString
|
||||
public class Chunk {
|
||||
private final int x;
|
||||
private final int z;
|
||||
private final boolean groundUp;
|
||||
private final int primaryBitmask;
|
||||
private final ChunkSection[] sections;
|
||||
private final byte[] biomeData;
|
||||
private boolean unloadPacket = false;
|
||||
|
||||
/**
|
||||
* Chunk unload.
|
||||
*
|
||||
* @param x coord
|
||||
* @param z coord
|
||||
*/
|
||||
public Chunk(int x, int z) {
|
||||
this(x, z, true, 0, new ChunkSection[16], null);
|
||||
this.unloadPacket = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this chunk have biome data
|
||||
*
|
||||
* @return True if the chunk has biome data
|
||||
*/
|
||||
public boolean hasBiomeData() {
|
||||
return biomeData != null && groundUp;
|
||||
}
|
||||
public interface Chunk {
|
||||
}
|
||||
@@ -11,12 +11,12 @@ 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) {
|
||||
@@ -26,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(ProtocolRegistry.BASE_PROTOCOL);
|
||||
protocolList.add(ProtocolRegistry.BASE_PROTOCOL);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -54,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");
|
||||
@@ -69,11 +69,9 @@ public class ProtocolPipeline extends Protocol {
|
||||
if (direction == Direction.OUTGOING)
|
||||
Collections.reverse(protocols);
|
||||
|
||||
for (Protocol protocol : protocols) { // Copy to prevent from removal.
|
||||
protocol.transform(direction, state, packetWrapper);
|
||||
// Reset the reader for the packetWrapper (So it can be recycled across packets)
|
||||
packetWrapper.resetReader();
|
||||
}
|
||||
// Apply protocols
|
||||
packetWrapper.apply(direction, state, 0, protocols);
|
||||
|
||||
super.transform(direction, state, packetWrapper);
|
||||
|
||||
if (ViaVersion.getInstance().isDebug()) {
|
||||
@@ -85,43 +83,46 @@ public class ProtocolPipeline extends Protocol {
|
||||
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);
|
||||
}
|
||||
if (type != null) {
|
||||
// Filter :) This would be not hard coded too, sorry :(
|
||||
if (type == PacketType.PLAY_CHUNK_DATA) return;
|
||||
if (type == PacketType.PLAY_TIME_UPDATE) return;
|
||||
if (type == PacketType.PLAY_KEEP_ALIVE) return;
|
||||
if (type == PacketType.PLAY_KEEP_ALIVE_REQUEST) return;
|
||||
if (type == PacketType.PLAY_ENTITY_LOOK_MOVE) return;
|
||||
if (type == PacketType.PLAY_ENTITY_LOOK) return;
|
||||
if (type == PacketType.PLAY_ENTITY_RELATIVE_MOVE) return;
|
||||
if (type == PacketType.PLAY_PLAYER_POSITION_LOOK_REQUEST) return;
|
||||
if (type == PacketType.PLAY_PLAYER_LOOK_REQUEST) return;
|
||||
if (type == PacketType.PLAY_PLAYER_POSITION_REQUEST) return;
|
||||
|
||||
// Filter :) This would be not hard coded too, sorry :(
|
||||
if (type == PacketType.PLAY_CHUNK_DATA) return;
|
||||
if (type == PacketType.PLAY_TIME_UPDATE) return;
|
||||
if (type == PacketType.PLAY_KEEP_ALIVE) return;
|
||||
if (type == PacketType.PLAY_KEEP_ALIVE_REQUEST) return;
|
||||
if (type == PacketType.PLAY_ENTITY_LOOK_MOVE) return;
|
||||
if (type == PacketType.PLAY_ENTITY_LOOK) return;
|
||||
if (type == PacketType.PLAY_ENTITY_RELATIVE_MOVE) return;
|
||||
if (type == PacketType.PLAY_PLAYER_POSITION_LOOK_REQUEST) return;
|
||||
if (type == PacketType.PLAY_PLAYER_LOOK_REQUEST) return;
|
||||
if (type == PacketType.PLAY_PLAYER_POSITION_REQUEST) return;
|
||||
|
||||
packet = type.name();
|
||||
packet = type.name();
|
||||
}
|
||||
}
|
||||
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
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -157,4 +158,8 @@ public class ProtocolPipeline extends Protocol {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<Protocol> pipes() {
|
||||
return protocolList;
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,28 @@
|
||||
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_10to1_9_3.Protocol1_10To1_9_3_4;
|
||||
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 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<>();
|
||||
public static final Protocol BASE_PROTOCOL = new BaseProtocol();
|
||||
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
|
||||
@@ -24,6 +31,11 @@ public class ProtocolRegistry {
|
||||
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 Protocol1_10To1_9_3_4(), Collections.singletonList(ProtocolVersion.v1_10.getId()), ProtocolVersion.v1_9_3.getId());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,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.
|
||||
*
|
||||
@@ -84,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
|
||||
@@ -97,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)) {
|
||||
@@ -109,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
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,14 +1,24 @@
|
||||
package us.myles.ViaVersion.api.protocol;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public class ProtocolVersion {
|
||||
private static final Map<Integer, ProtocolVersion> versions = new HashMap<>();
|
||||
private static final List<ProtocolVersion> versionList = new ArrayList<>();
|
||||
|
||||
public static final ProtocolVersion v1_4_6;
|
||||
public static final ProtocolVersion v1_5_1;
|
||||
public static final ProtocolVersion v1_5_2;
|
||||
public static final ProtocolVersion v_1_6_1;
|
||||
public static final ProtocolVersion v_1_6_2;
|
||||
public static final ProtocolVersion v_1_6_3;
|
||||
public static final ProtocolVersion v_1_6_4;
|
||||
public static final ProtocolVersion v1_7_1;
|
||||
public static final ProtocolVersion v1_7_6;
|
||||
public static final ProtocolVersion v1_8;
|
||||
@@ -16,22 +26,36 @@ public class ProtocolVersion {
|
||||
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 v1_10;
|
||||
public static final ProtocolVersion unknown;
|
||||
|
||||
private final int id;
|
||||
private final String name;
|
||||
|
||||
static {
|
||||
// Before netty rewrite
|
||||
register(v1_4_6 = new ProtocolVersion(51, "1.4.6"));
|
||||
register(v1_5_1 = new ProtocolVersion(60, "1.5.1"));
|
||||
register(v1_5_2 = new ProtocolVersion(61, "1.5.2"));
|
||||
register(v_1_6_1 = new ProtocolVersion(73, "1.6.1"));
|
||||
register(v_1_6_2 = new ProtocolVersion(74, "1.6.2"));
|
||||
register(v_1_6_3 = new ProtocolVersion(77, "1.6.3"));
|
||||
register(v_1_6_4 = new ProtocolVersion(78, "1.6.4"));
|
||||
// After netty rewrite
|
||||
register(v1_7_1 = new ProtocolVersion(4, "1.7-1.7.5"));
|
||||
register(v1_7_6 = new ProtocolVersion(5, "1.7.6-1.7.10"));
|
||||
register(v1_8 = new ProtocolVersion(47, "1.8.x"));
|
||||
register(v1_9 = new ProtocolVersion(107, "1.9"));
|
||||
register(v1_9_1 = new ProtocolVersion(108, "1.9.1"));
|
||||
register(v1_9_2 = new ProtocolVersion(109, "1.9.2"));
|
||||
register(v1_9_3 = new ProtocolVersion(110, "1.9.3"));
|
||||
register(v1_9_3 = new ProtocolVersion(110, "1.9.3/4"));
|
||||
register(v1_10 = new ProtocolVersion(210, "1.10"));
|
||||
register(unknown = new ProtocolVersion(-1, "UNKNOWN"));
|
||||
}
|
||||
|
||||
public static void register(@NonNull ProtocolVersion protocol) {
|
||||
versions.put(protocol.getId(), protocol);
|
||||
versionList.add(protocol);
|
||||
}
|
||||
|
||||
public static boolean isRegistered(int id) {
|
||||
@@ -46,7 +70,25 @@ public class ProtocolVersion {
|
||||
}
|
||||
}
|
||||
|
||||
public static int getIndex(ProtocolVersion version) {
|
||||
return versionList.indexOf(version);
|
||||
}
|
||||
|
||||
public static List<ProtocolVersion> getProtocols() {
|
||||
return Collections.unmodifiableList(new ArrayList<ProtocolVersion>(versions.values()));
|
||||
return Collections.unmodifiableList(new ArrayList<>(versions.values()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
ProtocolVersion that = (ProtocolVersion) o;
|
||||
return id == that.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -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,7 @@ 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.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Getter
|
||||
@@ -59,8 +60,10 @@ public abstract class Type<T> implements ByteBufReader<T>, ByteBufWriter<T> {
|
||||
public static final Type<EulerAngle> ROTATION = new EulerAngleType();
|
||||
public static final Type<Vector> VECTOR = new VectorType();
|
||||
public static final Type<CompoundTag> NBT = new NBTType();
|
||||
public static final Type<CompoundTag[]> NBT_ARRAY = new ArrayType<>(Type.NBT);
|
||||
|
||||
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();
|
||||
@@ -78,6 +81,10 @@ public abstract class Type<T> implements ByteBufReader<T>, ByteBufWriter<T> {
|
||||
this.typeName = typeName;
|
||||
}
|
||||
|
||||
public Class<? extends Type> getBaseClass() {
|
||||
return this.getClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Type|" + getTypeName();
|
||||
|
||||
@@ -13,38 +13,9 @@ public class ArrayType<T> extends Type<T[]> {
|
||||
this.elementType = type;
|
||||
}
|
||||
|
||||
/* Taken from http://stackoverflow.com/questions/4901128/obtaining-the-array-class-of-a-component-type */
|
||||
public static Class<?> getArrayClass(Class<?> componentType) {
|
||||
ClassLoader classLoader = componentType.getClassLoader();
|
||||
String name;
|
||||
if (componentType.isArray()) {
|
||||
// just add a leading "["
|
||||
name = "[" + componentType.getName();
|
||||
} else if (componentType == boolean.class) {
|
||||
name = "[Z";
|
||||
} else if (componentType == byte.class) {
|
||||
name = "[B";
|
||||
} else if (componentType == char.class) {
|
||||
name = "[C";
|
||||
} else if (componentType == double.class) {
|
||||
name = "[D";
|
||||
} else if (componentType == float.class) {
|
||||
name = "[F";
|
||||
} else if (componentType == int.class) {
|
||||
name = "[I";
|
||||
} else if (componentType == long.class) {
|
||||
name = "[J";
|
||||
} else if (componentType == short.class) {
|
||||
name = "[S";
|
||||
} else {
|
||||
// must be an object non-array class
|
||||
name = "[L" + componentType.getName() + ";";
|
||||
}
|
||||
try {
|
||||
return classLoader != null ? classLoader.loadClass(name) : Class.forName(name);
|
||||
} catch (ClassNotFoundException e) {
|
||||
return null; // oh
|
||||
}
|
||||
// Should only happen once per class init.
|
||||
return Array.newInstance(componentType, 0).getClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package us.myles.ViaVersion.api.type.types.minecraft;
|
||||
|
||||
import us.myles.ViaVersion.api.minecraft.chunks.Chunk;
|
||||
import us.myles.ViaVersion.api.type.Type;
|
||||
|
||||
public abstract class BaseChunkType extends Type<Chunk> {
|
||||
public BaseChunkType() {
|
||||
super(Chunk.class);
|
||||
}
|
||||
|
||||
public BaseChunkType(String typeName) {
|
||||
super(typeName, Chunk.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Type> getBaseClass() {
|
||||
return BaseChunkType.class;
|
||||
}
|
||||
}
|
||||
@@ -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,165 @@
|
||||
package us.myles.ViaVersion.classgenerator;
|
||||
|
||||
import javassist.*;
|
||||
import javassist.expr.ConstructorCall;
|
||||
import javassist.expr.ExprEditor;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import us.myles.ViaVersion.api.ViaVersion;
|
||||
import us.myles.ViaVersion.handlers.ViaDecodeHandler;
|
||||
import us.myles.ViaVersion.handlers.ViaEncodeHandler;
|
||||
import us.myles.ViaVersion.util.ReflectionUtil;
|
||||
|
||||
public class ClassGenerator {
|
||||
private static HandlerConstructor constructor = new BasicHandlerConstructor();
|
||||
private static String psPackage = null;
|
||||
|
||||
public static HandlerConstructor getConstructor() {
|
||||
return constructor;
|
||||
}
|
||||
|
||||
public static void generate() {
|
||||
if (ViaVersion.getInstance().isCompatSpigotBuild() || ViaVersion.getInstance().isProtocolSupport()) {
|
||||
try {
|
||||
ClassPool pool = ClassPool.getDefault();
|
||||
for (Plugin p : Bukkit.getPluginManager().getPlugins()) {
|
||||
pool.insertClassPath(new LoaderClassPath(p.getClass().getClassLoader()));
|
||||
}
|
||||
|
||||
if (ViaVersion.getInstance().isCompatSpigotBuild()) {
|
||||
Class decodeSuper = ReflectionUtil.nms("PacketDecoder");
|
||||
Class encodeSuper = ReflectionUtil.nms("PacketEncoder");
|
||||
// Generate the classes
|
||||
addSpigotCompatibility(pool, ViaDecodeHandler.class, decodeSuper);
|
||||
addSpigotCompatibility(pool, ViaEncodeHandler.class, encodeSuper);
|
||||
} else {
|
||||
Class decodeSuper = Class.forName(getPSPackage() + ".wrapped.WrappedDecoder");
|
||||
Class encodeSuper = Class.forName(getPSPackage() + ".wrapped.WrappedEncoder");
|
||||
// Generate the classes
|
||||
addPSCompatibility(pool, ViaDecodeHandler.class, decodeSuper);
|
||||
addPSCompatibility(pool, ViaEncodeHandler.class, encodeSuper);
|
||||
}
|
||||
|
||||
|
||||
// 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 addSpigotCompatibility(ClassPool pool, Class input, Class superclass) {
|
||||
String newName = "us.myles.ViaVersion.classgenerator.generated." + input.getSimpleName();
|
||||
|
||||
try {
|
||||
CtClass generated = pool.getAndRename(input.getName(), newName);
|
||||
if (superclass != null) {
|
||||
CtClass toExtend = pool.get(superclass.getName());
|
||||
generated.setSuperclass(toExtend);
|
||||
|
||||
// If it's NMS satisfy constructor.
|
||||
if (superclass.getName().startsWith("net.minecraft")) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
private static Class addPSCompatibility(ClassPool pool, Class input, Class superclass) {
|
||||
String newName = "us.myles.ViaVersion.classgenerator.generated." + input.getSimpleName();
|
||||
|
||||
try {
|
||||
CtClass generated = pool.getAndRename(input.getName(), newName);
|
||||
if (superclass != null) {
|
||||
CtClass toExtend = pool.get(superclass.getName());
|
||||
generated.setSuperclass(toExtend);
|
||||
|
||||
// Override setRealEncoder / setRealDecoder
|
||||
pool.importPackage(getPSPackage());
|
||||
pool.importPackage(getPSPackage() + ".wrapped");
|
||||
if (superclass.getName().endsWith("Decoder")) {
|
||||
// Decoder
|
||||
generated.addMethod(CtMethod.make("public void setRealDecoder(IPacketDecoder dec) {\n" +
|
||||
" WrappedDecoder decoder = new WrappedDecoder();" +
|
||||
" decoder.setRealDecoder(dec);\n" +
|
||||
" this.minecraftDecoder = decoder;\n" +
|
||||
" }", generated));
|
||||
} else {
|
||||
// Encoder
|
||||
generated.addMethod(CtMethod.make("public void setRealEncoder(IPacketEncoder enc) {\n" +
|
||||
" WrappedEncoder encoder = new WrappedEncoder();" +
|
||||
" encoder.setRealEncoder(enc);\n" +
|
||||
" this.minecraftEncoder = encoder;\n" +
|
||||
" }", generated));
|
||||
}
|
||||
}
|
||||
return generated.toClass(HandlerConstructor.class.getClassLoader());
|
||||
} catch (NotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (CannotCompileException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getPSPackage() {
|
||||
if (psPackage == null) {
|
||||
try {
|
||||
Class.forName("protocolsupport.protocol.core.IPacketDecoder");
|
||||
psPackage = "protocolsupport.protocol.core";
|
||||
} catch (ClassNotFoundException e) {
|
||||
try {
|
||||
Class.forName("protocolsupport.protocol.pipeline.IPacketDecoder");
|
||||
psPackage = "protocolsupport.protocol.pipeline";
|
||||
} catch (ClassNotFoundException e1) {
|
||||
psPackage = "unknown";
|
||||
}
|
||||
}
|
||||
}
|
||||
return psPackage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
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 "));
|
||||
|
||||
@@ -27,19 +27,25 @@ public class ListSubCmd extends ViaSubCommand {
|
||||
|
||||
@Override
|
||||
public boolean execute(CommandSender sender, String[] args) {
|
||||
Map<Integer, Set<String>> playerVersions = new HashMap<>();
|
||||
Map<ProtocolVersion, Set<String>> playerVersions = new TreeMap<>(new Comparator<ProtocolVersion>() {
|
||||
@Override
|
||||
public int compare(ProtocolVersion o1, ProtocolVersion o2) {
|
||||
return ProtocolVersion.getIndex(o2) - ProtocolVersion.getIndex(o1);
|
||||
}
|
||||
});
|
||||
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
int playerVersion = ViaVersion.getInstance().getPlayerVersion(p);
|
||||
if (!playerVersions.containsKey(playerVersion))
|
||||
playerVersions.put(playerVersion, new HashSet<String>());
|
||||
playerVersions.get(playerVersion).add(p.getName());
|
||||
ProtocolVersion key = ProtocolVersion.getProtocol(playerVersion);
|
||||
if (!playerVersions.containsKey(key))
|
||||
playerVersions.put(key, new HashSet<String>());
|
||||
playerVersions.get(key).add(p.getName());
|
||||
}
|
||||
Map<Integer, Set<String>> sorted = new TreeMap<>(playerVersions);
|
||||
|
||||
for (Map.Entry<Integer, Set<String>> entry : sorted.entrySet())
|
||||
sendMessage(sender, "&8[&6%s&8]: &b%s", ProtocolVersion.getProtocol(entry.getKey()).getName(), entry.getValue());
|
||||
for (Map.Entry<ProtocolVersion, Set<String>> entry : playerVersions.entrySet())
|
||||
sendMessage(sender, "&8[&6%s&8]: &b%s", entry.getKey().getName(), entry.getValue());
|
||||
|
||||
sorted.clear();
|
||||
playerVersions.clear();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,9 @@ public class PPSSubCmd extends ViaSubCommand {
|
||||
sendMessage(sender, "&cAverage: &f" + (totalPackets / clients));
|
||||
sendMessage(sender, "&cHighest: &f" + max);
|
||||
}
|
||||
if (clients == 0) {
|
||||
sendMessage(sender, "&cNo clients to display.");
|
||||
}
|
||||
for (Map.Entry<Integer, Set<String>> entry : sorted.entrySet())
|
||||
sendMessage(sender, "&8[&6%s&8]: &b%s", ProtocolVersion.getProtocol(entry.getKey()).getName(), entry.getValue());
|
||||
sorted.clear();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -38,8 +38,8 @@ public class ViaDecodeHandler extends ByteToMessageDecoder {
|
||||
// Increment received
|
||||
boolean second = info.incrementReceived();
|
||||
// Check PPS
|
||||
if(second) {
|
||||
if (((ViaVersionPlugin) ViaVersion.getConfig()).handlePPS(info))
|
||||
if (second) {
|
||||
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
|
||||
|
||||
@@ -17,9 +17,9 @@ public class ViaPacketHandler extends MessageToMessageEncoder {
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, Object o, List list) throws Exception {
|
||||
// Split chunk bulk packet up in to single chunk packets before it reached the encoder.
|
||||
// This will prevent issues with several plugins and other protocol handlers due to the chunk being sent twice.
|
||||
// It also sends the chunk in the right order possible resolving some issues with added chunk/block/entity data.
|
||||
// Split chunks bulk packet up in to single chunks packets before it reached the encoder.
|
||||
// This will prevent issues with several plugins and other protocol handlers due to the chunks being sent twice.
|
||||
// It also sends the chunks in the right order possible resolving some issues with added chunks/block/entity data.
|
||||
if (!(o instanceof ByteBuf)) {
|
||||
info.setLastPacket(o);
|
||||
/* This transformer is more for fixing issues which we find hard at packet level :) */
|
||||
|
||||
@@ -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;
|
||||
@@ -18,10 +19,12 @@ import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||
import us.myles.ViaVersion.api.remapper.PacketHandler;
|
||||
import us.myles.ViaVersion.api.remapper.PacketRemapper;
|
||||
import us.myles.ViaVersion.api.type.Type;
|
||||
import us.myles.ViaVersion.packets.Direction;
|
||||
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 +43,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 +88,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(), ", ")
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -157,4 +171,15 @@ public class BaseProtocol extends Protocol {
|
||||
}
|
||||
}, plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(Direction direction, State state, PacketWrapper packetWrapper) throws Exception {
|
||||
super.transform(direction, state, packetWrapper);
|
||||
if (direction == Direction.INCOMING && state == State.HANDSHAKE) {
|
||||
// Disable if it isn't a handshake packet.
|
||||
if (packetWrapper.getId() > 0) {
|
||||
packetWrapper.user().setActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_10to1_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.protocol1_10to1_9_3.storage.ResourcePackTracker;
|
||||
import us.myles.ViaVersion.protocols.protocol1_10to1_9_3.types.Meta1_10Type;
|
||||
import us.myles.ViaVersion.protocols.protocol1_10to1_9_3.types.MetaList1_10Type;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Protocol1_10To1_9_3_4 extends Protocol {
|
||||
public static final Type<List<Metadata>> METADATA_LIST = new MetaList1_10Type();
|
||||
public static final Type<Metadata> METADATA = new Meta1_10Type();
|
||||
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));
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_10to1_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);
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_10to1_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 Meta1_10Type 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_10to1_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_10to1_9_3.Protocol1_10To1_9_3_4;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.metadata.NewType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MetaList1_10Type extends MetaListTypeTemplate {
|
||||
|
||||
@Override
|
||||
public List<Metadata> read(ByteBuf buffer) throws Exception {
|
||||
List<Metadata> list = new ArrayList<>();
|
||||
Metadata meta;
|
||||
do {
|
||||
meta = Protocol1_10To1_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)
|
||||
Protocol1_10To1_9_3_4.METADATA.write(buffer, new Metadata(5, NewType.Boolean.getTypeID(), Type.BOOLEAN, false)); // No gravity metadata
|
||||
Protocol1_10To1_9_3_4.METADATA.write(buffer, m);
|
||||
}
|
||||
|
||||
// Write end of list
|
||||
Protocol1_10To1_9_3_4.METADATA.write(buffer, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
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);
|
||||
|
||||
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(Protocol1_9_1_2TO1_9_3_4.class);
|
||||
}
|
||||
|
||||
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(Protocol1_9_1_2TO1_9_3_4.class);
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
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 us.myles.ViaVersion.api.minecraft.chunks.Chunk;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class Chunk1_9_3_4 implements Chunk {
|
||||
private int x;
|
||||
private int z;
|
||||
private boolean groundUp;
|
||||
private int bitmask;
|
||||
private byte[] sections;
|
||||
List<CompoundTag> blockEntities;
|
||||
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
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.minecraft.chunks.Chunk;
|
||||
import us.myles.ViaVersion.api.type.Type;
|
||||
import us.myles.ViaVersion.api.type.types.minecraft.BaseChunkType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Chunk1_9_3_4Type extends BaseChunkType {
|
||||
public Chunk1_9_3_4Type() {
|
||||
super("1.9.3 Chunk");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk 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, Chunk input) throws Exception {
|
||||
if (!(input instanceof Chunk1_9_3_4))
|
||||
throw new Exception("Tried to send the wrong chunk type from 1.9.3-4 chunk: " + input.getClass());
|
||||
Chunk1_9_3_4 chunk = (Chunk1_9_3_4) input;
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
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.minecraft.chunks.Chunk;
|
||||
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<Chunk> 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 {
|
||||
Chunk chunk = wrapper.passthrough(CHUNK);
|
||||
BlockEntity.handle(((Chunk1_9_3_4) chunk).getBlockEntities(), wrapper.user());
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(UserConnection userConnection) {
|
||||
|
||||
}
|
||||
}
|
||||
+20
@@ -1,7 +1,9 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_9_1to1_9;
|
||||
|
||||
import us.myles.ViaVersion.api.PacketWrapper;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
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;
|
||||
@@ -24,6 +26,24 @@ public class Protocol1_9_1TO1_9 extends Protocol {
|
||||
map(Type.BOOLEAN); // 6 - Reduced Debug info
|
||||
}
|
||||
});
|
||||
|
||||
// Sound Effect Packet
|
||||
registerOutgoing(State.PLAY, 0x47, 0x47, new PacketRemapper() {
|
||||
@Override
|
||||
public void registerMap() {
|
||||
map(Type.VAR_INT); // 0 - Sound ID
|
||||
|
||||
handler(new PacketHandler() {
|
||||
@Override
|
||||
public void handle(PacketWrapper wrapper) throws Exception {
|
||||
int sound = wrapper.get(Type.VAR_INT, 0);
|
||||
|
||||
if (sound >= 415) // Add 1 to every sound id since there is no Elytra sound on a 1.9 server
|
||||
wrapper.set(Type.VAR_INT, 0, sound + 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import org.spacehq.opennbt.tag.builtin.CompoundTag;
|
||||
import us.myles.ViaVersion.api.minecraft.chunks.Chunk;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class Chunk1_9_1_2 implements Chunk {
|
||||
private int x;
|
||||
private int z;
|
||||
private boolean groundUp;
|
||||
private int bitmask;
|
||||
private final ChunkSection1_9_1_2[] sections;
|
||||
private byte[] biomeData;
|
||||
List<CompoundTag> blockEntities;
|
||||
|
||||
public boolean isBiomeData() {
|
||||
return biomeData != null;
|
||||
}
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import org.spacehq.opennbt.tag.builtin.CompoundTag;
|
||||
import us.myles.ViaVersion.api.minecraft.chunks.Chunk;
|
||||
import us.myles.ViaVersion.api.type.Type;
|
||||
import us.myles.ViaVersion.api.type.types.minecraft.BaseChunkType;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.chunks.ChunkSection1_9to1_8;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
|
||||
public class Chunk1_9_1_2Type extends BaseChunkType {
|
||||
public Chunk1_9_1_2Type() {
|
||||
super("1.9.1/2 Chunk");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk 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);
|
||||
|
||||
BitSet usedSections = new BitSet(16);
|
||||
ChunkSection1_9_1_2[] sections = new ChunkSection1_9_1_2[16];
|
||||
// Calculate section count from bitmask
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if ((primaryBitmask & (1 << i)) != 0) {
|
||||
usedSections.set(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Read sections
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (!usedSections.get(i)) continue; // Section not set
|
||||
ChunkSection1_9_1_2 section = new ChunkSection1_9_1_2();
|
||||
sections[i] = section;
|
||||
// WIP.
|
||||
// section.readBlocks(input);
|
||||
// section.readBlockLight(input);
|
||||
// section.readSkyLight(input);
|
||||
/*
|
||||
BlockStorage blocks = new BlockStorage(in);
|
||||
NibbleArray3d blocklight = new NibbleArray3d(in, 2048); (1024 bytes)
|
||||
NibbleArray3d skylight = hasSkylight ? new NibbleArray3d(in, 2048) : null; (1024 bytes)
|
||||
chunks[index] = new Chunk(blocks, blocklight, skylight);
|
||||
*/
|
||||
}
|
||||
byte[] biomeData = groundUp ? new byte[256] : null;
|
||||
if (groundUp)
|
||||
input.readBytes(biomeData);
|
||||
|
||||
return new Chunk1_9_1_2(chunkX, chunkZ, groundUp, primaryBitmask, sections, biomeData, new ArrayList<CompoundTag>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf output, Chunk input) throws Exception {
|
||||
if (!(input instanceof Chunk1_9_1_2))
|
||||
throw new Exception("Tried to send the wrong chunk type from 1.9.3-4 chunk: " + input.getClass());
|
||||
Chunk1_9_1_2 chunk = (Chunk1_9_1_2) input;
|
||||
|
||||
output.writeInt(chunk.getX());
|
||||
output.writeInt(chunk.getZ());
|
||||
|
||||
output.writeBoolean(chunk.isGroundUp());
|
||||
Type.VAR_INT.write(output, chunk.getBitmask());
|
||||
|
||||
ByteBuf buf = Unpooled.buffer();
|
||||
for (int i = 0; i < 16; i++) {
|
||||
ChunkSection1_9_1_2 section = chunk.getSections()[i];
|
||||
if (section == null) continue; // Section not set
|
||||
section.writeBlocks(buf);
|
||||
section.writeBlockLight(buf);
|
||||
|
||||
if (!section.hasSkyLight()) continue; // No sky light, we're done here.
|
||||
section.writeSkyLight(buf);
|
||||
|
||||
}
|
||||
buf.readerIndex(0);
|
||||
Type.VAR_INT.write(output, buf.readableBytes() + (chunk.isBiomeData() ? 256 : 0));
|
||||
output.writeBytes(buf);
|
||||
buf.release(); // release buffer
|
||||
|
||||
// Write biome data
|
||||
if (chunk.isBiomeData()) {
|
||||
output.writeBytes(chunk.getBiomeData());
|
||||
}
|
||||
|
||||
// Type.NBT_ARRAY.write(output, tags.toArray(new CompoundTag[0])); Written by the handler
|
||||
}
|
||||
}
|
||||
+197
@@ -0,0 +1,197 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import us.myles.ViaVersion.api.minecraft.chunks.NibbleArray;
|
||||
import us.myles.ViaVersion.api.type.Type;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ChunkSection1_9_1_2 {
|
||||
/**
|
||||
* Size (dimensions) of blocks in a chunks section.
|
||||
*/
|
||||
public static final int SIZE = 16 * 16 * 16; // width * depth * height
|
||||
/**
|
||||
* Length of the sky and block light nibble arrays.
|
||||
*/
|
||||
public static final int LIGHT_LENGTH = 16 * 16 * 16 / 2; // size * size * size / 2 (nibble bit count)
|
||||
/**
|
||||
* Length of the block data array.
|
||||
*/
|
||||
|
||||
private final List<Integer> palette = Lists.newArrayList();
|
||||
private final int[] blocks;
|
||||
private final NibbleArray blockLight;
|
||||
private NibbleArray skyLight;
|
||||
|
||||
public ChunkSection1_9_1_2() {
|
||||
this.blocks = new int[SIZE];
|
||||
this.blockLight = new NibbleArray(SIZE);
|
||||
palette.add(0); // AIR
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a block in the chunks
|
||||
*
|
||||
* @param x Block X
|
||||
* @param y Block Y
|
||||
* @param z Block Z
|
||||
* @param type The type of the block
|
||||
* @param data The data value of the block
|
||||
*/
|
||||
public void setBlock(int x, int y, int z, int type, int data) {
|
||||
setBlock(index(x, y, z), type, data);
|
||||
}
|
||||
|
||||
public int getBlockId(int x, int y, int z){
|
||||
int index = blocks[index(x, y, z)];
|
||||
return palette.indexOf(index) >> 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a block in the chunks based on the index
|
||||
*
|
||||
* @param idx Index
|
||||
* @param type The type of the block
|
||||
* @param data The data value of the block
|
||||
*/
|
||||
public void setBlock(int idx, int type, int data) {
|
||||
int hash = type << 4 | (data & 0xF);
|
||||
int index = palette.indexOf(hash);
|
||||
if (index == -1) {
|
||||
index = palette.size();
|
||||
palette.add(hash);
|
||||
}
|
||||
|
||||
blocks[idx] = index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the block light array
|
||||
*
|
||||
* @param data The value to set the block light to
|
||||
*/
|
||||
public void setBlockLight(byte[] data) {
|
||||
blockLight.setHandle(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the sky light array
|
||||
*
|
||||
* @param data The value to set the sky light to
|
||||
*/
|
||||
public void setSkyLight(byte[] data) {
|
||||
if (data.length != LIGHT_LENGTH) throw new IllegalArgumentException("Data length != " + LIGHT_LENGTH);
|
||||
this.skyLight = new NibbleArray(data);
|
||||
}
|
||||
|
||||
private int index(int x, int y, int z) {
|
||||
return z << 8 | y << 4 | x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the blocks to a buffer.
|
||||
*
|
||||
* @param output The buffer to write to.
|
||||
* @throws Exception Throws if it failed to write.
|
||||
*/
|
||||
public void writeBlocks(ByteBuf output) throws Exception {
|
||||
// Write bits per block
|
||||
int bitsPerBlock = 4;
|
||||
while (palette.size() > 1 << bitsPerBlock) {
|
||||
bitsPerBlock += 1;
|
||||
}
|
||||
long maxEntryValue = (1L << bitsPerBlock) - 1;
|
||||
output.writeByte(bitsPerBlock);
|
||||
|
||||
// Write pallet (or not)
|
||||
Type.VAR_INT.write(output, palette.size());
|
||||
for (int mappedId : palette) {
|
||||
Type.VAR_INT.write(output, mappedId);
|
||||
}
|
||||
|
||||
int length = (int) Math.ceil(SIZE * bitsPerBlock / 64.0);
|
||||
Type.VAR_INT.write(output, length);
|
||||
long[] data = new long[length];
|
||||
for (int index = 0; index < blocks.length; index++) {
|
||||
int value = blocks[index];
|
||||
int bitIndex = index * bitsPerBlock;
|
||||
int startIndex = bitIndex / 64;
|
||||
int endIndex = ((index + 1) * bitsPerBlock - 1) / 64;
|
||||
int startBitSubIndex = bitIndex % 64;
|
||||
data[startIndex] = data[startIndex] & ~(maxEntryValue << startBitSubIndex) | ((long) value & maxEntryValue) << startBitSubIndex;
|
||||
if (startIndex != endIndex) {
|
||||
int endBitSubIndex = 64 - startBitSubIndex;
|
||||
data[endIndex] = data[endIndex] >>> endBitSubIndex << endBitSubIndex | ((long) value & maxEntryValue) >> endBitSubIndex;
|
||||
}
|
||||
}
|
||||
for (long l : data) {
|
||||
Type.LONG.write(output, l);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the block light to a buffer
|
||||
*
|
||||
* @param output The buffer to write to
|
||||
*/
|
||||
public void writeBlockLight(ByteBuf output) {
|
||||
output.writeBytes(blockLight.getHandle());
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the sky light to a buffer
|
||||
*
|
||||
* @param output The buffer to write to
|
||||
*/
|
||||
public void writeSkyLight(ByteBuf output) {
|
||||
output.writeBytes(skyLight.getHandle());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if sky light is present
|
||||
*
|
||||
* @return True if skylight is present
|
||||
*/
|
||||
public boolean hasSkyLight() {
|
||||
return skyLight != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get expected size of this chunks 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;
|
||||
int bytes = 1; // bits per block
|
||||
bytes += paletteBytes(); // palette
|
||||
bytes += countBytes(bitsPerBlock == 16 ? SIZE * 2 : SIZE); // block data length
|
||||
bytes += (palette.size() > 255 ? 2 : 1) * SIZE; // block data
|
||||
bytes += LIGHT_LENGTH; // block light
|
||||
bytes += hasSkyLight() ? LIGHT_LENGTH : 0; // sky light
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private int paletteBytes() throws Exception {
|
||||
// Count bytes used by pallet
|
||||
int bytes = countBytes(palette.size());
|
||||
for (int mappedId : palette) {
|
||||
bytes += countBytes(mappedId);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private int countBytes(int value) throws Exception {
|
||||
// Count amount of bytes that would be sent if the value were sent as a VarInt
|
||||
ByteBuf buf = Unpooled.buffer();
|
||||
Type.VAR_INT.write(buf, value);
|
||||
buf.readerIndex(0);
|
||||
int bitCount = buf.readableBytes();
|
||||
buf.release();
|
||||
return bitCount;
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.spacehq.opennbt.tag.builtin.CompoundTag;
|
||||
import org.spacehq.opennbt.tag.builtin.IntTag;
|
||||
import org.spacehq.opennbt.tag.builtin.StringTag;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Mojang changed the way how tile entities inside chunk packets work in 1.10.1
|
||||
* It requires now to have all tile entity data included in the chunk packet, otherwise it'll crash.
|
||||
*/
|
||||
public class FakeTileEntity {
|
||||
private static Map<Integer, CompoundTag> tileEntities = new ConcurrentHashMap<>();
|
||||
|
||||
static {
|
||||
register(Material.FURNACE, "Furnace");
|
||||
register(Arrays.asList(Material.CHEST, Material.TRAPPED_CHEST), "Chest");
|
||||
register(Material.ENDER_CHEST, "EnderChest");
|
||||
register(Material.JUKEBOX, "RecordPlayer");
|
||||
register(Material.DISPENSER, "Trap");
|
||||
register(Material.DROPPER, "Dropper");
|
||||
register(Arrays.asList(Material.SIGN_POST, Material.WALL_SIGN), "Sign");
|
||||
register(Material.MOB_SPAWNER, "MobSpawner");
|
||||
register(Material.NOTE_BLOCK, "Music");
|
||||
register(Material.PISTON_BASE, "Piston");
|
||||
register(Arrays.asList(Material.BREWING_STAND, Material.CAULDRON), "Cauldron");
|
||||
register(Material.ENCHANTMENT_TABLE, "EnchantTable");
|
||||
register(Arrays.asList(Material.ENDER_PORTAL, Material.ENDER_PORTAL_FRAME), "Airportal");
|
||||
register(Material.BEACON, "Beacon");
|
||||
register(Arrays.asList(Material.SKULL, Material.SKULL_ITEM), "Skull");
|
||||
register(Arrays.asList(Material.DAYLIGHT_DETECTOR, Material.DAYLIGHT_DETECTOR_INVERTED), "DLDetector");
|
||||
register(Material.HOPPER, "Hopper");
|
||||
register(Arrays.asList(Material.REDSTONE_COMPARATOR, Material.REDSTONE_COMPARATOR_OFF, Material.REDSTONE_COMPARATOR_ON), "Comparator");
|
||||
register(Material.FLOWER_POT, "FlowerPot");
|
||||
register(Arrays.asList(Material.STANDING_BANNER, Material.WALL_BANNER, Material.BANNER), "Banner");
|
||||
register(209, "EndGateway"); // todo test
|
||||
register(Material.COMMAND.getId(), "Control");
|
||||
}
|
||||
|
||||
private static void register(Integer material, String name) {
|
||||
CompoundTag comp = new CompoundTag("");
|
||||
comp.put(new StringTag(name));
|
||||
tileEntities.put(material, comp);
|
||||
}
|
||||
|
||||
private static void register(Material material, String name) {
|
||||
register(material.getId(), name);
|
||||
}
|
||||
|
||||
private static void register(List<Material> materials, String name) {
|
||||
for (Material m : materials)
|
||||
register(m.getId(), name);
|
||||
}
|
||||
|
||||
public static boolean hasBlock(int block) {
|
||||
return tileEntities.containsKey(block);
|
||||
}
|
||||
|
||||
public static CompoundTag getFromBlock(int x, int y, int z, int block) {
|
||||
if (tileEntities.containsKey(block)) {
|
||||
CompoundTag tag = tileEntities.get(block).clone();
|
||||
tag.put(new IntTag("x", x));
|
||||
tag.put(new IntTag("y", y));
|
||||
tag.put(new IntTag("z", z));
|
||||
return tag;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+38
-3
@@ -11,6 +11,13 @@ import us.myles.ViaVersion.api.remapper.PacketHandler;
|
||||
import us.myles.ViaVersion.api.remapper.PacketRemapper;
|
||||
import us.myles.ViaVersion.api.type.Type;
|
||||
import us.myles.ViaVersion.packets.State;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.chunks.Chunk1_9to1_8;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.chunks.ChunkSection1_9to1_8;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.ClientChunks;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.types.ChunkType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Protocol1_9_3TO1_9_1_2 extends Protocol {
|
||||
@Override
|
||||
@@ -24,7 +31,7 @@ public class Protocol1_9_3TO1_9_1_2 extends Protocol {
|
||||
registerOutgoing(State.PLAY, 0x4B, 0x4A); //Entity properties
|
||||
registerOutgoing(State.PLAY, 0x4C, 0x4B); //Entity effect
|
||||
|
||||
//Sign update
|
||||
// Sign update packet
|
||||
registerOutgoing(State.PLAY, 0x46, -1, new PacketRemapper() {
|
||||
@Override
|
||||
public void registerMap() {
|
||||
@@ -60,14 +67,42 @@ public class Protocol1_9_3TO1_9_1_2 extends Protocol {
|
||||
}
|
||||
});
|
||||
|
||||
// Chunk packet
|
||||
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);
|
||||
ClientChunks clientChunks = wrapper.user().get(ClientChunks.class);
|
||||
|
||||
ChunkType type = new ChunkType(clientChunks);
|
||||
if (wrapper.isReadable(type, 0)) {
|
||||
Chunk1_9to1_8 chunk = (Chunk1_9to1_8) wrapper.read(type);
|
||||
|
||||
List<CompoundTag> tags = new ArrayList<>();
|
||||
for (int i = 0; i < chunk.getSections().length; i++) {
|
||||
ChunkSection1_9to1_8 section = chunk.getSections()[i];
|
||||
if (section == null)
|
||||
continue;
|
||||
|
||||
for (int x = 0; x < 16; x++)
|
||||
for (int y = 0; y < 16; y++)
|
||||
for (int z = 0; z < 16; z++) {
|
||||
int block = section.getBlockId(x, y, z);
|
||||
if (FakeTileEntity.hasBlock(block)) {
|
||||
// NOT SURE WHY Y AND Z WORK THIS WAY, TODO: WORK OUT WHY THIS IS OR FIX W/E BROKE IT
|
||||
tags.add(FakeTileEntity.getFromBlock(x + (chunk.getX() << 4), z + (i << 4), y + (chunk.getZ() << 4), block));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wrapper.write(type, chunk);
|
||||
wrapper.write(Type.NBT_ARRAY, tags.toArray(new CompoundTag[0]));
|
||||
} else {
|
||||
wrapper.passthroughAll();
|
||||
wrapper.write(Type.VAR_INT, 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -98,13 +98,13 @@ public class Protocol1_9TO1_8 extends Protocol {
|
||||
Bukkit.getPluginManager().registerEvents(new CommandBlockListener(plugin), plugin);
|
||||
Bukkit.getPluginManager().registerEvents(new DeathListener(plugin), plugin);
|
||||
Bukkit.getPluginManager().registerEvents(new BlockListener(plugin), plugin);
|
||||
if (Bukkit.getVersion().toLowerCase().contains("paper")) {
|
||||
plugin.getLogger().info("Enabling PaperSpigot patch: Fixes block placement.");
|
||||
if (Bukkit.getVersion().toLowerCase().contains("paper") || Bukkit.getVersion().toLowerCase().contains("taco")) {
|
||||
plugin.getLogger().info("Enabling PaperSpigot/TacoSpigot patch: Fixes block placement.");
|
||||
Bukkit.getPluginManager().registerEvents(new PaperPatch(), plugin);
|
||||
}
|
||||
if (plugin.getConfig().getBoolean("simulate-pt", true))
|
||||
if (plugin.getConf().isStimulatePlayerTick())
|
||||
new ViaIdleThread(plugin.getPortedPlayers()).runTaskTimer(plugin, 1L, 1L); // Updates player's idle status
|
||||
if (plugin.getConfig().getBoolean("item-cache", true)) {
|
||||
if (plugin.getConf().isItemCache()) {
|
||||
new HandItemCache().runTaskTimerAsynchronously(plugin, 2L, 2L); // Updates player's items :)
|
||||
HandItemCache.CACHE = true;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import us.myles.ViaVersion.ViaVersionPlugin;
|
||||
import us.myles.ViaVersion.api.ViaVersion;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||
@@ -30,7 +29,7 @@ public class ViaIdleThread extends BukkitRunnable {
|
||||
private Method handleFlying;
|
||||
|
||||
public ViaIdleThread(Map<UUID, UserConnection> portedPlayers) {
|
||||
USE_NMS = ((ViaVersionPlugin) ViaVersion.getInstance()).getConfig().getBoolean("nms-player-ticking", true);
|
||||
USE_NMS = ViaVersion.getConfig().isNMSPlayerTicking();
|
||||
|
||||
this.portedPlayers = portedPlayers;
|
||||
Class<?> idlePacketClass;
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_9to1_8.chunks;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import us.myles.ViaVersion.api.minecraft.chunks.Chunk;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
@ToString
|
||||
public class Chunk1_9to1_8 implements Chunk {
|
||||
private final int x;
|
||||
private final int z;
|
||||
private final boolean groundUp;
|
||||
private final int primaryBitmask;
|
||||
private final ChunkSection1_9to1_8[] sections;
|
||||
private final byte[] biomeData;
|
||||
private boolean unloadPacket = false;
|
||||
|
||||
/**
|
||||
* Chunk unload.
|
||||
*
|
||||
* @param x coord
|
||||
* @param z coord
|
||||
*/
|
||||
public Chunk1_9to1_8(int x, int z) {
|
||||
this(x, z, true, 0, new ChunkSection1_9to1_8[16], null);
|
||||
this.unloadPacket = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this chunks have biome data
|
||||
*
|
||||
* @return True if the chunks has biome data
|
||||
*/
|
||||
public boolean hasBiomeData() {
|
||||
return biomeData != null && groundUp;
|
||||
}
|
||||
}
|
||||
+14
-7
@@ -1,15 +1,16 @@
|
||||
package us.myles.ViaVersion.api.minecraft.chunks;
|
||||
package us.myles.ViaVersion.protocols.protocol1_9to1_8.chunks;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import us.myles.ViaVersion.api.minecraft.chunks.NibbleArray;
|
||||
import us.myles.ViaVersion.api.type.Type;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ChunkSection {
|
||||
public class ChunkSection1_9to1_8 {
|
||||
/**
|
||||
* Size (dimensions) of blocks in a chunk section.
|
||||
* Size (dimensions) of blocks in a chunks section.
|
||||
*/
|
||||
public static final int SIZE = 16 * 16 * 16; // width * depth * height
|
||||
/**
|
||||
@@ -25,14 +26,14 @@ public class ChunkSection {
|
||||
private final NibbleArray blockLight;
|
||||
private NibbleArray skyLight;
|
||||
|
||||
public ChunkSection() {
|
||||
public ChunkSection1_9to1_8() {
|
||||
this.blocks = new int[SIZE];
|
||||
this.blockLight = new NibbleArray(SIZE);
|
||||
palette.add(0); // AIR
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a block in the chunk
|
||||
* Set a block in the chunks
|
||||
*
|
||||
* @param x Block X
|
||||
* @param y Block Y
|
||||
@@ -44,8 +45,13 @@ public class ChunkSection {
|
||||
setBlock(index(x, y, z), type, data);
|
||||
}
|
||||
|
||||
public int getBlockId(int x, int y, int z){
|
||||
int index = blocks[index(x, y, z)];
|
||||
return palette.get(index) >> 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a block in the chunk based on the index
|
||||
* Set a block in the chunks based on the index
|
||||
*
|
||||
* @param idx Index
|
||||
* @param type The type of the block
|
||||
@@ -154,9 +160,10 @@ public class ChunkSection {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get expected size of this chunk section.
|
||||
* Get expected size of this chunks 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;
|
||||
+14
-19
@@ -1,7 +1,5 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_9to1_8.listeners;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
@@ -17,9 +15,9 @@ import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerRespawnEvent;
|
||||
import org.bukkit.inventory.CraftingInventory;
|
||||
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.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;
|
||||
@@ -40,24 +38,21 @@ 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();
|
||||
|
||||
PacketWrapper wrapper = new PacketWrapper(0x4B, null, userConnection);
|
||||
try {
|
||||
wrapper.write(Type.VAR_INT, player.getEntityId()); // Player ID
|
||||
wrapper.write(Type.INT, 1); // only 1 property
|
||||
wrapper.write(Type.STRING, "generic.armor");
|
||||
wrapper.write(Type.DOUBLE, 0D); //default 0 armor
|
||||
wrapper.write(Type.VAR_INT, 1); // 1 modifier
|
||||
wrapper.write(Type.UUID, ARMOR_ATTRIBUTE); // armor modifier uuid
|
||||
wrapper.write(Type.DOUBLE, (double) armor); // the modifier value
|
||||
wrapper.write(Type.BYTE, (byte) 0);// the modifier operation, 0 is add number
|
||||
|
||||
//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");
|
||||
buf.writeDouble(0); //default 0 armor
|
||||
Type.VAR_INT.write(buf, 1); // 1 modifier
|
||||
Type.UUID.write(buf, ARMOR_ATTRIBUTE); // armor modifier uuid
|
||||
buf.writeDouble((double) armor); // the modifier value
|
||||
buf.writeByte(0); // the modifier operation, 0 is add number
|
||||
|
||||
ViaVersion.getInstance().sendRawPacket(player, buf);
|
||||
} catch (Exception ignored) {
|
||||
buf.release();
|
||||
wrapper.send(Protocol1_9TO1_8.class);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+24
-17
@@ -19,6 +19,7 @@ import org.bukkit.event.player.PlayerRespawnEvent;
|
||||
import org.spacehq.opennbt.tag.builtin.ByteTag;
|
||||
import org.spacehq.opennbt.tag.builtin.CompoundTag;
|
||||
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.minecraft.Position;
|
||||
@@ -80,12 +81,12 @@ public class CommandBlockListener implements Listener {
|
||||
if (!userConnection.get(ProtocolInfo.class).getPipeline().contains(Protocol1_9TO1_8.class)) return;
|
||||
|
||||
try {
|
||||
ByteBuf buf = Unpooled.buffer();
|
||||
Type.VAR_INT.write(buf, 0x1B); // Entity Status
|
||||
buf.writeInt(p.getEntityId());
|
||||
buf.writeByte(26);
|
||||
plugin.sendRawPacket(p, buf);
|
||||
} catch (Exception ignored) {
|
||||
PacketWrapper wrapper = new PacketWrapper(0x1B, null, userConnection); // Entity status
|
||||
wrapper.write(Type.INT, p.getEntityId());
|
||||
wrapper.write(Type.BYTE, (byte) 26); //Hardcoded op permission level
|
||||
wrapper.send(Protocol1_9TO1_8.class);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,26 +98,32 @@ public class CommandBlockListener implements Listener {
|
||||
|
||||
Object tileEntityCommand = ReflectionUtil.get(cmd, "commandBlock", ReflectionUtil.nms("TileEntityCommand"));
|
||||
Object updatePacket = ReflectionUtil.invoke(tileEntityCommand, "getUpdatePacket");
|
||||
ByteBuf buf = packetToByteBuf(updatePacket);
|
||||
plugin.sendRawPacket(player, buf);
|
||||
|
||||
UserConnection userConnection = ((ViaVersionPlugin) ViaVersion.getInstance()).getConnection(player);
|
||||
|
||||
PacketWrapper wrapper = generatePacket(updatePacket, userConnection);
|
||||
wrapper.send(Protocol1_9TO1_8.class);
|
||||
}
|
||||
|
||||
private ByteBuf packetToByteBuf(Object updatePacket) throws Exception {
|
||||
ByteBuf buf = Unpooled.buffer();
|
||||
Type.VAR_INT.write(buf, 0x09); //Block Entity Packet ID
|
||||
private PacketWrapper generatePacket(Object updatePacket, UserConnection usr) throws Exception {
|
||||
PacketWrapper wrapper = new PacketWrapper(0x09, null, usr); // Update block entity
|
||||
|
||||
long[] pos = getPosition(ReflectionUtil.get(updatePacket, "a", ReflectionUtil.nms("BlockPosition")));
|
||||
Type.POSITION.write(buf, new Position(pos[0], pos[1], pos[2])); //Block position
|
||||
buf.writeByte(2); //Action id always 2
|
||||
|
||||
wrapper.write(Type.POSITION, new Position(pos[0], pos[1], pos[2])); //Block position
|
||||
wrapper.write(Type.BYTE, (byte) 2); // Action id always 2
|
||||
|
||||
CompoundTag nbt = getNBT(ReflectionUtil.get(updatePacket, "c", ReflectionUtil.nms("NBTTagCompound")));
|
||||
if (nbt == null) {
|
||||
buf.writeByte(0); //If nbt is null. Use 0 as nbt
|
||||
return buf;
|
||||
wrapper.write(Type.BYTE, (byte) 0); //If nbt is null. Use 0 as nbt
|
||||
return wrapper;
|
||||
}
|
||||
nbt.put(new ByteTag("powered", (byte) 0));
|
||||
nbt.put(new ByteTag("auto", (byte) 0));
|
||||
nbt.put(new ByteTag("conditionMet", (byte) 0));
|
||||
Type.NBT.write(buf, nbt); //NBT tag
|
||||
return buf;
|
||||
|
||||
wrapper.write(Type.NBT, nbt); // NBT TAG
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
private long[] getPosition(Object obj) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
|
||||
|
||||
+3
-2
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -54,7 +55,7 @@ public class DeathListener implements Listener {
|
||||
wrapper.write(Type.VAR_INT, p.getEntityId());
|
||||
wrapper.write(Type.INT, p.getEntityId());
|
||||
Protocol1_9TO1_8.FIX_JSON.write(wrapper, msg);
|
||||
wrapper.send();
|
||||
wrapper.send(Protocol1_9TO1_8.class);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
wrapper.clearInputBuffer();
|
||||
|
||||
+20
-14
@@ -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];
|
||||
}
|
||||
|
||||
}
|
||||
+7
-8
@@ -57,7 +57,7 @@ public class EntityPackets {
|
||||
passengerPacket.write(Type.VAR_INT_ARRAY, new Integer[]{passenger});
|
||||
tracker.getVehicleMap().put(passenger, vehicle);
|
||||
}
|
||||
passengerPacket.send(); // Send the packet
|
||||
passengerPacket.send(Protocol1_9TO1_8.class); // Send the packet
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
});
|
||||
|
||||
+3
-3
@@ -44,7 +44,7 @@ public class InventoryPackets {
|
||||
wrapper.write(Type.SHORT, property);
|
||||
wrapper.write(Type.SHORT, enchantID);
|
||||
}
|
||||
}).send();
|
||||
}).send(Protocol1_9TO1_8.class);
|
||||
|
||||
wrapper.set(Type.SHORT, 0, (short) (property + 3));
|
||||
wrapper.set(Type.SHORT, 1, level);
|
||||
@@ -230,7 +230,7 @@ public class InventoryPackets {
|
||||
wrapper.write(Type.SHORT, slot);
|
||||
wrapper.write(Type.SHORT, (short) -1);
|
||||
}
|
||||
}).send();
|
||||
}).send(Protocol1_9TO1_8.class);
|
||||
// Finally reset to simulate throwing item
|
||||
wrapper.set(Type.SHORT, 0, (short) -999); // Set slot to -999
|
||||
}
|
||||
@@ -285,7 +285,7 @@ public class InventoryPackets {
|
||||
wrapper.write(Type.SHORT, slot);
|
||||
wrapper.write(Type.SHORT, (short) -1);
|
||||
}
|
||||
}).send();
|
||||
}).send(Protocol1_9TO1_8.class);
|
||||
// Finally reset to simulate throwing item
|
||||
wrapper.set(Type.BYTE, 0, (byte) 0); // Set button to 0
|
||||
wrapper.set(Type.BYTE, 1, (byte) 0); // Set mode to 0
|
||||
|
||||
+9
-3
@@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -103,13 +104,13 @@ public class SpawnPackets {
|
||||
List<Metadata> meta = new ArrayList<>();
|
||||
Item item = new Item((short) Material.POTION.getId(), (byte) 1, (short) data, null);
|
||||
ItemRewriter.toClient(item); // Rewrite so that it gets the right nbt
|
||||
|
||||
// TEMP FIX FOR POTIONS UNTIL WE FIGURE OUT HOW TO TRANSFORM SENT PACKETS
|
||||
Metadata potion = new Metadata(5, NewType.Slot.getTypeID(), Type.ITEM, item);
|
||||
meta.add(potion);
|
||||
wrapper.write(Protocol1_9TO1_8.METADATA_LIST, meta);
|
||||
}
|
||||
});
|
||||
metaPacket.send();
|
||||
metaPacket.send(Protocol1_9TO1_8.class);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -297,7 +303,7 @@ public class SpawnPackets {
|
||||
packet.write(Type.VAR_INT, 0);
|
||||
packet.write(Type.ITEM, new Item(item, (byte) 1, (short) 0, null));
|
||||
try {
|
||||
packet.send();
|
||||
packet.send(Protocol1_9TO1_8.class);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
+2
-42
@@ -6,7 +6,6 @@ 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;
|
||||
@@ -16,6 +15,7 @@ import us.myles.ViaVersion.api.type.Type;
|
||||
import us.myles.ViaVersion.packets.State;
|
||||
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.chunks.Chunk1_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;
|
||||
@@ -115,7 +115,7 @@ public class WorldPackets {
|
||||
@Override
|
||||
public void handle(PacketWrapper wrapper) throws Exception {
|
||||
ClientChunks clientChunks = wrapper.user().get(ClientChunks.class);
|
||||
Chunk chunk = wrapper.passthrough(new ChunkType(clientChunks));
|
||||
Chunk1_9to1_8 chunk = (Chunk1_9to1_8) wrapper.passthrough(new ChunkType(clientChunks));
|
||||
if (chunk.isUnloadPacket())
|
||||
wrapper.setId(0x1D);
|
||||
|
||||
@@ -283,46 +283,6 @@ public class WorldPackets {
|
||||
wrapper.write(Type.BYTE, (byte) 0);
|
||||
}
|
||||
});
|
||||
/*
|
||||
|
||||
The thing i've discovered is when using an item in air, it needs to send 2 packets.
|
||||
I believe the issue is that this needs to be flipped with the packet above while still
|
||||
sending block info.
|
||||
|
||||
Otherwise no idea, the disadvantage: Interact does not get fired if you right click
|
||||
special items. (there's quite a few...)
|
||||
|
||||
*/
|
||||
// handler(new PacketHandler() {
|
||||
// @Override
|
||||
// public void handle(PacketWrapper wrapper) throws Exception {
|
||||
// if(wrapper.isCancelled()) return;
|
||||
// EntityTracker tracker = wrapper.user().get(EntityTracker.class);
|
||||
// if(tracker.isBlocking()) return;
|
||||
//
|
||||
// Long last = tracker.getLastPlaceBlock();
|
||||
// if (last != -1) {
|
||||
// if ((wrapper.user().getReceivedPackets() - last) < 3) {
|
||||
// tracker.setLastPlaceBlock(-1L);
|
||||
// return;
|
||||
// }
|
||||
// tracker.setLastPlaceBlock(-1L);
|
||||
// }
|
||||
// final Item item = wrapper.get(Type.ITEM, 0);
|
||||
// wrapper.create(0x08, new ValueCreator() {
|
||||
// @Override
|
||||
// public void write(PacketWrapper wrapper) throws Exception {
|
||||
// wrapper.write(Type.POSITION, new Position(1L, 1L, 1L));
|
||||
// wrapper.write(Type.BYTE, (byte) 2);
|
||||
// wrapper.write(Type.ITEM, item); // hand
|
||||
//
|
||||
// wrapper.write(Type.UNSIGNED_BYTE, (short) 1);
|
||||
// wrapper.write(Type.UNSIGNED_BYTE, (short) 1);
|
||||
// wrapper.write(Type.UNSIGNED_BYTE, (short) 1);
|
||||
// }
|
||||
// }).sendToServer();
|
||||
// }
|
||||
// });
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
+2
-2
@@ -64,7 +64,7 @@ public enum SoundEffect {
|
||||
MOB_HORSE_WOOD("mob.horse.wood", "entity.horse.step_wood", SoundCategory.NEUTRAL),
|
||||
MOB_ZOMBIE_UNFECT("mob.zombie.unfect", "entity.zombie_villager.converted", SoundCategory.HOSTILE),
|
||||
RANDOM_ANVIL_USE("random.anvil_use", "block.anvil.use", SoundCategory.BLOCK),
|
||||
RANDOM_CHESTCLOSED("random.chestclosed", "block.enderchest.close", SoundCategory.BLOCK),
|
||||
RANDOM_CHESTCLOSED("random.chestclosed", "block.chest.close", SoundCategory.BLOCK),
|
||||
MOB_SHEEP_SHEAR("mob.sheep.shear", "entity.sheep.shear", SoundCategory.NEUTRAL),
|
||||
RANDOM_POP("random.pop", "entity.item.pickup", SoundCategory.PLAYER),
|
||||
MOB_BAT_DEATH("mob.bat.death", "entity.bat.death", SoundCategory.NEUTRAL),
|
||||
@@ -85,7 +85,7 @@ public enum SoundEffect {
|
||||
MOB_HORSE_SKELETON_DEATH("mob.horse.skeleton.death", "entity.skeleton_horse.death", SoundCategory.NEUTRAL),
|
||||
AMBIENT_WEATHER_RAIN("ambient.weather.rain", "weather.rain.above", SoundCategory.WEATHER),
|
||||
PORTAL_TRIGGER("portal.trigger", "block.portal.trigger", SoundCategory.BLOCK),
|
||||
RANDOM_CHESTOPEN("random.chestopen", "block.enderchest.open", SoundCategory.BLOCK),
|
||||
RANDOM_CHESTOPEN("random.chestopen", "block.chest.open", SoundCategory.BLOCK),
|
||||
MOB_HORSE_LAND("mob.horse.land", "entity.horse.land", SoundCategory.NEUTRAL),
|
||||
MOB_SILVERFISH_STEP("mob.silverfish.step", "entity.silverfish.step", SoundCategory.HOSTILE),
|
||||
MOB_BAT_TAKEOFF("mob.bat.takeoff", "entity.bat.takeoff", SoundCategory.NEUTRAL),
|
||||
|
||||
+26
-2
@@ -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,13 +19,17 @@ 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);
|
||||
Bukkit.getLogger().log(Level.WARNING, "Failed to initialise chunks 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];
|
||||
@@ -57,7 +81,7 @@ public class ClientChunks extends StoredObject {
|
||||
list.add(chunkPacket);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Failed to transform chunk bulk", e);
|
||||
Bukkit.getLogger().log(Level.WARNING, "Failed to transform chunks bulk", e);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
+58
-22
@@ -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,28 +20,30 @@ 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;
|
||||
@Setter
|
||||
private boolean autoTeam = false;
|
||||
@Setter
|
||||
private Long lastPlaceBlock = -1L;
|
||||
@Setter
|
||||
private int entityID;
|
||||
@Setter
|
||||
private Position currentlyDigging = null;
|
||||
@@ -75,7 +75,7 @@ public class EntityTracker extends StoredObject {
|
||||
wrapper.write(Type.VAR_INT, 1); // slot
|
||||
wrapper.write(Type.ITEM, item);
|
||||
try {
|
||||
wrapper.send();
|
||||
wrapper.send(Protocol1_9TO1_8.class);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -87,6 +87,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) {
|
||||
@@ -113,7 +114,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)) {
|
||||
@@ -138,11 +141,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);
|
||||
@@ -154,7 +164,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();
|
||||
@@ -169,7 +179,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);
|
||||
@@ -179,9 +189,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);
|
||||
@@ -190,12 +200,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;
|
||||
@@ -204,7 +214,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);
|
||||
@@ -246,9 +256,35 @@ public class EntityTracker extends StoredObject {
|
||||
}
|
||||
teamExists = b;
|
||||
try {
|
||||
wrapper.send();
|
||||
wrapper.send(Protocol1_9TO1_8.class);
|
||||
} catch (Exception e) {
|
||||
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(Protocol1_9TO1_8.class);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
metadataBuffer.remove(entityID);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -8,7 +8,7 @@ import us.myles.ViaVersion.api.minecraft.Position;
|
||||
|
||||
@Getter
|
||||
public class PlaceBlockTracker extends StoredObject {
|
||||
private long lastPlaceTimestamp = System.currentTimeMillis();
|
||||
private long lastPlaceTimestamp = 0;
|
||||
@Setter
|
||||
private Position lastPlacedPosition = null;
|
||||
|
||||
|
||||
@@ -4,9 +4,11 @@ import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import org.bukkit.Bukkit;
|
||||
import us.myles.ViaVersion.api.minecraft.chunks.Chunk;
|
||||
import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection;
|
||||
import us.myles.ViaVersion.api.type.PartialType;
|
||||
import us.myles.ViaVersion.api.type.Type;
|
||||
import us.myles.ViaVersion.api.type.types.minecraft.BaseChunkType;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.chunks.Chunk1_9to1_8;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.chunks.ChunkSection1_9to1_8;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.ClientChunks;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
@@ -17,11 +19,11 @@ import java.util.logging.Level;
|
||||
|
||||
public class ChunkType extends PartialType<Chunk, ClientChunks> {
|
||||
/**
|
||||
* Amount of sections in a chunk.
|
||||
* Amount of sections in a chunks.
|
||||
*/
|
||||
private static final int SECTION_COUNT = 16;
|
||||
public static final int SECTION_COUNT = 16;
|
||||
/**
|
||||
* size of each chunk section (16x16x16).
|
||||
* size of each chunks section (16x16x16).
|
||||
*/
|
||||
private static final int SECTION_SIZE = 16;
|
||||
/**
|
||||
@@ -37,6 +39,11 @@ public class ChunkType extends PartialType<Chunk, ClientChunks> {
|
||||
return ((long) msw << 32) + lsw - -2147483648L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Type> getBaseClass() {
|
||||
return BaseChunkType.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk read(ByteBuf input, ClientChunks param) throws Exception {
|
||||
int chunkX = input.readInt();
|
||||
@@ -48,7 +55,7 @@ public class ChunkType extends PartialType<Chunk, ClientChunks> {
|
||||
|
||||
// Data to be read
|
||||
BitSet usedSections = new BitSet(16);
|
||||
ChunkSection[] sections = new ChunkSection[16];
|
||||
ChunkSection1_9to1_8[] sections = new ChunkSection1_9to1_8[16];
|
||||
byte[] biomeData = null;
|
||||
|
||||
// Calculate section count from bitmask
|
||||
@@ -59,33 +66,34 @@ public class ChunkType extends PartialType<Chunk, ClientChunks> {
|
||||
}
|
||||
int sectionCount = usedSections.cardinality(); // the amount of sections set
|
||||
|
||||
// If the chunk is from a chunk bulk, it is never an unload packet
|
||||
// If the chunks is from a chunks bulk, it is never an unload packet
|
||||
// Other wise, if it has no data, it is :)
|
||||
boolean isBulkPacket = param.getBulkChunks().remove(chunkHash);
|
||||
if (sectionCount == 0 && groundUp && !isBulkPacket && param.getLoadedChunks().contains(chunkHash)) {
|
||||
// This is a chunk unload packet
|
||||
// This is a chunks unload packet
|
||||
param.getLoadedChunks().remove(chunkHash);
|
||||
return new Chunk(chunkX, chunkZ);
|
||||
return new Chunk1_9to1_8(chunkX, chunkZ);
|
||||
}
|
||||
|
||||
int startIndex = input.readerIndex();
|
||||
param.getLoadedChunks().add(chunkHash); // mark chunk as loaded
|
||||
param.getLoadedChunks().add(chunkHash); // mark chunks as loaded
|
||||
|
||||
// Read blocks
|
||||
for (int i = 0; i < SECTION_COUNT; i++) {
|
||||
if (!usedSections.get(i)) continue; // Section not set
|
||||
ChunkSection section = new ChunkSection();
|
||||
ChunkSection1_9to1_8 section = new ChunkSection1_9to1_8();
|
||||
sections[i] = section;
|
||||
|
||||
// Read block data and convert to short buffer
|
||||
byte[] blockData = new byte[ChunkSection.SIZE * 2];
|
||||
byte[] blockData = new byte[ChunkSection1_9to1_8.SIZE * 2];
|
||||
input.readBytes(blockData);
|
||||
ShortBuffer blockBuf = ByteBuffer.wrap(blockData).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
|
||||
|
||||
for (int j = 0; j < ChunkSection.SIZE; j++) {
|
||||
for (int j = 0; j < ChunkSection1_9to1_8.SIZE; j++) {
|
||||
int mask = blockBuf.get();
|
||||
int type = mask >> 4;
|
||||
int data = mask & 0xF;
|
||||
|
||||
section.setBlock(j, type, data);
|
||||
}
|
||||
}
|
||||
@@ -93,20 +101,20 @@ public class ChunkType extends PartialType<Chunk, ClientChunks> {
|
||||
// Read block light
|
||||
for (int i = 0; i < SECTION_COUNT; i++) {
|
||||
if (!usedSections.get(i)) continue; // Section not set, has no light
|
||||
byte[] blockLightArray = new byte[ChunkSection.LIGHT_LENGTH];
|
||||
byte[] blockLightArray = new byte[ChunkSection1_9to1_8.LIGHT_LENGTH];
|
||||
input.readBytes(blockLightArray);
|
||||
sections[i].setBlockLight(blockLightArray);
|
||||
}
|
||||
|
||||
// Read sky light
|
||||
int bytesLeft = dataLength - (input.readerIndex() - startIndex);
|
||||
if (bytesLeft >= ChunkSection.LIGHT_LENGTH) {
|
||||
if (bytesLeft >= ChunkSection1_9to1_8.LIGHT_LENGTH) {
|
||||
for (int i = 0; i < SECTION_COUNT; i++) {
|
||||
if (!usedSections.get(i)) continue; // Section not set, has no light
|
||||
byte[] skyLightArray = new byte[ChunkSection.LIGHT_LENGTH];
|
||||
byte[] skyLightArray = new byte[ChunkSection1_9to1_8.LIGHT_LENGTH];
|
||||
input.readBytes(skyLightArray);
|
||||
sections[i].setSkyLight(skyLightArray);
|
||||
bytesLeft -= ChunkSection.LIGHT_LENGTH;
|
||||
bytesLeft -= ChunkSection1_9to1_8.LIGHT_LENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,15 +127,18 @@ public class ChunkType extends PartialType<Chunk, ClientChunks> {
|
||||
|
||||
// Check remaining bytes
|
||||
if (bytesLeft > 0) {
|
||||
Bukkit.getLogger().log(Level.WARNING, bytesLeft + " Bytes left after reading chunk! (" + groundUp + ")");
|
||||
Bukkit.getLogger().log(Level.WARNING, bytesLeft + " Bytes left after reading chunks! (" + groundUp + ")");
|
||||
}
|
||||
|
||||
// Return chunk
|
||||
return new Chunk(chunkX, chunkZ, groundUp, bitmask, sections, biomeData);
|
||||
// Return chunks
|
||||
return new Chunk1_9to1_8(chunkX, chunkZ, groundUp, bitmask, sections, biomeData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf output, ClientChunks param, Chunk chunk) throws Exception {
|
||||
public void write(ByteBuf output, ClientChunks param, Chunk input) throws Exception {
|
||||
if (!(input instanceof Chunk1_9to1_8)) throw new Exception("Incompatible chunk, " + input.getClass());
|
||||
|
||||
Chunk1_9to1_8 chunk = (Chunk1_9to1_8) input;
|
||||
// Write primary info
|
||||
output.writeInt(chunk.getX());
|
||||
output.writeInt(chunk.getZ());
|
||||
@@ -137,12 +148,14 @@ public class ChunkType extends PartialType<Chunk, ClientChunks> {
|
||||
|
||||
ByteBuf buf = Unpooled.buffer();
|
||||
for (int i = 0; i < SECTION_COUNT; i++) {
|
||||
ChunkSection section = chunk.getSections()[i];
|
||||
ChunkSection1_9to1_8 section = chunk.getSections()[i];
|
||||
if (section == null) continue; // Section not set
|
||||
section.writeBlocks(buf);
|
||||
section.writeBlockLight(buf);
|
||||
|
||||
if (!section.hasSkyLight()) continue; // No sky light, we're done here.
|
||||
section.writeSkyLight(buf);
|
||||
|
||||
}
|
||||
buf.readerIndex(0);
|
||||
Type.VAR_INT.write(output, buf.readableBytes() + (chunk.hasBiomeData() ? 256 : 0));
|
||||
@@ -153,5 +166,9 @@ public class ChunkType extends PartialType<Chunk, ClientChunks> {
|
||||
if (chunk.hasBiomeData()) {
|
||||
output.writeBytes(chunk.getBiomeData());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+2
-5
@@ -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 {
|
||||
|
||||
+2
-6
@@ -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 {
|
||||
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package us.myles.ViaVersion.protocols.protocol1_9to1_9_1;
|
||||
|
||||
import us.myles.ViaVersion.api.PacketWrapper;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
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_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
|
||||
}
|
||||
});
|
||||
|
||||
// Sound Effect Packet
|
||||
registerOutgoing(State.PLAY, 0x47, 0x47, new PacketRemapper() {
|
||||
@Override
|
||||
public void registerMap() {
|
||||
map(Type.VAR_INT); // 0 - Sound ID
|
||||
|
||||
handler(new PacketHandler() {
|
||||
@Override
|
||||
public void handle(PacketWrapper wrapper) throws Exception {
|
||||
int sound = wrapper.get(Type.VAR_INT, 0);
|
||||
|
||||
if (sound == 415) // Stop the Elytra sound for 1.9 (It's introduced in 1.9.2)
|
||||
wrapper.cancel();
|
||||
else if (sound >= 416) // Act like the Elytra sound never existed
|
||||
wrapper.set(Type.VAR_INT, 0, sound - 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(UserConnection userConnection) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package us.myles.ViaVersion.util;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class ProtocolSupportUtil {
|
||||
private static Method protocolVersionMethod = null;
|
||||
private static Method getIdMethod = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
protocolVersionMethod = Class.forName("protocolsupport.api.ProtocolSupportAPI").getMethod("getProtocolVersion", Player.class);
|
||||
getIdMethod = Class.forName("protocolsupport.api.ProtocolVersion").getMethod("getId");
|
||||
} catch (Exception e) {
|
||||
// ProtocolSupport not installed.
|
||||
}
|
||||
}
|
||||
|
||||
public static int getProtocolVersion(Player player) {
|
||||
if (protocolVersionMethod == null) return -1;
|
||||
try {
|
||||
Object version = protocolVersionMethod.invoke(null, player);
|
||||
return (int) getIdMethod.invoke(version);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
name: ViaVersion
|
||||
main: us.myles.ViaVersion.Bungee
|
||||
author: _MylesC
|
||||
version: ${project.version}
|
||||
@@ -1,44 +1,28 @@
|
||||
# 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 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, 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.
|
||||
|
||||
# What is the maximum per second a client can send
|
||||
# What is the maximum per second a client can send (Use %pps to display their pps)
|
||||
# Use -1 to disable.
|
||||
max-pps: 400
|
||||
max-pps: 600
|
||||
max-pps-kick-msg: "You are sending too many packets!"
|
||||
|
||||
# We can also kick them if over a period they send over a threshold a certain amount of times.
|
||||
@@ -51,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: -0.96
|
||||
# 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,8 +2,9 @@ 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]
|
||||
softdepend: [ProtocolSupport]
|
||||
commands:
|
||||
viaversion:
|
||||
description: Shows ViaVersion Version and more.
|
||||
|
||||
Reference in new issue
Block a user