Compare commits

...
129 Commits
Author SHA1 Message Date
Myles ea4650000e Bump to 0.5.5 2016-03-06 15:16:36 +00:00
Myles 2d2018b8d0 Disable latest feature due to it breaking signs (no more sync chunks for now) 2016-03-06 15:10:54 +00:00
HugoDaBosss 736a853a85 Merge pull request #153 from HugoDaBosss/patch
Make Metadata Rewriter exception output more clear
2016-03-06 16:00:50 +01:00
HugoDaBosss dfd4c5f93e Formatting 2016-03-06 15:55:53 +01:00
HugoDaBosss 2ac87acc8a Make Metadata Rewriter exception output more clear 2016-03-06 15:52:06 +01:00
Myles 3c5a6a3b7b Fix README, also change a bit of the fixJson so that it can handle quotes on signs. 2016-03-06 14:40:23 +00:00
Myles 6efb5c1b64 Merge pull request #151 from HugoDaBosss/patch
Fix checkforupdates changing from false to true
2016-03-06 14:20:45 +00:00
HugoDaBosss 91de7e5a22 Fix checkforupdates changing from false to true
FIXED:
When starting the server when checkforupdates is false, it won't register the listener.
So when you enable checkforupdates using /viaversion dontbugme it won't send you messages until a restart.
2016-03-06 15:11:36 +01:00
Myles 1c42ae1ee8 Update version to 0.5.4 2016-03-06 13:52:38 +00:00
Myles c5ac3c9b3d Don't freeze current thread when sending chunks 2016-03-06 13:49:33 +00:00
Myles 0ea32b3318 Merge pull request #150 from HugoDaBosss/patch
Fix mob spawners when no EntityId is given
2016-03-06 13:45:56 +00:00
Myles 8afc850ed3 Add new config option "sync-chunks", chunks will now be sent in sync with the MC thread when true, this fixes timings (paper spigot mostly issue) 2016-03-06 13:45:26 +00:00
HugoDaBosss 3c6dcfe5bf Update OutgoingTransformer.java 2016-03-06 14:42:50 +01:00
HugoDaBosss 59d637e0f5 More formatting (stupid eclipse) 2016-03-06 14:42:22 +01:00
HugoDaBosss 923f3088c0 Formatting 2016-03-06 14:40:52 +01:00
HugoDaBosss 4f8aff9c01 Forgot to remove debug message 2016-03-06 14:37:51 +01:00
HugoDaBosss 99ceb9ae79 Fix mob spawners when no EntityId is given 2016-03-06 14:32:57 +01:00
Myles 6e0554f4a4 Fix enchanting tooltips 2016-03-06 13:22:56 +00:00
Myles 36879f8d02 Fix small issue with updater 2016-03-06 13:02:54 +00:00
Myles fe77df1434 Fix brewing #141 2016-03-06 12:25:54 +00:00
Myles 713361f973 Merge pull request #148 from StamBoom/master
Fix commandblock minecarts
2016-03-06 11:20:50 +00:00
Mats a314b86f57 Fix commandblock minecarts 2016-03-06 12:18:18 +01:00
Myles 840c90f871 Don't use GSON >.> 2016-03-06 11:03:41 +00:00
Myles 2a247595c8 Handle invalid version numbers 2016-03-06 10:49:21 +00:00
Myles 4124c3454e Change it so when there is no connection we don't bug them. Also change it to use http instead of https, as https requires certain certificate info by linux. 2016-03-06 10:46:38 +00:00
HugoDaBosss c4185e3056 Merge pull request #147 from fillefilip8/patch-4
Made the config use the default bukkit config methods insteed.
2016-03-06 10:56:07 +01:00
fillefilip8 d6403d495d Opps :) Github likes me :D Removed the new api methods from this branch :D 2016-03-06 10:42:26 +01:00
fillefilip8 d7f54048ff Made the config use the default bukkit config methods insteed. 2016-03-06 10:39:58 +01:00
Myles e487eeb395 Update to 0.5.3, add inventory title tracking so we're working towards some of the inventory bugs with new ones. 2016-03-06 00:25:24 +00:00
Myles 0d0e1c16ea Fix issue with formatting :) (fixes quotes) 2016-03-05 23:24:23 +00:00
Myles f462ff9e8a Fix weird closedchannel bug 2016-03-05 22:16:43 +00:00
Myles 5582556d8a Fix issue with biomes on chunks, #125 2016-03-05 22:05:17 +00:00
Myles ef6214a442 Fix getHandItem across reloads, though half the things will still break on reload :( 2016-03-05 21:23:14 +00:00
Myles 369710333c Change updating so it doesn't tell you on current version up to date but warns if you're on a newer version than expected / older one in console. 2016-03-05 21:15:51 +00:00
Myles 30c4fea044 Add new /viaversion dontbugme, change method if the version looks like it's custom / debug (not compiled by maven) 2016-03-05 20:54:35 +00:00
Myles eccc5091b5 Merge pull request #139 from HugoDaBosss/master
Added proper update message (based on checkplys)
2016-03-05 20:40:48 +00:00
HugoDaBosss 65770d7c5b Added proper update message 2016-03-05 21:37:12 +01:00
Myles 715e873bae Bump version to 0.5.2 2016-03-05 20:21:21 +00:00
Myles eced599818 Merge pull request #138 from StamBoom/master
Fix commandblocks
2016-03-05 20:06:54 +00:00
Mats 6db7755633 Fix commandblocks 2016-03-05 20:36:06 +01:00
Myles 653c3d3984 Merge pull request #131 from StamBoom/patch
Fix book formatting and invalid book tag at empty book
2016-03-05 19:18:39 +00:00
HugoDaBosss 5ca841837d Added BungeeCord to the Issue Template 2016-03-05 20:04:16 +01:00
HugoDaBosss 554e037044 Merge pull request #133 from fillefilip8/patch-2
Fixed some maven warnings.
2016-03-05 19:48:26 +01:00
fillefilip8 457d7e4777 Fixed some maven warnings. 2016-03-05 14:37:01 +01:00
Mats b3dc465498 Remove debug message 2016-03-05 11:35:32 +01:00
Mats c56109a64c Fix book formatting and invalid book tag at empty book 2016-03-05 11:30:17 +01:00
Myles d5e720fe09 Merge pull request #130 from HugoDaBosss/patch-8
Fix spawners showing the correct mob
2016-03-05 00:28:24 +00:00
HugoDaBosss a42526bb88 Small formatting 2016-03-05 01:24:15 +01:00
HugoDaBosss bd5f44b477 Fixed spawners showing the correct mob 2016-03-05 01:21:37 +01:00
Myles d5d8881677 Add debug to show metadata ID on error 2016-03-04 23:30:37 +00:00
Myles ac2178a247 Add debug mode so we can analyse packets 2016-03-04 23:10:07 +00:00
Myles 24fa8aec35 Removed channel closed exception 2016-03-04 23:07:22 +00:00
Myles 2ba92a0d47 Merge pull request #126 from HugoDaBosss/herobrine
Removed Herobrine.
2016-03-04 23:03:45 +00:00
HugoDaBosss ace178834e Removed Herobrine. 2016-03-05 00:00:50 +01:00
HugoDaBosss 9c88d0a37f Merge pull request #10 from MylesIsCool/master
Update from master
2016-03-04 23:54:38 +01:00
Myles bafc1b6799 Merge pull request #122 from HugoDaBosss/patch-7
Fixed double flint and steel sound and added support to ignore sounds in 1.9
2016-03-04 22:29:39 +00:00
HugoDaBosss c9a575f45d Merge pull request #9 from MylesIsCool/master
Update Version I accidentally deployed debug version - 0.5.1
2016-03-04 23:23:44 +01:00
HugoDaBosss c071c895e7 Fixed double flint and steel sound and added support to ignore sounds in
1.9
2016-03-04 22:58:40 +01:00
Myles a8799bd493 Update Version I accidentally deployed debug version - 0.5.1 2016-03-04 21:51:56 +00:00
HugoDaBosss 20d4a94792 Merge pull request #8 from MylesIsCool/master
Update from master
2016-03-04 22:33:12 +01:00
Myles 89e0948f97 Updated version to 0.5.0 :) 2016-03-04 21:21:51 +00:00
Myles 6fe3c15f7d Remove 1.9 chunk unloading, should fix #38 2016-03-04 21:16:12 +00:00
Myles fb5dace6a6 Add armour, based on HugoDaBoss code but modified to work correctly with shift click. Also fix small issue from last commit. 2016-03-04 20:03:46 +00:00
Myles f71e51c85e Add packet sending to API 2016-03-04 19:24:44 +00:00
HugoDaBosss 0dd530a593 Merge pull request #7 from MylesIsCool/master
Update from master
2016-03-04 14:43:10 +01:00
Myles 12df86a142 As per wiki.vg only unload if bitmask = 0 and full chunk (not sure if this fixes chunk issue) 2016-03-04 10:09:06 +00:00
Myles 963f021226 Fix books, also makes ItemSlotRewriter.ItemStack fields public 2016-03-04 10:04:50 +00:00
Myles cb4a8b24d4 Merge pull request #113 from fillefilip8/patch-1
Some README.md fixes.
2016-03-04 09:10:05 +00:00
fillefilip8 76c908b132 Update README.md 2016-03-04 10:05:44 +01:00
Myles 89311af76a Small issue with README 2016-03-04 09:05:05 +00:00
fillefilip8 1ecf515006 Fixed README formatting. 2016-03-04 09:58:31 +01:00
Myles 5c18028577 Bump version to 0.4.9 2016-03-04 08:14:26 +00:00
Myles 678a7de664 Correct README 2016-03-04 01:02:35 +00:00
Myles 0aa190353e Add potions, including splash. 2016-03-04 01:01:04 +00:00
Myles a42b113618 Use new JSONParsers or they all implode. 2016-03-03 23:40:09 +00:00
Myles 2704611977 Cancel sounds properly, fixes block placing issue on bungee. Updated version to 0.4.8 2016-03-03 22:48:17 +00:00
Myles be6245e693 Bump version 0.4.7 2016-03-03 22:46:17 +00:00
Myles d7b7c4916a Read any remaining bytes, not sure if this fixes any errors but we ideally should to prevent issues. 2016-03-03 22:01:49 +00:00
Myles caae4e4cca Merge pull request #108 from gigosaurus/patch-2
Fix some MalformedJsonExceptions
2016-03-03 21:33:57 +00:00
gigosaurus ee58fbedbe Fix some MalformedJsonExceptions
This should fix the last possible cause of issue #70
2016-03-03 21:28:40 +00:00
Myles a84b45f5dd Add new contributor, make format of output match spigot 2016-03-03 21:15:20 +00:00
Myles c2edf45846 Change package for slot rewriter. 2016-03-03 21:06:36 +00:00
Myles 88ff4ee9ca Merge pull request #96 from Mystalion/spawnegg-and-potions
support for rewriting SpawnEggs
2016-03-03 21:03:50 +00:00
Paulomart fd704f6a29 Merge remote-tracking branch 'origin/spawnegg-and-potions'
Conflicts:
	src/main/java/us/myles/ViaVersion/transformers/OutgoingTransformer.java
	src/main/java/us/myles/ViaVersion/util/PacketUtil.java
2016-03-03 21:38:16 +01:00
Paulomart c97b443cf2 I dont even Java. 2016-03-03 21:32:01 +01:00
Paulomart 00df80e6fd Replace nms code with fancy library and own code. 2016-03-03 21:31:56 +01:00
Paulomart 64c2ba243f Basic support for rewriting SpawnEggs and Potions, still needs more work 2016-03-03 21:31:50 +01:00
Myles 0ad2e6478d Merge pull request #103 from StamBoom/master
Fix skin overlay
2016-03-03 19:56:55 +00:00
Myles ab9f786999 Don't send a signed byte for digging. 2016-03-03 19:56:00 +00:00
Mats e826b339f6 Fixed missing Player metadata 2016-03-03 20:49:29 +01:00
Mats f06851f57a Fix skin overlay 2016-03-03 20:37:46 +01:00
Myles 1a90f0eb28 Use new method for finding cause, might need updating with disconnect. Can't replicate disconnect spam on any version on my machine. Also move to JSON for all because older versions don't have GSON :( in main package 2016-03-03 19:24:37 +00:00
Myles fee986d215 Make the injectors work in any 1.8 version. Now looks through fields for suitable in case of different field names also construct slot using known arguments. 2016-03-03 18:12:10 +00:00
fillefilip8 9108e78491 Added more yml info and remove author name from the message in the command. 2016-03-03 18:30:13 +01:00
Myles 1b75526892 Implement changes to entity effect 2016-03-03 18:30:00 +01:00
fillefilip8 5930a83765 Added a command and a new API function "getVersion()" 2016-03-03 18:29:59 +01:00
fillefilip8 ef118a3a64 * One JavaDoc to the api XD
* Added faster way to change version number.
2016-03-03 17:33:47 +01:00
fillefilip8 bb42cda4a8 . 2016-03-03 17:33:28 +01:00
fillefilip8 121bc9de6c * Modifyed that fancy message when 1.9 clients try to enter a Minecart or a Boat :)
* Renamed the listener to something better.
2016-03-03 17:33:27 +01:00
fillefilip8 1e873c123c Added that fancy message when 1.9 clients try to enter a Minecart :) 2016-03-03 17:33:27 +01:00
Myles c704b3709a Implement changes to entity effect 2016-03-03 15:17:31 +00:00
HugoDaBosss 618e09b202 Merge pull request #6 from MylesIsCool/master
Update from master
2016-03-03 14:13:41 +01:00
Myles fd0bd53826 Bump version to 0.4.6 2016-03-03 13:07:57 +00:00
Myles e11c8320f0 Merge pull request #83 from StamBoom/master
Fix unmount
2016-03-03 12:56:54 +00:00
Myles 624595e9f6 Merge pull request #84 from HugoDaBosss/patch-4
Fix animals appearing as babies instead of parents
2016-03-03 12:56:37 +00:00
HugoDaBosss cc813545d8 Formatting 2016-03-03 12:22:54 +01:00
HugoDaBosss e1ba6e07c2 Fix animals appearing as babies instead of parent 2016-03-03 12:20:19 +01:00
Mats 1bf49b1f0b Fix unmount 2016-03-03 12:18:23 +01:00
HugoDaBosss 5e34fda7e4 Merge pull request #4 from MylesIsCool/master
Merge from master
2016-03-03 12:17:06 +01:00
Myles aa70ab8b78 Extra line 2016-03-03 10:37:43 +00:00
Myles 186ba22dc8 Update README with chat, and change issue template 2016-03-03 10:37:10 +00:00
Myles b10aa30d9b Change error correction to use super, should restore default functionality to errors. 2016-03-03 10:24:01 +00:00
Myles 615b9f847c Merge pull request #77 from HugoDaBosss/patch-2
Don't send malformed JSON anymore, preventing kicks.
2016-03-03 10:04:54 +00:00
Myles 8f132fed14 Merge pull request #64 from HugoDaBosss/master
Fixed double placing sound and small packet finding optimization. (I suck at github)
2016-03-03 10:04:33 +00:00
HugoDaBosss 854e24f8fc More formatting 2016-03-03 10:47:22 +01:00
HugoDaBosss ff0544f29a Eclipse is changing my bracket markup x.x 2016-03-03 10:46:38 +01:00
HugoDaBosss 72ae12bc77 Don't send malformed JSON anymore, preventing kicks. 2016-03-03 10:44:57 +01:00
HugoDaBosss 29d2334ef0 Fixed bracket markup ;) 2016-03-03 10:09:38 +01:00
HugoDaBosss afb96c4878 Fixed double break sound 2016-03-03 10:06:24 +01:00
HugoDaBosss e4346611c9 Small optimization 2016-03-03 01:40:24 +01:00
BuildTools f15e11272a Merge branch 'master' of https://github.com/HugoDaBosss/ViaVersion 2016-03-03 01:37:25 +01:00
HugoDaBosss 8764d24a16 Merge pull request #3 from MylesIsCool/master
Update from Fork
2016-03-03 01:37:25 +01:00
Myles 86d543d700 Add new contributor, update version to 0.4.5 :) 2016-03-03 00:13:53 +00:00
Myles 99fd01c359 Merge pull request #63 from gigosaurus/patch-1
Fix player entity meta data
2016-03-03 00:12:03 +00:00
gigosaurus 573dcc10b1 Fix player entity meta data
I'm not 100% confident that what I'm doing here is correct, but looking at http://wiki.vg/Pre-release_protocol#Spawn_Player I think I'm doing it right.

fixes #58
2016-03-03 00:06:13 +00:00
Myles 3e30d989a0 Print out stack traces instead of throwing them move. 2016-03-02 23:20:57 +00:00
Myles fc00dd2b38 Merge pull request #56 from gigosaurus/master
Fix PLAY_USE_BED's old ID
2016-03-02 23:08:57 +00:00
gigosaurus 2e9987373d Fix PLAY_USE_BED's old ID 2016-03-02 22:16:58 +00:00
HugoDaBosss b6c2a46a86 Merge pull request #2 from MylesIsCool/master
Update From Original #2
2016-03-02 11:44:24 +01:00
28 changed files with 2129 additions and 722 deletions

No files matched your search

+12
View File
@@ -0,0 +1,12 @@
### What version of ViaVersion are you using? Type /ver viaversion
### What version of Spigot are you using? Type /ver
### What plugins are you using? Type /plugins
### Are you using any additional software like BungeeCord? If so, what software and version? (Please list your plugins as well)
### How does this error happen? login? Using an item?
### Is there an error in the console? Use pastebin.com. Is there a kick message?
+18 -12
View File
@@ -1,17 +1,9 @@
# ViaVersion 0.4.4
**Allows the connection of 1.8 clients to 1.9**
# ViaVersion 0.5.5
**Allows the connection of 1.9 clients to 1.8**
This plugin modifies netty to allow connection of 1.9 clients to 1.8,
**Don't use late bind*
**As of this point it doesn't have everything, I need to fix:**
Attempt to make boats nicer when they don't work
Remap spawn eggs
If you have a bug with entities, please report the full stack trace
###*Don't use late bind*
This took hours of work, so if you enjoy this consider looking into contacting me and supporting my projects.
@@ -24,6 +16,10 @@ Sources:
**MCProtocolLib** (used for chunk reading & some of writing.)
**OpenNBT** (used for slot rewriting)
Contributors:
--------
@@ -37,10 +33,20 @@ Contributors:
**Paulomart**
**gigosaurus**
**fillefilip8**
**Chat: ** https://gitter.im/MylesIsCool/ViaVersion
We use it to collaborate and solve errors, sign in with github.
License:
--------
You may modify this work, all rights are still owned by myself excluding any files in the spacebase package as they belong to the respected contributors. Please credit the original author (myself) when forking etc. (or if it helped you understand the new protocol or netty!)
Thanks!
Thanks!
+37 -5
View File
@@ -1,16 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>us.myles</groupId>
<artifactId>ViaVersion</artifactId>
<version>1.0-SNAPSHOT</version>
<version>0.5.5</version>
<build>
<finalName>ViaVersion-${project.version}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.4</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<version>3.5.1</version>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
@@ -18,8 +35,19 @@
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
<dependencies>
<dependency>
<groupId>org.spacehq</groupId>
<artifactId>opennbt</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
@@ -50,5 +78,9 @@
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
</repositories>
<repository>
<id>spacehq-repo</id>
<url>https://repo.spacehq.org/content/repositories/releases/</url>
</repository>
</repositories>
</project>
@@ -30,7 +30,7 @@ public class NetUtil {
}
}
if(fullChunk) {
if(fullChunk && column.getBiomeData() != null) {
out.writeBytes(column.getBiomeData());
}
@@ -103,7 +103,8 @@ public class NetUtil {
}
byte biomeData[] = null;
if(isFullChunk) {
if(isFullChunk && (pos + 256 <= input.length)) {
biomeData = new byte[256];
System.arraycopy(input, pos, biomeData, 0, biomeData.length);
}
@@ -1,4 +1,4 @@
package us.myles.ViaVersion;
public class CancelException extends Exception{
public class CancelException extends Exception {
}
@@ -1,5 +1,7 @@
package us.myles.ViaVersion;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.socket.SocketChannel;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
@@ -12,6 +14,7 @@ public class ConnectionInfo {
private Object lastPacket;
private java.util.UUID UUID;
private State state = State.HANDSHAKE;
private String openWindow;
private int protocol = 0;
private int compression = 0;
private boolean active = true;
@@ -75,4 +78,26 @@ public class ConnectionInfo {
public void setActive(boolean active) {
this.active = active;
}
public void sendRawPacket(final ByteBuf packet) {
final ChannelHandler handler = channel.pipeline().get("encoder");
channel.eventLoop().submit(new Runnable() {
@Override
public void run() {
channel.pipeline().context(handler).writeAndFlush(packet);
}
});
}
public String getOpenWindow() {
return openWindow;
}
public void setOpenWindow(String openWindow) {
this.openWindow = openWindow;
}
public void closeWindow() {
this.openWindow = null;
}
}
@@ -1,5 +1,6 @@
package us.myles.ViaVersion;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
@@ -12,33 +13,41 @@ import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.java.JavaPlugin;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.ViaVersionAPI;
import us.myles.ViaVersion.armor.ArmorListener;
import us.myles.ViaVersion.commands.ViaVersionCommand;
import us.myles.ViaVersion.handlers.ViaVersionInitializer;
import us.myles.ViaVersion.listeners.CommandBlockListener;
import us.myles.ViaVersion.update.UpdateListener;
import us.myles.ViaVersion.update.UpdateUtil;
import us.myles.ViaVersion.util.ReflectionUtil;
import java.util.Collections;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Set;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
private final Set<UUID> portedPlayers = Collections.newSetFromMap(new ConcurrentHashMap<UUID, Boolean>());
private final Map<UUID, ConnectionInfo> portedPlayers = new ConcurrentHashMap<UUID, ConnectionInfo>();
private boolean debug = false;
@Override
public void onEnable() {
ViaVersion.setInstance(this);
if(System.getProperty("ViaVersion") != null){
saveDefaultConfig();
if (System.getProperty("ViaVersion") != null) {
getLogger().severe("ViaVersion is already loaded, we don't support reloads. Please reboot if you wish to update.");
getLogger().severe("Some features may not work.");
return;
}
getLogger().info("ViaVersion enabled, injecting. (Allows 1.8 to be accessed via 1.9)");
getLogger().info("ViaVersion " + getDescription().getVersion() + " is now enabled, injecting. (Allows 1.8 to be accessed via 1.9)");
try {
injectPacketHandler();
System.setProperty("ViaVersion", getDescription().getVersion());
@@ -46,49 +55,94 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
getLogger().severe("Unable to inject handlers, are you on 1.8? ");
e.printStackTrace();
}
if (getConfig().getBoolean("checkforupdates"))
UpdateUtil.sendUpdateMessage(this);
Bukkit.getPluginManager().registerEvents(new Listener() {
@EventHandler
public void onPlayerQuit(PlayerQuitEvent e) {
setPorted(e.getPlayer().getUniqueId(), false);
removePortedClient(e.getPlayer().getUniqueId());
}
}, this);
Bukkit.getPluginManager().registerEvents(new ArmorListener(this), this);
Bukkit.getPluginManager().registerEvents(new CommandBlockListener(this), this);
Bukkit.getPluginManager().registerEvents(new UpdateListener(this), this);
getCommand("viaversion").setExecutor(new ViaVersionCommand(this));
}
public void injectPacketHandler() throws Exception {
Class<?> serverClazz = ReflectionUtil.nms("MinecraftServer");
Object server = ReflectionUtil.invokeStatic(serverClazz, "getServer");
Object connection = serverClazz.getDeclaredMethod("getServerConnection").invoke(server);
List<ChannelFuture> futures = ReflectionUtil.get(connection, "g", List.class);
if (futures.size() == 0) {
throw new Exception("Could not find server to inject (Please ensure late-bind in your spigot.yml is false)");
// loop through all fields checking if list
boolean injected = false;
for (Field field : connection.getClass().getDeclaredFields()) {
field.setAccessible(true);
Object value = field.get(connection);
if (value instanceof List) {
for (Object o : (List) value) {
if (o instanceof ChannelFuture) {
ChannelFuture future = (ChannelFuture) o;
ChannelPipeline pipeline = future.channel().pipeline();
ChannelHandler bootstrapAcceptor = pipeline.first();
ChannelInitializer<SocketChannel> oldInit = ReflectionUtil.get(bootstrapAcceptor, "childHandler", ChannelInitializer.class);
ChannelInitializer newInit = new ViaVersionInitializer(oldInit);
ReflectionUtil.set(bootstrapAcceptor, "childHandler", newInit);
injected = true;
} else {
break; // not the right list.
}
}
}
}
for (ChannelFuture future : futures) {
ChannelPipeline pipeline = future.channel().pipeline();
ChannelHandler bootstrapAcceptor = pipeline.first();
ChannelInitializer<SocketChannel> oldInit = ReflectionUtil.get(bootstrapAcceptor, "childHandler", ChannelInitializer.class);
ChannelInitializer newInit = new ViaVersionInitializer(oldInit);
ReflectionUtil.set(bootstrapAcceptor, "childHandler", newInit);
if (!injected) {
throw new Exception("Could not find server to inject (Please ensure late-bind in your spigot.yml is false)");
}
}
@Override
public boolean isPorted(Player player) {
return portedPlayers.contains(player.getUniqueId());
return portedPlayers.containsKey(player.getUniqueId());
}
public void setPorted(UUID id, boolean value) {
if (value) {
portedPlayers.add(id);
} else {
portedPlayers.remove(id);
}
@Override
public String getVersion() {
return getDescription().getVersion();
}
public void sendRawPacket(Player player, ByteBuf packet) throws IllegalArgumentException {
if (!isPorted(player)) throw new IllegalArgumentException("This player is not on 1.9");
ConnectionInfo ci = portedPlayers.get(player.getUniqueId());
ci.sendRawPacket(packet);
}
@Override
public boolean isDebug() {
return this.debug;
}
@Override
public boolean isSyncedChunks() {
return getConfig().getBoolean("sync-chunks", true);
}
public void setDebug(boolean value) {
this.debug = value;
}
public void addPortedClient(ConnectionInfo info) {
portedPlayers.put(info.getUUID(), info);
}
public void removePortedClient(UUID clientID) {
portedPlayers.remove(clientID);
}
public static ItemStack getHandItem(final ConnectionInfo info) {
try {
return Bukkit.getScheduler().callSyncMethod(getPlugin(ViaVersionPlugin.class), new Callable<ItemStack>() {
return Bukkit.getScheduler().callSyncMethod(Bukkit.getPluginManager().getPlugin("ViaVersion"), new Callable<ItemStack>() {
@Override
public ItemStack call() throws Exception {
if (info.getPlayer() != null) {
@@ -103,4 +157,22 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
return null;
}
}
public void run(final Runnable runnable, boolean wait) {
try {
Future f = Bukkit.getScheduler().callSyncMethod(Bukkit.getPluginManager().getPlugin("ViaVersion"), new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
runnable.run();
return true;
}
});
if(wait){
f.get(10, TimeUnit.SECONDS);
}
} catch (Exception e) {
System.out.println("Failed to run task.");
e.printStackTrace();
}
}
}
@@ -1,8 +1,39 @@
package us.myles.ViaVersion.api;
import io.netty.buffer.ByteBuf;
import org.bukkit.entity.Player;
public interface ViaVersionAPI {
/**
* Is player using 1.9?
* @param player
* @return True if the client is on 1.9
*/
boolean isPorted(Player player);
/**
* Get the version of the plugin
* @return Plugin version
*/
String getVersion();
/**
* Send a raw packet to the player (Use new IDs)
* @param player The player to send packet
* @param packet The packet, you need a VarInt ID then the packet contents.
* @throws IllegalArgumentException If not on 1.9 throws IllegalArg
*/
void sendRawPacket(Player player, ByteBuf packet) throws IllegalArgumentException;
/**
* Obtain if global debug is enabled
* @return true if debug is enabled
*/
boolean isDebug();
/**
* Obtains if syncing chunks is on
* @return true if it is
*/
boolean isSyncedChunks();
}
@@ -0,0 +1,106 @@
package us.myles.ViaVersion.armor;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
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.PlayerInteractEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.inventory.CraftingInventory;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.packets.PacketType;
import java.util.UUID;
import static us.myles.ViaVersion.util.PacketUtil.*;
public class ArmorListener implements Listener {
private final ViaVersionPlugin plugin;
private static UUID armorAttribute = UUID.fromString("2AD3F246-FEE1-4E67-B886-69FD380BB150");
public ArmorListener(ViaVersionPlugin plugin) {
this.plugin = plugin;
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onInventoryClick(InventoryClickEvent e) {
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) {
sendDelayedArmorUpdate(player);
return;
}
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onInteract(PlayerInteractEvent e) {
if (e.getItem() != null) {
if (e.getAction() == Action.RIGHT_CLICK_AIR || e.getAction() == Action.RIGHT_CLICK_BLOCK) {
if (ArmorType.isArmor(e.getMaterial())) {
final Player player = e.getPlayer();
// Due to odd bugs it's 3 ticks later
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
@Override
public void run() {
if (ViaVersion.getInstance().isPorted(player)) {
sendArmorUpdate(player);
}
}
}, 3L);
}
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onJoin(PlayerJoinEvent e) {
sendDelayedArmorUpdate(e.getPlayer());
}
public void sendDelayedArmorUpdate(final Player player) {
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
@Override
public void run() {
if (ViaVersion.getInstance().isPorted(player)) {
sendArmorUpdate(player);
}
}
});
}
public static void sendArmorUpdate(Player player) {
int armor = ArmorType.calculateArmorPoints(player.getInventory().getArmorContents());
ByteBuf buf = Unpooled.buffer();
writeVarInt(PacketType.PLAY_ENTITY_PROPERTIES.getNewPacketID(), buf);
writeVarInt(player.getEntityId(), buf);
buf.writeInt(1); // only 1 property
writeString("generic.armor", buf);
buf.writeDouble(0); //default 0 armor
writeVarInt(1, buf); // 1 modifier
writeUUID(armorAttribute, buf); // armor modifier uuid
buf.writeDouble((double) armor); // the modifier value
buf.writeByte(0); // the modifier operation, 0 is add number
ViaVersion.getInstance().sendRawPacket(player, buf);
}
}
@@ -0,0 +1,91 @@
package us.myles.ViaVersion.armor;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
public enum ArmorType {
LEATHER_HELMET(1, 298, Material.LEATHER_HELMET),
LEATHER_CHESTPLATE(3, 299, Material.LEATHER_CHESTPLATE),
LEATHER_LEGGINGS(2, 300, Material.LEATHER_LEGGINGS),
LEATHER_BOOTS(1, 301, Material.LEATHER_BOOTS),
CHAINMAIL_HELMET(2, 302, Material.CHAINMAIL_HELMET),
CHAINMAIL_CHESTPLATE(5, 303, Material.CHAINMAIL_CHESTPLATE),
CHAINMAIL_LEGGINGS(4, 304, Material.CHAINMAIL_LEGGINGS),
CHAINMAIL_BOOTS(1, 305, Material.CHAINMAIL_BOOTS),
IRON_HELMET(2, 306, Material.IRON_HELMET),
IRON_CHESTPLATE(6, 307, Material.IRON_CHESTPLATE),
IRON_LEGGINGS(5, 308, Material.IRON_LEGGINGS),
IRON_BOOTS(2, 309, Material.IRON_BOOTS),
DIAMOND_HELMET(3, 310, Material.DIAMOND_HELMET),
DIAMOND_CHESTPLATE(8, 311, Material.DIAMOND_CHESTPLATE),
DIAMOND_LEGGINGS(6, 312, Material.DIAMOND_LEGGINGS),
DIAMOND_BOOTS(3, 313, Material.DIAMOND_BOOTS),
GOLD_HELMET(2, 314, Material.GOLD_HELMET),
GOLD_CHESTPLATE(5, 315, Material.GOLD_CHESTPLATE),
GOLD_LEGGINGS(3, 316, Material.GOLD_LEGGINGS),
GOLD_BOOTS(1, 317, Material.GOLD_BOOTS),
NONE(0, 0, Material.AIR);
private int armorpoints;
private int id;
private Material type;
ArmorType(int armor, int id, Material type) {
this.armorpoints = armor;
this.id = id;
this.type = type;
}
public int getArmorPoints() {
return this.armorpoints;
}
public int getId() {
return this.id;
}
public Material getType() {
return this.type;
}
public static ArmorType findByType(Material type) {
for(ArmorType a : ArmorType.values())
if(a.getType() == type)
return a;
return ArmorType.NONE;
}
public static int calculateArmorPoints(ItemStack[] armor) {
int total = 0;
for(int i = 0; i < armor.length; i++) {
if(armor[i] != null)
total += findByType(armor[i].getType()).getArmorPoints();
}
return total;
}
public static ArmorType findById(int id) {
for(ArmorType a : ArmorType.values())
if(a.getId() == id)
return a;
return ArmorType.NONE;
}
public static boolean isArmor(Material material){
for(ArmorType a : ArmorType.values())
if(a.getType() == material)
return true;
return false;
}
public static int calculateArmorPoints(int[] armor) {
int total = 0;
for(int i = 0; i < armor.length; i++) {
if(armor[i] != -1)
total += findById(armor[i]).getArmorPoints();
}
return total;
}
}
@@ -0,0 +1,66 @@
package us.myles.ViaVersion.commands;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaVersion;
import java.util.ArrayList;
import java.util.List;
/**
* Created by fillefilip8 on 2016-03-03.
*/
public class ViaVersionCommand implements CommandExecutor {
private final ViaVersionPlugin plugin;
public ViaVersionCommand(ViaVersionPlugin plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (sender.hasPermission("viaversion.admin")) {
if (args.length == 0) {
sender.sendMessage(color("&aViaVersion &c" + ViaVersion.getInstance().getVersion()));
sender.sendMessage(color("&6Commands:"));
sender.sendMessage(color("&2/viaversion list &7- &6Shows lists of all 1.9 clients and 1.8 clients."));
sender.sendMessage(color("&2/viaversion dontbugme &7- &6Toggle checking for updates."));
} else if (args.length == 1) {
if (args[0].equalsIgnoreCase("list")) {
List<String> portedPlayers = new ArrayList<String>();
List<String> normalPlayers = new ArrayList<String>();
for (Player p : Bukkit.getOnlinePlayers()) {
if (ViaVersion.getInstance().isPorted(p)) {
portedPlayers.add(p.getName());
} else {
normalPlayers.add(p.getName());
}
}
sender.sendMessage(color("&8[&61.9&8]: &b" + portedPlayers.toString()));
sender.sendMessage(color("&8[&61.8&8]: &b" + normalPlayers.toString()));
}
if (args[0].equalsIgnoreCase("debug")) {
plugin.setDebug(!plugin.isDebug());
sender.sendMessage(color("&6Debug mode is now " + (plugin.isDebug() ? "&aenabled" : "&cdisabled")));
}
if (args[0].equalsIgnoreCase("dontbugme")) {
boolean newValue = !plugin.getConfig().getBoolean("checkforupdates", true);
plugin.getConfig().set("checkforupdates", newValue);
plugin.saveConfig();
sender.sendMessage(color("&6We will " + (newValue ? "&anotify you about updates." : "&cnot tell you about updates.")));
}
}
}
return false;
}
public String color(String string) {
return string.replace("&", "§");
}
}
@@ -8,7 +8,6 @@ import us.myles.ViaVersion.ConnectionInfo;
import us.myles.ViaVersion.transformers.IncomingTransformer;
import us.myles.ViaVersion.util.PacketUtil;
import java.nio.channels.ClosedChannelException;
import java.util.List;
public class ViaDecodeHandler extends ByteToMessageDecoder {
@@ -32,6 +31,7 @@ public class ViaDecodeHandler extends ByteToMessageDecoder {
ByteBuf newPacket = ctx.alloc().buffer();
try {
incomingTransformer.transform(id, bytebuf, newPacket);
bytebuf.readBytes(bytebuf.readableBytes());
bytebuf = newPacket;
} catch (CancelException e) {
bytebuf.readBytes(bytebuf.readableBytes());
@@ -45,17 +45,7 @@ public class ViaDecodeHandler extends ByteToMessageDecoder {
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (!(cause.getCause().getCause() instanceof CancelException)
&& !(cause.getCause().getCause() instanceof ClosedChannelException)) {
if (!(cause.getCause() instanceof CancelException)
&& !(cause.getCause() instanceof ClosedChannelException)) {
if (!(cause instanceof CancelException)
&& !(cause instanceof ClosedChannelException)) {
if (cause instanceof Exception)
throw (Exception) cause;
}
}
}
if (PacketUtil.containsCause(cause, CancelException.class)) return;
super.exceptionCaught(ctx, cause);
}
}
@@ -5,12 +5,14 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import us.myles.ViaVersion.CancelException;
import us.myles.ViaVersion.ConnectionInfo;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.transformers.OutgoingTransformer;
import us.myles.ViaVersion.util.PacketUtil;
import us.myles.ViaVersion.util.ReflectionUtil;
import java.lang.reflect.Constructor;
import java.nio.channels.ClosedChannelException;
import java.lang.reflect.InvocationTargetException;
public class ViaEncodeHandler extends MessageToByteEncoder {
private final ConnectionInfo info;
@@ -25,26 +27,51 @@ public class ViaEncodeHandler extends MessageToByteEncoder {
@Override
protected void encode(ChannelHandlerContext ctx, Object o, ByteBuf bytebuf) throws Exception {
protected void encode(final ChannelHandlerContext ctx, Object o, final ByteBuf bytebuf) throws Exception {
// handle the packet type
if (!(o instanceof ByteBuf)) {
info.setLastPacket(o);
/* This transformer is more for fixing issues which we find hard at packet level :) */
if (o.getClass().getName().endsWith("PacketPlayOutMapChunkBulk") && info.isActive()) {
int[] locX = ReflectionUtil.get(o, "a", int[].class);
int[] locZ = ReflectionUtil.get(o, "b", int[].class);
final int[] locX = ReflectionUtil.get(o, "a", int[].class);
final int[] locZ = ReflectionUtil.get(o, "b", int[].class);
Object world = ReflectionUtil.get(o, "world", ReflectionUtil.nms("World"));
final Object world = ReflectionUtil.get(o, "world", ReflectionUtil.nms("World"));
Class<?> mapChunk = ReflectionUtil.nms("PacketPlayOutMapChunk");
Constructor constructor = mapChunk.getDeclaredConstructor(ReflectionUtil.nms("Chunk"), boolean.class, int.class);
for (int i = 0; i < locX.length; i++) {
int x = locX[i];
int z = locZ[i];
// world invoke function
Object chunk = ReflectionUtil.nms("World").getDeclaredMethod("getChunkAt", int.class, int.class).invoke(world, x, z);
Object packet = constructor.newInstance(chunk, true, 65535);
ctx.pipeline().writeAndFlush(packet);
}
final Constructor constructor = mapChunk.getDeclaredConstructor(ReflectionUtil.nms("Chunk"), boolean.class, int.class);
Runnable chunks = new Runnable() {
@Override
public void run() {
for (int i = 0; i < locX.length; i++) {
int x = locX[i];
int z = locZ[i];
// world invoke function
try {
Object chunk = ReflectionUtil.nms("World").getDeclaredMethod("getChunkAt", int.class, int.class).invoke(world, x, z);
Object packet = constructor.newInstance(chunk, true, 65535);
ctx.pipeline().writeAndFlush(packet);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
};
// Synced allows timings to work properly.
// if (ViaVersion.getInstance().isSyncedChunks()) {
// ((ViaVersionPlugin) ViaVersion.getInstance()).run(chunks, false);
// } else {
chunks.run();
// }
bytebuf.readBytes(bytebuf.readableBytes());
throw new CancelException();
}
@@ -72,16 +99,7 @@ public class ViaEncodeHandler extends MessageToByteEncoder {
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (!(cause.getCause().getCause() instanceof CancelException)
&& !(cause.getCause().getCause() instanceof ClosedChannelException)) {
if (!(cause.getCause() instanceof CancelException)
&& !(cause.getCause() instanceof ClosedChannelException)) {
if (!(cause instanceof CancelException)
&& !(cause instanceof ClosedChannelException)) {
if (cause instanceof Exception)
throw (Exception) cause;
}
}
}
if (PacketUtil.containsCause(cause, CancelException.class)) return;
super.exceptionCaught(ctx, cause);
}
}
@@ -0,0 +1,63 @@
package us.myles.ViaVersion.listeners;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
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.PlayerInteractEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.packets.PacketType;
import us.myles.ViaVersion.util.PacketUtil;
import us.myles.ViaVersion.util.ReflectionUtil;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class CommandBlockListener implements Listener {
private final ViaVersionPlugin plugin;
public CommandBlockListener(ViaVersionPlugin plugin) {
this.plugin = plugin;
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onJoin(final PlayerJoinEvent e) {
if (e.getPlayer().isOp() && plugin.isPorted(e.getPlayer())) {
ByteBuf buf = Unpooled.buffer();
PacketUtil.writeVarInt(PacketType.PLAY_ENTITY_STATUS.getNewPacketID(), buf);
buf.writeInt(e.getPlayer().getEntityId());
buf.writeByte(26);
plugin.sendRawPacket(e.getPlayer(), buf);
}
}
@EventHandler(ignoreCancelled = true)
public void onInteract(PlayerInteractEvent e) {
if (e.getAction() == Action.RIGHT_CLICK_BLOCK && plugin.isPorted(e.getPlayer()) && e.getPlayer().isOp()) {
try {
sendCommandBlockPacket(e.getClickedBlock(), e.getPlayer());
} catch (NoSuchFieldException | IllegalAccessException | InvocationTargetException | NoSuchMethodException | ClassNotFoundException e1) {
e1.printStackTrace();
}
}
}
private void sendCommandBlockPacket(Block b, Player player) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, ClassNotFoundException {
if (!(b.getState() instanceof CommandBlock))
return;
CommandBlock cmd = (CommandBlock) b.getState();
Object tileEntityCommand = ReflectionUtil.get(cmd, "commandBlock", ReflectionUtil.nms("TileEntityCommand"));
Object updatePacket = ReflectionUtil.invoke(tileEntityCommand, "getUpdatePacket");
Object nmsPlayer = ReflectionUtil.invoke(player, "getHandle");
Object playerConnection = ReflectionUtil.get(nmsPlayer, "playerConnection", ReflectionUtil.nms("PlayerConnection"));
Method sendPacket = playerConnection.getClass().getMethod("sendPacket", ReflectionUtil.nms("Packet"));
sendPacket.invoke(playerConnection, updatePacket); //Let the transformer do the work
}
}
@@ -27,10 +27,10 @@ public enum MetaIndex {
STAND_LL_POS(ArmorStand.class, 15, Type.Rotation, NewType.Vector3F),
STAND_RL_POS(ArmorStand.class, 16, Type.Rotation, NewType.Vector3F),
// human, discountined?
PLAYER_SKIN_FLAGS(HumanEntity.class, 10, Type.Byte, NewType.Discontinued), // unsigned on 1.8
PLAYER_SKIN_FLAGS(HumanEntity.class, 10, Type.Byte, 12, NewType.Byte), // unsigned on 1.8
PLAYER_HUMAN_BYTE(HumanEntity.class, 16, Type.Byte, NewType.Discontinued), // unused on 1.8
PLAYER_ADDITIONAL_HEARTS(HumanEntity.class, 17, Type.Float, NewType.Discontinued),
PLAYER_SCORE(HumanEntity.class, 18, Type.Int, NewType.Discontinued),
PLAYER_ADDITIONAL_HEARTS(HumanEntity.class, 17, Type.Float, 10, NewType.Float),
PLAYER_SCORE(HumanEntity.class, 18, Type.Int, 11, NewType.VarInt),
// horse
HORSE_INFO(Horse.class, 16, Type.Int, 12, NewType.Byte),
HORSE_TYPE(Horse.class, 19, Type.Byte, 13, NewType.VarInt),
@@ -105,6 +105,9 @@ public enum MetaIndex {
MINECART_BLOCK(Minecart.class, 20, Type.Int, 8, NewType.VarInt),
MINECART_BLOCK_Y(Minecart.class, 21, Type.Int, 9, NewType.VarInt),
MINECART_SHOWBLOCK(Minecart.class, 22, Type.Byte, 10, NewType.Boolean),
// Command minecart (they are still broken)
MINECART_COMMANDBLOCK_COMMAND(Minecart.class, 23, Type.String, 11, NewType.String),
MINECART_COMMANDBLOCK_OUTPUT(Minecart.class, 24, Type.String, 12, NewType.Chat),
// furnace cart
FURNACECART_ISPOWERED(org.bukkit.entity.minecart.PoweredMinecart.class, 16, Type.Byte, 11, NewType.Boolean),
// item drop
@@ -163,14 +166,14 @@ public enum MetaIndex {
public static MetaIndex getIndex(EntityType type, int index) {
Class<? extends org.bukkit.entity.Entity> entityClass = type.getEntityClass();
if(entityClass == null){
if (entityClass == null) {
System.out.println("Could not get entity class for " + type);
return null;
}
for (MetaIndex mi : MetaIndex.values()) {
if (mi.getIndex() == index) {
// To fix issue with armour stands colliding with new values
if(mi.getApplicableClass().equals(LivingEntity.class)) continue;
if (mi.getApplicableClass().equals(LivingEntity.class)) continue;
if ((mi.getApplicableClass().isAssignableFrom(entityClass) ||
mi.getApplicableClass().equals(entityClass))) {
@@ -1,18 +1,19 @@
package us.myles.ViaVersion.metadata;
import io.netty.buffer.ByteBuf;
import org.bukkit.entity.EntityType;
import org.bukkit.util.EulerAngle;
import org.bukkit.util.Vector;
import us.myles.ViaVersion.slot.ItemSlotRewriter;
import us.myles.ViaVersion.slot.ItemSlotRewriter.ItemStack;
import us.myles.ViaVersion.transformers.OutgoingTransformer;
import us.myles.ViaVersion.util.PacketUtil;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import org.bukkit.entity.EntityType;
import org.bukkit.util.EulerAngle;
import org.bukkit.util.Vector;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.util.PacketUtil;
public class MetadataRewriter {
public static void writeMetadata1_9(EntityType type, List<Entry> list, ByteBuf output) {
@@ -86,10 +87,15 @@ public class MetadataRewriter {
PacketUtil.writeString((String) value, output);
break;
case Boolean:
output.writeBoolean(((Byte) value).byteValue() != 0);
if (metaIndex == MetaIndex.AGEABLE_AGE)
output.writeBoolean(((Byte) value).byteValue() < 0);
else
output.writeBoolean(((Byte) value).byteValue() != 0);
break;
case Slot:
PacketUtil.writeItem(value, output);
ItemStack item = (ItemStack) value;
ItemSlotRewriter.fixIdsFrom1_8To1_9(item);
ItemSlotRewriter.writeItemStack(item, output);
break;
case Position:
Vector vector = (Vector) value;
@@ -103,18 +109,23 @@ public class MetadataRewriter {
output.writeFloat((float) angle.getY());
output.writeFloat((float) angle.getZ());
break;
case Chat:
PacketUtil.writeString(OutgoingTransformer.fixJson((String) value), output);
break;
default:
System.out.println("[Out] Unhandled MetaDataType: " + metaIndex.getNewType());
break;
}
}
} catch (Exception e) {
if (type != null) {
System.out.println("An error occurred with entity meta data for " + type);
if (metaIndex != null) {
System.out.println("Old ID: " + metaIndex.getIndex() + " New ID: " + metaIndex.getNewIndex());
System.out.println("Old Type: " + metaIndex.getOldType() + " New Type: " + metaIndex.getNewType());
}
System.out.println("INCLUDE THIS IN YOUR ERROR LOG!");
if (type != null)
System.out.println("An error occurred with entity meta data for " + type + " OldID: " + entry.oldID);
else
System.out.println("An error occurred with entity meta data for UNKOWN_ENTITY OldID: " + entry.oldID);
if (metaIndex != null) {
System.out.println("Old ID: " + metaIndex.getIndex() + " New ID: " + metaIndex.getNewIndex());
System.out.println("Old Type: " + metaIndex.getOldType() + " New Type: " + metaIndex.getNewType());
}
e.printStackTrace();
}
@@ -131,35 +142,40 @@ public class MetadataRewriter {
MetaIndex index = MetaIndex.getIndex(entityType, id);
switch (type) {
case Byte:
entries.add(new Entry(index, buf.readByte()));
entries.add(new Entry(index, buf.readByte(), id));
break;
case Short:
entries.add(new Entry(index, buf.readShort()));
entries.add(new Entry(index, buf.readShort(), id));
break;
case Int:
entries.add(new Entry(index, buf.readInt()));
entries.add(new Entry(index, buf.readInt(), id));
break;
case Float:
entries.add(new Entry(index, buf.readFloat()));
entries.add(new Entry(index, buf.readFloat(), id));
break;
case String:
entries.add(new Entry(index, PacketUtil.readString(buf)));
break;
case Slot:
entries.add(new Entry(index, PacketUtil.readItem(buf)));
entries.add(new Entry(index, PacketUtil.readString(buf), id));
break;
case Slot: {
try {
entries.add(new Entry(index, ItemSlotRewriter.readItemStack(buf), id));
} catch (Exception e) {
e.printStackTrace();
}
}
break;
case Position: {
int x = buf.readInt();
int y = buf.readInt();
int z = buf.readInt();
entries.add(new Entry(index, new Vector(x, y, z)));
entries.add(new Entry(index, new Vector(x, y, z), id));
break;
}
case Rotation: {
float x = buf.readFloat();
float y = buf.readFloat();
float z = buf.readFloat();
entries.add(new Entry(index, new EulerAngle(x, y, z)));
entries.add(new Entry(index, new EulerAngle(x, y, z), id));
break;
}
default:
@@ -172,12 +188,14 @@ public class MetadataRewriter {
public static class Entry {
private final int oldID;
private MetaIndex index;
private Object value;
private Entry(MetaIndex index, Object value) {
private Entry(MetaIndex index, Object value, int id) {
this.index = index;
this.value = value;
this.oldID = id;
}
}
}
@@ -96,7 +96,7 @@ public enum PacketType {
PLAY_COMBAT_EVENT(State.PLAY, Direction.OUTGOING, 0x42, 0x2C),
PLAY_PLAYER_LIST_ITEM(State.PLAY, Direction.OUTGOING, 0x38, 0x2D),
PLAY_PLAYER_POSITION_LOOK(State.PLAY, Direction.OUTGOING, 0x08, 0x2E),
PLAY_USE_BED(State.PLAY, Direction.OUTGOING, 0x2F, 0x2F),
PLAY_USE_BED(State.PLAY, Direction.OUTGOING, 0x0A, 0x2F),
PLAY_DESTROY_ENTITIES(State.PLAY, Direction.OUTGOING, 0x13, 0x30),
PLAY_REMOVE_ENTITY_EFFECT(State.PLAY, Direction.OUTGOING, 0x1E, 0x31),
PLAY_RESOURCE_PACK_SEND(State.PLAY, Direction.OUTGOING, 0x48, 0x32),
@@ -170,7 +170,7 @@ public enum PacketType {
if(id == -1)
return null;
for (PacketType pt : values()) {
if (pt.getNewPacketID() == id && id != -1
if (pt.getNewPacketID() == id
&& pt.getState() == state
&& pt.getDirection() == direction)
return pt;
@@ -182,7 +182,7 @@ public enum PacketType {
if(id == -1)
return null;
for (PacketType pt : values()) {
if (pt.getPacketID() == id && id != -1
if (pt.getPacketID() == id
&& pt.getState() == state
&& pt.getDirection() == direction)
return pt;
@@ -0,0 +1,322 @@
package us.myles.ViaVersion.slot;
import io.netty.buffer.ByteBuf;
import org.bukkit.Material;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
import org.spacehq.opennbt.tag.builtin.ListTag;
import org.spacehq.opennbt.tag.builtin.StringTag;
import org.spacehq.opennbt.tag.builtin.Tag;
import us.myles.ViaVersion.CancelException;
import us.myles.ViaVersion.transformers.OutgoingTransformer;
import us.myles.ViaVersion.util.PacketUtil;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class ItemSlotRewriter {
public static void rewrite1_9To1_8(ByteBuf input, ByteBuf output) throws CancelException {
try {
ItemStack item = readItemStack(input);
fixIdsFrom1_9To1_8(item);
writeItemStack(item, output);
} catch (Exception e) {
System.out.println("Error while rewriting an item slot.");
e.printStackTrace();
throw new CancelException();
}
}
public static void rewrite1_8To1_9(ByteBuf input, ByteBuf output) throws CancelException {
try {
ItemStack item = readItemStack(input);
fixIdsFrom1_8To1_9(item);
writeItemStack(item, output);
} catch (Exception e) {
System.out.println("Error while rewriting an item slot.");
e.printStackTrace();
throw new CancelException();
}
}
public static void fixIdsFrom1_9To1_8(ItemStack item) {
if (item != null) {
if (item.id == Material.MONSTER_EGG.getId() && item.data == 0) {
CompoundTag tag = item.tag;
int data = 0;
if (tag != null && tag.get("EntityTag") instanceof CompoundTag) {
CompoundTag entityTag = tag.get("EntityTag");
if (entityTag.get("id") instanceof StringTag) {
StringTag id = entityTag.get("id");
if (ENTTIY_NAME_TO_ID.containsKey(id.getValue()))
data = ENTTIY_NAME_TO_ID.get(id.getValue());
}
}
item.tag = null;
item.data = (short) data;
}
if (item.id == Material.POTION.getId()) {
CompoundTag tag = item.tag;
int data = 0;
if (tag != null && tag.get("Potion") instanceof StringTag) {
StringTag potion = tag.get("Potion");
String potionName = potion.getValue().replace("minecraft:", "");
if (POTION_NAME_TO_ID.containsKey(potionName)) {
data = POTION_NAME_TO_ID.get(potionName);
}
}
item.tag = null;
item.data = (short) data;
}
if (item.id == 438) {
CompoundTag tag = item.tag;
int data = 0;
item.id = (short) Material.POTION.getId();
if (tag != null && tag.get("Potion") instanceof StringTag) {
StringTag potion = tag.get("Potion");
String potionName = potion.getValue().replace("minecraft:", "");
if (POTION_NAME_TO_ID.containsKey(potionName)) {
data = POTION_NAME_TO_ID.get(potionName) + 8192;
}
}
item.tag = null;
item.data = (short) data;
}
}
}
public static void fixIdsFrom1_8To1_9(ItemStack item) {
if (item != null) {
if (item.id == Material.MONSTER_EGG.getId() && item.data != 0) {
CompoundTag tag = item.tag;
if (tag == null) {
tag = new CompoundTag("tag");
}
CompoundTag entityTag = new CompoundTag("EntityTag");
if (ENTTIY_ID_TO_NAME.containsKey(Integer.valueOf(item.data))) {
StringTag id = new StringTag("id", ENTTIY_ID_TO_NAME.get(Integer.valueOf(item.data)));
entityTag.put(id);
tag.put(entityTag);
}
item.tag = tag;
item.data = 0;
}
if (item.id == Material.POTION.getId()) {
CompoundTag tag = item.tag;
if (tag == null) {
tag = new CompoundTag("tag");
}
if (item.data >= 16384) {
item.id = 438; // splash id
item.data = (short) (item.data - 8192);
}
if (POTION_ID_TO_NAME.containsKey(Integer.valueOf(item.data))) {
String name = POTION_ID_TO_NAME.get(Integer.valueOf(item.data));
StringTag potion = new StringTag("Potion", "minecraft:" + name);
tag.put(potion);
}
item.tag = tag;
item.data = 0;
}
if (item.id == Material.WRITTEN_BOOK.getId()) {
CompoundTag tag = item.tag;
if (tag == null) {
tag = new CompoundTag("tag");
}
ListTag pages = tag.get("pages");
if (pages == null) {
pages = new ListTag("pages", Collections.<Tag>singletonList(new StringTag(OutgoingTransformer.fixJson(""))));
tag.put(pages);
item.tag = tag;
return;
}
for (int i = 0; i < pages.size(); i++) {
if (!(pages.get(i) instanceof StringTag))
continue;
StringTag page = pages.get(i);
page.setValue(OutgoingTransformer.fixJson(page.getValue()));
}
item.tag = tag;
}
}
}
public static ItemStack readItemStack(ByteBuf input) throws IOException {
short id = input.readShort();
if (id < 0) {
return null;
} else {
ItemStack item = new ItemStack();
item.id = id;
item.amount = input.readByte();
item.data = input.readShort();
item.tag = PacketUtil.readNBT(input);
return item;
}
}
public static void writeItemStack(ItemStack item, ByteBuf output) throws IOException {
if (item == null) {
output.writeShort(-1);
} else {
output.writeShort(item.id);
output.writeByte(item.amount);
output.writeShort(item.data);
PacketUtil.writeNBT(output, item.tag);
}
}
public static class ItemStack {
public short id;
public byte amount;
public short data;
public CompoundTag tag;
public static ItemStack fromBukkit(org.bukkit.inventory.ItemStack stack) {
ItemStack item = new ItemStack();
item.id = (short) stack.getTypeId();
item.amount = (byte) stack.getAmount();
item.data = stack.getData().getData();
// TODO: nbt
return item;
}
}
private static Map<String, Integer> ENTTIY_NAME_TO_ID = new HashMap<>();
private static Map<Integer, String> ENTTIY_ID_TO_NAME = new HashMap<>();
private static Map<String, Integer> POTION_NAME_TO_ID = new HashMap<>();
private static Map<Integer, String> POTION_ID_TO_NAME = new HashMap<>();
static {
/* Entities */
registerEntity(1, "Item");
registerEntity(2, "XPOrb");
registerEntity(7, "ThrownEgg");
registerEntity(8, "LeashKnot");
registerEntity(9, "Painting");
registerEntity(10, "Arrow");
registerEntity(11, "Snowball");
registerEntity(12, "Fireball");
registerEntity(13, "SmallFireball");
registerEntity(14, "ThrownEnderpearl");
registerEntity(15, "EyeOfEnderSignal");
registerEntity(16, "ThrownPotion");
registerEntity(17, "ThrownExpBottle");
registerEntity(18, "ItemFrame");
registerEntity(19, "WitherSkull");
registerEntity(20, "PrimedTnt");
registerEntity(21, "FallingSand");
registerEntity(22, "FireworksRocketEntity");
registerEntity(30, "ArmorStand");
registerEntity(40, "MinecartCommandBlock");
registerEntity(41, "Boat");
registerEntity(42, "MinecartRideable");
registerEntity(43, "MinecartChest");
registerEntity(44, "MinecartFurnace");
registerEntity(45, "MinecartTNT");
registerEntity(46, "MinecartHopper");
registerEntity(47, "MinecartSpawner");
registerEntity(48, "Mob");
registerEntity(49, "Monster");
registerEntity(50, "Creeper");
registerEntity(51, "Skeleton");
registerEntity(52, "Spider");
registerEntity(53, "Giant");
registerEntity(54, "Zombie");
registerEntity(55, "Slime");
registerEntity(56, "Ghast");
registerEntity(57, "PigZombie");
registerEntity(58, "Enderman");
registerEntity(59, "CaveSpider");
registerEntity(60, "Silverfish");
registerEntity(61, "Blaze");
registerEntity(62, "LavaSlime");
registerEntity(63, "EnderDragon");
registerEntity(64, "WitherBoss");
registerEntity(65, "Bat");
registerEntity(66, "Witch");
registerEntity(67, "Endermite");
registerEntity(68, "Guardian");
registerEntity(90, "Pig");
registerEntity(91, "Sheep");
registerEntity(92, "Cow");
registerEntity(93, "Chicken");
registerEntity(94, "Squid");
registerEntity(95, "Wolf");
registerEntity(96, "MushroomCow");
registerEntity(97, "SnowMan");
registerEntity(98, "Ozelot");
registerEntity(99, "VillagerGolem");
registerEntity(100, "EntityHorse");
registerEntity(101, "Rabbit");
registerEntity(120, "Villager");
registerEntity(200, "EnderCrystal");
/* Potions */
registerPotion(0, "water");
registerPotion(64, "mundane");
registerPotion(32, "thick");
registerPotion(16, "awkward");
registerPotion(8198, "night_vision");
registerPotion(8262, "long_night_vision");
registerPotion(8206, "invisibility");
registerPotion(8270, "long_invisibility");
registerPotion(8203, "leaping");
registerPotion(8267, "long_leaping");
registerPotion(8235, "strong_leaping");
registerPotion(8195, "fire_resistance");
registerPotion(8259, "long_fire_resistance");
registerPotion(8194, "swiftness");
registerPotion(8258, "long_swiftness");
registerPotion(8226, "strong_swiftness");
registerPotion(8202, "slowness");
registerPotion(8266, "long_slowness");
registerPotion(8205, "water_breathing");
registerPotion(8269, "long_water_breathing");
registerPotion(8197, "healing");
registerPotion(8229, "strong_healing");
registerPotion(8204, "harming");
registerPotion(8236, "strong_harming");
registerPotion(8196, "poison");
registerPotion(8260, "long_poison");
registerPotion(8228, "strong_poison");
registerPotion(8193, "regeneration");
registerPotion(8257, "long_regeneration");
registerPotion(8225, "strong_regeneration");
registerPotion(8201, "strength");
registerPotion(8265, "long_strength");
registerPotion(8233, "strong_strength");
registerPotion(8200, "weakness");
registerPotion(8264, "long_weakness");
}
private static void registerEntity(Integer id, String name) {
ENTTIY_ID_TO_NAME.put(id, name);
ENTTIY_NAME_TO_ID.put(name, id);
}
private static void registerPotion(Integer id, String name) {
POTION_ID_TO_NAME.put(id, name);
POTION_NAME_TO_ID.put(name, id);
}
}
@@ -198,7 +198,7 @@ public enum SoundEffect {
MOB_ENDERMEN_SCREAM("mob.endermen.scream", "entity.endermen.scream", SoundCategory.HOSTILE),
MOB_CAT_HITT("mob.cat.hitt", "entity.cat.hurt", SoundCategory.NEUTRAL),
MOB_MAGMACUBE_SMALL("mob.magmacube.small", "entity.small_magmacube.squish", SoundCategory.HOSTILE),
FIRE_IGNITE("fire.ignite", "item.flintandsteel.use", SoundCategory.BLOCK),
FIRE_IGNITE("fire.ignite", "item.flintandsteel.use", SoundCategory.BLOCK, true),
MOB_ENDERDRAGON_HIT("mob.enderdragon.hit", "entity.enderdragon.hurt", SoundCategory.HOSTILE),
MOB_ZOMBIE_HURT("mob.zombie.hurt", "entity.zombie_villager.hurt", SoundCategory.HOSTILE),
RANDOM_EXPLODE("random.explode", "block.end_gateway.spawn", SoundCategory.BLOCK),
@@ -252,11 +252,20 @@ public enum SoundEffect {
private String name;
private String newname;
private SoundCategory cat;
private boolean breaksound;
SoundEffect(String name, String newname, SoundCategory cat) {
this.cat = cat;
this.newname = newname;
this.name = name;
this.breaksound = name.startsWith("dig.");
}
SoundEffect(String name, String newname, SoundCategory cat, boolean shouldIgnore) {
this.cat = cat;
this.newname = newname;
this.name = name;
this.breaksound = name.startsWith("dig.") || shouldIgnore;
}
public static SoundEffect getByName(String name) {
@@ -279,5 +288,9 @@ public enum SoundEffect {
public SoundCategory getCategory() {
return cat;
}
public boolean isBreakPlaceSound() {
return breaksound;
}
}
@@ -1,17 +1,19 @@
package us.myles.ViaVersion.transformers;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import us.myles.ViaVersion.CancelException;
import us.myles.ViaVersion.ConnectionInfo;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.packets.PacketType;
import us.myles.ViaVersion.packets.State;
import us.myles.ViaVersion.slot.ItemSlotRewriter;
import us.myles.ViaVersion.util.PacketUtil;
import us.myles.ViaVersion.util.ReflectionUtil;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.io.IOException;
public class IncomingTransformer {
private final ConnectionInfo info;
@@ -31,9 +33,11 @@ public class IncomingTransformer {
if (packet.getPacketID() != -1) {
packetID = packet.getPacketID();
}
// if (packet != PacketType.PLAY_PLAYER_POSITION_LOOK_REQUEST && packet != PacketType.PLAY_KEEP_ALIVE_REQUEST && packet != PacketType.PLAY_PLAYER_POSITION_REQUEST && packet != PacketType.PLAY_PLAYER_LOOK_REQUEST) {
// System.out.println("Packet Type: " + packet + " New ID: " + packetID + " Original: " + original);
// }
if (ViaVersion.getInstance().isDebug()) {
if (packet != PacketType.PLAY_PLAYER_POSITION_LOOK_REQUEST && packet != PacketType.PLAY_KEEP_ALIVE_REQUEST && packet != PacketType.PLAY_PLAYER_POSITION_REQUEST && packet != PacketType.PLAY_PLAYER_LOOK_REQUEST) {
System.out.println("Direction " + packet.getDirection().name() + " Packet Type: " + packet + " New ID: " + packetID + " Original: " + original + " Size: " + input.readableBytes());
}
}
if (packet == PacketType.PLAY_TP_CONFIRM || packet == PacketType.PLAY_VEHICLE_MOVE_REQUEST) { //TODO handle client-sided horse riding
throw new CancelException();
}
@@ -69,7 +73,7 @@ public class IncomingTransformer {
output.writeLong(location);
for (int i = 0; i < 4; i++) {
String line = PacketUtil.readString(input);
line = "{\"text\":\"" + line + "\"}";
line = OutgoingTransformer.fixJson(line);
PacketUtil.writeString(line, output);
}
return;
@@ -82,7 +86,7 @@ public class IncomingTransformer {
return;
}
if (packet == PacketType.PLAY_PLAYER_DIGGING) {
byte status = input.readByte();
int status = input.readByte() & 0xFF; // unsign
if (status == 6) { // item swap
throw new CancelException();
}
@@ -98,32 +102,44 @@ public class IncomingTransformer {
byte button = input.readByte();
short action = input.readShort();
byte mode = input.readByte();
if (slot == 45 && windowID == 0) {
try {
Class<?> setSlot = ReflectionUtil.nms("PacketPlayOutSetSlot");
Object setSlotPacket = setSlot.getConstructors()[1].newInstance(windowID, slot, null);
info.getChannel().pipeline().writeAndFlush(setSlotPacket); // slot is empty
slot = -999; // we're evil, they'll throw item on the ground
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
int mode = input.readByte();
// if the action is on an elytra armour slot
boolean throwItem = (slot == 45 && windowID == 0);
if (info.getOpenWindow() != null && windowID > 0) {
if (info.getOpenWindow().equals("minecraft:brewing_stand")) {
if (slot == 4) {
// throw
throwItem = true;
}
if (slot > 4)
slot = (short) (slot - 1);
}
}
if (throwItem) {
ByteBuf buf = info.getChannel().alloc().buffer();
PacketUtil.writeVarInt(PacketType.PLAY_SET_SLOT.getNewPacketID(), buf);
buf.writeByte(windowID);
buf.writeShort(slot);
buf.writeShort(-1); // empty
info.sendRawPacket(buf);
// Continue the packet simulating throw
mode = 0;
button = 0;
slot = -999;
}
output.writeByte(windowID);
output.writeShort(slot);
output.writeByte(button);
output.writeShort(action);
output.writeByte(mode);
output.writeBytes(input);
ItemSlotRewriter.rewrite1_9To1_8(input, output);
return;
}
if (packet == PacketType.PLAY_CLOSE_WINDOW_REQUEST) {
info.closeWindow();
}
if (packet == PacketType.PLAY_CLIENT_SETTINGS) {
String locale = PacketUtil.readString(input);
PacketUtil.writeString(locale, output);
@@ -166,6 +182,49 @@ public class IncomingTransformer {
}
return;
}
if (packet == PacketType.PLAY_PLUGIN_MESSAGE_REQUEST) {
String name = PacketUtil.readString(input);
PacketUtil.writeString(name, output);
byte[] b = new byte[input.readableBytes()];
input.readBytes(b);
// patch books
if (name.equals("MC|BSign")) {
ByteBuf in = Unpooled.wrappedBuffer(b);
try {
ItemSlotRewriter.ItemStack stack = ItemSlotRewriter.readItemStack(in);
stack.id = (short) Material.WRITTEN_BOOK.getId();
// write
ItemSlotRewriter.writeItemStack(stack, output);
} catch (IOException e) {
e.printStackTrace();
}
return;
} else if (name.equals("MC|AutoCmd")) {
ByteBuf in = Unpooled.wrappedBuffer(b);
int x = in.readInt();
int y = in.readInt();
int z = in.readInt();
String command = PacketUtil.readString(in);
boolean flag = in.readBoolean();
output.clear();
PacketUtil.writeVarInt(PacketType.PLAY_PLUGIN_MESSAGE_REQUEST.getPacketID(), output);
PacketUtil.writeString("MC|AdvCdm", output);
output.writeByte(0);
output.writeInt(x);
output.writeInt(y);
output.writeInt(z);
PacketUtil.writeString(command, output);
output.writeBoolean(flag);
return;
} else if (name.equals("MC|AdvCmd")) {
output.clear();
PacketUtil.writeVarInt(PacketType.PLAY_PLUGIN_MESSAGE_REQUEST.getPacketID(), output);
PacketUtil.writeString("MC|AdvCdm", output);
output.writeBytes(b);
}
output.writeBytes(b);
}
if (packet == PacketType.PLAY_PLAYER_BLOCK_PLACEMENT) {
Long position = input.readLong();
output.writeLong(position);
@@ -174,22 +233,14 @@ public class IncomingTransformer {
int hand = PacketUtil.readVarInt(input);
ItemStack inHand = ViaVersionPlugin.getHandItem(info);
Object item = null;
try {
Method m = ReflectionUtil.obc("inventory.CraftItemStack").getDeclaredMethod("asNMSCopy", ItemStack.class);
item = m.invoke(null, inHand);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
ItemSlotRewriter.ItemStack item = ItemSlotRewriter.ItemStack.fromBukkit(inHand);
ItemSlotRewriter.fixIdsFrom1_9To1_8(item);
ItemSlotRewriter.writeItemStack(item, output);
} catch (Exception e) {
e.printStackTrace();
}
PacketUtil.writeItem(item, output);
short curX = input.readUnsignedByte();
output.writeByte(curX);
short curY = input.readUnsignedByte();
@@ -206,26 +257,25 @@ public class IncomingTransformer {
output.writeByte(255);
// write item in hand
ItemStack inHand = ViaVersionPlugin.getHandItem(info);
Object item = null;
try {
Method m = ReflectionUtil.obc("inventory.CraftItemStack").getDeclaredMethod("asNMSCopy", ItemStack.class);
item = m.invoke(null, inHand);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
ItemSlotRewriter.ItemStack item = ItemSlotRewriter.ItemStack.fromBukkit(inHand);
ItemSlotRewriter.fixIdsFrom1_9To1_8(item);
ItemSlotRewriter.writeItemStack(item, output);
} catch (Exception e) {
e.printStackTrace();
}
PacketUtil.writeItem(item, output);
output.writeByte(-1);
output.writeByte(-1);
output.writeByte(-1);
return;
}
if (packet == PacketType.PLAY_CREATIVE_INVENTORY_ACTION) {
short slot = input.readShort();
output.writeShort(slot);
ItemSlotRewriter.rewrite1_9To1_8(input, output);
}
output.writeBytes(input);
}
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,24 @@
package us.myles.ViaVersion.update;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.Plugin;
public class UpdateListener implements Listener {
private Plugin plugin;
public UpdateListener(Plugin plugin) {
this.plugin = plugin;
}
@EventHandler
public void onJoin(PlayerJoinEvent e) {
if(e.getPlayer().hasPermission("viaversion.update")
&& plugin.getConfig().getBoolean("checkforupdates", true)) {
UpdateUtil.sendUpdateMessage(e.getPlayer().getUniqueId(), plugin);
}
}
}
@@ -0,0 +1,125 @@
package us.myles.ViaVersion.update;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitRunnable;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import us.myles.ViaVersion.api.ViaVersion;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.UUID;
public class UpdateUtil {
private final static String URL = "http://api.spiget.org/v1/resources/";
private final static int PLUGIN = 19254;
public final static String PREFIX = ChatColor.GREEN + "" + ChatColor.BOLD + "[ViaVersion] " + ChatColor.GREEN;
public static void sendUpdateMessage(final UUID uuid, final Plugin plugin) {
new BukkitRunnable() {
@Override
public void run() {
final String message = getUpdateMessage(false);
if (message != null) {
new BukkitRunnable() {
@Override
public void run() {
Player p = Bukkit.getPlayer(uuid);
if (p != null) {
p.sendMessage(PREFIX + message);
}
}
}.runTask(plugin);
}
}
}.runTaskAsynchronously(plugin);
}
public static void sendUpdateMessage(final Plugin plugin) {
new BukkitRunnable() {
@Override
public void run() {
final String message = getUpdateMessage(true);
if (message != null) {
new BukkitRunnable() {
@Override
public void run() {
plugin.getLogger().warning(message);
}
}.runTask(plugin);
}
}
}.runTaskAsynchronously(plugin);
}
private static String getUpdateMessage(boolean console) {
if (ViaVersion.getInstance().getVersion().equals("${project.version}")) {
return "You are using a debug/custom version, consider updating.";
}
String newestString = getNewestVersion();
if (newestString == null) {
if (console) {
return "Could not check for updates, check your connection.";
} else {
return null;
}
}
Version current;
try {
current = new Version(ViaVersion.getInstance().getVersion());
} catch (IllegalArgumentException e) {
return "You are using a debug/custom version, consider updating.";
}
Version newest = new Version(newestString);
if (current.compareTo(newest) < 0)
return "There is a newer version available: " + newest.toString();
else if (console && current.compareTo(newest) != 0) {
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());
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setUseCaches(true);
connection.addRequestProperty("User-Agent", "Mozilla/4.76");
connection.setDoOutput(true);
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String input;
String content = "";
while ((input = br.readLine()) != null) {
content = content + input;
}
br.close();
JSONParser parser = new JSONParser();
JSONObject statistics;
try {
statistics = (JSONObject) parser.parse(content);
} catch (ParseException e) {
e.printStackTrace();
return null;
}
return (String) statistics.get("version");
} catch (MalformedURLException e) {
return null;
} catch (IOException e) {
return null;
}
}
}
@@ -0,0 +1,65 @@
package us.myles.ViaVersion.update;
import org.apache.commons.lang.StringUtils;
public class Version implements Comparable<Version> {
private int[] parts;
public Version(String value) {
if (value == null)
throw new IllegalArgumentException("Version can not be null");
if (value.matches("^[0-9]+(\\.[0-9]+)*$") == false)
throw new IllegalArgumentException("Invalid version format");
String[] split = value.split("\\.");
parts = new int[split.length];
for (int i = 0; i < split.length; i += 1)
parts[i] = Integer.parseInt(split[i]);
}
@Override
public String toString() {
String[] split = new String[parts.length];
for (int i = 0; i < parts.length; i += 1)
split[i] = String.valueOf(parts[i]);
return StringUtils.join(split, ".");
}
public static int compare(Version verA, Version verB) {
if (verA == verB) return 0;
if (verA == null) return -1;
if (verB == null) return 1;
int max = Math.max(verA.parts.length, verB.parts.length);
for (int i = 0; i < max; i += 1) {
int partA = i < verA.parts.length ? verA.parts[i] : 0;
int partB = i < verB.parts.length ? verB.parts[i] : 0;
if (partA < partB) return -1;
if (partA > partB) return 1;
}
return 0;
}
@Override
public int compareTo(Version that) {
return compare(this, that);
}
public static boolean equals(Version verA, Version verB) {
if (verA == verB) return true;
if (verA == null) return false;
if (verB == null) return false;
return compare(verA, verB) == 0;
}
@Override
public boolean equals(Object that) {
return that instanceof Version && equals(this, (Version) that);
}
}
@@ -3,14 +3,21 @@ package us.myles.ViaVersion.util;
import com.google.common.base.Charsets;
import com.google.common.base.Preconditions;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.ByteBufOutputStream;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import org.spacehq.opennbt.NBTIO;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
import us.myles.ViaVersion.chunks.MagicBitSet;
import us.myles.ViaVersion.chunks.PacketChunk;
import us.myles.ViaVersion.chunks.PacketChunkData;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
@@ -42,6 +49,25 @@ public class PacketUtil {
}
}
public static CompoundTag readNBT(ByteBuf input) throws IOException {
int readerIndex = input.readerIndex();
byte b = input.readByte();
if (b == 0) {
return null;
} else {
input.readerIndex(readerIndex);
return (CompoundTag) NBTIO.readTag(new DataInputStream(new ByteBufInputStream(input)));
}
}
public static void writeNBT(ByteBuf output, CompoundTag tag) throws IOException {
if (tag == null) {
output.writeByte(0);
} else {
NBTIO.writeTag(new DataOutputStream(new ByteBufOutputStream(output)), tag);
}
}
public static List<Object> callDecode(ByteToMessageDecoder decoder, ChannelHandlerContext ctx, Object input) {
List<Object> output = new ArrayList<Object>();
try {
@@ -354,45 +380,6 @@ public class PacketUtil {
return output;
}
public static void writeItem(Object value, ByteBuf output) {
try {
Class<?> serializer = ReflectionUtil.nms("PacketDataSerializer");
Object init = serializer.getDeclaredConstructor(ByteBuf.class).newInstance(output);
Method toCall = init.getClass().getDeclaredMethod("a", ReflectionUtil.nms("ItemStack"));
toCall.invoke(init, value);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
public static Object readItem(ByteBuf output) {
try {
Class<?> serializer = ReflectionUtil.nms("PacketDataSerializer");
Object init = serializer.getDeclaredConstructor(ByteBuf.class).newInstance(output);
Method toCall = init.getClass().getDeclaredMethod("i");
return toCall.invoke(init);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
public static long[] readBlockPosition(ByteBuf buf) {
long val = buf.readLong();
long x = (val >> 38); // signed
@@ -414,4 +401,13 @@ public class PacketUtil {
return data;
}
public static boolean containsCause(Throwable t, Class<? extends Throwable> c) {
while (t != null) {
t = t.getCause();
if (t != null)
if (c.isAssignableFrom(t.getClass())) return true;
}
return false;
}
}
@@ -27,6 +27,18 @@ public class ReflectionUtil {
return m.invoke(o);
}
public static <T> T getStatic(Class<?> clazz, String f, Class<T> t) throws NoSuchFieldException, IllegalAccessException {
Field field = clazz.getDeclaredField(f);
field.setAccessible(true);
return (T) field.get(null);
}
public static <T> T get(Object instance, Class<?> clazz, String f, Class<T> t) throws NoSuchFieldException, IllegalAccessException {
Field field = clazz.getDeclaredField(f);
field.setAccessible(true);
return (T) field.get(instance);
}
public static <T> T get(Object o, String f, Class<T> t) throws NoSuchFieldException, IllegalAccessException {
Field field = o.getClass().getDeclaredField(f);
field.setAccessible(true);
+5
View File
@@ -0,0 +1,5 @@
# Should ViaVersion check for updates?
checkforupdates: true
# Should we send any bulk chunks, in sync (may be slower but fixes timings)
# Currently broken due to sign updates, possibly will return
sync-chunks: true
+7 -2
View File
@@ -1,6 +1,11 @@
name: ViaVersion
main: us.myles.ViaVersion.ViaVersionPlugin
author: _MylesC
version: 0.4.4
version: ${project.version}
load: startup
loadbefore: [ProtocolLib, ProxyPipe]
loadbefore: [ProtocolLib, ProxyPipe]
commands:
viaversion:
description: Shows ViaVersion Version and more.
permission: viaversion.admin
aliases: [viaver]