Compare commits

..
66 Commits
Author SHA1 Message Date
Myles 25a7915c7f 0.9.9 Version 2016-08-25 16:52:34 +01:00
Myles 822d582074 Deprecate isPorted, we port all players use getPlayerVersion instead. 2016-08-24 20:40:53 +01:00
Matsv f8a73d5fc2 Merge branch 'master' of https://github.com/Matsv/ViaVersion into upmaster 2016-08-22 21:38:19 +02:00
Matsv a0ad97947d Add the configuration to the dump command, also add a toString method to the ProtocolVersion class. 2016-08-22 21:37:51 +02:00
Myles 6ea5d0849d Missed a bit off the README 2016-08-21 15:52:59 +01:00
Myles eba512ef0b Update README with IRC 2016-08-21 15:51:21 +01:00
Matsv 0f96c24c78 Merge branch 'master' of https://github.com/Matsv/ViaVersion into dumpthemall 2016-08-20 16:21:19 +02:00
Matsv f2e4c37cd9 Add ViaVersion dump command to get all the relevant info we need by bug reports. 2016-08-20 16:19:44 +02:00
Myles f159a2250c SemVer compatibility, also change up the messages a bit. 2016-08-20 13:47:09 +01:00
Myles ed311e4059 Clean up some messages to be more understandable. 2016-08-20 12:03:23 +01:00
AlfieC 6aae98a8a9 typo (#485) 2016-08-17 23:32:21 +02:00
Matsv 0f3daa5dc4 Merge branch 'chunkFix' of https://github.com/Matsv/ViaVersion into upmaster 2016-08-08 18:00:40 +02:00
Matsv f258cf8c89 Stop depending on versions for the ChunkTypes. fix cast exceptions by using a ChunkType in front of it. 2016-08-08 17:38:11 +02:00
Matsv ca759c056e Add some missing sounds 2016-08-07 17:53:08 +02:00
Matsv d715607826 Implement 1_8 writing 2016-08-05 20:17:39 +02:00
inventivetalent afca92d122 update requests to use /v2 (#479) 2016-08-04 20:42:03 +01:00
Myles ae37b34692 Snapshot 2016-08-01 14:07:33 +01:00
Myles 9e42a368e0 Merge branch 'master' of https://github.com/MylesIsCool/ViaVersion 2016-08-01 14:06:11 +01:00
Myles 27982efd29 Bump version to 0.9.8 2016-08-01 14:05:07 +01:00
Mason c3b343fbc8 Allow non-solid blocks to be placed at feet (#472) 2016-07-22 21:06:51 +01:00
Matsv 9bedb6c741 Move some classes to other packages 2016-07-17 12:00:46 +02:00
Matsv 873f4dd298 Give it some protection 2016-07-11 22:06:00 +02:00
Matsv 693990644f Rename the Meta(List)1_9_1_10Type to Metadata(List)1_9Type and cleanup the listeners 2016-07-11 20:27:44 +02:00
Matsv b2680d76a6 WIP cleanup 2016-07-11 15:52:06 +02:00
Matsv db935b454f Make the Metadata types version based and remove the NoGravity tag init since it doesn't seem needed. 2016-07-11 13:48:48 +02:00
Myles c207a9bfff Count other worlds as nether instead of imploding. 2016-07-10 12:35:46 +01:00
Myles f5bd041c7b Fix PacketListenerAPI load to be before Via, fixes #463. Tested with NickNamer 2016-07-09 15:21:17 +01:00
Myles 07d89b24af Custom reload message #459 2016-07-09 14:41:07 +01:00
Myles 1d0c0c527c Snapshot 2016-07-08 12:56:34 +01:00
Myles 7a9cb86563 0.9.7 release 2016-07-08 12:55:05 +01:00
Myles 87b1919863 Let the normal send go through the event loop. Fix signs are sent before the chunks on a 1.9.4 server with a 1.9-1.9.2 client (#460) 2016-07-03 12:05:32 +01:00
Myles d164e413c2 Snapshot 2016-07-02 23:34:31 +01:00
Myles 76d7db044f Version bump + small dead code fix 2016-07-02 23:28:54 +01:00
Myles 046ebb8ecc Fix chunk bug 2016-07-02 23:22:44 +01:00
Myles bccde04ace Back to snapshot 2016-07-02 22:37:29 +01:00
Myles 9385f03722 Bump version and tiny bit of formatting fix 2016-07-02 22:33:54 +01:00
Myles b48fc17ead Transform block 36 for 1.9.2 reading, and also use PartialType. 2016-07-02 22:32:40 +01:00
Myles b50d0075ca PacketWrapper allow returning of ChannelFuture with send, and fix blocked protocols disconnect.
Also remove a TODO.
2016-07-02 22:19:43 +01:00
Myles 84d006c71d Merge branch 'lenis-patch' 2016-07-02 22:06:39 +01:00
Myles 212da9c46c Fix resetReader being wrong, ty @Matsv for helping solve this 2016-07-02 22:05:08 +01:00
Myles 8edb7048a1 Code cleanup and implement index fix by @Matsv 2016-07-02 21:23:28 +01:00
Myles abe3c4b0c9 Identify unsigned byte properly 2016-07-02 21:07:41 +01:00
Myles c6d3c97c65 Fix clearing of wrapper 2016-07-02 21:07:22 +01:00
Matsv 13c6a9d612 Change getBlockId to get instead of indexOf 2016-07-02 20:45:34 +02:00
Myles 7d2ef743ac Fix stupidity, thanks @Pokechu22 <3 2016-07-02 19:09:38 +01:00
Myles 598d0f96d8 Not sure if i'm working forward or backwards on this, but pushing for progress 2016-07-01 20:17:25 +01:00
Matsv cbc22922d3 Set default force-sign-transformer to false 2016-07-01 18:51:42 +02:00
Myles 49783d36c2 Add link to docs. 2016-07-01 17:13:01 +01:00
Myles 70d91b4f87 Blocked versions now included when server sends supported versions, javadoc fixes & simple colour for blocked-msg. 2016-07-01 16:36:19 +01:00
Myles 17f3d13267 Fix #450, ProtocolSupport concurrency issues, also make listwrapper sync'd 2016-06-30 00:26:12 +01:00
Myles 559674bf58 Merge branch 'master' of https://github.com/MylesIsCool/ViaVersion 2016-06-29 16:43:42 +01:00
Myles fbc298bc30 Add some more detail to the config 2016-06-29 16:38:38 +01:00
Matsv e36902c441 Add possibility to block specific protocol versions 2016-06-29 12:26:03 +02:00
Matsv 805c78989a Port all the clients to prevent issues like ViaVersions BossBarAPI not working for clients on the same protocol. (If you use the api on a 1.9> server) 2016-06-29 11:35:15 +02:00
Mats 85e416171c Let the transformer handle the signs (#456) 2016-06-28 13:16:36 +02:00
Mats b55c0d0783 Possibility to force the json transformer (#455)
* Possibility to force the json transform

* Escape all the Strings. Who likes double quotes anyways.
2016-06-26 21:47:08 +01:00
Myles 33b4b3835f Update Contributors and version in README 2016-06-25 23:38:04 +01:00
Matsv 8ccd772105 Change the formatting a bit. merged #421 2016-06-25 13:22:18 +02:00
Matsv 8677c632df Merge remote-tracking branch 'jor/potion' into upmaster 2016-06-25 13:19:14 +02:00
Myles 560476c56f Should fix #452 2016-06-24 14:02:29 +01:00
lenis0012 20bbe7cec6 Support 1.9.2 servers
This code basically reads 1.9 data so it can then be transformed to add
in the tile entities.
it geta a little funky when it already loaded it as a 1.8 chunk tho, so
i had to add some methods to the chunk api.

in short: I hate minecraft
2016-06-23 04:00:59 +02:00
Myles 1a002486d0 Move back to snapshot, oops 2016-06-22 23:37:58 +01:00
Myles 26fcdfe3bc Allow ability to replace piston extension block to prevent crashing. 2016-06-22 23:34:32 +01:00
Mats 4af98b220c Fix piston tile entity crash (#443) 2016-06-22 21:37:53 +01:00
joserobjr a79533bf72 Fixed uncraftable potion conversions from 1.8 to 1.9 2016-06-08 10:31:03 -03:00
joserobjr e3510d01d6 Fixes potion data conversion from 1.8 to 1.9 2016-06-08 08:09:13 -03:00
63 changed files with 2012 additions and 491 deletions

No files matched your search

+11 -29
View File
@@ -1,47 +1,29 @@
# ViaVersion 0.9.3
# ViaVersion 0.9.9
[![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)
**Allows the connection of 1.9 clients to 1.8**
**1.10 clients on 1.8 / 1.9 servers**
IRC: [#viaversion](http://buzz.spi.gt/iris/?channels=viaversion) on irc.spi.gt for Support.
This took 100s hours of work, so if you enjoy this consider looking into contacting me and supporting my projects.
**Allows the connection of higher client versions to lower server versions**
Allows 1.10, 1.9 on 1.8 server and 1.10 on a 1.9 server.
**User Docs:** https://docs.viaversion.com/display/VIAVERSION/
**Contributor Chat:** https://gitter.im/MylesIsCool/ViaVersion
Sources:
--------
**wiki.vg** (Used for various information, we also contribute back)
**wiki.vg** (Protocol info, though I did have to find a lot myself)
**Burger** We use this tool to get protocol and other useful information for new / undocumented Minecraft versions
**Burger** (See [PAaaS](https://github.com/Matsv/Paaas))
**OpenNBT** (used for slot rewriting)
Contributors:
--------
**Myself** (harhar)
**Matsv/StamBoom**
**HugoDaBosss**
**SanderGielisse**
**Paulomart**
**gigosaurus**
**fillefilip8**
**lenis0012**
Releases / Dev Builds:
--------
You can find official releases here:
@@ -64,5 +46,5 @@ License:
MIT License, see LICENSE for more details.
Thanks!
Special thanks to all our [Contributors](https://github.com/MylesIsCool/ViaVersion/graphs/contributors)
+1 -1
View File
@@ -6,7 +6,7 @@
<groupId>us.myles</groupId>
<artifactId>viaversion</artifactId>
<version>0.9.4</version>
<version>0.9.9</version>
<packaging>jar</packaging>
<name>ViaVersion</name>
@@ -4,6 +4,7 @@ import us.myles.ViaVersion.api.ViaVersionConfig;
import us.myles.ViaVersion.util.Configuration;
import java.io.File;
import java.util.List;
public class ViaConfig implements ViaVersionConfig {
private final ViaVersionPlugin plugin;
@@ -150,8 +151,38 @@ public class ViaConfig implements ViaVersionConfig {
return plugin.getConfig().getBoolean("nms-player-ticking", true);
}
@Override
public boolean isReplacePistons() {
return plugin.getConfig().getBoolean("replace-pistons", false);
}
@Override
public int getPistonReplacementId() {
return plugin.getConfig().getInt("replacement-piston-id", 0);
}
public boolean isAutoTeam() {
// Collision has to be enabled first
return isPreventCollision() && plugin.getConfig().getBoolean("auto-team", true);
}
@Override
public boolean isForceJsonTransform() {
return plugin.getConfig().getBoolean("force-json-transform", false);
}
@Override
public List<Integer> getBlockedProtocols() {
return plugin.getConfig().getIntegerList("block-protocols");
}
@Override
public String getBlockedDisconnectMsg() {
return plugin.getConfig().getString("block-disconnect-msg", "You are using an unsupported Minecraft version!");
}
@Override
public String getReloadDisconnectMsg() {
return plugin.getConfig().getString("reload-disconnect-msg", "Server reload, please rejoin!");
}
}
@@ -7,6 +7,7 @@ import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import lombok.Getter;
import lombok.NonNull;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginDescriptionFile;
@@ -20,6 +21,7 @@ import us.myles.ViaVersion.api.boss.BossStyle;
import us.myles.ViaVersion.api.command.ViaVersionCommand;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
import us.myles.ViaVersion.boss.ViaBossBar;
import us.myles.ViaVersion.classgenerator.ClassGenerator;
import us.myles.ViaVersion.commands.ViaCommandHandler;
@@ -27,6 +29,7 @@ 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.ConcurrentList;
import us.myles.ViaVersion.util.ListWrapper;
import us.myles.ViaVersion.util.ProtocolSupportUtil;
import us.myles.ViaVersion.util.ReflectionUtil;
@@ -53,6 +56,20 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
@Getter
private ViaConfig conf;
public ViaVersionPlugin() {
// Check if we're using protocol support too
protocolSupport = Bukkit.getPluginManager().getPlugin("ProtocolSupport") != null;
if (protocolSupport) {
getLogger().info("Hooking into ProtocolSupport, to prevent issues!");
try {
patchLists();
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public void onLoad() {
// Config magic
@@ -64,11 +81,11 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
if (Bukkit.getPluginManager().getPlugin("ProtocolLib") != null) {
getLogger().severe("ViaVersion is already loaded, we're going to kick all the players... because otherwise we'll crash because of ProtocolLib.");
for (Player player : Bukkit.getOnlinePlayers()) {
player.kickPlayer("Server reload, please rejoin!");
player.kickPlayer(ChatColor.translateAlternateColorCodes('&', getConf().getReloadDisconnectMsg()));
}
} else {
getLogger().severe("ViaVersion is already loaded, this should work fine... Otherwise reboot the server!!!");
getLogger().severe("ViaVersion is already loaded, this should work fine. If you get any console errors, try rebooting.");
}
}
@@ -87,9 +104,6 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
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();
@@ -112,9 +126,9 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
gatherProtocolVersion();
// Check if there are any pipes to this version
if (ProtocolRegistry.SERVER_PROTOCOL != -1) {
getLogger().info("ViaVersion detected protocol version: " + ProtocolRegistry.SERVER_PROTOCOL);
getLogger().info("ViaVersion detected server version: " + ProtocolVersion.getProtocol(ProtocolRegistry.SERVER_PROTOCOL));
if (!ProtocolRegistry.isWorkingPipe()) {
getLogger().warning("ViaVersion will not function on the current protocol.");
getLogger().warning("ViaVersion does not have any compatible versions for this server version, please read our resource page carefully.");
}
}
ProtocolRegistry.refreshVersions();
@@ -138,7 +152,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
@Override
public void onDisable() {
getLogger().info("ViaVersion is disabling, if this is a reload it may not work.");
getLogger().info("ViaVersion is disabling, if this is a reload and you experience issues consider rebooting.");
uninject();
}
@@ -209,7 +223,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
try {
Object connection = getServerConnection();
if (connection == null) {
getLogger().warning("We failed to find the ServerConnection? :( What server are you running?");
getLogger().warning("We failed to find the core component 'ServerConnection', please file an issue on our GitHub.");
return;
}
for (Field field : connection.getClass().getDeclaredFields()) {
@@ -243,11 +257,32 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
}
System.setProperty("ViaVersion", getDescription().getVersion());
} catch (Exception e) {
getLogger().severe("Unable to inject handlers, are you on 1.8? ");
getLogger().severe("Unable to inject ViaVersion, please post these details on our GitHub and ensure you're using a compatible server version.");
e.printStackTrace();
}
}
public void patchLists() throws Exception {
Object connection = getServerConnection();
if (connection == null) {
getLogger().warning("We failed to find the core component 'ServerConnection', please file an issue on our GitHub.");
return;
}
for (Field field : connection.getClass().getDeclaredFields()) {
field.setAccessible(true);
final Object value = field.get(connection);
if (value instanceof List) {
if (!(value instanceof ConcurrentList)) {
ConcurrentList list = new ConcurrentList();
list.addAll((List) value);
field.set(connection, list);
}
}
}
}
public boolean isBinded() {
try {
Object connection = getServerConnection();
@@ -291,12 +326,12 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
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());
throw new Exception("Unable to find core component 'childHandler', please check your plugins. issue: " + bootstrapAcceptor.getClass().getName());
}
}
} catch (Exception e) {
getLogger().severe("Have you got late-bind enabled with something else?");
getLogger().severe("We failed to inject ViaVersion, have you got late-bind enabled with something else?");
e.printStackTrace();
}
}
@@ -311,7 +346,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
ReflectionUtil.set(bootstrapAcceptor, "childHandler", ((ViaVersionInitializer) oldInit).getOriginal());
}
} catch (Exception e) {
System.out.println("Failed to remove injection... reload won't work with connections sorry");
System.out.println("Failed to remove injection handler, reload won't work with connections, please reboot!");
}
}
injectedFutures.clear();
@@ -323,7 +358,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
pair.getKey().set(pair.getValue(), ((ListWrapper) o).getOriginalList());
}
} catch (IllegalAccessException e) {
System.out.println("Failed to remove injection... reload might not work with connections sorry");
System.out.println("Failed to remove injection, reload won't work with connections, please reboot!");
}
}
@@ -417,7 +452,10 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
@Override
public SortedSet<Integer> getSupportedVersions() {
return ProtocolRegistry.getSupportedVersions();
SortedSet<Integer> outputSet = new TreeSet<>(ProtocolRegistry.getSupportedVersions());
outputSet.removeAll(getConf().getBlockedProtocols());
return outputSet;
}
@Override
@@ -3,6 +3,7 @@ package us.myles.ViaVersion.api;
import com.google.common.base.Preconditions;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import lombok.Getter;
import lombok.Setter;
import us.myles.ViaVersion.api.data.UserConnection;
@@ -223,6 +224,7 @@ public class PacketWrapper {
}
if (readableObjects.size() > 0) {
packetValues.addAll(readableObjects);
readableObjects.clear();
}
int index = 0;
@@ -267,10 +269,59 @@ public class PacketWrapper {
private void writeRemaining(ByteBuf output) {
if (inputBuffer != null) {
output.writeBytes(inputBuffer);
output.writeBytes(inputBuffer, inputBuffer.readableBytes());
}
}
/**
* Send this packet to the associated user.
* Be careful not to send packets twice.
* (Sends it after current)
*
* @param packetProtocol - The protocol version of the packet.
* @param skipCurrentPipeline - Skip the current pipeline
* @throws Exception if it fails to write
*/
public void send(Class<? extends Protocol> packetProtocol, boolean skipCurrentPipeline) throws Exception {
if (!isCancelled()) {
ByteBuf output = constructPacket(packetProtocol, skipCurrentPipeline);
user().sendRawPacket(output);
}
}
/**
* Let the packet go through the protocol pipes and write it to ByteBuf
*
* @param packetProtocol - The protocol version of the packet.
* @param skipCurrentPipeline - Skip the current pipeline
* @return Packet buffer
* @throws Exception if it fails to write
*/
private ByteBuf constructPacket(Class<? extends Protocol> packetProtocol, boolean skipCurrentPipeline) throws Exception {
// Apply current pipeline
List<Protocol> protocols = new ArrayList<>(user().get(ProtocolInfo.class).getPipeline().pipes());
// Other way if outgoing
Collections.reverse(protocols);
int index = 0;
for (int i = 0; i < protocols.size(); i++) {
if (protocols.get(i).getClass().equals(packetProtocol)) {
index = skipCurrentPipeline ? (i + 1) : (i);
break;
}
}
// Reset reader before we start
resetReader();
// Apply other protocols
apply(Direction.OUTGOING, user().get(ProtocolInfo.class).getState(), index, protocols);
// Send
ByteBuf output = inputBuffer == null ? Unpooled.buffer() : inputBuffer.alloc().buffer();
writeToBuffer(output);
return output;
}
/**
* Send this packet to the associated user.
* Be careful not to send packets twice.
@@ -280,25 +331,25 @@ public class PacketWrapper {
* @throws Exception if it fails to write
*/
public void send(Class<? extends Protocol> packetProtocol) throws Exception {
send(packetProtocol, true);
}
/**
* Send this packet to the associated user.
* Be careful not to send packets twice.
* (Sends it after current)
* Also returns the packets ChannelFuture
*
* @param packetProtocol - The protocol version of the packet.
* @return The packets ChannelFuture
* @throws Exception if it fails to write
*/
public ChannelFuture sendFuture(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);
ByteBuf output = constructPacket(packetProtocol, true);
return user().sendRawPacketFuture(output);
}
return user().getChannel().newFailedFuture(new Exception("Cancelled packet"));
}
/**
@@ -393,6 +444,10 @@ public class PacketWrapper {
* Reset the reader, so that it can be read again.
*/
public void resetReader() {
// Move readable objects are packet values
this.packetValues.addAll(readableObjects);
this.readableObjects.clear();
// Move all packet values to the readable for next packet.
this.readableObjects.addAll(packetValues);
this.packetValues.clear();
}
@@ -0,0 +1,75 @@
package us.myles.ViaVersion.api;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.protocol.Protocol;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import java.util.UUID;
@Getter(AccessLevel.PROTECTED)
@RequiredArgsConstructor
public abstract class ViaListener implements Listener {
private final ViaVersionPlugin plugin;
private final Class<? extends Protocol> requiredPipeline;
private boolean registered = false;
/**
* Get the UserConnection from a player
*
* @param player Player object
* @return The UserConnection
*/
protected UserConnection getUserConnection(@NonNull Player player) {
return getUserConnection(player.getUniqueId());
}
/**
* Get the UserConnection from an UUID
*
* @param uuid UUID object
* @return The UserConnection
*/
protected UserConnection getUserConnection(@NonNull UUID uuid) {
if (!plugin.isPorted(uuid)) return null;
return plugin.getConnection(uuid);
}
/**
* Checks if the player is on the selected pipe
*
* @param player Player Object
* @return True if on pipe
*/
protected boolean isOnPipe(Player player) {
return isOnPipe(player.getUniqueId());
}
/**
* Checks if the UUID is on the selected pipe
*
* @param uuid UUID Object
* @return True if on pipe
*/
protected boolean isOnPipe(UUID uuid) {
UserConnection userConnection = getUserConnection(uuid);
return userConnection != null &&
userConnection.get(ProtocolInfo.class).getPipeline().contains(requiredPipeline);
}
/**
* Register as Bukkit event
*/
public void register() {
if (registered) return;
plugin.getServer().getPluginManager().registerEvents(this, plugin);
registered = true;
}
}
@@ -6,6 +6,7 @@ import us.myles.ViaVersion.api.boss.BossBar;
import us.myles.ViaVersion.api.boss.BossColor;
import us.myles.ViaVersion.api.boss.BossStyle;
import us.myles.ViaVersion.api.command.ViaVersionCommand;
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
import java.util.SortedSet;
import java.util.UUID;
@@ -16,6 +17,7 @@ public interface ViaVersionAPI {
*
* @param player Bukkit player object
* @return True if the client is modified (At the moment it also means version 1.9 and higher)
* @deprecated As of 0.9.9, because all players are ported use {@link #getPlayerVersion(Player)}
*/
boolean isPorted(Player player);
@@ -41,7 +43,9 @@ public interface ViaVersionAPI {
*
* @param playerUUID UUID of a player
* @return True if the client is on 1.9
* @deprecated As of 0.9.9, because all players are ported use {@link #getPlayerVersion(UUID)}
*/
@Deprecated
boolean isPorted(UUID playerUUID);
/**
@@ -114,8 +118,10 @@ public interface ViaVersionAPI {
/**
* Get the supported protocol versions
* This method removes any blocked protocol versions.
*
* @return a list of protocol versions
* @see ProtocolRegistry#getSupportedVersions() for full list.
*/
SortedSet<Integer> getSupportedVersions();
@@ -1,5 +1,7 @@
package us.myles.ViaVersion.api;
import java.util.List;
public interface ViaVersionConfig {
/**
@@ -172,4 +174,47 @@ public interface ViaVersionConfig {
* @return if true, enabled
*/
boolean isNMSPlayerTicking();
/**
* Replace extended pistons on 1.10 chunk loading.
*
* @return True if to replace them
*/
boolean isReplacePistons();
/**
* Get the id for replacing extended pistons.
*
* @return The integer id
*/
int getPistonReplacementId();
/**
* Force json transform
*
* @return True if enabled
*/
boolean isForceJsonTransform();
/**
* Get the blocked protocols
*
* @return An Integer list
*/
List<Integer> getBlockedProtocols();
/**
* Get the custom disconnect message
*
* @return Disconnect message
*/
String getBlockedDisconnectMsg();
/**
* Get the message sent to players being kicked on reload.
* Players are kicked to stop the server crashing
*
* @return Disconnect message
*/
String getReloadDisconnectMsg();
}
@@ -1,10 +1,9 @@
package us.myles.ViaVersion.api.data;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter(AccessLevel.PROTECTED)
@Getter
@AllArgsConstructor
public class StoredObject {
private UserConnection user;
@@ -1,6 +1,7 @@
package us.myles.ViaVersion.api.data;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.socket.SocketChannel;
import lombok.Data;
@@ -85,6 +86,17 @@ public class UserConnection {
}
}
/**
* Send a raw packet to the player with returning the future
*
* @param packet The raw packet to send
* @return ChannelFuture of the packet being sent
*/
public ChannelFuture sendRawPacketFuture(final ByteBuf packet) {
final ChannelHandler handler = channel.pipeline().get("encoder");
return channel.pipeline().context(handler).writeAndFlush(packet);
}
/**
* Send a raw packet to the player (netty thread)
*
@@ -1,4 +1,23 @@
package us.myles.ViaVersion.api.minecraft.chunks;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
import java.util.List;
public interface Chunk {
int getX();
int getZ();
ChunkSection[] getSections();
boolean isGroundUp();
boolean isBiomeData();
byte[] getBiomeData();
int getBitmask();
List<CompoundTag> getBlockEntities();
}
@@ -0,0 +1,15 @@
package us.myles.ViaVersion.api.minecraft.chunks;
import io.netty.buffer.ByteBuf;
public interface ChunkSection {
int getBlockId(int x, int y, int z);
void writeBlocks(ByteBuf output) throws Exception;
void writeBlockLight(ByteBuf output) throws Exception;
boolean hasSkyLight();
void writeSkyLight(ByteBuf output) throws Exception;
}
@@ -79,6 +79,11 @@ public class ProtocolRegistry {
}
}
/**
* Get the versions compatible with the server.
*
* @return Read-only set of the versions.
*/
public static SortedSet<Integer> getSupportedVersions() {
return Collections.unmodifiableSortedSet(new TreeSet<>(supportedVersions));
}
@@ -91,4 +91,9 @@ public class ProtocolVersion {
public int hashCode() {
return id;
}
@Override
public String toString() {
return String.format("%s(%d)", this.getName(), this.getId());
}
}
@@ -10,7 +10,6 @@ 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
@@ -6,7 +6,7 @@ import us.myles.ViaVersion.api.type.TypeConverter;
public class UnsignedByteType extends Type<Short> implements TypeConverter<Short> {
public UnsignedByteType() {
super(Short.class);
super("Unsigned Byte", Short.class);
}
@Override
@@ -1,4 +1,4 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8.types;
package us.myles.ViaVersion.api.type.types.version;
import io.netty.buffer.ByteBuf;
@@ -6,7 +6,7 @@ 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.MetadataTypes;
public class MetadataType extends MetaTypeTemplate {
public class Metadata1_8Type extends MetaTypeTemplate {
@Override
public Metadata read(ByteBuf buffer) throws Exception {
@@ -19,13 +19,9 @@ public class MetadataType extends MetaTypeTemplate {
}
@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());
}
public void write(ByteBuf buffer, Metadata meta) throws Exception {
byte item = (byte) (meta.getTypeID() << 5 | meta.getId() & 0x1F);
buffer.writeByte(item);
meta.getType().write(buffer, meta.getValue());
}
}
@@ -1,11 +1,11 @@
package us.myles.ViaVersion.protocols.protocol1_10to1_9_3.types;
package us.myles.ViaVersion.api.type.types.version;
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 {
public class Metadata1_9Type extends MetaTypeTemplate {
@Override
public Metadata read(ByteBuf buffer) throws Exception {
@@ -1,21 +1,20 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8.types;
package us.myles.ViaVersion.api.type.types.version;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.minecraft.metadata.Metadata;
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 MetaListTypeTemplate {
public class MetadataList1_8Type extends MetaListTypeTemplate {
@Override
public List<Metadata> read(ByteBuf buffer) throws Exception {
List<Metadata> list = new ArrayList<>();
Metadata m;
do {
m = Protocol1_9TO1_8.METADATA.read(buffer);
m = Types1_8.METADATA.read(buffer);
if (m != null) {
list.add(m);
}
@@ -26,10 +25,8 @@ public class MetadataListType extends MetaListTypeTemplate {
@Override
public void write(ByteBuf buffer, List<Metadata> object) throws Exception {
for (Metadata m : object) {
Protocol1_9TO1_8.METADATA.write(buffer, m);
}
// Write end of list
Protocol1_9TO1_8.METADATA.write(buffer, null);
for (Metadata data : object)
Types1_8.METADATA.write(buffer, data);
buffer.writeByte(127);
}
}
@@ -0,0 +1,33 @@
package us.myles.ViaVersion.api.type.types.version;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.api.minecraft.metadata.Metadata;
import us.myles.ViaVersion.api.type.types.minecraft.MetaListTypeTemplate;
import java.util.ArrayList;
import java.util.List;
public class MetadataList1_9Type extends MetaListTypeTemplate {
@Override
public List<Metadata> read(ByteBuf buffer) throws Exception {
List<Metadata> list = new ArrayList<>();
Metadata meta;
do {
meta = Types1_9.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)
Types1_9.METADATA.write(buffer, m);
// Write end of list
Types1_9.METADATA.write(buffer, null);
}
}
@@ -0,0 +1,18 @@
package us.myles.ViaVersion.api.type.types.version;
import us.myles.ViaVersion.api.minecraft.metadata.Metadata;
import us.myles.ViaVersion.api.type.Type;
import java.util.List;
public class Types1_8 {
/**
* Metadata list type for 1.8
*/
public static Type<List<Metadata>> METADATA_LIST = new MetadataList1_8Type();
/**
* Metadata type for 1.8
*/
public static Type<Metadata> METADATA = new Metadata1_8Type();
}
@@ -0,0 +1,18 @@
package us.myles.ViaVersion.api.type.types.version;
import us.myles.ViaVersion.api.minecraft.metadata.Metadata;
import us.myles.ViaVersion.api.type.Type;
import java.util.List;
public class Types1_9 {
/**
* Metadata list type for 1.9
*/
public static final Type<List<Metadata>> METADATA_LIST = new MetadataList1_9Type();
/**
* Metadata type for 1.9
*/
public static final Type<Metadata> METADATA = new Metadata1_9Type();
}
@@ -132,6 +132,7 @@ public class ViaCommandHandler implements ViaVersionCommand, CommandExecutor, Ta
registerSubCommand(new ListSubCmd());
registerSubCommand(new PPSSubCmd());
registerSubCommand(new DebugSubCmd());
registerSubCommand(new DumpSubCmd());
registerSubCommand(new DisplayLeaksSubCmd());
registerSubCommand(new DontBugMeSubCmd());
registerSubCommand(new AutoTeamSubCmd());
@@ -0,0 +1,94 @@
package us.myles.ViaVersion.commands.defaultsubs;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.command.ViaSubCommand;
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
import us.myles.ViaVersion.dump.DumpTemplate;
import us.myles.ViaVersion.dump.PluginInfo;
import us.myles.ViaVersion.dump.VersionInfo;
import java.io.InputStreamReader;
import java.io.InvalidObjectException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
public class DumpSubCmd extends ViaSubCommand {
private final Gson gson = new GsonBuilder().setPrettyPrinting().create();
@Override
public String name() {
return "dump";
}
@Override
public String description() {
return "Dump information about your server, this is helpful if you report bugs.";
}
@Override
public boolean execute(final CommandSender sender, String[] args) {
VersionInfo version = new VersionInfo(
Bukkit.getServer().getVersion(),
Bukkit.getServer().getBukkitVersion(),
System.getProperty("java.version"),
System.getProperty("os.name"),
ProtocolRegistry.SERVER_PROTOCOL,
ProtocolRegistry.getSupportedVersions());
List<PluginInfo> plugins = new ArrayList<>();
for (Plugin p : Bukkit.getPluginManager().getPlugins())
plugins.add(new PluginInfo(p.isEnabled(), p.getDescription().getName(), p.getDescription().getVersion(), p.getDescription().getMain(), p.getDescription().getAuthors()));
Map<String, Object> configuration = ((ViaVersionPlugin) ViaVersion.getInstance()).getConfig().getValues(false);
final DumpTemplate template = new DumpTemplate(version, configuration, plugins);
Bukkit.getScheduler().runTaskAsynchronously((ViaVersionPlugin) ViaVersion.getInstance(), new Runnable() {
@Override
public void run() {
try {
HttpURLConnection con = (HttpURLConnection) new URL("http://hastebin.com/documents").openConnection();
con.setRequestProperty("Content-Type", "text/plain");
con.setRequestMethod("POST");
con.setDoOutput(true);
OutputStream out = con.getOutputStream();
out.write(gson.toJson(template).getBytes(Charset.forName("UTF-8")));
out.close();
JsonObject output = gson.fromJson(new InputStreamReader(con.getInputStream()), JsonObject.class);
con.getInputStream().close();
if (!output.has("key"))
throw new InvalidObjectException("Key is not given in Hastebin output");
sender.sendMessage(ChatColor.GREEN + "We've made a dump with useful information, report your issue and provide this url: " + getUrl(output.get("key").getAsString()));
} catch (Exception e) {
sender.sendMessage(ChatColor.RED + "Failed to dump, please check the console for more information");
((ViaVersionPlugin) ViaVersion.getInstance()).getLogger().log(Level.WARNING, "Could not paste ViaVersion dump to Hastebin", e);
}
}
});
return true;
}
private String getUrl(String id) {
return String.format("http://hastebin.com/%s.json", id);
}
}
@@ -0,0 +1,15 @@
package us.myles.ViaVersion.dump;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.List;
import java.util.Map;
@Data
@AllArgsConstructor
public class DumpTemplate {
private VersionInfo versionInfo;
private Map<String, Object> configuration;
private List<PluginInfo> plugins;
}
@@ -0,0 +1,16 @@
package us.myles.ViaVersion.dump;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.List;
@Data
@AllArgsConstructor
public class PluginInfo {
private boolean enabled;
private String name;
private String version;
private String main;
private List<String> authors;
}
@@ -0,0 +1,18 @@
package us.myles.ViaVersion.dump;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.Set;
@Data
@AllArgsConstructor
public class VersionInfo {
private String version;
private String bukkitVersion;
private String javaVersion;
private String operatingSystem;
private int serverProtocol;
private Set<Integer> enabledPipelines;
}
@@ -1,5 +1,9 @@
package us.myles.ViaVersion.protocols.base;
import io.netty.channel.ChannelFuture;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import net.md_5.bungee.api.ChatColor;
import org.apache.commons.lang.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
@@ -21,6 +25,7 @@ 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 us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
import java.util.List;
import java.util.UUID;
@@ -31,6 +36,8 @@ public class BaseProtocol extends Protocol {
@Override
protected void registerPackets() {
/* Outgoing Packets */
// Status Response Packet
registerOutgoing(State.STATUS, 0x00, 0x00, new PacketRemapper() { // Status Response Packet
@Override
public void registerMap() {
@@ -43,20 +50,26 @@ public class BaseProtocol extends Protocol {
try {
JSONObject json = (JSONObject) new JSONParser().parse(originalStatus);
JSONObject version = (JSONObject) json.get("version");
if (ViaVersion.getConfig().isSendSupportedVersions())
int protocolVersion = ((Long) version.get("protocol")).intValue();
if (ViaVersion.getConfig().isSendSupportedVersions()) //Send supported versions
version.put("supportedVersions", ViaVersion.getInstance().getSupportedVersions());
if (ProtocolRegistry.SERVER_PROTOCOL == -1) {
Long original = (Long) version.get("protocol");
ProtocolRegistry.SERVER_PROTOCOL = original.intValue();
}
if (ProtocolRegistry.SERVER_PROTOCOL == -1) // Set the Server protocol if the detection on startup failed
ProtocolRegistry.SERVER_PROTOCOL = protocolVersion;
List<Pair<Integer, Protocol>> protocols = ProtocolRegistry.getProtocolPath(info.getProtocolVersion(), ProtocolRegistry.SERVER_PROTOCOL);
if (protocols != null) {
if ((long) version.get("protocol") != 9999) //Fix serverlistplus
if (protocolVersion != 9999) //Fix ServerListPlus
version.put("protocol", info.getProtocolVersion());
} else {
// not compatible :(, *plays very sad violin*
wrapper.user().setActive(false);
}
if (ViaVersion.getConfig().getBlockedProtocols().contains(info.getProtocolVersion()))
version.put("protocol", -1); // Show blocked versions as outdated
wrapper.set(Type.STRING, 0, json.toJSONString()); // Update value
} catch (ParseException e) {
e.printStackTrace();
@@ -88,6 +101,10 @@ public class BaseProtocol extends Protocol {
info.setUsername(wrapper.get(Type.STRING, 1));
// Add to ported clients
((ViaVersionPlugin) ViaVersion.getInstance()).addPortedClient(wrapper.user());
if (info.getPipeline().pipes().size() == 1 && info.getPipeline().pipes().get(0).getClass() == BaseProtocol.class) // Only base protocol
wrapper.user().setActive(false);
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}",
@@ -130,11 +147,6 @@ public class BaseProtocol extends Protocol {
pipeline.add(prot.getValue());
}
wrapper.set(Type.VAR_INT, 0, ProtocolRegistry.SERVER_PROTOCOL);
} else {
if (state == 2) {
// not compatible :(, *plays very sad violin*
wrapper.user().setActive(false);
}
}
// Change state
@@ -151,7 +163,34 @@ public class BaseProtocol extends Protocol {
registerIncoming(State.STATUS, 0x00, 0x00); // Status Request Packet
registerIncoming(State.STATUS, 0x01, 0x01); // Status Ping Packet
registerIncoming(State.LOGIN, 0x00, 0x00); // Login Start Packet
// Login Start Packet
registerIncoming(State.LOGIN, 0x00, 0x00, new PacketRemapper() {
@Override
public void registerMap() {
handler(new PacketHandler() {
@Override
public void handle(final PacketWrapper wrapper) throws Exception {
int protocol = wrapper.user().get(ProtocolInfo.class).getProtocolVersion();
if (ViaVersion.getConfig().getBlockedProtocols().contains(protocol)) {
if (!wrapper.user().getChannel().isOpen()) return;
PacketWrapper disconnectPacket = new PacketWrapper(0x00, null, wrapper.user()); // Disconnect Packet
Protocol1_9TO1_8.FIX_JSON.write(disconnectPacket, ChatColor.translateAlternateColorCodes('&', ViaVersion.getConfig().getBlockedDisconnectMsg()));
wrapper.cancel(); // cancel current
// Send and close
ChannelFuture future = disconnectPacket.sendFuture(BaseProtocol.class);
future.addListener(new GenericFutureListener<Future<? super Void>>() {
@Override
public void operationComplete(Future<? super Void> future) throws Exception {
wrapper.user().getChannel().close();
}
});
}
}
});
}
}); // Login Start Packet
registerIncoming(State.LOGIN, 0x01, 0x01); // Encryption Response Packet
}
@@ -8,21 +8,36 @@ 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.api.type.types.version.Metadata1_9Type;
import us.myles.ViaVersion.api.type.types.version.MetadataList1_9Type;
import us.myles.ViaVersion.api.type.types.version.Types1_9;
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;
import java.util.concurrent.CopyOnWriteArrayList;
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();
@Deprecated
public static final Type<List<Metadata>> METADATA_LIST = new MetadataList1_9Type();
@Deprecated
public static final Type<Metadata> METADATA = new Metadata1_9Type();
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;
}
};
public static ValueTransformer<List<Metadata>, List<Metadata>> transformMetadata = new ValueTransformer<List<Metadata>, List<Metadata>>(Types1_9.METADATA_LIST) {
@Override
public List<Metadata> transform(PacketWrapper wrapper, List<Metadata> inputValue) throws Exception {
List<Metadata> metaList = new CopyOnWriteArrayList<>(inputValue);
for (Metadata m : metaList) {
if (m.getId() >= 5)
m.setId(m.getId() + 1);
}
return metaList;
}
};
@@ -69,7 +84,7 @@ public class Protocol1_10To1_9_3_4 extends Protocol {
@Override
public void registerMap() {
map(Type.VAR_INT); // 0 - Entity ID
map(METADATA_LIST); // 1 - Metadata list
map(Types1_9.METADATA_LIST, transformMetadata); // 1 - Metadata list
}
});
@@ -89,7 +104,7 @@ public class Protocol1_10To1_9_3_4 extends Protocol {
map(Type.SHORT); // 9 - Velocity X
map(Type.SHORT); // 10 - Velocity Y
map(Type.SHORT); // 11 - Velocity Z
map(METADATA_LIST); // 12 - Metadata
map(Types1_9.METADATA_LIST, transformMetadata); // 12 - Metadata
}
});
@@ -104,7 +119,7 @@ public class Protocol1_10To1_9_3_4 extends Protocol {
map(Type.DOUBLE); // 4 - Z
map(Type.BYTE); // 5 - Yaw
map(Type.BYTE); // 6 - Pitch
map(METADATA_LIST); // 7 - Metadata list
map(Types1_9.METADATA_LIST, transformMetadata); // 7 - Metadata list
}
});
@@ -1,41 +0,0 @@
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);
}
}
@@ -1,54 +0,0 @@
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
}
}
@@ -10,9 +10,11 @@ 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_9_1_2to1_9_3_4.chunks.BlockEntity;
import us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4.types.Chunk1_9_3_4Type;
import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.storage.ClientWorld;
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() {
@@ -57,8 +59,50 @@ public class Protocol1_9_1_2TO1_9_3_4 extends Protocol {
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());
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
Chunk1_9_3_4Type type = new Chunk1_9_3_4Type(clientWorld);
Chunk chunk = wrapper.passthrough(type);
BlockEntity.handle(chunk.getBlockEntities(), wrapper.user());
}
});
}
});
// Join (save dimension id)
registerOutgoing(State.PLAY, 0x23, 0x23, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.INT); // 0 - Entity ID
map(Type.UNSIGNED_BYTE); // 1 - Gamemode
map(Type.INT); // 2 - Dimension
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
ClientWorld clientChunks = wrapper.user().get(ClientWorld.class);
int dimensionId = wrapper.get(Type.INT, 1);
clientChunks.setEnvironment(dimensionId);
}
});
}
});
// Respawn (save dimension id)
registerOutgoing(State.PLAY, 0x33, 0x33, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.INT); // 0 - Dimension ID
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
int dimensionId = wrapper.get(Type.INT, 0);
clientWorld.setEnvironment(dimensionId);
}
});
}
@@ -67,6 +111,7 @@ public class Protocol1_9_1_2TO1_9_3_4 extends Protocol {
@Override
public void init(UserConnection userConnection) {
if (!userConnection.has(ClientWorld.class))
userConnection.put(new ClientWorld(userConnection));
}
}
@@ -1,4 +1,4 @@
package us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4;
package us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4.chunks;
import lombok.Getter;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
@@ -7,6 +7,7 @@ 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 us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4.Protocol1_9_1_2TO1_9_3_4;
import java.util.List;
import java.util.Map;
@@ -26,9 +27,6 @@ public class BlockEntity {
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) {
@@ -45,21 +43,13 @@ public class BlockEntity {
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);
}
updateBlockEntity(pos, (short) newId, tag, connection);
} catch (Exception e) {
if (ViaVersion.getInstance().isDebug()) {
System.out.println("Block Entity: " + e.getMessage() + ": " + tag);
@@ -73,14 +63,6 @@ public class BlockEntity {
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);
wrapper.send(Protocol1_9_1_2TO1_9_3_4.class, false);
}
}
@@ -1,4 +1,4 @@
package us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4;
package us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4.chunks;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -14,7 +14,12 @@ public class Chunk1_9_3_4 implements Chunk {
private int z;
private boolean groundUp;
private int bitmask;
private byte[] sections;
List<CompoundTag> blockEntities;
private ChunkSection1_9_3_4[] sections;
private byte[] biomeData;
private List<CompoundTag> blockEntities;
@Override
public boolean isBiomeData() {
return biomeData != null;
}
}
@@ -0,0 +1,293 @@
package us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4.chunks;
import com.google.common.collect.Lists;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.Getter;
import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection;
import us.myles.ViaVersion.api.minecraft.chunks.NibbleArray;
import us.myles.ViaVersion.api.type.Type;
import java.util.List;
public class ChunkSection1_9_3_4 implements ChunkSection {
/**
* 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.
*/
@Getter
private final List<Integer> palette = Lists.newArrayList();
private final int[] blocks;
private final NibbleArray blockLight;
private NibbleArray skyLight;
public ChunkSection1_9_3_4() {
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.get(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 y << 8 | z << 4 | x;
}
/**
* Read blocks from input stream.
* This reads all the block related data:
* <ul>
* <li>Block length/palette type</li>
* <li>Palette</li>
* <li>Block hashes/palette reference</li>
* </ul>
*
* @param input The buffer to read from.
* @throws Exception
*/
public void readBlocks(ByteBuf input) throws Exception {
palette.clear();
// Reaad bits per block
int bitsPerBlock = input.readUnsignedByte();
long maxEntryValue = (1L << bitsPerBlock) - 1;
if (bitsPerBlock == 0) {
bitsPerBlock = 13;
}
if (bitsPerBlock < 4) {
bitsPerBlock = 4;
}
if (bitsPerBlock > 8) {
bitsPerBlock = 13;
}
int paletteLength = Type.VAR_INT.read(input);
// Read palette
for (int i = 0; i < paletteLength; i++) {
if (bitsPerBlock != 13) {
palette.add(Type.VAR_INT.read(input));
} else {
Type.VAR_INT.read(input);
}
}
// Read blocks
Long[] blockData = Type.LONG_ARRAY.read(input);
if (blockData.length > 0) {
for (int i = 0; i < blocks.length; i++) {
int bitIndex = i * bitsPerBlock;
int startIndex = bitIndex / 64;
int endIndex = ((i + 1) * bitsPerBlock - 1) / 64;
int startBitSubIndex = bitIndex % 64;
int val;
if (startIndex == endIndex) {
val = (int) (blockData[startIndex] >>> startBitSubIndex & maxEntryValue);
} else {
int endBitSubIndex = 64 - startBitSubIndex;
val = (int) ((blockData[startIndex] >>> startBitSubIndex | blockData[endIndex] << endBitSubIndex) & maxEntryValue);
}
if (bitsPerBlock == 13) {
int type = val >> 4;
int data = val & 0xF;
setBlock(i, type, data);
} else {
blocks[i] = val;
}
}
}
}
/**
* Read block light from buffer.
*
* @param input The buffer to read from
*/
public void readBlockLight(ByteBuf input) {
byte[] handle = new byte[LIGHT_LENGTH];
input.readBytes(handle);
blockLight.setHandle(handle);
}
/**
* Read sky light from buffer.
* Note: Only sent in overworld!
*
* @param input The buffer to read from
*/
public void readSkyLight(ByteBuf input) {
byte[] handle = new byte[LIGHT_LENGTH];
input.readBytes(handle);
if (skyLight != null) {
skyLight.setHandle(handle);
return;
}
this.skyLight = new NibbleArray(handle);
}
/**
* 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;
}
}
@@ -0,0 +1,102 @@
package us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4.types;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.bukkit.World;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
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_9_1_2to1_9_3_4.chunks.Chunk1_9_3_4;
import us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4.chunks.ChunkSection1_9_3_4;
import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.storage.ClientWorld;
import java.util.Arrays;
import java.util.BitSet;
import java.util.List;
public class Chunk1_9_3_4Type extends PartialType<Chunk, ClientWorld> {
public Chunk1_9_3_4Type(ClientWorld param) {
super(param, Chunk.class);
}
@Override
public Chunk read(ByteBuf input, ClientWorld world) throws Exception {
int chunkX = input.readInt();
int chunkZ = input.readInt();
boolean groundUp = input.readBoolean();
int primaryBitmask = Type.VAR_INT.read(input);
Type.VAR_INT.read(input);
BitSet usedSections = new BitSet(16);
ChunkSection1_9_3_4[] sections = new ChunkSection1_9_3_4[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_3_4 section = new ChunkSection1_9_3_4();
sections[i] = section;
section.readBlocks(input);
section.readBlockLight(input);
if (world.getEnvironment() == World.Environment.NORMAL) {
section.readSkyLight(input);
}
}
byte[] biomeData = groundUp ? new byte[256] : null;
if (groundUp) {
input.readBytes(biomeData);
}
List<CompoundTag> nbtData = Arrays.asList(Type.NBT_ARRAY.read(input));
return new Chunk1_9_3_4(chunkX, chunkZ, groundUp, primaryBitmask, sections, biomeData, nbtData);
}
@Override
public void write(ByteBuf output, ClientWorld world, Chunk chunk) throws Exception {
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++) {
ChunkSection 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());
}
// Don't write block entities
}
@Override
public Class<? extends Type> getBaseClass() {
return BaseChunkType.class;
}
}
@@ -6,15 +6,16 @@ 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.minecraft.chunks.Chunk;
import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection;
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;
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 us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.chunks.FakeTileEntity;
import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.storage.ClientWorld;
import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.types.Chunk1_9_1_2Type;
import java.util.ArrayList;
import java.util.List;
@@ -74,35 +75,65 @@ public class Protocol1_9_3TO1_9_1_2 extends Protocol {
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
ClientChunks clientChunks = wrapper.user().get(ClientChunks.class);
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ChunkType type = new ChunkType(clientChunks);
if (wrapper.isReadable(type, 0)) {
Chunk1_9to1_8 chunk = (Chunk1_9to1_8) wrapper.read(type);
Chunk1_9_1_2Type type = new Chunk1_9_1_2Type(clientWorld);
Chunk chunk = wrapper.passthrough(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;
List<CompoundTag> tags = new ArrayList<>();
for (int i = 0; i < chunk.getSections().length; i++) {
ChunkSection 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));
}
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)) {
tags.add(FakeTileEntity.getFromBlock(x + (chunk.getX() << 4), y + (i << 4), z + (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);
}
wrapper.write(Type.NBT_ARRAY, tags.toArray(new CompoundTag[0]));
}
});
}
});
// Join (save dimension id)
registerOutgoing(State.PLAY, 0x23, 0x23, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.INT); // 0 - Entity ID
map(Type.UNSIGNED_BYTE); // 1 - Gamemode
map(Type.INT); // 2 - Dimension
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
ClientWorld clientChunks = wrapper.user().get(ClientWorld.class);
int dimensionId = wrapper.get(Type.INT, 1);
clientChunks.setEnvironment(dimensionId);
}
});
}
});
// Respawn (save dimension id)
registerOutgoing(State.PLAY, 0x33, 0x33, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.INT); // 0 - Dimension ID
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
int dimensionId = wrapper.get(Type.INT, 0);
clientWorld.setEnvironment(dimensionId);
}
});
}
@@ -110,7 +141,8 @@ public class Protocol1_9_3TO1_9_1_2 extends Protocol {
}
@Override
public void init(UserConnection userConnection) {
public void init(UserConnection user) {
if (!user.has(ClientWorld.class))
user.put(new ClientWorld(user));
}
}
@@ -1,4 +1,4 @@
package us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2;
package us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.chunks;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -1,14 +1,16 @@
package us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2;
package us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.chunks;
import com.google.common.collect.Lists;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.Getter;
import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection;
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 {
public class ChunkSection1_9_1_2 implements ChunkSection {
/**
* Size (dimensions) of blocks in a chunks section.
*/
@@ -20,7 +22,7 @@ public class ChunkSection1_9_1_2 {
/**
* Length of the block data array.
*/
@Getter
private final List<Integer> palette = Lists.newArrayList();
private final int[] blocks;
private final NibbleArray blockLight;
@@ -45,9 +47,9 @@ public class ChunkSection1_9_1_2 {
setBlock(index(x, y, z), type, data);
}
public int getBlockId(int x, int y, int z){
public int getBlockId(int x, int y, int z) {
int index = blocks[index(x, y, z)];
return palette.indexOf(index) >> 4;
return palette.get(index) >> 4;
}
/**
@@ -88,7 +90,101 @@ public class ChunkSection1_9_1_2 {
}
private int index(int x, int y, int z) {
return z << 8 | y << 4 | x;
return y << 8 | z << 4 | x;
}
/**
* Read blocks from input stream.
* This reads all the block related data:
* <ul>
* <li>Block length/palette type</li>
* <li>Palette</li>
* <li>Block hashes/palette reference</li>
* </ul>
*
* @param input The buffer to read from.
* @throws Exception
*/
public void readBlocks(ByteBuf input) throws Exception {
palette.clear();
// Reaad bits per block
int bitsPerBlock = input.readUnsignedByte();
long maxEntryValue = (1L << bitsPerBlock) - 1;
if (bitsPerBlock == 0) {
bitsPerBlock = 13;
}
if (bitsPerBlock < 4) {
bitsPerBlock = 4;
}
if (bitsPerBlock > 8) {
bitsPerBlock = 13;
}
int paletteLength = Type.VAR_INT.read(input);
// Read palette
for (int i = 0; i < paletteLength; i++) {
if (bitsPerBlock != 13) {
palette.add(Type.VAR_INT.read(input));
} else {
Type.VAR_INT.read(input);
}
}
// Read blocks
Long[] blockData = Type.LONG_ARRAY.read(input);
if (blockData.length > 0) {
for (int i = 0; i < blocks.length; i++) {
int bitIndex = i * bitsPerBlock;
int startIndex = bitIndex / 64;
int endIndex = ((i + 1) * bitsPerBlock - 1) / 64;
int startBitSubIndex = bitIndex % 64;
int val;
if (startIndex == endIndex) {
val = (int) (blockData[startIndex] >>> startBitSubIndex & maxEntryValue);
} else {
int endBitSubIndex = 64 - startBitSubIndex;
val = (int) ((blockData[startIndex] >>> startBitSubIndex | blockData[endIndex] << endBitSubIndex) & maxEntryValue);
}
if (bitsPerBlock == 13) {
int type = val >> 4;
int data = val & 0xF;
setBlock(i, type, data);
} else {
blocks[i] = val;
}
}
}
}
/**
* Read block light from buffer.
*
* @param input The buffer to read from
*/
public void readBlockLight(ByteBuf input) {
byte[] handle = new byte[LIGHT_LENGTH];
input.readBytes(handle);
blockLight.setHandle(handle);
}
/**
* Read sky light from buffer.
* Note: Only sent in overworld!
*
* @param input The buffer to read from
*/
public void readSkyLight(ByteBuf input) {
byte[] handle = new byte[LIGHT_LENGTH];
input.readBytes(handle);
if (skyLight != null) {
skyLight.setHandle(handle);
return;
}
this.skyLight = new NibbleArray(handle);
}
/**
@@ -1,4 +1,4 @@
package us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2;
package us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.chunks;
import org.bukkit.Material;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
@@ -27,7 +27,7 @@ public class FakeTileEntity {
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.PISTON_BASE, Material.PISTON_EXTENSION, Material.PISTON_STICKY_BASE, Material.PISTON_MOVING_PIECE), "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");
@@ -38,7 +38,7 @@ public class FakeTileEntity {
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(209, "EndGateway");
register(Material.COMMAND.getId(), "Control");
}
@@ -0,0 +1,33 @@
package us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.storage;
import lombok.Getter;
import org.bukkit.World;
import us.myles.ViaVersion.api.data.StoredObject;
import us.myles.ViaVersion.api.data.UserConnection;
@Getter
public class ClientWorld extends StoredObject {
private World.Environment environment;
public ClientWorld(UserConnection user) {
super(user);
}
public void setEnvironment(int environmentId) {
this.environment = getEnvFromId(environmentId);
}
private World.Environment getEnvFromId(int id) {
switch(id) {
case -1:
return World.Environment.NETHER;
case 0:
return World.Environment.NORMAL;
case 1:
return World.Environment.THE_END;
default:
return World.Environment.NETHER;
//throw new IllegalArgumentException("Invalid environment id:" + id);
}
}
}
@@ -1,23 +1,35 @@
package us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2;
package us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.types;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.bukkit.World;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
import us.myles.ViaVersion.api.ViaVersion;
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.ChunkSection1_9to1_8;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.protocols.protocol1_10to1_9_3.Protocol1_10To1_9_3_4;
import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.chunks.Chunk1_9_1_2;
import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.chunks.ChunkSection1_9_1_2;
import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.storage.ClientWorld;
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");
public class Chunk1_9_1_2Type extends PartialType<Chunk, ClientWorld> {
public Chunk1_9_1_2Type(ClientWorld clientWorld) {
super(clientWorld, Chunk.class);
}
@Override
public Chunk read(ByteBuf input) throws Exception {
public Chunk read(ByteBuf input, ClientWorld world) throws Exception {
boolean replacePistons = world.getUser().get(ProtocolInfo.class).getPipeline().contains(Protocol1_10To1_9_3_4.class) && ViaVersion.getConfig().isReplacePistons();
int replacementId = ViaVersion.getConfig().getPistonReplacementId();
int chunkX = input.readInt();
int chunkZ = input.readInt();
@@ -39,29 +51,29 @@ public class Chunk1_9_1_2Type extends BaseChunkType {
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);
*/
section.readBlocks(input);
section.readBlockLight(input);
if (world.getEnvironment() == World.Environment.NORMAL) {
section.readSkyLight(input);
}
if (replacePistons) {
if (section.getPalette().contains(36)) {
section.getPalette().set(section.getPalette().indexOf(36), replacementId);
}
}
}
byte[] biomeData = groundUp ? new byte[256] : null;
if (groundUp)
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;
public void write(ByteBuf output, ClientWorld world, Chunk input) throws Exception {
Chunk chunk = input;
output.writeInt(chunk.getX());
output.writeInt(chunk.getZ());
@@ -71,7 +83,7 @@ public class Chunk1_9_1_2Type extends BaseChunkType {
ByteBuf buf = Unpooled.buffer();
for (int i = 0; i < 16; i++) {
ChunkSection1_9_1_2 section = chunk.getSections()[i];
ChunkSection section = chunk.getSections()[i];
if (section == null) continue; // Section not set
section.writeBlocks(buf);
section.writeBlockLight(buf);
@@ -89,7 +101,10 @@ public class Chunk1_9_1_2Type extends BaseChunkType {
if (chunk.isBiomeData()) {
output.writeBytes(chunk.getBiomeData());
}
}
// Type.NBT_ARRAY.write(output, tags.toArray(new CompoundTag[0])); Written by the handler
@Override
public Class<? extends Type> getBaseClass() {
return BaseChunkType.class;
}
}
@@ -213,11 +213,9 @@ public class ItemRewriter {
item.setId((short) 438); // splash id
item.setData((short) (item.getData() - 8192));
}
if (POTION_ID_TO_NAME.containsKey((int) item.getData())) {
String name = POTION_ID_TO_NAME.get((int) item.getData());
StringTag potion = new StringTag("Potion", "minecraft:" + name);
tag.put(potion);
}
String name = potionNameFromDamage(item.getData());
StringTag potion = new StringTag("Potion", "minecraft:" + name);
tag.put(potion);
item.setTag(tag);
item.setData((short) 0);
}
@@ -245,10 +243,113 @@ public class ItemRewriter {
}
}
public static String potionNameFromDamage(short damage) {
String cached = POTION_ID_TO_NAME.get((int) damage);
if (cached != null) {
return cached;
}
if (damage == 0) {
return "water";
}
int effect = damage & 0xF;
int name = damage & 0x3F;
boolean enhanced = (damage & 0x20) > 0;
boolean extended = (damage & 0x40) > 0;
boolean canEnhance = true;
boolean canExtend = true;
String id;
switch (effect) {
case 1:
id = "regeneration";
break;
case 2:
id = "swiftness";
break;
case 3:
id = "fire_resistance";
canEnhance = false;
break;
case 4:
id = "poison";
break;
case 5:
id = "healing";
canExtend = false;
break;
case 6:
id = "night_vision";
canEnhance = false;
break;
case 8:
id = "weakness";
canEnhance = false;
break;
case 9:
id = "strength";
break;
case 10:
id = "slowness";
canEnhance = false;
break;
case 11:
id = "leaping";
break;
case 12:
id = "harming";
canExtend = false;
break;
case 13:
id = "water_breathing";
canEnhance = false;
break;
case 14:
id = "invisibility";
canEnhance = false;
break;
default:
canEnhance = false;
canExtend = false;
switch (name) {
case 0:
id = "mundane";
break;
case 16:
id = "awkward";
break;
case 32:
id = "thick";
break;
default:
id = "empty";
}
}
if (effect > 0) {
if (canEnhance && enhanced) {
id = "strong_" + id;
} else if (canExtend && extended) {
id = "long_" + id;
}
}
return id;
}
public static int getNewEffectID(int oldID) {
if (oldID >= 16384) {
oldID -= 8192;
}
if (POTION_INDEX.containsKey(oldID)) {
return POTION_INDEX.get(oldID);
}
oldID = POTION_NAME_TO_ID.get(potionNameFromDamage((short) oldID));
return POTION_INDEX.containsKey(oldID) ? POTION_INDEX.get(oldID) : 0;
}
@@ -13,12 +13,12 @@ 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.api.type.types.version.Metadata1_8Type;
import us.myles.ViaVersion.api.type.types.version.MetadataList1_8Type;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.listeners.*;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.packets.*;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.*;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.types.MetadataListType;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.types.MetadataType;
import java.util.List;
import java.util.UUID;
@@ -26,8 +26,11 @@ import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
public class Protocol1_9TO1_8 extends Protocol {
public static Type<List<Metadata>> METADATA_LIST = new MetadataListType();
public static Type<Metadata> METADATA = new MetadataType();
@Deprecated
public static Type<List<Metadata>> METADATA_LIST = new MetadataList1_8Type();
@Deprecated
public static Type<Metadata> METADATA = new Metadata1_8Type();
private static Gson gson = new GsonBuilder().create();
public static ValueTransformer<String, String> FIX_JSON = new ValueTransformer<String, String>(Type.STRING) {
@Override
@@ -41,9 +44,7 @@ public class Protocol1_9TO1_8 extends Protocol {
line = "{\"text\":\"\"}";
} else {
if ((!line.startsWith("\"") || !line.endsWith("\"")) && (!line.startsWith("{") || !line.endsWith("}"))) {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("text", line);
return gson.toJson(jsonObject);
return constructJson(line);
}
if (line.startsWith("\"") && line.endsWith("\"")) {
line = "{\"text\":" + line + "}";
@@ -52,12 +53,22 @@ public class Protocol1_9TO1_8 extends Protocol {
try {
gson.fromJson(line, JsonObject.class);
} catch (Exception e) {
System.out.println("Invalid JSON String: \"" + line + "\" Please report this issue to the ViaVersion Github: " + e.getMessage());
return "{\"text\":\"\"}";
if (ViaVersion.getConfig().isForceJsonTransform()) {
return constructJson(line);
} else {
System.out.println("Invalid JSON String: \"" + line + "\" Please report this issue to the ViaVersion Github: " + e.getMessage());
return "{\"text\":\"\"}";
}
}
return line;
}
private static String constructJson(String text) {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("text", text);
return gson.toJson(jsonObject);
}
public static Item getHandItem(final UserConnection info) {
if (HandItemCache.CACHE) {
return HandItemCache.getHandItem(info.get(ProtocolInfo.class).getUuid());
@@ -94,13 +105,15 @@ public class Protocol1_9TO1_8 extends Protocol {
@Override
protected void registerListeners() {
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);
new ArmorListener(plugin).register();
new CommandBlockListener(plugin).register();
new DeathListener(plugin).register();
new BlockListener(plugin).register();
if (Bukkit.getVersion().toLowerCase().contains("paper") || Bukkit.getVersion().toLowerCase().contains("taco")) {
plugin.getLogger().info("Enabling PaperSpigot/TacoSpigot patch: Fixes block placement.");
Bukkit.getPluginManager().registerEvents(new PaperPatch(), plugin);
new PaperPatch(plugin).register();
}
if (plugin.getConf().isStimulatePlayerTick())
new ViaIdleThread(plugin.getPortedPlayers()).runTaskTimer(plugin, 1L, 1L); // Updates player's idle status
@@ -3,8 +3,12 @@ package us.myles.ViaVersion.protocols.protocol1_9to1_8.chunks;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
import us.myles.ViaVersion.api.minecraft.chunks.Chunk;
import java.util.Collections;
import java.util.List;
@RequiredArgsConstructor
@Getter
@ToString
@@ -36,4 +40,19 @@ public class Chunk1_9to1_8 implements Chunk {
public boolean hasBiomeData() {
return biomeData != null && groundUp;
}
@Override
public boolean isBiomeData() {
return biomeData != null;
}
@Override
public int getBitmask() {
return primaryBitmask;
}
@Override
public List<CompoundTag> getBlockEntities() {
return Collections.emptyList();
}
}
@@ -3,12 +3,13 @@ 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.ChunkSection;
import us.myles.ViaVersion.api.minecraft.chunks.NibbleArray;
import us.myles.ViaVersion.api.type.Type;
import java.util.List;
public class ChunkSection1_9to1_8 {
public class ChunkSection1_9to1_8 implements ChunkSection {
/**
* Size (dimensions) of blocks in a chunks section.
*/
@@ -88,7 +89,7 @@ public class ChunkSection1_9to1_8 {
}
private int index(int x, int y, int z) {
return z << 8 | y << 4 | x;
return y << 8 | z << 4 | x;
}
/**
@@ -1,12 +1,10 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8.listeners;
import lombok.RequiredArgsConstructor;
import org.bukkit.Bukkit;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.PlayerChangedWorldEvent;
@@ -16,30 +14,28 @@ 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.ViaListener;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.ArmorType;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
import java.util.UUID;
@RequiredArgsConstructor
public class ArmorListener implements Listener {
public class ArmorListener extends ViaListener {
private static final UUID ARMOR_ATTRIBUTE = UUID.fromString("2AD3F246-FEE1-4E67-B886-69FD380BB150");
private final ViaVersionPlugin plugin;
public static void sendArmorUpdate(Player player) {
public ArmorListener(ViaVersionPlugin plugin) {
super(plugin, Protocol1_9TO1_8.class);
}
public void sendArmorUpdate(Player player) {
// Ensure that the player is on our pipe
UserConnection userConnection = ((ViaVersionPlugin) ViaVersion.getInstance()).getConnection(player);
if (userConnection == null) return;
if (!userConnection.get(ProtocolInfo.class).getPipeline().contains(Protocol1_9TO1_8.class)) return;
if (!isOnPipe(player)) return;
int armor = ArmorType.calculateArmorPoints(player.getInventory().getArmorContents());
PacketWrapper wrapper = new PacketWrapper(0x4B, null, userConnection);
PacketWrapper wrapper = new PacketWrapper(0x4B, null, getUserConnection(player));
try {
wrapper.write(Type.VAR_INT, player.getEntityId()); // Player ID
wrapper.write(Type.INT, 1); // only 1 property
@@ -61,17 +57,15 @@ public class ArmorListener implements Listener {
HumanEntity human = e.getWhoClicked();
if (human instanceof Player && e.getInventory() instanceof CraftingInventory) {
final Player player = (Player) human;
if (ViaVersion.getInstance().isPorted(player)) {
if (e.getCurrentItem() != null) {
if (ArmorType.isArmor(e.getCurrentItem().getType())) {
sendDelayedArmorUpdate(player);
return;
}
}
if (e.getRawSlot() >= 5 && e.getRawSlot() <= 8) {
if (e.getCurrentItem() != null) {
if (ArmorType.isArmor(e.getCurrentItem().getType())) {
sendDelayedArmorUpdate(player);
return;
}
}
if (e.getRawSlot() >= 5 && e.getRawSlot() <= 8) {
sendDelayedArmorUpdate(player);
}
}
}
@@ -81,12 +75,10 @@ public class ArmorListener implements Listener {
if (e.getAction() == Action.RIGHT_CLICK_AIR || e.getAction() == Action.RIGHT_CLICK_BLOCK) {
final Player player = e.getPlayer();
// Due to odd bugs it's 3 ticks later
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
Bukkit.getScheduler().scheduleSyncDelayedTask(getPlugin(), new Runnable() {
@Override
public void run() {
if (ViaVersion.getInstance().isPorted(player)) {
sendArmorUpdate(player);
}
sendArmorUpdate(player);
}
}, 3L);
}
@@ -100,23 +92,20 @@ public class ArmorListener implements Listener {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onRespawn(PlayerRespawnEvent e) {
if (ViaVersion.getInstance().isPorted(e.getPlayer()))
sendDelayedArmorUpdate(e.getPlayer());
sendDelayedArmorUpdate(e.getPlayer());
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onWorldChange(PlayerChangedWorldEvent e) {
if (ViaVersion.getInstance().isPorted(e.getPlayer()))
sendArmorUpdate(e.getPlayer());
sendArmorUpdate(e.getPlayer());
}
public void sendDelayedArmorUpdate(final Player player) {
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
if (!isOnPipe(player)) return; // Don't start a task if the player is not on the pipe
Bukkit.getScheduler().scheduleSyncDelayedTask(getPlugin(), new Runnable() {
@Override
public void run() {
if (ViaVersion.getInstance().isPorted(player)) {
sendArmorUpdate(player);
}
sendArmorUpdate(player);
}
});
}
@@ -1,30 +1,28 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8.listeners;
import lombok.RequiredArgsConstructor;
import org.bukkit.block.Block;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.ViaListener;
import us.myles.ViaVersion.api.minecraft.Position;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.EntityTracker;
@RequiredArgsConstructor
public class BlockListener implements Listener {
public class BlockListener extends ViaListener {
private final ViaVersionPlugin plugin;
public BlockListener(ViaVersionPlugin plugin) {
super(plugin, Protocol1_9TO1_8.class);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void placeBlock(BlockPlaceEvent e) {
if (plugin.isPorted(e.getPlayer())) {
UserConnection c = plugin.getConnection(e.getPlayer());
if (!c.get(ProtocolInfo.class).getPipeline().contains(Protocol1_9TO1_8.class)) return;
if (isOnPipe(e.getPlayer())) {
Block b = e.getBlockPlaced();
plugin.getConnection(e.getPlayer()).get(EntityTracker.class).addBlockInteraction(new Position((long) b.getX(), (long) b.getY(), (long) b.getZ()));
getUserConnection(e.getPlayer())
.get(EntityTracker.class)
.addBlockInteraction(new Position((long) b.getX(), (long) b.getY(), (long) b.getZ()));
}
}
}
@@ -3,14 +3,12 @@ package us.myles.ViaVersion.protocols.protocol1_9to1_8.listeners;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufOutputStream;
import io.netty.buffer.Unpooled;
import lombok.RequiredArgsConstructor;
import org.bukkit.Bukkit;
import org.bukkit.block.Block;
import org.bukkit.block.CommandBlock;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerInteractEvent;
@@ -20,11 +18,10 @@ 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.ViaListener;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.minecraft.Position;
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.util.ReflectionUtil;
@@ -32,10 +29,11 @@ import java.io.DataOutput;
import java.io.DataOutputStream;
import java.lang.reflect.Method;
@RequiredArgsConstructor
public class CommandBlockListener implements Listener {
public class CommandBlockListener extends ViaListener {
private final ViaVersionPlugin plugin;
public CommandBlockListener(ViaVersionPlugin plugin) {
super(plugin, Protocol1_9TO1_8.class);
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onJoin(PlayerJoinEvent e) {
@@ -44,7 +42,9 @@ public class CommandBlockListener implements Listener {
@EventHandler(priority = EventPriority.MONITOR)
public void onRespawn(final PlayerRespawnEvent e) {
Bukkit.getScheduler().runTaskLater(plugin, new Runnable() {
if (!isOnPipe(e.getPlayer())) return;
Bukkit.getScheduler().runTaskLater(getPlugin(), new Runnable() {
@Override
public void run() {
sendOp(e.getPlayer());
@@ -59,12 +59,7 @@ public class CommandBlockListener implements Listener {
@EventHandler(ignoreCancelled = true)
public void onInteract(PlayerInteractEvent e) {
if (e.getAction() == Action.RIGHT_CLICK_BLOCK && plugin.isPorted(e.getPlayer()) && e.getPlayer().isOp()) {
// Ensure that the player is on our pipe
UserConnection userConnection = ((ViaVersionPlugin) ViaVersion.getInstance()).getConnection(e.getPlayer());
if (userConnection == null) return;
if (!userConnection.get(ProtocolInfo.class).getPipeline().contains(Protocol1_9TO1_8.class)) return;
if (e.getAction() == Action.RIGHT_CLICK_BLOCK && isOnPipe(e.getPlayer()) && e.getPlayer().isOp()) {
try {
sendCommandBlockPacket(e.getClickedBlock(), e.getPlayer());
} catch (Exception ex) {
@@ -74,16 +69,13 @@ public class CommandBlockListener implements Listener {
}
private void sendOp(Player p) {
if (p.isOp() && plugin.isPorted(p)) {
// Ensure that the player is on our pipe
UserConnection userConnection = ((ViaVersionPlugin) ViaVersion.getInstance()).getConnection(p);
if (userConnection == null) return;
if (!userConnection.get(ProtocolInfo.class).getPipeline().contains(Protocol1_9TO1_8.class)) return;
if (p.isOp() && isOnPipe(p)) {
try {
PacketWrapper wrapper = new PacketWrapper(0x1B, null, userConnection); // Entity status
wrapper.write(Type.INT, p.getEntityId());
PacketWrapper wrapper = new PacketWrapper(0x1B, null, getUserConnection(p)); // Entity status
wrapper.write(Type.INT, p.getEntityId()); // Entity ID
wrapper.write(Type.BYTE, (byte) 26); //Hardcoded op permission level
wrapper.send(Protocol1_9TO1_8.class);
} catch (Exception e) {
e.printStackTrace();
@@ -99,9 +91,7 @@ public class CommandBlockListener implements Listener {
Object tileEntityCommand = ReflectionUtil.get(cmd, "commandBlock", ReflectionUtil.nms("TileEntityCommand"));
Object updatePacket = ReflectionUtil.invoke(tileEntityCommand, "getUpdatePacket");
UserConnection userConnection = ((ViaVersionPlugin) ViaVersion.getInstance()).getConnection(player);
PacketWrapper wrapper = generatePacket(updatePacket, userConnection);
PacketWrapper wrapper = generatePacket(updatePacket, getUserConnection(player));
wrapper.send(Protocol1_9TO1_8.class);
}
@@ -1,40 +1,28 @@
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.ViaListener;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
@RequiredArgsConstructor
public class DeathListener implements Listener {
private final ViaVersionPlugin plugin;
public class DeathListener extends ViaListener {
public DeathListener(ViaVersionPlugin plugin) {
super(plugin, Protocol1_9TO1_8.class);
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onDeath(PlayerDeathEvent e) {
Player p = e.getEntity();
if (ViaVersion.getConfig().isShowNewDeathMessages() && checkGamerule(p.getWorld()) && e.getDeathMessage() != null && checkPipeline(p)) {
if (isOnPipe(p) && ViaVersion.getConfig().isShowNewDeathMessages() && checkGamerule(p.getWorld()) && e.getDeathMessage() != null)
sendPacket(p, e.getDeathMessage());
}
}
public boolean checkPipeline(Player p) {
UserConnection userConnection = plugin.getConnection(p);
return userConnection != null && userConnection.get(ProtocolInfo.class).getPipeline().contains(Protocol1_9TO1_8.class);
}
private UserConnection getUserConnection(Player p) {
return plugin.getConnection(p);
}
public boolean checkGamerule(World w) {
@@ -46,19 +34,19 @@ public class DeathListener implements Listener {
}
private void sendPacket(final Player p, final String msg) {
Bukkit.getScheduler().runTask(plugin, new Runnable() {
Bukkit.getScheduler().runTask(getPlugin(), new Runnable() {
@Override
public void run() {
PacketWrapper wrapper = new PacketWrapper(0x2C, null, getUserConnection(p));
try {
wrapper.write(Type.VAR_INT, 2);
wrapper.write(Type.VAR_INT, p.getEntityId());
wrapper.write(Type.INT, p.getEntityId());
Protocol1_9TO1_8.FIX_JSON.write(wrapper, msg);
wrapper.write(Type.VAR_INT, 2); // Event - Entity dead
wrapper.write(Type.VAR_INT, p.getEntityId()); // Player ID
wrapper.write(Type.INT, p.getEntityId()); // Entity ID
Protocol1_9TO1_8.FIX_JSON.write(wrapper, msg); // Message
wrapper.send(Protocol1_9TO1_8.class);
} catch (Exception e) {
e.printStackTrace();
wrapper.clearInputBuffer();
}
}
});
@@ -1,32 +1,35 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_8.listeners;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.api.ViaListener;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
public class PaperPatch implements Listener {
public class PaperPatch extends ViaListener {
public PaperPatch(ViaVersionPlugin plugin) {
super(plugin, Protocol1_9TO1_8.class);
}
/*
This patch is applied when Paper is detected.
I'm unsure of what causes this but essentially,
placing blocks where your standing works?
placing blocks where you're standing works?
If there is a better fix then we'll replace this.
*/
@EventHandler(ignoreCancelled = true)
public void onPlace(BlockPlaceEvent e) {
if (ViaVersion.getInstance().isPorted(e.getPlayer())) {
UserConnection userConnection = ((ViaVersionPlugin) ViaVersion.getInstance()).getConnection(e.getPlayer());
if (userConnection == null) return;
if (!userConnection.get(ProtocolInfo.class).getPipeline().contains(Protocol1_9TO1_8.class)) return;
if (isOnPipe(e.getPlayer())) {
Location diff = e.getPlayer().getLocation().subtract(e.getBlock().getLocation().add(0.5D, 0, 0.5D));
Material block = e.getBlockPlaced().getType();
if (!block.isSolid()) {
return;
}
if (e.getPlayer().getLocation().getBlock().equals(e.getBlock())) {
e.setCancelled(true);
} else {
@@ -10,6 +10,8 @@ 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.api.type.types.version.Types1_8;
import us.myles.ViaVersion.api.type.types.version.Types1_9;
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;
@@ -175,11 +177,11 @@ public class EntityPackets {
@Override
public void registerMap() {
map(Type.VAR_INT); // 0 - Entity ID
map(Protocol1_9TO1_8.METADATA_LIST); // 1 - Metadata List
map(Types1_8.METADATA_LIST, Types1_9.METADATA_LIST); // 1 - Metadata List
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
List<Metadata> metadataList = wrapper.get(Protocol1_9TO1_8.METADATA_LIST, 0);
List<Metadata> metadataList = wrapper.get(Types1_9.METADATA_LIST, 0);
int entityID = wrapper.get(Type.VAR_INT, 0);
EntityTracker tracker = wrapper.user().get(EntityTracker.class);
if (tracker.getClientEntityTypes().containsKey(entityID)) {
@@ -196,7 +198,7 @@ public class EntityPackets {
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
List<Metadata> metadataList = wrapper.get(Protocol1_9TO1_8.METADATA_LIST, 0);
List<Metadata> metadataList = wrapper.get(Types1_9.METADATA_LIST, 0);
int entityID = wrapper.get(Type.VAR_INT, 0);
EntityTracker tracker = wrapper.user().get(EntityTracker.class);
tracker.handleMetadata(entityID, metadataList);
@@ -207,7 +209,7 @@ public class EntityPackets {
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
List<Metadata> metadataList = wrapper.get(Protocol1_9TO1_8.METADATA_LIST, 0);
List<Metadata> metadataList = wrapper.get(Types1_9.METADATA_LIST, 0);
if (metadataList.size() == 0) {
wrapper.cancel();
}
@@ -11,6 +11,8 @@ import us.myles.ViaVersion.api.remapper.PacketRemapper;
import us.myles.ViaVersion.api.remapper.ValueCreator;
import us.myles.ViaVersion.api.remapper.ValueTransformer;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.api.type.types.version.Types1_8;
import us.myles.ViaVersion.api.type.types.version.Types1_9;
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;
@@ -107,7 +109,7 @@ public class SpawnPackets {
// 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);
wrapper.write(Types1_9.METADATA_LIST, meta);
}
});
metaPacket.send(Protocol1_9TO1_8.class);
@@ -206,11 +208,11 @@ public class SpawnPackets {
map(Type.SHORT); // 10 - Velocity Y
map(Type.SHORT); // 11 - Velocity Z
map(Protocol1_9TO1_8.METADATA_LIST);
map(Types1_8.METADATA_LIST, Types1_9.METADATA_LIST);
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
List<Metadata> metadataList = wrapper.get(Protocol1_9TO1_8.METADATA_LIST, 0);
List<Metadata> metadataList = wrapper.get(Types1_9.METADATA_LIST, 0);
int entityID = wrapper.get(Type.VAR_INT, 0);
EntityTracker tracker = wrapper.user().get(EntityTracker.class);
if (tracker.getClientEntityTypes().containsKey(entityID)) {
@@ -225,7 +227,7 @@ public class SpawnPackets {
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
List<Metadata> metadataList = wrapper.get(Protocol1_9TO1_8.METADATA_LIST, 0);
List<Metadata> metadataList = wrapper.get(Types1_9.METADATA_LIST, 0);
int entityID = wrapper.get(Type.VAR_INT, 0);
EntityTracker tracker = wrapper.user().get(EntityTracker.class);
tracker.handleMetadata(entityID, metadataList);
@@ -311,12 +313,12 @@ public class SpawnPackets {
}
});
map(Protocol1_9TO1_8.METADATA_LIST);
map(Types1_8.METADATA_LIST, Types1_9.METADATA_LIST);
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
List<Metadata> metadataList = wrapper.get(Protocol1_9TO1_8.METADATA_LIST, 0);
List<Metadata> metadataList = wrapper.get(Types1_9.METADATA_LIST, 0);
int entityID = wrapper.get(Type.VAR_INT, 0);
EntityTracker tracker = wrapper.user().get(EntityTracker.class);
if (tracker.getClientEntityTypes().containsKey(entityID)) {
@@ -332,7 +334,7 @@ public class SpawnPackets {
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
List<Metadata> metadataList = wrapper.get(Protocol1_9TO1_8.METADATA_LIST, 0);
List<Metadata> metadataList = wrapper.get(Types1_9.METADATA_LIST, 0);
int entityID = wrapper.get(Type.VAR_INT, 0);
EntityTracker tracker = wrapper.user().get(EntityTracker.class);
tracker.handleMetadata(entityID, metadataList);
@@ -35,7 +35,7 @@ public enum SoundEffect {
MOB_HORSE_ZOMBIE_DEATH("mob.horse.zombie.death", "entity.zombie_horse.death", SoundCategory.NEUTRAL),
MOB_SILVERFISH_KILL("mob.silverfish.kill", "entity.endermite.death", SoundCategory.HOSTILE),
MOB_WOLF_PANTING("mob.wolf.panting", "entity.wolf.pant", SoundCategory.NEUTRAL),
NOTE_BASS("note.bass", "null", SoundCategory.RECORD),
NOTE_BASS("note.bass", "block.note.bass", SoundCategory.RECORD),
DIG_STONE("dig.stone", "block.glass.place", SoundCategory.BLOCK),
MOB_ENDERMEN_STARE("mob.endermen.stare", "entity.endermen.stare", SoundCategory.HOSTILE),
GAME_PLAYER_SWIM_SPLASH("game.player.swim.splash", "entity.generic.splash", SoundCategory.BLOCK),
@@ -79,7 +79,7 @@ public enum SoundEffect {
CREEPER_PRIMED("creeper.primed", "entity.creeper.primed", SoundCategory.HOSTILE),
DIG_SAND("dig.sand", "block.sand.break", SoundCategory.BLOCK),
MOB_CHICKEN_SAY("mob.chicken.say", "entity.chicken.ambient", SoundCategory.NEUTRAL),
RANDOM_DOOR_CLOSE("random.door_close", "null", SoundCategory.BLOCK),
RANDOM_DOOR_CLOSE("random.door_close", "block.wooden_door.close", SoundCategory.BLOCK),
MOB_GUARDIAN_ELDER_DEATH("mob.guardian.elder.death", "entity.elder_guardian.death", SoundCategory.HOSTILE),
FIREWORKS_TWINKLE("fireworks.twinkle", "entity.firework.twinkle", SoundCategory.AMBIENT),
MOB_HORSE_SKELETON_DEATH("mob.horse.skeleton.death", "entity.skeleton_horse.death", SoundCategory.NEUTRAL),
@@ -177,7 +177,7 @@ public enum SoundEffect {
GAME_TNT_PRIMED("game.tnt.primed", "entity.creeper.primed", SoundCategory.BLOCK),
MOB_SHEEP_STEP("mob.sheep.step", "entity.sheep.step", SoundCategory.NEUTRAL),
MOB_ZOMBIE_DEATH("mob.zombie.death", "entity.zombie.death", SoundCategory.HOSTILE),
RANDOM_DOOR_OPEN("random.door_open", "null", SoundCategory.BLOCK),
RANDOM_DOOR_OPEN("random.door_open", "block.wooden_door.open", SoundCategory.BLOCK),
MOB_ENDERMEN_PORTAL("mob.endermen.portal", "entity.endermen.teleport", SoundCategory.HOSTILE),
MOB_HORSE_ANGRY("mob.horse.angry", "entity.horse.angry", SoundCategory.NEUTRAL),
MOB_WOLF_GROWL("mob.wolf.growl", "entity.wolf.growl", SoundCategory.NEUTRAL),
@@ -242,7 +242,7 @@ public enum SoundEffect {
MOB_RABBIT_IDLE("mob.rabbit.idle", "entity.rabbit.ambient", SoundCategory.NEUTRAL),
MUSIC_GAME_END("music.game.end", "music.end", SoundCategory.MUSIC),
MUSIC_GAME("music.game", "music.game", SoundCategory.MUSIC),
MOB_GUARDIAN_IDLE("mob.guardian.idle", "null", SoundCategory.HOSTILE),
MOB_GUARDIAN_IDLE("mob.guardian.idle", "entity.elder_guardian.ambient", SoundCategory.HOSTILE),
RECORDS_WARD("records.ward", "record.ward", SoundCategory.RECORD),
RECORDS_13("records.13", "record.13", SoundCategory.RECORD),
MOB_RABBIT_HOP("mob.rabbit.hop", "entity.rabbit.jump", SoundCategory.NEUTRAL),
@@ -3,7 +3,10 @@ package us.myles.ViaVersion.protocols.protocol1_9to1_8.storage;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.WorldType;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.data.StoredObject;
import us.myles.ViaVersion.api.data.UserConnection;
@@ -26,8 +29,10 @@ public class ClientChunks extends StoredObject {
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");
if (ViaVersion.getInstance().isSpigot()) {
obfuscateRef = Class.forName("org.spigotmc.AntiXray").getMethod("obfuscate", int.class, int.class, int.class, byte[].class, ReflectionUtil.nms("World"));
worldRef = ReflectionUtil.nms("World");
}
} catch (Exception e) {
Bukkit.getLogger().log(Level.WARNING, "Failed to initialise chunks reflection", e);
}
@@ -19,6 +19,7 @@ import us.myles.ViaVersion.api.minecraft.Position;
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.api.type.types.version.Types1_9;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.chat.GameMode;
@@ -274,7 +275,7 @@ public class EntityTracker extends StoredObject {
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));
wrapper.write(Types1_9.METADATA_LIST, metadataBuffer.get(entityID));
MetadataRewriter.transform(getClientEntityTypes().get(entityID), metadataBuffer.get(entityID));
handleMetadata(entityID, metadataBuffer.get(entityID));
if (metadataBuffer.get(entityID).size() > 0) {
@@ -3,10 +3,13 @@ package us.myles.ViaVersion.protocols.protocol1_9to1_8.types;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.bukkit.Bukkit;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.minecraft.chunks.Chunk;
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.base.ProtocolInfo;
import us.myles.ViaVersion.protocols.protocol1_10to1_9_3.Protocol1_10To1_9_3_4;
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;
@@ -46,6 +49,9 @@ public class ChunkType extends PartialType<Chunk, ClientChunks> {
@Override
public Chunk read(ByteBuf input, ClientChunks param) throws Exception {
boolean replacePistons = param.getUser().get(ProtocolInfo.class).getPipeline().contains(Protocol1_10To1_9_3_4.class) && ViaVersion.getConfig().isReplacePistons();
int replacementId = ViaVersion.getConfig().getPistonReplacementId();
int chunkX = input.readInt();
int chunkZ = input.readInt();
long chunkHash = toLong(chunkX, chunkZ);
@@ -93,7 +99,8 @@ public class ChunkType extends PartialType<Chunk, ClientChunks> {
int mask = blockBuf.get();
int type = mask >> 4;
int data = mask & 0xF;
if (replacePistons && type == 36)
type = replacementId;
section.setBlock(j, type, data);
}
}
@@ -21,8 +21,9 @@ import java.util.UUID;
public class UpdateUtil {
public final static String PREFIX = ChatColor.GREEN + "" + ChatColor.BOLD + "[ViaVersion] " + ChatColor.GREEN;
private final static String URL = "http://api.spiget.org/v1/resources/";
private final static String URL = "http://api.spiget.org/v2/resources/";
private final static int PLUGIN = 19254;
private final static String LATEST_VERSION = "/versions/latest";
public static void sendUpdateMessage(final UUID uuid, final Plugin plugin) {
new BukkitRunnable() {
@@ -81,20 +82,24 @@ public class UpdateUtil {
try {
current = new Version(ViaVersion.getInstance().getVersion());
} catch (IllegalArgumentException e) {
return "You are using a debug/custom version, consider updating.";
return "You are using a custom version, consider updating.";
}
Version newest = new Version(newestString);
if (current.compareTo(newest) < 0)
return "There is a newer version available: " + newest.toString();
return "There is a newer version available: " + newest.toString() + ", you're on: " + current.toString();
else if (console && current.compareTo(newest) != 0) {
return "You are running a newer version than is released!";
if (current.getTag().toLowerCase().startsWith("dev") || current.getTag().toLowerCase().startsWith("snapshot")) {
return "You are running a development version, please report any bugs to GitHub.";
} else {
return "You are running a newer version than is released!";
}
}
return null;
}
private static String getNewestVersion() {
try {
URL url = new URL(URL + PLUGIN + "?" + System.currentTimeMillis());
URL url = new URL(URL + PLUGIN + LATEST_VERSION + "?" + System.currentTimeMillis());
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setUseCaches(true);
connection.addRequestProperty("User-Agent", "ViaVersion " + ViaVersion.getInstance().getVersion());
@@ -114,7 +119,7 @@ public class UpdateUtil {
e.printStackTrace();
return null;
}
return (String) statistics.get("version");
return (String) statistics.get("name");
} catch (MalformedURLException e) {
return null;
} catch (IOException e) {
@@ -2,21 +2,26 @@ package us.myles.ViaVersion.update;
import org.apache.commons.lang.StringUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Version implements Comparable<Version> {
private int[] parts;
private static Pattern semVer = Pattern.compile("(?<a>0|[1-9]\\d*)\\.(?<b>0|[1-9]\\d*)(?:\\.(?<c>0|[1-9]\\d*))?(?:-(?<tag>[A-z0-9.-]*))?");
private int[] parts = new int[3];
private String tag;
public Version(String value) {
if (value == null)
throw new IllegalArgumentException("Version can not be null");
if (!value.matches("^[0-9]+(\\.[0-9]+)*$"))
Matcher matcher = semVer.matcher(value);
if (!matcher.matches())
throw new IllegalArgumentException("Invalid version format");
parts[0] = Integer.parseInt(matcher.group("a"));
parts[1] = Integer.parseInt(matcher.group("b"));
parts[2] = matcher.group("c") == null ? 0 : Integer.parseInt(matcher.group("c"));
String[] split = value.split("\\.");
parts = new int[split.length];
for (int i = 0; i < split.length; i += 1)
parts[i] = Integer.parseInt(split[i]);
tag = matcher.group("tag") == null ? "" : matcher.group("tag");
}
public static int compare(Version verA, Version verB) {
@@ -33,6 +38,12 @@ public class Version implements Comparable<Version> {
if (partA > partB) return 1;
}
// Simple tag check
if (verA.tag.length() == 0 && verB.tag.length() > 0)
return 1;
if (verA.tag.length() > 0 && verB.tag.length() == 0)
return -1;
return 0;
}
@@ -47,7 +58,7 @@ public class Version implements Comparable<Version> {
for (int i = 0; i < parts.length; i += 1)
split[i] = String.valueOf(parts[i]);
return StringUtils.join(split, ".");
return StringUtils.join(split, ".") + (tag.length() != 0 ? "-" + tag : "");
}
@Override
@@ -59,4 +70,8 @@ public class Version implements Comparable<Version> {
public boolean equals(Object that) {
return that instanceof Version && equals(this, (Version) that);
}
public String getTag() {
return tag;
}
}
@@ -0,0 +1,268 @@
package us.myles.ViaVersion.util;
import lombok.SneakyThrows;
import java.lang.reflect.Field;
import java.util.*;
/**
* Created by wea_ondara licensed under MIT
* Same license as in LICENSE
*
* Taken from:
* https://github.com/weaondara/BungeePerms/blob/master/src/main/java/net/alpenblock/bungeeperms/util/ConcurrentList.java
* @param <E> List Type
*/
public class ConcurrentList<E> extends ArrayList<E> {
private final Object lock = new Object();
@Override
public boolean add(E e) {
synchronized (lock) {
return super.add(e);
}
}
@Override
public void add(int index, E element) {
synchronized (lock) {
super.add(index, element);
}
}
@Override
public boolean addAll(Collection<? extends E> c) {
synchronized (lock) {
return super.addAll(c);
}
}
@Override
public boolean addAll(int index, Collection<? extends E> c) {
synchronized (lock) {
return super.addAll(index, c);
}
}
@Override
public void clear() {
synchronized (lock) {
super.clear();
}
}
@Override
@SneakyThrows
public Object clone() {
synchronized (lock) {
ConcurrentList<E> clist = (ConcurrentList<E>) super.clone();
clist.modCount = 0;
Field f = ArrayList.class.getDeclaredField("elementData");
f.setAccessible(true);
f.set(clist, Arrays.copyOf((Object[]) f.get(this), this.size()));
return clist;
}
}
@Override
public boolean contains(Object o) {
synchronized (lock) {
return super.contains(o);
}
}
@Override
public void ensureCapacity(int minCapacity) {
synchronized (lock) {
super.ensureCapacity(minCapacity);
}
}
@Override
public E get(int index) {
synchronized (lock) {
return super.get(index);
}
}
@Override
public int indexOf(Object o) {
synchronized (lock) {
return super.indexOf(o);
}
}
@Override
public int lastIndexOf(Object o) {
synchronized (lock) {
return super.lastIndexOf(o);
}
}
@Override
public E remove(int index) {
synchronized (lock) {
return super.remove(index);
}
}
@Override
public boolean remove(Object o) {
synchronized (lock) {
return super.remove(o);
}
}
@Override
public boolean removeAll(Collection<?> c) {
synchronized (lock) {
return super.removeAll(c);
}
}
@Override
public boolean retainAll(Collection<?> c) {
synchronized (lock) {
return super.retainAll(c);
}
}
@Override
public E set(int index, E element) {
synchronized (lock) {
return super.set(index, element);
}
}
@Override
public List<E> subList(int fromIndex, int toIndex) {
synchronized (lock) {
return super.subList(fromIndex, toIndex);
}
}
@Override
public Object[] toArray() {
synchronized (lock) {
return super.toArray();
}
}
@Override
public <T> T[] toArray(T[] a) {
synchronized (lock) {
return super.toArray(a);
}
}
@Override
public void trimToSize() {
synchronized (lock) {
super.trimToSize();
}
}
@Override
public ListIterator<E> listIterator() {
return new ListItr(0);
}
@Override
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
protected int cursor;
protected int lastRet;
final ConcurrentList l;
public Itr() {
cursor = 0;
lastRet = -1;
l = (ConcurrentList) ConcurrentList.this.clone();
}
@Override
public boolean hasNext() {
return cursor < l.size();
}
@Override
public E next() {
int i = cursor;
if (i >= l.size()) {
throw new NoSuchElementException();
}
cursor = i + 1;
return (E) l.get(lastRet = i);
}
@Override
public void remove() {
if (lastRet < 0) {
throw new IllegalStateException();
}
l.remove(lastRet);
ConcurrentList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
}
}
public class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
super();
cursor = index;
}
@Override
public boolean hasPrevious() {
return cursor > 0;
}
@Override
public int nextIndex() {
return cursor;
}
@Override
public int previousIndex() {
return cursor - 1;
}
@Override
public E previous() {
int i = cursor - 1;
if (i < 0) {
throw new NoSuchElementException();
}
cursor = i;
return (E) l.get(lastRet = i);
}
@Override
public void set(E e) {
if (lastRet < 0) {
throw new IllegalStateException();
}
l.set(lastRet, e);
ConcurrentList.this.set(lastRet, e);
}
@Override
public void add(E e) {
int i = cursor;
l.add(i, e);
ConcurrentList.this.add(i, e);
cursor = i + 1;
lastRet = -1;
}
}
}
@@ -1,11 +1,9 @@
package us.myles.ViaVersion.util;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.*;
public abstract class ListWrapper implements List {
public final Object lock = new Object();
private final List list;
public ListWrapper(List inputList) {
@@ -20,123 +18,169 @@ public abstract class ListWrapper implements List {
@Override
public synchronized int size() {
return this.list.size();
synchronized (lock) {
return this.list.size();
}
}
@Override
public synchronized boolean isEmpty() {
return this.list.isEmpty();
synchronized (lock) {
return this.list.isEmpty();
}
}
@Override
public synchronized boolean contains(Object o) {
return this.list.contains(o);
synchronized (lock) {
return this.list.contains(o);
}
}
@Override
public synchronized Iterator iterator() {
return this.list.iterator();
synchronized (lock) {
return listIterator();
}
}
@Override
public synchronized Object[] toArray() {
return this.list.toArray();
synchronized (lock) {
return this.list.toArray();
}
}
@Override
public synchronized boolean add(Object o) {
handleAdd(o);
return this.list.add(o);
synchronized (lock) {
handleAdd(o);
return this.list.add(o);
}
}
@Override
public synchronized boolean remove(Object o) {
return this.list.remove(o);
synchronized (lock) {
return this.list.remove(o);
}
}
@Override
public synchronized boolean addAll(Collection c) {
for (Object o : c) {
handleAdd(o);
synchronized (lock) {
for (Object o : c) {
handleAdd(o);
}
return this.list.addAll(c);
}
return this.list.addAll(c);
}
@Override
public synchronized boolean addAll(int index, Collection c) {
for (Object o : c) {
handleAdd(o);
synchronized (lock) {
for (Object o : c) {
handleAdd(o);
}
return this.list.addAll(index, c);
}
return this.list.addAll(index, c);
}
@Override
public synchronized void clear() {
this.list.clear();
synchronized (lock) {
this.list.clear();
}
}
@Override
public synchronized Object get(int index) {
return this.list.get(index);
synchronized (lock) {
return this.list.get(index);
}
}
@Override
public synchronized Object set(int index, Object element) {
return this.list.set(index, element);
synchronized (lock) {
return this.list.set(index, element);
}
}
@Override
public synchronized void add(int index, Object element) {
this.list.add(index, element);
synchronized (lock) {
this.list.add(index, element);
}
}
@Override
public synchronized Object remove(int index) {
return this.list.remove(index);
synchronized (lock) {
return this.list.remove(index);
}
}
@Override
public synchronized int indexOf(Object o) {
return this.list.indexOf(o);
synchronized (lock) {
return this.list.indexOf(o);
}
}
@Override
public synchronized int lastIndexOf(Object o) {
return this.list.lastIndexOf(o);
synchronized (lock) {
return this.list.lastIndexOf(o);
}
}
@Override
public synchronized ListIterator listIterator() {
return this.list.listIterator();
synchronized (lock) {
return this.list.listIterator();
}
}
@Override
public synchronized ListIterator listIterator(int index) {
return this.list.listIterator(index);
synchronized (lock) {
return this.list.listIterator(index);
}
}
@Override
public synchronized List subList(int fromIndex, int toIndex) {
return this.list.subList(fromIndex, toIndex);
synchronized (lock) {
return this.list.subList(fromIndex, toIndex);
}
}
@Override
public synchronized boolean retainAll(Collection c) {
return this.list.retainAll(c);
synchronized (lock) {
return this.list.retainAll(c);
}
}
@Override
public synchronized boolean removeAll(Collection c) {
return this.list.removeAll(c);
synchronized (lock) {
return this.list.removeAll(c);
}
}
@Override
public synchronized boolean containsAll(Collection c) {
return this.list.containsAll(c);
synchronized (lock) {
return this.list.containsAll(c);
}
}
@Override
public synchronized Object[] toArray(Object[] a) {
return this.list.toArray(a);
synchronized (lock) {
return this.list.toArray(a);
}
}
}
+22 -6
View File
@@ -12,28 +12,38 @@
checkforupdates: true
# Send the supported versions with the Status (Ping) response packet
send-supported-versions: false
# Block specific Minecraft protocols that ViaVersion allows
# List of all Minecraft protocol versions: http://wiki.vg/Protocol_version_numbers
block-protocols: []
# Change the blocked disconnect message
block-disconnect-msg: "You are using an unsupported Minecraft version!"
# If you use ProtocolLib, we can't reload without kicking the players.
# (We don't suggest using reload either, use a plugin manager)
# You can customise the message we kick people with if you use ProtocolLib here.
reload-disconnect-msg: "Server reload, please rejoin!"
#
#----------------------------------------------------------#
# GLOBAL PACKET LIMITER #
#----------------------------------------------------------#
#
# Anti-Cheat, Packets Per Second (PPS) limiter
#
# Packets Per Second (PPS) limiter (Use -1 on max-pps and tracking-period to disable)
# Clients by default send around 20-90 packets per second.
#
# What is the maximum per second a client can send (Use %pps to display their pps)
# Use -1 to disable.
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.
#
# 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"
# This can never be higher than "tracking-period"
tracking-max-warnings: 4
tracking-max-kick-msg: "You are sending too many packets, :("
#
@@ -70,4 +80,10 @@ 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
anti-xray-patch: true
# Should we replace extended pistons to fix 1.10.1 (Only on chunk load)
replace-pistons: false
# What id should we replace with, default is air. (careful of players getting stuck standing on them)
replacement-piston-id: 0
# Force the string -> json transform
force-json-transform: false
+2 -2
View File
@@ -3,8 +3,8 @@ main: us.myles.ViaVersion.ViaVersionPlugin
author: _MylesC
version: ${project.version}
load: postworld
loadbefore: [ProtocolLib, ProxyPipe, SpigotLib, PacketListenerApi, SkinRestorer]
softdepend: [ProtocolSupport]
loadbefore: [ProtocolLib, ProxyPipe, SpigotLib, SkinRestorer]
softdepend: [ProtocolSupport, PacketListenerApi]
commands:
viaversion:
description: Shows ViaVersion Version and more.