Compare commits

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

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

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

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

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

* Remove test line

* Remove Lombok unused thingy

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

* Fix typo
2016-04-06 13:50:09 +01:00
Myles 7ea2156f37 Bump version 2016-04-05 14:31:40 +01:00
Mats 5032e7d07e Only apply the 'Hologram patch' to small entities since it only happens to them.
Only apply the 'Hologram patch' to small entities (Doesn't fix issue but hey)
2016-04-04 15:55:48 +01:00
Myles c7c6ee9fbc Delay registration of protocols until the plugin has loaded to prevent it being done at the wrong time, #323 #316 Fixed 2016-04-03 23:30:10 +01:00
Mats 4431ca63c2 Fix viaversion list command 2016-04-03 11:26:27 +01:00
Myles 1fa7211cf0 Construct List properly, Fix #314 2016-04-03 01:51:38 +01:00
Myles de576795dc Blame @Matsv 2016-04-02 22:59:40 +01:00
56 changed files with 1300 additions and 236 deletions

No files matched your search

+2 -4
View File
@@ -1,4 +1,4 @@
# ViaVersion 0.7.3
# ViaVersion 0.8.1
[![Build Status](https://travis-ci.org/MylesIsCool/ViaVersion.svg?branch=master)](https://travis-ci.org/MylesIsCool/ViaVersion)
[![Gitter](https://badges.gitter.im/MylesIsCool/ViaVersion.svg)](https://gitter.im/MylesIsCool/ViaVersion)
@@ -20,8 +20,6 @@ Sources:
**wiki.vg** (Protocol info, though I did have to find a lot myself)
**MCProtocolLib** (used for chunk reading & some of writing.)
**OpenNBT** (used for slot rewriting)
@@ -58,7 +56,7 @@ https://www.spigotmc.org/resources/viaversion.19254/history
You can find unofficial dev builds here:
**fillefilip8's Build Server:** http://build.fillecraft.com:8080/job/ViaVersion
**Terrobility's Build Server:** https://ci.terrocidepvp.net/job/ViaVersion/
**sgdc3's Build Server:** http://ci.xephi.fr/job/ViaVersion/
**sgdc3's Maven:** http://ci.xephi.fr/plugin/repository/everything/
+14 -1
View File
@@ -6,7 +6,7 @@
<groupId>us.myles</groupId>
<artifactId>viaversion</artifactId>
<version>0.7.4-SNAPSHOT</version>
<version>0.8.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>ViaVersion</name>
@@ -105,6 +105,10 @@
<pattern>com.google.gson</pattern>
<shadedPattern>us.myles.viaversion.libs.gson</shadedPattern>
</relocation>
<relocation>
<pattern>org.javassist</pattern>
<shadedPattern>us.myles.viaversion.libs.javassist</shadedPattern>
</relocation>
</relocations>
</configuration>
<executions>
@@ -157,6 +161,15 @@
</exclusions>
</dependency>
<!-- Javassist (Bytecode Library) -->
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.20.0-GA</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<!-- NBT Edit Library -->
<dependency>
<groupId>org.spacehq</groupId>
@@ -1,48 +0,0 @@
package us.myles.ViaVersion;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import org.bukkit.scheduler.BukkitRunnable;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.MovementTracker;
import us.myles.ViaVersion.util.PipelineUtil;
import us.myles.ViaVersion.util.ReflectionUtil;
import java.util.Map;
import java.util.UUID;
public class ViaIdleThread extends BukkitRunnable {
private final Map<UUID, UserConnection> portedPlayers;
private final Object idlePacket;
public ViaIdleThread(Map<UUID, UserConnection> portedPlayers) {
this.portedPlayers = portedPlayers;
try {
Class<?> idlePacketClass = ReflectionUtil.nms("PacketPlayInFlying");
idlePacket = idlePacketClass.newInstance();
} catch (InstantiationException | IllegalArgumentException | IllegalAccessException | ClassNotFoundException e) {
throw new RuntimeException("Couldn't find/make player idle packet, help!", e);
}
}
@Override
public void run() {
for (UserConnection info : portedPlayers.values()) {
if (info.get(ProtocolInfo.class).getPipeline().contains(Protocol1_9TO1_8.class)) {
long nextIdleUpdate = info.get(MovementTracker.class).getNextIdlePacket();
if (nextIdleUpdate <= System.currentTimeMillis()) {
ChannelHandlerContext context = PipelineUtil.getContextBefore("decoder", info.getChannel().pipeline());
if(info.getChannel().isOpen()) {
if (context != null) {
context.fireChannelRead(idlePacket);
info.get(MovementTracker.class).incrementIdlePacket();
}
}
}
}
}
}
}
@@ -20,6 +20,7 @@ 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;
@@ -48,6 +49,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
private List<Pair<Field, Object>> injectedLists = new ArrayList<>();
private ViaCommandHandler commandHandler;
private boolean debug = false;
private boolean compatSpigotBuild = false;
@Override
public void onLoad() {
@@ -65,8 +67,16 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
}
}
// Check if it's a spigot build with a protocol mod
try {
compatSpigotBuild = ReflectionUtil.nms("PacketEncoder").getDeclaredField("version") != null;
} catch (Exception e){
compatSpigotBuild = false;
}
// Generate classes needed (only works if it's compat)
ClassGenerator.generate();
getLogger().info("ViaVersion " + getDescription().getVersion() + " is now loaded, injecting.");
getLogger().info("ViaVersion " + getDescription().getVersion() + (compatSpigotBuild ? "compat" : "") + " is now loaded, injecting.");
injectPacketHandler();
}
@@ -94,6 +104,9 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
getCommand("viaversion").setExecutor(commandHandler = new ViaCommandHandler());
getCommand("viaversion").setTabCompleter(commandHandler);
// Register Protocol Listeners
ProtocolRegistry.registerListeners();
}
@Override
@@ -345,6 +358,11 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
return commandHandler;
}
@Override
public boolean isCompatSpigotBuild() {
return compatSpigotBuild;
}
public boolean isCheckForUpdates() {
return getConfig().getBoolean("checkforupdates", true);
}
@@ -357,6 +375,11 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
return getConfig().getBoolean("use-new-effect-indicator", true);
}
@Override
public boolean isShowNewDeathMessages() {
return getConfig().getBoolean("use-new-deathmessages", false);
}
public boolean isSuppressMetadataErrors() {
return getConfig().getBoolean("suppress-metadata-errors", false);
}
@@ -385,6 +408,40 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
return getConfig().getDouble("hologram-y", -1D);
}
public boolean isBlockBreakPatch() {
return getConfig().getBoolean("block-break-patch", true);
}
@Override
public int getMaxPPS() {
return getConfig().getInt("max-pps", 140);
}
@Override
public String getMaxPPSKickMessage() {
return getConfig().getString("max-pps-kick-msg", "Sending packets too fast? lag?");
}
@Override
public int getTrackingPeriod() {
return getConfig().getInt("tracking-period", 6);
}
@Override
public int getWarningPPS() {
return getConfig().getInt("tracking-warning-pps", 120);
}
@Override
public int getMaxWarnings() {
return getConfig().getInt("tracking-max-warnings", 3);
}
@Override
public String getMaxWarningsKickMessage() {
return getConfig().getString("tracking-max-kick-msg", "You are sending too many packets, :(");
}
public boolean isAutoTeam() {
// Collision has to be enabled first
return isPreventCollision() && getConfig().getBoolean("auto-team", true);
@@ -420,4 +477,34 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
public Map<UUID, UserConnection> getPortedPlayers() {
return portedPlayers;
}
public boolean handlePPS(UserConnection info) {
// Max PPS Checker
if (getMaxPPS() > 0) {
if (info.getPacketsPerSecond() >= getMaxPPS()) {
info.disconnect(getMaxPPSKickMessage());
return true; // don't send current packet
}
}
// Tracking PPS Checker
if (getMaxWarnings() > 0 && getTrackingPeriod() > 0) {
if (info.getSecondsObserved() > getTrackingPeriod()) {
// Reset
info.setWarnings(0);
info.setSecondsObserved(1);
} else {
info.setSecondsObserved(info.getSecondsObserved() + 1);
if (info.getPacketsPerSecond() >= getWarningPPS()) {
info.setWarnings(info.getWarnings() + 1);
}
if (info.getWarnings() >= getMaxWarnings()) {
info.disconnect(getMaxWarningsKickMessage());
return true; // don't send current packet
}
}
}
return false;
}
}
@@ -56,6 +56,26 @@ public class PacketWrapper {
throw new InformativeException(e).set("Type", type.getTypeName()).set("Index", index).set("Packet ID", getId()).set("Data", packetValues);
}
/**
* Check if a type is at an index
*
* @param type The type of the part you wish to get.
* @param index The index of the part (relative to the type)
* @return True if the type is at the index
*/
public boolean is(Type type, int index) {
int currentIndex = 0;
for (Pair<Type, Object> packetValue : packetValues) {
if (packetValue.getKey() == type) { // Ref check
if (currentIndex == index) {
return true;
}
currentIndex++;
}
}
return false;
}
/**
* Set a currently existing part in the output
*
@@ -143,6 +163,21 @@ public class PacketWrapper {
return value;
}
/**
* Take all the inputs and write them to the output.
*
* @throws Exception If it failed to read or write
*/
public void passthroughAll() throws Exception {
// Copy previous objects
packetValues.addAll(readableObjects);
readableObjects.clear();
// If the buffer has readable bytes, copy them.
if(inputBuffer.readableBytes() > 0){
passthrough(Type.REMAINING_BYTES);
}
}
/**
* Write the current output to a buffer.
*
@@ -283,4 +318,13 @@ public class PacketWrapper {
PipelineUtil.getContextBefore("decompress", user().getChannel().pipeline()).fireChannelRead(output);
}
}
@Override
public String toString() {
return "PacketWrapper{" +
"packetValues=" + packetValues +
", readableObjects=" + readableObjects +
", id=" + id +
'}';
}
}
@@ -101,4 +101,12 @@ 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();
}
@@ -30,6 +30,13 @@ public interface ViaVersionConfig {
*/
boolean isNewEffectIndicator();
/**
* Get if 1.9 clients are shown the new death message on the death screen
*
* @return true if enabled
*/
boolean isShowNewDeathMessages();
/**
* Get if metadata errors will be suppressed
*
@@ -86,4 +93,53 @@ public interface ViaVersionConfig {
* @return true if automatic teaming is enabled
*/
boolean isAutoTeam();
/**
* Get if our block break patch is enabled to prevent weird ghost glitches.
*
* @return true if it is enabled.
*/
boolean isBlockBreakPatch();
/**
* Get the maximum number of packets a client can send per second.
*
* @return The number of packets a client can send per second.
*/
int getMaxPPS();
/**
* Get the kick message sent if the user hits the max packets per second.
*
* @return Kick message, with colour codes using '&'
*/
String getMaxPPSKickMessage();
/**
* The time in seconds that should be tracked for warnings
*
* @return Time in seconds that should be tracked for warnings
*/
int getTrackingPeriod();
/**
* The number of packets per second to count as a warning
*
* @return The number of packets per second to count as a warning.
*/
int getWarningPPS();
/**
* Get the maximum number of warnings the client can have in the interval
*
* @return The number of packets a client can send per second.
*/
int getMaxWarnings();
/**
* Get the kick message sent if the user goes over the warnings in the interval
*
* @return Kick message, with colour codes using '&'
*/
String getMaxWarningsKickMessage();
}
@@ -69,13 +69,21 @@ public interface BossBar {
*/
BossBar addPlayer(Player player);
/**
* Show the bossbar to a player (uuid)
*
* @param player uuid of the player
* @return the BossBar instance
*/
BossBar addPlayer(UUID player);
/**
* add multiple players
*
* @param players list of players
* @return the bossbar instance
*/
BossBar addPlayers(Player...players);
BossBar addPlayers(Player... players);
/**
* Remove the bossbar from a player
@@ -67,11 +67,11 @@ public abstract class ViaSubCommand {
/**
* Send message formatted / colored
*
* @param sender command sender
* @param sender command sender
* @param message string message
* @param args optional objects
* @param args optional objects
*/
public void sendMessage(CommandSender sender, String message, Object... args){
public void sendMessage(CommandSender sender, String message, Object... args) {
ViaCommandHandler.sendMessage(sender, message, args);
}
}
@@ -3,26 +3,32 @@ package us.myles.ViaVersion.api.data;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.socket.SocketChannel;
import lombok.Getter;
import lombok.Setter;
import lombok.Data;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@Data
public class UserConnection {
@Getter
private final SocketChannel channel;
Map<Class, StoredObject> storedObjects = new ConcurrentHashMap<>();
@Getter
@Setter
private boolean active = true;
@Getter
@Setter
private boolean pendingDisconnect = false;
private Object lastPacket;
@Getter
private long sentPackets = 0L;
@Getter
private long receivedPackets = 0L;
// Used for tracking pps
private long startTime = 0L;
private long intervalPackets = 0L;
private long packetsPerSecond = -1L;
// Used for handling warnings (over time)
private int secondsObserved = 0;
private int warnings = 0;
public UserConnection(SocketChannel socketChannel) {
@@ -97,7 +103,45 @@ public class UserConnection {
/**
* Used for incrementing the number of packets received from the client
*/
public void incrementReceived() {
public boolean incrementReceived() {
// handle stats
Long diff = System.currentTimeMillis() - startTime;
if (diff >= 1000) {
packetsPerSecond = intervalPackets;
startTime = System.currentTimeMillis();
intervalPackets = 1;
return true;
} else {
intervalPackets++;
}
// increase total
this.receivedPackets++;
return false;
}
/**
* Disconnect a connection
*
* @param reason The reason to use, not used if player is not active.
*/
public void disconnect(final String reason) {
if(!getChannel().isOpen()) return;
if(pendingDisconnect) return;
pendingDisconnect = true;
if (get(ProtocolInfo.class).getUuid() != null) {
final UUID uuid = get(ProtocolInfo.class).getUuid();
if (Bukkit.getPlayer(uuid) != null) {
Bukkit.getScheduler().runTask(Bukkit.getPluginManager().getPlugin("ViaVersion"), new Runnable() {
@Override
public void run() {
Player player = Bukkit.getPlayer(uuid);
if (player != null)
player.kickPlayer(ChatColor.translateAlternateColorCodes('&', reason));
}
});
return;
}
}
getChannel().close(); // =)
}
}
@@ -1,12 +1,14 @@
package us.myles.ViaVersion.api.minecraft;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
@AllArgsConstructor
@Getter
@ToString
@EqualsAndHashCode
public class Position {
private Long x;
private Long y;
@@ -2,11 +2,11 @@ package us.myles.ViaVersion.api.protocol;
import lombok.AllArgsConstructor;
import lombok.Getter;
import us.myles.ViaVersion.exception.CancelException;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.Pair;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.remapper.PacketRemapper;
import us.myles.ViaVersion.exception.CancelException;
import us.myles.ViaVersion.packets.Direction;
import us.myles.ViaVersion.packets.State;
@@ -20,7 +20,6 @@ public abstract class Protocol {
public Protocol() {
registerPackets();
registerListeners();
}
/**
@@ -7,17 +7,16 @@ import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.packets.Direction;
import us.myles.ViaVersion.packets.PacketType;
import us.myles.ViaVersion.packets.State;
import us.myles.ViaVersion.protocols.base.BaseProtocol;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
public class ProtocolPipeline extends Protocol {
LinkedList<Protocol> protocolList;
List<Protocol> protocolList;
private UserConnection userConnection;
public ProtocolPipeline(UserConnection userConnection) {
@@ -27,9 +26,9 @@ public class ProtocolPipeline extends Protocol {
@Override
protected void registerPackets() {
protocolList = new LinkedList<>();
protocolList = new CopyOnWriteArrayList<>();
// This is a pipeline so we register basic pipes
protocolList.addLast(new BaseProtocol());
protocolList.add(ProtocolRegistry.BASE_PROTOCOL);
}
@Override
@@ -55,7 +54,7 @@ public class ProtocolPipeline extends Protocol {
*/
public void add(Protocol protocol) {
if (protocolList != null) {
protocolList.addLast(protocol);
protocolList.add(protocol);
protocol.init(userConnection);
} else {
throw new NullPointerException("Tried to add protocol to early");
@@ -83,7 +82,7 @@ public class ProtocolPipeline extends Protocol {
// For 1.8/1.9 server version, eventually we'll probably get an API for this...
if (ProtocolRegistry.SERVER_PROTOCOL >= ProtocolVersion.v1_8.getId() &&
ProtocolRegistry.SERVER_PROTOCOL <= ProtocolVersion.v1_9_2.getId()) {
ProtocolRegistry.SERVER_PROTOCOL <= ProtocolVersion.v1_9_3.getId()) {
PacketType type;
if (ProtocolRegistry.SERVER_PROTOCOL == ProtocolVersion.v1_8.getId()) {
@@ -1,7 +1,10 @@
package us.myles.ViaVersion.api.protocol;
import org.bukkit.Bukkit;
import us.myles.ViaVersion.api.Pair;
import us.myles.ViaVersion.protocols.base.BaseProtocol;
import us.myles.ViaVersion.protocols.protocol1_9_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 java.util.*;
@@ -11,11 +14,16 @@ public class ProtocolRegistry {
// Input Version -> Output Version & Protocol (Allows fast lookup)
private static Map<Integer, Map<Integer, Protocol>> registryMap = new HashMap<>();
private static Map<Pair<Integer, Integer>, List<Pair<Integer, Protocol>>> pathCache = new HashMap<>();
private static List<Protocol> registerList = new ArrayList<>();
public static final Protocol BASE_PROTOCOL = new BaseProtocol();
static {
// Base Protocol
registerProtocol(BASE_PROTOCOL, Arrays.<Integer>asList(), -1);
// Register built in protocols
registerProtocol(new Protocol1_9TO1_8(), Collections.singletonList(ProtocolVersion.v1_9.getId()), ProtocolVersion.v1_8.getId());
registerProtocol(new Protocol1_9_1TO1_9(), Arrays.asList(ProtocolVersion.v1_9_1.getId(), ProtocolVersion.v1_9_2.getId()), ProtocolVersion.v1_9.getId());
registerProtocol(new Protocol1_9_3TO1_9_1_2(), Arrays.asList(ProtocolVersion.v1_9_3.getId()), ProtocolVersion.v1_9_2.getId());
}
/**
@@ -37,6 +45,12 @@ public class ProtocolRegistry {
registryMap.get(version).put(output, protocol);
}
if (Bukkit.getPluginManager().getPlugin("ViaVersion").isEnabled()) {
protocol.registerListeners();
} else {
registerList.add(protocol);
}
}
/**
@@ -51,6 +65,16 @@ public class ProtocolRegistry {
return false; // No destination for protocol
}
/**
* Called when the server is enabled, to register any non registered listeners.
*/
public static void registerListeners() {
for (Protocol protocol : registerList) {
protocol.registerListeners();
}
registerList.clear();
}
/**
* Calculate a path to get from an input protocol to the servers protocol.
*
@@ -15,6 +15,7 @@ public class ProtocolVersion {
public static final ProtocolVersion v1_9;
public static final ProtocolVersion v1_9_1;
public static final ProtocolVersion v1_9_2;
public static final ProtocolVersion v1_9_3;
private final int id;
private final String name;
@@ -26,6 +27,7 @@ public class ProtocolVersion {
register(v1_9 = new ProtocolVersion(107, "1.9"));
register(v1_9_1 = new ProtocolVersion(108, "1.9.1"));
register(v1_9_2 = new ProtocolVersion(109, "1.9.2"));
register(v1_9_3 = new ProtocolVersion(110, "1.9.3"));
}
public static void register(@NonNull ProtocolVersion protocol) {
@@ -37,7 +39,11 @@ public class ProtocolVersion {
}
public static ProtocolVersion getProtocol(int id) {
return versions.get(id);
if (versions.containsKey(id)) {
return versions.get(id);
} else {
return new ProtocolVersion(id, "Unknown (" + id + ")");
}
}
public static List<ProtocolVersion> getProtocols() {
@@ -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;
}
@@ -153,14 +158,16 @@ public class ViaBossBar implements BossBar {
}
private void sendPacket(UpdateAction action) {
ByteBuf buf = getPacket(action);
for (UUID uuid : new ArrayList<>(players))
for (UUID uuid : new ArrayList<>(players)) {
ByteBuf buf = getPacket(action);
sendPacket(uuid, buf);
}
}
private void sendPacket(UUID uuid, ByteBuf buf) {
if (!ViaVersion.getInstance().isPorted(uuid) || !(ViaVersion.getInstance().getPlayerVersion(uuid) >= ProtocolVersion.v1_9.getId())) {
players.remove(uuid);
buf.release();
return;
}
ViaVersion.getInstance().sendRawPacket(uuid, buf);
@@ -0,0 +1,20 @@
package us.myles.ViaVersion.classgenerator;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.classgenerator.HandlerConstructor;
import us.myles.ViaVersion.handlers.ViaDecodeHandler;
import us.myles.ViaVersion.handlers.ViaEncodeHandler;
public class BasicHandlerConstructor implements HandlerConstructor {
@Override
public ViaEncodeHandler newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {
return new ViaEncodeHandler(info, minecraftEncoder);
}
@Override
public ViaDecodeHandler newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {
return new ViaDecodeHandler(info, minecraftDecoder);
}
}
@@ -0,0 +1,88 @@
package us.myles.ViaVersion.classgenerator;
import javassist.*;
import javassist.expr.ConstructorCall;
import javassist.expr.ExprEditor;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.handlers.ViaDecodeHandler;
import us.myles.ViaVersion.handlers.ViaEncodeHandler;
import us.myles.ViaVersion.util.ReflectionUtil;
public class ClassGenerator {
private static HandlerConstructor constructor = new BasicHandlerConstructor();
public static HandlerConstructor getConstructor() {
return constructor;
}
public static void generate() {
if(!ViaVersion.getInstance().isCompatSpigotBuild()) return; // Use Basic Handler as not needed.
try {
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new LoaderClassPath(ClassGenerator.class.getClassLoader()));
// Generate the classes
transformSuperclass(pool, ViaDecodeHandler.class, ReflectionUtil.nms("PacketDecoder"));
transformSuperclass(pool, ViaEncodeHandler.class, ReflectionUtil.nms("PacketEncoder"));
// Implement Constructor
CtClass generated = pool.makeClass("us.myles.ViaVersion.classgenerator.generated.GeneratedConstructor");
CtClass handlerInterface = pool.get(HandlerConstructor.class.getName());
generated.setInterfaces(new CtClass[]{handlerInterface});
// Import required classes
pool.importPackage("us.myles.ViaVersion.classgenerator.generated");
pool.importPackage("us.myles.ViaVersion.classgenerator");
pool.importPackage("us.myles.ViaVersion.api.data");
pool.importPackage("io.netty.handler.codec");
// Implement Methods
generated.addMethod(CtMethod.make("public MessageToByteEncoder newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {\n" +
" return new ViaEncodeHandler(info, minecraftEncoder);\n" +
" }", generated));
generated.addMethod(CtMethod.make("public ByteToMessageDecoder newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {\n" +
" return new ViaDecodeHandler(info, minecraftDecoder);\n" +
" }", generated));
constructor = (HandlerConstructor) generated.toClass(HandlerConstructor.class.getClassLoader()).newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (CannotCompileException e) {
e.printStackTrace();
} catch (NotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
private static Class transformSuperclass(ClassPool pool, Class input, Class superclass) {
String newName = "us.myles.ViaVersion.classgenerator.generated." + input.getSimpleName();
try {
CtClass toExtend = pool.get(superclass.getName());
CtClass generated = pool.getAndRename(input.getName(), newName);
generated.setSuperclass(toExtend);
// Modify constructor to call super
if(generated.getConstructors().length != 0) {
generated.getConstructors()[0].instrument(new ExprEditor() {
@Override
public void edit(ConstructorCall c) throws CannotCompileException {
if (c.isSuper()) {
// Constructor for both has a stats thing.
c.replace("super(null);");
}
super.edit(c);
}
});
}
return generated.toClass(HandlerConstructor.class.getClassLoader());
} catch (NotFoundException e) {
e.printStackTrace();
} catch (CannotCompileException e) {
e.printStackTrace();
}
return null;
}
}
@@ -0,0 +1,10 @@
package us.myles.ViaVersion.classgenerator;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import us.myles.ViaVersion.api.data.UserConnection;
public interface HandlerConstructor {
public MessageToByteEncoder newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder);
public ByteToMessageDecoder newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder);
}
@@ -130,6 +130,7 @@ public class ViaCommandHandler implements ViaVersionCommand, CommandExecutor, Ta
private void registerDefaults() throws Exception {
registerSubCommand(new ListSubCmd());
registerSubCommand(new PPSSubCmd());
registerSubCommand(new DebugSubCmd());
registerSubCommand(new DisplayLeaksSubCmd());
registerSubCommand(new DontBugMeSubCmd());
@@ -21,7 +21,7 @@ public class DebugSubCmd extends ViaSubCommand {
ViaVersionPlugin plugin = (ViaVersionPlugin) ViaVersion.getInstance();
plugin.setDebug(!plugin.isDebug());
sendMessage(sender, "&6Debug mode is now %s" , (plugin.isDebug() ? "&aenabled" : "&cdisabled"));
sendMessage(sender, "&6Debug mode is now %s", (plugin.isDebug() ? "&aenabled" : "&cdisabled"));
return true;
}
}
@@ -30,11 +30,9 @@ public class ListSubCmd extends ViaSubCommand {
Map<Integer, Set<String>> playerVersions = new HashMap<>();
for (Player p : Bukkit.getOnlinePlayers()) {
int playerVersion = ViaVersion.getInstance().getPlayerVersion(p);
if (playerVersions.containsKey(playerVersion)) {
playerVersions.get(playerVersion).add(p.getName());
continue;
}
playerVersions.put(playerVersion, Collections.singleton(p.getName()));
if (!playerVersions.containsKey(playerVersion))
playerVersions.put(playerVersion, new HashSet<String>());
playerVersions.get(playerVersion).add(p.getName());
}
Map<Integer, Set<String>> sorted = new TreeMap<>(playerVersions);
@@ -0,0 +1,64 @@
package us.myles.ViaVersion.commands.defaultsubs;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.command.ViaSubCommand;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
import java.util.*;
public class PPSSubCmd extends ViaSubCommand {
@Override
public String name() {
return "pps";
}
@Override
public String description() {
return "Shows the packets per second of online players";
}
@Override
public String usage() {
return "pps";
}
@Override
public boolean execute(CommandSender sender, String[] args) {
Map<Integer, Set<String>> playerVersions = new HashMap<>();
int totalPackets = 0;
int clients = 0;
long max = 0;
for (Player p : Bukkit.getOnlinePlayers()) {
if (!ViaVersion.getInstance().isPorted(p))
continue;
int playerVersion = ViaVersion.getInstance().getPlayerVersion(p);
if (!playerVersions.containsKey(playerVersion))
playerVersions.put(playerVersion, new HashSet<String>());
UserConnection uc = ((ViaVersionPlugin) ViaVersion.getInstance()).getConnection(p);
if (uc.getPacketsPerSecond() > -1) {
playerVersions.get(playerVersion).add(p.getName() + " (" + uc.getPacketsPerSecond() + " PPS)");
totalPackets += uc.getPacketsPerSecond();
if (uc.getPacketsPerSecond() > max) {
max = uc.getPacketsPerSecond();
}
clients++;
}
}
Map<Integer, Set<String>> sorted = new TreeMap<>(playerVersions);
sendMessage(sender, "&4Live Packets Per Second");
if (clients > 1) {
sendMessage(sender, "&cAverage: &f" + (totalPackets / clients));
sendMessage(sender, "&cHighest: &f" + max);
}
for (Map.Entry<Integer, Set<String>> entry : sorted.entrySet())
sendMessage(sender, "&8[&6%s&8]: &b%s", ProtocolVersion.getProtocol(entry.getKey()).getName(), entry.getValue());
sorted.clear();
return true;
}
}
@@ -21,9 +21,9 @@ public class InformativeException extends Exception {
}
private String getSource(Class<?> sourceClazz) {
if(sourceClazz.isAnonymousClass()){
if (sourceClazz.isAnonymousClass()) {
return sourceClazz.getName() + " (Anonymous)";
}else{
} else {
return sourceClazz.getName();
}
}
@@ -3,7 +3,9 @@ package us.myles.ViaVersion.handlers;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.exception.CancelException;
@@ -29,9 +31,19 @@ public class ViaDecodeHandler extends ByteToMessageDecoder {
protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> list) throws Exception {
// use transformers
if (bytebuf.readableBytes() > 0) {
// Ignore if pending disconnect
if (info.isPendingDisconnect()) {
return;
}
// Increment received
boolean second = info.incrementReceived();
// Check PPS
if(second) {
if (((ViaVersionPlugin) ViaVersion.getConfig()).handlePPS(info))
return;
}
if (info.isActive()) {
// Increment received
info.incrementReceived();
// Handle ID
int id = Type.VAR_INT.read(bytebuf);
// Transform
@@ -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
@@ -39,9 +46,9 @@ public class ViaEncodeHandler extends MessageToByteEncoder {
if (bytebuf.readableBytes() == 0) {
throw new CancelException();
}
// Increment sent
info.incrementSent();
if (info.isActive()) {
// Increment sent
info.incrementSent();
// Handle ID
int id = Type.VAR_INT.read(bytebuf);
// Transform
@@ -49,10 +56,10 @@ public class ViaEncodeHandler extends MessageToByteEncoder {
bytebuf.clear();
try {
PacketWrapper wrapper = new PacketWrapper(id, oldPacket, info);
ProtocolInfo protInfo = info.get(ProtocolInfo.class);
protInfo.getPipeline().transform(Direction.OUTGOING, protInfo.getState(), wrapper);
wrapper.writeToBuffer(bytebuf);
PacketWrapper wrapper = new PacketWrapper(id, oldPacket, info);
ProtocolInfo protInfo = info.get(ProtocolInfo.class);
protInfo.getPipeline().transform(Direction.OUTGOING, protInfo.getState(), wrapper);
wrapper.writeToBuffer(bytebuf);
} catch (Exception e) {
bytebuf.clear();
throw e;
@@ -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);
@@ -9,7 +9,7 @@ import us.myles.ViaVersion.packets.State;
public class Protocol1_9_1TO1_9 extends Protocol {
@Override
protected void registerPackets() {
// Currently supports 1.9.1 PRE 2
// Currently supports 1.9.1 and 1.9.2
// Join Game Packet
registerOutgoing(State.PLAY, 0x23, 0x23, new PacketRemapper() {
@Override
@@ -0,0 +1,81 @@
package us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
import org.spacehq.opennbt.tag.builtin.IntTag;
import org.spacehq.opennbt.tag.builtin.StringTag;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.minecraft.Position;
import us.myles.ViaVersion.api.protocol.Protocol;
import us.myles.ViaVersion.api.remapper.PacketHandler;
import us.myles.ViaVersion.api.remapper.PacketRemapper;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.packets.State;
public class Protocol1_9_3TO1_9_1_2 extends Protocol {
@Override
protected void registerPackets() {
//Unchanged packet structure
registerOutgoing(State.PLAY, 0x47, 0x46); //Sound effect
registerOutgoing(State.PLAY, 0x48, 0x47); //Player list header and footer
registerOutgoing(State.PLAY, 0x49, 0x48); //Collect item
registerOutgoing(State.PLAY, 0x4A, 0x49); //Entity teleport
registerOutgoing(State.PLAY, 0x4B, 0x4A); //Entity properties
registerOutgoing(State.PLAY, 0x4C, 0x4B); //Entity effect
//Sign update
registerOutgoing(State.PLAY, 0x46, -1, new PacketRemapper() {
@Override
public void registerMap() {
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
//read data
Position position = wrapper.read(Type.POSITION);
String[] lines = new String[4];
for (int i = 0; i < 4; i++)
lines[i] = wrapper.read(Type.STRING);
wrapper.clearInputBuffer();
//write data
wrapper.setId(0x09); //Update block entity
wrapper.write(Type.POSITION, position); //Block location
wrapper.write(Type.UNSIGNED_BYTE, (short) 9); //Action type (9 update sign)
//Create nbt
CompoundTag tag = new CompoundTag("");
tag.put(new StringTag("id", "Sign"));
tag.put(new IntTag("x", position.getX().intValue()));
tag.put(new IntTag("y", position.getY().intValue()));
tag.put(new IntTag("z", position.getZ().intValue()));
for (int i = 0; i < lines.length; i++)
tag.put(new StringTag("Text" + (i + 1), lines[i]));
wrapper.write(Type.NBT, tag);
}
});
}
});
registerOutgoing(State.PLAY, 0x20, 0x20, new PacketRemapper() {
@Override
public void registerMap() {
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
wrapper.passthroughAll();
wrapper.write(Type.VAR_INT, 0);
}
});
}
});
}
@Override
public void init(UserConnection userConnection) {
}
}
@@ -2,17 +2,17 @@ package us.myles.ViaVersion.protocols.protocol1_9to1_8;
import us.myles.ViaVersion.api.PacketWrapper;
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.protocols.protocol1_9to1_8.storage.MovementTracker;
public class PlayerMovementMapper extends PacketRemapper {
public class PlayerMovementMapper extends PacketHandler {
@Override
public void registerMap() {
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
wrapper.user().get(MovementTracker.class).incrementIdlePacket();
}
});
public void handle(PacketWrapper wrapper) throws Exception {
MovementTracker tracker = wrapper.user().get(MovementTracker.class);
tracker.incrementIdlePacket();
// If packet has the ground data
if (wrapper.is(Type.BOOLEAN, 0)) {
tracker.setGround(wrapper.get(Type.BOOLEAN, 0));
}
}
}
@@ -4,26 +4,19 @@ import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import org.bukkit.Bukkit;
import org.bukkit.inventory.ItemStack;
import us.myles.ViaVersion.ViaIdleThread;
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.item.Item;
import us.myles.ViaVersion.api.minecraft.metadata.Metadata;
import us.myles.ViaVersion.api.protocol.Protocol;
import us.myles.ViaVersion.api.remapper.ValueTransformer;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.listeners.ArmorListener;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.listeners.BlockListener;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.listeners.CommandBlockListener;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.listeners.PaperPatch;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.listeners.*;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.packets.*;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.ClientChunks;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.EntityTracker;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.InventoryTracker;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.MovementTracker;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.*;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.types.MetadataListType;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.types.MetadataType;
@@ -65,23 +58,27 @@ public class Protocol1_9TO1_8 extends Protocol {
return line;
}
public static ItemStack getHandItem(final UserConnection info) {
try {
return Bukkit.getScheduler().callSyncMethod(Bukkit.getPluginManager().getPlugin("ViaVersion"), new Callable<ItemStack>() {
@Override
public ItemStack call() throws Exception {
UUID playerUUID = info.get(ProtocolInfo.class).getUuid();
if (Bukkit.getPlayer(playerUUID) != null) {
return Bukkit.getPlayer(playerUUID).getItemInHand();
public static Item getHandItem(final UserConnection info) {
if (HandItemCache.CACHE) {
return HandItemCache.getHandItem(info.get(ProtocolInfo.class).getUuid());
} else {
try {
return Bukkit.getScheduler().callSyncMethod(Bukkit.getPluginManager().getPlugin("ViaVersion"), new Callable<Item>() {
@Override
public Item call() throws Exception {
UUID playerUUID = info.get(ProtocolInfo.class).getUuid();
if (Bukkit.getPlayer(playerUUID) != null) {
return Item.getItem(Bukkit.getPlayer(playerUUID).getItemInHand());
}
return null;
}
return null;
}
}).get(10, TimeUnit.SECONDS);
} catch (Exception e) {
System.out.println("Error fetching hand item: " + e.getClass().getName());
if (ViaVersion.getInstance().isDebug())
e.printStackTrace();
return null;
}).get(10, TimeUnit.SECONDS);
} catch (Exception e) {
System.out.println("Error fetching hand item: " + e.getClass().getName());
if (ViaVersion.getInstance().isDebug())
e.printStackTrace();
return null;
}
}
}
@@ -99,13 +96,18 @@ public class Protocol1_9TO1_8 extends Protocol {
ViaVersionPlugin plugin = (ViaVersionPlugin) Bukkit.getPluginManager().getPlugin("ViaVersion");
Bukkit.getPluginManager().registerEvents(new ArmorListener(plugin), plugin);
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")){
if (Bukkit.getVersion().toLowerCase().contains("paper")) {
plugin.getLogger().info("Enabling PaperSpigot patch: Fixes block placement.");
Bukkit.getPluginManager().registerEvents(new PaperPatch(), plugin);
}
if (plugin.getConfig().getBoolean("simulate-pt", true))
new ViaIdleThread(plugin.getPortedPlayers()).runTaskTimerAsynchronously(plugin, 1L, 1L); // Updates player's idle status
new ViaIdleThread(plugin.getPortedPlayers()).runTaskTimer(plugin, 1L, 1L); // Updates player's idle status
if (plugin.getConfig().getBoolean("item-cache", true)) {
new HandItemCache().runTaskTimerAsynchronously(plugin, 2L, 2L); // Updates player's items :)
HandItemCache.CACHE = true;
}
}
@Override
@@ -128,5 +130,7 @@ public class Protocol1_9TO1_8 extends Protocol {
userConnection.put(new MovementTracker(userConnection));
// Inventory tracker
userConnection.put(new InventoryTracker(userConnection));
// Place block tracker
userConnection.put(new PlaceBlockTracker(userConnection));
}
}
@@ -0,0 +1,114 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8;
import io.netty.channel.ChannelHandlerContext;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.MovementTracker;
import us.myles.ViaVersion.util.PipelineUtil;
import us.myles.ViaVersion.util.ReflectionUtil;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.UUID;
public class ViaIdleThread extends BukkitRunnable {
private static boolean USE_NMS = true;
private final Map<UUID, UserConnection> portedPlayers;
// Used for packet mode
private Object idlePacket;
private Object idlePacket2;
// Use for nms
private Method getHandle;
private Field connection;
private Method handleFlying;
public ViaIdleThread(Map<UUID, UserConnection> portedPlayers) {
USE_NMS = ((ViaVersionPlugin) ViaVersion.getInstance()).getConfig().getBoolean("nms-player-ticking", true);
this.portedPlayers = portedPlayers;
Class<?> idlePacketClass;
try {
idlePacketClass = ReflectionUtil.nms("PacketPlayInFlying");
} catch (ClassNotFoundException e) {
throw new RuntimeException("Couldn't find idle packet, help!", e);
}
try {
idlePacket = idlePacketClass.newInstance();
idlePacket2 = idlePacketClass.newInstance();
Field flying = idlePacketClass.getDeclaredField("f");
flying.setAccessible(true);
flying.set(idlePacket2, true);
} catch (NoSuchFieldException | InstantiationException | IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException("Couldn't make player idle packet, help!", e);
}
if (USE_NMS) {
try {
getHandle = ReflectionUtil.obc("entity.CraftPlayer").getDeclaredMethod("getHandle");
} catch (NoSuchMethodException | ClassNotFoundException e) {
throw new RuntimeException("Couldn't find CraftPlayer", e);
}
try {
connection = ReflectionUtil.nms("EntityPlayer").getDeclaredField("playerConnection");
} catch (NoSuchFieldException | ClassNotFoundException e) {
throw new RuntimeException("Couldn't find Player Connection", e);
}
try {
handleFlying = ReflectionUtil.nms("PlayerConnection").getDeclaredMethod("a", idlePacketClass);
} catch (NoSuchMethodException | ClassNotFoundException e) {
throw new RuntimeException("Couldn't find CraftPlayer", e);
}
}
}
@Override
public void run() {
for (UserConnection info : portedPlayers.values()) {
if (info.get(ProtocolInfo.class).getPipeline().contains(Protocol1_9TO1_8.class)) {
long nextIdleUpdate = info.get(MovementTracker.class).getNextIdlePacket();
if (nextIdleUpdate <= System.currentTimeMillis()) {
if (info.getChannel().isOpen()) {
if (USE_NMS) {
Player player = Bukkit.getPlayer(info.get(ProtocolInfo.class).getUuid());
if (player != null) {
try {
// Tick player
Object entityPlayer = getHandle.invoke(player);
Object pc = connection.get(entityPlayer);
if (pc != null) {
handleFlying.invoke(pc, (info.get(MovementTracker.class).isGround() ? idlePacket2 : idlePacket));
// Tick world
info.get(MovementTracker.class).incrementIdlePacket();
}
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
} else {
// Old method using packets.
ChannelHandlerContext context = PipelineUtil.getContextBefore("decoder", info.getChannel().pipeline());
if (context != null) {
if (info.get(MovementTracker.class).isGround()) {
context.fireChannelRead(idlePacket2);
} else {
context.fireChannelRead(idlePacket);
}
info.get(MovementTracker.class).incrementIdlePacket();
}
}
}
}
}
}
}
}
@@ -0,0 +1,25 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8.chat;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.EntityTracker;
public class ChatRewriter {
public static void toClient(JsonObject obj, UserConnection user) {
//Check gamemode change
if (obj.get("translate") != null && obj.get("translate").getAsString().equals("gameMode.changed")) {
String gameMode = user.get(EntityTracker.class).getGameMode().getText();
JsonObject gameModeObject = new JsonObject();
gameModeObject.addProperty("text", gameMode);
gameModeObject.addProperty("color", "gray");
gameModeObject.addProperty("italic", true);
JsonArray array = new JsonArray();
array.add(gameModeObject);
obj.add("with", array);
}
}
}
@@ -0,0 +1,23 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8.chat;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Getter
public enum GameMode {
SURVIVAL(0, "Survival Mode"),
CREATIVE(1, "Creative Mode"),
ADVENTURE(2, "Adventure Mode"),
SPECTATOR(3, "Spectator Mode");
private final int id;
private final String text;
public static GameMode getById(int id) {
for (GameMode gm : GameMode.values())
if (gm.getId() == id)
return gm;
return null;
}
}
@@ -19,6 +19,7 @@ import org.bukkit.inventory.CraftingInventory;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.ArmorType;
@@ -39,9 +40,12 @@ public class ArmorListener implements Listener {
if (!userConnection.get(ProtocolInfo.class).getPipeline().contains(Protocol1_9TO1_8.class)) return;
int armor = ArmorType.calculateArmorPoints(player.getInventory().getArmorContents());
int protocol = userConnection.get(ProtocolInfo.class).getProtocolVersion();
ByteBuf buf = Unpooled.buffer();
try {
ByteBuf buf = Unpooled.buffer();
Type.VAR_INT.write(buf, 0x4B); // Entity Properties
//TODO possibility to send packets by Protocol version, to let the transformer do the work
Type.VAR_INT.write(buf, (protocol >= ProtocolVersion.v1_9_3.getId()) ? 0x4A : 0x4B); // Entity Properties
Type.VAR_INT.write(buf, player.getEntityId());
buf.writeInt(1); // only 1 property
Type.STRING.write(buf, "generic.armor");
@@ -53,6 +57,7 @@ public class ArmorListener implements Listener {
ViaVersion.getInstance().sendRawPacket(player, buf);
} catch (Exception ignored) {
buf.release();
}
}
@@ -20,7 +20,7 @@ public class BlockListener implements Listener {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void placeBlock(BlockPlaceEvent e) {
if(plugin.isPorted(e.getPlayer())) {
if (plugin.isPorted(e.getPlayer())) {
UserConnection c = plugin.getConnection(e.getPlayer());
if (!c.get(ProtocolInfo.class).getPipeline().contains(Protocol1_9TO1_8.class)) return;
Block b = e.getBlockPlaced();
@@ -122,11 +122,15 @@ public class CommandBlockListener implements Listener {
private long[] getPosition(Object obj) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
return new long[]{
(long) ReflectionUtil.getSuper(obj, "a", int.class), //X
(long) ReflectionUtil.getSuper(obj, "c", int.class), //Y
(long) ReflectionUtil.getSuper(obj, "d", int.class) //Z
(long) ReflectionUtil.getSuper(obj, isR1() ? "b" : "c", int.class), //Y
(long) ReflectionUtil.getSuper(obj, isR1() ? "c" : "d", int.class) //Z
};
}
private boolean isR1() {
return ReflectionUtil.getVersion().equals("v1_8_R1");
}
private CompoundTag getNBT(Object obj) throws Exception {
ByteBuf buf = Unpooled.buffer();
Method m = ReflectionUtil.nms("NBTCompressedStreamTools").getMethod("a", ReflectionUtil.nms("NBTTagCompound"), DataOutput.class);
@@ -0,0 +1,65 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8.listeners;
import lombok.RequiredArgsConstructor;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.data.UserConnection;
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;
@RequiredArgsConstructor
public class DeathListener implements Listener {
private final ViaVersionPlugin plugin;
@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)) {
sendPacket(p, e.getDeathMessage());
}
}
public boolean checkPipeline(Player p) {
UserConnection userConnection = plugin.getConnection(p);
return userConnection != null && userConnection.get(ProtocolInfo.class).getPipeline().contains(Protocol1_9TO1_8.class);
}
private UserConnection getUserConnection(Player p) {
return plugin.getConnection(p);
}
public boolean checkGamerule(World w) {
try {
return Boolean.parseBoolean(w.getGameRuleValue("showDeathMessages"));
} catch (Exception e) {
return false;
}
}
private void sendPacket(final Player p, final String msg) {
Bukkit.getScheduler().runTask(plugin, new Runnable() {
@Override
public void run() {
PacketWrapper wrapper = new PacketWrapper(0x2C, null, getUserConnection(p));
try {
wrapper.write(Type.VAR_INT, 2);
wrapper.write(Type.VAR_INT, p.getEntityId());
wrapper.write(Type.INT, p.getEntityId());
Protocol1_9TO1_8.FIX_JSON.write(wrapper, msg);
wrapper.send();
} catch (Exception e) {
e.printStackTrace();
wrapper.clearInputBuffer();
}
}
});
}
}
@@ -0,0 +1,36 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8.listeners;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import us.myles.ViaVersion.api.minecraft.item.Item;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class HandItemCache extends BukkitRunnable {
public static boolean CACHE = false;
private static ConcurrentHashMap<UUID, Item> handCache = new ConcurrentHashMap<>();
public static Item getHandItem(UUID player) {
if (!handCache.containsKey(player))
return null;
return handCache.get(player);
}
@Override
public void run() {
List<UUID> players = new ArrayList<>(handCache.keySet());
for (Player p : Bukkit.getOnlinePlayers()) {
handCache.put(p.getUniqueId(), Item.getItem(p.getItemInHand()));
players.remove(p.getUniqueId());
}
// Remove offline players
for (UUID uuid : players) {
handCache.remove(uuid);
}
}
}
@@ -32,18 +32,18 @@ public class PaperPatch implements Listener {
} else {
if (e.getPlayer().getLocation().getBlock().getRelative(BlockFace.UP).equals(e.getBlock())) {
e.setCancelled(true);
}else{
} else {
// Within radius of block
if(Math.abs(diff.getX()) <= 0.8 && Math.abs(diff.getZ()) <= 0.8D){
if (Math.abs(diff.getX()) <= 0.8 && Math.abs(diff.getZ()) <= 0.8D) {
// Are they on the edge / shifting ish
if(diff.getY() <= 0.1D && diff.getY() >= -0.1D){
if (diff.getY() <= 0.1D && diff.getY() >= -0.1D) {
e.setCancelled(true);
return;
}
BlockFace relative = e.getBlockAgainst().getFace(e.getBlock());
// Are they towering up, (handles some latency)
if(relative == BlockFace.UP){
if(diff.getY() < 1D && diff.getY() >= 0D){
if (relative == BlockFace.UP) {
if (diff.getY() < 1D && diff.getY() >= 0D) {
e.setCancelled(true);
}
}
@@ -157,7 +157,7 @@ public enum MetaIndex {
}
public static MetaIndex getIndex(EntityType type, int index) {
Class<? extends org.bukkit.entity.Entity> entityClass = type.getEntityClass();
Class<? extends org.bukkit.entity.Entity> entityClass = type == null ? LivingEntity.class : type.getEntityClass();
if (entityClass == null) {
System.out.println("Could not get entity class for " + type);
return null;
@@ -3,7 +3,6 @@ package us.myles.ViaVersion.protocols.protocol1_9to1_8.metadata;
import org.bukkit.entity.EntityType;
import org.bukkit.util.EulerAngle;
import org.bukkit.util.Vector;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.minecraft.item.Item;
import us.myles.ViaVersion.api.minecraft.metadata.Metadata;
@@ -207,7 +207,7 @@ 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();
}
});
@@ -252,6 +252,24 @@ public class EntityPackets {
}
});
// Combat Event Packet
protocol.registerOutgoing(State.PLAY, 0x42, 0x2C, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.VAR_INT); //Event id
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
if (wrapper.get(Type.VAR_INT, 0) == 2) { // entity dead
wrapper.passthrough(Type.VAR_INT); //Player id
wrapper.passthrough(Type.INT); //Entity id
Protocol1_9TO1_8.FIX_JSON.write(wrapper, wrapper.read(Type.STRING));
}
}
});
}
});
/* Packets which do not have any field remapping or handlers */
@@ -261,7 +279,6 @@ public class EntityPackets {
protocol.registerOutgoing(State.PLAY, 0x16, 0x27); // Entity Look Packet
protocol.registerOutgoing(State.PLAY, 0x14, 0x28); // Entity Packet
protocol.registerOutgoing(State.PLAY, 0x42, 0x2C); // Combat Event Packet
protocol.registerOutgoing(State.PLAY, 0x0A, 0x2F); // Use Bed Packet
protocol.registerOutgoing(State.PLAY, 0x1E, 0x31); // Remove Entity Effect Packet
@@ -146,10 +146,10 @@ public class InventoryPackets {
Item[] oldStack = wrapper.get(Type.ITEM_ARRAY, 0);
Item[] newStack = new Item[oldStack.length + 1];
for (int i = 0; i < newStack.length; i++) {
if (i > 3) {
if (i > 4) {
newStack[i] = oldStack[i - 1];
} else {
if (i != 3) { // Leave index 3 blank
if (i != 4) { // Leave index 3 blank
newStack[i] = oldStack[i];
}
}
@@ -1,5 +1,7 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8.packets;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
import us.myles.ViaVersion.ViaVersionPlugin;
@@ -13,8 +15,11 @@ import us.myles.ViaVersion.api.remapper.ValueCreator;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.packets.State;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.ItemRewriter;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.PlayerMovementMapper;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.chat.ChatRewriter;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.chat.GameMode;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.ClientChunks;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.EntityTracker;
@@ -26,6 +31,19 @@ public class PlayerPackets {
public void registerMap() {
map(Type.STRING, Protocol1_9TO1_8.FIX_JSON); // 0 - Chat Message (json)
map(Type.BYTE); // 1 - Chat Positon
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
try {
JsonObject obj = (JsonObject) new JsonParser().parse(wrapper.get(Type.STRING, 0));
ChatRewriter.toClient(obj, wrapper.user());
wrapper.set(Type.STRING, 0, obj.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
});
@@ -159,6 +177,14 @@ public class PlayerPackets {
map(Type.UNSIGNED_BYTE); // 4 - Max Players (Tab)
map(Type.STRING); // 5 - Level Type
map(Type.BOOLEAN); // 6 - Reduced Debug info
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
EntityTracker tracker = wrapper.user().get(EntityTracker.class);
tracker.setGameMode(GameMode.getById(wrapper.get(Type.UNSIGNED_BYTE, 0))); //Set player gamemode
}
});
}
});
@@ -228,6 +254,31 @@ public class PlayerPackets {
wrapper.passthrough(Type.REMAINING_BYTES); // This is so ugly, :(
wrapper.write(Type.VAR_INT, 0);
}
if (name.equalsIgnoreCase("MC|TrList")) {
wrapper.passthrough(Type.INT); // ID
Short size = wrapper.passthrough(Type.UNSIGNED_BYTE);
for (int i = 0; i < size; ++i) {
Item item1 = wrapper.passthrough(Type.ITEM);
ItemRewriter.toClient(item1);
Item item2 = wrapper.passthrough(Type.ITEM);
ItemRewriter.toClient(item2);
boolean present = wrapper.passthrough(Type.BOOLEAN);
if (present) {
Item item3 = wrapper.passthrough(Type.ITEM);
ItemRewriter.toClient(item3);
}
wrapper.passthrough(Type.BOOLEAN);
wrapper.passthrough(Type.INT);
wrapper.passthrough(Type.INT);
}
}
}
});
}
@@ -253,6 +304,49 @@ public class PlayerPackets {
}
});
// Respawn Packet
protocol.registerOutgoing(State.PLAY, 0x07, 0x33, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.INT); // 0 - Dimension
map(Type.UNSIGNED_BYTE); // 1 - Difficulty
map(Type.UNSIGNED_BYTE); // 2 - GameMode
map(Type.STRING); // 3 - Level Type
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
// Client unloads chunks on respawn, take note
ClientChunks cc = wrapper.user().get(ClientChunks.class);
cc.getBulkChunks().clear();
cc.getLoadedChunks().clear();
int gamemode = wrapper.get(Type.UNSIGNED_BYTE, 0);
wrapper.user().get(EntityTracker.class).setGameMode(GameMode.getById(gamemode));
}
});
}
});
// Change Game State Packet
protocol.registerOutgoing(State.PLAY, 0x2B, 0x1E, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.UNSIGNED_BYTE); //0 - Reason
map(Type.FLOAT); //1 - Value
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
if (wrapper.get(Type.UNSIGNED_BYTE, 0) == 3) { //Change gamemode
int gamemode = wrapper.get(Type.FLOAT, 0).intValue();
wrapper.user().get(EntityTracker.class).setGameMode(GameMode.getById(gamemode));
}
}
});
}
});
/* Removed packets */
// Map Bulk
@@ -290,9 +384,7 @@ public class PlayerPackets {
protocol.registerOutgoing(State.PLAY, 0x39, 0x2B); // Player Abilities Packet
protocol.registerOutgoing(State.PLAY, 0x00, 0x1F); // Keep Alive Packet
protocol.registerOutgoing(State.PLAY, 0x48, 0x32); // Resource Pack Send Packet
protocol.registerOutgoing(State.PLAY, 0x07, 0x33); // Respawn Packet
protocol.registerOutgoing(State.PLAY, 0x43, 0x36); // Camera Packet
protocol.registerOutgoing(State.PLAY, 0x2B, 0x1E); // Change Game State Packet
protocol.registerOutgoing(State.PLAY, 0x3D, 0x38); // Display Scoreboard Packet
protocol.registerOutgoing(State.PLAY, 0x3B, 0x3F); // Scoreboard Objective Packet
@@ -428,6 +520,52 @@ public class PlayerPackets {
}
});
// Player Position Packet
protocol.registerIncoming(State.PLAY, 0x04, 0x0C, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.DOUBLE); // 0 - X
map(Type.DOUBLE); // 1 - Y
map(Type.DOUBLE); // 2 - Z
map(Type.BOOLEAN); // 3 - Ground
handler(new PlayerMovementMapper());
}
});
// Player Move & Look Packet
protocol.registerIncoming(State.PLAY, 0x06, 0x0D, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.DOUBLE); // 0 - X
map(Type.DOUBLE); // 1 - Y
map(Type.DOUBLE); // 2 - Z
map(Type.FLOAT); // 3 - Yaw
map(Type.FLOAT); // 4 - Pitch
map(Type.BOOLEAN); // 5 - Ground
handler(new PlayerMovementMapper());
}
});
// Player Look Packet
protocol.registerIncoming(State.PLAY, 0x05, 0x0E, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.FLOAT); // 0 - Yaw
map(Type.FLOAT); // 1 - Pitch
map(Type.BOOLEAN); // 2 - Ground
handler(new PlayerMovementMapper());
}
});
// Player Packet
protocol.registerIncoming(State.PLAY, 0x03, 0x0F, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.BOOLEAN); // 0 - Ground
handler(new PlayerMovementMapper());
}
});
/* Packets which do not have any field remapping or handlers */
protocol.registerIncoming(State.PLAY, 0x01, 0x02); // Chat Message Packet
@@ -436,9 +574,6 @@ public class PlayerPackets {
protocol.registerIncoming(State.PLAY, 0x00, 0x0B); // Keep Alive Request Packet
protocol.registerIncoming(State.PLAY, 0x04, 0x0C, new PlayerMovementMapper()); // Player Position Packet
protocol.registerIncoming(State.PLAY, 0x06, 0x0D, new PlayerMovementMapper()); // Player Move & Look Packet
protocol.registerIncoming(State.PLAY, 0x05, 0x0E, new PlayerMovementMapper()); // Player Look Packet
protocol.registerIncoming(State.PLAY, 0x03, 0x0F, new PlayerMovementMapper()); // Player Packet
}
}
@@ -290,11 +290,11 @@ public class SpawnPackets {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
short item = wrapper.read(Type.SHORT);
System.out.println(item);
// System.out.println(item);
if (item != 0) {
PacketWrapper packet = new PacketWrapper(0x3C, null, wrapper.user());
packet.write(Type.VAR_INT, wrapper.get(Type.VAR_INT, 0));
packet.write(Type.VAR_INT, 1);
packet.write(Type.VAR_INT, 0);
packet.write(Type.ITEM, new Item(item, (byte) 1, (short) 0, null));
try {
packet.send();
@@ -14,12 +14,13 @@ import us.myles.ViaVersion.api.remapper.PacketRemapper;
import us.myles.ViaVersion.api.remapper.ValueCreator;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.packets.State;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.ArmorType;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.ItemRewriter;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.sounds.Effect;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.sounds.SoundEffect;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.ClientChunks;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.EntityTracker;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.PlaceBlockTracker;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.types.ChunkType;
public class WorldPackets {
@@ -49,12 +50,8 @@ public class WorldPackets {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
int id = wrapper.get(Type.INT, 0);
if (id >= 1000 && id < 2000 && id != 1005) { // Sound Effect
wrapper.cancel();
}
if (id == 1005) { // Fix jukebox
id = 1010;
}
id = Effect.getNewId(id);
wrapper.set(Type.INT, 0, id);
}
});
@@ -119,13 +116,11 @@ public class WorldPackets {
public void handle(PacketWrapper wrapper) throws Exception {
ClientChunks clientChunks = wrapper.user().get(ClientChunks.class);
Chunk chunk = wrapper.passthrough(new ChunkType(clientChunks));
if (chunk.isUnloadPacket()) {
PacketWrapper unload = wrapper.create(0x1D);
unload.write(Type.INT, chunk.getX());
unload.write(Type.INT, chunk.getZ());
unload.send();
wrapper.cancel();
}
if (chunk.isUnloadPacket())
wrapper.setId(0x1D);
// eat any other data (Usually happens with unload packets)
wrapper.read(Type.REMAINING_BYTES);
}
});
}
@@ -182,11 +177,19 @@ public class WorldPackets {
});
}
});
// Block Change Packet
protocol.registerOutgoing(State.PLAY, 0x23, 0x0B, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.POSITION);
map(Type.VAR_INT);
}
});
/* Packets which do not have any field remapping or handlers */
protocol.registerOutgoing(State.PLAY, 0x25, 0x08); // Block Break Animation Packet
protocol.registerOutgoing(State.PLAY, 0x24, 0x0A); // Block Action Packet
protocol.registerOutgoing(State.PLAY, 0x23, 0x0B); // Block Change Packet
protocol.registerOutgoing(State.PLAY, 0x22, 0x10); // Multi Block Change Packet
protocol.registerOutgoing(State.PLAY, 0x27, 0x1C); // Explosion Packet
protocol.registerOutgoing(State.PLAY, 0x2A, 0x22); // Particle Packet
@@ -227,7 +230,7 @@ public class WorldPackets {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
int status = wrapper.get(Type.UNSIGNED_BYTE, 0);
if (status == 5) {
if (status == 5 || status == 4 || status == 3) {
EntityTracker entityTracker = wrapper.user().get(EntityTracker.class);
if (entityTracker.isBlocking()) {
entityTracker.setBlocking(false);
@@ -254,7 +257,7 @@ public class WorldPackets {
wrapper.write(Type.LONG, -1L);
wrapper.write(Type.BYTE, (byte) 255);
// Write item in hand
Item item = Item.getItem(Protocol1_9TO1_8.getHandItem(wrapper.user()));
Item item = Protocol1_9TO1_8.getHandItem(wrapper.user());
// Blocking patch
if (ViaVersion.getConfig().isShieldBlocking()) {
if (item != null) {
@@ -334,7 +337,7 @@ public class WorldPackets {
create(new ValueCreator() {
@Override
public void write(PacketWrapper wrapper) throws Exception {
Item item = Item.getItem(Protocol1_9TO1_8.getHandItem(wrapper.user()));
Item item = Protocol1_9TO1_8.getHandItem(wrapper.user());
wrapper.write(Type.ITEM, item); // 3 - Item
}
});
@@ -346,32 +349,12 @@ public class WorldPackets {
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
Item item = wrapper.get(Type.ITEM, 0);
if (item != null) {
Material m = Material.getMaterial(item.getId());
if (m != null) {
// Prevent special items from sending certain info
// Books
boolean special = m == Material.WRITTEN_BOOK;
// Buckets
special = special || m == Material.WATER_BUCKET || m == Material.LAVA_BUCKET || m == Material.BUCKET;
// Food
special = special || m.isEdible();
// Potions
special = special || m == Material.POTION || m == Material.GLASS_BOTTLE;
// Projectiles
special = special || m == Material.BOW;
special = special || m == Material.SNOW_BALL || m == Material.EGG || m == Material.EXP_BOTTLE || m == Material.ENDER_PEARL || m == Material.EYE_OF_ENDER;
// Armour
special = special || ArmorType.isArmor(m);
// Don't send data if special
if (special && m != Material.AIR) {
EntityTracker tracker = wrapper.user().get(EntityTracker.class);
tracker.setLastPlaceBlock(wrapper.user().getReceivedPackets());
}
}
}
Position position = wrapper.get(Type.POSITION, 0);
PlaceBlockTracker tracker = wrapper.user().get(PlaceBlockTracker.class);
if (tracker.getLastPlacedPosition() != null && tracker.getLastPlacedPosition().equals(position) && !tracker.isExpired(50))
wrapper.cancel();
tracker.updateTime();
tracker.setLastPlacedPosition(position);
}
});
@@ -0,0 +1,44 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8.sounds;
import java.util.HashMap;
public class Effect {
private static HashMap<Integer, Integer> effects;
static {
effects = new HashMap<>();
addRewrite(1005, 1010); //Play music disc
addRewrite(1003, 1005); //Iron door open
addRewrite(1006, 1011); //Iron door close
addRewrite(1004, 1009); //Fizz / Fire extinguished
addRewrite(1007, 1015); //Ghast charge / warns
addRewrite(1008, 1016); //Ghast shoot
addRewrite(1009, 1016); //Ghast shoot (Lower volume according to wiki.vg)
addRewrite(1010, 1019); //Zombie attacks wood door
addRewrite(1011, 1020); //Zombie attacks metal door
addRewrite(1012, 1021); //Zombie breaks wood door
addRewrite(1014, 1024); //Wither shoot
addRewrite(1015, 1025); //Bat takeoff / aka herobrine
addRewrite(1016, 1026); //Zombie inject
addRewrite(1017, 1027); //Zombie villager converted
addRewrite(1020, 1029); //Anvil break
addRewrite(1021, 1030); //Anvil use
addRewrite(1022, 1031); //Anvil land
}
public static int getNewId(int id) {
if (!contains(id))
return id;
return effects.get(id);
}
public static boolean contains(int oldId) {
return effects.containsKey(oldId);
}
private static void addRewrite(int oldId, int newId) {
effects.put(oldId, newId);
}
}
@@ -260,9 +260,10 @@ public enum SoundEffect {
private final boolean breaksound;
private static HashMap<String, SoundEffect> effects;
static {
effects = new HashMap<String, SoundEffect>();
for(SoundEffect e : SoundEffect.values()) {
effects = new HashMap<>();
for (SoundEffect e : SoundEffect.values()) {
effects.put(e.getName(), e);
}
}
@@ -283,7 +284,7 @@ public enum SoundEffect {
public static SoundEffect getByName(String name) {
name = name.toLowerCase();
if(effects.containsKey(name))
if (effects.containsKey(name))
return effects.get(name);
return null;
}
@@ -2,13 +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;
@@ -22,18 +21,21 @@ 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.chat.GameMode;
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, 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;
@@ -43,7 +45,11 @@ public class EntityTracker extends StoredObject {
private Long lastPlaceBlock = -1L;
@Setter
private int entityID;
@Setter
private Position currentlyDigging = null;
private boolean teamExists = false;
@Setter
private GameMode gameMode;
public EntityTracker(UserConnection user) {
super(user);
@@ -89,21 +95,21 @@ public class EntityTracker extends StoredObject {
}
public boolean interactedBlockRecently(int x, int y, int z) {
if(blockInteractions.size() == 0)
if (blockInteractions.size() == 0)
return false;
Iterator<Position> it = blockInteractions.asMap().keySet().iterator();
while(it.hasNext()) {
while (it.hasNext()) {
Position p = it.next();
if(p.getX() == x)
if(p.getY() == y)
if(p.getZ() == z)
if (p.getX() == x)
if (p.getY() == y)
if (p.getZ() == z)
return true;
}
return false;
}
public void addBlockInteraction(Position p) {
blockInteractions.put(p,Material.AIR);
blockInteractions.put(p, Material.AIR);
}
public void handleMetadata(int entityID, List<Metadata> metadataList) {
@@ -126,6 +132,12 @@ public class EntityTracker extends StoredObject {
}
}
if (type == EntityType.SKELETON) {
if ((getMetaByIndex(metadataList, 12)) == null) {
metadataList.add(new Metadata(12, NewType.Boolean.getTypeID(), Type.BOOLEAN, true));
}
}
if (type == EntityType.PLAYER) {
if (metadata.getId() == 0) {
// Byte
@@ -143,9 +155,12 @@ public class EntityTracker extends StoredObject {
}
}
if (type == EntityType.ARMOR_STAND && ((ViaVersionPlugin) ViaVersion.getInstance()).isHologramPatch()) {
if (metadata.getId() == 0) {
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();
if ((data & 0x20) == 0x20) {
// Check invisible | Check small | Check if custom name is empty | Check if custom name visible is true
if ((data & 0x20) == 0x20 && ((byte) meta.getValue() & 0x01) == 0x01
&& ((String) getMetaByIndex(metadataList, 2).getValue()).length() != 0 && (boolean) getMetaByIndex(metadataList, 3).getValue()) {
if (!knownHolograms.contains(entityID)) {
knownHolograms.add(entityID);
try {
@@ -164,7 +179,7 @@ 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 (type == EntityType.ENDER_DRAGON || type == EntityType.WITHER) {
@@ -175,7 +190,7 @@ 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);
@@ -189,7 +204,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);
@@ -200,6 +215,13 @@ public class EntityTracker extends StoredObject {
}
}
public Metadata getMetaByIndex(List<Metadata> list, int index) {
for (Metadata meta : list)
if (index == meta.getId())
return meta;
return null;
}
public void sendTeamPacket(boolean b) {
PacketWrapper wrapper = new PacketWrapper(0x41, null, getUser());
wrapper.write(Type.STRING, "viaversion"); // Use viaversion as name
@@ -1,6 +1,7 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8.storage;
import lombok.Getter;
import lombok.Setter;
import us.myles.ViaVersion.api.data.StoredObject;
import us.myles.ViaVersion.api.data.UserConnection;
@@ -9,6 +10,9 @@ public class MovementTracker extends StoredObject {
private static final long IDLE_PACKET_LIMIT = 20; // Max 20 ticks behind
@Getter
private long nextIdlePacket = 0L;
@Getter
@Setter
private boolean ground = true;
public MovementTracker(UserConnection user) {
super(user);
@@ -0,0 +1,26 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8.storage;
import lombok.Getter;
import lombok.Setter;
import us.myles.ViaVersion.api.data.StoredObject;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.minecraft.Position;
@Getter
public class PlaceBlockTracker extends StoredObject {
private long lastPlaceTimestamp = System.currentTimeMillis();
@Setter
private Position lastPlacedPosition = null;
public PlaceBlockTracker(UserConnection user) {
super(user);
}
public boolean isExpired(int ms) {
return System.currentTimeMillis() > (lastPlaceTimestamp + ms);
}
public void updateTime() {
lastPlaceTimestamp = System.currentTimeMillis();
}
}
@@ -128,11 +128,6 @@ public class ChunkType extends PartialType<Chunk, ClientChunks> {
@Override
public void write(ByteBuf output, ClientChunks param, Chunk chunk) throws Exception {
if (chunk.isUnloadPacket()) {
output.clear();
Type.VAR_INT.write(output, 0x1D); // Unload packet ID
}
// Write primary info
output.writeInt(chunk.getX());
output.writeInt(chunk.getZ());
@@ -1,7 +1,6 @@
package us.myles.ViaVersion.util;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.ByteToMessageDecoder;
@@ -22,6 +22,10 @@ public class ReflectionUtil {
return Class.forName(BASE + "." + className);
}
public static String getVersion() {
return BASE.substring(BASE.lastIndexOf('.') + 1);
}
public static Object invokeStatic(Class<?> clazz, String method) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Method m = clazz.getDeclaredMethod(method);
return m.invoke(null);
+28 -1
View File
@@ -16,12 +16,39 @@ hologram-patch: false
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
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
# 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
# Use -1 to disable.
max-pps: 400
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.
# Period to track (in seconds)
# Use -1 to disable.
tracking-period: 6
# How many packets per second counts as a warning
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, :("