Compare commits

..
37 Commits
Author SHA1 Message Date
retrooper f7ed5f1fd8 Merge pull request #570 from D3lta-2-1/fabric
Fabric server side support added
2023-05-13 20:36:05 +02:00
retrooper db41fe5292 Remove debugs 2023-05-13 20:32:59 +02:00
d3lta 25f896c6d1 debug singlePlayer and add lan support 2023-04-10 15:19:27 +02:00
d3lta 192b622d56 Make it load on server and client 2023-04-09 17:17:29 +02:00
d3lta 25f2ec8fd7 update to support server side 2023-04-08 14:02:16 +02:00
d3lta c4d0953be8 Merge pull request #1 from retrooper/fabric
Update fabric client to latest packetevents
2023-04-07 20:02:12 +02:00
retrooper 5cd2314965 Update fabric client to latest packetevents 2023-04-07 19:54:51 +02:00
retrooper a97869ae44 Added adventure-nbt as a dependency. 2022-03-18 21:23:00 +01:00
retrooper 45dca9af9c Now shade adventure fully. 2022-03-18 21:15:39 +01:00
retrooper 97ed7066b4 Adventure isn't being shaded properly. 2022-03-18 21:10:27 +01:00
retrooper 285e96324d Updated to latest 2.0 commit 2022-03-18 20:52:18 +01:00
retrooper e220e992d8 Fixed updating to packetevents. 2022-03-13 19:45:56 +01:00
retrooper aa92479285 Updated packetevents. 2022-03-13 19:44:53 +01:00
retrooper 066c948af8 Updated to latest packetevents snapshot. 2022-03-11 17:39:31 +01:00
retrooper 1e5adc00c6 Updated packetevents with bug fixes.
We initialize packetevents a bit later, but setup the API instance early enough for regular mods.

Tried to fix event.getPlayer() being null?
2022-03-10 22:24:47 +01:00
retrooper fdeb473dba We now load on preLaunch. This should allow ordinary mods to initialize packetevents in the main entry point. 2022-03-07 18:31:23 +01:00
retrooper 048d1ae870 Believe we fixed cancelling outgoing packets. 2022-03-07 17:33:32 +01:00
retrooper a17c5fa767 I believe we can now cancel packets properly with our custom compression encoder that helps discards packets. 2022-03-07 00:25:13 +01:00
retrooper c21d74551d PacketEncoder is now a MessageToMessageEncoder to support cancelling outgoing packets. 2022-03-06 23:29:50 +01:00
retrooper 98d2c35107 Updated. Bug fixes for cancelling outgoing (packetreceiveevent) packets. 2022-03-06 22:48:43 +01:00
retrooper a35f8d5b1c Mod is now called packetevents. 2022-03-06 12:52:34 +01:00
retrooper 2a5977fdd2 Got packetevents working I guess? Seems good. Some changes in injector to support compression. 2022-03-05 23:44:16 +01:00
retrooper 232b20788a Fixed include() in build.gradle 2022-02-22 21:41:18 +01:00
retrooper 9962e60c90 Updated to latest packetevents 2022-02-21 22:16:27 +01:00
retrooper 4da9dc7f33 Updated packetevents. 2022-02-12 22:01:30 +01:00
retrooper b5ee1c38f2 Merge pull request #231 from Olivoz/fabric
Use Mojang Mappings with ParchmentMC
2022-02-11 16:46:33 +01:00
Olivoz 24577569b1 Use Mojang Mappings with ParchmentMC
Use Mojang Mappings with ParchmentMC so method names are the same across different platforms.
2022-02-11 14:11:38 +01:00
retrooper 76bfb92926 Updated packetevents. 2022-02-11 13:46:40 +01:00
retrooper f2173e6d5c Updated. 2022-02-09 17:13:58 +01:00
retrooper e24151150f Updated to latest Fabric API. 2022-02-06 19:38:26 +01:00
retrooper 41be143837 Removed debugs. 2022-02-06 19:22:04 +01:00
retrooper 74e615ec40 Cleaned stuff up, made a FabricPacketEventsBuilder 2022-02-06 18:44:12 +01:00
retrooper 30b6d2f33a Updated LICENSE 2022-02-06 17:59:57 +01:00
retrooper 595f15eee0 Updated to latest 2.0 packetevents 2022-02-06 17:55:51 +01:00
retrooper 76e0c2274b Updated to latest 2.0 packetevents 2022-02-06 11:54:09 +01:00
retrooper d8fa583e0f Minor changes. 2022-02-05 22:32:07 +01:00
retrooper e2599e036d Initial commit 2022-02-05 20:21:30 +01:00
261 changed files with 1266 additions and 27209 deletions

No files matched your search

-5
View File
@@ -1,5 +0,0 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: retrooper
custom: ['https://paypal.me/retrooperdev']
-38
View File
@@ -1,38 +0,0 @@
---
name: Bug report
about: Report bugs to help us improve our software.
title: ""
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**Software brand**
Please let us know what software you are using.
Eg. Spigot 1.18.2, Paper 1.18.2, Tuinity 1.18.2, Pufferfish 1.18.2, etc...
Make sure to mention the version of the software.
**Plugins**
Please give us a list of your plugins. Sometimes we run into incompatibilities. Having an overview of the plugins on your server can really help identify the problem quicker.
Eg. ViaVersion, ProtocolLib, HolographicDisplays
You may also provide a screenshot.
**How To Reproduce**
Steps to reproduce the behavior:
*Example:*
1. Join with the 1.18.2 vanilla minecraft client.
2. Spam
3. ....
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here.
-21
View File
@@ -1,21 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: FEATURE REQUEST
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered to solve your solution without
us adding this as a feature?**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
+39
View File
@@ -0,0 +1,39 @@
# Automatically build the project and run any configured tests for every push
# and submitted pull request. This can help catch issues that only occur on
# certain platforms or Java versions, and provides a first line of defence
# against bad commits.
name: build
on: [pull_request, push]
jobs:
build:
strategy:
matrix:
# Use these Java versions
java: [
17, # Current Java LTS & minimum supported by Minecraft
]
# and run on both Linux and Windows
os: [ubuntu-20.04, windows-2022]
runs-on: ${{ matrix.os }}
steps:
- name: checkout repository
uses: actions/checkout@v2
- name: validate gradle wrapper
uses: gradle/wrapper-validation-action@v1
- name: setup jdk ${{ matrix.java }}
uses: actions/setup-java@v1
with:
java-version: ${{ matrix.java }}
- name: make gradle wrapper executable
if: ${{ runner.os != 'Windows' }}
run: chmod +x ./gradlew
- name: build
run: ./gradlew build
- name: capture build artifacts
if: ${{ runner.os == 'Linux' && matrix.java == '17' }} # Only upload artifacts built from latest java on one OS
uses: actions/upload-artifact@v2
with:
name: Artifacts
path: build/libs/
-67
View File
@@ -1,67 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ master, dev ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master, dev ]
schedule:
- cron: '39 0 * * 0'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: [ 'java' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
-33
View File
@@ -1,33 +0,0 @@
# This workflow will build a package using Gradle and then publish it to GitHub packages when a release is created
# For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#Publishing-using-gradle
name: Gradle Package
on: [ push, pull_request ]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v2
- name: Set up JDK 8
uses: actions/setup-java@v2
with:
java-version: '8'
distribution: 'adopt'
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
settings-path: ${{ github.workspace }} # location for the settings.xml file
- name: Build with Gradle
run: gradle :clean :build
- name: Upload build artifacts
uses: actions/upload-artifact@v1
with:
name: packetevents-dev-build.jar
path: build/libs
+21 -105
View File
@@ -1,117 +1,33 @@
#
# JetBrains
#
# gradle
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
.gradle/
build/
out/
classes/
# Generated files
.idea/**/contentModel.xml
# eclipse
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
*.launch
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# idea
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
.idea/
*.iml
*.ipr
*.iws
# mpeltonen/sbt-idea plugin
.idea_modules/
# vscode
# JIRA plugin
atlassian-ide-plugin.xml
.settings/
.vscode/
bin/
.classpath
.project
# Cursive Clojure plugin
.idea/replstate.xml
# macos
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
*.DS_Store
# Editor-based Rest Client
.idea/httpRequests
# fabric
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
#
# Java
#
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
#
# Maven
#
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
.mvn/wrapper/maven-wrapper.jar
/src/main/resources/
/.gradle/
/.idea/
/build/
run/
+1 -1
View File
@@ -671,4 +671,4 @@ into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.
<https://www.gnu.org/licenses/why-not-lgpl.html>.
+5 -19
View File
@@ -1,23 +1,9 @@
# packetevents
# Fabric Example Mod
[![](https://img.shields.io/badge/License-GPLv3-yellow.svg)](https://github.com/retrooper/packetevents/blob/dev/LICENSE)
[![](https://jitpack.io/v/retrooper/packetevents.svg)](https://jitpack.io/#retrooper/packetevents)
## Setup
PacketEvents is a powerful packet library. Our packet wrappers are efficient and easy to use. We support many protocol versions. (1.8+)
For setup instructions please see the [fabric wiki page](https://fabricmc.net/wiki/tutorial:setup) that relates to the IDE that you are using.
### Resources
* [SpigotMC](https://www.spigotmc.org/resources/packetevents-api.80279/)
* [JavaDoc](https://packetevents.github.io/javadocs)
* [Discord](https://discord.me/packetevents)
## License
### Setup
[Learn more](https://github.com/retrooper/packetevents/wiki/1.-Setup)
### Sponsorships
[![](https://www.ej-technologies.com/images/product_banners/jprofiler_small.png)](https://www.ej-technologies.com/products/jprofiler/overview.html)
### Statistics
PacketEvents collects statistics anonymously using bStats. It helps give us an overview of what platforms use our project. If you really don't like, you can turn it off.
### Credit
PacketEvents uses an injector that is extremely similar to ViaVersion's injector. I have included license and copyright holder notice in the files taken from ViaVersion. Thank you ViaVersion.
This template is available under the CC0 license. Feel free to learn from it and incorporate it in your own projects.
-4
View File
@@ -1,4 +0,0 @@
# Table of contents
* [Initial page](README.md)
+77 -67
View File
@@ -1,83 +1,93 @@
plugins {
id 'java'
id 'maven-publish'
id 'fabric-loom' version '0.11-SNAPSHOT'
id 'maven-publish'
}
//gradle myJavadocs
task myJavadocs(type: Javadoc) {
source = sourceSets.main.allJava
File projectDir = getProjectDir()
File javadocsDir = new File(projectDir.getParentFile().getAbsolutePath() + "/docs");
javadocsDir.mkdirs()
setDestinationDir(javadocsDir)
}
version = project.mod_version
group = project.maven_group
project.ext.adventureVersion = '4.10.1'
project.ext.adventureDependencies=["net.kyori:adventure-api:${adventureVersion}",
"net.kyori:adventure-text-serializer-gson:${adventureVersion}",
"net.kyori:adventure-text-serializer-legacy:${adventureVersion}",
"net.kyori:adventure-text-serializer-gson-legacy-impl:${adventureVersion}",
"net.kyori:adventure-key:${adventureVersion}",
"net.kyori:adventure-nbt:${adventureVersion}",
"net.kyori:examination-api:1.3.0",
"net.kyori:examination-string:1.3.0"]
repositories {
mavenLocal()
maven {
url = uri('https://hub.spigotmc.org/nexus/content/repositories/snapshots/')
}
maven {
url 'https://papermc.io/repo/repository/maven-public/'
}
maven {
url 'https://repo.opencollab.dev/maven-snapshots/'
}
maven {
url 'https://repo.opencollab.dev/maven-releases/'
}
maven {
url = uri('https://jitpack.io/')
}
maven {
url = uri('https://nexus.funkemunky.cc/content/repositories/releases/')
}
maven {
url = uri('https://repo.viaversion.com/')
}
maven {
url = uri('https://oss.sonatype.org/content/repositories/releases/')
}
maven {
url = uri('https://repo.maven.apache.org/maven2/')
}
mavenCentral()
mavenCentral()
maven { url 'https://repo.codemc.io/repository/maven-snapshots/' }
maven {
name = 'ParchmentMC'
url = 'https://maven.parchmentmc.org'
}
}
dependencies {
implementation 'org.jetbrains:annotations:23.0.0'
modImplementation 'com.github.retrooper.packetevents:netty-common:2.0.0-SNAPSHOT'
include('com.github.retrooper.packetevents:netty-common:2.0.0-SNAPSHOT')
modImplementation(adventureDependencies)
include(adventureDependencies)
compileOnly 'org.spigotmc:spigot-api:1.17-R0.1-SNAPSHOT'
compileOnly 'com.destroystokyo.paper:paper-api:1.16.5-R0.1-SNAPSHOT'
compileOnly 'com.viaversion:viaversion-api:4.0.1'
compileOnly 'com.github.ProtocolSupport:ProtocolSupport:3d24efeda6'
// To change the versions see the gradle.properties file
minecraft "com.mojang:minecraft:${project.minecraft_version}"
compileOnly 'org.github.spigot:1.16.2:1.16.2'
compileOnly 'org.github.spigot:1.8.8:1.8.8'
compileOnly 'org.github.spigot:1.7.10:1.7.10'
mappings loom.layered() {
officialMojangMappings()
parchment("org.parchmentmc.data:parchment-${project.parchment_minecraft_version}:${project.parchment_mappings}")
}
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
// Fabric API. This is technically optional, but you probably want it anyway.
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
}
group = 'io.github.retrooper'
version = '1.8.4'
description = 'packetevents'
java.sourceCompatibility = JavaVersion.VERSION_1_8
configurations.all {
resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
}
processResources {
inputs.property "version", project.version
filesMatching("fabric.mod.json") {
expand "version": project.version
}
}
tasks.withType(JavaCompile).configureEach {
// Minecraft 1.18 (1.18-pre2) upwards uses Java 17.
it.options.release = 17
}
java {
// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
// if it is present.
// If you remove this line, sources will not be generated.
withSourcesJar()
}
jar {
from("LICENSE") {
rename { "${it}_${project.archivesBaseName}"}
}
}
// configure the maven publication
publishing {
publications {
maven(MavenPublication) {
from(components.java)
}
}
}
publications {
mavenJava(MavenPublication) {
from components.java
}
}
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
repositories {
// Add repositories to publish to here.
// Notice: This block does NOT have the same function as the block in the top level.
// The repositories here will be used for publishing your artifact, not for
// retrieving dependencies.
}
}
+18
View File
@@ -0,0 +1,18 @@
# Done to increase the memory available to gradle.
org.gradle.jvmargs=-Xmx1G
# Fabric Properties
# check these on https://fabricmc.net/develop
minecraft_version=1.19.4
parchment_mappings=2023.03.12
parchment_minecraft_version=1.19.3
loader_version=0.14.18
# Mod Properties
mod_version = 2.0.0
maven_group = io.github.retrooper
archives_base_name = packetevents
# Dependencies
fabric_version=0.77.0+1.19.4
Binary file not shown.
+1 -1
View File
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored Executable → Regular
+174 -109
View File
@@ -1,67 +1,117 @@
#!/usr/bin/env sh
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn () {
echo "$*"
}
} >&2
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -71,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -82,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@@ -90,80 +140,95 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"
+10 -5
View File
@@ -1,5 +1,10 @@
/*
* This file was generated by the Gradle 'init' task.
*/
rootProject.name = 'packetevents'
pluginManagement {
repositories {
maven {
name = 'Fabric'
url = 'https://maven.fabricmc.net/'
}
mavenCentral()
gradlePluginPortal()
}
}
@@ -0,0 +1,21 @@
package io.github.retrooper.packetevents;
import io.netty.channel.ChannelPipeline;
public class ChannelUtilities {
public static boolean pipelineContainsSplitterAndPrepender(ChannelPipeline pipeline)
{
boolean containsSplitter = false;
boolean containsPrepender = false;
for(var handler : pipeline) {
PacketEventsMod.LOGGER.info(handler.getClass().getName());
if(handler.getKey().equals("splitter")) {
containsSplitter = true;
}
if(handler.getKey().equals("prepender")) {
containsPrepender = true;
}
}
return containsSplitter && containsPrepender;
}
}
@@ -1,372 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents;
import io.github.retrooper.packetevents.bstats.Metrics;
import io.github.retrooper.packetevents.event.impl.PostPlayerInjectEvent;
import io.github.retrooper.packetevents.event.manager.EventManager;
import io.github.retrooper.packetevents.event.manager.PEEventManager;
import io.github.retrooper.packetevents.exceptions.PacketEventsLoadFailureException;
import io.github.retrooper.packetevents.injector.GlobalChannelInjector;
import io.github.retrooper.packetevents.packettype.PacketType;
import io.github.retrooper.packetevents.packettype.PacketTypeClasses;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.packetwrappers.play.out.entityequipment.WrappedPacketOutEntityEquipment;
import io.github.retrooper.packetevents.processor.BukkitEventProcessorInternal;
import io.github.retrooper.packetevents.processor.PacketProcessorInternal;
import io.github.retrooper.packetevents.settings.PacketEventsSettings;
import io.github.retrooper.packetevents.updatechecker.UpdateChecker;
import io.github.retrooper.packetevents.utils.entityfinder.EntityFinderUtils;
import io.github.retrooper.packetevents.utils.guava.GuavaUtils;
import io.github.retrooper.packetevents.utils.netty.bytebuf.ByteBufUtil;
import io.github.retrooper.packetevents.utils.netty.bytebuf.ByteBufUtil_7;
import io.github.retrooper.packetevents.utils.netty.bytebuf.ByteBufUtil_8;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.player.PlayerUtils;
import io.github.retrooper.packetevents.utils.server.ServerUtils;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
import io.github.retrooper.packetevents.utils.version.PEVersion;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.ServicePriority;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
public final class PacketEvents implements Listener, EventManager {
private static PacketEvents instance;
private static Plugin plugin;
private final PEVersion version = new PEVersion(1, 8, 4);
private final EventManager eventManager = new PEEventManager();
private final PlayerUtils playerUtils = new PlayerUtils();
private final ServerUtils serverUtils = new ServerUtils();
private final PacketProcessorInternal packetProcessorInternal = new PacketProcessorInternal();
private final BukkitEventProcessorInternal bukkitEventProcessorInternal = new BukkitEventProcessorInternal();
private final GlobalChannelInjector injector = new GlobalChannelInjector();
private final AtomicBoolean injectorReady = new AtomicBoolean();
private String handlerName;
private PacketEventsSettings settings = new PacketEventsSettings();
private ByteBufUtil byteBufUtil;
private UpdateChecker updateChecker;
private volatile boolean loading, loaded;
private boolean initialized, initializing, terminating;
private boolean lateBind = false;
public static PacketEvents create(final Plugin plugin) {
if (Bukkit.isPrimaryThread()) {
//We are on the main thread
if (!Bukkit.getServicesManager().isProvidedFor(PacketEvents.class)) {
//We can register in the service manager.
instance = new PacketEvents();
Bukkit.getServicesManager().register(PacketEvents.class, instance,
plugin, ServicePriority.Normal);
PacketEvents.plugin = plugin;
return instance;
} else {
//We have already registered. Let us load what was registered.
return instance = Bukkit.getServicesManager().load(PacketEvents.class);
}
} else {
//We are off thread, we cannot use the service manager.
if (instance == null) {
PacketEvents.plugin = plugin;
instance = new PacketEvents();
}
return instance;
}
}
public static PacketEvents get() {
return instance;
}
@Deprecated
public static PacketEvents getAPI() {
return instance;
}
public void load() {
if (!loaded && !loading) {
loading = true;
//Resolve server version and cache
ServerVersion version = ServerVersion.getVersion();
WrappedPacket.version = version;
NMSUtils.version = version;
EntityFinderUtils.version = version;
handlerName = "pe-" + plugin.getName();
try {
NMSUtils.load();
PacketTypeClasses.load();
PacketType.load();
EntityFinderUtils.load();
getServerUtils().entityCache = GuavaUtils.makeMap();
if (version.isNewerThanOrEquals(ServerVersion.v_1_9)) {
for (WrappedPacketOutEntityEquipment.EquipmentSlot slot : WrappedPacketOutEntityEquipment.EquipmentSlot.values()) {
slot.id = (byte) slot.ordinal();
}
} else {
WrappedPacketOutEntityEquipment.EquipmentSlot.MAINHAND.id = 0;
WrappedPacketOutEntityEquipment.EquipmentSlot.OFFHAND.id = -1; //Invalid
WrappedPacketOutEntityEquipment.EquipmentSlot.BOOTS.id = 1;
WrappedPacketOutEntityEquipment.EquipmentSlot.LEGGINGS.id = 2;
WrappedPacketOutEntityEquipment.EquipmentSlot.CHESTPLATE.id = 3;
WrappedPacketOutEntityEquipment.EquipmentSlot.HELMET.id = 4;
}
} catch (Exception ex) {
loading = false;
throw new PacketEventsLoadFailureException(ex);
}
byteBufUtil = NMSUtils.legacyNettyImportMode ? new ByteBufUtil_7() : new ByteBufUtil_8();
updateChecker = new UpdateChecker();
if (!injectorReady.get()) {
injector.load();
lateBind = !injector.isBound();
//If late-bind is enabled, we will inject a bit later.
if (!lateBind) {
injector.inject();
}
injectorReady.set(true);
}
loaded = true;
loading = false;
}
}
@Deprecated
public void loadAsyncNewThread() {
new Thread(this::load).start();
}
@Deprecated
public void loadAsync(ExecutorService executorService) {
executorService.execute(this::load);
}
public void loadSettings(PacketEventsSettings settings) {
this.settings = settings;
}
public void init() {
init(getSettings());
}
public void init(PacketEventsSettings packetEventsSettings) {
//Load if we haven't loaded already
load();
if (!initialized && !initializing) {
initializing = true;
settings = packetEventsSettings;
settings.lock();
if (settings.shouldCheckForUpdates()) {
handleUpdateCheck();
}
if (settings.isbStatsEnabled()) {
Metrics metrics = new Metrics((JavaPlugin) getPlugin(), 11327);
//Just to have an idea what versions of packetevents people use
metrics.addCustomChart(new Metrics.SimplePie("packetevents_version", () -> {
return getVersion().toString();
}));
}
//We must wait for the injector to initialize.
//Wait for the injector to be ready.
while (!injectorReady.get()) {
}
Runnable postInjectTask = () -> {
Bukkit.getPluginManager().registerEvents(bukkitEventProcessorInternal, plugin);
for (final Player p : Bukkit.getOnlinePlayers()) {
try {
injector.injectPlayer(p);
getEventManager().callEvent(new PostPlayerInjectEvent(p, false));
} catch (Exception ex) {
p.kickPlayer("Failed to inject... Please rejoin!");
}
}
};
if (lateBind) {
//If late-bind is enabled, we still need to inject (after all plugins enabled).
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, injector::inject);
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, postInjectTask);
} else {
postInjectTask.run();
}
initialized = true;
initializing = false;
}
}
@Deprecated
public void init(Plugin plugin) {
init(plugin, settings);
}
@Deprecated
public void init(Plugin pl, PacketEventsSettings packetEventsSettings) {
init(packetEventsSettings);
}
public void terminate() {
if (initialized && !terminating) {
//Eject all players
for (Player p : Bukkit.getOnlinePlayers()) {
injector.ejectPlayer(p);
}
//Eject the injector if needed
injector.eject();
//Unregister all our listeners
getEventManager().unregisterAllListeners();
initialized = false;
terminating = false;
}
}
/**
* Use {@link #terminate()}. This is deprecated
*
* @deprecated "Stop" might be misleading and "terminate" sounds better I guess...
*/
@Deprecated
public void stop() {
terminate();
}
public boolean isLoading() {
return loading;
}
public boolean hasLoaded() {
return loaded;
}
public boolean isTerminating() {
return terminating;
}
@Deprecated
public boolean isStopping() {
return isTerminating();
}
public boolean isInitializing() {
return initializing;
}
public boolean isInitialized() {
return initialized;
}
public Plugin getPlugin() {
return plugin;
}
public GlobalChannelInjector getInjector() {
return injector;
}
public PacketProcessorInternal getInternalPacketProcessor() {
return packetProcessorInternal;
}
public String getHandlerName() {
return handlerName;
}
public PacketEventsSettings getSettings() {
return settings;
}
public PEVersion getVersion() {
return version;
}
public EventManager getEventManager() {
return eventManager;
}
public PlayerUtils getPlayerUtils() {
return playerUtils;
}
public ServerUtils getServerUtils() {
return serverUtils;
}
public ByteBufUtil getByteBufUtil() {
return byteBufUtil;
}
public UpdateChecker getUpdateChecker() {
return updateChecker;
}
private void handleUpdateCheck() {
if (updateChecker == null) {
updateChecker = new UpdateChecker();
}
Thread thread = new Thread(() -> {
getPlugin().getLogger().info("[packetevents] Checking for an update, please wait...");
UpdateChecker.UpdateCheckerStatus status = updateChecker.checkForUpdate();
int seconds = 5;
int retryCount = 5;
for (int i = 0; i < retryCount; i++) {
if (status != UpdateChecker.UpdateCheckerStatus.FAILED) {
break;
}
getPlugin().getLogger().severe("[packetevents] Checking for an update again in " + seconds + " seconds...");
try {
Thread.sleep(seconds * 1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
seconds *= 2;
status = updateChecker.checkForUpdate();
if (i == (retryCount - 1)) {
getPlugin().getLogger().severe("[packetevents] PacketEvents failed to check for an update. No longer retrying.");
break;
}
}
}, "packetevents-update-check-thread");
thread.start();
}
}
@@ -0,0 +1,62 @@
package io.github.retrooper.packetevents;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketListenerAbstract;
import com.github.retrooper.packetevents.event.PacketSendEvent;
import io.github.retrooper.packetevents.factory.fabric.FabricPacketEventsBuilder;
import io.github.retrooper.packetevents.factory.fabric.ServerInstanceManager;
import io.github.retrooper.packetevents.mixin.ClientPacketListenerAccessor;
import io.github.retrooper.packetevents.mixin.ConnectionAccessor;
import io.github.retrooper.packetevents.mixin.ServerGamePacketListenerImplAccessor;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint;
import net.minecraft.client.Minecraft;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PacketEventsMod implements PreLaunchEntrypoint, ModInitializer, ClientModInitializer {
//single player world are locked on loading, don't know why
public static final Logger LOGGER = LoggerFactory.getLogger("packetevents");
@Override
public void onPreLaunch() {
PacketEvents.setAPI(FabricPacketEventsBuilder.build("packetevents"));
PacketEvents.getAPI().getSettings().debug(true).bStats(true);
PacketEvents.getAPI().load();
//TODO Test if userconnectevent and userdisconnectevent work.
//especially disconnect
}
@Override
public void onInitialize() {
ServerInstanceManager.init();
PacketEvents.getAPI().init();
ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> {
var connection = ((ServerGamePacketListenerImplAccessor)handler).getConnection();
var channel = ((ConnectionAccessor)connection).getChannel();
if(ChannelUtilities.pipelineContainsSplitterAndPrepender(channel.pipeline()))
PacketEvents.getAPI().getInjector().setPlayer(channel, handler.player);
});
PacketEvents.getAPI().getEventManager().registerListener(new PacketListenerAbstract() {
@Override
public void onPacketSend(PacketSendEvent event) {
//System.out.println("Packet send: " + event.getPacketType());
//System.out.println("player: " + event.getPlayer());
}
});
}
@Override
public void onInitializeClient() {
ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> {
var connection = ((ClientPacketListenerAccessor)handler).getConnection();
var channel = ((ConnectionAccessor)connection).getChannel();
if(ChannelUtilities.pipelineContainsSplitterAndPrepender(channel.pipeline()))
PacketEvents.getAPI().getInjector().setPlayer(channel, Minecraft.getInstance().player);
});
}
}
@@ -1,63 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents;
import io.github.retrooper.packetevents.event.PacketListenerAbstract;
import io.github.retrooper.packetevents.event.impl.PacketPlayReceiveEvent;
import io.github.retrooper.packetevents.packettype.PacketType;
import io.github.retrooper.packetevents.packetwrappers.play.out.setslot.WrappedPacketOutSetSlot;
import io.github.retrooper.packetevents.settings.PacketEventsSettings;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.java.JavaPlugin;
public class PacketEventsPlugin extends JavaPlugin {
@Override
public void onLoad() {
PacketEventsSettings settings = PacketEvents.create(this).getSettings();
settings
.fallbackServerVersion(ServerVersion.getLatest())
.compatInjector(false)
.checkForUpdates(true)
.bStats(true);
PacketEvents.get().loadAsyncNewThread();
//You can do something here as it is loading
}
@Override
public void onEnable() {
/*PacketEvents.get().getEventManager().registerListener(new PacketListenerAbstract() {
@Override
public void onPacketPlayReceive(PacketPlayReceiveEvent event) {
if (event.getPacketId() == PacketType.Play.Client.USE_ENTITY) {
ItemStack stack = new ItemStack(Material.STICK);
WrappedPacketOutSetSlot setSlot = new WrappedPacketOutSetSlot(0, 2, stack);
PacketEvents.get().getPlayerUtils().sendPacket(event.getPlayer(), setSlot);
}
}
});*/
PacketEvents.get().init();
}
@Override
public void onDisable() {
PacketEvents.get().terminate();
}
}
@@ -1,860 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.bstats;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import javax.net.ssl.HttpsURLConnection;
import java.io.*;
import java.lang.reflect.Method;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.stream.Collectors;
import java.util.zip.GZIPOutputStream;
public class Metrics {
private final Plugin plugin;
private final MetricsBase metricsBase;
/**
* Creates a new Metrics instance.
*
* @param plugin Your plugin instance.
* @param serviceId The id of the service. It can be found at <a
* href="https://bstats.org/what-is-my-plugin-id">What is my plugin id?</a>
*/
public Metrics(JavaPlugin plugin, int serviceId) {
this.plugin = plugin;
// Get the config file
File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats");
File configFile = new File(bStatsFolder, "config.yml");
YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
if (!config.isSet("serverUuid")) {
config.addDefault("enabled", true);
config.addDefault("serverUuid", UUID.randomUUID().toString());
config.addDefault("logFailedRequests", false);
config.addDefault("logSentData", false);
config.addDefault("logResponseStatusText", false);
// Inform the server owners about bStats
config
.options()
.header(
"bStats (https://bStats.org) collects some basic information for plugin authors, like how\n"
+ "many people use their plugin and their total player count. It's recommended to keep bStats\n"
+ "enabled, but if you're not comfortable with this, you can turn this setting off. There is no\n"
+ "performance penalty associated with having metrics enabled, and data sent to bStats is fully\n"
+ "anonymous.")
.copyDefaults(true);
try {
config.save(configFile);
} catch (IOException ignored) {
}
}
// Load the data
boolean enabled = config.getBoolean("enabled", true);
String serverUUID = config.getString("serverUuid");
boolean logErrors = config.getBoolean("logFailedRequests", false);
boolean logSentData = config.getBoolean("logSentData", false);
boolean logResponseStatusText = config.getBoolean("logResponseStatusText", false);
metricsBase =
new MetricsBase(
"bukkit",
serverUUID,
serviceId,
enabled,
this::appendPlatformData,
this::appendServiceData,
submitDataTask -> Bukkit.getScheduler().runTask(plugin, submitDataTask),
plugin::isEnabled,
(message, error) -> this.plugin.getLogger().log(Level.WARNING, message, error),
(message) -> this.plugin.getLogger().log(Level.INFO, message),
logErrors,
logSentData,
logResponseStatusText);
}
/**
* Adds a custom chart.
*
* @param chart The chart to add.
*/
public void addCustomChart(CustomChart chart) {
metricsBase.addCustomChart(chart);
}
private void appendPlatformData(JsonObjectBuilder builder) {
builder.appendField("playerAmount", getPlayerAmount());
builder.appendField("onlineMode", Bukkit.getOnlineMode() ? 1 : 0);
builder.appendField("bukkitVersion", Bukkit.getVersion());
builder.appendField("bukkitName", Bukkit.getName());
builder.appendField("javaVersion", System.getProperty("java.version"));
builder.appendField("osName", System.getProperty("os.name"));
builder.appendField("osArch", System.getProperty("os.arch"));
builder.appendField("osVersion", System.getProperty("os.version"));
builder.appendField("coreCount", Runtime.getRuntime().availableProcessors());
}
private void appendServiceData(JsonObjectBuilder builder) {
builder.appendField("pluginVersion", plugin.getDescription().getVersion());
}
private int getPlayerAmount() {
try {
// Around MC 1.8 the return type was changed from an array to a collection,
// This fixes java.lang.NoSuchMethodError:
// org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection;
Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers");
return onlinePlayersMethod.getReturnType().equals(Collection.class)
? ((Collection<?>) onlinePlayersMethod.invoke(Bukkit.getServer())).size()
: ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length;
} catch (Exception e) {
// Just use the new method if the reflection failed
return Bukkit.getOnlinePlayers().size();
}
}
public static class MetricsBase {
/**
* The version of the Metrics class.
*/
public static final String METRICS_VERSION = "2.2.1";
private static final ScheduledExecutorService scheduler =
Executors.newScheduledThreadPool(1, task -> new Thread(task, "bStats-Metrics"));
private static final String REPORT_URL = "https://bStats.org/api/v2/data/%s";
private final String platform;
private final String serverUuid;
private final int serviceId;
private final Consumer<JsonObjectBuilder> appendPlatformDataConsumer;
private final Consumer<JsonObjectBuilder> appendServiceDataConsumer;
private final Consumer<Runnable> submitTaskConsumer;
private final Supplier<Boolean> checkServiceEnabledSupplier;
private final BiConsumer<String, Throwable> errorLogger;
private final Consumer<String> infoLogger;
private final boolean logErrors;
private final boolean logSentData;
private final boolean logResponseStatusText;
private final Set<CustomChart> customCharts = new HashSet<>();
private final boolean enabled;
/**
* Creates a new MetricsBase class instance.
*
* @param platform The platform of the service.
* @param serviceId The id of the service.
* @param serverUuid The server uuid.
* @param enabled Whether or not data sending is enabled.
* @param appendPlatformDataConsumer A consumer that receives a {@code JsonObjectBuilder} and
* appends all platform-specific data.
* @param appendServiceDataConsumer A consumer that receives a {@code JsonObjectBuilder} and
* appends all service-specific data.
* @param submitTaskConsumer A consumer that takes a runnable with the submit task. This can be
* used to delegate the data collection to a another thread to prevent errors caused by
* concurrency. Can be {@code null}.
* @param checkServiceEnabledSupplier A supplier to check if the service is still enabled.
* @param errorLogger A consumer that accepts log message and an error.
* @param infoLogger A consumer that accepts info log messages.
* @param logErrors Whether or not errors should be logged.
* @param logSentData Whether or not the sent data should be logged.
* @param logResponseStatusText Whether or not the response status text should be logged.
*/
public MetricsBase(
String platform,
String serverUuid,
int serviceId,
boolean enabled,
Consumer<JsonObjectBuilder> appendPlatformDataConsumer,
Consumer<JsonObjectBuilder> appendServiceDataConsumer,
Consumer<Runnable> submitTaskConsumer,
Supplier<Boolean> checkServiceEnabledSupplier,
BiConsumer<String, Throwable> errorLogger,
Consumer<String> infoLogger,
boolean logErrors,
boolean logSentData,
boolean logResponseStatusText) {
this.platform = platform;
this.serverUuid = serverUuid;
this.serviceId = serviceId;
this.enabled = enabled;
this.appendPlatformDataConsumer = appendPlatformDataConsumer;
this.appendServiceDataConsumer = appendServiceDataConsumer;
this.submitTaskConsumer = submitTaskConsumer;
this.checkServiceEnabledSupplier = checkServiceEnabledSupplier;
this.errorLogger = errorLogger;
this.infoLogger = infoLogger;
this.logErrors = logErrors;
this.logSentData = logSentData;
this.logResponseStatusText = logResponseStatusText;
checkRelocation();
if (enabled) {
startSubmitting();
}
}
/**
* Gzips the given string.
*
* @param str The string to gzip.
* @return The gzipped string.
*/
private static byte[] compress(final String str) throws IOException {
if (str == null) {
return null;
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try (GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) {
gzip.write(str.getBytes(StandardCharsets.UTF_8));
}
return outputStream.toByteArray();
}
public void addCustomChart(CustomChart chart) {
this.customCharts.add(chart);
}
private void startSubmitting() {
final Runnable submitTask =
() -> {
if (!enabled || !checkServiceEnabledSupplier.get()) {
// Submitting data or service is disabled
scheduler.shutdown();
return;
}
if (submitTaskConsumer != null) {
submitTaskConsumer.accept(this::submitData);
} else {
this.submitData();
}
};
// Many servers tend to restart at a fixed time at xx:00 which causes an uneven distribution
// of requests on the
// bStats backend. To circumvent this problem, we introduce some randomness into the initial
// and second delay.
// WARNING: You must not modify and part of this Metrics class, including the submit delay or
// frequency!
// WARNING: Modifying this code will get your plugin banned on bStats. Just don't do it!
long initialDelay = (long) (1000 * 60 * (3 + Math.random() * 3));
long secondDelay = (long) (1000 * 60 * (Math.random() * 30));
scheduler.schedule(submitTask, initialDelay, TimeUnit.MILLISECONDS);
scheduler.scheduleAtFixedRate(
submitTask, initialDelay + secondDelay, 1000 * 60 * 30, TimeUnit.MILLISECONDS);
}
private void submitData() {
final JsonObjectBuilder baseJsonBuilder = new JsonObjectBuilder();
appendPlatformDataConsumer.accept(baseJsonBuilder);
final JsonObjectBuilder serviceJsonBuilder = new JsonObjectBuilder();
appendServiceDataConsumer.accept(serviceJsonBuilder);
JsonObjectBuilder.JsonObject[] chartData =
customCharts.stream()
.map(customChart -> customChart.getRequestJsonObject(errorLogger, logErrors))
.filter(Objects::nonNull)
.toArray(JsonObjectBuilder.JsonObject[]::new);
serviceJsonBuilder.appendField("id", serviceId);
serviceJsonBuilder.appendField("customCharts", chartData);
baseJsonBuilder.appendField("service", serviceJsonBuilder.build());
baseJsonBuilder.appendField("serverUUID", serverUuid);
baseJsonBuilder.appendField("metricsVersion", METRICS_VERSION);
JsonObjectBuilder.JsonObject data = baseJsonBuilder.build();
scheduler.execute(
() -> {
try {
// Send the data
sendData(data);
} catch (Exception e) {
// Something went wrong! :(
if (logErrors) {
errorLogger.accept("Could not submit bStats metrics data", e);
}
}
});
}
private void sendData(JsonObjectBuilder.JsonObject data) throws Exception {
if (logSentData) {
infoLogger.accept("Sent bStats metrics data: " + data.toString());
}
String url = String.format(REPORT_URL, platform);
HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection();
// Compress the data to save bandwidth
byte[] compressedData = compress(data.toString());
connection.setRequestMethod("POST");
connection.addRequestProperty("Accept", "application/json");
connection.addRequestProperty("Connection", "close");
connection.addRequestProperty("Content-Encoding", "gzip");
connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length));
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("User-Agent", "Metrics-Service/1");
connection.setDoOutput(true);
try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) {
outputStream.write(compressedData);
}
StringBuilder builder = new StringBuilder();
try (BufferedReader bufferedReader =
new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
String line;
while ((line = bufferedReader.readLine()) != null) {
builder.append(line);
}
}
if (logResponseStatusText) {
infoLogger.accept("Sent data to bStats and received response: " + builder);
}
}
/**
* Checks that the class was properly relocated.
*/
private void checkRelocation() {
// You can use the property to disable the check in your test environment
if (System.getProperty("bstats.relocatecheck") == null
|| !System.getProperty("bstats.relocatecheck").equals("false")) {
// Maven's Relocate is clever and changes strings, too. So we have to use this little
// "trick" ... :D
final String defaultPackage =
new String(new byte[]{'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's'});
final String examplePackage =
new String(new byte[]{'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'});
// We want to make sure no one just copy & pastes the example and uses the wrong package
// names
if (MetricsBase.class.getPackage().getName().startsWith(defaultPackage)
|| MetricsBase.class.getPackage().getName().startsWith(examplePackage)) {
throw new IllegalStateException("bStats Metrics class has not been relocated correctly!");
}
}
}
}
public static class AdvancedBarChart extends CustomChart {
private final Callable<Map<String, int[]>> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public AdvancedBarChart(String chartId, Callable<Map<String, int[]>> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
Map<String, int[]> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
boolean allSkipped = true;
for (Map.Entry<String, int[]> entry : map.entrySet()) {
if (entry.getValue().length == 0) {
// Skip this invalid
continue;
}
allSkipped = false;
valuesBuilder.appendField(entry.getKey(), entry.getValue());
}
if (allSkipped) {
// Null = skip the chart
return null;
}
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
}
}
public static class SimpleBarChart extends CustomChart {
private final Callable<Map<String, Integer>> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public SimpleBarChart(String chartId, Callable<Map<String, Integer>> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
Map<String, Integer> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
for (Map.Entry<String, Integer> entry : map.entrySet()) {
valuesBuilder.appendField(entry.getKey(), new int[]{entry.getValue()});
}
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
}
}
public static class MultiLineChart extends CustomChart {
private final Callable<Map<String, Integer>> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public MultiLineChart(String chartId, Callable<Map<String, Integer>> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
Map<String, Integer> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
boolean allSkipped = true;
for (Map.Entry<String, Integer> entry : map.entrySet()) {
if (entry.getValue() == 0) {
// Skip this invalid
continue;
}
allSkipped = false;
valuesBuilder.appendField(entry.getKey(), entry.getValue());
}
if (allSkipped) {
// Null = skip the chart
return null;
}
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
}
}
public static class AdvancedPie extends CustomChart {
private final Callable<Map<String, Integer>> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public AdvancedPie(String chartId, Callable<Map<String, Integer>> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
Map<String, Integer> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
boolean allSkipped = true;
for (Map.Entry<String, Integer> entry : map.entrySet()) {
if (entry.getValue() == 0) {
// Skip this invalid
continue;
}
allSkipped = false;
valuesBuilder.appendField(entry.getKey(), entry.getValue());
}
if (allSkipped) {
// Null = skip the chart
return null;
}
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
}
}
public abstract static class CustomChart {
private final String chartId;
protected CustomChart(String chartId) {
if (chartId == null) {
throw new IllegalArgumentException("chartId must not be null");
}
this.chartId = chartId;
}
public JsonObjectBuilder.JsonObject getRequestJsonObject(
BiConsumer<String, Throwable> errorLogger, boolean logErrors) {
JsonObjectBuilder builder = new JsonObjectBuilder();
builder.appendField("chartId", chartId);
try {
JsonObjectBuilder.JsonObject data = getChartData();
if (data == null) {
// If the data is null we don't send the chart.
return null;
}
builder.appendField("data", data);
} catch (Throwable t) {
if (logErrors) {
errorLogger.accept("Failed to get data for custom chart with id " + chartId, t);
}
return null;
}
return builder.build();
}
protected abstract JsonObjectBuilder.JsonObject getChartData() throws Exception;
}
public static class SingleLineChart extends CustomChart {
private final Callable<Integer> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public SingleLineChart(String chartId, Callable<Integer> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
int value = callable.call();
if (value == 0) {
// Null = skip the chart
return null;
}
return new JsonObjectBuilder().appendField("value", value).build();
}
}
public static class SimplePie extends CustomChart {
private final Callable<String> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public SimplePie(String chartId, Callable<String> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
String value = callable.call();
if (value == null || value.isEmpty()) {
// Null = skip the chart
return null;
}
return new JsonObjectBuilder().appendField("value", value).build();
}
}
public static class DrilldownPie extends CustomChart {
private final Callable<Map<String, Map<String, Integer>>> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public DrilldownPie(String chartId, Callable<Map<String, Map<String, Integer>>> callable) {
super(chartId);
this.callable = callable;
}
@Override
public JsonObjectBuilder.JsonObject getChartData() throws Exception {
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
Map<String, Map<String, Integer>> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
boolean reallyAllSkipped = true;
for (Map.Entry<String, Map<String, Integer>> entryValues : map.entrySet()) {
JsonObjectBuilder valueBuilder = new JsonObjectBuilder();
boolean allSkipped = true;
for (Map.Entry<String, Integer> valueEntry : map.get(entryValues.getKey()).entrySet()) {
valueBuilder.appendField(valueEntry.getKey(), valueEntry.getValue());
allSkipped = false;
}
if (!allSkipped) {
reallyAllSkipped = false;
valuesBuilder.appendField(entryValues.getKey(), valueBuilder.build());
}
}
if (reallyAllSkipped) {
// Null = skip the chart
return null;
}
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
}
}
/**
* An extremely simple JSON builder.
*
* <p>While this class is neither feature-rich nor the most performant one, it's sufficient enough
* for its use-case.
*/
public static class JsonObjectBuilder {
private StringBuilder builder = new StringBuilder();
private boolean hasAtLeastOneField = false;
public JsonObjectBuilder() {
builder.append("{");
}
/**
* Escapes the given string like stated in https://www.ietf.org/rfc/rfc4627.txt.
*
* <p>This method escapes only the necessary characters '"', '\'. and '\u0000' - '\u001F'.
* Compact escapes are not used (e.g., '\n' is escaped as "\u000a" and not as "\n").
*
* @param value The value to escape.
* @return The escaped value.
*/
private static String escape(String value) {
final StringBuilder builder = new StringBuilder();
for (int i = 0; i < value.length(); i++) {
char c = value.charAt(i);
if (c == '"') {
builder.append("\\\"");
} else if (c == '\\') {
builder.append("\\\\");
} else if (c <= '\u000F') {
builder.append("\\u000").append(Integer.toHexString(c));
} else if (c <= '\u001F') {
builder.append("\\u00").append(Integer.toHexString(c));
} else {
builder.append(c);
}
}
return builder.toString();
}
/**
* Appends a null field to the JSON.
*
* @param key The key of the field.
* @return A reference to this object.
*/
public JsonObjectBuilder appendNull(String key) {
appendFieldUnescaped(key, "null");
return this;
}
/**
* Appends a string field to the JSON.
*
* @param key The key of the field.
* @param value The value of the field.
* @return A reference to this object.
*/
public JsonObjectBuilder appendField(String key, String value) {
if (value == null) {
throw new IllegalArgumentException("JSON value must not be null");
}
appendFieldUnescaped(key, "\"" + escape(value) + "\"");
return this;
}
/**
* Appends an integer field to the JSON.
*
* @param key The key of the field.
* @param value The value of the field.
* @return A reference to this object.
*/
public JsonObjectBuilder appendField(String key, int value) {
appendFieldUnescaped(key, String.valueOf(value));
return this;
}
/**
* Appends an object to the JSON.
*
* @param key The key of the field.
* @param object The object.
* @return A reference to this object.
*/
public JsonObjectBuilder appendField(String key, JsonObject object) {
if (object == null) {
throw new IllegalArgumentException("JSON object must not be null");
}
appendFieldUnescaped(key, object.toString());
return this;
}
/**
* Appends a string array to the JSON.
*
* @param key The key of the field.
* @param values The string array.
* @return A reference to this object.
*/
public JsonObjectBuilder appendField(String key, String[] values) {
if (values == null) {
throw new IllegalArgumentException("JSON values must not be null");
}
String escapedValues =
Arrays.stream(values)
.map(value -> "\"" + escape(value) + "\"")
.collect(Collectors.joining(","));
appendFieldUnescaped(key, "[" + escapedValues + "]");
return this;
}
/**
* Appends an integer array to the JSON.
*
* @param key The key of the field.
* @param values The integer array.
* @return A reference to this object.
*/
public JsonObjectBuilder appendField(String key, int[] values) {
if (values == null) {
throw new IllegalArgumentException("JSON values must not be null");
}
String escapedValues =
Arrays.stream(values).mapToObj(String::valueOf).collect(Collectors.joining(","));
appendFieldUnescaped(key, "[" + escapedValues + "]");
return this;
}
/**
* Appends an object array to the JSON.
*
* @param key The key of the field.
* @param values The integer array.
* @return A reference to this object.
*/
public JsonObjectBuilder appendField(String key, JsonObject[] values) {
if (values == null) {
throw new IllegalArgumentException("JSON values must not be null");
}
String escapedValues =
Arrays.stream(values).map(JsonObject::toString).collect(Collectors.joining(","));
appendFieldUnescaped(key, "[" + escapedValues + "]");
return this;
}
/**
* Appends a field to the object.
*
* @param key The key of the field.
* @param escapedValue The escaped value of the field.
*/
private void appendFieldUnescaped(String key, String escapedValue) {
if (builder == null) {
throw new IllegalStateException("JSON has already been built");
}
if (key == null) {
throw new IllegalArgumentException("JSON key must not be null");
}
if (hasAtLeastOneField) {
builder.append(",");
}
builder.append("\"").append(escape(key)).append("\":").append(escapedValue);
hasAtLeastOneField = true;
}
/**
* Builds the JSON string and invalidates this builder.
*
* @return The built JSON string.
*/
public JsonObject build() {
if (builder == null) {
throw new IllegalStateException("JSON has already been built");
}
JsonObject object = new JsonObject(builder.append("}").toString());
builder = null;
return object;
}
/**
* A super simple representation of a JSON object.
*
* <p>This class only exists to make methods of the {@link JsonObjectBuilder} type-safe and not
* allow a raw string inputs for methods like {@link JsonObjectBuilder#appendField(String,
* JsonObject)}.
*/
public static class JsonObject {
private final String value;
private JsonObject(String value) {
this.value = value;
}
@Override
public String toString() {
return value;
}
}
}
}
@@ -1,59 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event;
import io.github.retrooper.packetevents.event.eventtypes.CallableEvent;
/**
* An event in both of PacketEvents' event systems.
*
* @author retrooper
* @since 1.2.6
*/
public abstract class PacketEvent implements CallableEvent {
private long timestamp = System.currentTimeMillis();
/**
* Timestamp of when the PacketEvent was created.
* Basically timestamp of the packet.
*
* @return Packet timestamp in milliseconds.
*/
public long getTimestamp() {
return timestamp;
}
/**
* Setter for the timestamp.
*
* @param timestamp Packet timestamp in milliseconds.
*/
public void setTimestamp(final long timestamp) {
this.timestamp = timestamp;
}
public void callPacketEventExternal(final PacketListenerAbstract listener) {
listener.onPacketEventExternal(this);
}
public boolean isInbuilt() {
return false;
}
}
@@ -1,32 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event;
/**
* The legacy Packet listener.
* Implement this interface in your listener if you are using the legacy event system.
*
* @author retrooper
* @see PacketListenerAbstract
* @since 1.2.6
* @deprecated There is a new and better listener for the new event system.
*/
@Deprecated
public interface PacketListener {
}
@@ -1,201 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event;
import io.github.retrooper.packetevents.event.impl.*;
import io.github.retrooper.packetevents.event.priority.PacketEventPriority;
import io.github.retrooper.packetevents.utils.immutableset.ImmutableSetCustom;
/**
* Abstract packet listener.
*
* @author retrooper
* @since 1.8
*/
public abstract class PacketListenerAbstract {
private final PacketListenerPriority priority;
public ImmutableSetCustom<Byte> serverSidedStatusAllowance;
public ImmutableSetCustom<Byte> serverSidedLoginAllowance;
public ImmutableSetCustom<Byte> serverSidedPlayAllowance;
public ImmutableSetCustom<Byte> clientSidedStatusAllowance;
public ImmutableSetCustom<Byte> clientSidedHandshakeAllowance;
public ImmutableSetCustom<Byte> clientSidedLoginAllowance;
public ImmutableSetCustom<Byte> clientSidedPlayAllowance;
@Deprecated
public PacketListenerAbstract(final PacketEventPriority priority) {
this(PacketListenerPriority.getById(priority.getPriorityValue()));
}
public PacketListenerAbstract(PacketListenerPriority priority) {
this.priority = priority;
this.serverSidedStatusAllowance = null;
this.serverSidedLoginAllowance = null;
this.serverSidedPlayAllowance = null;
this.clientSidedStatusAllowance = null;
this.clientSidedHandshakeAllowance = null;
this.clientSidedLoginAllowance = null;
this.clientSidedPlayAllowance = null;
}
public PacketListenerAbstract() {
this(PacketListenerPriority.NORMAL);
}
public PacketListenerPriority getPriority() {
return priority;
}
public void onPacketStatusReceive(PacketStatusReceiveEvent event) {
}
public void onPacketStatusSend(PacketStatusSendEvent event) {
}
public void onPacketHandshakeReceive(PacketHandshakeReceiveEvent event) {
}
public void onPacketLoginReceive(PacketLoginReceiveEvent event) {
}
public void onPacketLoginSend(PacketLoginSendEvent event) {
}
public void onPacketPlayReceive(PacketPlayReceiveEvent event) {
}
public void onPacketPlaySend(PacketPlaySendEvent event) {
}
public void onPostPacketPlayReceive(PostPacketPlayReceiveEvent event) {
}
public void onPostPacketPlaySend(PostPacketPlaySendEvent event) {
}
public void onPostPlayerInject(PostPlayerInjectEvent event) {
}
public void onPlayerInject(PlayerInjectEvent event) {
}
public void onPlayerEject(PlayerEjectEvent event) {
}
public void onPacketEventExternal(PacketEvent event) {
}
public final void addServerSidedStatusFilter(Byte... statusPacketIDs) {
if (this.serverSidedStatusAllowance == null) {
this.serverSidedStatusAllowance = new ImmutableSetCustom<>(statusPacketIDs);
} else {
this.serverSidedStatusAllowance.addAll(statusPacketIDs);
}
}
public final void addServerSidedLoginFilter(Byte... loginPacketIDs) {
if (this.serverSidedLoginAllowance == null) {
this.serverSidedLoginAllowance = new ImmutableSetCustom<>(loginPacketIDs);
} else {
this.serverSidedLoginAllowance.addAll(loginPacketIDs);
}
}
public final void addServerSidedPlayFilter(Byte... playPacketIDs) {
if (this.serverSidedPlayAllowance == null) {
this.serverSidedPlayAllowance = new ImmutableSetCustom<>(playPacketIDs);
} else {
this.serverSidedPlayAllowance.addAll(playPacketIDs);
}
}
public final void addClientSidedStatusFilter(Byte... statusPacketIDs) {
if (this.clientSidedStatusAllowance == null) {
this.clientSidedStatusAllowance = new ImmutableSetCustom<>(statusPacketIDs);
} else {
this.clientSidedStatusAllowance.addAll(statusPacketIDs);
}
}
public final void addClientSidedHandshakeFilter(Byte... handshakePacketIDs) {
if (this.clientSidedHandshakeAllowance == null) {
this.clientSidedHandshakeAllowance = new ImmutableSetCustom<>(handshakePacketIDs);
} else {
this.clientSidedHandshakeAllowance.addAll(handshakePacketIDs);
}
}
public final void addClientSidedLoginFilter(Byte... loginPacketIDs) {
if (this.clientSidedLoginAllowance == null) {
this.clientSidedLoginAllowance = new ImmutableSetCustom<>(loginPacketIDs);
} else {
this.clientSidedLoginAllowance.addAll(loginPacketIDs);
}
}
public final void addClientSidedPlayFilter(Byte... playPacketIDs) {
if (this.clientSidedPlayAllowance == null) {
this.clientSidedPlayAllowance = new ImmutableSetCustom<>(playPacketIDs);
} else {
this.clientSidedPlayAllowance.addAll(playPacketIDs);
}
}
public final void filterAll() {
filterServerSidedStatus();
filterServerSidedLogin();
filterServerSidedPlay();
filterClientSidedStatus();
filterClientSidedHandshake();
filterClientSidedLogin();
filterClientSidedPlay();
}
public final void filterServerSidedStatus() {
this.serverSidedStatusAllowance = new ImmutableSetCustom<>();
}
public final void filterServerSidedLogin() {
this.serverSidedLoginAllowance = new ImmutableSetCustom<>();
}
public final void filterServerSidedPlay() {
this.serverSidedPlayAllowance = new ImmutableSetCustom<>();
}
public final void filterClientSidedStatus() {
this.clientSidedStatusAllowance = new ImmutableSetCustom<>();
}
public final void filterClientSidedHandshake() {
this.clientSidedHandshakeAllowance = new ImmutableSetCustom<>();
}
public final void filterClientSidedLogin() {
this.clientSidedLoginAllowance = new ImmutableSetCustom<>();
}
public final void filterClientSidedPlay() {
this.clientSidedPlayAllowance = new ImmutableSetCustom<>();
}
}
@@ -1,45 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event;
import io.github.retrooper.packetevents.event.priority.PacketEventPriority;
/**
* Deprecated abstract PacketListener.
* Please use {@link PacketListenerAbstract}, but this class will still work for a bit.
*
* @author retrooper
* @since 1.7.7
*/
@Deprecated
public abstract class PacketListenerDynamic extends PacketListenerAbstract {
@Deprecated
public PacketListenerDynamic(final PacketEventPriority priority) {
super(priority);
}
public PacketListenerDynamic(PacketListenerPriority priority) {
super(priority);
}
public PacketListenerDynamic() {
super(PacketListenerPriority.NORMAL);
}
}
@@ -1,72 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event;
/**
* The priority of packet listeners affect the order they will be invoked in.
* The lowest priority listeners are invoked first, the most high ones are invoked last.
* The most high priority listener has the final decider on an event being cancelled.
* This priority can be specified in the PacketListenerAbstract constructor.
* If you don't specify a priority in the constructor, it will use the {@link #NORMAL} priority.
*
* @author retrooper
* @since 1.8
*/
public enum PacketListenerPriority {
/**
* Listener is of very low importance.
* This listener will be ran first.
*/
LOWEST,
/**
* Listener is of low importance.
*/
LOW,
/**
* Default listener priority.
* Listener is neither important nor unimportant and may run normally.
*/
NORMAL,
/**
* Listener is of high importance.
*/
HIGH,
/**
* Listener is of critical importance and wants to decide the cancellation of an event.
*/
HIGHEST,
/**
* Listener is purely trying to decide the cancellation of an event.
* This listener should be ran last.
*/
MONITOR;
public static PacketListenerPriority getById(byte id) {
return values()[id];
}
public byte getId() {
return (byte) ordinal();
}
}
@@ -1,39 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* This is what you override your event listener with on the old event system.
* You can specify the event priority of the listener method.
*
* @author retrooper
* @since 1.0
* @deprecated Was used for the old event system, the new one doesn't need this anymore.
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Deprecated
public @interface PacketHandler {
byte priority() default 2; //NORMAL priority value
}
@@ -1,38 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event.eventtypes;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.PacketListenerAbstract;
import io.github.retrooper.packetevents.event.impl.PacketPlayReceiveEvent;
/**
* The {@link PacketEvent} implements this interface.
* Every inbuilt event should implement the {@link #call(PacketListenerAbstract)} method.
* If you are making a custom event, don't implement this.
* The {@link PacketListenerAbstract#onPacketEventExternal(PacketEvent)} method is called for every event that is not in-built.
* including custom events.
*
* @author retrooper
* @see PacketPlayReceiveEvent
* @since 1.8
*/
public interface CallableEvent {
void call(PacketListenerAbstract listener);
}
@@ -1,51 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event.eventtypes;
import io.github.retrooper.packetevents.event.impl.PacketPlayReceiveEvent;
/**
* Every event that supports cancellation should implement this interface.
* PacketEvents' event system lets the highest priority listener be have the highest priority
* in deciding whether the event will cancel.
* This means an event with a lower priority than the higher priority one would not be able to decide.
* Cancelling the event means the action assosiated with the event will be cancelled.
* For example, cancelling the {@link PacketPlayReceiveEvent}
* will prevent minecraft from processing the incoming packet.
*
* @author retrooper
* @see PacketPlayReceiveEvent
* @since 1.7
*/
public interface CancellableEvent {
/**
* This method returns if the event will be cancelled.
*
* @return Will the event be cancelled.
*/
boolean isCancelled();
/**
* Cancel or proceed with the event.
*
* @param val Is the event cancelled
*/
void setCancelled(boolean val);
}
@@ -1,41 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event.eventtypes;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import java.net.InetSocketAddress;
public abstract class CancellableNMSPacketEvent extends NMSPacketEvent implements CancellableEvent {
private boolean cancelled;
public CancellableNMSPacketEvent(Object channel, NMSPacket packet) {
super(channel, packet);
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean value) {
cancelled = value;
}
}
@@ -1,114 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event.eventtypes;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.packettype.PacketType;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import io.github.retrooper.packetevents.utils.netty.channel.ChannelUtils;
import io.github.retrooper.packetevents.utils.reflection.ClassUtil;
import java.net.InetSocketAddress;
/**
* The {@code NMSPacketEvent} abstract class represents an event that has to do with an actual packet.
* Don't mix this up with {@link io.github.retrooper.packetevents.event.PacketEvent}.
* The PacketEvent class represents an event that belongs to PacketEvent's packet system.
*
* @author retrooper
* @since 1.8
*/
public abstract class NMSPacketEvent extends PacketEvent implements CallableEvent {
private final Object channel;
private final InetSocketAddress socketAddress;
private final byte packetID;
protected NMSPacket packet;
public NMSPacketEvent(Object channel, NMSPacket packet) {
this.channel = channel;
this.socketAddress = ChannelUtils.getSocketAddress(channel);
this.packet = packet;
packetID = PacketType.packetIDMap.getOrDefault(packet.getRawNMSPacket().getClass(), PacketType.INVALID);
}
/**
* Get the associated player's socket address.
*
* @return Socket address of the associated player.
*/
public final InetSocketAddress getSocketAddress() {
return socketAddress;
}
/**
* Get the associated player's netty channel.
* @return Netty channel
*/
public Object getChannel() {
return channel;
}
/**
* This method returns the NMS name of the packet.
* To get the name of the packet we get the class of the packet and then the simple name of the class.
* See also: {@link Class#getSimpleName()}
* We cache the name after the first call to improve performance.
* It is not recommended to call this method unless you NEED it.
* If you are comparing packet types, use the {@link PacketType} byte system.
* You would only need the packet name if packet type system doesn't contain your desired packet yet.
*
* @return Name of the packet.
*/
@Deprecated
public final String getPacketName() {
return ClassUtil.getClassSimpleName(packet.getRawNMSPacket().getClass());
}
/**
* Get the NMS packet.
*
* @return Get NMS packet.
*/
public final NMSPacket getNMSPacket() {
return packet;
}
/**
* Update the NMS Packet.
*
* @param packet NMS Object
*/
public final void setNMSPacket(NMSPacket packet) {
this.packet = packet;
}
/**
* Get the Packet ID.
*
* @return Packet ID.
*/
public byte getPacketId() {
return packetID;
}
@Override
public boolean isInbuilt() {
return true;
}
}
@@ -1,38 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event.eventtypes;
import io.github.retrooper.packetevents.event.impl.PacketPlayReceiveEvent;
import org.bukkit.entity.Player;
/**
* Every event that has an associated player is recommended to implement this interface.
*
* @author retrooper
* @see PacketPlayReceiveEvent
* @since 1.6.9
*/
public interface PlayerEvent {
/**
* Associated player.
*
* @return Player.
*/
Player getPlayer();
}
@@ -1,37 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event.eventtypes;
import io.github.retrooper.packetevents.event.impl.PacketPlayReceiveEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Every event that allows you to schedule a task that will run after the action associated with the event.
*
* @author retrooper
* @since 1.8
*/
public interface PostTaskEvent {
boolean isPostTaskAvailable();
@Nullable Runnable getPostTask();
void setPostTask(@NotNull Runnable postTask);
}
@@ -1,48 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.PacketListenerAbstract;
import io.github.retrooper.packetevents.event.eventtypes.CancellableNMSPacketEvent;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import java.net.InetSocketAddress;
/**
* The {@code PacketHandshakeReceiveEvent} event is fired whenever the a HANDSHAKE packet is received from a client.
* The {@code PacketHandshakeReceiveEvent} has no Bukkit player, the player object is null in this state.
* Use the {@link #getSocketAddress()} to identify who sends the packet.
*
* @author retrooper
* @see <a href="https://wiki.vg/Protocol#Handshaking">https://wiki.vg/Protocol#Handshaking</a>
* @since 1.8
*/
public class PacketHandshakeReceiveEvent extends CancellableNMSPacketEvent {
public PacketHandshakeReceiveEvent(Object channel, NMSPacket packet) {
super(channel, packet);
}
@Override
public void call(PacketListenerAbstract listener) {
if (listener.clientSidedLoginAllowance == null || listener.clientSidedLoginAllowance.contains(getPacketId())) {
listener.onPacketHandshakeReceive(this);
}
}
}
@@ -1,47 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.PacketListenerAbstract;
import io.github.retrooper.packetevents.event.eventtypes.CancellableNMSPacketEvent;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import java.net.InetSocketAddress;
/**
* The {@code PacketLoginReceiveEvent} event is fired whenever the a LOGIN packet is received from a client.
* The {@code PacketLoginReceiveEvent} has no Bukkit player, the player object is null in this state.
* Use the {@link #getSocketAddress()} to identify who sends the packet.
*
* @author retrooper
* @see <a href="https://wiki.vg/Protocol#Login">https://wiki.vg/Protocol#Login</a>
* @since 1.8
*/
public class PacketLoginReceiveEvent extends CancellableNMSPacketEvent {
public PacketLoginReceiveEvent(Object channel, NMSPacket packet) {
super(channel, packet);
}
@Override
public void call(PacketListenerAbstract listener) {
if (listener.clientSidedLoginAllowance == null || listener.clientSidedLoginAllowance.contains(getPacketId())) {
listener.onPacketLoginReceive(this);
}
}
}
@@ -1,65 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.PacketListenerAbstract;
import io.github.retrooper.packetevents.event.eventtypes.CancellableNMSPacketEvent;
import io.github.retrooper.packetevents.event.eventtypes.PostTaskEvent;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import org.jetbrains.annotations.NotNull;
import java.net.InetSocketAddress;
/**
* The {@code PacketLoginSendEvent} event is fired whenever the a LOGIN packet is being planned to be sent to the client.
* The {@code PacketLoginSendEvent} has no Bukkit player, the player object is null in this state.
* Use the {@link #getSocketAddress()} to identify who sends the packet.
*
* @author retrooper
* @see <a href="https://wiki.vg/Protocol#Login">https://wiki.vg/Protocol#Login</a>
* @since 1.8
*/
public class PacketLoginSendEvent extends CancellableNMSPacketEvent implements PostTaskEvent {
private Runnable postTask;
public PacketLoginSendEvent(Object channel, NMSPacket packet) {
super(channel, packet);
}
@Override
public boolean isPostTaskAvailable() {
return postTask != null;
}
@Override
public Runnable getPostTask() {
return postTask;
}
@Override
public void setPostTask(@NotNull Runnable postTask) {
this.postTask = postTask;
}
@Override
public void call(PacketListenerAbstract listener) {
if (listener.serverSidedLoginAllowance == null || listener.serverSidedLoginAllowance.contains(getPacketId())) {
listener.onPacketLoginSend(this);
}
}
}
@@ -1,64 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.PacketListenerAbstract;
import io.github.retrooper.packetevents.event.eventtypes.CancellableNMSPacketEvent;
import io.github.retrooper.packetevents.event.eventtypes.PlayerEvent;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
/**
* The {@code PacketPlayReceiveEvent} event is fired whenever the a PLAY packet is
* received from any connected client.
* Cancelling this event will result in preventing minecraft from processing the incoming packet.
* It would be as if the player never sent the packet from the server's view.
*
* @author retrooper
* @see <a href="https://wiki.vg/Protocol#Play">https://wiki.vg/Protocol#Play</a>
* @since 1.2.6
*/
public final class PacketPlayReceiveEvent extends CancellableNMSPacketEvent implements PlayerEvent {
private final Player player;
public PacketPlayReceiveEvent(Player player, Object channel, NMSPacket packet) {
super(channel, packet);
this.player = player;
}
/**
* This method returns the bukkit player object of the packet sender.
* The player object might be null during early packets.
*
* @return Packet sender.
*/
@NotNull
@Override
public Player getPlayer() {
return player;
}
@Override
public void call(PacketListenerAbstract listener) {
if (listener.clientSidedPlayAllowance == null || listener.clientSidedPlayAllowance.contains(getPacketId())) {
listener.onPacketPlayReceive(this);
}
}
}
@@ -1,82 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.PacketListenerAbstract;
import io.github.retrooper.packetevents.event.eventtypes.CancellableNMSPacketEvent;
import io.github.retrooper.packetevents.event.eventtypes.PlayerEvent;
import io.github.retrooper.packetevents.event.eventtypes.PostTaskEvent;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* The {@code PacketPlaySendEvent} event is fired whenever the a PLAY packet is about to be sent to a client.
* Cancelling this event will result in preventing minecraft from sending the packet.
* The player won't receive the packet if you cancel it.
*
* @author retrooper
* @see <a href="https://wiki.vg/Protocol#Play">https://wiki.vg/Protocol#Play</a>
* @since 1.2.6
*/
public final class PacketPlaySendEvent extends CancellableNMSPacketEvent implements PlayerEvent, PostTaskEvent {
private final Player player;
private Runnable postTask;
public PacketPlaySendEvent(final Player player, final Object channel, final NMSPacket packet) {
super(channel, packet);
this.player = player;
}
/**
* This method returns the bukkit player object of the packet receiver.
* The player object might be null during early packets.
*
* @return Packet receiver.
*/
@NotNull
@Override
public Player getPlayer() {
return player;
}
@Override
public boolean isPostTaskAvailable() {
return postTask != null;
}
@Override
public Runnable getPostTask() {
return postTask;
}
@Override
public void setPostTask(@NotNull Runnable postTask) {
this.postTask = postTask;
}
@Override
public void call(PacketListenerAbstract listener) {
if (listener.serverSidedPlayAllowance == null || listener.serverSidedPlayAllowance.contains(getPacketId())) {
listener.onPacketPlaySend(this);
}
}
}
@@ -1,47 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.PacketListenerAbstract;
import io.github.retrooper.packetevents.event.eventtypes.CancellableNMSPacketEvent;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import java.net.InetSocketAddress;
/**
* The {@code PacketStatusReceiveEvent} event is fired whenever the server receives a STATUS packet from a client.
* The {@code PacketStatusSendEvent} has no Bukkit player, the player object is null in this state.
* Use the {@link #getSocketAddress()} to identify who sends the packet.
*
* @author retrooper
* @see <a href="https://wiki.vg/Protocol#Status">https://wiki.vg/Protocol#Status</a>
* @since 1.8
*/
public class PacketStatusReceiveEvent extends CancellableNMSPacketEvent {
public PacketStatusReceiveEvent(final Object channel, final NMSPacket packet) {
super(channel, packet);
}
@Override
public void call(PacketListenerAbstract listener) {
if (listener.clientSidedStatusAllowance == null || listener.clientSidedStatusAllowance.contains(getPacketId())) {
listener.onPacketStatusReceive(this);
}
}
}
@@ -1,68 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.PacketListenerAbstract;
import io.github.retrooper.packetevents.event.eventtypes.CancellableEvent;
import io.github.retrooper.packetevents.event.eventtypes.CancellableNMSPacketEvent;
import io.github.retrooper.packetevents.event.eventtypes.PostTaskEvent;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.net.InetSocketAddress;
/**
* The {@code PacketStatusSendEvent} event is fired whenever the server wants to send a STATUS packet to a client.
* This class implements {@link CancellableEvent}.
* The {@code PacketStatusSendEvent} has no Bukkit player, the player object is null in this state.
* Use the {@link #getSocketAddress()} to identify who sends the packet.
*
* @author retrooper
* @see <a href="https://wiki.vg/Protocol#Status">https://wiki.vg/Protocol#Status</a>
* @since 1.8
*/
public class PacketStatusSendEvent extends CancellableNMSPacketEvent implements PostTaskEvent {
private Runnable postTask;
public PacketStatusSendEvent(Object channel, NMSPacket packet) {
super(channel, packet);
}
@Override
public boolean isPostTaskAvailable() {
return postTask != null;
}
@Override
public Runnable getPostTask() {
return postTask;
}
@Override
public void setPostTask(@NotNull Runnable postTask) {
this.postTask = postTask;
}
@Override
public void call(PacketListenerAbstract listener) {
if (listener.serverSidedStatusAllowance == null || listener.serverSidedStatusAllowance.contains(getPacketId())) {
listener.onPacketStatusSend(this);
}
}
}
@@ -1,84 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.PacketListenerAbstract;
import io.github.retrooper.packetevents.event.eventtypes.CancellableEvent;
import io.github.retrooper.packetevents.event.eventtypes.PlayerEvent;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
/**
* The {@code PlayerEjectEvent} event is fired whenever a player is ejected.
* This class implements {@link CancellableEvent} and {@link PlayerEvent}.
*
* @author retrooper
* @see <a href="https://github.com/retrooper/packetevents/blob/dev/src/main/java/io/github/retrooper/packetevents/handler/PacketHandlerInternal.java">https://github.com/retrooper/packetevents/blob/dev/src/main/java/io/github/retrooper/packetevents/handler/PacketHandlerInternal.java</a>
* @since 1.6.9
*/
public final class PlayerEjectEvent extends PacketEvent implements CancellableEvent, PlayerEvent {
private final Player player;
private boolean cancelled;
public PlayerEjectEvent(final Player player) {
this.player = player;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean value) {
cancelled = value;
}
/**
* This method returns the bukkit player object of the player being ejected.
* The player object is guaranteed to NOT be null.
*
* @return Ejected player.
*/
@NotNull
@Override
public Player getPlayer() {
return player;
}
/**
* @return Is the event called async?
* @deprecated Now always false
*/
@Deprecated
public boolean isAsync() {
return false;
}
@Override
public void call(PacketListenerAbstract listener) {
listener.onPlayerEject(this);
}
@Override
public boolean isInbuilt() {
return true;
}
}
@@ -1,100 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.PacketListenerAbstract;
import io.github.retrooper.packetevents.event.eventtypes.CancellableEvent;
import io.github.retrooper.packetevents.event.eventtypes.PlayerEvent;
import io.github.retrooper.packetevents.utils.netty.channel.ChannelUtils;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.Nullable;
import java.net.InetSocketAddress;
/**
* The {@code PlayerInjectEvent} event is fired whenever a player is injected.
* A player is injected by PacketEvents whenever they join the server.
* This class implements {@link CancellableEvent} and {@link PlayerEvent}.
*
* @author retrooper
* @see <a href="https://github.com/retrooper/packetevents/blob/dev/src/main/java/io/github/retrooper/packetevents/handler/PacketHandlerInternal.java">https://github.com/retrooper/packetevents/blob/dev/src/main/java/io/github/retrooper/packetevents/handler/PacketHandlerInternal.java</a>
* @since 1.6.9
*/
public final class PlayerInjectEvent extends PacketEvent implements CancellableEvent, PlayerEvent {
private final Player player;
private final InetSocketAddress address;
private boolean cancelled;
public PlayerInjectEvent(final Player player) {
this.player = player;
this.address = ChannelUtils.getSocketAddress(PacketEvents.get().getPlayerUtils().getChannel(player));
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean value) {
cancelled = value;
}
/**
* This method returns the bukkit player object of the player being injected.
* This player might not be fully initialized.
*
* @return Injected Player.
*/
@Nullable
@Override
public Player getPlayer() {
return player;
}
/**
* This method returns the socket address injecting player.
*
* @return Socket address of the injecting player.
*/
@Nullable
public InetSocketAddress getSocketAddress() {
return address;
}
/**
* @deprecated Will always be false
*/
@Deprecated
public boolean isAsync() {
return false;
}
@Override
public void call(PacketListenerAbstract listener) {
listener.onPlayerInject(this);
}
@Override
public boolean isInbuilt() {
return true;
}
}
@@ -1,60 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.PacketListenerAbstract;
import io.github.retrooper.packetevents.event.eventtypes.NMSPacketEvent;
import io.github.retrooper.packetevents.event.eventtypes.PlayerEvent;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import org.bukkit.entity.Player;
/**
* The {@code PostPacketPlayReceiveEvent} event is fired after all PacketEvents listeners finished processing
* the {@code PacketPlayReceiveEvent}. This event won't be called if the PacketPlayReceiveEvent event was cancelled.
* You cannot cancel this event.
*
* @author retrooper
* @see <a href="https://wiki.vg/Protocol#Serverbound_4">https://wiki.vg/Protocol#Serverbound_4</a>
* @since 1.7
*/
public class PostPacketPlayReceiveEvent extends NMSPacketEvent implements PlayerEvent {
private final Player player;
public PostPacketPlayReceiveEvent(final Player player, final Object channel, final NMSPacket packet) {
super(channel, packet);
this.player = player;
}
/**
* This method returns the bukkit player object of the packet sender.
*
* @return Packet sender.
*/
@Override
public Player getPlayer() {
return player;
}
@Override
public void call(PacketListenerAbstract listener) {
if (listener.clientSidedPlayAllowance == null || listener.clientSidedPlayAllowance.contains(getPacketId())) {
listener.onPostPacketPlayReceive(this);
}
}
}
@@ -1,60 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.PacketListenerAbstract;
import io.github.retrooper.packetevents.event.eventtypes.NMSPacketEvent;
import io.github.retrooper.packetevents.event.eventtypes.PlayerEvent;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import org.bukkit.entity.Player;
/**
* The {@code PostPacketPlaySendEvent} event is fired after all PacketEvents listeners finished processing
* the {@code PacketPlaySendEvent}. This event won't be called if the PacketPlaySendEvent event was cancelled.
* You cannot cancel this event.
*
* @author retrooper
* @see <a href="https://wiki.vg/Protocol#Clientbound_4">https://wiki.vg/Protocol#Clientbound_4</a>
* @since 1.7
*/
public class PostPacketPlaySendEvent extends NMSPacketEvent implements PlayerEvent {
private final Player player;
public PostPacketPlaySendEvent(final Player player, final Object channel, final NMSPacket packet) {
super(channel, packet);
this.player = player;
}
/**
* This method returns the bukkit player object of the packet sender.
*
* @return Packet receiver.
*/
@Override
public Player getPlayer() {
return player;
}
@Override
public void call(PacketListenerAbstract listener) {
if (listener.serverSidedPlayAllowance == null || listener.serverSidedPlayAllowance.contains(getPacketId())) {
listener.onPostPacketPlaySend(this);
}
}
}
@@ -1,106 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.PacketListenerAbstract;
import io.github.retrooper.packetevents.event.eventtypes.PlayerEvent;
import io.github.retrooper.packetevents.utils.netty.channel.ChannelUtils;
import io.github.retrooper.packetevents.utils.player.ClientVersion;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.net.InetSocketAddress;
/**
* The {@code PostPlayerInjectEvent} event is fired after a successful injection.
* Use the {@link #isAsync()} method to figure out if is being called sync or async.
* A player is injected by PacketEvents each time they join the server.
*
* @author retrooper
* @see <a href="https://github.com/retrooper/packetevents/blob/dev/src/main/java/io/github/retrooper/packetevents/handler/PacketHandlerInternal.java">https://github.com/retrooper/packetevents/blob/dev/src/main/java/io/github/retrooper/packetevents/handler/PacketHandlerInternal.java</a>
* @since 1.3
*/
public class PostPlayerInjectEvent extends PacketEvent implements PlayerEvent {
private final Player player;
private final boolean async;
public PostPlayerInjectEvent(Player player, boolean async) {
this.player = player;
this.async = async;
}
/**
* This method returns the bukkit player object of the player that has been injected.
* The player is guaranteed to not be null.
*
* @return Injected Player.
*/
@NotNull
@Override
public Player getPlayer() {
return player;
}
/**
* This method returns the cached netty channel of the player.
*
* @return Netty channel of the injected player.
*/
@NotNull
public Object getChannel() {
return PacketEvents.get().getPlayerUtils().getChannel(player);
}
@NotNull
public InetSocketAddress getSocketAddress() {
return ChannelUtils.getSocketAddress(getChannel());
}
/**
* This method returns the ClientVersion of the injected player.
*
* @return ClientVersion of injected player.
* @see ClientVersion
*/
@NotNull
public ClientVersion getClientVersion() {
return PacketEvents.get().getPlayerUtils().getClientVersion(player);
}
/**
* Has the event been called async or sync?
*
* @return Was the event call in an async context?
*/
public boolean isAsync() {
return async;
}
@Override
public void call(PacketListenerAbstract listener) {
listener.onPostPlayerInject(this);
}
@Override
public boolean isInbuilt() {
return true;
}
}
@@ -1,194 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event.manager;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.PacketListener;
import io.github.retrooper.packetevents.event.PacketListenerAbstract;
import io.github.retrooper.packetevents.event.PacketListenerDynamic;
/**
* This is the event manager interface.
* Every method is already implemented, we just use this
* to have less code duplications.
* You can either call event manager methods in the
* {@link io.github.retrooper.packetevents.PacketEvents} instance or with an instance of the
* {@link PEEventManager} stored in {@link PacketEvents}.
*
* @author retrooper
* @see PacketEvents#getEventManager()
* @since 1.0
*/
public interface EventManager {
/**
* Call a packet event.
* This will let all listeners(new and deprecated listeners) process the event.
* It isn't recommended to use a mix of both listeners(new and deprecated),
* but it will work and they are compatible.
*
* @param event {@link PacketEvent}
* @return Same event manager instance.
*/
default EventManager callEvent(PacketEvent event) {
//The dynamic event manager calls the legacy event manager.
PEEventManager.EVENT_MANAGER_MODERN.callEvent(event);
return this;
}
/**
* Register a deprecated event listener.
* Not recommended to use the deprecated event listener.
*
* @param listener {@link PacketListener}
* @return Same event manager instance.
*/
@Deprecated
default EventManager registerListener(PacketListener listener) {
if (listener != null) {
PEEventManager.EVENT_MANAGER_LEGACY.registerListener(listener);
}
return this;
}
/**
* Register multiple deprecated event listeners with one method.
* Not recommended to use the deprecated event listener.
*
* @param listeners {@link PacketListener}
* @return Same event manager instance.
*/
@Deprecated
default EventManager registerListeners(PacketListener... listeners) {
PEEventManager.EVENT_MANAGER_LEGACY.registerListeners(listeners);
return this;
}
/**
* Unregister a deprecated event listener.
* Not recommended to use the deprecated event listener.
*
* @param listener {@link PacketListener}
* @return Same event manager instance.
*/
@Deprecated
default EventManager unregisterListener(PacketListener listener) {
PEEventManager.EVENT_MANAGER_LEGACY.unregisterListener(listener);
return this;
}
/**
* Unregister multiple deprecated event listeners with one method.
* Not recommended to use the deprecated event listener.
*
* @param listeners {@link PacketListener}
* @return Same event manager instance.
*/
@Deprecated
default EventManager unregisterListeners(PacketListener... listeners) {
PEEventManager.EVENT_MANAGER_LEGACY.unregisterListeners(listeners);
return this;
}
/**
* Register a PacketListenerDynamic listener.
*
* @param listener {@link PacketListenerDynamic}
* @return Same event manager instance.
*/
@Deprecated
default EventManager registerListener(PacketListenerDynamic listener) {
PEEventManager.EVENT_MANAGER_MODERN.registerListener(listener);
return this;
}
/**
* Register multiple PacketListenerDynamic listeners.
*
* @param listeners {@link PacketListenerDynamic}
* @return Same event manager instance.
*/
@Deprecated
default EventManager registerListeners(PacketListenerDynamic... listeners) {
PEEventManager.EVENT_MANAGER_MODERN.registerListeners(listeners);
return this;
}
/**
* Register a PacketListenerAbstract listener.
*
* @param listener {@link PacketListenerAbstract}
* @return Same event manager instance.
*/
default EventManager registerListener(PacketListenerAbstract listener) {
if (listener != null) {
PEEventManager.EVENT_MANAGER_MODERN.registerListener(listener);
}
return this;
}
/**
* Register multiple PacketListenerAbstract listeners.
*
* @param listeners {@link PacketListenerAbstract}
* @return Same event manager instance.
*/
default EventManager registerListeners(PacketListenerAbstract... listeners) {
PEEventManager.EVENT_MANAGER_MODERN.registerListeners(listeners);
return this;
}
/**
* Unregister a PacketListenerAbstract listener.
*
* @param listener {@link PacketListenerAbstract}
* @return Same event manager instance.
*/
default EventManager unregisterListener(PacketListenerAbstract listener) {
if (listener != null) {
PEEventManager.EVENT_MANAGER_MODERN.unregisterListener(listener);
}
return this;
}
/**
* Unregister multiple PacketListenerAbstract listeners.
*
* @param listeners {@link PacketListenerAbstract}
* @return Same event manager instance.
*/
default EventManager unregisterListeners(PacketListenerAbstract... listeners) {
PEEventManager.EVENT_MANAGER_MODERN.unregisterListeners(listeners);
return this;
}
/**
* Unregister all registered event listeners.
* All the deprecated and the dynamic listeners will be unregistered.
*
* @return Same event manager instance.
*/
default EventManager unregisterAllListeners() {
PEEventManager.EVENT_MANAGER_MODERN.unregisterAllListeners();
PEEventManager.EVENT_MANAGER_LEGACY.unregisterAllListeners();
return this;
}
}
@@ -1,160 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event.manager;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.PacketListener;
import io.github.retrooper.packetevents.event.annotation.PacketHandler;
import io.github.retrooper.packetevents.event.eventtypes.CancellableEvent;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@Deprecated
class EventManagerLegacy {
/**
* Map storing all all legacy packet event listeners.
* The key is an individual listener, the values are the key's event methods.
*/
private final Map<PacketListener, HashSet<Method>> staticRegisteredMethods = new HashMap<>();
/**
* Call a PacketEvent with the legacy event manager.
* This method processes the event on all legacy packet event listeners.
* This method is actually called by {@link EventManagerModern#callEvent(PacketEvent)} as the
* if you mix the two event systems, the dynamic listeners are always processed first and pass
* their highest reached event priority that this legacy one has to beat/reach to be able to cancel
* the event.
* This downside of this system is the event listeners aren't executed in any particular order, just
* in the order they were registered.
* This system is also slower than the other event system.
*
* @param event {@link PacketEvent}
* @param eventPriority Priority the legacy listeners should beat to decide cancellation of the event.
*/
@Deprecated
public void callEvent(final PacketEvent event, byte eventPriority) {
boolean isCancelled = false;
if (event instanceof CancellableEvent) {
isCancelled = ((CancellableEvent) event).isCancelled();
}
//STATIC LISTENERS
for (final PacketListener listener : staticRegisteredMethods.keySet()) {
HashSet<Method> methods = staticRegisteredMethods.get(listener);
for (Method method : methods) {
Class<?> parameterType = method.getParameterTypes()[0];
if (parameterType.equals(PacketEvent.class)
|| parameterType.isInstance(event)) {
PacketHandler annotation = method.getAnnotation(PacketHandler.class);
try {
method.invoke(listener, event);
} catch (IllegalAccessException | InvocationTargetException ex) {
ex.printStackTrace();
}
if (event instanceof CancellableEvent) {
CancellableEvent ce = (CancellableEvent) event;
if (annotation.priority() >= eventPriority) {
eventPriority = annotation.priority();
isCancelled = ce.isCancelled();
}
}
}
}
}
if (event instanceof CancellableEvent) {
CancellableEvent ce = (CancellableEvent) event;
ce.setCancelled(isCancelled);
}
}
/**
* Register a legacy packet event listener.
* Not recommended to use the deprecated event listener.
*
* @param listener {@link PacketListener}
*/
@Deprecated
public void registerListener(final PacketListener listener) {
final HashSet<Method> methods = new HashSet<>();
for (final Method m : listener.getClass().getDeclaredMethods()) {
if (!m.isAccessible()) {
m.setAccessible(true);
}
if (m.isAnnotationPresent(PacketHandler.class)
&& m.getParameterTypes().length == 1) {
methods.add(m);
}
}
if (!methods.isEmpty()) {
staticRegisteredMethods.put(listener, methods);
}
}
/**
* Register multiple legacy packet event listeners with one method.
* Not recommended to use the deprecated event listener.
*
* @param listeners {@link PacketListener}
*/
@Deprecated
public void registerListeners(final PacketListener... listeners) {
for (final PacketListener listener : listeners) {
registerListener(listener);
}
}
/**
* Unregister a legacy packet event listener.
* Not recommended to use the deprecated event listener.
*
* @param listener {@link PacketListener}
*/
@Deprecated
public void unregisterListener(final PacketListener listener) {
staticRegisteredMethods.remove(listener);
}
/**
* Unregister multiple legacy packet event listeners with one method.
* Not recommended to use the deprecated event listener.
*
* @param listeners {@link PacketListener}
*/
@Deprecated
public void unregisterListeners(final PacketListener... listeners) {
for (final PacketListener listener : listeners) {
unregisterListener(listener);
}
}
/**
* Unregister all legacy packet event listeners.
*/
@Deprecated
public void unregisterAllListeners() {
staticRegisteredMethods.clear();
}
}
@@ -1,127 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event.manager;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.PacketListenerAbstract;
import io.github.retrooper.packetevents.event.eventtypes.CancellableEvent;
import io.github.retrooper.packetevents.event.priority.PacketEventPriority;
import io.github.retrooper.packetevents.event.PacketListenerPriority;
import java.util.HashSet;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
class EventManagerModern {
private final Map<Byte, HashSet<PacketListenerAbstract>> listenersMap = new ConcurrentHashMap<>();
/**
* Call the PacketEvent.
* This method processes the event on all the registered dynamic packet event listeners.
* The {@link PacketEventPriority#LOWEST} prioritized listeners will be processing first,
* the {@link PacketEventPriority#MONITOR} will be processing last and can
* be the final decider whether the event has been cancelled or not.
* This call event also calls the legacy event manager call event.
*
* @param event {@link PacketEvent}
* @see EventManagerLegacy#callEvent(PacketEvent, byte)
*/
public void callEvent(final PacketEvent event) {
byte highestReachedPriority = (byte) (PacketListenerPriority.LOWEST.getId() - 1);
for (byte priority = PacketListenerPriority.LOWEST.getId(); priority <= PacketListenerPriority.MONITOR.getId(); priority++) {
HashSet<PacketListenerAbstract> listeners = listenersMap.get(priority);
if (listeners != null) {
for (PacketListenerAbstract listener : listeners) {
try {
event.call(listener);
} catch (Exception ex) {
PacketEvents.get().getPlugin().getLogger()
.log(Level.SEVERE, "PacketEvents found an exception while calling a packet listener.", ex);
}
//TODO Remove, because its redundant. We are only keeping it for compatibility with the legacy event manager.
if (event instanceof CancellableEvent) {
if (priority > highestReachedPriority) {
highestReachedPriority = priority;
}
}
}
}
}
PEEventManager.EVENT_MANAGER_LEGACY.callEvent(event, highestReachedPriority);
}
/**
* Register the dynamic packet event listener.
*
* @param listener {@link PacketListenerAbstract}
*/
public synchronized void registerListener(final PacketListenerAbstract listener) {
byte priority = listener.getPriority().getId();
HashSet<PacketListenerAbstract> listenerSet = listenersMap.get(priority);
if (listenerSet == null) {
listenerSet = new HashSet<>();
}
listenerSet.add(listener);
listenersMap.put(priority, listenerSet);
}
/**
* Register multiple dynamic packet event listeners with one method.
*
* @param listeners {@link PacketListenerAbstract}
*/
public synchronized void registerListeners(PacketListenerAbstract... listeners) {
for (PacketListenerAbstract listener : listeners) {
registerListener(listener);
}
}
/**
* Unregister the dynamic packet event listener.
*
* @param listener {@link PacketListenerAbstract}
*/
public synchronized void unregisterListener(final PacketListenerAbstract listener) {
byte priority = listener.getPriority().getId();
HashSet<PacketListenerAbstract> listenerSet = listenersMap.get(priority);
if (listenerSet != null) {
listenerSet.remove(listener);
}
}
/**
* Unregister multiple dynamic packet event listeners with one method.
*
* @param listeners {@link PacketListenerAbstract}
*/
public synchronized void unregisterListeners(PacketListenerAbstract... listeners) {
for (PacketListenerAbstract listener : listeners) {
unregisterListener(listener);
}
}
/**
* Unregister all dynamic packet event listeners.
*/
public synchronized void unregisterAllListeners() {
listenersMap.clear();
}
}
@@ -1,32 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event.manager;
/**
* Class storing a static instance of the dynamic and the legacy event manager.
*
* @author retrooper
* @since 1.8
*/
public class PEEventManager implements EventManager {
public static final EventManagerLegacy EVENT_MANAGER_LEGACY = new EventManagerLegacy();
public static final EventManagerModern EVENT_MANAGER_MODERN = new EventManagerModern();
}
@@ -1,92 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.event.priority;
/**
* Event priority enum for the new event system.
* The event priority counts for the whole {@link io.github.retrooper.packetevents.event.PacketListenerAbstract}
* and not for just one event.
* The priority can be specified in the PacketListenerAbstract constructor.
* If you don't specify a priority in the constructor, it will use the {@link #NORMAL} priority.
*
* @author retrooper
* @since 1.6.9
*/
@Deprecated
public enum PacketEventPriority {
/**
* The weakest event priority.
* The first to be processed(IN THE DYNAMIC EVENT SYSTEM ONLY).
* Use this if you need to be the first processing the event and
* need no power in cancelling an event or preventing an event cancellation.
*/
LOWEST,
/**
* A weak event priority.
* Second to be processed(IN THE DYNAMIC EVENT SYSTEM ONLY).
* Use this if you would prefer to be one of the first to process the event,
* but don't mind if some other listener processes before you.
*/
LOW,
/**
* Default event priority.
* Third to be processed(IN THE DYNAMIC EVENT SYSTEM ONLY).
* Use this if you don't really care/know when you process or just want to
* be in the middle.
*/
NORMAL,
/**
* Higher than the {@link PacketEventPriority#NORMAL} event priority.
* Fourth to be processed(IN THE DYNAMIC EVENT SYSTEM ONLY).
* Use this if you want to process before the default event prioritized listeners.
*/
HIGH,
/**
* Second most powerful event priority.
* Fifth to be processed(IN THE DYNAMIC EVENT SYSTEM ONLY).
* Use this if you prefer to be one of the last to process,
* but don't mind if some other listener really needs to process after you.
* Also use this if you prefer deciding if the event cancelled or not, but don't
* mind if some other listener urgently needs to decide over you.
* {@link PacketEventPriority#MONITOR} is rarely ever recommended to use.
*/
HIGHEST,
/**
* Most powerful event priority.
* Last(Sixth) to be processed(IN THE DYNAMIC EVENT SYSTEM ONLY).
* Use this if you urgently need to be the last to process
* or urgently need to be the final decider whether the event has cancelled or not.
* This is rarely recommended.
*/
MONITOR;
public static PacketEventPriority getPacketEventPriority(byte bytePriority) {
return values()[bytePriority];
}
public byte getPriorityValue() {
return (byte) ordinal();
}
}
@@ -1,45 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.exceptions;
/**
* An exception thrown by PacketEvents when the {@link io.github.retrooper.packetevents.PacketEvents#load}
* method fails to execute without any exceptions.
* Resulting in PacketEvents failing to load.
*
* @author retrooper
* @since 1.7.6
*/
public class PacketEventsLoadFailureException extends RuntimeException {
public PacketEventsLoadFailureException(String message) {
super(message);
}
public PacketEventsLoadFailureException(String message, Throwable cause) {
super(message, cause);
}
public PacketEventsLoadFailureException() {
this("PacketEvents failed to load...");
}
public PacketEventsLoadFailureException(Throwable cause) {
this("PacketEvents failed to load...", cause);
}
}
@@ -1,40 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.exceptions;
import io.github.retrooper.packetevents.utils.reflection.ClassUtil;
/**
* An exception thrown by PacketEvents when a wrapper fails
* to find a field.
*
* @author retrooper
* @see io.github.retrooper.packetevents.packetwrappers.WrappedPacket#read(int, Class)
* @see io.github.retrooper.packetevents.packetwrappers.WrappedPacket#write(Class, int, Object)
* @since 1.6.9
*/
public class WrapperFieldNotFoundException extends RuntimeException {
public WrapperFieldNotFoundException(String message) {
super(message);
}
public WrapperFieldNotFoundException(Class<?> packetClass, Class<?> type, int index) {
this("PacketEvents failed to find a " + ClassUtil.getClassSimpleName(type) + " indexed " + index + " by its type in the " + packetClass.getName() + " class!");
}
}
@@ -1,42 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.exceptions;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.reflection.ClassUtil;
/**
* An exception thrown by PacketEvents when a wrapper is used although it isn't supported on the local server version.
* Make sure to decompile a wrapper before using it, if you are unsure if it is supported through out all the server versions.
* We override a {@link WrappedPacket#isSupported()} method if it isn't supported on all server versions.
*
* @author retrooper
* @see WrappedPacket#isSupported()
* @see WrappedPacket.SupportedVersions
* @since 1.7
*/
public class WrapperUnsupportedUsageException extends RuntimeException {
public WrapperUnsupportedUsageException(String message) {
super(message);
}
public WrapperUnsupportedUsageException(Class<? extends WrappedPacket> wrapperClass) {
this("You are using a packet wrapper which happens to be unsupported on the local server version. Packet wrapper you attempted to use: " + ClassUtil.getClassSimpleName(wrapperClass));
}
}
@@ -0,0 +1,270 @@
package io.github.retrooper.packetevents.factory.fabric;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.PacketEventsAPI;
import com.github.retrooper.packetevents.injector.ChannelInjector;
import com.github.retrooper.packetevents.manager.InternalPacketListener;
import com.github.retrooper.packetevents.manager.player.PlayerManager;
import com.github.retrooper.packetevents.manager.protocol.ProtocolManager;
import com.github.retrooper.packetevents.manager.server.ServerManager;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.netty.NettyManager;
import com.github.retrooper.packetevents.protocol.ProtocolVersion;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.User;
import com.github.retrooper.packetevents.settings.PacketEventsSettings;
import com.github.retrooper.packetevents.util.LogManager;
import com.github.retrooper.packetevents.util.reflection.ReflectionObject;
import io.github.retrooper.packetevents.PacketEventsMod;
import io.github.retrooper.packetevents.handler.ServerPacketDecoder;
import io.github.retrooper.packetevents.handler.ServerPacketEncoder;
import io.github.retrooper.packetevents.impl.netty.NettyManagerImpl;
import io.github.retrooper.packetevents.impl.netty.manager.player.PlayerManagerAbstract;
import io.github.retrooper.packetevents.impl.netty.manager.protocol.ProtocolManagerAbstract;
import io.github.retrooper.packetevents.impl.netty.manager.server.ServerManagerAbstract;
import io.netty.channel.Channel;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minecraft.SharedConstants;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.network.Connection;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.entity.player.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
import java.util.logging.Level;
import java.util.regex.Pattern;
public class FabricPacketEventsBuilder {
private static final Pattern STRIP_COLOR_PATTERN = Pattern.compile("(?i)" + '\u00A7' + "[0-9A-FK-ORX]");
private static PacketEventsAPI<MinecraftServer> INSTANCE;
public static void clearBuildCache() {
INSTANCE = null;
}
public static PacketEventsAPI<MinecraftServer> build(String modId) {
if (INSTANCE == null) {
INSTANCE = buildNoCache(modId);
}
return INSTANCE;
}
public static PacketEventsAPI<MinecraftServer> build(String modId, PacketEventsSettings settings) {
if (INSTANCE == null) {
INSTANCE = buildNoCache(modId, settings);
}
return INSTANCE;
}
public static PacketEventsAPI<MinecraftServer> buildNoCache(String modId) {
return buildNoCache(modId, new PacketEventsSettings());
}
public static PacketEventsAPI<MinecraftServer> buildNoCache(String modId, PacketEventsSettings inSettings) {
return new PacketEventsAPI<>() {
private final PacketEventsSettings settings = inSettings;
//TODO Implement platform version
private final ProtocolManager protocolManager = new ProtocolManagerAbstract() {
@Override
public ProtocolVersion getPlatformVersion() {
return ProtocolVersion.UNKNOWN;
}
};
private final ServerManager serverManager = new ServerManagerAbstract() {
private static ServerVersion VERSION;
@Override
public ServerVersion getVersion() {
//TODO Not perfect, as this is on the client! Might be inaccurate by a few patch versions.
if (VERSION == null) {
int targetPV = SharedConstants.getProtocolVersion();
for (ServerVersion version : ServerVersion.reversedValues()) {
if (version.getProtocolVersion() == targetPV) {
VERSION = version;
}
}
}
return VERSION;
}
};
private final PlayerManagerAbstract playerManager = new PlayerManagerAbstract() {
@Override
public int getPing(@NotNull Object player) {
UUID id = ((Player) player).getGameProfile().getId();
try {
var minecraft = getPlugin();
if(minecraft == null)
return ((LocalPlayer) player).connection.getPlayerInfo(id).getLatency();
else {
var playerManager = minecraft.getPlayerList();
var playerEntity = playerManager.getPlayer(id);
return playerEntity.latency;
}
} catch (Exception ex) {
PacketEvents.getAPI().getLogManager().debug("Failed to get ping for player " + id);
return -1;
}
}
@Override
public Object getChannel(@NotNull Object player) {
Connection connection = ((LocalPlayer) player).connection.getConnection();
ReflectionObject reflectConnection = new ReflectionObject(connection);
return reflectConnection.readObject(0, Channel.class);
}
};
private final ChannelInjector injector = new ChannelInjector() {
@Override
public boolean isServerBound() {
return true;
}
@Override
public void inject() {
}
@Override
public void uninject() {
}
@Override
public void updateUser(Object ch, User user) {
Channel channel = (Channel) ch;
ServerPacketDecoder decoder = (ServerPacketDecoder) channel.pipeline().get(PacketEvents.DECODER_NAME);
decoder.user = user;
ServerPacketEncoder encoder = (ServerPacketEncoder) channel.pipeline().get(PacketEvents.ENCODER_NAME);
encoder.user = user;
}
@Override
public void setPlayer(Object ch, Object player) {
Channel channel = (Channel) ch;
ServerPacketDecoder decoder = (ServerPacketDecoder) channel.pipeline().get(PacketEvents.DECODER_NAME);
decoder.player = (Player) player;
ServerPacketEncoder encoder = (ServerPacketEncoder) channel.pipeline().get(PacketEvents.ENCODER_NAME);
encoder.player = (Player) player;
}
};
private final NettyManager nettyManager = new NettyManagerImpl();
private final LogManager logManager = new LogManager() {
@Override
protected void log(Level level, @Nullable NamedTextColor color, String message) {
//First we must strip away the color codes that might be in this message
message = STRIP_COLOR_PATTERN.matcher(message).replaceAll("");
PacketEventsMod.LOGGER.info(message);
}
};
private boolean loaded;
private boolean initialized;
@Override
public void load() {
if (!loaded) {
final String id = modId.toLowerCase();
//Resolve server version and cache
PacketEvents.IDENTIFIER = "pe-" + id;
PacketEvents.ENCODER_NAME = "pe-encoder-" + id;
PacketEvents.DECODER_NAME = "pe-decoder-" + id;
PacketEvents.CONNECTION_HANDLER_NAME = "pe-connection-handler-" + id;
PacketEvents.SERVER_CHANNEL_HANDLER_NAME = "pe-connection-initializer-" + id;
injector.inject();
loaded = true;
//Register internal packet listener (should be the first listener)
//This listener doesn't do any modifications to the packets, just reads data
getEventManager().registerListener(new InternalPacketListener());
}
}
@Override
public boolean isLoaded() {
return loaded;
}
@Override
public void init() {
//Load if we haven't loaded already
load();
if (!initialized) {
if (settings.shouldCheckForUpdates()) {
getUpdateChecker().handleUpdateCheck();
}
if (settings.isbStatsEnabled()) {
//TODO Cross-platform metrics?
}
PacketType.Play.Client.load();
PacketType.Play.Server.load();
initialized = true;
}
}
@Override
public boolean isInitialized() {
return initialized;
}
@Override
public void terminate() {
if (initialized) {
//Eject the injector if needed(depends on the injector implementation)
injector.uninject();
//Unregister all our listeners
getEventManager().unregisterAllListeners();
initialized = false;
}
}
@Override
public MinecraftServer getPlugin() {
return ServerInstanceManager.getServerInstance();
}
@Override
public ProtocolManager getProtocolManager() {
return protocolManager;
}
@Override
public ServerManager getServerManager() {
return serverManager;
}
@Override
public LogManager getLogManager() {
return logManager;
}
@Override
public PlayerManager getPlayerManager() {
return playerManager;
}
@Override
public ChannelInjector getInjector() {
return injector;
}
@Override
public PacketEventsSettings getSettings() {
return settings;
}
@Override
public NettyManager getNettyManager() {
return nettyManager;
}
};
}
}
@@ -0,0 +1,16 @@
package io.github.retrooper.packetevents.factory.fabric;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.minecraft.server.MinecraftServer;
public class ServerInstanceManager {
private static MinecraftServer serverInstance;
public static void init() {
ServerLifecycleEvents.SERVER_STARTED.register(server -> serverInstance = server);
ServerLifecycleEvents.SERVER_STOPPED.register(server -> serverInstance = null);
}
public static MinecraftServer getServerInstance() {
return serverInstance;
}
}
@@ -0,0 +1,31 @@
package io.github.retrooper.packetevents.handler;
import com.github.retrooper.packetevents.protocol.player.User;
import com.github.retrooper.packetevents.util.PacketEventsImplHelper;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import java.util.List;
@ChannelHandler.Sharable
public class ClientPacketDecoder extends ServerPacketDecoder {
public ClientPacketDecoder(User user) {
super(user);
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
if (msg.isReadable()) {
ByteBuf outputBuffer = ctx.alloc().buffer().writeBytes(msg);
boolean recompress = handleCompression(ctx, outputBuffer);
PacketEventsImplHelper.handleClientBoundPacket(ctx.channel(), user, player, outputBuffer, false);
//TODO hasTasksAfter
if (outputBuffer.isReadable()) {
if (recompress) {
recompress(ctx, outputBuffer);
}
out.add(outputBuffer.retain());
}
}
}
}
@@ -0,0 +1,22 @@
package io.github.retrooper.packetevents.handler;
import com.github.retrooper.packetevents.protocol.player.User;
import com.github.retrooper.packetevents.util.PacketEventsImplHelper;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
@ChannelHandler.Sharable
public class ClientPacketEncoder extends ServerPacketEncoder {
public ClientPacketEncoder(User user) {
super(user);
}
@Override
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception {
if (msg.isReadable()) {
PacketEventsImplHelper.handleServerBoundPacket(ctx.channel(), user, player, msg, false);
out.writeBytes(msg);
}
}
}
@@ -0,0 +1,104 @@
package io.github.retrooper.packetevents.handler;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.protocol.player.User;
import com.github.retrooper.packetevents.util.PacketEventsImplHelper;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import net.minecraft.world.entity.player.Player;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
@ChannelHandler.Sharable
public class PacketDecoder extends MessageToMessageDecoder<ByteBuf> {
private static Method DECOMPRESSOR_METHOD, COMPRESSOR_METHOD;
public User user;
public Player player;
public boolean checkedCompression;
public PacketDecoder(User user) {
this.user = user;
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
if (msg.isReadable()) {
ByteBuf outputBuffer = ctx.alloc().buffer().writeBytes(msg);
boolean recompress = handleCompression(ctx, outputBuffer);
PacketEventsImplHelper.handleClientBoundPacket(ctx.channel(), user, player, outputBuffer, false);
//TODO hasTasksAfter
if (outputBuffer.isReadable()) {
if (recompress) {
recompress(ctx, outputBuffer);
}
out.add(outputBuffer.retain());
}
}
}
@Override
public void channelInactive(@NotNull ChannelHandlerContext ctx) throws Exception {
super.channelInactive(ctx);
}
protected boolean handleCompression(ChannelHandlerContext ctx, ByteBuf buffer) {
if (checkedCompression) return false;
if (ctx.pipeline().names().indexOf("decompress") > ctx.pipeline().names().indexOf(PacketEvents.DECODER_NAME)) {
// Need to decompress this packet due to bad order
ChannelHandler decompressor = ctx.pipeline().get("decompress");
//CompressionDecoder
try {
if (DECOMPRESSOR_METHOD == null) {
DECOMPRESSOR_METHOD = decompressor.getClass().getDeclaredMethod("decode", ChannelHandlerContext.class, ByteBuf.class, List.class);
}
List<?> list = new ArrayList<>(1);
DECOMPRESSOR_METHOD.invoke(decompressor, ctx, buffer, list);
ByteBuf decompressed = (ByteBuf) list.get(0);
if (buffer != decompressed) {
try {
buffer.clear().writeBytes(decompressed);
} finally {
decompressed.release();
}
}
//Relocate handlers
PacketDecoder decoder = (PacketDecoder) ctx.pipeline().remove(PacketEvents.DECODER_NAME);
ctx.pipeline().addAfter("decompress", PacketEvents.DECODER_NAME, decoder);
PacketEncoder encoder = (PacketEncoder) ctx.pipeline().remove(PacketEvents.ENCODER_NAME);
ctx.pipeline().addAfter("compress", PacketEvents.ENCODER_NAME, encoder);
checkedCompression = true;
return true;
} catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
e.printStackTrace();
}
}
return false;
}
protected void recompress(ChannelHandlerContext ctx, ByteBuf buffer) {
ByteBuf compressed = ctx.alloc().buffer();
try {
ChannelHandler compressor = ctx.pipeline().get("compress");
if (COMPRESSOR_METHOD == null) {
COMPRESSOR_METHOD = compressor.getClass().getDeclaredMethod("encode", ChannelHandlerContext.class, ByteBuf.class, ByteBuf.class);
}
COMPRESSOR_METHOD.invoke(compressor, ctx, buffer, compressed);
} catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
e.printStackTrace();
}
try {
buffer.clear().writeBytes(compressed);
PacketEvents.getAPI().getLogManager().debug("Recompressed packet!");
} finally {
compressed.release();
}
}
}
@@ -0,0 +1,64 @@
package io.github.retrooper.packetevents.handler;
import com.github.retrooper.packetevents.protocol.player.User;
import com.github.retrooper.packetevents.util.PacketEventsImplHelper;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.EncoderException;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.util.ReferenceCountUtil;
import net.minecraft.world.entity.player.Player;
@ChannelHandler.Sharable
public class PacketEncoder extends MessageToByteEncoder<ByteBuf> {
public User user;
public Player player;
public PacketEncoder(User user) {
this.user = user;
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
ByteBuf buf = null;
try {
if (acceptOutboundMessage(msg)) {
ByteBuf in = (ByteBuf) msg;
buf = allocateBuffer(ctx, in, true);
try {
encode(ctx, in, buf);
} finally {
ReferenceCountUtil.release(in);
}
if (buf.isReadable()) {
ctx.write(buf, promise);
} else {
buf.release();
//We cancelled this packet, do not pass it on to the next handler.
//ctx.write(Unpooled.EMPTY_BUFFER, promise);
}
buf = null;
} else {
ctx.write(msg, promise);
}
} catch (EncoderException e) {
throw e;
} catch (Throwable e) {
throw new EncoderException(e);
} finally {
if (buf != null) {
buf.release();
}
}
}
@Override
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception {
if (msg.isReadable()) {
PacketEventsImplHelper.handleServerBoundPacket(ctx.channel(), user, player, msg, false);
out.writeBytes(msg);
}
}
}
@@ -0,0 +1,104 @@
package io.github.retrooper.packetevents.handler;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.protocol.player.User;
import com.github.retrooper.packetevents.util.PacketEventsImplHelper;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import net.minecraft.world.entity.player.Player;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
@ChannelHandler.Sharable
public class ServerPacketDecoder extends MessageToMessageDecoder<ByteBuf> {
private static Method DECOMPRESSOR_METHOD, COMPRESSOR_METHOD;
public User user;
public Player player;
public boolean checkedCompression;
public ServerPacketDecoder(User user) {
this.user = user;
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
if (msg.isReadable()) {
ByteBuf outputBuffer = ctx.alloc().buffer().writeBytes(msg);
boolean recompress = handleCompression(ctx, outputBuffer);
PacketEventsImplHelper.handleServerBoundPacket(ctx.channel(), user, player, outputBuffer, false);
//TODO hasTasksAfter
if (outputBuffer.isReadable()) {
if (recompress) {
recompress(ctx, outputBuffer);
}
out.add(outputBuffer.retain());
}
}
}
@Override
public void channelInactive(@NotNull ChannelHandlerContext ctx) throws Exception {
super.channelInactive(ctx);
}
protected boolean handleCompression(ChannelHandlerContext ctx, ByteBuf buffer) {
if (checkedCompression) return false;
if (ctx.pipeline().names().indexOf("decompress") > ctx.pipeline().names().indexOf(PacketEvents.DECODER_NAME)) {
// Need to decompress this packet due to bad order
ChannelHandler decompressor = ctx.pipeline().get("decompress");
//CompressionDecoder
try {
if (DECOMPRESSOR_METHOD == null) {
DECOMPRESSOR_METHOD = decompressor.getClass().getDeclaredMethod("decode", ChannelHandlerContext.class, ByteBuf.class, List.class);
}
List<?> list = new ArrayList<>(1);
DECOMPRESSOR_METHOD.invoke(decompressor, ctx, buffer, list);
ByteBuf decompressed = (ByteBuf) list.get(0);
if (buffer != decompressed) {
try {
buffer.clear().writeBytes(decompressed);
} finally {
decompressed.release();
}
}
//Relocate handlers
ServerPacketDecoder decoder = (ServerPacketDecoder) ctx.pipeline().remove(PacketEvents.DECODER_NAME);
ctx.pipeline().addAfter("decompress", PacketEvents.DECODER_NAME, decoder);
ServerPacketEncoder encoder = (ServerPacketEncoder) ctx.pipeline().remove(PacketEvents.ENCODER_NAME);
ctx.pipeline().addAfter("compress", PacketEvents.ENCODER_NAME, encoder);
checkedCompression = true;
return true;
} catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
e.printStackTrace();
}
}
return false;
}
protected void recompress(ChannelHandlerContext ctx, ByteBuf buffer) {
ByteBuf compressed = ctx.alloc().buffer();
try {
ChannelHandler compressor = ctx.pipeline().get("compress");
if (COMPRESSOR_METHOD == null) {
COMPRESSOR_METHOD = compressor.getClass().getDeclaredMethod("encode", ChannelHandlerContext.class, ByteBuf.class, ByteBuf.class);
}
COMPRESSOR_METHOD.invoke(compressor, ctx, buffer, compressed);
} catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
e.printStackTrace();
}
try {
buffer.clear().writeBytes(compressed);
PacketEvents.getAPI().getLogManager().debug("Recompressed packet!");
} finally {
compressed.release();
}
}
}
@@ -0,0 +1,64 @@
package io.github.retrooper.packetevents.handler;
import com.github.retrooper.packetevents.protocol.player.User;
import com.github.retrooper.packetevents.util.PacketEventsImplHelper;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.EncoderException;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.util.ReferenceCountUtil;
import net.minecraft.world.entity.player.Player;
@ChannelHandler.Sharable
public class ServerPacketEncoder extends MessageToByteEncoder<ByteBuf> {
public User user;
public Player player;
public ServerPacketEncoder(User user) {
this.user = user;
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
ByteBuf buf = null;
try {
if (acceptOutboundMessage(msg)) {
ByteBuf in = (ByteBuf) msg;
buf = allocateBuffer(ctx, in, true);
try {
encode(ctx, in, buf);
} finally {
ReferenceCountUtil.release(in);
}
if (buf.isReadable()) {
ctx.write(buf, promise);
} else {
buf.release();
//We cancelled this packet, do not pass it on to the next handler.
//ctx.write(Unpooled.EMPTY_BUFFER, promise);
}
buf = null;
} else {
ctx.write(msg, promise);
}
} catch (EncoderException e) {
throw e;
} catch (Throwable e) {
throw new EncoderException(e);
} finally {
if (buf != null) {
buf.release();
}
}
}
@Override
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception {
if (msg.isReadable()) {
PacketEventsImplHelper.handleClientBoundPacket(ctx.channel(), user, player, msg, false);
out.writeBytes(msg);
}
}
}
@@ -1,43 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.injector;
import org.bukkit.entity.Player;
public interface ChannelInjector {
default boolean isBound() {
return true;
}
void inject();
void eject();
void injectPlayer(Player player);
void ejectPlayer(Player player);
boolean hasInjected(Player player);
void writePacket(Object channel, Object rawNMSPacket);
void flushPackets(Object channel);
void sendPacket(Object channel, Object rawNMSPacket);
}
@@ -1,25 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.injector;
import org.bukkit.entity.Player;
public interface EarlyInjector extends ChannelInjector {
void updatePlayerObject(Player player, Object channel);
}
@@ -1,98 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.injector;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.event.impl.PlayerEjectEvent;
import io.github.retrooper.packetevents.event.impl.PlayerInjectEvent;
import io.github.retrooper.packetevents.injector.legacy.early.EarlyChannelInjectorLegacy;
import io.github.retrooper.packetevents.injector.legacy.late.LateChannelInjectorLegacy;
import io.github.retrooper.packetevents.injector.modern.early.EarlyChannelInjectorModern;
import io.github.retrooper.packetevents.injector.modern.late.LateChannelInjectorModern;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import org.bukkit.entity.Player;
public class GlobalChannelInjector {
private ChannelInjector injector;
public void load() {
boolean legacy = NMSUtils.legacyNettyImportMode;
if (!PacketEvents.get().getSettings().shouldUseCompatibilityInjector()) {
injector = legacy ? new EarlyChannelInjectorLegacy() : new EarlyChannelInjectorModern();
} else {
injector = legacy ? new LateChannelInjectorLegacy() : new LateChannelInjectorModern();
}
}
public boolean isBound() {
return injector.isBound();
}
public void inject() {
try {
//Try inject...
injector.inject();
} catch (Exception ex) {
//Failed to inject! Let us revert to the compatibility injector and re-inject.
if (injector instanceof EarlyInjector) {
PacketEvents.get().getSettings().compatInjector(true);
load();
injector.inject();
PacketEvents.get().getPlugin().getLogger().warning("[packetevents] Failed to inject with the Early Injector. Reverting to the Compatibility/Late Injector... This is just a warning, but please report this!");
ex.printStackTrace();
}
}
}
public void eject() {
injector.eject();
}
public void injectPlayer(Player player) {
PlayerInjectEvent injectEvent = new PlayerInjectEvent(player);
PacketEvents.get().callEvent(injectEvent);
if (!injectEvent.isCancelled()) {
injector.injectPlayer(player);
}
}
public void ejectPlayer(Player player) {
PlayerEjectEvent ejectEvent = new PlayerEjectEvent(player);
PacketEvents.get().callEvent(ejectEvent);
if (!ejectEvent.isCancelled()) {
injector.ejectPlayer(player);
}
}
public boolean hasInjected(Player player) {
return injector.hasInjected(player);
}
public void writePacket(Object ch, Object rawNMSPacket) {
injector.writePacket(ch, rawNMSPacket);
}
public void flushPackets(Object ch) {
injector.flushPackets(ch);
}
public void sendPacket(Object ch, Object rawNMSPacket) {
injector.sendPacket(ch, rawNMSPacket);
}
}
@@ -1,23 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.injector;
public interface LateInjector extends ChannelInjector {
}
@@ -1,64 +0,0 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2021 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.injector.legacy;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.processor.PacketProcessorInternal;
import net.minecraft.util.io.netty.buffer.ByteBuf;
import net.minecraft.util.io.netty.channel.ChannelDuplexHandler;
import net.minecraft.util.io.netty.channel.ChannelHandler;
import net.minecraft.util.io.netty.channel.ChannelHandlerContext;
import net.minecraft.util.io.netty.channel.ChannelPromise;
import org.bukkit.entity.Player;
@ChannelHandler.Sharable
public class PlayerChannelHandlerLegacy extends ChannelDuplexHandler {
/**
* Associated player.
* This is null until we inject the player.
*/
public volatile Player player;
@Override
public void channelRead(final ChannelHandlerContext ctx, Object packet) throws Exception {
PacketProcessorInternal.PacketData data = PacketEvents.get().getInternalPacketProcessor().read(player, ctx.channel(), packet);
if (data.packet != null) {
super.channelRead(ctx, data.packet);
PacketEvents.get().getInternalPacketProcessor().postRead(player, ctx.channel(), data.packet);
}
}
@Override
public void write(final ChannelHandlerContext ctx, Object packet, final ChannelPromise promise) throws Exception {
if (packet instanceof ByteBuf) {
//Ignore bytebufs!
super.write(ctx, packet, promise);
return;
}
PacketProcessorInternal.PacketData data = PacketEvents.get().getInternalPacketProcessor().write(player, ctx.channel(), packet);
if (data.postAction != null) {
promise.addListener(f -> {
data.postAction.run();
});
}
if (data.packet != null) {
super.write(ctx, data.packet, promise);
PacketEvents.get().getInternalPacketProcessor().postWrite(player, ctx.channel(), data.packet);
}
}
}
@@ -1,319 +0,0 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2021 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.injector.legacy.early;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.injector.EarlyInjector;
import io.github.retrooper.packetevents.injector.legacy.PlayerChannelHandlerLegacy;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.list.ListWrapper;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import net.minecraft.util.io.netty.channel.Channel;
import net.minecraft.util.io.netty.channel.ChannelFuture;
import net.minecraft.util.io.netty.channel.ChannelHandler;
import net.minecraft.util.io.netty.channel.ChannelInitializer;
import net.minecraft.util.io.netty.channel.socket.nio.NioSocketChannel;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginDescriptionFile;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class EarlyChannelInjectorLegacy implements EarlyInjector {
private final List<ChannelFuture> injectedFutures = new ArrayList<>();
private final List<Map<Field, Object>> injectedLists = new ArrayList<>();
@Override
public boolean isBound() {
try {
Object connection = NMSUtils.getMinecraftServerConnection();
if (connection == null) {
return false;
}
for (Field field : connection.getClass().getDeclaredFields()) {
field.setAccessible(true);
final Object value = field.get(connection);
if (value instanceof List) {
// Inject the list
synchronized (value) {
for (Object o : (List<?>) value) {
if (o instanceof ChannelFuture) {
return true;
} else {
break; // not the right list.
}
}
}
}
}
} catch (Exception ignored) {
}
return false;
}
@Override
public void inject() {
try {
Object serverConnection = NMSUtils.getMinecraftServerConnection();
for (Field field : serverConnection.getClass().getDeclaredFields()) {
field.setAccessible(true);
Object value = null;
try {
value = field.get(serverConnection);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
if (value instanceof List) {
//Get the list.
List<?> listWrapper = new ListWrapper((List<?>) value) {
@Override
public void processAdd(Object o) {
if (o instanceof ChannelFuture) {
try {
injectChannelFuture((ChannelFuture) o);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
};
HashMap<Field, Object> map = new HashMap<>();
map.put(field, serverConnection);
injectedLists.add(map);
field.set(serverConnection, listWrapper);
synchronized (listWrapper) {
for (Object serverChannel : (List<?>) value) {
//Is this the server channel future list?
if (serverChannel instanceof ChannelFuture) {
//Yes it is...
injectChannelFuture((ChannelFuture) serverChannel);
} else {
break;//Wrong list
}
}
}
}
}
} catch (Exception ex) {
PacketEvents.get().getPlugin().getLogger().severe("PacketEvents failed to inject!");
ex.printStackTrace();
}
//Player channels might have been registered already. Let us add our handlers. We are a little late though.
//This only happens when you join extremely early on older versions of minecraft.
List<Object> networkManagers = NMSUtils.getNetworkManagers();
synchronized (networkManagers) {
for (Object networkManager : networkManagers) {
WrappedPacket networkManagerWrapper = new WrappedPacket(new NMSPacket(networkManager), NMSUtils.networkManagerClass);
Channel channel = (Channel) networkManagerWrapper.readObject(0, NMSUtils.nettyChannelClass);
if (channel == null ||
(!channel.getClass().equals(NioSocketChannel.class))) {
continue;
}
if (channel.pipeline().get(PacketEvents.get().getHandlerName()) != null) {
channel.pipeline().remove(PacketEvents.get().getHandlerName());
}
if (channel.pipeline().get("packet_handler") != null) {
channel.pipeline().addBefore("packet_handler", PacketEvents.get().getHandlerName(), new PlayerChannelHandlerLegacy());
}
}
}
}
private void injectChannelFuture(ChannelFuture channelFuture) {
List<String> channelHandlerNames = channelFuture.channel().pipeline().names();
ChannelHandler bootstrapAcceptor = null;
Field bootstrapAcceptorField = null;
for (String handlerName : channelHandlerNames) {
ChannelHandler handler = channelFuture.channel().pipeline().get(handlerName);
try {
bootstrapAcceptorField = handler.getClass().getDeclaredField("childHandler");
bootstrapAcceptorField.setAccessible(true);
bootstrapAcceptorField.get(handler);
bootstrapAcceptor = handler;
} catch (Exception ignored) {
}
}
if (bootstrapAcceptor == null) {
bootstrapAcceptor = channelFuture.channel().pipeline().first();
}
ChannelInitializer<?> oldChannelInitializer = null;
try {
oldChannelInitializer = (ChannelInitializer<?>) bootstrapAcceptorField.get(bootstrapAcceptor);
ChannelInitializer<?> channelInitializer = new PEChannelInitializerLegacy(oldChannelInitializer);
//Replace the old channel initializer with our own.
bootstrapAcceptorField.setAccessible(true);
bootstrapAcceptorField.set(bootstrapAcceptor, channelInitializer);
injectedFutures.add(channelFuture);
} catch (IllegalAccessException e) {
ClassLoader cl = bootstrapAcceptor.getClass().getClassLoader();
if (cl.getClass().getName().equals("org.bukkit.plugin.java.PluginClassLoader")) {
PluginDescriptionFile yaml = null;
try {
yaml = (PluginDescriptionFile) PluginDescriptionFile.class.getDeclaredField("description").get(cl);
} catch (IllegalAccessException | NoSuchFieldException e2) {
e2.printStackTrace();
}
throw new IllegalStateException("PacketEvents failed to inject, because of " + bootstrapAcceptor.getClass().getName() + ", you might want to try running without " + yaml.getName() + "?");
} else {
throw new IllegalStateException("PacketEvents failed to find core component 'childHandler', please check your plugins. issue: " + bootstrapAcceptor.getClass().getName());
}
}
}
@Override
public void eject() {
Field childHandlerField = null;
for (ChannelFuture future : injectedFutures) {
List<String> names = future.channel().pipeline().names();
ChannelHandler bootstrapAcceptor = null;
// Pick best
for (String name : names) {
try {
ChannelHandler handler = future.channel().pipeline().get(name);
if (childHandlerField == null) {
childHandlerField = handler.getClass().getDeclaredField("childHandler");
childHandlerField.setAccessible(true);
}
ChannelInitializer<Channel> oldInit = (ChannelInitializer<Channel>) childHandlerField.get(handler);
if (oldInit instanceof PEChannelInitializerLegacy) {
bootstrapAcceptor = handler;
}
} catch (Exception e) {
// Not this one
}
}
// Default to first
if (bootstrapAcceptor == null) {
bootstrapAcceptor = future.channel().pipeline().first();
}
try {
ChannelInitializer<Channel> oldInit = (ChannelInitializer<Channel>) childHandlerField.get(bootstrapAcceptor);
if (oldInit instanceof PEChannelInitializerLegacy) {
childHandlerField.setAccessible(true);
childHandlerField.set(bootstrapAcceptor, ((PEChannelInitializerLegacy) oldInit).getOldChannelInitializer());
}
} catch (Exception e) {
PacketEvents.get().getPlugin().getLogger().severe("PacketEvents failed to eject the injection handler! Please reboot!");
}
}
injectedFutures.clear();
for (Map<Field, Object> map : injectedLists) {
try {
for (Field key : map.keySet()) {
key.setAccessible(true);
Object o = map.get(key);
if (o instanceof ListWrapper) {
key.set(o, ((ListWrapper) o).getOriginalList());
}
}
} catch (IllegalAccessException e) {
PacketEvents.get().getPlugin().getLogger().severe("PacketEvents failed to eject the injection handler! Please reboot!!");
}
}
injectedLists.clear();
}
@Override
public void injectPlayer(Player player) {
Object channel = PacketEvents.get().getPlayerUtils().getChannel(player);
if (channel != null) {
updatePlayerObject(player, channel);
}
}
@Override
public void ejectPlayer(Player player) {
Object channel = PacketEvents.get().getPlayerUtils().getChannel(player);
if (channel != null) {
try {
((Channel) channel).pipeline().remove(PacketEvents.get().getHandlerName());
} catch (Exception ignored) {
}
}
}
@Override
public boolean hasInjected(Player player) {
Object channel = PacketEvents.get().getPlayerUtils().getChannel(player);
if (channel == null) {
return false;
}
PlayerChannelHandlerLegacy handler = getHandler(channel);
return handler != null && handler.player != null;
}
@Override
public void writePacket(Object ch, Object rawNMSPacket) {
Channel channel = (Channel) ch;
channel.write(rawNMSPacket);
}
@Override
public void flushPackets(Object ch) {
Channel channel = (Channel) ch;
channel.flush();
}
@Override
public void sendPacket(Object ch, Object rawNMSPacket) {
Channel channel = (Channel) ch;
channel.writeAndFlush(rawNMSPacket);
}
private PlayerChannelHandlerLegacy getHandler(Object rawChannel) {
Channel channel = (Channel) rawChannel;
ChannelHandler handler = channel.pipeline().get(PacketEvents.get().getHandlerName());
if (handler instanceof PlayerChannelHandlerLegacy) {
return (PlayerChannelHandlerLegacy) handler;
} else {
return null;
}
}
@Override
public void updatePlayerObject(Player player, Object rawChannel) {
PlayerChannelHandlerLegacy handler = getHandler(rawChannel);
if (handler != null) {
handler.player = player;
}
}
}
@@ -1,62 +0,0 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2021 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.injector.legacy.early;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.injector.legacy.PlayerChannelHandlerLegacy;
import io.github.retrooper.packetevents.utils.reflection.Reflection;
import net.minecraft.util.io.netty.channel.Channel;
import net.minecraft.util.io.netty.channel.ChannelInitializer;
import net.minecraft.util.io.netty.channel.socket.nio.NioSocketChannel;
import java.lang.reflect.Method;
public class PEChannelInitializerLegacy extends ChannelInitializer<Channel> {
private final ChannelInitializer<?> oldChannelInitializer;
private Method initChannelMethod;
public PEChannelInitializerLegacy(ChannelInitializer<?> oldChannelInitializer) {
this.oldChannelInitializer = oldChannelInitializer;
load();
}
private void load() {
initChannelMethod = Reflection.getMethod(oldChannelInitializer.getClass(), "initChannel", 0);
}
public ChannelInitializer<?> getOldChannelInitializer() {
return oldChannelInitializer;
}
@Override
protected void initChannel(Channel channel) throws Exception {
initChannelMethod.invoke(oldChannelInitializer, channel);
PlayerChannelHandlerLegacy channelHandler = new PlayerChannelHandlerLegacy();
if (channel.getClass().equals(NioSocketChannel.class)) {
if (channel.pipeline().get("packet_handler") != null) {
String handlerName = PacketEvents.get().getHandlerName();
if (channel.pipeline().get(handlerName) != null) {
PacketEvents.get().getPlugin().getLogger().warning("[PacketEvents] Attempted to initialize a channel twice!");
} else {
channel.pipeline().addBefore("packet_handler", handlerName, channelHandler);
}
}
}
}
}
@@ -1,84 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.injector.legacy.late;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.injector.LateInjector;
import io.github.retrooper.packetevents.injector.legacy.PlayerChannelHandlerLegacy;
import net.minecraft.util.io.netty.channel.Channel;
import net.minecraft.util.io.netty.channel.socket.nio.NioSocketChannel;
import org.bukkit.entity.Player;
public class LateChannelInjectorLegacy implements LateInjector {
@Override
public void inject() {
}
@Override
public void eject() {
}
@Override
public void injectPlayer(Player player) {
PlayerChannelHandlerLegacy playerChannelHandlerLegacy = new PlayerChannelHandlerLegacy();
playerChannelHandlerLegacy.player = player;
Channel channel = (Channel) PacketEvents.get().getPlayerUtils().getChannel(player);
if (channel.getClass().equals(NioSocketChannel.class)) {
channel.pipeline().addBefore("packet_handler", PacketEvents.get().getHandlerName(), playerChannelHandlerLegacy);
}
}
@Override
public void ejectPlayer(Player player) {
Object channel = PacketEvents.get().getPlayerUtils().getChannel(player);
if (channel != null) {
try {
((Channel) channel).pipeline().remove(PacketEvents.get().getHandlerName());
} catch (Exception ignored) {
}
}
}
@Override
public boolean hasInjected(Player player) {
Channel channel = (Channel) PacketEvents.get().getPlayerUtils().getChannel(player);
return channel.pipeline().get(PacketEvents.get().getHandlerName()) != null;
}
@Override
public void writePacket(Object ch, Object rawNMSPacket) {
Channel channel = (Channel) ch;
channel.write(rawNMSPacket);
}
@Override
public void flushPackets(Object ch) {
Channel channel = (Channel) ch;
channel.flush();
}
@Override
public void sendPacket(Object rawChannel, Object packet) {
Channel channel = (Channel) rawChannel;
channel.pipeline().writeAndFlush(packet);
}
}
@@ -1,64 +0,0 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2021 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.injector.modern;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.processor.PacketProcessorInternal;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import org.bukkit.entity.Player;
@ChannelHandler.Sharable
public class PlayerChannelHandlerModern extends ChannelDuplexHandler {
/**
* Associated player.
* This is null until we inject the player.
*/
public volatile Player player;
@Override
public void channelRead(final ChannelHandlerContext ctx, Object packet) throws Exception {
PacketProcessorInternal.PacketData data = PacketEvents.get().getInternalPacketProcessor().read(player, ctx.channel(), packet);
if (data.packet != null) {
super.channelRead(ctx, data.packet);
PacketEvents.get().getInternalPacketProcessor().postRead(player, ctx.channel(), data.packet);
}
}
@Override
public void write(final ChannelHandlerContext ctx, Object packet, final ChannelPromise promise) throws Exception {
if (packet instanceof ByteBuf) {
//Ignore bytebufs!
super.write(ctx, packet, promise);
return;
}
PacketProcessorInternal.PacketData data = PacketEvents.get().getInternalPacketProcessor().write(player, ctx.channel(), packet);
if (data.postAction != null) {
promise.addListener(f -> {
data.postAction.run();
});
}
if (data.packet != null) {
super.write(ctx, data.packet, promise);
PacketEvents.get().getInternalPacketProcessor().postWrite(player, ctx.channel(), data.packet);
}
}
}
@@ -1,330 +0,0 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2021 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.injector.modern.early;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.injector.EarlyInjector;
import io.github.retrooper.packetevents.injector.modern.PlayerChannelHandlerModern;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.list.ListWrapper;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.epoll.EpollSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginDescriptionFile;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class EarlyChannelInjectorModern implements EarlyInjector {
private final List<ChannelFuture> injectedFutures = new ArrayList<>();
private final List<Map<Field, Object>> injectedLists = new ArrayList<>();
@Override
public boolean isBound() {
try {
Object connection = NMSUtils.getMinecraftServerConnection();
if (connection == null) {
return false;
}
for (Field field : connection.getClass().getDeclaredFields()) {
field.setAccessible(true);
final Object value = field.get(connection);
if (value instanceof List) {
// Inject the list
synchronized (value) {
for (Object o : (List) value) {
if (o instanceof ChannelFuture) {
return true;
} else {
break; // not the right list.
}
}
}
}
}
} catch (Exception e) {
}
return false;
}
@Override
public void inject() {
try {
/* if (PaperChannelInjector.PAPER_INJECTION_METHOD) {
PaperChannelInjector.setPaperChannelInitializeListener();
return;
}*/
Object serverConnection = NMSUtils.getMinecraftServerConnection();
for (Field field : serverConnection.getClass().getDeclaredFields()) {
field.setAccessible(true);
Object value = null;
try {
value = field.get(serverConnection);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
if (value instanceof List) {
//Get the list.
List listWrapper = new ListWrapper((List) value) {
@Override
public void processAdd(Object o) {
if (o instanceof ChannelFuture) {
try {
injectChannelFuture((ChannelFuture) o);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
};
HashMap<Field, Object> map = new HashMap<>();
map.put(field, serverConnection);
injectedLists.add(map);
field.set(serverConnection, listWrapper);
synchronized (listWrapper) {
for (Object serverChannel : (List) value) {
//Is this the server channel future list?
if (serverChannel instanceof ChannelFuture) {
//Yes it is...
injectChannelFuture((ChannelFuture) serverChannel);
} else {
break;//Wrong list
}
}
}
}
}
} catch (Exception ex) {
throw new IllegalStateException("PacketEvents failed to inject!", ex);
}
//Player channels might have been registered already. Let us add our handlers. We are a little late though.
//This only happens when you join extremely early on older versions of minecraft.
List<Object> networkManagers = NMSUtils.getNetworkManagers();
synchronized (networkManagers) {
for (Object networkManager : networkManagers) {
WrappedPacket networkManagerWrapper = new WrappedPacket(new NMSPacket(networkManager), NMSUtils.networkManagerClass);
Channel channel = (Channel) networkManagerWrapper.readObject(0, NMSUtils.nettyChannelClass);
if (channel == null ||
(!(channel.getClass().equals(NioSocketChannel.class))) &&
!(channel.getClass().equals(EpollSocketChannel.class))) {
continue;
}
if (channel.pipeline().get(PacketEvents.get().getHandlerName()) != null) {
channel.pipeline().remove(PacketEvents.get().getHandlerName());
}
if (channel.pipeline().get("packet_handler") != null) {
channel.pipeline().addBefore("packet_handler", PacketEvents.get().getHandlerName(), new PlayerChannelHandlerModern());
}
}
}
}
private void injectChannelFuture(ChannelFuture channelFuture) {
List<String> channelHandlerNames = channelFuture.channel().pipeline().names();
ChannelHandler bootstrapAcceptor = null;
Field bootstrapAcceptorField = null;
for (String handlerName : channelHandlerNames) {
ChannelHandler handler = channelFuture.channel().pipeline().get(handlerName);
try {
bootstrapAcceptorField = handler.getClass().getDeclaredField("childHandler");
bootstrapAcceptorField.setAccessible(true);
bootstrapAcceptorField.get(handler);
bootstrapAcceptor = handler;
} catch (Exception ignored) {
}
}
if (bootstrapAcceptor == null) {
bootstrapAcceptor = channelFuture.channel().pipeline().first();
}
ChannelInitializer<?> oldChannelInitializer;
try {
oldChannelInitializer = (ChannelInitializer<?>) bootstrapAcceptorField.get(bootstrapAcceptor);
ChannelInitializer<?> channelInitializer = new PEChannelInitializerModern(oldChannelInitializer);
//Replace the old channel initializer with our own.
bootstrapAcceptorField.setAccessible(true);
bootstrapAcceptorField.set(bootstrapAcceptor, channelInitializer);
injectedFutures.add(channelFuture);
} catch (IllegalAccessException e) {
ClassLoader cl = bootstrapAcceptor.getClass().getClassLoader();
if (cl.getClass().getName().equals("org.bukkit.plugin.java.PluginClassLoader")) {
PluginDescriptionFile yaml = null;
try {
yaml = (PluginDescriptionFile) PluginDescriptionFile.class.getDeclaredField("description").get(cl);
} catch (IllegalAccessException | NoSuchFieldException e2) {
e2.printStackTrace();
}
throw new IllegalStateException("PacketEvents failed to inject, because of " + bootstrapAcceptor.getClass().getName() + ", you might want to try running without " + yaml.getName() + "?");
} else {
throw new IllegalStateException("PacketEvents failed to find core component 'childHandler', please check your plugins. issue: " + bootstrapAcceptor.getClass().getName());
}
}
}
@Override
public void eject() {
// TODO: Uninject from players currently online to prevent protocol lib issues.
/* if (PaperChannelInjector.PAPER_INJECTION_METHOD) {
try {
PaperChannelInjector.removePaperChannelInitializeListener();
} catch (ReflectiveOperationException e) {
e.printStackTrace();
}
}*/
Field childHandlerField = null;
for (ChannelFuture future : injectedFutures) {
List<String> names = future.channel().pipeline().names();
ChannelHandler bootstrapAcceptor = null;
// Pick best
for (String name : names) {
try {
ChannelHandler handler = future.channel().pipeline().get(name);
if (childHandlerField == null) {
childHandlerField = handler.getClass().getDeclaredField("childHandler");
childHandlerField.setAccessible(true);
}
ChannelInitializer<Channel> oldInit = (ChannelInitializer<Channel>) childHandlerField.get(handler);
if (oldInit instanceof PEChannelInitializerModern) {
bootstrapAcceptor = handler;
}
} catch (Exception ignored) {
// Not this one
}
}
// Default to first
if (bootstrapAcceptor == null) {
bootstrapAcceptor = future.channel().pipeline().first();
}
try {
ChannelInitializer<Channel> oldInit = (ChannelInitializer<Channel>) childHandlerField.get(bootstrapAcceptor);
if (oldInit instanceof PEChannelInitializerModern) {
childHandlerField.setAccessible(true);
childHandlerField.set(bootstrapAcceptor, ((PEChannelInitializerModern) oldInit).getOldChannelInitializer());
}
} catch (Exception e) {
PacketEvents.get().getPlugin().getLogger().severe("PacketEvents failed to eject the injection handler! Please reboot!");
}
}
injectedFutures.clear();
for (Map<Field, Object> map : injectedLists) {
try {
for (Field key : map.keySet()) {
key.setAccessible(true);
Object o = map.get(key);
if (o instanceof ListWrapper) {
key.set(o, ((ListWrapper) o).getOriginalList());
}
}
} catch (IllegalAccessException e) {
PacketEvents.get().getPlugin().getLogger().severe("PacketEvents failed to eject the injection handler! Please reboot!!");
}
}
injectedLists.clear();
}
@Override
public void injectPlayer(Player player) {
Object channel = PacketEvents.get().getPlayerUtils().getChannel(player);
if (channel != null) {
updatePlayerObject(player, channel);
}
}
@Override
public void ejectPlayer(Player player) {
Object channel = PacketEvents.get().getPlayerUtils().getChannel(player);
if (channel != null) {
Channel chnl = (Channel) channel;
try {
chnl.pipeline().remove(PacketEvents.get().getHandlerName());
} catch (Exception ignored) {
}
}
}
@Override
public boolean hasInjected(Player player) {
Object channel = PacketEvents.get().getPlayerUtils().getChannel(player);
if (channel == null) {
return false;
}
PlayerChannelHandlerModern handler = getHandler(channel);
return handler != null && handler.player != null;
}
@Override
public void writePacket(Object ch, Object rawNMSPacket) {
Channel channel = (Channel) ch;
channel.write(rawNMSPacket);
}
@Override
public void flushPackets(Object ch) {
Channel channel = (Channel) ch;
channel.flush();
}
@Override
public void sendPacket(Object ch, Object rawNMSPacket) {
Channel channel = (Channel) ch;
channel.writeAndFlush(rawNMSPacket);
}
private PlayerChannelHandlerModern getHandler(Object rawChannel) {
Channel channel = (Channel) rawChannel;
ChannelHandler handler = channel.pipeline().get(PacketEvents.get().getHandlerName());
if (handler instanceof PlayerChannelHandlerModern) {
return (PlayerChannelHandlerModern) handler;
} else {
return null;
}
}
@Override
public void updatePlayerObject(Player player, Object rawChannel) {
PlayerChannelHandlerModern handler = getHandler(rawChannel);
if (handler != null) {
handler.player = player;
}
}
}
@@ -1,69 +0,0 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2021 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.injector.modern.early;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.injector.modern.PlayerChannelHandlerModern;
import io.github.retrooper.packetevents.utils.reflection.Reflection;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.epoll.EpollSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.lang.reflect.Method;
public class PEChannelInitializerModern extends ChannelInitializer<Channel> {
private final ChannelInitializer<?> oldChannelInitializer;
private Method initChannelMethod;
public PEChannelInitializerModern(ChannelInitializer<?> oldChannelInitializer) {
this.oldChannelInitializer = oldChannelInitializer;
load();
}
public static void postInitChannel(Channel channel) {
if (channel.getClass().equals(NioSocketChannel.class)
|| channel.getClass().equals(EpollSocketChannel.class)) {
PlayerChannelHandlerModern channelHandler = new PlayerChannelHandlerModern();
if (channel.pipeline().get("packet_handler") != null) {
String handlerName = PacketEvents.get().getHandlerName();
if (channel.pipeline().get(handlerName) != null) {
//Just ignore this to support latest ProtocolLib snapshots.
//PacketEvents.get().getPlugin().getLogger().warning("[PacketEvents] Attempted to initialize a channel twice!");
} else {
channel.pipeline().addBefore("packet_handler", handlerName, channelHandler);
}
}
}
}
private void load() {
initChannelMethod = Reflection.getMethod(oldChannelInitializer.getClass(), "initChannel", 0);
}
public ChannelInitializer<?> getOldChannelInitializer() {
return oldChannelInitializer;
}
@Override
protected void initChannel(Channel channel) throws Exception {
initChannelMethod.invoke(oldChannelInitializer, channel);
postInitChannel(channel);
}
}
@@ -1,87 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.injector.modern.late;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.injector.LateInjector;
import io.github.retrooper.packetevents.injector.modern.PlayerChannelHandlerModern;
import io.netty.channel.Channel;
import io.netty.channel.epoll.EpollSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.bukkit.entity.Player;
public class LateChannelInjectorModern implements LateInjector {
@Override
public void inject() {
}
@Override
public void eject() {
}
@Override
public void injectPlayer(Player player) {
PlayerChannelHandlerModern playerChannelHandlerModern = new PlayerChannelHandlerModern();
playerChannelHandlerModern.player = player;
Channel channel = (Channel) PacketEvents.get().getPlayerUtils().getChannel(player);
if (channel.getClass().equals(NioSocketChannel.class) ||
channel.getClass().equals(EpollSocketChannel.class)) {
channel.pipeline().addBefore("packet_handler", PacketEvents.get().getHandlerName(), playerChannelHandlerModern);
}
}
@Override
public void ejectPlayer(Player player) {
Object channel = PacketEvents.get().getPlayerUtils().getChannel(player);
if (channel != null) {
Channel chnl = (Channel) channel;
try {
chnl.pipeline().remove(PacketEvents.get().getHandlerName());
} catch (Exception ex) {
}
}
}
@Override
public boolean hasInjected(Player player) {
Channel channel = (Channel) PacketEvents.get().getPlayerUtils().getChannel(player);
return channel.pipeline().get(PacketEvents.get().getHandlerName()) != null;
}
@Override
public void writePacket(Object ch, Object rawNMSPacket) {
Channel channel = (Channel) ch;
channel.write(rawNMSPacket);
}
@Override
public void flushPackets(Object ch) {
Channel channel = (Channel) ch;
channel.flush();
}
@Override
public void sendPacket(Object rawChannel, Object packet) {
Channel channel = (Channel) rawChannel;
channel.pipeline().writeAndFlush(packet);
}
}
@@ -0,0 +1,12 @@
package io.github.retrooper.packetevents.mixin;
import net.minecraft.client.multiplayer.ClientPacketListener;
import net.minecraft.network.Connection;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(ClientPacketListener.class)
public interface ClientPacketListenerAccessor {
@Accessor
Connection getConnection();
}
@@ -0,0 +1,11 @@
package io.github.retrooper.packetevents.mixin;
import io.netty.channel.Channel;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(net.minecraft.network.Connection.class)
public interface ConnectionAccessor {
@Accessor
Channel getChannel();
}
@@ -0,0 +1,67 @@
package io.github.retrooper.packetevents.mixin;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.protocol.ProtocolManager;
import com.github.retrooper.packetevents.netty.channel.ChannelHelper;
import com.github.retrooper.packetevents.protocol.ConnectionState;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.User;
import com.github.retrooper.packetevents.protocol.player.UserProfile;
import io.github.retrooper.packetevents.ChannelUtilities;
import io.github.retrooper.packetevents.PacketEventsMod;
import io.github.retrooper.packetevents.handler.ServerPacketDecoder;
import io.github.retrooper.packetevents.handler.ServerPacketEncoder;
import io.github.retrooper.packetevents.handler.ClientPacketDecoder;
import io.github.retrooper.packetevents.handler.ClientPacketEncoder;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import net.minecraft.network.protocol.PacketFlow;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(net.minecraft.network.Connection.class)
public class PacketEventsInjectorMixin {
@Shadow @Final
private PacketFlow receiving;
@Inject(method = "channelActive", at = @At("HEAD"))
private void channelActive(ChannelHandlerContext ctx, CallbackInfo info) {
Channel channel = ctx.channel();
User user = new User(channel, ConnectionState.HANDSHAKING, ClientVersion.getLatest(),
new UserProfile(null, null));
ProtocolManager.USERS.put(channel, user);
ServerPacketDecoder decoder;
ServerPacketEncoder encoder;
if(receiving == PacketFlow.CLIENTBOUND) {
PacketEventsMod.LOGGER.info("Connected as Client!");
decoder = new ClientPacketDecoder(user);
encoder = new ClientPacketEncoder(user);
}
else
{
PacketEventsMod.LOGGER.info("Connected as Server!");
decoder = new ServerPacketDecoder(user);
encoder = new ServerPacketEncoder(user);
}
if(ChannelUtilities.pipelineContainsSplitterAndPrepender(channel.pipeline()))
{
channel.pipeline().addAfter("splitter", PacketEvents.DECODER_NAME, decoder);
channel.pipeline().addAfter("prepender", PacketEvents.ENCODER_NAME, encoder);
}
PacketEventsMod.LOGGER.info("Pipeline: " + ChannelHelper.pipelineHandlerNamesAsString(channel));
}
@Inject(method = "channelInactive", at = @At("HEAD"))
private void channelInactive(ChannelHandlerContext ctx, CallbackInfo info) {
PacketEventsMod.LOGGER.debug("Disconnected!");
}
}
@@ -0,0 +1,12 @@
package io.github.retrooper.packetevents.mixin;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import net.minecraft.network.Connection;
@Mixin(ServerGamePacketListenerImpl.class)
public interface ServerGamePacketListenerImplAccessor {
@Accessor
Connection getConnection();
}
@@ -1,27 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.packettype;
/**
* @author retrooper
* @since 1.8
*/
public enum PacketState {
STATUS, HANDSHAKING, LOGIN, PLAY
}
@@ -1,467 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.packettype;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
import java.util.IdentityHashMap;
import java.util.Map;
/**
* Packet Type IDs.
* This is the Packet ID system, it is recommended to use this over packet comparisons by packet name.
* This is also faster than comparing packet names.
*
* @author retrooper
* @since 1.6.8
*/
public class PacketType {
/**
* If a Packet Type could not be resolved, it will be set to the current value of this constant.
* This value may change over the versions so it is important to use the variable and not hard code its value.
*/
public static final byte INVALID = -128;
public static final Map<Class<?>, Byte> packetIDMap = new IdentityHashMap<>();
private static final boolean isNine = ServerVersion.getVersion().isNewerThanOrEquals(ServerVersion.v_1_9);
private static void insertPacketID(Class<?> cls, byte packetID) {
if (cls != null) {
packetIDMap.put(cls, packetID);
}
}
public static void load() {
Status.Client.load();
Status.Server.load();
Handshaking.Client.load();
Login.Client.load();
Login.Server.load();
Play.Client.load();
Play.Server.load();
}
/**
* Status Packet IDs.
*
* @author retrooper
* @see <a href="https://wiki.vg/Protocol#Status">https://wiki.vg/Protocol#Status</a>
* @since 1.7
*/
public static class Status {
/**
* Server-bound (client-sided) Status Packet IDs.
*
* @author retrooper
* @see <a href="https://wiki.vg/Protocol#Serverbound_2">https://wiki.vg/Protocol#Serverbound_2</a>
* @since 1.8
*/
public static class Client {
public static final byte START = -127, PING = -126;
private static void load() {
insertPacketID(PacketTypeClasses.Status.Client.START, Client.START);
insertPacketID(PacketTypeClasses.Status.Client.PING, Client.PING);
}
}
/**
* Client-bound (server-sided) Status Packet IDs.
*
* @author retrooper
* @see <a href="https://wiki.vg/Protocol#Clientbound_2">https://wiki.vg/Protocol#Clientbound_2</a>
* @since 1.8
*/
public static class Server {
public static final byte PONG = -125, SERVER_INFO = -124;
private static void load() {
insertPacketID(PacketTypeClasses.Status.Server.PONG, Server.PONG);
insertPacketID(PacketTypeClasses.Status.Server.SERVER_INFO, Server.SERVER_INFO);
}
}
}
/**
* Handshaking Packet IDs.
*
* @author retrooper
* @see <a href="https://wiki.vg/Protocol#Handshaking">https://wiki.vg/Protocol#Handshaking</a>
* @since 1.8
*/
public static class Handshaking {
/**
* Server-bound (client-sided) Handshaking Packet IDs.
*
* @author retrooper
* @since 1.8
*/
public static class Client {
public static final byte SET_PROTOCOL = -123;
private static void load() {
insertPacketID(PacketTypeClasses.Handshaking.Client.SET_PROTOCOL, Client.SET_PROTOCOL);
}
}
}
/**
* Login Packet IDs.
*
* @author retrooper
* @see <a href="https://wiki.vg/Protocol#Login">https://wiki.vg/Protocol#Login</a>
* @since 1.7
*/
public static class Login {
/**
* Server-bound (client-sided) Login Packet IDs.
*
* @author retrooper
* @see <a href="https://wiki.vg/Protocol#Serverbound_3">https://wiki.vg/Protocol#Serverbound_3</a>
* @since 1.8
*/
public static class Client {
public static final byte CUSTOM_PAYLOAD = -122, START = -121, ENCRYPTION_BEGIN = -120;
private static void load() {
insertPacketID(PacketTypeClasses.Login.Client.CUSTOM_PAYLOAD, Client.CUSTOM_PAYLOAD);
insertPacketID(PacketTypeClasses.Login.Client.START, Client.START);
insertPacketID(PacketTypeClasses.Login.Client.ENCRYPTION_BEGIN, Client.ENCRYPTION_BEGIN);
}
}
/**
* Client-bound (server-sided) Login Packet IDs.
*
* @author retrooper
* @see <a href="https://wiki.vg/Protocol#Clientbound_3">https://wiki.vg/Protocol#Clientbound_3</a>
* @since 1.8
*/
public static class Server {
public static final byte CUSTOM_PAYLOAD = -119, DISCONNECT = -118, ENCRYPTION_BEGIN = -117, SUCCESS = -116, SET_COMPRESSION = -115;
private static void load() {
insertPacketID(PacketTypeClasses.Login.Server.CUSTOM_PAYLOAD, Server.CUSTOM_PAYLOAD);
insertPacketID(PacketTypeClasses.Login.Server.DISCONNECT, Server.DISCONNECT);
insertPacketID(PacketTypeClasses.Login.Server.ENCRYPTION_BEGIN, Server.ENCRYPTION_BEGIN);
insertPacketID(PacketTypeClasses.Login.Server.SUCCESS, Server.SUCCESS);
insertPacketID(PacketTypeClasses.Login.Server.SET_COMPRESSION, Server.SET_COMPRESSION);
}
}
}
/**
* Play Packet IDs.
*
* @author retrooper
* @see <a href="https://wiki.vg/Protocol#Play">https://wiki.vg/Protocol#Play</a>
* @since 1.8
*/
public static class Play {
/**
* Server-bound (client-sided) Play Packet IDs.
*
* @author retrooper
* @see <a href="https://wiki.vg/Protocol#Serverbound_4">https://wiki.vg/Protocol#Serverbound_4</a>
* @since 1.8
*/
public static class Client {
public static final byte TELEPORT_ACCEPT = -114,
TILE_NBT_QUERY = -113, DIFFICULTY_CHANGE = -112, CHAT = -111, CLIENT_COMMAND = -110,
SETTINGS = -109, TAB_COMPLETE = -108, TRANSACTION = -107, ENCHANT_ITEM = -106,
WINDOW_CLICK = -105, CLOSE_WINDOW = -104, CUSTOM_PAYLOAD = -103, B_EDIT = -102,
ENTITY_NBT_QUERY = -101, USE_ENTITY = -100, JIGSAW_GENERATE = -99, KEEP_ALIVE = -98,
DIFFICULTY_LOCK = -97, POSITION = -96, POSITION_LOOK = -95, LOOK = -94,
FLYING = -93, VEHICLE_MOVE = -92, BOAT_MOVE = -91, PICK_ITEM = -90,
AUTO_RECIPE = -89, ABILITIES = -88, BLOCK_DIG = -87, ENTITY_ACTION = -86,
STEER_VEHICLE = -85, RECIPE_DISPLAYED = -84, ITEM_NAME = -83, RESOURCE_PACK_STATUS = -82,
ADVANCEMENTS = -81, TR_SEL = -80, BEACON = -79, HELD_ITEM_SLOT = -78,
SET_COMMAND_BLOCK = -77, SET_COMMAND_MINECART = -76, SET_CREATIVE_SLOT = -75, SET_JIGSAW = -74,
STRUCT = -73, UPDATE_SIGN = -72, ARM_ANIMATION = -71, SPECTATE = -70,
USE_ITEM = -69, BLOCK_PLACE = -68, PONG = 28;
private static void load() {
insertPacketID(PacketTypeClasses.Play.Client.TELEPORT_ACCEPT, TELEPORT_ACCEPT);
insertPacketID(PacketTypeClasses.Play.Client.TILE_NBT_QUERY, TILE_NBT_QUERY);
insertPacketID(PacketTypeClasses.Play.Client.DIFFICULTY_CHANGE, DIFFICULTY_CHANGE);
insertPacketID(PacketTypeClasses.Play.Client.CHAT, CHAT);
insertPacketID(PacketTypeClasses.Play.Client.CLIENT_COMMAND, CLIENT_COMMAND);
insertPacketID(PacketTypeClasses.Play.Client.SETTINGS, SETTINGS);
insertPacketID(PacketTypeClasses.Play.Client.TAB_COMPLETE, TAB_COMPLETE);
insertPacketID(PacketTypeClasses.Play.Client.TRANSACTION, TRANSACTION);
insertPacketID(PacketTypeClasses.Play.Client.ENCHANT_ITEM, ENCHANT_ITEM);
insertPacketID(PacketTypeClasses.Play.Client.WINDOW_CLICK, WINDOW_CLICK);
insertPacketID(PacketTypeClasses.Play.Client.CLOSE_WINDOW, CLOSE_WINDOW);
insertPacketID(PacketTypeClasses.Play.Client.CUSTOM_PAYLOAD, CUSTOM_PAYLOAD);
insertPacketID(PacketTypeClasses.Play.Client.B_EDIT, B_EDIT);
insertPacketID(PacketTypeClasses.Play.Client.ENTITY_NBT_QUERY, ENTITY_NBT_QUERY);
insertPacketID(PacketTypeClasses.Play.Client.USE_ENTITY, USE_ENTITY);
insertPacketID(PacketTypeClasses.Play.Client.JIGSAW_GENERATE, JIGSAW_GENERATE);
insertPacketID(PacketTypeClasses.Play.Client.KEEP_ALIVE, KEEP_ALIVE);
insertPacketID(PacketTypeClasses.Play.Client.DIFFICULTY_LOCK, DIFFICULTY_LOCK);
insertPacketID(PacketTypeClasses.Play.Client.POSITION, POSITION);
insertPacketID(PacketTypeClasses.Play.Client.POSITION_LOOK, POSITION_LOOK);
insertPacketID(PacketTypeClasses.Play.Client.LOOK, LOOK);
insertPacketID(PacketTypeClasses.Play.Client.GROUND, FLYING);
insertPacketID(PacketTypeClasses.Play.Client.VEHICLE_MOVE, VEHICLE_MOVE);
insertPacketID(PacketTypeClasses.Play.Client.BOAT_MOVE, BOAT_MOVE);
insertPacketID(PacketTypeClasses.Play.Client.PICK_ITEM, PICK_ITEM);
insertPacketID(PacketTypeClasses.Play.Client.AUTO_RECIPE, AUTO_RECIPE);
insertPacketID(PacketTypeClasses.Play.Client.ABILITIES, ABILITIES);
insertPacketID(PacketTypeClasses.Play.Client.BLOCK_DIG, BLOCK_DIG);
insertPacketID(PacketTypeClasses.Play.Client.ENTITY_ACTION, ENTITY_ACTION);
insertPacketID(PacketTypeClasses.Play.Client.STEER_VEHICLE, STEER_VEHICLE);
insertPacketID(PacketTypeClasses.Play.Client.RECIPE_DISPLAYED, RECIPE_DISPLAYED);
insertPacketID(PacketTypeClasses.Play.Client.ITEM_NAME, ITEM_NAME);
insertPacketID(PacketTypeClasses.Play.Client.RESOURCE_PACK_STATUS, RESOURCE_PACK_STATUS);
insertPacketID(PacketTypeClasses.Play.Client.ADVANCEMENTS, ADVANCEMENTS);
insertPacketID(PacketTypeClasses.Play.Client.TR_SEL, TR_SEL);
insertPacketID(PacketTypeClasses.Play.Client.BEACON, BEACON);
insertPacketID(PacketTypeClasses.Play.Client.HELD_ITEM_SLOT, HELD_ITEM_SLOT);
insertPacketID(PacketTypeClasses.Play.Client.SET_COMMAND_BLOCK, SET_COMMAND_BLOCK);
insertPacketID(PacketTypeClasses.Play.Client.SET_COMMAND_MINECART, SET_COMMAND_MINECART);
insertPacketID(PacketTypeClasses.Play.Client.SET_CREATIVE_SLOT, SET_CREATIVE_SLOT);
insertPacketID(PacketTypeClasses.Play.Client.SET_JIGSAW, SET_JIGSAW);
insertPacketID(PacketTypeClasses.Play.Client.STRUCT, STRUCT);
insertPacketID(PacketTypeClasses.Play.Client.UPDATE_SIGN, UPDATE_SIGN);
insertPacketID(PacketTypeClasses.Play.Client.ARM_ANIMATION, ARM_ANIMATION);
insertPacketID(PacketTypeClasses.Play.Client.SPECTATE, SPECTATE);
insertPacketID(PacketTypeClasses.Play.Client.USE_ITEM, USE_ITEM);
insertPacketID(PacketTypeClasses.Play.Client.BLOCK_PLACE, BLOCK_PLACE);
insertPacketID(PacketTypeClasses.Play.Client.PONG, PONG);
}
/**
* Server-bound Play Packet Type utility.
* Save a few lines of code by using this.
*
* @author retrooper
* @since 1.8
*/
public static class Util {
/**
* Is the play packet a PacketPlayInFlying, PacketPlayInPosition, PacketPlayInPositionLook
* or a PacketPlayInLook packet?
*
* @param packetID Play Packet ID.
* @return Is the Packet ID an instance of the PacketPlayInFlying packet?
*/
public static boolean isInstanceOfFlying(final byte packetID) {
return packetID == FLYING
|| packetID == POSITION
|| packetID == POSITION_LOOK
|| packetID == LOOK;
}
/**
* Is this the packet where the client places a block?
* On 1.7.10 - 1.8.8 the client sends a PacketPlayInBlockPlace packet when actually placing the block.
* On 1.9 - now the client sends a PacketPlayInUseItem packet when placing the block and the
* PacketPlayInBlockPlace has a different use.
* This method is a nice utility supporting all these versions letting you know
* if the client played a block.
* The {@link io.github.retrooper.packetevents.packetwrappers.play.in.blockplace.WrappedPacketInBlockPlace} wrapper
* only works on an actual block place.
* Use this method before using the wrapper to support all minecraft versions.
*
* @param packetID Play Packet ID.
* @return Has the client placed a block?
*/
public static boolean isBlockPlace(final byte packetID) {
return isNine ? packetID == PacketType.Play.Client.USE_ITEM : packetID == PacketType.Play.Client.BLOCK_PLACE;
}
}
}
/**
* Client-bound (server-sided) Play Packet IDs.
*
* @author retrooper
* @see <a href="https://wiki.vg/Protocol#Clientbound_4">https://wiki.vg/Protocol#Clientbound_4</a>
* @since 1.8
*/
public static class Server {
public static final byte SPAWN_ENTITY = -67, SPAWN_ENTITY_EXPERIENCE_ORB = -66, SPAWN_ENTITY_WEATHER = -65, SPAWN_ENTITY_LIVING = -64,
SPAWN_ENTITY_PAINTING = -63, SPAWN_ENTITY_SPAWN = -62, ANIMATION = -61, STATISTIC = -60,
BLOCK_BREAK = -59, BLOCK_BREAK_ANIMATION = -58, TILE_ENTITY_DATA = -57, BLOCK_ACTION = -56,
BLOCK_CHANGE = -55, BOSS = -54, SERVER_DIFFICULTY = -53, CHAT = -52, MULTI_BLOCK_CHANGE = -51,
TAB_COMPLETE = -50, COMMANDS = -49, TRANSACTION = -48, CLOSE_WINDOW = -47,
WINDOW_ITEMS = -46, WINDOW_DATA = -45, SET_SLOT = -44, SET_COOLDOWN = -43,
CUSTOM_PAYLOAD = -42, CUSTOM_SOUND_EFFECT = -41, KICK_DISCONNECT = -40, ENTITY_STATUS = -39,
EXPLOSION = -38, UNLOAD_CHUNK = -37, GAME_STATE_CHANGE = -36, OPEN_WINDOW_HORSE = -35,
KEEP_ALIVE = -34, MAP_CHUNK = -33, WORLD_EVENT = -32, WORLD_PARTICLES = -31,
LIGHT_UPDATE = -30, LOGIN = -29, MAP = -28, OPEN_WINDOW_MERCHANT = -27,
REL_ENTITY_MOVE = -26, REL_ENTITY_MOVE_LOOK = -25, ENTITY_LOOK = -24, ENTITY = -23,
VEHICLE_MOVE = -22, OPEN_BOOK = -21, OPEN_WINDOW = -20, OPEN_SIGN_EDITOR = -19,
AUTO_RECIPE = -18, ABILITIES = -17, COMBAT_EVENT = -16, PLAYER_INFO = -15,
LOOK_AT = -14, POSITION = -13, RECIPES = -12, ENTITY_DESTROY = -11,
REMOVE_ENTITY_EFFECT = -10, RESOURCE_PACK_SEND = -9, RESPAWN = -8, ENTITY_HEAD_ROTATION = -7,
SELECT_ADVANCEMENT_TAB = -6, WORLD_BORDER = -5, CAMERA = -4, HELD_ITEM_SLOT = -3,
VIEW_CENTRE = -2, VIEW_DISTANCE = -1, SCOREBOARD_DISPLAY_OBJECTIVE = 0, ENTITY_METADATA = 1,
ATTACH_ENTITY = 2, ENTITY_VELOCITY = 3, ENTITY_EQUIPMENT = 4, EXPERIENCE = 5,
UPDATE_HEALTH = 6, SCOREBOARD_OBJECTIVE = 7, MOUNT = 8, SCOREBOARD_TEAM = 9,
SCOREBOARD_SCORE = 10, SPAWN_POSITION = 11, UPDATE_TIME = 12, TITLE = 13,
ENTITY_SOUND = 14, NAMED_SOUND_EFFECT = 15, STOP_SOUND = 16, PLAYER_LIST_HEADER_FOOTER = 17,
NBT_QUERY = 18, COLLECT = 19, ENTITY_TELEPORT = 20, ADVANCEMENTS = 21, UPDATE_ATTRIBUTES = 22,
ENTITY_EFFECT = 23, RECIPE_UPDATE = 24, TAGS = 25, MAP_CHUNK_BULK = 26, NAMED_ENTITY_SPAWN = 27, PING = 29,
ADD_VIBRATION_SIGNAL = 30, CLEAR_TITLES = 31, INITIALIZE_BORDER = 32, PLAYER_COMBAT_END = 33,
PLAYER_COMBAT_ENTER = 34, PLAYER_COMBAT_KILL = 35, SET_ACTIONBAR_TEXT = 36, SET_BORDER_CENTER = 37,
SET_BORDER_LERP_SIZE = 38, SET_BORDER_SIZE = 39, SET_BORDER_WARNING_DELAY = 40, SET_BORDER_WARNING_DISTANCE = 41,
SET_SUBTITLE_TEXT = 42, SET_TITLES_ANIMATION = 43, SET_TITLE_TEXT = 44;
private static void load() {
insertPacketID(PacketTypeClasses.Play.Server.SPAWN_ENTITY, SPAWN_ENTITY);
insertPacketID(PacketTypeClasses.Play.Server.SPAWN_ENTITY_EXPERIENCE_ORB, SPAWN_ENTITY_EXPERIENCE_ORB);
insertPacketID(PacketTypeClasses.Play.Server.SPAWN_ENTITY_WEATHER, SPAWN_ENTITY_WEATHER);
insertPacketID(PacketTypeClasses.Play.Server.SPAWN_ENTITY_LIVING, SPAWN_ENTITY_LIVING);
insertPacketID(PacketTypeClasses.Play.Server.SPAWN_ENTITY_PAINTING, SPAWN_ENTITY_PAINTING);
insertPacketID(PacketTypeClasses.Play.Server.SPAWN_ENTITY_SPAWN, SPAWN_ENTITY_SPAWN);
insertPacketID(PacketTypeClasses.Play.Server.ANIMATION, ANIMATION);
insertPacketID(PacketTypeClasses.Play.Server.STATISTIC, STATISTIC);
insertPacketID(PacketTypeClasses.Play.Server.BLOCK_BREAK, BLOCK_BREAK);
insertPacketID(PacketTypeClasses.Play.Server.BLOCK_BREAK_ANIMATION, BLOCK_BREAK_ANIMATION);
insertPacketID(PacketTypeClasses.Play.Server.TILE_ENTITY_DATA, TILE_ENTITY_DATA);
insertPacketID(PacketTypeClasses.Play.Server.BLOCK_ACTION, BLOCK_ACTION);
insertPacketID(PacketTypeClasses.Play.Server.BLOCK_CHANGE, BLOCK_CHANGE);
insertPacketID(PacketTypeClasses.Play.Server.BOSS, BOSS);
insertPacketID(PacketTypeClasses.Play.Server.SERVER_DIFFICULTY, SERVER_DIFFICULTY);
insertPacketID(PacketTypeClasses.Play.Server.CHAT, CHAT);
insertPacketID(PacketTypeClasses.Play.Server.MULTI_BLOCK_CHANGE, MULTI_BLOCK_CHANGE);
insertPacketID(PacketTypeClasses.Play.Server.TAB_COMPLETE, TAB_COMPLETE);
insertPacketID(PacketTypeClasses.Play.Server.COMMANDS, COMMANDS);
insertPacketID(PacketTypeClasses.Play.Server.TRANSACTION, TRANSACTION);
insertPacketID(PacketTypeClasses.Play.Server.CLOSE_WINDOW, CLOSE_WINDOW);
insertPacketID(PacketTypeClasses.Play.Server.WINDOW_ITEMS, WINDOW_ITEMS);
insertPacketID(PacketTypeClasses.Play.Server.WINDOW_DATA, WINDOW_DATA);
insertPacketID(PacketTypeClasses.Play.Server.SET_SLOT, SET_SLOT);
insertPacketID(PacketTypeClasses.Play.Server.SET_COOLDOWN, SET_COOLDOWN);
insertPacketID(PacketTypeClasses.Play.Server.CUSTOM_PAYLOAD, CUSTOM_PAYLOAD);
insertPacketID(PacketTypeClasses.Play.Server.CUSTOM_SOUND_EFFECT, CUSTOM_SOUND_EFFECT);
insertPacketID(PacketTypeClasses.Play.Server.KICK_DISCONNECT, KICK_DISCONNECT);
insertPacketID(PacketTypeClasses.Play.Server.ENTITY_STATUS, ENTITY_STATUS);
insertPacketID(PacketTypeClasses.Play.Server.EXPLOSION, EXPLOSION);
insertPacketID(PacketTypeClasses.Play.Server.UNLOAD_CHUNK, UNLOAD_CHUNK);
insertPacketID(PacketTypeClasses.Play.Server.GAME_STATE_CHANGE, GAME_STATE_CHANGE);
insertPacketID(PacketTypeClasses.Play.Server.OPEN_WINDOW_HORSE, OPEN_WINDOW_HORSE);
insertPacketID(PacketTypeClasses.Play.Server.KEEP_ALIVE, KEEP_ALIVE);
insertPacketID(PacketTypeClasses.Play.Server.MAP_CHUNK, MAP_CHUNK);
insertPacketID(PacketTypeClasses.Play.Server.WORLD_EVENT, WORLD_EVENT);
insertPacketID(PacketTypeClasses.Play.Server.WORLD_PARTICLES, WORLD_PARTICLES);
insertPacketID(PacketTypeClasses.Play.Server.LIGHT_UPDATE, LIGHT_UPDATE);
insertPacketID(PacketTypeClasses.Play.Server.LOGIN, LOGIN);
insertPacketID(PacketTypeClasses.Play.Server.MAP, MAP);
insertPacketID(PacketTypeClasses.Play.Server.OPEN_WINDOW_MERCHANT, OPEN_WINDOW_MERCHANT);
insertPacketID(PacketTypeClasses.Play.Server.REL_ENTITY_MOVE, REL_ENTITY_MOVE);
insertPacketID(PacketTypeClasses.Play.Server.REL_ENTITY_MOVE_LOOK, REL_ENTITY_MOVE_LOOK);
insertPacketID(PacketTypeClasses.Play.Server.ENTITY_LOOK, ENTITY_LOOK);
insertPacketID(PacketTypeClasses.Play.Server.ENTITY, ENTITY);
insertPacketID(PacketTypeClasses.Play.Server.VEHICLE_MOVE, VEHICLE_MOVE);
insertPacketID(PacketTypeClasses.Play.Server.OPEN_BOOK, OPEN_BOOK);
insertPacketID(PacketTypeClasses.Play.Server.OPEN_WINDOW, OPEN_WINDOW);
insertPacketID(PacketTypeClasses.Play.Server.OPEN_SIGN_EDITOR, OPEN_SIGN_EDITOR);
insertPacketID(PacketTypeClasses.Play.Server.AUTO_RECIPE, AUTO_RECIPE);
insertPacketID(PacketTypeClasses.Play.Server.ABILITIES, ABILITIES);
insertPacketID(PacketTypeClasses.Play.Server.COMBAT_EVENT, COMBAT_EVENT);
insertPacketID(PacketTypeClasses.Play.Server.PLAYER_INFO, PLAYER_INFO);
insertPacketID(PacketTypeClasses.Play.Server.LOOK_AT, LOOK_AT);
insertPacketID(PacketTypeClasses.Play.Server.POSITION, POSITION);
insertPacketID(PacketTypeClasses.Play.Server.RECIPES, RECIPES);
insertPacketID(PacketTypeClasses.Play.Server.ENTITY_DESTROY, ENTITY_DESTROY);
insertPacketID(PacketTypeClasses.Play.Server.REMOVE_ENTITY_EFFECT, REMOVE_ENTITY_EFFECT);
insertPacketID(PacketTypeClasses.Play.Server.RESOURCE_PACK_SEND, RESOURCE_PACK_SEND);
insertPacketID(PacketTypeClasses.Play.Server.RESPAWN, RESPAWN);
insertPacketID(PacketTypeClasses.Play.Server.ENTITY_HEAD_ROTATION, ENTITY_HEAD_ROTATION);
insertPacketID(PacketTypeClasses.Play.Server.SELECT_ADVANCEMENT_TAB, SELECT_ADVANCEMENT_TAB);
insertPacketID(PacketTypeClasses.Play.Server.WORLD_BORDER, WORLD_BORDER);
insertPacketID(PacketTypeClasses.Play.Server.CAMERA, CAMERA);
insertPacketID(PacketTypeClasses.Play.Server.HELD_ITEM_SLOT, HELD_ITEM_SLOT);
insertPacketID(PacketTypeClasses.Play.Server.VIEW_CENTRE, VIEW_CENTRE);
insertPacketID(PacketTypeClasses.Play.Server.VIEW_DISTANCE, VIEW_DISTANCE);
insertPacketID(PacketTypeClasses.Play.Server.SCOREBOARD_DISPLAY_OBJECTIVE, SCOREBOARD_DISPLAY_OBJECTIVE);
insertPacketID(PacketTypeClasses.Play.Server.ENTITY_METADATA, ENTITY_METADATA);
insertPacketID(PacketTypeClasses.Play.Server.ATTACH_ENTITY, ATTACH_ENTITY);
insertPacketID(PacketTypeClasses.Play.Server.ENTITY_VELOCITY, ENTITY_VELOCITY);
insertPacketID(PacketTypeClasses.Play.Server.ENTITY_EQUIPMENT, ENTITY_EQUIPMENT);
insertPacketID(PacketTypeClasses.Play.Server.EXPERIENCE, EXPERIENCE);
insertPacketID(PacketTypeClasses.Play.Server.UPDATE_HEALTH, UPDATE_HEALTH);
insertPacketID(PacketTypeClasses.Play.Server.SCOREBOARD_OBJECTIVE, SCOREBOARD_OBJECTIVE);
insertPacketID(PacketTypeClasses.Play.Server.MOUNT, MOUNT);
insertPacketID(PacketTypeClasses.Play.Server.SCOREBOARD_TEAM, SCOREBOARD_TEAM);
insertPacketID(PacketTypeClasses.Play.Server.SCOREBOARD_SCORE, SCOREBOARD_SCORE);
insertPacketID(PacketTypeClasses.Play.Server.SPAWN_POSITION, SPAWN_POSITION);
insertPacketID(PacketTypeClasses.Play.Server.UPDATE_TIME, UPDATE_TIME);
insertPacketID(PacketTypeClasses.Play.Server.TITLE, TITLE);
insertPacketID(PacketTypeClasses.Play.Server.ENTITY_SOUND, ENTITY_SOUND);
insertPacketID(PacketTypeClasses.Play.Server.NAMED_SOUND_EFFECT, NAMED_SOUND_EFFECT);
insertPacketID(PacketTypeClasses.Play.Server.STOP_SOUND, STOP_SOUND);
insertPacketID(PacketTypeClasses.Play.Server.PLAYER_LIST_HEADER_FOOTER, PLAYER_LIST_HEADER_FOOTER);
insertPacketID(PacketTypeClasses.Play.Server.NBT_QUERY, NBT_QUERY);
insertPacketID(PacketTypeClasses.Play.Server.COLLECT, COLLECT);
insertPacketID(PacketTypeClasses.Play.Server.ENTITY_TELEPORT, ENTITY_TELEPORT);
insertPacketID(PacketTypeClasses.Play.Server.ADVANCEMENTS, ADVANCEMENTS);
insertPacketID(PacketTypeClasses.Play.Server.UPDATE_ATTRIBUTES, UPDATE_ATTRIBUTES);
insertPacketID(PacketTypeClasses.Play.Server.ENTITY_EFFECT, ENTITY_EFFECT);
insertPacketID(PacketTypeClasses.Play.Server.RECIPE_UPDATE, RECIPE_UPDATE);
insertPacketID(PacketTypeClasses.Play.Server.TAGS, TAGS);
insertPacketID(PacketTypeClasses.Play.Server.MAP_CHUNK_BULK, MAP_CHUNK_BULK);
insertPacketID(PacketTypeClasses.Play.Server.NAMED_ENTITY_SPAWN, NAMED_ENTITY_SPAWN);
insertPacketID(PacketTypeClasses.Play.Server.PING, PING);
insertPacketID(PacketTypeClasses.Play.Server.ADD_VIBRATION_SIGNAL, ADD_VIBRATION_SIGNAL);
insertPacketID(PacketTypeClasses.Play.Server.CLEAR_TITLES, CLEAR_TITLES );
insertPacketID(PacketTypeClasses.Play.Server.INITIALIZE_BORDER, INITIALIZE_BORDER);
insertPacketID(PacketTypeClasses.Play.Server.PLAYER_COMBAT_END, PLAYER_COMBAT_END);
insertPacketID(PacketTypeClasses.Play.Server.PLAYER_COMBAT_ENTER, PLAYER_COMBAT_ENTER);
insertPacketID(PacketTypeClasses.Play.Server.PLAYER_COMBAT_KILL, PLAYER_COMBAT_KILL);
insertPacketID(PacketTypeClasses.Play.Server.SET_ACTIONBAR_TEXT, SET_ACTIONBAR_TEXT);
insertPacketID(PacketTypeClasses.Play.Server.SET_BORDER_CENTER, SET_BORDER_CENTER);
insertPacketID(PacketTypeClasses.Play.Server.SET_BORDER_LERP_SIZE, SET_BORDER_LERP_SIZE);
insertPacketID(PacketTypeClasses.Play.Server.SET_BORDER_SIZE, SET_BORDER_SIZE);
insertPacketID(PacketTypeClasses.Play.Server.SET_BORDER_WARNING_DELAY, SET_BORDER_WARNING_DELAY);
insertPacketID(PacketTypeClasses.Play.Server.SET_BORDER_WARNING_DISTANCE, SET_BORDER_WARNING_DISTANCE);
insertPacketID(PacketTypeClasses.Play.Server.SET_SUBTITLE_TEXT, SET_SUBTITLE_TEXT);
insertPacketID(PacketTypeClasses.Play.Server.SET_TITLES_ANIMATION, SET_TITLES_ANIMATION);
insertPacketID(PacketTypeClasses.Play.Server.SET_TITLE_TEXT, SET_TITLE_TEXT);
}
/**
* Client-bound Play Packet Type utility.
* Save a few lines of code by using this.
*
* @author retrooper
* @since 1.8
*/
public static class Util {
/**
* Is the play packet a PacketPlayOutEntity, PacketPlayOutRelEntityMove, PacketPlayOutRelEntityMoveLook
* or a PacketPlayOutEntityLook packet?
*
* @param packetID Play Packet ID.
* @return Is the Packet ID an instance of the PacketPlayOutEntity packet?
*/
public static boolean isInstanceOfEntity(final byte packetID) {
return packetID == ENTITY || packetID == REL_ENTITY_MOVE ||
packetID == REL_ENTITY_MOVE_LOOK || packetID == ENTITY_LOOK;
}
}
}
}
}
@@ -1,410 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.packettype;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.utils.reflection.Reflection;
import io.github.retrooper.packetevents.utils.reflection.SubclassUtil;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
public class PacketTypeClasses {
public static void load() {
//STATUS
PacketTypeClasses.Status.Client.load();
PacketTypeClasses.Status.Server.load();
//HANDSHAKING
PacketTypeClasses.Handshaking.Client.load();
//LOGIN
PacketTypeClasses.Login.Client.load();
PacketTypeClasses.Login.Server.load();
//PLAY
PacketTypeClasses.Play.Client.load();
PacketTypeClasses.Play.Server.load();
}
public static class Status {
public static class Client {
private static String PREFIX;
public static Class<?> START, PING;
public static void load() {
if (PacketEvents.get().getServerUtils().getVersion().isNewerThanOrEquals(ServerVersion.v_1_17)) {
PREFIX = "net.minecraft.network.protocol.status.";
}
else {
PREFIX = ServerVersion.getNMSDirectory() + ".";
}
Client.START = Reflection.getClassByNameWithoutException(PREFIX + "PacketStatusInStart");
Client.PING = Reflection.getClassByNameWithoutException(PREFIX + "PacketStatusInPing");
}
}
public static class Server {
private static String PREFIX;
public static Class<?> PONG, SERVER_INFO;
public static void load() {
if (PacketEvents.get().getServerUtils().getVersion().isNewerThanOrEquals(ServerVersion.v_1_17)) {
PREFIX = "net.minecraft.network.protocol.status.";
}
else {
PREFIX = ServerVersion.getNMSDirectory() + ".";
}
Server.PONG = Reflection.getClassByNameWithoutException(PREFIX + "PacketStatusOutPong");
Server.SERVER_INFO = Reflection.getClassByNameWithoutException(PREFIX + "PacketStatusOutServerInfo");
}
}
}
public static class Handshaking {
public static class Client {
private static String PREFIX;
public static Class<?> SET_PROTOCOL;
public static void load() {
if (PacketEvents.get().getServerUtils().getVersion().isNewerThanOrEquals(ServerVersion.v_1_17)) {
PREFIX = "net.minecraft.network.protocol.handshake.";
}
else {
PREFIX = ServerVersion.getNMSDirectory() + ".";
}
Handshaking.Client.SET_PROTOCOL = Reflection.getClassByNameWithoutException(PREFIX + "PacketHandshakingInSetProtocol");
}
}
}
public static class Login {
public static class Client {
private static String PREFIX;
public static Class<?> CUSTOM_PAYLOAD, START, ENCRYPTION_BEGIN;
public static void load() {
if (PacketEvents.get().getServerUtils().getVersion().isNewerThanOrEquals(ServerVersion.v_1_17)) {
PREFIX = "net.minecraft.network.protocol.login.";
}
else {
PREFIX = ServerVersion.getNMSDirectory() + ".";
}
//In and Out custom payload login packets have been here since 1.13
if (PacketEvents.get().getServerUtils().getVersion().isNewerThanOrEquals(ServerVersion.v_1_13)) {
Client.CUSTOM_PAYLOAD = Reflection.getClassByNameWithoutException(PREFIX + "PacketLoginInCustomPayload");
}
Client.START = Reflection.getClassByNameWithoutException(PREFIX + "PacketLoginInStart");
Client.ENCRYPTION_BEGIN = Reflection.getClassByNameWithoutException(PREFIX + "PacketLoginInEncryptionBegin");
}
}
public static class Server {
private static String PREFIX;
public static Class<?> CUSTOM_PAYLOAD, DISCONNECT, ENCRYPTION_BEGIN, SUCCESS, SET_COMPRESSION;
public static void load() {
if (PacketEvents.get().getServerUtils().getVersion().isNewerThanOrEquals(ServerVersion.v_1_17)) {
PREFIX = "net.minecraft.network.protocol.login.";
}
else {
PREFIX = ServerVersion.getNMSDirectory() + ".";
}
//In and Out custom payload login packets have been here since 1.13
if (PacketEvents.get().getServerUtils().getVersion().isNewerThanOrEquals(ServerVersion.v_1_13)) {
Server.CUSTOM_PAYLOAD = Reflection.getClassByNameWithoutException(PREFIX + "PacketLoginOutCustomPayload");
}
Server.DISCONNECT = Reflection.getClassByNameWithoutException(PREFIX + "PacketLoginOutDisconnect");
Server.ENCRYPTION_BEGIN = Reflection.getClassByNameWithoutException(PREFIX + "PacketLoginOutEncryptionBegin");
Server.SUCCESS = Reflection.getClassByNameWithoutException(PREFIX + "PacketLoginOutSuccess");
if (PacketEvents.get().getServerUtils().getVersion().isNewerThan(ServerVersion.v_1_7_10)) {
Server.SET_COMPRESSION = Reflection.getClassByNameWithoutException(PREFIX + "PacketLoginOutSetCompression");
}
}
}
}
public static class Play {
public static class Client {
private static String COMMON_PREFIX;
private static String PREFIX;
public static Class<?> FLYING, POSITION, POSITION_LOOK, LOOK, GROUND, CLIENT_COMMAND,
TRANSACTION, BLOCK_DIG, ENTITY_ACTION, USE_ENTITY,
WINDOW_CLICK, STEER_VEHICLE, CUSTOM_PAYLOAD, ARM_ANIMATION,
BLOCK_PLACE, USE_ITEM, ABILITIES, HELD_ITEM_SLOT,
CLOSE_WINDOW, TAB_COMPLETE, CHAT, SET_CREATIVE_SLOT,
KEEP_ALIVE, SETTINGS, ENCHANT_ITEM, TELEPORT_ACCEPT,
TILE_NBT_QUERY, DIFFICULTY_CHANGE, B_EDIT, ENTITY_NBT_QUERY,
JIGSAW_GENERATE, DIFFICULTY_LOCK, VEHICLE_MOVE, BOAT_MOVE, PICK_ITEM,
AUTO_RECIPE, RECIPE_DISPLAYED, ITEM_NAME, RESOURCE_PACK_STATUS,
ADVANCEMENTS, TR_SEL, BEACON, SET_COMMAND_BLOCK,
SET_COMMAND_MINECART, SET_JIGSAW, STRUCT, UPDATE_SIGN, SPECTATE, PONG;
/**
* Initiate all server-bound play packet classes.
*/
public static void load() {
if (PacketEvents.get().getServerUtils().getVersion().isNewerThanOrEquals(ServerVersion.v_1_17)) {
PREFIX = "net.minecraft.network.protocol.game.";
}
else {
PREFIX = ServerVersion.getNMSDirectory() + ".";
}
COMMON_PREFIX = PREFIX + "PacketPlayIn";
FLYING = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Flying");
try {
POSITION = Class.forName(COMMON_PREFIX + "Position");
POSITION_LOOK = Class.forName(COMMON_PREFIX + "PositionLook");
LOOK = Class.forName(COMMON_PREFIX + "Look");
} catch (ClassNotFoundException ex) {
POSITION = SubclassUtil.getSubClass(FLYING,"PacketPlayInPosition");
POSITION_LOOK = SubclassUtil.getSubClass(FLYING, "PacketPlayInPositionLook");
LOOK = SubclassUtil.getSubClass(FLYING, "PacketPlayInLook");
}
if (PacketEvents.get().getServerUtils().getVersion().isNewerThanOrEquals(ServerVersion.v_1_17)) {
GROUND = SubclassUtil.getSubClass(FLYING, "d");
}
else {
GROUND = FLYING;
}
//This packet does not exist in the 1.17+ protocol
TRANSACTION = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Transaction");
//This packet was added in 1.17 protocol
PONG = Reflection.getClassByNameWithoutException(PREFIX + "ServerboundPongPacket");
try {
SETTINGS = Class.forName(COMMON_PREFIX + "Settings");
ENCHANT_ITEM = Class.forName(COMMON_PREFIX + "EnchantItem");
CLIENT_COMMAND = Class.forName(COMMON_PREFIX + "ClientCommand");
BLOCK_DIG = Class.forName(COMMON_PREFIX + "BlockDig");
ENTITY_ACTION = Class.forName(COMMON_PREFIX + "EntityAction");
USE_ENTITY = Class.forName(COMMON_PREFIX + "UseEntity");
WINDOW_CLICK = Class.forName(COMMON_PREFIX + "WindowClick");
STEER_VEHICLE = Class.forName(COMMON_PREFIX + "SteerVehicle");
CUSTOM_PAYLOAD = Class.forName(COMMON_PREFIX + "CustomPayload");
ARM_ANIMATION = Class.forName(COMMON_PREFIX + "ArmAnimation");
ABILITIES = Class.forName(COMMON_PREFIX + "Abilities");
HELD_ITEM_SLOT = Class.forName(COMMON_PREFIX + "HeldItemSlot");
CLOSE_WINDOW = Class.forName(COMMON_PREFIX + "CloseWindow");
TAB_COMPLETE = Class.forName(COMMON_PREFIX + "TabComplete");
CHAT = Class.forName(COMMON_PREFIX + "Chat");
SET_CREATIVE_SLOT = Class.forName(COMMON_PREFIX + "SetCreativeSlot");
KEEP_ALIVE = Class.forName(COMMON_PREFIX + "KeepAlive");
UPDATE_SIGN = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "UpdateSign");
TELEPORT_ACCEPT = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "TeleportAccept");
TILE_NBT_QUERY = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "TileNBTQuery");
DIFFICULTY_CHANGE = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "DifficultyChange");
B_EDIT = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "BEdit");
ENTITY_NBT_QUERY = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "EntityNBTQuery");
JIGSAW_GENERATE = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "JigsawGenerate");
DIFFICULTY_LOCK = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "DifficultyLock");
VEHICLE_MOVE = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "VehicleMove");
BOAT_MOVE = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "BoatMove");
PICK_ITEM = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "PickItem");
AUTO_RECIPE = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "AutoRecipe");
RECIPE_DISPLAYED = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "RecipeDisplayed");
ITEM_NAME = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "ItemName");
//1.8+
RESOURCE_PACK_STATUS = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "ResourcePackStatus");
ADVANCEMENTS = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Advancements");
TR_SEL = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "TrSel");
BEACON = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Beacon");
SET_COMMAND_BLOCK = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "SetCommandBlock");
SET_COMMAND_MINECART = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "SetCommandMinecart");
SET_JIGSAW = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "SetJigsaw");
STRUCT = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Struct");
SPECTATE = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Spectate");
} catch (Exception e) {
e.printStackTrace();
}
try {
BLOCK_PLACE = Class.forName(COMMON_PREFIX + "BlockPlace");
USE_ITEM = Class.forName(COMMON_PREFIX + "UseItem");
} catch (Exception ignored) {
}
}
}
public static class Server {
private static String COMMON_PREFIX, PREFIX;
public static Class<?> SPAWN_ENTITY, SPAWN_ENTITY_EXPERIENCE_ORB, SPAWN_ENTITY_WEATHER, SPAWN_ENTITY_LIVING,
SPAWN_ENTITY_PAINTING, SPAWN_ENTITY_SPAWN, ANIMATION, STATISTIC,
BLOCK_BREAK, BLOCK_BREAK_ANIMATION, TILE_ENTITY_DATA, BLOCK_ACTION,
BLOCK_CHANGE, BOSS, SERVER_DIFFICULTY, CHAT, MULTI_BLOCK_CHANGE,
TAB_COMPLETE, COMMANDS, TRANSACTION, CLOSE_WINDOW,
WINDOW_ITEMS, WINDOW_DATA, SET_SLOT, SET_COOLDOWN,
CUSTOM_PAYLOAD, CUSTOM_SOUND_EFFECT, KICK_DISCONNECT, ENTITY_STATUS,
EXPLOSION, UNLOAD_CHUNK, GAME_STATE_CHANGE, OPEN_WINDOW_HORSE,
KEEP_ALIVE, MAP_CHUNK, WORLD_EVENT, WORLD_PARTICLES,
LIGHT_UPDATE, LOGIN, MAP, OPEN_WINDOW_MERCHANT,
REL_ENTITY_MOVE, REL_ENTITY_MOVE_LOOK, ENTITY_LOOK, ENTITY,
VEHICLE_MOVE, OPEN_BOOK, OPEN_WINDOW, OPEN_SIGN_EDITOR,
AUTO_RECIPE, ABILITIES, COMBAT_EVENT, PLAYER_INFO,
LOOK_AT, POSITION, RECIPES, ENTITY_DESTROY,
REMOVE_ENTITY_EFFECT, RESOURCE_PACK_SEND, RESPAWN, ENTITY_HEAD_ROTATION,
SELECT_ADVANCEMENT_TAB, WORLD_BORDER, CAMERA, HELD_ITEM_SLOT,
VIEW_CENTRE, VIEW_DISTANCE, SCOREBOARD_DISPLAY_OBJECTIVE, ENTITY_METADATA,
ATTACH_ENTITY, ENTITY_VELOCITY, ENTITY_EQUIPMENT, EXPERIENCE,
UPDATE_HEALTH, SCOREBOARD_OBJECTIVE, MOUNT, SCOREBOARD_TEAM,
SCOREBOARD_SCORE, SPAWN_POSITION, UPDATE_TIME, TITLE,
ENTITY_SOUND, NAMED_SOUND_EFFECT, STOP_SOUND, PLAYER_LIST_HEADER_FOOTER,
NBT_QUERY, COLLECT, ENTITY_TELEPORT, ADVANCEMENTS, UPDATE_ATTRIBUTES,
ENTITY_EFFECT, RECIPE_UPDATE, TAGS, MAP_CHUNK_BULK, NAMED_ENTITY_SPAWN, PING, ADD_VIBRATION_SIGNAL,
CLEAR_TITLES, INITIALIZE_BORDER, PLAYER_COMBAT_END, PLAYER_COMBAT_ENTER, PLAYER_COMBAT_KILL,
SET_ACTIONBAR_TEXT, SET_BORDER_CENTER, SET_BORDER_LERP_SIZE, SET_BORDER_SIZE, SET_BORDER_WARNING_DELAY,
SET_BORDER_WARNING_DISTANCE, SET_SUBTITLE_TEXT, SET_TITLES_ANIMATION, SET_TITLE_TEXT;
/**
* Initiate all client-bound packet classes.
*/
public static void load() {
if (PacketEvents.get().getServerUtils().getVersion().isNewerThanOrEquals(ServerVersion.v_1_17)) {
PREFIX = "net.minecraft.network.protocol.game.";
}
else {
PREFIX = ServerVersion.getNMSDirectory() + ".";
}
COMMON_PREFIX = PREFIX + "PacketPlayOut";
SPAWN_ENTITY = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "SpawnEntity");
SPAWN_ENTITY_EXPERIENCE_ORB = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "SpawnEntityExperienceOrb");
SPAWN_ENTITY_WEATHER = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "SpawnEntityWeather");
SPAWN_ENTITY_LIVING = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "SpawnEntityLiving");
SPAWN_ENTITY_PAINTING = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "SpawnEntityPainting");
SPAWN_ENTITY_SPAWN = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "SpawnEntitySpawn");
ANIMATION = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Animation");
STATISTIC = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Statistic");
BLOCK_BREAK = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "BlockBreak");
BLOCK_BREAK_ANIMATION = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "BlockBreakAnimation");
TILE_ENTITY_DATA = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "TileEntityData");
BLOCK_ACTION = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "BlockAction");
BLOCK_CHANGE = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "BlockChange");
BOSS = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Boss");
SERVER_DIFFICULTY = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "ServerDifficulty");
CHAT = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Chat");
MULTI_BLOCK_CHANGE = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "MultiBlockChange");
TAB_COMPLETE = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "TabComplete");
COMMANDS = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Commands");
TRANSACTION = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Transaction");
CLOSE_WINDOW = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "CloseWindow");
WINDOW_ITEMS = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "WindowItems");
WINDOW_DATA = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "WindowData");
SET_SLOT = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "SetSlot");
SET_COOLDOWN = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "SetCooldown");
CUSTOM_PAYLOAD = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "CustomPayload");
CUSTOM_SOUND_EFFECT = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "CustomSoundEffect");
KICK_DISCONNECT = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "KickDisconnect");
ENTITY_STATUS = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "EntityStatus");
EXPLOSION = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Explosion");
UNLOAD_CHUNK = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "UnloadChunk");
GAME_STATE_CHANGE = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "GameStateChange");
OPEN_WINDOW_HORSE = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "OpenWindowHorse");
KEEP_ALIVE = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "KeepAlive");
MAP_CHUNK = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "MapChunk");
WORLD_EVENT = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "WorldEvent");
WORLD_PARTICLES = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "WorldParticles");
LIGHT_UPDATE = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "LightUpdate");
LOGIN = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Login");
MAP = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Map");
OPEN_WINDOW_MERCHANT = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "OpenWindowMerchant");
ENTITY = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Entity");
REL_ENTITY_MOVE = SubclassUtil.getSubClass(ENTITY, "PacketPlayOutRelEntityMove");
REL_ENTITY_MOVE_LOOK = SubclassUtil.getSubClass(ENTITY, "PacketPlayOutRelEntityMoveLook");
ENTITY_LOOK = SubclassUtil.getSubClass(ENTITY, "PacketPlayOutEntityLook");
if (REL_ENTITY_MOVE == null) {
//is not a subclass and should be accessed normally
REL_ENTITY_MOVE = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "RelEntityMove");
REL_ENTITY_MOVE_LOOK = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "RelEntityMoveLook");
ENTITY_LOOK = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "RelEntityLook");
}
VEHICLE_MOVE = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "VehicleMove");
OPEN_BOOK = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "OpenBook");
OPEN_WINDOW = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "OpenWindow");
OPEN_SIGN_EDITOR = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "OpenSignEditor");
AUTO_RECIPE = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "AutoRecipe");
ABILITIES = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Abilities");
COMBAT_EVENT = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "CombatEvent");
PLAYER_INFO = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "PlayerInfo");
LOOK_AT = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "LookAt");
POSITION = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Position");
RECIPES = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Recipes");
ENTITY_DESTROY = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "EntityDestroy");
REMOVE_ENTITY_EFFECT = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "RemoveEntityEffect");
RESOURCE_PACK_SEND = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "ResourcePackSend");
RESPAWN = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Respawn");
ENTITY_HEAD_ROTATION = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "EntityHeadRotation");
SELECT_ADVANCEMENT_TAB = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "SelectAdvancementTab");
WORLD_BORDER = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "WorldBorder");
CAMERA = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Camera");
HELD_ITEM_SLOT = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "HeldItemSlot");
VIEW_CENTRE = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "ViewCentre");
VIEW_DISTANCE = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "ViewDistance");
SCOREBOARD_DISPLAY_OBJECTIVE = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "ScoreboardDisplayObjective");
ENTITY_METADATA = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "EntityMetadata");
ATTACH_ENTITY = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "AttachEntity");
ENTITY_VELOCITY = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "EntityVelocity");
ENTITY_EQUIPMENT = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "EntityEquipment");
EXPERIENCE = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Experience");
UPDATE_HEALTH = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "UpdateHealth");
SCOREBOARD_OBJECTIVE = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "ScoreboardObjective");
MOUNT = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Mount");
SCOREBOARD_TEAM = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "ScoreboardTeam");
SCOREBOARD_SCORE = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "ScoreboardScore");
SPAWN_POSITION = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "SpawnPosition");
UPDATE_TIME = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "UpdateTime");
TITLE = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Title");
ENTITY_SOUND = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "EntitySound");
NAMED_SOUND_EFFECT = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "NamedSoundEffect");
STOP_SOUND = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "StopSound");
PLAYER_LIST_HEADER_FOOTER = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "PlayerListHeaderFooter");
NBT_QUERY = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "NBTQuery");
COLLECT = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Collect");
ENTITY_TELEPORT = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "EntityTeleport");
ADVANCEMENTS = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Advancements");
UPDATE_ATTRIBUTES = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "UpdateAttributes");
ENTITY_EFFECT = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "EntityEffect");
RECIPE_UPDATE = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "RecipeUpdate");
TAGS = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "Tags");
MAP_CHUNK_BULK = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "MapChunkBulk");
NAMED_ENTITY_SPAWN = Reflection.getClassByNameWithoutException(COMMON_PREFIX + "NamedEntitySpawn");
//These packets were added in 1.17
PING = Reflection.getClassByNameWithoutException(PREFIX + "ClientboundPingPacket");
ADD_VIBRATION_SIGNAL = Reflection.getClassByNameWithoutException(PREFIX + "ClientboundAddVibrationSignalPacket");
CLEAR_TITLES = Reflection.getClassByNameWithoutException(PREFIX + "ClientboundClearTitlesPacket");
INITIALIZE_BORDER = Reflection.getClassByNameWithoutException(PREFIX + "ClientboundInitializeBorderPacket");
PLAYER_COMBAT_END = Reflection.getClassByNameWithoutException(PREFIX + "ClientboundPlayerCombatEndPacket");
PLAYER_COMBAT_ENTER = Reflection.getClassByNameWithoutException(PREFIX + "ClientboundPlayerCombatEnterPacket");
PLAYER_COMBAT_KILL = Reflection.getClassByNameWithoutException(PREFIX + "ClientboundPlayerCombatKillPacket");
SET_ACTIONBAR_TEXT = Reflection.getClassByNameWithoutException(PREFIX + "ClientboundSetActionBarTextPacket");
SET_BORDER_CENTER = Reflection.getClassByNameWithoutException(PREFIX + "ClientboundSetBorderCenterPacket");
SET_BORDER_LERP_SIZE = Reflection.getClassByNameWithoutException(PREFIX + "ClientboundSetBorderLerpSizePacket");
SET_BORDER_SIZE = Reflection.getClassByNameWithoutException(PREFIX + "ClientboundSetBorderSizePacket");
SET_BORDER_WARNING_DELAY = Reflection.getClassByNameWithoutException(PREFIX + "ClientboundSetBorderWarningDelayPacket");
SET_BORDER_WARNING_DISTANCE = Reflection.getClassByNameWithoutException(PREFIX + "ClientboundSetBorderWarningDistancePacket");
SET_SUBTITLE_TEXT = Reflection.getClassByNameWithoutException(PREFIX + "ClientboundSetSubtitleTextPacket");
SET_TITLES_ANIMATION = Reflection.getClassByNameWithoutException(PREFIX + "ClientboundSetTitlesAnimationPacket");
SET_TITLE_TEXT = Reflection.getClassByNameWithoutException(PREFIX + "ClientboundSetTitleTextPacket");
// 1.18+ only, doesn't follow the naming convention
if (MAP_CHUNK == null) {
MAP_CHUNK = Reflection.getClassByNameWithoutException("net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket");
}
}
}
}
}
@@ -1,37 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.packetwrappers;
import io.github.retrooper.packetevents.utils.reflection.ClassUtil;
public class NMSPacket {
private final Object rawNMSPacket;
public NMSPacket(Object rawNMSPacket) {
this.rawNMSPacket = rawNMSPacket;
}
public Object getRawNMSPacket() {
return rawNMSPacket;
}
public String getName() {
return ClassUtil.getClassSimpleName(rawNMSPacket.getClass());
}
}
@@ -1,593 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.packetwrappers;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.exceptions.WrapperFieldNotFoundException;
import io.github.retrooper.packetevents.exceptions.WrapperUnsupportedUsageException;
import io.github.retrooper.packetevents.packettype.PacketTypeClasses;
import io.github.retrooper.packetevents.packetwrappers.api.WrapperPacketReader;
import io.github.retrooper.packetevents.packetwrappers.api.WrapperPacketWriter;
import io.github.retrooper.packetevents.utils.enums.EnumUtil;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.player.GameMode;
import io.github.retrooper.packetevents.utils.reflection.ClassUtil;
import io.github.retrooper.packetevents.utils.reflection.Reflection;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
import io.github.retrooper.packetevents.utils.vector.Vector3i;
import io.github.retrooper.packetevents.utils.world.Difficulty;
import io.github.retrooper.packetevents.utils.world.Dimension;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
public class WrappedPacket implements WrapperPacketReader, WrapperPacketWriter {
private static final Map<Class<? extends WrappedPacket>, Boolean> LOADED_WRAPPERS = new ConcurrentHashMap<>();
private static final Map<Class<?>, Map<Class<?>, Field[]>> FIELD_CACHE = new ConcurrentHashMap<>();
private static final Field[] EMPTY_FIELD_ARRAY = new Field[0];
private static byte isVersion_1_17 = -1;
public static ServerVersion version;
protected final NMSPacket packet;
private final Class<?> packetClass;
public WrappedPacket() {
packet = null;
packetClass = null;
load0();
}
public WrappedPacket(final NMSPacket packet) {
this(packet, packet.getRawNMSPacket().getClass());
}
public WrappedPacket(final NMSPacket packet, Class<?> packetClass) {
if (packetClass.getSuperclass().equals(PacketTypeClasses.Play.Client.FLYING)) {
packetClass = PacketTypeClasses.Play.Client.FLYING;
} else if (packetClass.getSuperclass().equals(PacketTypeClasses.Play.Server.ENTITY)) {
packetClass = PacketTypeClasses.Play.Server.ENTITY;
}
this.packetClass = packetClass;
this.packet = packet;
load0();
}
private void load0() {
final Class<? extends WrappedPacket> clazz = getClass();
if (!LOADED_WRAPPERS.containsKey(clazz)) {
if (!isSupported()) {
throw new WrapperUnsupportedUsageException(getClass());
}
try {
load();
} catch (Exception ex) {
String wrapperName = ClassUtil.getClassSimpleName(clazz);
PacketEvents.get().getPlugin().getLogger()
.log(Level.SEVERE, "PacketEvents found an exception while loading the " + wrapperName + " packet wrapper. Please report this bug! Tell us about your server version, spigot and code(of you using the wrapper)", ex);
LOADED_WRAPPERS.put(clazz, false);
}
LOADED_WRAPPERS.put(clazz, true);
}
}
protected void load() {
}
protected boolean hasLoaded() {
return LOADED_WRAPPERS.getOrDefault(getClass(), false);
}
protected void throwUnsupportedOperation(Enum<?> enumConst) throws UnsupportedOperationException {
Class<?> enumConstClass = enumConst.getClass();
Field field = null;
try {
field = enumConstClass.getField(enumConst.name());
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
if (field.isAnnotationPresent(SupportedVersions.class)) {
SupportedVersions supportedVersions = field.getAnnotation(SupportedVersions.class);
List<ServerVersion> versionList = parseSupportedVersionsAnnotation(supportedVersions);
String supportedVersionsMsg = Arrays.toString(versionList.toArray(new ServerVersion[0]));
throw new UnsupportedOperationException("PacketEvents failed to use the " + enumConst.name() + " enum constant in the " + enumConstClass.getSimpleName() + " enum. This enum constant is not supported on your server version. (" + PacketEvents.get().getServerUtils().getVersion() + ")\n This enum constant is only supported on these server versions: " + supportedVersionsMsg);
} else {
throw new UnsupportedOperationException("PacketEvents failed to use the " + enumConst.name() + " enum constant in the " + enumConstClass.getSimpleName() + " enum. This enum constant is not supported on your server version. (" + PacketEvents.get().getServerUtils().getVersion() + ")\n Failed to find out what server versions this enum constant is supported on.");
}
}
protected void throwUnsupportedOperation() throws UnsupportedOperationException {
final String currentMethodName = "throwUnsupportedOperation";
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
int stackTraceElementIndex = 2;
for (int i = 0; i < stackTraceElements.length; i++) {
StackTraceElement element = stackTraceElements[i];
if (element.getMethodName().equals(currentMethodName)) {
stackTraceElementIndex = i + 1; //It is the next method
break;
}
}
StackTraceElement stackTraceElement = stackTraceElements[stackTraceElementIndex];
String methodName = stackTraceElement.getMethodName();
List<Method> possibleMethods = Reflection.getMethods(getClass(), methodName, (Class<?>) null);
Method method = null;
for (Method m : possibleMethods) {
if (m.isAnnotationPresent(SupportedVersions.class)) {
method = m;
break;
}
}
if (method == null) {
throw new UnsupportedOperationException("PacketEvents failed to access your requested field. This field is not supported on your server version. Failed to lookup the server versions this field supports...");
} else {
SupportedVersions supportedVersions = method.getAnnotation(SupportedVersions.class);
List<ServerVersion> versionList = parseSupportedVersionsAnnotation(supportedVersions);
String supportedVersionsMsg = Arrays.toString(versionList.toArray(new ServerVersion[0]));
throw new UnsupportedOperationException("PacketEvents failed to access your requested field. This field is not supported on your server version. (" + PacketEvents.get().getServerUtils().getVersion() + ")\n This field is only supported on these server versions: " + supportedVersionsMsg);
}
}
private List<ServerVersion> parseSupportedVersionsAnnotation(SupportedVersions supportedVersions) {
List<ServerVersion> versionList = new ArrayList<>();
for (int i = 0; i < supportedVersions.ranges().length; i += 2) {
ServerVersion first = supportedVersions.ranges()[i];
ServerVersion last = supportedVersions.ranges()[i + 1];
if (first == last) {
versionList.add(first);
continue;
} else if (first == ServerVersion.ERROR) {
first = ServerVersion.getOldest();
} else if (last == ServerVersion.ERROR) {
last = ServerVersion.getLatest();
}
versionList.addAll(Arrays.asList(ServerVersion.values()).subList(first.ordinal(), last.ordinal() + 1));
}
versionList.remove(ServerVersion.ERROR);
return versionList;
}
@Override
public boolean readBoolean(int index) {
return read(index, boolean.class);
}
@Override
public byte readByte(int index) {
return read(index, byte.class);
}
@Override
public short readShort(int index) {
return read(index, short.class);
}
@Override
public int readInt(int index) {
return read(index, int.class);
}
@Override
public long readLong(int index) {
return read(index, long.class);
}
@Override
public float readFloat(int index) {
return read(index, float.class);
}
@Override
public double readDouble(int index) {
return read(index, double.class);
}
@Override
public boolean[] readBooleanArray(int index) {
return read(index, boolean[].class);
}
@Override
public byte[] readByteArray(int index) {
return read(index, byte[].class);
}
@Override
public short[] readShortArray(int index) {
return read(index, short[].class);
}
@Override
public int[] readIntArray(int index) {
return read(index, int[].class);
}
@Override
public long[] readLongArray(int index) {
return read(index, long[].class);
}
@Override
public float[] readFloatArray(int index) {
return read(index, float[].class);
}
@Override
public double[] readDoubleArray(int index) {
return read(index, double[].class);
}
@Override
public String[] readStringArray(int index) {
return read(index, String[].class); // JavaImpact: Can we be sure that returning the original array is okay? retrooper: Yes
}
@Override
public String readString(int index) {
return read(index, String.class);
}
@Override
public Object readAnyObject(int index) {
try {
Field f = packetClass.getDeclaredFields()[index];
if (!f.isAccessible()) {
f.setAccessible(true);
}
try {
return f.get(packet.getRawNMSPacket());
} catch (IllegalAccessException | NullPointerException | ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
}
} catch (ArrayIndexOutOfBoundsException e) {
throw new WrapperFieldNotFoundException("PacketEvents failed to find any field indexed " + index + " in the " + ClassUtil.getClassSimpleName(packetClass) + " class!");
}
return null;
}
@Override
public <T> T readObject(int index, Class<? extends T> type) {
return read(index, type);
}
@Override
public Enum<?> readEnumConstant(int index, Class<? extends Enum<?>> type) {
return read(index, type);
}
@SuppressWarnings("unchecked")
public <T> T read(int index, Class<? extends T> type) {
try {
Field field = getField(type, index);
return (T) field.get(packet.getRawNMSPacket());
} catch (IllegalAccessException | NullPointerException | ArrayIndexOutOfBoundsException e) {
throw new WrapperFieldNotFoundException(packetClass, type, index);
}
}
@Override
public void writeBoolean(int index, boolean value) {
write(boolean.class, index, value);
}
@Override
public void writeByte(int index, byte value) {
write(byte.class, index, value);
}
@Override
public void writeShort(int index, short value) {
write(short.class, index, value);
}
@Override
public void writeInt(int index, int value) {
write(int.class, index, value);
}
@Override
public void writeLong(int index, long value) {
write(long.class, index, value);
}
@Override
public void writeFloat(int index, float value) {
write(float.class, index, value);
}
@Override
public void writeDouble(int index, double value) {
write(double.class, index, value);
}
@Override
public void writeString(int index, String value) {
write(String.class, index, value);
}
@Override
public void writeObject(int index, Object value) {
write(value.getClass(), index, value);
}
@Override
public void writeBooleanArray(int index, boolean[] array) {
write(boolean[].class, index, array);
}
@Override
public void writeByteArray(int index, byte[] value) {
write(byte[].class, index, value);
}
@Override
public void writeShortArray(int index, short[] value) {
write(short[].class, index, value);
}
@Override
public void writeIntArray(int index, int[] value) {
write(int[].class, index, value);
}
@Override
public void writeLongArray(int index, long[] value) {
write(long[].class, index, value);
}
@Override
public void writeFloatArray(int index, float[] value) {
write(float[].class, index, value);
}
@Override
public void writeDoubleArray(int index, double[] value) {
write(double[].class, index, value);
}
@Override
public void writeStringArray(int index, String[] value) {
write(String[].class, index, value);
}
@Override
public void writeAnyObject(int index, Object value) {
try {
Field f = packetClass.getDeclaredFields()[index];
if (!f.isAccessible()) {
f.setAccessible(true);
}
f.set(packet.getRawNMSPacket(), value);
} catch (Exception e) {
throw new WrapperFieldNotFoundException("PacketEvents failed to find any field indexed " + index + " in the " + ClassUtil.getClassSimpleName(packetClass) + " class!");
}
}
@Override
public void writeEnumConstant(int index, Enum<?> enumConstant) {
try {
write(enumConstant.getClass(), index, enumConstant);
} catch (WrapperFieldNotFoundException ex) {
write(enumConstant.getDeclaringClass(), index, enumConstant);
}
}
public void write(Class<?> type, int index, Object value) throws WrapperFieldNotFoundException {
Field field = getField(type, index);
if (field == null) {
throw new WrapperFieldNotFoundException(packetClass, type, index);
}
try {
field.set(packet.getRawNMSPacket(), value);
} catch (IllegalAccessException | NullPointerException e) {
e.printStackTrace();
}
}
public Vector3i readBlockPosition(int index) {
Object blockPosObj = readObject(index, NMSUtils.blockPosClass);
try {
int x = (Integer) NMSUtils.getBlockPosX.invoke(blockPosObj);
int y = (Integer) NMSUtils.getBlockPosY.invoke(blockPosObj);
int z = (Integer) NMSUtils.getBlockPosZ.invoke(blockPosObj);
return new Vector3i(x, y, z);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
return null;
}
}
public Vector3i readSectionPosition(int index) {
Object blockPosObj = readObject(index, NMSUtils.sectionPositionClass);
try {
int x = (Integer) NMSUtils.getBlockPosX.invoke(blockPosObj);
int y = (Integer) NMSUtils.getBlockPosY.invoke(blockPosObj);
int z = (Integer) NMSUtils.getBlockPosZ.invoke(blockPosObj);
return new Vector3i(x, y, z);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
return null;
}
}
public void writeBlockPosition(int index, Vector3i blockPosition) {
Object blockPosObj = NMSUtils.generateNMSBlockPos(blockPosition);
write(NMSUtils.blockPosClass, index, blockPosObj);
}
public ItemStack readItemStack(int index) {
Object nmsItemStack = readObject(index, NMSUtils.nmsItemStackClass);
return NMSUtils.toBukkitItemStack(nmsItemStack);
}
public void writeItemStack(int index, ItemStack stack) {
Object nmsItemStack = NMSUtils.toNMSItemStack(stack);
write(NMSUtils.nmsItemStackClass, index, nmsItemStack);
}
@Nullable
public GameMode readGameMode(int index) {
Enum<?> enumConst = readEnumConstant(index, NMSUtils.enumGameModeClass);
int targetIndex = enumConst.ordinal() - 1;
if (targetIndex == -1) {
return null;
}
return GameMode.values()[targetIndex];
}
public void writeGameMode(int index, @Nullable GameMode gameMode) {
int i = gameMode != null ? (gameMode.ordinal() + 1) : (0);
Enum<?> enumConst = EnumUtil.valueByIndex(NMSUtils.enumGameModeClass, i);
writeEnumConstant(index, enumConst);
}
public Dimension readDimension(int index, int dimensionIDLegacyIndex) {
int dimensionID;
if (version.isOlderThan(ServerVersion.v_1_13_2)) {
dimensionID = readInt(dimensionIDLegacyIndex);
} else {
Object dimensionManagerObject = readObject(index, NMSUtils.dimensionManagerClass);
WrappedPacket dimensionManagerWrapper = new WrappedPacket(new NMSPacket(dimensionManagerObject));
dimensionID = dimensionManagerWrapper.readInt(0) - 1;
}
return Dimension.getById(dimensionID);
}
public void writeDimension(int index, int dimensionIDLegacyIndex, Dimension dimension) {
if (version.isOlderThan(ServerVersion.v_1_13_2)) {
writeInt(dimensionIDLegacyIndex, dimension.getId());
} else {
Object dimensionManagerObject = readObject(index, NMSUtils.dimensionManagerClass);
WrappedPacket dimensionManagerWrapper = new WrappedPacket(new NMSPacket(dimensionManagerObject));
dimensionManagerWrapper.writeInt(0, dimension.getId() + 1);
}
}
public Difficulty readDifficulty(int index) {
Enum<?> enumConstant = readEnumConstant(index, NMSUtils.enumDifficultyClass);
return Difficulty.values()[enumConstant.ordinal()];
}
public void writeDifficulty(int index, Difficulty difficulty) {
Enum<?> enumConstant = EnumUtil.valueByIndex(NMSUtils.enumDifficultyClass, difficulty.ordinal());
writeEnumConstant(index, enumConstant);
}
public String readIChatBaseComponent(int index) {
Object iChatBaseComponent = readObject(index, NMSUtils.iChatBaseComponentClass);
return NMSUtils.readIChatBaseComponent(iChatBaseComponent);
}
public void writeIChatBaseComponent(int index, String content) {
Object iChatBaseComponent = NMSUtils.generateIChatBaseComponent(content);
write(NMSUtils.iChatBaseComponentClass, index, iChatBaseComponent);
}
public String readMinecraftKey(int index) {
if (isVersion_1_17 == -1) {
isVersion_1_17 = (byte) (version.isNewerThanOrEquals(ServerVersion.v_1_17) ? 1 : 0);
}
int namespaceIndex = isVersion_1_17 == 1 ? 2 : 0;
int keyIndex = isVersion_1_17 == 1 ? 3 : 1;
Object minecraftKey = readObject(index, NMSUtils.minecraftKeyClass);
WrappedPacket minecraftKeyWrapper = new WrappedPacket(new NMSPacket(minecraftKey));
return minecraftKeyWrapper.readString(namespaceIndex) + ":" + minecraftKeyWrapper.readString(keyIndex);
}
public void writeMinecraftKey(int index, String content) {
Object minecraftKey = null;
try {
minecraftKey = NMSUtils.minecraftKeyConstructor.newInstance(content);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
write(NMSUtils.minecraftKeyClass, index, minecraftKey);
}
public List<Object> readList(int index) {
return read(index, List.class);
}
public void writeList(int index, List<Object> list) {
write(List.class, index, list);
}
private Field getField(Class<?> type, int index) {
Map<Class<?>, Field[]> cached = FIELD_CACHE.computeIfAbsent(packetClass, k -> new ConcurrentHashMap<>());
Field[] fields = cached.computeIfAbsent(type, typeClass -> getFields(typeClass, packetClass.getDeclaredFields()));
if (fields.length >= index + 1) {
return fields[index];
} else {
throw new WrapperFieldNotFoundException(packetClass, type, index);
}
}
private Field[] getFields(Class<?> type, Field[] fields) {
List<Field> ret = new ArrayList<>();
for (Field field : fields) {
if (field.getType().equals(type)) {
if (!field.isAccessible()) {
field.setAccessible(true);
}
ret.add(field);
}
}
return ret.toArray(EMPTY_FIELD_ARRAY);
}
/**
* Does the local server version support reading at-least one field with this packet wrapper?
* If it does, we can label this wrapper to be supported on the local server version.
* One example where it would not be supported would be if the packet the wrapper is wrapping doesn't even exist on the local server version.
*
* @return Is the wrapper supported on the local server version?
*/
public boolean isSupported() {
return true;
}
/**
* If a method in a wrapper is annotated with this, it means it isn't supported on all server versions.
* It not being supported by all server versions can lead to exceptions. Make sure you always decompile a wrapper getter before using it.
* This annotation will specify what versions are supported.
*
* @author retrooper
* @since 1.8
*/
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
public @interface SupportedVersions {
ServerVersion[] ranges() default {};
}
}
@@ -1,29 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.packetwrappers.api;
/**
* Packet-Wrappers that can be sent to clients.
*
* @author retrooper
* //TODO since javadoc annotation
*/
public interface SendableWrapper {
Object asNMSPacket() throws Exception;
}
@@ -1,60 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.packetwrappers.api;
public interface WrapperPacketReader {
boolean readBoolean(int index);
byte readByte(int index);
short readShort(int index);
int readInt(int index);
long readLong(int index);
float readFloat(int index);
double readDouble(int index);
boolean[] readBooleanArray(int index);
byte[] readByteArray(int index);
short[] readShortArray(int index);
int[] readIntArray(int index);
long[] readLongArray(int index);
float[] readFloatArray(int index);
double[] readDoubleArray(int index);
String[] readStringArray(int index);
String readString(int index);
<T> T readObject(int index, Class<? extends T> type);
Enum<?> readEnumConstant(int index, Class<? extends Enum<?>> type);
Object readAnyObject(int index);
}
@@ -1,60 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.packetwrappers.api;
public interface WrapperPacketWriter {
void writeBoolean(int index, boolean value);
void writeByte(int index, byte value);
void writeShort(int index, short value);
void writeInt(int index, int value);
void writeLong(int index, long value);
void writeFloat(int index, float value);
void writeDouble(int index, double value);
void writeString(int index, String value);
//ARRAYS
void writeBooleanArray(int index, boolean[] array);
void writeByteArray(int index, byte[] value);
void writeShortArray(int index, short[] value);
void writeIntArray(int index, int[] value);
void writeLongArray(int index, long[] value);
void writeFloatArray(int index, float[] value);
void writeDoubleArray(int index, double[] value);
void writeStringArray(int index, String[] value);
void writeObject(int index, Object object);
void writeAnyObject(int index, Object value);
void writeEnumConstant(int index, Enum<?> enumConstant);
}
@@ -1,91 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.packetwrappers.api.helper;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class WrappedPacketEntityAbstraction extends WrappedPacket {
private final int entityIDFieldIndex;
protected Entity entity;
protected int entityID = -1;
public WrappedPacketEntityAbstraction(NMSPacket packet, int entityIDFieldIndex) {
super(packet);
this.entityIDFieldIndex = entityIDFieldIndex;
}
public WrappedPacketEntityAbstraction(NMSPacket packet) {
super(packet);
this.entityIDFieldIndex = 0;
}
public WrappedPacketEntityAbstraction(int entityIDFieldIndex) {
super();
this.entityIDFieldIndex = entityIDFieldIndex;
}
public WrappedPacketEntityAbstraction() {
super();
this.entityIDFieldIndex = 0;
}
public int getEntityId() {
if (entityID != -1 || packet == null) {
return entityID;
}
return entityID = readInt(entityIDFieldIndex);
}
public void setEntityId(int entityID) {
if (packet != null) {
writeInt(entityIDFieldIndex, this.entityID = entityID);
} else {
this.entityID = entityID;
}
this.entity = null;
}
@Nullable
public Entity getEntity(@Nullable World world) {
if (entity != null) {
return entity;
}
return PacketEvents.get().getServerUtils().getEntityById(world, getEntityId());
}
@Nullable
public Entity getEntity() {
if (entity != null) {
return entity;
}
return PacketEvents.get().getServerUtils().getEntityById(getEntityId());
}
public void setEntity(@NotNull Entity entity) {
setEntityId(entity.getEntityId());
this.entity = entity;
}
}
@@ -1,59 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.packetwrappers.handshaking.setprotocol;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
public class WrappedPacketHandshakingInSetProtocol extends WrappedPacket {
private static boolean v_1_17;
public WrappedPacketHandshakingInSetProtocol(NMSPacket packet) {
super(packet);
}
@Override
protected void load() {
v_1_17 = version.isNewerThanOrEquals(ServerVersion.v_1_17);
}
public int getProtocolVersion() {
return readInt(v_1_17 ? 1 : 0);
}
public void setProtocolVersion(int protocolVersion) {
writeInt(v_1_17 ? 1 : 0, protocolVersion);
}
public int getPort() {
return readInt(v_1_17 ? 2 : 1);
}
public void setPort(int port) {
writeInt(v_1_17 ? 2 : 1, port);
}
public String getHostName() {
return readString(0);
}
public void setHostName(String hostName) {
writeString(0, hostName);
}
}
@@ -1,73 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.packetwrappers.login.in.custompayload;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
public class WrappedPacketLoginInCustomPayload extends WrappedPacket {
private static boolean v_1_17;
public WrappedPacketLoginInCustomPayload(NMSPacket packet) {
super(packet);
}
@Override
protected void load() {
v_1_17 = version.isNewerThanOrEquals(ServerVersion.v_1_17);
}
public int getMessageId() {
return readInt(v_1_17 ? 1 : 0);
}
public void setMessageId(int id) {
writeInt(v_1_17 ? 1 : 0, id);
}
public byte[] getData() {
return PacketEvents.get().getByteBufUtil().getBytes(getBuffer());
}
public void setData(byte[] data) {
PacketEvents.get().getByteBufUtil().setBytes(getBuffer(), data);
}
private Object getBuffer() {
Object dataSerializer = readObject(0, NMSUtils.packetDataSerializerClass);
WrappedPacket byteBufWrapper = new WrappedPacket(new NMSPacket(dataSerializer));
return byteBufWrapper.readObject(0, NMSUtils.byteBufClass);
}
public void retain() {
PacketEvents.get().getByteBufUtil().retain(getBuffer());
}
public void release() {
PacketEvents.get().getByteBufUtil().release(getBuffer());
}
@Override
public boolean isSupported() {
return version.isNewerThan(ServerVersion.v_1_12_2);
}
}
@@ -1,50 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.packetwrappers.login.in.encryptionbegin;
import io.github.retrooper.packetevents.packettype.PacketTypeClasses;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
public class WrappedPacketLoginInEncryptionBegin extends WrappedPacket {
public WrappedPacketLoginInEncryptionBegin(NMSPacket packet) {
super(packet);
}
public byte[] getPublicKey() {
return readByteArray(0);
}
public void setPublicKey(byte[] key) {
writeByteArray(0, key);
}
public byte[] getVerifyToken() {
return readByteArray(1);
}
public void setVerifyToken(byte[] token) {
writeByteArray(1, token);
}
@Override
public boolean isSupported() {
return PacketTypeClasses.Login.Client.ENCRYPTION_BEGIN != null;
}
}
@@ -1,48 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.packetwrappers.login.in.start;
import io.github.retrooper.packetevents.packettype.PacketTypeClasses;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.gameprofile.GameProfileUtil;
import io.github.retrooper.packetevents.utils.gameprofile.WrappedGameProfile;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
public class WrappedPacketLoginInStart extends WrappedPacket {
public WrappedPacketLoginInStart(NMSPacket packet) {
super(packet);
}
//TODO Allow accessing game profile property
public WrappedGameProfile getGameProfile() {
return GameProfileUtil.getWrappedGameProfile(readObject(0, NMSUtils.gameProfileClass));
}
//TODO Add support for game profile property
public void setGameProfile(WrappedGameProfile wrappedGameProfile) {
Object gameProfile = GameProfileUtil.getGameProfile(wrappedGameProfile.getId(), wrappedGameProfile.getName());
write(NMSUtils.gameProfileClass, 0, gameProfile);
}
@Override
public boolean isSupported() {
return PacketTypeClasses.Login.Client.START != null;
}
}
@@ -1,139 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.packetwrappers.login.out.custompayload;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.packettype.PacketTypeClasses;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.packetwrappers.api.SendableWrapper;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
import java.lang.reflect.Constructor;
public class WrappedPacketLoginOutCustomPayload extends WrappedPacket implements SendableWrapper {
private static boolean v_1_17;
private static Constructor<?> constructor;
private static Constructor<?> packetDataSerializerConstructor;
private int messageID;
private String channelName;
private byte[] data;
public WrappedPacketLoginOutCustomPayload(NMSPacket packet) {
super(packet);
}
public WrappedPacketLoginOutCustomPayload(int messageID, String channelName, byte[] data) {
this.messageID = messageID;
this.channelName = channelName;
this.data = data;
}
@Override
protected void load() {
v_1_17 = version.isNewerThanOrEquals(ServerVersion.v_1_17);
Class<?> packetClass = PacketTypeClasses.Login.Server.CUSTOM_PAYLOAD;
if (packetClass != null) {
try {
if (NMSUtils.packetDataSerializerClass != null) {
packetDataSerializerConstructor = NMSUtils.packetDataSerializerClass.getConstructor(NMSUtils.byteBufClass);
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
constructor = packetClass.getConstructor(int.class, NMSUtils.minecraftKeyClass, NMSUtils.packetDataSerializerClass);
} catch (NoSuchMethodException e3) {
throw new IllegalStateException("PacketEvents is unable to resolve the PacketPlayOutCustomPayload constructor.");
}
}
}
public int getMessageId() {
if (packet != null) {
return readInt(v_1_17 ? 1 : 0);
}
return messageID;
}
public void setMessageId(int messageID) {
if (packet != null) {
writeInt(v_1_17 ? 1 : 0, messageID);
} else {
this.messageID = messageID;
}
}
public String getChannelName() {
if (packet != null) {
return readMinecraftKey(0);
}
else {
return channelName;
}
}
public void setChannelName(String channelName) {
if (packet != null) {
writeMinecraftKey(0, channelName);
} else {
this.channelName = channelName;
}
}
public byte[] getData() {
if (packet != null) {
Object dataSerializer = readObject(0, NMSUtils.packetDataSerializerClass);
WrappedPacket byteBufWrapper = new WrappedPacket(new NMSPacket(dataSerializer));
Object byteBuf = byteBufWrapper.readObject(0, NMSUtils.byteBufClass);
return PacketEvents.get().getByteBufUtil().getBytes(byteBuf);
} else {
return data;
}
}
public void setData(byte[] data) {
if (packet != null) {
PacketEvents.get().getByteBufUtil().setBytes(getBuffer(), data);
} else {
this.data = data;
}
}
private Object getBuffer() {
Object dataSerializer = readObject(0, NMSUtils.packetDataSerializerClass);
WrappedPacket byteBufWrapper = new WrappedPacket(new NMSPacket(dataSerializer));
return byteBufWrapper.readObject(0, NMSUtils.byteBufClass);
}
@Override
public Object asNMSPacket() throws Exception {
Object byteBufObject = PacketEvents.get().getByteBufUtil().newByteBuf(data);
Object minecraftKey = NMSUtils.generateMinecraftKeyNew(channelName);
Object dataSerializer = packetDataSerializerConstructor.newInstance(byteBufObject);
return constructor.newInstance(getMessageId(), minecraftKey, dataSerializer);
}
@Override
public boolean isSupported() {
return PacketTypeClasses.Login.Server.CUSTOM_PAYLOAD != null;
}
}
@@ -1,75 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.packetwrappers.login.out.disconnect;
import io.github.retrooper.packetevents.packettype.PacketTypeClasses;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.packetwrappers.api.SendableWrapper;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import java.lang.reflect.Constructor;
public class WrappedPacketLoginOutDisconnect extends WrappedPacket implements SendableWrapper {
private static Constructor<?> packetConstructor;
private String reason;
public WrappedPacketLoginOutDisconnect(NMSPacket packet) {
super(packet);
}
public WrappedPacketLoginOutDisconnect(String reason) {
this.reason = reason;
}
@Override
protected void load() {
try {
packetConstructor = PacketTypeClasses.Login.Server.DISCONNECT.getConstructor(NMSUtils.iChatBaseComponentClass);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
public String getReason() {
if (packet != null) {
return readIChatBaseComponent(0);
} else {
return this.reason;
}
}
public void setReason(final String reason) {
if (packet != null) {
writeIChatBaseComponent(0, reason);
} else {
this.reason = reason;
}
}
@Override
public Object asNMSPacket() throws Exception {
return packetConstructor.newInstance(NMSUtils.generateIChatBaseComponent(getReason()));
}
@Override
public boolean isSupported() {
return PacketTypeClasses.Login.Server.DISCONNECT != null;
}
}
@@ -1,85 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.packetwrappers.login.out.encryptionbegin;
import io.github.retrooper.packetevents.packettype.PacketTypeClasses;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
public class WrappedPacketLoginOutEncryptionBegin extends WrappedPacket {
private static boolean v_1_17;
public WrappedPacketLoginOutEncryptionBegin(NMSPacket packet) {
super(packet);
}
@Override
protected void load() {
v_1_17 = version.isNewerThanOrEquals(ServerVersion.v_1_17);
}
public String getEncodedString() {
return readString(0);
}
public void setEncodedString(String encodedString) {
writeString(0, encodedString);
}
public PublicKey getPublicKey() {
return v_1_17 ? encrypt(readByteArray(0)) : readObject(0, PublicKey.class);
}
public void setPublicKey(PublicKey key) {
if (v_1_17) {
writeByteArray(0, key.getEncoded());
} else {
writeObject(0, key);
}
}
public byte[] getVerifyToken() {
return readByteArray(v_1_17 ? 1 : 0);
}
public void setVerifyToken(byte[] verifyToken) {
writeByteArray(v_1_17 ? 1 : 0, verifyToken);
}
private PublicKey encrypt(byte[] bytes) {
try {
EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec(bytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(encodedKeySpec);
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
@Override
public boolean isSupported() {
return PacketTypeClasses.Login.Server.ENCRYPTION_BEGIN != null;
}
}
@@ -1,81 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.packetwrappers.login.out.setcompression;
import io.github.retrooper.packetevents.packettype.PacketTypeClasses;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.packetwrappers.api.SendableWrapper;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
import java.lang.reflect.Constructor;
public class WrappedPacketLoginOutSetCompression extends WrappedPacket implements SendableWrapper {
private static Constructor<?> constructor;
private int threshold;
public WrappedPacketLoginOutSetCompression(NMSPacket packet) {
super(packet);
}
public WrappedPacketLoginOutSetCompression(int threshold) {
this.threshold = threshold;
}
@Override
protected void load() {
try {
if (PacketTypeClasses.Login.Server.SET_COMPRESSION != null) {
constructor = PacketTypeClasses.Login.Server.SET_COMPRESSION.getConstructor(int.class);
}
} catch (NoSuchMethodException e) {
//probably 1.7.10
}
}
/**
* Maximum size of a packet before it can be compressed.
*
* @return threshold Threshold
*/
public int getThreshold() {
if (packet != null) {
return readInt(0);
}
return threshold;
}
public void setThreshold(int threshold) {
if (packet != null) {
writeInt(0, threshold);
} else {
this.threshold = threshold;
}
}
@Override
public Object asNMSPacket() throws Exception {
return constructor.newInstance(getThreshold());
}
@Override
public boolean isSupported() {
return version.isNewerThan(ServerVersion.v_1_7_10);
}
}
@@ -1,82 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.packetwrappers.login.out.success;
import io.github.retrooper.packetevents.packettype.PacketTypeClasses;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.packetwrappers.api.SendableWrapper;
import io.github.retrooper.packetevents.utils.gameprofile.GameProfileUtil;
import io.github.retrooper.packetevents.utils.gameprofile.WrappedGameProfile;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import java.lang.reflect.Constructor;
public class WrappedPacketLoginOutSuccess extends WrappedPacket implements SendableWrapper {
private static Constructor<?> packetConstructor;
private WrappedGameProfile wrappedGameProfile;
public WrappedPacketLoginOutSuccess(final NMSPacket packet) {
super(packet);
}
public WrappedPacketLoginOutSuccess(final WrappedGameProfile wrappedGameProfile) {
this.wrappedGameProfile = wrappedGameProfile;
}
@Override
protected void load() {
try {
packetConstructor = PacketTypeClasses.Login.Server.SUCCESS.getConstructors()[1];
} catch (final Exception e) {
e.printStackTrace();
}
}
//TODO Support property reading in wrapped game profile
public WrappedGameProfile getGameProfile() {
if (packet != null) {
return GameProfileUtil.getWrappedGameProfile(readObject(0, NMSUtils.gameProfileClass));
} else {
return this.wrappedGameProfile;
}
}
//TODO Support writing property in wrapped game profile
public void setGameProfile(final WrappedGameProfile wrappedGameProfile) {
if (packet != null) {
final Object gameProfile = GameProfileUtil.getGameProfile(wrappedGameProfile.getId(), wrappedGameProfile.getName());
write(NMSUtils.gameProfileClass, 0, gameProfile);
} else {
this.wrappedGameProfile = wrappedGameProfile;
}
}
@Override
public Object asNMSPacket() throws Exception {
WrappedGameProfile gp = getGameProfile();
//TODO Support writing property in wrapped game profile
return packetConstructor.newInstance(GameProfileUtil.getGameProfile(gp.getId(), gp.getName()));
}
@Override
public boolean isSupported() {
return PacketTypeClasses.Login.Server.SUCCESS != null;
}
}
@@ -1,113 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.packetwrappers.play.in.abilities;
import io.github.retrooper.packetevents.packettype.PacketTypeClasses;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.reflection.Reflection;
import java.util.Optional;
public final class WrappedPacketInAbilities extends WrappedPacket {
private static boolean v_1_16_Mode;
public WrappedPacketInAbilities(NMSPacket packet) {
super(packet);
}
@Override
protected void load() {
v_1_16_Mode = Reflection.getField(PacketTypeClasses.Play.Client.ABILITIES, boolean.class, 1) == null;
}
public boolean isFlying() {
return readBoolean(v_1_16_Mode ? 0 : 1);
}
public void setFlying(boolean flying) {
writeBoolean(v_1_16_Mode ? 0 : 1, flying);
}
public Optional<Boolean> isVulnerable() {
if (v_1_16_Mode) {
return Optional.empty();
}
return Optional.of(readBoolean(0));
}
public void setVulnerable(boolean vulnerable) {
if (!v_1_16_Mode) {
writeBoolean(0, vulnerable);
}
}
public Optional<Boolean> isFlightAllowed() {
if (v_1_16_Mode) {
return Optional.empty();
}
return Optional.of(readBoolean(2));
}
public void setFlightAllowed(boolean flightAllowed) {
if (!v_1_16_Mode) {
writeBoolean(2, flightAllowed);
}
}
public Optional<Boolean> canInstantlyBuild() {
if (v_1_16_Mode) {
return Optional.empty();
}
return Optional.of(readBoolean(3));
}
public void setCanInstantlyBuild(boolean canInstantlyBuild) {
if (!v_1_16_Mode) {
writeBoolean(3, canInstantlyBuild);
}
}
public Optional<Float> getFlySpeed() {
if (v_1_16_Mode) {
return Optional.empty();
}
return Optional.of(readFloat(0));
}
public void setFlySpeed(float flySpeed) {
if (!v_1_16_Mode) {
writeFloat(0, flySpeed);
}
}
public Optional<Float> getWalkSpeed() {
if (v_1_16_Mode) {
return Optional.empty();
}
return Optional.of(readFloat(1));
}
public void setWalkSpeed(float walkSpeed) {
if (!v_1_16_Mode) {
writeFloat(1, walkSpeed);
}
}
}
@@ -1,56 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.packetwrappers.play.in.armanimation;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.enums.EnumUtil;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.player.Hand;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
public class WrappedPacketInArmAnimation extends WrappedPacket {
private static boolean v_1_9;
public WrappedPacketInArmAnimation(NMSPacket packet) {
super(packet);
}
@Override
protected void load() {
v_1_9 = version.isNewerThanOrEquals(ServerVersion.v_1_9);
}
public Hand getHand() {
if (v_1_9) {
Enum<?> enumConst = readEnumConstant(0, NMSUtils.enumHandClass);
return Hand.values()[enumConst.ordinal()];
}
else {
return Hand.MAIN_HAND;
}
}
public void setHand(Hand hand) {
//Optimize to do nothing on legacy versions. The protocol of the legacy versions only support one hand, the main hand.
if (v_1_9) {
Enum<?> enumConst = EnumUtil.valueByIndex(NMSUtils.enumHandClass, hand.ordinal());
writeEnumConstant(0, enumConst);
}
}
}
@@ -1,44 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.packetwrappers.play.in.beacon;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
public class WrappedPacketInBeacon extends WrappedPacket {
public WrappedPacketInBeacon(NMSPacket packet) {
super(packet);
}
public int getPrimaryEffect() {
return readInt(0);
}
public void setPrimaryEffect(int primaryEffect) {
writeInt(0, primaryEffect);
}
public int getSecondaryEffect() {
return readInt(1);
}
public void setSecondaryEffect(int secondaryEffect) {
writeInt(1, secondaryEffect);
}
}
@@ -1,129 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.packetwrappers.play.in.blockdig;
import io.github.retrooper.packetevents.packettype.PacketTypeClasses;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.enums.EnumUtil;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.player.Direction;
import io.github.retrooper.packetevents.utils.reflection.SubclassUtil;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
import io.github.retrooper.packetevents.utils.vector.Vector3i;
public final class WrappedPacketInBlockDig extends WrappedPacket {
private static Class<? extends Enum<?>> digTypeClass;
private static boolean isVersionLowerThan_v_1_8;
public WrappedPacketInBlockDig(NMSPacket packet) {
super(packet);
}
@Override
protected void load() {
Class<?> blockDigClass = PacketTypeClasses.Play.Client.BLOCK_DIG;
isVersionLowerThan_v_1_8 = version.isOlderThan(ServerVersion.v_1_8);
if (version != ServerVersion.v_1_7_10) {
try {
digTypeClass = NMSUtils.getNMSEnumClass("EnumPlayerDigType");
} catch (ClassNotFoundException e) {
//It is probably a subclass
digTypeClass = SubclassUtil.getEnumSubClass(blockDigClass, "EnumPlayerDigType");
}
}
}
public Vector3i getBlockPosition() {
if (isVersionLowerThan_v_1_8) {
int x = readInt(0);
int y = readInt(1);
int z = readInt(2);
return new Vector3i(x, y, z);
} else {
return readBlockPosition(0);
}
}
public void setBlockPosition(Vector3i blockPos) {
if (isVersionLowerThan_v_1_8) {
writeInt(0, blockPos.x);
writeInt(1, blockPos.y);
writeInt(2, blockPos.z);
} else {
writeBlockPosition(0, blockPos);
}
}
/**
* Get the direction / Get the face.
*
* @return Direction
*/
public Direction getDirection() {
if (isVersionLowerThan_v_1_8) {
return Direction.getDirection(readInt(3));
} else {
Enum<?> enumDir = readEnumConstant(0, NMSUtils.enumDirectionClass);
return Direction.values()[enumDir.ordinal()];
}
}
public void setDirection(Direction direction) {
if (isVersionLowerThan_v_1_8) {
writeInt(3, direction.getFaceValue());
} else {
Enum<?> enumConst = EnumUtil.valueByIndex(NMSUtils.enumDirectionClass, direction.ordinal());
write(NMSUtils.enumDirectionClass, 0, enumConst);
}
}
/**
* Get the PlayerDigType enum sent in this packet.
*
* @return Dig Type
*/
public PlayerDigType getDigType() {
if (isVersionLowerThan_v_1_8) {
return PlayerDigType.values()[readInt(4)];
} else {
return PlayerDigType.values()[readEnumConstant(0, digTypeClass).ordinal()];
}
}
public void setDigType(PlayerDigType type) {
if (isVersionLowerThan_v_1_8) {
writeInt(4, type.ordinal());
} else {
Enum<?> enumConst = EnumUtil.valueByIndex(digTypeClass, type.ordinal());
writeEnumConstant(0, enumConst);
}
}
public enum PlayerDigType {
START_DESTROY_BLOCK,
ABORT_DESTROY_BLOCK,
STOP_DESTROY_BLOCK,
DROP_ALL_ITEMS,
DROP_ITEM,
RELEASE_USE_ITEM,
SWAP_ITEM_WITH_OFFHAND
}
}
@@ -1,162 +0,0 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2021 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.packetwrappers.play.in.blockplace;
import io.github.retrooper.packetevents.packetwrappers.NMSPacket;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.enums.EnumUtil;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.player.Direction;
import io.github.retrooper.packetevents.utils.player.Hand;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
import io.github.retrooper.packetevents.utils.vector.Vector3f;
import io.github.retrooper.packetevents.utils.vector.Vector3i;
import org.bukkit.inventory.ItemStack;
import java.util.Optional;
public final class WrappedPacketInBlockPlace extends WrappedPacket {
private static boolean newerThan_v_1_8_8, newerThan_v_1_7_10;
private static int handEnumIndex;
public WrappedPacketInBlockPlace(final NMSPacket packet) {
super(packet);
}
@Override
protected void load() {
newerThan_v_1_7_10 = version.isNewerThan(ServerVersion.v_1_7_10);
newerThan_v_1_8_8 = version.isNewerThan(ServerVersion.v_1_8_8);
try {
Object handEnum = readObject(1, NMSUtils.enumHandClass);
handEnumIndex = 1;
} catch (Exception ex) {
handEnumIndex = 0;//Most likely a newer version
}
}
public Hand getHand() {
if (newerThan_v_1_8_8) {
Enum<?> enumConst = readEnumConstant(handEnumIndex, NMSUtils.enumHandClass);
return Hand.values()[enumConst.ordinal()];
}
else {
return Hand.MAIN_HAND;
}
}
public void setHand(Hand hand) {
//Optimize to do nothing on legacy versions. The protocol of the legacy versions only support one hand, the main hand.
if (newerThan_v_1_8_8) {
Enum<?> enumConst = EnumUtil.valueByIndex(NMSUtils.enumHandClass, hand.ordinal());
writeEnumConstant(handEnumIndex, enumConst);
}
}
public Direction getDirection() {
if (newerThan_v_1_8_8) {
WrappedPacketInBlockPlace_1_9 blockPlace_1_9 = new WrappedPacketInBlockPlace_1_9(new NMSPacket(packet.getRawNMSPacket()));
return blockPlace_1_9.getDirection();
} else if (newerThan_v_1_7_10) {
WrappedPacketInBlockPlace_1_8 blockPlace_1_8 = new WrappedPacketInBlockPlace_1_8(new NMSPacket(packet.getRawNMSPacket()));
return Direction.getDirection(blockPlace_1_8.getFace());
} else {
WrappedPacketInBlockPlace_1_7_10 blockPlace_1_7_10 = new WrappedPacketInBlockPlace_1_7_10(new NMSPacket(packet.getRawNMSPacket()));
return Direction.getDirection(blockPlace_1_7_10.getFace());
}
}
public void setDirection(Direction direction) {
if (newerThan_v_1_8_8) {
WrappedPacketInBlockPlace_1_9 blockPlace_1_9 = new WrappedPacketInBlockPlace_1_9(new NMSPacket(packet.getRawNMSPacket()));
blockPlace_1_9.setDirection(direction);
} else if (newerThan_v_1_7_10) {
WrappedPacketInBlockPlace_1_8 blockPlace_1_8 = new WrappedPacketInBlockPlace_1_8(new NMSPacket(packet.getRawNMSPacket()));
blockPlace_1_8.setFace(direction.getFaceValue());
} else {
WrappedPacketInBlockPlace_1_7_10 blockPlace_1_7_10 = new WrappedPacketInBlockPlace_1_7_10(new NMSPacket(packet.getRawNMSPacket()));
blockPlace_1_7_10.setFace(direction.getFaceValue());
}
}
public Vector3i getBlockPosition() {
Vector3i blockPos;
if (newerThan_v_1_8_8) {
WrappedPacketInBlockPlace_1_9 blockPlace_1_9 = new WrappedPacketInBlockPlace_1_9(packet);
blockPos = blockPlace_1_9.getBlockPosition();
} else if (newerThan_v_1_7_10) {
WrappedPacketInBlockPlace_1_8 blockPlace_1_8 = new WrappedPacketInBlockPlace_1_8(packet);
blockPos = blockPlace_1_8.getBlockPosition();
} else {
WrappedPacketInBlockPlace_1_7_10 blockPlace_1_7_10 = new WrappedPacketInBlockPlace_1_7_10(packet);
blockPos = blockPlace_1_7_10.getBlockPosition();
}
return blockPos;
}
public Optional<Vector3f> getCursorPosition() {
if (newerThan_v_1_8_8) {
return Optional.empty();
} else if (newerThan_v_1_7_10) {
WrappedPacketInBlockPlace_1_8 blockPlace_1_8 = new WrappedPacketInBlockPlace_1_8(packet);
return Optional.of(blockPlace_1_8.getCursorPosition());
} else {
WrappedPacketInBlockPlace_1_7_10 blockPlace_1_7_10 = new WrappedPacketInBlockPlace_1_7_10(packet);
return Optional.of(blockPlace_1_7_10.getCursorPosition());
}
}
public void setCursorPosition(Vector3f cursorPos) {
if (newerThan_v_1_8_8) {
} else if (newerThan_v_1_7_10) {
WrappedPacketInBlockPlace_1_8 blockPlace_1_8 = new WrappedPacketInBlockPlace_1_8(packet);
blockPlace_1_8.setCursorPosition(cursorPos);
} else {
WrappedPacketInBlockPlace_1_7_10 blockPlace_1_7_10 = new WrappedPacketInBlockPlace_1_7_10(packet);
blockPlace_1_7_10.setCursorPosition(cursorPos);
}
}
public Optional<ItemStack> getItemStack() {
if (newerThan_v_1_8_8) {
return Optional.empty();
} else if (newerThan_v_1_7_10) {
WrappedPacketInBlockPlace_1_8 blockPlace_1_8 = new WrappedPacketInBlockPlace_1_8(packet);
return Optional.of(blockPlace_1_8.getItemStack());
} else {
WrappedPacketInBlockPlace_1_7_10 blockPlace_1_7_10 = new WrappedPacketInBlockPlace_1_7_10(packet);
return Optional.of(blockPlace_1_7_10.getItemStack());
}
}
public void setItemStack(ItemStack stack) {
if (newerThan_v_1_8_8) {
//Newer versions do not contain an itemstack
} else if (newerThan_v_1_7_10) {
WrappedPacketInBlockPlace_1_8 blockPlace_1_8 = new WrappedPacketInBlockPlace_1_8(packet);
blockPlace_1_8.setItemStack(stack);
} else {
WrappedPacketInBlockPlace_1_7_10 blockPlace_1_7_10 = new WrappedPacketInBlockPlace_1_7_10(packet);
blockPlace_1_7_10.setItemStack(stack);
}
}
}
Loaded 100 of 261 files, more files were not shown because too many files have changed in this diff. Show more