Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
463327c2a7 | ||
|
|
b0050d4a8d | ||
|
|
a743895c3f | ||
|
|
f65666b7a6 | ||
|
|
3a217503fc | ||
|
|
c71b75e13b | ||
|
|
0c890c3a30 | ||
|
|
f38bb0ca22 | ||
|
|
2144fa1837 | ||
|
|
fc4a617da7 | ||
|
|
126ee6e03f | ||
|
|
498867032f | ||
|
|
aef8eca790 | ||
|
|
d8bbb51721 | ||
|
|
6e4fd5a63b | ||
|
|
e7bd6245c2 | ||
|
|
6242cb0b47 | ||
|
|
bf5072e1cf | ||
|
|
c24b673550 | ||
|
|
dfc1e1cf51 | ||
|
|
c600ab6dd1 | ||
|
|
29754c0787 | ||
|
|
9144980474 | ||
|
|
6a449f8db1 | ||
|
|
3780210f76 | ||
|
|
67bad0dec8 | ||
|
|
79291fd7d9 | ||
|
|
ee9d8d6365 | ||
|
|
cc354db464 | ||
|
|
2b29d27b0d | ||
|
|
75db62ee6f | ||
|
|
7cd7b5ba24 | ||
|
|
a3bfcefdca | ||
|
|
098b787355 | ||
|
|
abb9665813 | ||
|
|
012eec47b5 | ||
|
|
2d40afa3a1 | ||
|
|
a92a7d6e02 | ||
|
|
fc7cdb4244 | ||
|
|
d5b375b264 | ||
|
|
99eadbe343 | ||
|
|
38d33dba16 | ||
|
|
b3de4de0cd | ||
|
|
6b5c166a22 | ||
|
|
1aea00036f | ||
|
|
1262847a0e | ||
|
|
21cfb1297f | ||
|
|
0b1cb61986 | ||
|
|
44907b3e8d | ||
|
|
dac616d72c | ||
|
|
528b234d5a | ||
|
|
e4288383f4 | ||
|
|
bb17eb01b8 | ||
|
|
ca6638c740 | ||
|
|
d8ce66ce29 | ||
|
|
8460c157a5 | ||
|
|
0b807569ad | ||
|
|
75d001d09b | ||
|
|
2118379cf7 | ||
|
|
cd2441ee52 | ||
|
|
ffb4fb5c5a | ||
|
|
c404f2206c | ||
|
|
aec5aa48da | ||
|
|
b63051a796 | ||
|
|
ea4650000e | ||
|
|
2d2018b8d0 | ||
|
|
736a853a85 | ||
|
|
dfd4c5f93e | ||
|
|
2ac87acc8a | ||
|
|
3c5a6a3b7b | ||
|
|
6efb5c1b64 | ||
|
|
91de7e5a22 | ||
|
|
1c42ae1ee8 | ||
|
|
c5ac3c9b3d | ||
|
|
0ea32b3318 | ||
|
|
8afc850ed3 | ||
|
|
3c6dcfe5bf | ||
|
|
59d637e0f5 | ||
|
|
923f3088c0 | ||
|
|
4f8aff9c01 | ||
|
|
99ceb9ae79 | ||
|
|
6e0554f4a4 | ||
|
|
36879f8d02 | ||
|
|
fe77df1434 | ||
|
|
713361f973 | ||
|
|
a314b86f57 | ||
|
|
840c90f871 | ||
|
|
2a247595c8 | ||
|
|
4124c3454e | ||
|
|
c4185e3056 | ||
|
|
d6403d495d | ||
|
|
d7f54048ff | ||
|
|
e487eeb395 | ||
|
|
0d0e1c16ea | ||
|
|
f462ff9e8a | ||
|
|
5582556d8a | ||
|
|
ef6214a442 | ||
|
|
369710333c | ||
|
|
30c4fea044 | ||
|
|
eccc5091b5 | ||
|
|
65770d7c5b | ||
|
|
715e873bae | ||
|
|
eced599818 | ||
|
|
6db7755633 | ||
|
|
653c3d3984 | ||
|
|
5ca841837d | ||
|
|
554e037044 | ||
|
|
457d7e4777 | ||
|
|
b3dc465498 | ||
|
|
c56109a64c | ||
|
|
d5e720fe09 | ||
|
|
a42526bb88 | ||
|
|
bd5f44b477 | ||
|
|
d5d8881677 | ||
|
|
ac2178a247 | ||
|
|
24fa8aec35 | ||
|
|
2ba92a0d47 | ||
|
|
ace178834e | ||
|
|
9c88d0a37f | ||
|
|
bafc1b6799 | ||
|
|
c9a575f45d | ||
|
|
c071c895e7 | ||
|
|
a8799bd493 | ||
|
|
20d4a94792 | ||
|
|
89e0948f97 | ||
|
|
6fe3c15f7d | ||
|
|
fb5dace6a6 | ||
|
|
f71e51c85e | ||
|
|
0dd530a593 | ||
|
|
12df86a142 | ||
|
|
963f021226 | ||
|
|
cb4a8b24d4 | ||
|
|
76c908b132 | ||
|
|
89311af76a | ||
|
|
1ecf515006 | ||
|
|
5c18028577 | ||
|
|
678a7de664 | ||
|
|
0aa190353e | ||
|
|
a42b113618 | ||
|
|
2704611977 | ||
|
|
be6245e693 | ||
|
|
d7b7c4916a | ||
|
|
caae4e4cca | ||
|
|
ee58fbedbe | ||
|
|
a84b45f5dd | ||
|
|
c2edf45846 | ||
|
|
88ff4ee9ca | ||
|
|
fd704f6a29 | ||
|
|
c97b443cf2 | ||
|
|
00df80e6fd | ||
|
|
64c2ba243f | ||
|
|
0ad2e6478d | ||
|
|
ab9f786999 | ||
|
|
e826b339f6 | ||
|
|
f06851f57a | ||
|
|
1a90f0eb28 | ||
|
|
fee986d215 | ||
|
|
9108e78491 | ||
|
|
1b75526892 | ||
|
|
5930a83765 | ||
|
|
ef118a3a64 | ||
|
|
bb42cda4a8 | ||
|
|
121bc9de6c | ||
|
|
1e873c123c | ||
|
|
c704b3709a | ||
|
|
618e09b202 | ||
|
|
fd0bd53826 | ||
|
|
e11c8320f0 | ||
|
|
624595e9f6 | ||
|
|
cc813545d8 | ||
|
|
e1ba6e07c2 | ||
|
|
1bf49b1f0b | ||
|
|
5e34fda7e4 | ||
|
|
aa70ab8b78 | ||
|
|
186ba22dc8 | ||
|
|
b10aa30d9b | ||
|
|
615b9f847c | ||
|
|
8f132fed14 | ||
|
|
854e24f8fc | ||
|
|
ff0544f29a | ||
|
|
72ae12bc77 | ||
|
|
29d2334ef0 | ||
|
|
afb96c4878 | ||
|
|
e4346611c9 | ||
|
|
f15e11272a | ||
|
|
8764d24a16 | ||
|
|
86d543d700 | ||
|
|
99fd01c359 | ||
|
|
573dcc10b1 | ||
|
|
3e30d989a0 | ||
|
|
fc00dd2b38 | ||
|
|
2e9987373d | ||
|
|
27c2f4c076 | ||
|
|
e9b61a8e91 | ||
|
|
222dee6fda | ||
|
|
e8cc25baad | ||
|
|
785f0664da | ||
|
|
ea6c648e4f | ||
|
|
4cdfd72700 | ||
|
|
ccd6987f11 | ||
|
|
6c96271925 | ||
|
|
318db73f3c | ||
|
|
b5b0117fa9 | ||
|
|
79e5555d42 | ||
|
|
b6c2a46a86 | ||
|
|
114a7b6bd6 | ||
|
|
8e6d76296d | ||
|
|
153a68bf06 | ||
|
|
6199e1d8ce | ||
|
|
0db43e612e | ||
|
|
06296ead77 | ||
|
|
dac9bd58e5 | ||
|
|
db9cd296ee | ||
|
|
442d4de74b |
No files matched your search
+115
-2
@@ -1,3 +1,116 @@
|
||||
target/
|
||||
.idea/
|
||||
### Java files ###
|
||||
*.class
|
||||
|
||||
# Package Files
|
||||
#*.jar
|
||||
*.war
|
||||
*.ear
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
||||
|
||||
|
||||
### Intellij ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
|
||||
# Ignore project files
|
||||
*.iml
|
||||
|
||||
# Ignore IDEA directory
|
||||
.idea/*
|
||||
|
||||
# Include the project's code style settings file
|
||||
!.idea/codeStyleSettings.xml
|
||||
|
||||
# Include the project's dictionary
|
||||
!.idea/dictionaries/
|
||||
!.idea/dictionaries/*
|
||||
|
||||
# File-based project format:
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
### Plugin-specific files: ###
|
||||
# IntelliJ
|
||||
/out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
|
||||
|
||||
|
||||
### Eclipse ###
|
||||
*.pydevproject
|
||||
.metadata
|
||||
.gradle
|
||||
bin/
|
||||
tmp/
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*~.nib
|
||||
local.properties
|
||||
.settings/
|
||||
.loadpath
|
||||
|
||||
# Eclipse Core
|
||||
.project
|
||||
|
||||
# External tool builders
|
||||
.externalToolBuilders/
|
||||
|
||||
# Locally stored "Eclipse launch configurations"
|
||||
*.launch
|
||||
|
||||
# CDT-specific
|
||||
.cproject
|
||||
|
||||
# JDT-specific (Eclipse Java Development Tools)
|
||||
.classpath
|
||||
|
||||
# PDT-specific
|
||||
.buildpath
|
||||
|
||||
# sbteclipse plugin
|
||||
.target
|
||||
|
||||
# TeXlipse plugin
|
||||
.texlipse
|
||||
|
||||
|
||||
|
||||
### Maven ###
|
||||
target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
dependency-reduced-pom.xml
|
||||
buildNumber.properties
|
||||
|
||||
|
||||
|
||||
### NetBeans ###
|
||||
nbproject/private/
|
||||
build/
|
||||
nbbuild/
|
||||
dist/
|
||||
nbdist/
|
||||
nbactions.xml
|
||||
nb-configuration.xml
|
||||
.nb-gradle/
|
||||
|
||||
|
||||
|
||||
### Git ###
|
||||
# Don't exclude the .gitignore itself
|
||||
!.gitignore
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
sudo: false
|
||||
|
||||
language: java
|
||||
jdk: oraclejdk7
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- '$HOME/.m2/repository'
|
||||
|
||||
script:
|
||||
- mvn dependency:purge-local-repository -DactTransitively=false -DreResolve=false
|
||||
- mvn clean install -B -U
|
||||
@@ -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?
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
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!)
|
||||
@@ -1,21 +1,16 @@
|
||||
# ViaVersion 0.3.7
|
||||
**Allows the connection of 1.8 clients to 1.9**
|
||||
# ViaVersion 0.6.0
|
||||
[](https://travis-ci.org/MylesIsCool/ViaVersion)
|
||||
**Allows the connection of 1.9 clients to 1.8**
|
||||
|
||||
This plugin modifies netty to allow connection of 1.9 clients to 1.8,
|
||||
|
||||
**Don't use late bind nor ProtocolLib**
|
||||
|
||||
**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.
|
||||
|
||||
**Contributor Chat:** https://gitter.im/MylesIsCool/ViaVersion
|
||||
|
||||
|
||||
Sources:
|
||||
--------
|
||||
@@ -24,6 +19,10 @@ Sources:
|
||||
|
||||
**MCProtocolLib** (used for chunk reading & some of writing.)
|
||||
|
||||
**OpenNBT** (used for slot rewriting)
|
||||
|
||||
|
||||
|
||||
Contributors:
|
||||
--------
|
||||
|
||||
@@ -33,10 +32,34 @@ Contributors:
|
||||
|
||||
**HugoDaBosss**
|
||||
|
||||
**SanderGielisse**
|
||||
|
||||
**Paulomart**
|
||||
|
||||
**gigosaurus**
|
||||
|
||||
**fillefilip8**
|
||||
|
||||
|
||||
|
||||
Releases / Dev Builds:
|
||||
--------
|
||||
You can find official releases here:
|
||||
|
||||
https://www.spigotmc.org/resources/viaversion.19254/history
|
||||
|
||||
|
||||
----------
|
||||
|
||||
You can find unofficial dev builds here:
|
||||
|
||||
**fillefilip8's Build Server:** http://build.fillecraft.com:8080/job/ViaVersion
|
||||
|
||||
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!
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
machine:
|
||||
java:
|
||||
version: oraclejdk7
|
||||
general:
|
||||
artifacts:
|
||||
- "target/*.jar"
|
||||
test:
|
||||
override:
|
||||
- mvn clean install -B
|
||||
post:
|
||||
- cp ./target/*.jar $CIRCLE_ARTIFACTS
|
||||
@@ -1,54 +1,181 @@
|
||||
<?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"
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
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>
|
||||
<artifactId>viaversion</artifactId>
|
||||
<version>0.6.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>ViaVersion</name>
|
||||
<description>Allow 1.8 clients to join 1.9 bukkit servers!</description>
|
||||
<inceptionYear>2016</inceptionYear>
|
||||
<url>https://www.spigotmc.org/resources/viaversion.19254/</url>
|
||||
|
||||
<prerequisites>
|
||||
<maven>3.3.3</maven>
|
||||
</prerequisites>
|
||||
|
||||
<properties>
|
||||
<!-- Project Properties -->
|
||||
<projectEncoding>UTF-8</projectEncoding>
|
||||
<project.build.sourceEncoding>${projectEncoding}</project.build.sourceEncoding>
|
||||
<project.build.outputEncoding>${projectEncoding}</project.build.outputEncoding>
|
||||
<jdkVersion>1.7</jdkVersion>
|
||||
<!-- <testJreVersion>1.7</testJreVersion> -->
|
||||
|
||||
<!-- Change Bukkit Version HERE! -->
|
||||
<bukkitVersion>1.8.8-R0.1-SNAPSHOT</bukkitVersion>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<finalName>${project.name}-${project.version}</finalName>
|
||||
<sourceDirectory>src/main/java</sourceDirectory>
|
||||
<!-- <testSourceDirectory>src/test/java</testSourceDirectory> -->
|
||||
|
||||
<resources>
|
||||
<resource>
|
||||
<targetPath>.</targetPath>
|
||||
<filtering>false</filtering>
|
||||
<directory>.</directory>
|
||||
<includes>
|
||||
<include>LICENSE</include>
|
||||
</includes>
|
||||
</resource>
|
||||
<resource>
|
||||
<targetPath>.</targetPath>
|
||||
<filtering>true</filtering>
|
||||
<directory>src/main/resources/</directory>
|
||||
<includes>
|
||||
<include>*</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
<!--
|
||||
<testResources>
|
||||
<testResource>
|
||||
<directory>src/test/resources</directory>
|
||||
</testResource>
|
||||
</testResources>
|
||||
-->
|
||||
|
||||
<plugins>
|
||||
<!-- Maven Java Compiler -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
<source>${jdkVersion}</source>
|
||||
<target>${jdkVersion}</target>
|
||||
<!--
|
||||
<testSource>${testJreVersion}</testSource>
|
||||
<testTarget>${testJreVersion}</testTarget>
|
||||
-->
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!-- Unit Test Plugin
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.19.1</version>
|
||||
<configuration>
|
||||
<argLine>-Dfile.encoding=${projectEncoding} ${argLine}</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
-->
|
||||
<!-- Libs Shading and Relocation -->
|
||||
<plugin>
|
||||
<!--Relocate all lib we use in order to fix class loading errors if we use different versions
|
||||
than already loaded libs (i.e. by Mojang -> gson)-->
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>2.4.3</version>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<minimizeJar>false</minimizeJar>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>org.spacehq.opennbt</pattern>
|
||||
<shadedPattern>us.myles.viaversion.libs.opennbt</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<!-- SpigotMC Repo (Bukkit API) -->
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots</url>
|
||||
</repository>
|
||||
|
||||
<!-- SpaceHQ Repo-->
|
||||
<repository>
|
||||
<id>spacehq-repo</id>
|
||||
<url>https://repo.spacehq.org/content/repositories/releases/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<!-- Bukkit API, http://www.spigotmc.org/ or http://bukkit.org/ -->
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
<version>1.8.8-R0.1-SNAPSHOT</version>
|
||||
<version>${bukkitVersion}</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>junit</artifactId>
|
||||
<groupId>junit</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>gson</artifactId>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>persistence-api</artifactId>
|
||||
<groupId>javax.persistence</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- NBT Edit Library -->
|
||||
<dependency>
|
||||
<groupId>org.spacehq</groupId>
|
||||
<artifactId>opennbt</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Netty (Network Library) -->
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>4.0.20.Final</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!-- Lombok -->
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.4</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>18.0</version>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.16.6</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
</project>
|
||||
@@ -17,7 +17,7 @@ public class BlockStorage {
|
||||
public BlockStorage() {
|
||||
this.bitsPerEntry = 4;
|
||||
|
||||
this.states = new ArrayList<Integer>();
|
||||
this.states = new ArrayList<>();
|
||||
this.states.add(0);
|
||||
|
||||
this.storage = new FlexibleStorage(this.bitsPerEntry, 4096);
|
||||
@@ -26,7 +26,7 @@ public class BlockStorage {
|
||||
public BlockStorage(ByteBuf in) throws IOException {
|
||||
this.bitsPerEntry = in.readUnsignedByte();
|
||||
|
||||
this.states = new ArrayList<Integer>();
|
||||
this.states = new ArrayList<>();
|
||||
int stateCount = PacketUtil.readVarInt(in);
|
||||
for (int i = 0; i < stateCount; i++) {
|
||||
this.states.add(PacketUtil.readVarInt(in));
|
||||
@@ -35,6 +35,10 @@ public class BlockStorage {
|
||||
this.storage = new FlexibleStorage(this.bitsPerEntry, PacketUtil.readLongs(PacketUtil.readVarInt(in), in));
|
||||
}
|
||||
|
||||
private static int index(int x, int y, int z) {
|
||||
return y << 8 | z << 4 | x;
|
||||
}
|
||||
|
||||
public void write(ByteBuf out) throws IOException {
|
||||
out.writeByte(this.bitsPerEntry);
|
||||
|
||||
@@ -78,7 +82,7 @@ public class BlockStorage {
|
||||
|
||||
List<Integer> oldStates = this.states;
|
||||
if (this.bitsPerEntry > 8) {
|
||||
oldStates = new ArrayList<Integer>(this.states);
|
||||
oldStates = new ArrayList<>(this.states);
|
||||
this.states.clear();
|
||||
this.bitsPerEntry = 13;
|
||||
}
|
||||
@@ -107,10 +111,6 @@ public class BlockStorage {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int index(int x, int y, int z) {
|
||||
return y << 8 | z << 4 | x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return this == o || (o instanceof BlockStorage && this.bitsPerEntry == ((BlockStorage) o).bitsPerEntry && this.states.equals(((BlockStorage) o).states) && this.storage.equals(((BlockStorage) o).storage));
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
package org.spacehq.mc.protocol.data.game.chunk;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class Column {
|
||||
private int x;
|
||||
private int z;
|
||||
@@ -23,9 +28,9 @@ public class Column {
|
||||
|
||||
this.skylight = false;
|
||||
boolean noSkylight = false;
|
||||
for(int index = 0; index < chunks.length; index++) {
|
||||
if(chunks[index] != null) {
|
||||
if(chunks[index].getSkyLight() == null) {
|
||||
for (Chunk chunk : chunks) {
|
||||
if (chunk != null) {
|
||||
if (chunk.getSkyLight() == null) {
|
||||
noSkylight = true;
|
||||
} else {
|
||||
this.skylight = true;
|
||||
@@ -43,26 +48,11 @@ public class Column {
|
||||
this.biomeData = biomeData;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return this.x;
|
||||
}
|
||||
|
||||
public int getZ() {
|
||||
return this.z;
|
||||
}
|
||||
|
||||
public Chunk[] getChunks() {
|
||||
return this.chunks;
|
||||
}
|
||||
|
||||
public boolean hasBiomeData() {
|
||||
return this.biomeData != null;
|
||||
}
|
||||
|
||||
public byte[] getBiomeData() {
|
||||
return this.biomeData;
|
||||
}
|
||||
|
||||
public boolean hasSkylight() {
|
||||
return this.skylight;
|
||||
}
|
||||
|
||||
@@ -18,19 +18,19 @@ public class NetUtil {
|
||||
public static int writeNewColumn(ByteBuf out, Column column, boolean fullChunk, boolean hasSkylight) throws IOException {
|
||||
int mask = 0;
|
||||
Chunk chunks[] = column.getChunks();
|
||||
for(int index = 0; index < chunks.length; index++) {
|
||||
for (int index = 0; index < chunks.length; index++) {
|
||||
Chunk chunk = chunks[index];
|
||||
if(chunk != null && (!fullChunk || !chunk.isEmpty())) {
|
||||
if (chunk != null && (!fullChunk || !chunk.isEmpty())) {
|
||||
mask |= 1 << index;
|
||||
chunk.getBlocks().write(out);
|
||||
chunk.getBlockLight().write(out);
|
||||
if(hasSkylight || column.hasSkylight()) {
|
||||
if (hasSkylight || column.hasSkylight()) {
|
||||
chunk.getSkyLight().write(out); // TODO: Make a PR to original lib to correct this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(fullChunk) {
|
||||
if (fullChunk && column.getBiomeData() != null) {
|
||||
out.writeBytes(column.getBiomeData());
|
||||
}
|
||||
|
||||
@@ -47,45 +47,47 @@ public class NetUtil {
|
||||
// 2 = Get block light.
|
||||
// 3 = Get sky light.
|
||||
Chunk[] chunks = new Chunk[16];
|
||||
|
||||
for(int pass = 0; pass < 4; pass++) {
|
||||
for(int ind = 0; ind < 16; ind++) {
|
||||
if((bitmask & 1 << ind) != 0) {
|
||||
if(pass == 0) {
|
||||
int chunkCount = 0;
|
||||
for (int pass = 0; pass < 4; pass++) {
|
||||
if(pass == 1){
|
||||
if(chunkCount == 0) return null;
|
||||
}
|
||||
for (int ind = 0; ind < 16; ind++) {
|
||||
if ((bitmask & 1 << ind) != 0) {
|
||||
if (pass == 0) {
|
||||
chunkCount++;
|
||||
// Block length + Blocklight length
|
||||
expected += (4096 * 2) + 2048;
|
||||
}
|
||||
|
||||
if(pass == 1) {
|
||||
if (pass == 1) {
|
||||
chunks[ind] = new Chunk(sky || hasSkyLight);
|
||||
|
||||
buf.position(pos / 2);
|
||||
short[] tempData = new short[4096];
|
||||
buf.get(tempData, 0, tempData.length);
|
||||
int buffPos = buf.position();
|
||||
// convert short array to new one
|
||||
int index = 0;
|
||||
for(short ss:tempData){
|
||||
|
||||
for (int index = 0; index < 4096; index++) {
|
||||
short ss = buf.get(buffPos + index);
|
||||
// s is 16 bits, 12 bits id and 4 bits data
|
||||
int data = ss & 0xF;
|
||||
int id = (ss >> 4) << 4 | data;
|
||||
|
||||
int newCombined = id ; // test
|
||||
int newCombined = id; // test
|
||||
|
||||
chunks[ind].getBlocks().set(index, newCombined);
|
||||
index++;
|
||||
}
|
||||
pos += tempData.length * 2;
|
||||
pos += 4096 * 2;
|
||||
|
||||
}
|
||||
|
||||
if(pass == 2) {
|
||||
if (pass == 2) {
|
||||
NibbleArray3d blocklight = chunks[ind].getBlockLight();
|
||||
System.arraycopy(input, pos, blocklight.getData(), 0, blocklight.getData().length);
|
||||
pos += blocklight.getData().length;
|
||||
}
|
||||
|
||||
if(pass == 3) {
|
||||
if(sky) {
|
||||
if (pass == 3) {
|
||||
if (sky) {
|
||||
NibbleArray3d skylight = chunks[ind].getSkyLight();
|
||||
System.arraycopy(input, pos, skylight.getData(), 0, skylight.getData().length);
|
||||
pos += skylight.getData().length;
|
||||
@@ -94,16 +96,17 @@ public class NetUtil {
|
||||
}
|
||||
}
|
||||
|
||||
if(pass == 0) {
|
||||
if (pass == 0) {
|
||||
// If we have more data than blocks and blocklight combined, there must be skylight data as well.
|
||||
if(input.length > expected) {
|
||||
if (input.length > expected) {
|
||||
sky = checkForSky;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,59 +1,59 @@
|
||||
package us.myles.ViaVersion;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import us.myles.ViaVersion.packets.State;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class ConnectionInfo {
|
||||
private int protocol = 0;
|
||||
private State state = State.HANDSHAKE;
|
||||
private int compression = 0;
|
||||
private final SocketChannel channel;
|
||||
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 int entityID;
|
||||
private boolean active = true;
|
||||
private String username;
|
||||
|
||||
public int getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public void setProtocol(int protocol) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
public State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(State state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public void setCompression(int compression) {
|
||||
this.compression = compression;
|
||||
}
|
||||
|
||||
public int getCompression() {
|
||||
return compression;
|
||||
}
|
||||
|
||||
public void setLastPacket(Object lastPacket) {
|
||||
this.lastPacket = lastPacket;
|
||||
}
|
||||
|
||||
public Object getLastPacket() {
|
||||
return lastPacket;
|
||||
}
|
||||
|
||||
public void setUUID(UUID UUID) {
|
||||
this.UUID = UUID;
|
||||
}
|
||||
|
||||
public java.util.UUID getUUID() {
|
||||
return UUID;
|
||||
public ConnectionInfo(SocketChannel socketChannel) {
|
||||
this.channel = socketChannel;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return UUID == null ? null : Bukkit.getPlayer(UUID);
|
||||
}
|
||||
|
||||
public void setActive(boolean active) {
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
public void sendRawPacket(final ByteBuf packet, boolean currentThread) {
|
||||
final ChannelHandler handler = channel.pipeline().get("encoder");
|
||||
if (currentThread) {
|
||||
channel.pipeline().context(handler).writeAndFlush(packet);
|
||||
} else {
|
||||
channel.eventLoop().submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
channel.pipeline().context(handler).writeAndFlush(packet);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void sendRawPacket(final ByteBuf packet) {
|
||||
sendRawPacket(packet, false);
|
||||
}
|
||||
|
||||
public void closeWindow() {
|
||||
this.openWindow = null;
|
||||
}
|
||||
}
|
||||
@@ -1,114 +1,50 @@
|
||||
package us.myles.ViaVersion;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
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.api.boss.BossBar;
|
||||
import us.myles.ViaVersion.api.boss.BossColor;
|
||||
import us.myles.ViaVersion.api.boss.BossStyle;
|
||||
import us.myles.ViaVersion.armor.ArmorListener;
|
||||
import us.myles.ViaVersion.boss.ViaBossBar;
|
||||
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.ListWrapper;
|
||||
import us.myles.ViaVersion.util.ReflectionUtil;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
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>());
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
ViaVersion.setInstance(this);
|
||||
System.out.println("ViaVersion enabled, injecting. (Allows 1.8 to be accessed via 1.9)");
|
||||
try {
|
||||
injectPacketHandler();
|
||||
} catch (Exception e) {
|
||||
if(Bukkit.getPluginManager().getPlugin("ProtocolLib") != null){
|
||||
System.out.println("This plugin is not compatible with protocol lib.");
|
||||
}
|
||||
System.out.println("Unable to inject handlers, are you on 1.8? ");
|
||||
e.printStackTrace();
|
||||
}
|
||||
Bukkit.getPluginManager().registerEvents(new Listener() {
|
||||
@EventHandler
|
||||
public void onPlayerQuit(PlayerQuitEvent e) {
|
||||
setPorted(e.getPlayer().getUniqueId(), false);
|
||||
}
|
||||
}, 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 (late bind?)");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPorted(Player player) {
|
||||
return portedPlayers.contains(player.getUniqueId());
|
||||
}
|
||||
|
||||
public void setPorted(UUID id, boolean value) {
|
||||
if (value) {
|
||||
portedPlayers.add(id);
|
||||
} else {
|
||||
portedPlayers.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
public static Entity getEntity(final UUID player, final int id) {
|
||||
try {
|
||||
return Bukkit.getScheduler().callSyncMethod(getPlugin(ViaVersionPlugin.class), new Callable<Entity>() {
|
||||
@Override
|
||||
public Entity call() throws Exception {
|
||||
Player p = Bukkit.getPlayer(player);
|
||||
if (p == null) return null;
|
||||
for (Entity e : p.getWorld().getEntities()) {
|
||||
if (e.getEntityId() == id) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}).get(10, TimeUnit.SECONDS);
|
||||
} catch (Exception e) {
|
||||
System.out.println("Error fetching entity ");
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
private final Map<UUID, ConnectionInfo> portedPlayers = new ConcurrentHashMap<>();
|
||||
private boolean debug = false;
|
||||
|
||||
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) {
|
||||
@@ -118,9 +54,211 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
|
||||
}
|
||||
}).get(10, TimeUnit.SECONDS);
|
||||
} catch (Exception e) {
|
||||
System.out.println("Error fetching hand item ");
|
||||
e.printStackTrace();
|
||||
System.out.println("Error fetching hand item: " + e.getClass().getName());
|
||||
if (ViaVersion.getInstance().isDebug())
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
ViaVersion.setInstance(this);
|
||||
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 " + getDescription().getVersion() + " is now enabled, injecting. (Allows 1.8 to be accessed via 1.9)");
|
||||
injectPacketHandler();
|
||||
|
||||
if (getConfig().getBoolean("checkforupdates"))
|
||||
UpdateUtil.sendUpdateMessage(this);
|
||||
|
||||
Bukkit.getPluginManager().registerEvents(new Listener() {
|
||||
@EventHandler
|
||||
public void onPlayerQuit(PlayerQuitEvent e) {
|
||||
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() {
|
||||
try {
|
||||
Class<?> serverClazz = ReflectionUtil.nms("MinecraftServer");
|
||||
Object server = ReflectionUtil.invokeStatic(serverClazz, "getServer");
|
||||
Object connection = serverClazz.getDeclaredMethod("getServerConnection").invoke(server);
|
||||
if (connection == null) {
|
||||
System.out.println("connection is null!!");
|
||||
//try others
|
||||
for (Method m : serverClazz.getDeclaredMethods()) {
|
||||
if (m.getReturnType() != null && !m.getName().equals("getServerConnection")) {
|
||||
if (m.getReturnType().getSimpleName().equals("ServerConnection")) {
|
||||
if (m.getParameterTypes().length == 0) {
|
||||
connection = m.invoke(server);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (connection == null) {
|
||||
getLogger().warning("We failed to find the ServerConnection? :(");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (connection != null) {
|
||||
for (Field field : connection.getClass().getDeclaredFields()) {
|
||||
field.setAccessible(true);
|
||||
final Object value = field.get(connection);
|
||||
if (value instanceof List) {
|
||||
// Inject the list
|
||||
field.set(connection, new ListWrapper((List) value) {
|
||||
@Override
|
||||
public void handleAdd(Object o) {
|
||||
synchronized (value) {
|
||||
if (o instanceof ChannelFuture) {
|
||||
inject((ChannelFuture) o);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
// Iterate through current list
|
||||
synchronized (value) {
|
||||
for (Object o : (List) value) {
|
||||
if (o instanceof ChannelFuture) {
|
||||
inject((ChannelFuture) o);
|
||||
} else {
|
||||
break; // not the right list.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
System.setProperty("ViaVersion", getDescription().getVersion());
|
||||
} catch (Exception e) {
|
||||
getLogger().severe("Unable to inject handlers, are you on 1.8? ");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void inject(ChannelFuture future) {
|
||||
try {
|
||||
ChannelHandler bootstrapAcceptor = future.channel().pipeline().first();
|
||||
try {
|
||||
ChannelInitializer<SocketChannel> oldInit = ReflectionUtil.get(bootstrapAcceptor, "childHandler", ChannelInitializer.class);
|
||||
ChannelInitializer newInit = new ViaVersionInitializer(oldInit);
|
||||
|
||||
ReflectionUtil.set(bootstrapAcceptor, "childHandler", newInit);
|
||||
} catch (NoSuchFieldException e) {
|
||||
// field not found
|
||||
throw new Exception("Unable to find childHandler, blame " + bootstrapAcceptor.getClass().getName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
getLogger().severe("Have you got late-bind enabled with something else? (ProtocolLib?)");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPorted(Player player) {
|
||||
return isPorted(player.getUniqueId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPorted(UUID playerUUID) {
|
||||
return portedPlayers.containsKey(playerUUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return getDescription().getVersion();
|
||||
}
|
||||
|
||||
public void sendRawPacket(Player player, ByteBuf packet) throws IllegalArgumentException {
|
||||
sendRawPacket(player.getUniqueId(), packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendRawPacket(UUID uuid, ByteBuf packet) throws IllegalArgumentException {
|
||||
if (!isPorted(uuid)) throw new IllegalArgumentException("This player is not on 1.9");
|
||||
ConnectionInfo ci = portedPlayers.get(uuid);
|
||||
ci.sendRawPacket(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BossBar createBossBar(String title, BossColor color, BossStyle style) {
|
||||
return new ViaBossBar(title, 1F, color, style);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BossBar createBossBar(String title, float health, BossColor color, BossStyle style) {
|
||||
return new ViaBossBar(title, health, color, style);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebug() {
|
||||
return this.debug;
|
||||
}
|
||||
|
||||
public void setDebug(boolean value) {
|
||||
this.debug = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSyncedChunks() {
|
||||
return getConfig().getBoolean("sync-chunks", true);
|
||||
}
|
||||
|
||||
public boolean isPreventCollision() {
|
||||
return getConfig().getBoolean("prevent-collision", true);
|
||||
}
|
||||
|
||||
public boolean isSuppressMetadataErrors() {
|
||||
return getConfig().getBoolean("suppress-metadata-errors", false);
|
||||
}
|
||||
|
||||
public boolean isShieldBlocking() {
|
||||
return getConfig().getBoolean("shield-blocking", true);
|
||||
}
|
||||
|
||||
public boolean isAutoTeam() {
|
||||
// Collision has to be enabled first
|
||||
if (!isPreventCollision()) return false;
|
||||
return getConfig().getBoolean("auto-team", true);
|
||||
}
|
||||
|
||||
public void addPortedClient(ConnectionInfo info) {
|
||||
portedPlayers.put(info.getUUID(), info);
|
||||
}
|
||||
|
||||
public void removePortedClient(UUID clientID) {
|
||||
portedPlayers.remove(clientID);
|
||||
}
|
||||
|
||||
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.getClass().getName());
|
||||
if (ViaVersion.getInstance().isDebug())
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,11 @@
|
||||
package us.myles.ViaVersion.api;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class ViaVersion {
|
||||
|
||||
private static ViaVersionAPI INSTANCE;
|
||||
|
||||
public static void setInstance(ViaVersionAPI api) {
|
||||
if (INSTANCE != null) {
|
||||
throw new IllegalStateException("Instance already set.");
|
||||
}
|
||||
INSTANCE = api;
|
||||
}
|
||||
|
||||
public static ViaVersionAPI getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
@Getter
|
||||
@Setter
|
||||
private static ViaVersionAPI instance;
|
||||
}
|
||||
@@ -1,8 +1,87 @@
|
||||
package us.myles.ViaVersion.api;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.bukkit.entity.Player;
|
||||
import us.myles.ViaVersion.api.boss.BossBar;
|
||||
import us.myles.ViaVersion.api.boss.BossColor;
|
||||
import us.myles.ViaVersion.api.boss.BossStyle;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public interface ViaVersionAPI {
|
||||
|
||||
/**
|
||||
* Is player using 1.9?
|
||||
*
|
||||
* @param player
|
||||
* @return True if the client is on 1.9
|
||||
*/
|
||||
boolean isPorted(Player player);
|
||||
|
||||
/**
|
||||
* Is player using 1.9?
|
||||
*
|
||||
* @param playerUUID
|
||||
* @return True if the client is on 1.9
|
||||
*/
|
||||
boolean isPorted(UUID playerUUID);
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Send a raw packet to the player (Use new IDs)
|
||||
*
|
||||
* @param uuid The uuid from 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(UUID uuid, ByteBuf packet) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Create a new bossbar instance
|
||||
*
|
||||
* @param title The title
|
||||
* @param color The color
|
||||
* @param style The style
|
||||
* @return Bossbar instance
|
||||
*/
|
||||
BossBar createBossBar(String title, BossColor color, BossStyle style);
|
||||
|
||||
/**
|
||||
* Create a new bossbar instance
|
||||
*
|
||||
* @param title The title
|
||||
* @param health Number between 0 and 1
|
||||
* @param color The color
|
||||
* @param style The style
|
||||
* @return Bossbar instance
|
||||
*/
|
||||
BossBar createBossBar(String title, float health, BossColor color, BossStyle style);
|
||||
|
||||
/**
|
||||
* 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,122 @@
|
||||
package us.myles.ViaVersion.api.boss;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface BossBar {
|
||||
/**
|
||||
* Change the title
|
||||
*
|
||||
* @param title Title can be in either JSON or just text
|
||||
*/
|
||||
void setTitle(String title);
|
||||
|
||||
/**
|
||||
* Get the current title
|
||||
*
|
||||
* @return the title
|
||||
*/
|
||||
String getTitle();
|
||||
|
||||
/**
|
||||
* Change the health
|
||||
*
|
||||
* @param health this float has to be between 0F - 1F
|
||||
*/
|
||||
void setHealth(float health);
|
||||
|
||||
/**
|
||||
* Get the health
|
||||
*
|
||||
* @return float between 0F - 1F
|
||||
*/
|
||||
float getHealth();
|
||||
|
||||
/**
|
||||
* Yay colors!
|
||||
*
|
||||
* @param color Whatever color you want!
|
||||
*/
|
||||
void setColor(BossColor color);
|
||||
|
||||
/**
|
||||
* Get the bossbar color
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
BossColor getColor();
|
||||
|
||||
/**
|
||||
* Change the bosbar style
|
||||
*
|
||||
* @param style BossStyle
|
||||
*/
|
||||
void setStyle(BossStyle style);
|
||||
|
||||
/**
|
||||
* Get the bosbar style
|
||||
*
|
||||
* @return BossStyle
|
||||
*/
|
||||
BossStyle getStyle();
|
||||
|
||||
/**
|
||||
* Show the bossbar to a player.
|
||||
*
|
||||
* @param player
|
||||
*/
|
||||
void addPlayer(Player player);
|
||||
|
||||
/**
|
||||
* Remove the bossbar from a player
|
||||
*
|
||||
* @param player
|
||||
*/
|
||||
void removePlayer(Player player);
|
||||
|
||||
/**
|
||||
* Add flags
|
||||
*
|
||||
* @param flag
|
||||
*/
|
||||
void addFlag(BossFlag flag);
|
||||
|
||||
/**
|
||||
* Remove flags.
|
||||
*
|
||||
* @param flag
|
||||
*/
|
||||
void removeFlag(BossFlag flag);
|
||||
|
||||
/**
|
||||
* @param flag
|
||||
* @return
|
||||
*/
|
||||
boolean hasFlag(BossFlag flag);
|
||||
|
||||
/**
|
||||
* Get players
|
||||
*
|
||||
* @return UUIDS from players (sorry I lied)
|
||||
*/
|
||||
Set<UUID> getPlayers();
|
||||
|
||||
/**
|
||||
* Show the bossbar to everyone (In the getPlayer set)
|
||||
*/
|
||||
void show();
|
||||
|
||||
/**
|
||||
* Hide the bossbar from everyone (In the getPlayer set)
|
||||
*/
|
||||
void hide();
|
||||
|
||||
/**
|
||||
* Is it visible?
|
||||
*
|
||||
* @return visibility changable with show() and hide()
|
||||
*/
|
||||
boolean isVisible();
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package us.myles.ViaVersion.api.boss;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum BossColor {
|
||||
PINK(0),
|
||||
BLUE(1),
|
||||
RED(2),
|
||||
GREEN(3),
|
||||
YELLOW(4),
|
||||
PURPLE(5),
|
||||
WHITE(6);
|
||||
|
||||
private final int id;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package us.myles.ViaVersion.api.boss;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum BossFlag {
|
||||
DARKEN_SKY(1),
|
||||
PLAY_BOSS_MUSIC(2);
|
||||
|
||||
private final int id;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package us.myles.ViaVersion.api.boss;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum BossStyle {
|
||||
SOLID(0),
|
||||
SEGMENTED_6(1),
|
||||
SEGMENTED_10(2),
|
||||
SEGMENTED_12(3),
|
||||
SEGMENTED_20(4);
|
||||
|
||||
private final int id;
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package us.myles.ViaVersion.armor;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
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.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.*;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class ArmorListener implements Listener {
|
||||
|
||||
private static final UUID ARMOR_ATTRIBUTE = UUID.fromString("2AD3F246-FEE1-4E67-B886-69FD380BB150");
|
||||
private final ViaVersionPlugin plugin;
|
||||
|
||||
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(ARMOR_ATTRIBUTE, 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);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package us.myles.ViaVersion.armor;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
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 final int armorPoints;
|
||||
private final int id;
|
||||
private final Material 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 (ItemStack anArmor : armor) {
|
||||
if (anArmor != null)
|
||||
total += findByType(anArmor.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 anArmor : armor) {
|
||||
if (anArmor != -1)
|
||||
total += findById(anArmor).getArmorPoints();
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Material getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
package us.myles.ViaVersion.boss;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.entity.Player;
|
||||
import us.myles.ViaVersion.api.ViaVersion;
|
||||
import us.myles.ViaVersion.api.boss.BossBar;
|
||||
import us.myles.ViaVersion.api.boss.BossColor;
|
||||
import us.myles.ViaVersion.api.boss.BossFlag;
|
||||
import us.myles.ViaVersion.api.boss.BossStyle;
|
||||
import us.myles.ViaVersion.packets.PacketType;
|
||||
import us.myles.ViaVersion.transformers.OutgoingTransformer;
|
||||
import us.myles.ViaVersion.util.PacketUtil;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@Getter
|
||||
public class ViaBossBar implements BossBar {
|
||||
private UUID uuid;
|
||||
private String title;
|
||||
private float health;
|
||||
private BossColor color;
|
||||
private BossStyle style;
|
||||
private Set<UUID> players;
|
||||
private boolean visible;
|
||||
private Set<BossFlag> flags;
|
||||
|
||||
public ViaBossBar(String title, float health, BossColor color, BossStyle style) {
|
||||
Validate.notNull(title, "Title cannot be null");
|
||||
Validate.isTrue((health >= 0 && health <= 1), "Health must be between 0 and 1");
|
||||
this.uuid = UUID.randomUUID();
|
||||
this.title = title;
|
||||
this.health = health;
|
||||
this.color = color == null ? BossColor.PURPLE : color;
|
||||
this.style = style == null ? BossStyle.SOLID : style;
|
||||
this.players = new HashSet<>();
|
||||
this.flags = new HashSet<>();
|
||||
visible = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(String title) {
|
||||
Validate.notNull(title, "Title cannot be null");
|
||||
this.title = title;
|
||||
sendPacket(UpdateAction.UPDATE_TITLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHealth(float health) {
|
||||
Validate.isTrue((health >= 0 && health <= 1), "Health must be between 0 and 1");
|
||||
this.health = health;
|
||||
sendPacket(UpdateAction.UPDATE_HEALTH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BossColor getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColor(BossColor color) {
|
||||
Validate.notNull(color, "Color cannot be null");
|
||||
this.color = color;
|
||||
sendPacket(UpdateAction.UPDATE_STYLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStyle(BossStyle style) {
|
||||
Validate.notNull(style, "Style cannot be null");
|
||||
this.style = style;
|
||||
sendPacket(UpdateAction.UPDATE_STYLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPlayer(Player player) {
|
||||
if (player != null && !players.contains(player.getUniqueId())) {
|
||||
players.add(player.getUniqueId());
|
||||
if (visible)
|
||||
sendPacket(player.getUniqueId(), getPacket(UpdateAction.ADD));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePlayer(Player player) {
|
||||
if (player != null && players.contains(player.getUniqueId())) {
|
||||
players.remove(player.getUniqueId());
|
||||
sendPacket(player.getUniqueId(), getPacket(UpdateAction.REMOVE));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFlag(BossFlag flag) {
|
||||
if (!hasFlag(flag))
|
||||
flags.add(flag);
|
||||
sendPacket(UpdateAction.UPDATE_FLAGS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFlag(BossFlag flag) {
|
||||
if (hasFlag(flag))
|
||||
flags.remove(flag);
|
||||
sendPacket(UpdateAction.UPDATE_FLAGS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFlag(BossFlag flag) {
|
||||
return flags.contains(flag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> getPlayers() {
|
||||
return Collections.unmodifiableSet(players);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide() {
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible() {
|
||||
return visible;
|
||||
}
|
||||
|
||||
private void setVisible(boolean value) {
|
||||
if (visible != value) {
|
||||
visible = value;
|
||||
sendPacket(value ? UpdateAction.ADD : UpdateAction.REMOVE);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendPacket(UpdateAction action) {
|
||||
ByteBuf buf = getPacket(action);
|
||||
for (UUID uuid : players)
|
||||
sendPacket(uuid, buf);
|
||||
}
|
||||
|
||||
private void sendPacket(UUID uuid, ByteBuf buf) {
|
||||
if (!ViaVersion.getInstance().isPorted(uuid)) {
|
||||
players.remove(uuid);
|
||||
return;
|
||||
}
|
||||
ViaVersion.getInstance().sendRawPacket(uuid, buf);
|
||||
}
|
||||
|
||||
private ByteBuf getPacket(UpdateAction action) {
|
||||
ByteBuf buf = Unpooled.buffer();
|
||||
PacketUtil.writeVarInt(PacketType.PLAY_BOSS_BAR.getNewPacketID(), buf);
|
||||
PacketUtil.writeUUID(uuid, buf);
|
||||
PacketUtil.writeVarInt(action.getId(), buf);
|
||||
switch (action) {
|
||||
case ADD:
|
||||
PacketUtil.writeString(fixJson(title), buf);
|
||||
buf.writeFloat(health);
|
||||
PacketUtil.writeVarInt(color.getId(), buf);
|
||||
PacketUtil.writeVarInt(style.getId(), buf);
|
||||
buf.writeByte(flagToBytes());
|
||||
break;
|
||||
case REMOVE:
|
||||
break;
|
||||
case UPDATE_HEALTH:
|
||||
buf.writeFloat(health);
|
||||
break;
|
||||
case UPDATE_TITLE:
|
||||
PacketUtil.writeString(fixJson(title), buf);
|
||||
break;
|
||||
case UPDATE_STYLE:
|
||||
PacketUtil.writeVarInt(color.getId(), buf);
|
||||
PacketUtil.writeVarInt(style.getId(), buf);
|
||||
break;
|
||||
case UPDATE_FLAGS:
|
||||
buf.writeByte(flagToBytes());
|
||||
break;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
private int flagToBytes() {
|
||||
int bitmask = 0;
|
||||
for (BossFlag flag : flags)
|
||||
bitmask |= flag.getId();
|
||||
return bitmask;
|
||||
}
|
||||
|
||||
private String fixJson(String text) {
|
||||
return OutgoingTransformer.fixJson(text);
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
private enum UpdateAction {
|
||||
ADD(0),
|
||||
REMOVE(1),
|
||||
UPDATE_HEALTH(2),
|
||||
UPDATE_TITLE(3),
|
||||
UPDATE_STYLE(4),
|
||||
UPDATE_FLAGS(5);
|
||||
|
||||
private final int id;
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package us.myles.ViaVersion.chunks;
|
||||
|
||||
public class ByteWriter {
|
||||
private final byte[] bytes;
|
||||
private int byteIndex;
|
||||
private int bitIndex;
|
||||
|
||||
public ByteWriter(int size) {
|
||||
this.bytes = new byte[size];
|
||||
this.byteIndex = 0;
|
||||
this.bitIndex = 0;
|
||||
}
|
||||
|
||||
public byte[] getOutput() {
|
||||
return this.bytes;
|
||||
}
|
||||
|
||||
public void writeFullByte(int b){
|
||||
writeByte(b, 8);
|
||||
}
|
||||
|
||||
public void writeByte(int b, int length) {
|
||||
byte current = getCurrentByte();
|
||||
byte byteB = (byte)(int)((b) & 0xff);
|
||||
System.out.println("Input: " + byteB);
|
||||
System.out.println(Integer.toBinaryString(byteB));
|
||||
|
||||
int space = (8 - bitIndex);
|
||||
int written = space > length ? length : space;
|
||||
System.out.println("Written is " + written);
|
||||
bytes[byteIndex] = (byte) (current | (extractRange(byteB, 0, written) >> (bitIndex - 1)));
|
||||
System.out.println("output value: " + bytes[byteIndex]);
|
||||
this.bitIndex += length;
|
||||
if(this.bitIndex >= 8) {
|
||||
this.byteIndex += 1;
|
||||
this.bitIndex = bitIndex - 8;
|
||||
// write remaining into this
|
||||
System.out.println("Writing from " + written + " to " + (written + bitIndex));
|
||||
System.out.println("Value: " + extractRange(byteB, written, written + bitIndex));
|
||||
bytes[byteIndex] = (byte) (extractRange(byteB, written, written + bitIndex) << written);
|
||||
}
|
||||
}
|
||||
|
||||
private byte extractRange(int in, int begin, int end){
|
||||
return (byte) ((in >> begin) & ((1 << (end - begin)) - 1));
|
||||
}
|
||||
public byte getCurrentByte() {
|
||||
if(byteIndex == bytes.length) throw new RuntimeException("ByteWriter overflow!");
|
||||
|
||||
return bytes[byteIndex];
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package us.myles.ViaVersion.chunks;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
public class MagicBitSet extends BitSet{
|
||||
private final int initLength;
|
||||
|
||||
public MagicBitSet(int nbits) {
|
||||
super(nbits);
|
||||
this.initLength = nbits;
|
||||
}
|
||||
|
||||
public int getTrueLength() {
|
||||
return length() == 0 ? initLength : length();
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package us.myles.ViaVersion.chunks;
|
||||
|
||||
public class PacketChunk {
|
||||
private PacketChunkData[] chunkData;
|
||||
private byte[] biomeData;
|
||||
|
||||
public PacketChunk(PacketChunkData[] chunkData, byte[] biomeData) {
|
||||
this.chunkData = chunkData;
|
||||
this.biomeData = biomeData;
|
||||
}
|
||||
|
||||
public PacketChunkData[] getChunkData() {
|
||||
return chunkData;
|
||||
}
|
||||
|
||||
public byte[] getBiomeData() {
|
||||
return biomeData;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package us.myles.ViaVersion.chunks;
|
||||
|
||||
public class PacketChunkData {
|
||||
private short[] blocks = new short[4096];
|
||||
private byte[] blockLight = new byte[2048];
|
||||
private byte[] skyLight;
|
||||
|
||||
public PacketChunkData(boolean isSkyLightData) {
|
||||
if(isSkyLightData){
|
||||
skyLight = new byte[2048];
|
||||
}
|
||||
}
|
||||
|
||||
public short[] getBlocks() {
|
||||
return this.blocks;
|
||||
}
|
||||
|
||||
public byte[] getBlockLight() {
|
||||
return this.blockLight;
|
||||
}
|
||||
|
||||
public byte[] getSkyLight() {
|
||||
return this.skyLight;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package us.myles.ViaVersion.commands;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
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.
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class ViaVersionCommand implements CommandExecutor {
|
||||
|
||||
private final ViaVersionPlugin plugin;
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
|
||||
if (sender.hasPermission("viaversion.admin")) {
|
||||
if (args.length == 0) {
|
||||
sendHelp(sender);
|
||||
} else if (args.length == 1) {
|
||||
if (args[0].equalsIgnoreCase("list")) {
|
||||
List<String> portedPlayers = new ArrayList<>();
|
||||
List<String> normalPlayers = new ArrayList<>();
|
||||
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()));
|
||||
} else if (args[0].equalsIgnoreCase("debug")) {
|
||||
plugin.setDebug(!plugin.isDebug());
|
||||
sender.sendMessage(color("&6Debug mode is now " + (plugin.isDebug() ? "&aenabled" : "&cdisabled")));
|
||||
} else 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.")));
|
||||
} else if (args[0].equalsIgnoreCase("autoteam")) {
|
||||
boolean newValue = !plugin.getConfig().getBoolean("auto-team", true);
|
||||
plugin.getConfig().set("auto-team", newValue);
|
||||
plugin.saveConfig();
|
||||
sender.sendMessage(color("&6We will " + (newValue ? "&aautomatically team players" : "&cno longer auto team players")));
|
||||
sender.sendMessage(color("&6All players will need to re-login for the change to take place."));
|
||||
} else {
|
||||
sendHelp(sender);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void sendHelp(CommandSender sender){
|
||||
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 debug &7- &6Toggle debug mode"));
|
||||
sender.sendMessage(color("&2/viaversion autoteam &7- &6Toggle automatically teaming to prevent colliding."));
|
||||
sender.sendMessage(color("&2/viaversion dontbugme &7- &6Toggle checking for updates."));
|
||||
}
|
||||
|
||||
public String color(String string) {
|
||||
return string.replace("&", "§");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package us.myles.ViaVersion.handlers;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import us.myles.ViaVersion.CancelException;
|
||||
import us.myles.ViaVersion.ConnectionInfo;
|
||||
import us.myles.ViaVersion.transformers.IncomingTransformer;
|
||||
import us.myles.ViaVersion.util.PacketUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ViaDecodeHandler extends ByteToMessageDecoder {
|
||||
|
||||
private final IncomingTransformer incomingTransformer;
|
||||
private final ByteToMessageDecoder minecraftDecoder;
|
||||
private final ConnectionInfo info;
|
||||
|
||||
public ViaDecodeHandler(ConnectionInfo info, ByteToMessageDecoder minecraftDecoder) {
|
||||
this.info = info;
|
||||
this.minecraftDecoder = minecraftDecoder;
|
||||
this.incomingTransformer = new IncomingTransformer(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> list) throws Exception {
|
||||
// use transformers
|
||||
if (bytebuf.readableBytes() > 0) {
|
||||
if (info.isActive()) {
|
||||
int id = PacketUtil.readVarInt(bytebuf);
|
||||
// Transform
|
||||
ByteBuf newPacket = ctx.alloc().buffer();
|
||||
try {
|
||||
incomingTransformer.transform(id, bytebuf, newPacket);
|
||||
bytebuf.clear();
|
||||
bytebuf = newPacket;
|
||||
} catch (Exception e) {
|
||||
bytebuf.clear();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
// call minecraft decoder
|
||||
list.addAll(PacketUtil.callDecode(this.minecraftDecoder, ctx, bytebuf));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
if (PacketUtil.containsCause(cause, CancelException.class)) return;
|
||||
super.exceptionCaught(ctx, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package us.myles.ViaVersion.handlers;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
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.transformers.OutgoingTransformer;
|
||||
import us.myles.ViaVersion.util.PacketUtil;
|
||||
import us.myles.ViaVersion.util.ReflectionUtil;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
public class ViaEncodeHandler extends MessageToByteEncoder {
|
||||
private final ConnectionInfo info;
|
||||
private final MessageToByteEncoder minecraftEncoder;
|
||||
private final OutgoingTransformer outgoingTransformer;
|
||||
|
||||
public ViaEncodeHandler(ConnectionInfo info, MessageToByteEncoder minecraftEncoder) {
|
||||
this.info = info;
|
||||
this.minecraftEncoder = minecraftEncoder;
|
||||
this.outgoingTransformer = new OutgoingTransformer(info);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
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()) {
|
||||
final int[] locX = ReflectionUtil.get(o, "a", int[].class);
|
||||
final int[] locZ = ReflectionUtil.get(o, "b", int[].class);
|
||||
|
||||
final Object world = ReflectionUtil.get(o, "world", ReflectionUtil.nms("World"));
|
||||
Class<?> mapChunk = ReflectionUtil.nms("PacketPlayOutMapChunk");
|
||||
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 | InvocationTargetException | ClassNotFoundException | IllegalAccessException | NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
chunks.run();
|
||||
bytebuf.clear();
|
||||
throw new CancelException();
|
||||
}
|
||||
// call minecraft encoder
|
||||
PacketUtil.callEncode(this.minecraftEncoder, ctx, o, bytebuf);
|
||||
}
|
||||
if (bytebuf.readableBytes() == 0) {
|
||||
throw new CancelException();
|
||||
}
|
||||
if (info.isActive()) {
|
||||
int id = PacketUtil.readVarInt(bytebuf);
|
||||
// Transform
|
||||
ByteBuf oldPacket = bytebuf.copy();
|
||||
bytebuf.clear();
|
||||
try {
|
||||
outgoingTransformer.transform(id, oldPacket, bytebuf);
|
||||
} catch (Exception e) {
|
||||
bytebuf.clear();
|
||||
throw e;
|
||||
} finally {
|
||||
oldPacket.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
if (PacketUtil.containsCause(cause, CancelException.class)) return;
|
||||
super.exceptionCaught(ctx, cause);
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package us.myles.ViaVersion.handlers;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import us.myles.ViaVersion.CancelException;
|
||||
import us.myles.ViaVersion.ConnectionInfo;
|
||||
import us.myles.ViaVersion.util.PacketUtil;
|
||||
import us.myles.ViaVersion.transformers.IncomingTransformer;
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
public class ViaInboundHandler extends ChannelInboundHandlerAdapter {
|
||||
private final IncomingTransformer incomingTransformer;
|
||||
private final ViaVersionInitializer init;
|
||||
|
||||
public ViaInboundHandler(Channel c, ConnectionInfo info, ViaVersionInitializer init) {
|
||||
this.init = init;
|
||||
this.incomingTransformer = new IncomingTransformer(c, info, init);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
boolean compression = ctx.pipeline().get("compress") != null;
|
||||
|
||||
if (msg instanceof ByteBuf) {
|
||||
ByteBuf bytebuf = (ByteBuf) msg;
|
||||
if (compression) {
|
||||
// decompress :)
|
||||
bytebuf = PacketUtil.decompress(ctx, bytebuf);
|
||||
}
|
||||
int id = PacketUtil.readVarInt(bytebuf);
|
||||
// Transform
|
||||
ByteBuf newPacket = ctx.alloc().buffer();
|
||||
try {
|
||||
incomingTransformer.transform(id, bytebuf, newPacket);
|
||||
} catch (CancelException e) {
|
||||
return;
|
||||
} finally {
|
||||
bytebuf.release();
|
||||
}
|
||||
if (compression) {
|
||||
// recompress :)
|
||||
newPacket = PacketUtil.compress(ctx, newPacket);
|
||||
}
|
||||
msg = newPacket;
|
||||
}
|
||||
super.channelRead(ctx, msg);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package us.myles.ViaVersion.handlers;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.*;
|
||||
import us.myles.ViaVersion.CancelException;
|
||||
import us.myles.ViaVersion.ConnectionInfo;
|
||||
import us.myles.ViaVersion.util.PacketUtil;
|
||||
import us.myles.ViaVersion.transformers.OutgoingTransformer;
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
public class ViaOutboundHandler extends ChannelOutboundHandlerAdapter {
|
||||
private final OutgoingTransformer outgoingTransformer;
|
||||
private final ViaVersionInitializer init;
|
||||
|
||||
public ViaOutboundHandler(Channel c, ConnectionInfo info, ViaVersionInitializer init) {
|
||||
this.init = init;
|
||||
this.outgoingTransformer = new OutgoingTransformer(c, info, init);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise channelPromise) throws Exception {
|
||||
try {
|
||||
if (channelPromise.isDone()) return; // don't break any <3s
|
||||
boolean compression = ctx.pipeline().get("compress") != null;
|
||||
if (msg instanceof ByteBuf) {
|
||||
ByteBuf bytebuf = (ByteBuf) msg;
|
||||
if (compression) {
|
||||
// decompress :)
|
||||
bytebuf = PacketUtil.decompress(ctx, bytebuf);
|
||||
}
|
||||
int id = PacketUtil.readVarInt(bytebuf);
|
||||
// Transform
|
||||
ByteBuf newPacket = ctx.alloc().buffer();
|
||||
try {
|
||||
outgoingTransformer.transform(id, bytebuf, newPacket);
|
||||
} catch (CancelException e) {
|
||||
return;
|
||||
} finally {
|
||||
bytebuf.release();
|
||||
}
|
||||
if (compression) {
|
||||
// recompress :)
|
||||
newPacket = PacketUtil.compress(ctx, newPacket);
|
||||
}
|
||||
msg = newPacket;
|
||||
}
|
||||
super.write(ctx, msg, channelPromise);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package us.myles.ViaVersion.handlers;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.*;
|
||||
import us.myles.ViaVersion.ConnectionInfo;
|
||||
import us.myles.ViaVersion.util.ReflectionUtil;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
public class ViaOutboundPacketHandler extends ChannelOutboundHandlerAdapter {
|
||||
private final ConnectionInfo info;
|
||||
|
||||
public ViaOutboundPacketHandler(Channel c, ConnectionInfo info) {
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ChannelHandlerContext channelHandlerContext, Object o, ChannelPromise channelPromise) throws Exception {
|
||||
if (!(o instanceof ByteBuf)) {
|
||||
info.setLastPacket(o);
|
||||
/* This transformer is more for fixing issues which we find hard at byte level :) */
|
||||
if (o.getClass().getName().endsWith("PacketPlayOutMapChunkBulk")) {
|
||||
int[] locX = ReflectionUtil.get(o, "a", int[].class);
|
||||
int[] locZ = ReflectionUtil.get(o, "b", int[].class);
|
||||
|
||||
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);
|
||||
channelHandlerContext.write(packet);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.write(channelHandlerContext, o, channelPromise);
|
||||
}
|
||||
}
|
||||
@@ -3,18 +3,16 @@ package us.myles.ViaVersion.handlers;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import us.myles.ViaVersion.ConnectionInfo;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class ViaVersionInitializer extends ChannelInitializer<SocketChannel> {
|
||||
|
||||
private final ChannelInitializer<SocketChannel> oldInit;
|
||||
private Method method;
|
||||
private ConnectionInfo info;
|
||||
private ViaInboundHandler inbound;
|
||||
private ViaOutboundHandler outbound;
|
||||
private SocketChannel socketChannel;
|
||||
private ViaOutboundPacketHandler outbound2;
|
||||
|
||||
public ViaVersionInitializer(ChannelInitializer<SocketChannel> oldInit) {
|
||||
this.oldInit = oldInit;
|
||||
@@ -28,24 +26,14 @@ public class ViaVersionInitializer extends ChannelInitializer<SocketChannel> {
|
||||
|
||||
@Override
|
||||
protected void initChannel(SocketChannel socketChannel) throws Exception {
|
||||
info = new ConnectionInfo();
|
||||
ConnectionInfo info = new ConnectionInfo(socketChannel);
|
||||
// Add originals
|
||||
this.method.invoke(this.oldInit, socketChannel);
|
||||
// Add our transformers
|
||||
this.socketChannel = socketChannel;
|
||||
this.inbound = new ViaInboundHandler(socketChannel, info, this);
|
||||
this.outbound = new ViaOutboundHandler(socketChannel, info, this);
|
||||
this.outbound2 = new ViaOutboundPacketHandler(socketChannel, info);
|
||||
socketChannel.pipeline().addBefore("decoder", "via_incoming", this.inbound);
|
||||
socketChannel.pipeline().addBefore("packet_handler", "via_outgoing2", this.outbound2);
|
||||
socketChannel.pipeline().addBefore("encoder", "via_outgoing", this.outbound);
|
||||
ViaEncodeHandler encoder = new ViaEncodeHandler(info, (MessageToByteEncoder) socketChannel.pipeline().get("encoder"));
|
||||
ViaDecodeHandler decoder = new ViaDecodeHandler(info, (ByteToMessageDecoder) socketChannel.pipeline().get("decoder"));
|
||||
|
||||
socketChannel.pipeline().replace("encoder", "encoder", encoder);
|
||||
socketChannel.pipeline().replace("decoder", "decoder", decoder);
|
||||
}
|
||||
|
||||
public void remove(){
|
||||
socketChannel.pipeline().remove("via_incoming");
|
||||
socketChannel.pipeline().remove("via_outgoing");
|
||||
socketChannel.pipeline().remove("via_outgoing2");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package us.myles.ViaVersion.listeners;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
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;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class CommandBlockListener implements Listener {
|
||||
|
||||
private final ViaVersionPlugin 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
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
package us.myles.ViaVersion.metadata;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.bukkit.entity.*;
|
||||
|
||||
@Getter
|
||||
public enum MetaIndex {
|
||||
|
||||
// entity
|
||||
@@ -27,10 +29,11 @@ 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),
|
||||
PLAYER_HAND(HumanEntity.class, -1, Type.NonExistent, 5, NewType.Byte), // new in 1.9
|
||||
// horse
|
||||
HORSE_INFO(Horse.class, 16, Type.Int, 12, NewType.Byte),
|
||||
HORSE_TYPE(Horse.class, 19, Type.Byte, 13, NewType.VarInt),
|
||||
@@ -88,6 +91,8 @@ public enum MetaIndex {
|
||||
WITHER_TARGET2(Wither.class, 18, Type.Int, 12, NewType.VarInt),
|
||||
WITHER_TARGET3(Wither.class, 19, Type.Int, 13, NewType.VarInt),
|
||||
WITHER_INVULN_TIME(Wither.class, 20, Type.Int, 14, NewType.VarInt),
|
||||
// wither skull
|
||||
WITHERSKULL_INVULN(WitherSkull.class, 10, Type.Byte, 5, NewType.Boolean),
|
||||
// guardian
|
||||
GUARDIAN_INFO(Guardian.class, 16, Type.Int, 11, NewType.Byte),
|
||||
GUARDIAN_TARGET(Guardian.class, 17, Type.Int, 12, NewType.VarInt),
|
||||
@@ -103,8 +108,11 @@ 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),
|
||||
FURNACECART_ISPOWERED(Minecart.class, 16, Type.Byte, 11, NewType.Boolean),
|
||||
// item drop
|
||||
ITEM_ITEM(Item.class, 10, Type.Slot, 5, NewType.Slot),
|
||||
// arrow
|
||||
@@ -139,36 +147,16 @@ public enum MetaIndex {
|
||||
this.newType = newType;
|
||||
}
|
||||
|
||||
public int getNewIndex() {
|
||||
return newIndex;
|
||||
}
|
||||
|
||||
public NewType getNewType() {
|
||||
return newType;
|
||||
}
|
||||
|
||||
public Type getOldType() {
|
||||
return oldType;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public Class<?> getApplicableClass() {
|
||||
return this.clazz;
|
||||
}
|
||||
|
||||
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))) {
|
||||
@@ -187,5 +175,9 @@ public enum MetaIndex {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Class<?> getApplicableClass() {
|
||||
return this.clazz;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
package us.myles.ViaVersion.metadata;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.util.EulerAngle;
|
||||
import org.bukkit.util.Vector;
|
||||
import us.myles.ViaVersion.ViaVersionPlugin;
|
||||
import us.myles.ViaVersion.api.ViaVersion;
|
||||
import us.myles.ViaVersion.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.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class MetadataRewriter {
|
||||
|
||||
public static void writeMetadata1_9(EntityType type, List<Entry> list, ByteBuf output) {
|
||||
short id = -1;
|
||||
int data = -1;
|
||||
for (Entry entry : list) {
|
||||
MetaIndex metaIndex = entry.index;
|
||||
try {
|
||||
if (metaIndex.getNewType() != NewType.Discontinued) {
|
||||
if (metaIndex.getNewType() != NewType.BlockID || id != -1 && data == -1 || id == -1 && data != -1) { // block ID is only written if we have both parts
|
||||
output.writeByte(metaIndex.getNewIndex());
|
||||
output.writeByte(metaIndex.getNewType().getTypeID());
|
||||
}
|
||||
Object value = entry.value;
|
||||
switch (metaIndex.getNewType()) {
|
||||
case Byte:
|
||||
// convert from int, byte
|
||||
if (metaIndex.getOldType() == Type.Byte) {
|
||||
output.writeByte((Byte) value);
|
||||
}
|
||||
if (metaIndex.getOldType() == Type.Int) {
|
||||
output.writeByte(((Integer) value).byteValue());
|
||||
}
|
||||
// After writing the last one
|
||||
if (metaIndex == MetaIndex.ENTITY_STATUS && type == EntityType.PLAYER) {
|
||||
output.writeByte(MetaIndex.PLAYER_HAND.getNewIndex());
|
||||
output.writeByte(MetaIndex.PLAYER_HAND.getNewType().getTypeID());
|
||||
if ((((Byte) value) & 0x10) == 0x10) { // Player eating/aiming/drinking
|
||||
output.writeByte(1); // Using main hand
|
||||
} else {
|
||||
output.writeByte(0); // Not using any hand to stop animation
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OptUUID:
|
||||
String owner = (String) value;
|
||||
UUID toWrite = null;
|
||||
if (owner.length() != 0) {
|
||||
try {
|
||||
toWrite = UUID.fromString(owner);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
output.writeBoolean(toWrite != null);
|
||||
if (toWrite != null)
|
||||
PacketUtil.writeUUID(toWrite, output);
|
||||
break;
|
||||
case BlockID:
|
||||
// if we have both sources :))
|
||||
if (metaIndex.getOldType() == Type.Byte) {
|
||||
data = (Byte) value;
|
||||
}
|
||||
if (metaIndex.getOldType() == Type.Short) {
|
||||
id = (Short) value;
|
||||
}
|
||||
if (id != -1 && data != -1) {
|
||||
int combined = id << 4 | data;
|
||||
data = -1;
|
||||
id = -1;
|
||||
PacketUtil.writeVarInt(combined, output);
|
||||
}
|
||||
break;
|
||||
case VarInt:
|
||||
// convert from int, short, byte
|
||||
if (metaIndex.getOldType() == Type.Byte) {
|
||||
PacketUtil.writeVarInt(((Byte) value).intValue(), output);
|
||||
}
|
||||
if (metaIndex.getOldType() == Type.Short) {
|
||||
PacketUtil.writeVarInt(((Short) value).intValue(), output);
|
||||
}
|
||||
if (metaIndex.getOldType() == Type.Int) {
|
||||
PacketUtil.writeVarInt((Integer) value, output);
|
||||
}
|
||||
break;
|
||||
case Float:
|
||||
output.writeFloat((Float) value);
|
||||
break;
|
||||
case String:
|
||||
PacketUtil.writeString((String) value, output);
|
||||
break;
|
||||
case Boolean:
|
||||
if (metaIndex == MetaIndex.AGEABLE_AGE)
|
||||
output.writeBoolean((Byte) value < 0);
|
||||
else
|
||||
output.writeBoolean((Byte) value != 0);
|
||||
break;
|
||||
case Slot:
|
||||
ItemStack item = (ItemStack) value;
|
||||
ItemSlotRewriter.fixIdsFrom1_8To1_9(item);
|
||||
ItemSlotRewriter.writeItemStack(item, output);
|
||||
break;
|
||||
case Position:
|
||||
Vector vector = (Vector) value;
|
||||
output.writeInt((int) vector.getX());
|
||||
output.writeInt((int) vector.getY());
|
||||
output.writeInt((int) vector.getZ());
|
||||
break;
|
||||
case Vector3F:
|
||||
EulerAngle angle = (EulerAngle) value;
|
||||
output.writeFloat((float) angle.getX());
|
||||
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 (!((ViaVersionPlugin) ViaVersion.getInstance()).isSuppressMetadataErrors()) {
|
||||
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 UNKNOWN_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();
|
||||
}
|
||||
}
|
||||
}
|
||||
output.writeByte(255);
|
||||
}
|
||||
|
||||
public static List<Entry> readMetadata1_8(EntityType entityType, ByteBuf buf) {
|
||||
List<Entry> entries = new ArrayList<>();
|
||||
byte item;
|
||||
while ((item = buf.readByte()) != 127) {
|
||||
Type type = Type.byId((item & 0xE0) >> 5);
|
||||
int id = item & 0x1F;
|
||||
MetaIndex index = MetaIndex.getIndex(entityType, id);
|
||||
switch (type) {
|
||||
case Byte:
|
||||
entries.add(new Entry(index, buf.readByte(), id));
|
||||
break;
|
||||
case Short:
|
||||
entries.add(new Entry(index, buf.readShort(), id));
|
||||
break;
|
||||
case Int:
|
||||
entries.add(new Entry(index, buf.readInt(), id));
|
||||
break;
|
||||
case Float:
|
||||
entries.add(new Entry(index, buf.readFloat(), id));
|
||||
break;
|
||||
case String:
|
||||
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), 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), id));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
System.out.println("[Out] Unhandled MetaDataType: " + type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public static final class Entry {
|
||||
|
||||
private final int oldID;
|
||||
private MetaIndex index;
|
||||
private Object value;
|
||||
|
||||
private Entry(MetaIndex index, Object value, int id) {
|
||||
this.index = index;
|
||||
this.value = value;
|
||||
this.oldID = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,10 @@
|
||||
package us.myles.ViaVersion.metadata;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum NewType {
|
||||
Byte(0),
|
||||
VarInt(1),
|
||||
@@ -15,13 +20,7 @@ public enum NewType {
|
||||
OptUUID(11),
|
||||
BlockID(12),
|
||||
Discontinued(99);
|
||||
|
||||
private final int typeID;
|
||||
|
||||
NewType(int typeID){
|
||||
this.typeID = typeID;
|
||||
}
|
||||
|
||||
public int getTypeID() {
|
||||
return typeID;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,10 @@
|
||||
package us.myles.ViaVersion.metadata;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum Type {
|
||||
Byte(0),
|
||||
Short(1),
|
||||
@@ -8,14 +13,11 @@ public enum Type {
|
||||
String(4),
|
||||
Slot(5),
|
||||
Position(6),
|
||||
Rotation(7);
|
||||
Rotation(7),
|
||||
NonExistent(-1);
|
||||
private final int typeID;
|
||||
|
||||
Type(int typeID){
|
||||
this.typeID = typeID;
|
||||
}
|
||||
|
||||
public int getTypeID() {
|
||||
return typeID;
|
||||
public static Type byId(int id) {
|
||||
return values()[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 {
|
||||
|
||||
private static final Map<String, Integer> ENTTIY_NAME_TO_ID = new HashMap<>();
|
||||
private static final Map<Integer, String> ENTTIY_ID_TO_NAME = new HashMap<>();
|
||||
private static final Map<String, Integer> POTION_NAME_TO_ID = new HashMap<>();
|
||||
private static final 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");
|
||||
|
||||
}
|
||||
|
||||
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((int) item.data)) {
|
||||
StringTag id = new StringTag("id", ENTTIY_ID_TO_NAME.get((int) 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((int) item.data)) {
|
||||
String name = POTION_ID_TO_NAME.get((int) 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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
if(stack == null) return null;
|
||||
ItemStack item = new ItemStack();
|
||||
item.id = (short) stack.getTypeId();
|
||||
item.amount = (byte) stack.getAmount();
|
||||
item.data = stack.getData().getData();
|
||||
// TODO: nbt
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,10 @@
|
||||
package us.myles.ViaVersion.sounds;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum SoundCategory {
|
||||
|
||||
|
||||
@@ -14,20 +19,7 @@ public enum SoundCategory {
|
||||
AMBIENT("ambient", 8),
|
||||
VOICE("voice", 9);
|
||||
|
||||
private String name;
|
||||
private int id;
|
||||
|
||||
SoundCategory(String name, int id) {
|
||||
this.name = name;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
private final String name;
|
||||
private final int id;
|
||||
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
package us.myles.ViaVersion.sounds;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum SoundEffect {
|
||||
|
||||
MOB_HORSE_ZOMBIE_IDLE("mob.horse.zombie.idle", "entity.zombie_horse.ambient", SoundCategory.NEUTRAL),
|
||||
@@ -198,7 +201,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),
|
||||
@@ -249,14 +252,23 @@ public enum SoundEffect {
|
||||
MUSIC_GAME_END_CREDITS("music.game.end.credits", "music.credits", SoundCategory.MUSIC),
|
||||
MUSIC_GAME_CREATIVE("music.game.creative", "music.creative", SoundCategory.MUSIC);
|
||||
|
||||
private String name;
|
||||
private String newname;
|
||||
private SoundCategory cat;
|
||||
private final String name;
|
||||
private final String newName;
|
||||
private final SoundCategory category;
|
||||
private final boolean breaksound;
|
||||
|
||||
SoundEffect(String name, String newname, SoundCategory cat) {
|
||||
this.cat = cat;
|
||||
this.newname = newname;
|
||||
this.category = cat;
|
||||
this.newName = newname;
|
||||
this.name = name;
|
||||
this.breaksound = name.startsWith("dig.");
|
||||
}
|
||||
|
||||
SoundEffect(String name, String newname, SoundCategory cat, boolean shouldIgnore) {
|
||||
this.category = cat;
|
||||
this.newName = newname;
|
||||
this.name = name;
|
||||
this.breaksound = name.startsWith("dig.") || shouldIgnore;
|
||||
}
|
||||
|
||||
public static SoundEffect getByName(String name) {
|
||||
@@ -268,16 +280,4 @@ public enum SoundEffect {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getNewName() {
|
||||
return newname;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public SoundCategory getCategory() {
|
||||
return cat;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +1,27 @@
|
||||
package us.myles.ViaVersion.transformers;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import us.myles.ViaVersion.*;
|
||||
import us.myles.ViaVersion.handlers.ViaVersionInitializer;
|
||||
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 Channel channel;
|
||||
private final ViaVersionPlugin plugin = (ViaVersionPlugin) ViaVersion.getInstance();
|
||||
private final ConnectionInfo info;
|
||||
private final ViaVersionInitializer init;
|
||||
private boolean startedBlocking = false;
|
||||
|
||||
public IncomingTransformer(Channel channel, ConnectionInfo info, ViaVersionInitializer init) {
|
||||
this.channel = channel;
|
||||
public IncomingTransformer(ConnectionInfo info) {
|
||||
this.info = info;
|
||||
this.init = init;
|
||||
}
|
||||
|
||||
public void transform(int packetID, ByteBuf input, ByteBuf output) throws CancelException {
|
||||
@@ -35,9 +35,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 (plugin.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();
|
||||
}
|
||||
@@ -48,8 +50,8 @@ public class IncomingTransformer {
|
||||
PacketUtil.writeVarInt(protVer <= 102 ? protVer : 47, output); // pretend to be older
|
||||
|
||||
if (protVer <= 102) {
|
||||
// Not 1.9 remove pipes
|
||||
this.init.remove();
|
||||
// not 1.9, remove pipes
|
||||
info.setActive(false);
|
||||
}
|
||||
String serverAddress = PacketUtil.readString(input);
|
||||
PacketUtil.writeString(serverAddress, output);
|
||||
@@ -73,7 +75,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;
|
||||
@@ -86,18 +88,31 @@ public class IncomingTransformer {
|
||||
return;
|
||||
}
|
||||
if (packet == PacketType.PLAY_PLAYER_DIGGING) {
|
||||
byte status = input.readByte();
|
||||
int status = input.readByte() & 0xFF; // unsign
|
||||
if (status == 5 && startedBlocking) {
|
||||
// stopped blocking
|
||||
startedBlocking = false;
|
||||
sendSecondHandItem(null);
|
||||
}
|
||||
if (status == 6) { // item swap
|
||||
throw new CancelException();
|
||||
}
|
||||
output.writeByte(status);
|
||||
// read position
|
||||
Long pos = input.readLong();
|
||||
output.writeLong(pos);
|
||||
short face = input.readUnsignedByte();
|
||||
// write remaining bytes
|
||||
Long position = input.readLong();
|
||||
output.writeLong(position);
|
||||
|
||||
int face = input.readUnsignedByte();
|
||||
output.writeByte(face);
|
||||
return;
|
||||
}
|
||||
if (packet == PacketType.PLAY_HELD_ITEM_CHANGE_REQUEST) {
|
||||
if (startedBlocking) {
|
||||
// stopped blocking
|
||||
startedBlocking = false;
|
||||
sendSecondHandItem(null);
|
||||
}
|
||||
}
|
||||
if (packet == PacketType.PLAY_CLICK_WINDOW) {
|
||||
// if placed in new slot, reject :)
|
||||
int windowID = input.readUnsignedByte();
|
||||
@@ -105,32 +120,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);
|
||||
channel.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);
|
||||
@@ -154,6 +181,19 @@ public class IncomingTransformer {
|
||||
PacketUtil.readVarInt(input);
|
||||
return;
|
||||
}
|
||||
if (packet == PacketType.PLAY_ENTITY_ACTION) {
|
||||
int playerId = PacketUtil.readVarInt(input);
|
||||
int action = PacketUtil.readVarInt(input);
|
||||
int jump = PacketUtil.readVarInt(input);
|
||||
if (action == 6 || action == 8) //Ignore stop jumping / start elytra flying
|
||||
throw new CancelException();
|
||||
if (action == 7) //Change open horse inventory to the 1.8 value
|
||||
action = 6;
|
||||
PacketUtil.writeVarInt(playerId, output);
|
||||
PacketUtil.writeVarInt(action, output);
|
||||
PacketUtil.writeVarInt(jump, output);
|
||||
return;
|
||||
}
|
||||
if (packet == PacketType.PLAY_USE_ENTITY) {
|
||||
int target = PacketUtil.readVarInt(input);
|
||||
PacketUtil.writeVarInt(target, output);
|
||||
@@ -173,52 +213,135 @@ 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
|
||||
switch (name) {
|
||||
case "MC|BSign": {
|
||||
ByteBuf in = Unpooled.wrappedBuffer(b);
|
||||
try {
|
||||
ItemSlotRewriter.ItemStack stack = ItemSlotRewriter.readItemStack(in);
|
||||
if (stack != null)
|
||||
stack.id = (short) Material.WRITTEN_BOOK.getId();
|
||||
// write
|
||||
ItemSlotRewriter.writeItemStack(stack, output);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return;
|
||||
}
|
||||
case "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;
|
||||
}
|
||||
case "MC|AdvCmd":
|
||||
output.clear();
|
||||
PacketUtil.writeVarInt(PacketType.PLAY_PLUGIN_MESSAGE_REQUEST.getPacketID(), output);
|
||||
PacketUtil.writeString("MC|AdvCdm", output);
|
||||
output.writeBytes(b);
|
||||
break;
|
||||
}
|
||||
output.writeBytes(b);
|
||||
}
|
||||
if (packet == PacketType.PLAY_PLAYER_BLOCK_PLACEMENT) {
|
||||
Long position = input.readLong();
|
||||
output.writeLong(position);
|
||||
int face = PacketUtil.readVarInt(input);
|
||||
output.writeByte(face);
|
||||
int hand = PacketUtil.readVarInt(input);
|
||||
PacketUtil.readVarInt(input);
|
||||
|
||||
ItemStack inHand = ViaVersionPlugin.getHandItem(info);
|
||||
Object item = null;
|
||||
ItemStack inHand = plugin.getHandItem(info);
|
||||
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();
|
||||
output.writeByte(curY);
|
||||
short curZ = input.readUnsignedByte();
|
||||
output.writeByte(curZ);
|
||||
return;
|
||||
short curX = input.readUnsignedByte();
|
||||
output.writeByte(curX);
|
||||
short curY = input.readUnsignedByte();
|
||||
output.writeByte(curY);
|
||||
short curZ = input.readUnsignedByte();
|
||||
output.writeByte(curZ);
|
||||
return;
|
||||
}
|
||||
if (packet == PacketType.PLAY_USE_ITEM) {
|
||||
int hand = PacketUtil.readVarInt(input);
|
||||
output.clear();
|
||||
PacketUtil.writeVarInt(PacketType.PLAY_PLAYER_BLOCK_PLACEMENT.getPacketID(), output);
|
||||
// Simulate using item :)
|
||||
output.writeLong(-1L);
|
||||
output.writeByte(-1);
|
||||
output.writeByte(255);
|
||||
// write item in hand
|
||||
output.writeShort(-1);
|
||||
ItemStack inHand = plugin.getHandItem(info);
|
||||
if (inHand != null && plugin.isShieldBlocking()) {
|
||||
if (inHand.getType().name().endsWith("SWORD")) {
|
||||
// blocking?
|
||||
if (hand == 0) {
|
||||
if (!startedBlocking) {
|
||||
startedBlocking = true;
|
||||
ItemSlotRewriter.ItemStack shield = new ItemSlotRewriter.ItemStack();
|
||||
shield.id = 442;
|
||||
shield.amount = 1;
|
||||
shield.data = 0;
|
||||
sendSecondHandItem(shield);
|
||||
}
|
||||
throw new CancelException();
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
ItemSlotRewriter.ItemStack item = ItemSlotRewriter.ItemStack.fromBukkit(inHand);
|
||||
ItemSlotRewriter.fixIdsFrom1_9To1_8(item);
|
||||
ItemSlotRewriter.writeItemStack(item, output);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
output.writeByte(-1);
|
||||
output.writeByte(-1);
|
||||
output.writeByte(-1);
|
||||
output.writeByte(0); //Is zero in 1.8, not -1
|
||||
output.writeByte(0);
|
||||
output.writeByte(0);
|
||||
return;
|
||||
}
|
||||
if (packet == PacketType.PLAY_CREATIVE_INVENTORY_ACTION) {
|
||||
short slot = input.readShort();
|
||||
output.writeShort(slot);
|
||||
|
||||
ItemSlotRewriter.rewrite1_9To1_8(input, output);
|
||||
}
|
||||
output.writeBytes(input);
|
||||
}
|
||||
|
||||
private void sendSecondHandItem(ItemSlotRewriter.ItemStack o) {
|
||||
ByteBuf buf = info.getChannel().alloc().buffer();
|
||||
PacketUtil.writeVarInt(PacketType.PLAY_ENTITY_EQUIPMENT.getNewPacketID(), buf);
|
||||
PacketUtil.writeVarInt(info.getEntityID(), buf);
|
||||
PacketUtil.writeVarInt(1, buf); // slot
|
||||
// write shield
|
||||
try {
|
||||
ItemSlotRewriter.writeItemStack(o, buf);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
info.sendRawPacket(buf);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,22 @@
|
||||
package us.myles.ViaVersion.update;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class UpdateListener implements Listener {
|
||||
|
||||
private final 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", "ViaVersion " + ViaVersion.getInstance().getVersion());
|
||||
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,62 @@
|
||||
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]+)*$"))
|
||||
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]);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public static boolean equals(Version verA, Version verB) {
|
||||
return verA == verB || verA != null && verB != null && compare(verA, verB) == 0;
|
||||
}
|
||||
|
||||
@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, ".");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Version that) {
|
||||
return compare(this, that);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object that) {
|
||||
return that instanceof Version && equals(this, (Version) that);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package us.myles.ViaVersion.util;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
public class EntityUtil {
|
||||
|
||||
public static EntityType getTypeFromID(int typeID, boolean isObject) {
|
||||
if (isObject) {
|
||||
return getObjectFromID(typeID);
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
package us.myles.ViaVersion.util;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
public abstract class ListWrapper implements List {
|
||||
private final List list;
|
||||
|
||||
public ListWrapper(List inputList) {
|
||||
this.list = inputList;
|
||||
}
|
||||
|
||||
public abstract void handleAdd(Object o);
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.list.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.list.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return this.list.contains(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator iterator() {
|
||||
return this.list.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
return this.list.toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(Object o) {
|
||||
handleAdd(o);
|
||||
return this.list.add(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
return this.list.remove(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection c) {
|
||||
for (Object o : c) {
|
||||
handleAdd(o);
|
||||
}
|
||||
return this.list.addAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(int index, Collection c) {
|
||||
for (Object o : c) {
|
||||
handleAdd(o);
|
||||
}
|
||||
return this.list.addAll(index, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.list.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(int index) {
|
||||
return this.list.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object set(int index, Object element) {
|
||||
return this.list.set(index, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, Object element) {
|
||||
this.list.add(index, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object remove(int index) {
|
||||
return this.list.remove(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(Object o) {
|
||||
return this.list.indexOf(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastIndexOf(Object o) {
|
||||
return this.list.lastIndexOf(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator listIterator() {
|
||||
return this.list.listIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator listIterator(int index) {
|
||||
return this.listIterator(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List subList(int fromIndex, int toIndex) {
|
||||
return this.list.subList(fromIndex, toIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection c) {
|
||||
return this.list.retainAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection c) {
|
||||
return this.list.removeAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection c) {
|
||||
return this.list.containsAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray(Object[] a) {
|
||||
return this.list.toArray(a);
|
||||
}
|
||||
}
|
||||
@@ -3,21 +3,20 @@ 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 us.myles.ViaVersion.chunks.MagicBitSet;
|
||||
import us.myles.ViaVersion.chunks.PacketChunk;
|
||||
import us.myles.ViaVersion.chunks.PacketChunkData;
|
||||
import org.spacehq.opennbt.NBTIO;
|
||||
import org.spacehq.opennbt.tag.builtin.CompoundTag;
|
||||
|
||||
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;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.ShortBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -42,29 +41,64 @@ public class PacketUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static ByteBuf decompress(ChannelHandlerContext ctx, ByteBuf msg) {
|
||||
ByteToMessageDecoder x = (ByteToMessageDecoder) ctx.pipeline().get("decompress");
|
||||
List<Object> output = new ArrayList<Object>();
|
||||
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);
|
||||
ByteBufInputStream bytebufStream = new ByteBufInputStream(input);
|
||||
DataInputStream dataInputStream = new DataInputStream(bytebufStream);
|
||||
try {
|
||||
return (CompoundTag) NBTIO.readTag(dataInputStream);
|
||||
} finally {
|
||||
dataInputStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeNBT(ByteBuf output, CompoundTag tag) throws IOException {
|
||||
if (tag == null) {
|
||||
output.writeByte(0);
|
||||
} else {
|
||||
ByteBufOutputStream bytebufStream = new ByteBufOutputStream(output);
|
||||
DataOutputStream dataOutputStream = new DataOutputStream(bytebufStream);
|
||||
|
||||
NBTIO.writeTag(dataOutputStream, tag);
|
||||
|
||||
dataOutputStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Object> callDecode(ByteToMessageDecoder decoder, ChannelHandlerContext ctx, Object input) {
|
||||
List<Object> output = new ArrayList<>();
|
||||
try {
|
||||
PacketUtil.DECODE_METHOD.invoke(x, ctx, msg, output);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
PacketUtil.DECODE_METHOD.invoke(decoder, ctx, input, output);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
public static void callEncode(MessageToByteEncoder encoder, ChannelHandlerContext ctx, Object msg, ByteBuf output) {
|
||||
try {
|
||||
PacketUtil.ENCODE_METHOD.invoke(encoder, ctx, msg, output);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static ByteBuf decompress(ChannelHandlerContext ctx, ByteBuf msg) {
|
||||
ByteToMessageDecoder x = (ByteToMessageDecoder) ctx.pipeline().get("decompress");
|
||||
List<Object> output = callDecode(x, ctx, msg);
|
||||
return output.size() == 0 ? null : (ByteBuf) output.get(0);
|
||||
}
|
||||
|
||||
public static ByteBuf compress(ChannelHandlerContext ctx, ByteBuf msg) {
|
||||
MessageToByteEncoder x = (MessageToByteEncoder) ctx.pipeline().get("compress");
|
||||
ByteBuf output = ctx.alloc().buffer();
|
||||
try {
|
||||
PacketUtil.ENCODE_METHOD.invoke(x, ctx, msg, output);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
callEncode(x, ctx, msg, output);
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -134,7 +168,7 @@ public class PacketUtil {
|
||||
|
||||
public static List<String> readStringArray(ByteBuf buf) {
|
||||
int len = readVarInt(buf);
|
||||
List<String> ret = new ArrayList<String>(len);
|
||||
List<String> ret = new ArrayList<>(len);
|
||||
for (int i = 0; i < len; i++) {
|
||||
ret.add(readString(buf));
|
||||
}
|
||||
@@ -185,9 +219,9 @@ public class PacketUtil {
|
||||
}
|
||||
|
||||
public static void writeVarIntArray(List<Integer> integers, ByteBuf output) {
|
||||
writeVarInt(integers.size(),output);
|
||||
for (Integer i : integers){
|
||||
writeVarInt(i,output);
|
||||
writeVarInt(integers.size(), output);
|
||||
for (Integer i : integers) {
|
||||
writeVarInt(i, output);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,8 +257,8 @@ public class PacketUtil {
|
||||
}
|
||||
|
||||
public static void writeLongs(long[] data, ByteBuf output) {
|
||||
for (int index = 0; index < data.length; index++) {
|
||||
output.writeLong(data[index]);
|
||||
for (long aData : data) {
|
||||
output.writeLong(aData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,133 +271,6 @@ public class PacketUtil {
|
||||
return data;
|
||||
}
|
||||
|
||||
// This method is based on one from here
|
||||
// https://github.com/Steveice10/MCProtocolLib/blob/master/src/main/java/org/spacehq/mc/protocol/util/NetUtil.java
|
||||
public static PacketChunk readChunkData(boolean isFullChunk, int bitmask, byte[] input) {
|
||||
PacketChunkData[] chunks = new PacketChunkData[16];
|
||||
boolean sky = false;
|
||||
int expected = 0;
|
||||
int position = 0;
|
||||
ShortBuffer blockData = ByteBuffer.wrap(input).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
|
||||
|
||||
for (int i = 0; i < chunks.length; i++) {
|
||||
if ((bitmask & 1 << i) != 0) {
|
||||
expected += (4096 * 2) + 2048;
|
||||
}
|
||||
}
|
||||
// If there is more data, then there must be skylights :D
|
||||
if (input.length > expected) {
|
||||
sky = true;
|
||||
}
|
||||
|
||||
// Read block data
|
||||
for (int i = 0; i < chunks.length; i++) {
|
||||
if ((bitmask & 1 << i) != 0) {
|
||||
chunks[i] = new PacketChunkData(sky);
|
||||
blockData.position(position / 2);
|
||||
blockData.get(chunks[i].getBlocks(), 0, 4096);
|
||||
position = position + (4096 * 2);
|
||||
} else {
|
||||
chunks[i] = new PacketChunkData(sky);
|
||||
}
|
||||
}
|
||||
// Read blocklight data
|
||||
for (int i = 0; i < chunks.length; i++) {
|
||||
if ((bitmask & 1 << i) != 0) {
|
||||
System.arraycopy(input, position, chunks[i].getBlockLight(), 0, 2048);
|
||||
position = position + 2048;
|
||||
}
|
||||
}
|
||||
// Read skylight data
|
||||
if (sky) {
|
||||
for (int i = 0; i < chunks.length; i++) {
|
||||
if ((bitmask & 1 << i) != 0) {
|
||||
System.arraycopy(input, position, chunks[i].getSkyLight(), 0, 2048);
|
||||
position = position + 2048;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
byte[] biomeData = null;
|
||||
|
||||
if (isFullChunk) {
|
||||
// yay im a full chunk meaning i know my biomes, mommy get the camera!
|
||||
biomeData = new byte[256];
|
||||
System.arraycopy(input, position, biomeData, 0, 256);
|
||||
}
|
||||
return new PacketChunk(chunks, biomeData);
|
||||
}
|
||||
|
||||
public static void writeNewChunk(ByteBuf buffer, PacketChunkData chunk) {
|
||||
// Bits Per Block (We use 0, cause we're not gonna write a palette ;) )
|
||||
buffer.writeByte(0);
|
||||
// No Palette nor length :D
|
||||
|
||||
// Data Array Length
|
||||
byte[] blockData = convertBlockArray(chunk.getBlocks());
|
||||
writeVarInt(blockData.length / 8, buffer); // Notchian is divide by 8
|
||||
|
||||
buffer.writeBytes(blockData);
|
||||
// Block Light
|
||||
buffer.writeBytes(chunk.getBlockLight());
|
||||
// If has skylight, write it
|
||||
if (chunk.getSkyLight() != null) {
|
||||
buffer.writeBytes(chunk.getSkyLight());
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] convertBlockArray(short[] blocks) {
|
||||
// block ID for the first 9 bits, and the block damage value for the last 4 bits
|
||||
byte[] output = new byte[6664]; // (16 * 16 * 16 * 13) / 8 :) (plus some for padding ...)
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
for (short block : blocks) {
|
||||
int blockID = block >> 4; // (Needs to be to 9 bits)
|
||||
int data = block & 0xF; // 8 bits
|
||||
|
||||
}
|
||||
return null; // todo: finish
|
||||
}
|
||||
|
||||
private static BitSet append(BitSet base, int index, MagicBitSet toAdd) {
|
||||
int length = index;
|
||||
for (int i = 0; i < toAdd.getTrueLength(); i++) {
|
||||
base.set(length + i, toAdd.get(i));
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
private static MagicBitSet getPaddedBitSet(int value, int bitSize) {
|
||||
MagicBitSet output = new MagicBitSet(bitSize);
|
||||
BitSet temp = BitSet.valueOf(new long[]{value});
|
||||
for (int i = 0; i < bitSize; i++) {
|
||||
output.set(i, false);
|
||||
}
|
||||
int toShift = bitSize - temp.length();
|
||||
for (int i = 0; i < temp.length(); i++) {
|
||||
output.set(toShift + i, temp.get(i));
|
||||
}
|
||||
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 long[] readBlockPosition(ByteBuf buf) {
|
||||
long val = buf.readLong();
|
||||
long x = (val >> 38); // signed
|
||||
@@ -385,4 +292,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);
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# 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
|
||||
# No collide options, these allow you to configure how collision works.
|
||||
# Do you want us to prevent collision?
|
||||
prevent-collision: true
|
||||
# If the above is true, should we automatically team players until you do?
|
||||
auto-team: true
|
||||
# When enabled if certain metadata can't be read we won't tell you about it
|
||||
suppress-metadata-errors: false
|
||||
# When enabled 1.9 will be able to block by using shields
|
||||
shield-blocking: true
|
||||
@@ -1,4 +1,11 @@
|
||||
name: ViaVersion
|
||||
main: us.myles.ViaVersion.ViaVersionPlugin
|
||||
author: _MylesC
|
||||
version: 0.3.7
|
||||
version: ${project.version}
|
||||
load: startup
|
||||
loadbefore: [ProtocolLib, ProxyPipe]
|
||||
commands:
|
||||
viaversion:
|
||||
description: Shows ViaVersion Version and more.
|
||||
permission: viaversion.admin
|
||||
aliases: [viaver]
|
||||
Reference in new issue
Block a user