notion says hi

This commit is contained in:
Brandon 2023-05-21 01:15:25 +01:00
parent bfc6df2b70
commit 3e15e361ff
256 changed files with 26450 additions and 1 deletions

4
.gitattributes vendored Normal file
View File

@ -0,0 +1,4 @@
# Auto detect text files and perform LF normalization
* text=auto

154
.gitignore vendored Normal file
View File

@ -0,0 +1,154 @@
# Compiled source #
###################
*.com
*.class
*.dll
*.exe
*.o
*.iml
# Packages #
############
# it's better to unpack these files and commit the raw source
# git has its own built in compression methods
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
# Logs and databases #
######################
*.log
*.sqlite
# OS generated files #
######################
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
.idea
ehthumbs.db
Thumbs.db
#Eclipse
*.pydevproject
.metadata
.gradle
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
# sbteclipse plugin
.target
# TeXlipse plugin
.texlipse
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode
## Directory-based project format
.idea/
# if you remove the above rule, at least ignore user-specific stuff:
# .idea/workspace.xml
# .idea/tasks.xml
# and these sensitive or high-churn files:
# .idea/dataSources.ids
# .idea/dataSources.xml
# .idea/sqlDataSources.xml
# .idea/dynamic.xml
## File-based project format
*.ipr
*.iws
*.iml
## Additional for IntelliJ
out/
# generated by mpeltonen/sbt-idea plugin
.idea_modules/
# generated by JIRA plugin
atlassian-ide-plugin.xml
# generated by Crashlytics plugin (for Android Studio and Intellij)
com_crashlytics_export_strings.xml
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Notepad++ backups #
*.bak
# Project stuff
target/
#IntelliJ
.idea/**
*.iml
# eclipse specific
*.pydevproject
.project
.metadata
bin/**
tmp/**
tmp/**/*
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
Karhu.iml
*.iml
Karhu.iml
*.iml
Karhu.iml

165
LICENSE Normal file
View File

@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

View File

@ -1 +1,4 @@
# Karhu -old
MC-Market anticheat
Contact me on discord before u start working on something xd, so i can commit shit, because i forget to commit so often.

102
pom.xml Normal file
View File

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>me.liwk</groupId>
<artifactId>Karhu</artifactId>
<version>1.9.20-</version>
<packaging>jar</packaging>
<name>Karhu</name>
<description>KarhuAC</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<defaultGoal>clean package</defaultGoal>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
<repositories>
<repository>
<id>sonatype</id>
<url>https://oss.sonatype.org/content/groups/public/</url>
</repository>
</repositories>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>29.0-jre</version>
</dependency>
<dependency>
<groupId>io.janusproject.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0.0</version>
</dependency>
<!-- Thanks for using https://jar-download.com -->
<dependency>
<groupId>com.google.collections</groupId>
<artifactId>google-collections</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,285 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.impl.PostPlayerInjectEvent;
import io.github.retrooper.packetevents.exceptions.PacketEventsLoadFailureException;
import io.github.retrooper.packetevents.packetmanager.PacketManager;
import io.github.retrooper.packetevents.packettype.PacketTypeClasses;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
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.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.player.ClientVersion;
import io.github.retrooper.packetevents.utils.server.PEVersion;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
import io.github.retrooper.packetevents.utils.versionlookup.VersionLookupUtils;
import io.github.retrooper.packetevents.utils.versionlookup.v_1_7_10.ProtocolVersionAccessor_v_1_7;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.plugin.Plugin;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public final class PacketEvents implements Listener {
private static final PacketEventsAPI packetEventsAPI = new PacketEventsAPI();
private static final PacketEvents instance = new PacketEvents();
private static final ArrayList<Plugin> plugins = new ArrayList<>(1);
private static boolean loading, loaded, initialized, initializing, uninitializing;
private static final PEVersion version = new PEVersion(1, 7, 9);
private static PacketEventsSettings settings = new PacketEventsSettings();
/**
* General executor service, basically for anything that the packet executor service doesn't do.
*/
public static ExecutorService generalExecutorService = Executors.newSingleThreadExecutor();
//Executor used for player injecting/ejecting and for packet processing/event calling
public static ExecutorService packetHandlingExecutorService = Executors.newSingleThreadExecutor();
/**
* This loads the PacketEvents API.
* <p>
* ServerVersion:
* In this method we detect and cache the server version.
* <p>
* NMSUtils:
* We setup some NMS utilities.
* <p>
* Packet ID System:
* All the packet classes we will be needing are cached in a Map with an integer ID.
* <p>
* Version Lookup Utils:
* We setup the client protocol version system.
* We check if ViaVersion, ProtocolSupport or ProtocolLib is present.
* <p>
* Wrappers:
* All PacketEvents' wrappers are setup and do all loading they need to do.
*/
public static void load() {
if (!loaded && !loading) {
loading = true;
ServerVersion version = ServerVersion.getVersion();
WrappedPacket.version = version;
PacketEvent.version = version;
NMSUtils.version = version;
EntityFinderUtils.version = version;
try {
NMSUtils.load();
PacketTypeClasses.Client.load();
PacketTypeClasses.Server.load();
PacketTypeClasses.Login.load();
PacketTypeClasses.Status.load();
EntityFinderUtils.load();
WrappedPacket.loadAllWrappers();
} catch (Exception ex) {
loading = false;
throw new PacketEventsLoadFailureException(ex);
}
loaded = true;
loading = false;
}
}
public static void loadSettings(PacketEventsSettings settings) {
PacketEvents.settings = settings;
}
public static void init(final Plugin plugin) {
init(plugin, settings);
}
/**
* Initiates PacketEvents
* <p>
* Loading:
* Loads PacketEvents if you haven't already.
* <p>
* Registering:
* Registers this class as a Bukkit listener to inject/eject players.
*
* @param pl JavaPlugin instance
*/
public static void init(final Plugin pl, PacketEventsSettings packetEventsSettings) {
load();
if (!initialized && !initializing) {
initializing = true;
settings = packetEventsSettings;
int packetHandlingThreadCount = settings.getPacketHandlingThreadCount();
//if the count is 1 or is invalid
if (packetHandlingThreadCount == 1 || packetHandlingThreadCount < 0) {
packetHandlingExecutorService = Executors.newSingleThreadExecutor();
} else {
packetHandlingExecutorService = Executors.newFixedThreadPool(packetHandlingThreadCount);
}
plugins.add(pl);
//Register Bukkit listener
Bukkit.getPluginManager().registerEvents(instance, plugins.get(0));
PacketEvents.getAPI().packetManager = new PacketManager(plugins.get(0), settings.shouldInjectEarly());
for (final Player p : Bukkit.getOnlinePlayers()) {
try {
getAPI().getPlayerUtils().injectPlayer(p);
} catch (Exception ex) {
p.kickPlayer("Failed to inject you, please rejoin the server!");
}
}
if (settings.shouldCheckForUpdates()) {
PacketEvents.generalExecutorService.execute(new Runnable() {
@Override
public void run() {
new UpdateChecker().handleUpdate();
}
});
}
initialized = true;
initializing = false;
}
}
/**
*
*/
public static void stop() {
if (initialized && !uninitializing) {
uninitializing = true;
for (Player player : Bukkit.getOnlinePlayers()) {
PacketEvents.getAPI().packetManager.ejectPlayer(player);
}
if (PacketEvents.getAPI().packetManager.tinyProtocol != null) {
PacketEvents.getAPI().packetManager.tinyProtocol.unregisterChannelHandler();
}
getAPI().getEventManager().unregisterAllListeners();
PacketEvents.generalExecutorService.shutdownNow();
PacketEvents.packetHandlingExecutorService.shutdownNow();
initialized = false;
uninitializing = true;
}
}
public static boolean hasLoaded() {
return loaded;
}
public static boolean isLoading() {
return loading;
}
public static boolean isInitializing() {
return initializing;
}
public static boolean isUninitializing() {
return uninitializing;
}
public static boolean isInitialized() {
return initialized;
}
public static PacketEventsAPI getAPI() {
return packetEventsAPI;
}
public static ArrayList<Plugin> getPlugins() {
return plugins;
}
/**
* Get the PacketEvents settings.
*
* @return Configure some settings for the API
*/
public static PacketEventsSettings getSettings() {
return settings;
}
public static PEVersion getVersion() {
return version;
}
@EventHandler(priority = EventPriority.LOW)
public void onLogin(PlayerLoginEvent e) {
if (PacketEvents.getSettings().shouldInjectEarly()) {
assert getAPI().packetManager.tinyProtocol != null;
try {
getAPI().packetManager.injectPlayer(e.getPlayer());
} catch (Exception ex) {
e.disallow(PlayerLoginEvent.Result.KICK_OTHER, "We are unable to inject you. Please try again!");
}
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onJoin(final PlayerJoinEvent e) {
Object channel = NMSUtils.getChannel(e.getPlayer());
if (PacketEvents.getAPI().getServerUtils().getVersion() == ServerVersion.v_1_7_10) {
ClientVersion version = ClientVersion.getClientVersion(ProtocolVersionAccessor_v_1_7.getProtocolVersion(e.getPlayer()));
PacketEvents.getAPI().getPlayerUtils().clientVersionsMap.put(channel, version);
}
else if(VersionLookupUtils.isDependencyAvailable()) {
int protocolVersion = VersionLookupUtils.getProtocolVersion(e.getPlayer());
ClientVersion version = ClientVersion.getClientVersion(protocolVersion);
PacketEvents.getAPI().getPlayerUtils().clientVersionsMap.put(channel, version);
}
if (!PacketEvents.getSettings().shouldInjectEarly()) {
try {
PacketEvents.getAPI().packetManager.injectPlayer(e.getPlayer());
PacketEvents.getAPI().getEventManager().callEvent(new PostPlayerInjectEvent(e.getPlayer()));
} catch (Exception ex) {
e.getPlayer().kickPlayer("There was an issue injecting you. Please try again!");
}
}
else {
PacketEvents.getAPI().getEventManager().callEvent(new PostPlayerInjectEvent(e.getPlayer()));
}
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onQuit(final PlayerQuitEvent e) {
Object channel = NMSUtils.getChannelNoCache(e.getPlayer());
PacketEvents.getAPI().getPlayerUtils().clientVersionsMap.remove(channel);
}
}

View File

@ -0,0 +1,67 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents;
import io.github.retrooper.packetevents.event.manager.EventManager;
import io.github.retrooper.packetevents.packetmanager.PacketManager;
import io.github.retrooper.packetevents.settings.PacketEventsSettings;
import io.github.retrooper.packetevents.utils.player.PlayerUtils;
import io.github.retrooper.packetevents.utils.server.ServerUtils;
public final class PacketEventsAPI {
private final EventManager eventManager = new EventManager();
private final PlayerUtils playerUtils = new PlayerUtils();
private final ServerUtils serverUtils = new ServerUtils();
public PacketManager packetManager = null;
/**
* Get all utilities to do with the player
*
* @return Player Utilities
*/
public PlayerUtils getPlayerUtils() {
return playerUtils;
}
/**
* Get all utilities to do with the server
*
* @return Server Utilities
*/
public ServerUtils getServerUtils() {
return serverUtils;
}
/**
* Get the event manager
* Used to call events, register and unregister listeners
*
* @return PacketEvents' event manager
*/
public EventManager getEventManager() {
return eventManager;
}
}

View File

@ -0,0 +1,37 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.annotations;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* This annotation indicates that something might be unstable.
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Beta {
}

View File

@ -0,0 +1,40 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.annotations;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Guaranteed to not be null.
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface NotNull {
}

View File

@ -0,0 +1,40 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.annotations;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Possible that it is null.
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Nullable {
}

View File

@ -0,0 +1,57 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.enums;
public enum Direction {
/**
* -Y offset
*/
DOWN,
/**
* +Y offset
*/
UP,
/**
* -Z offset
*/
NORTH,
/**
* +Z offset
*/
SOUTH,
/**
* -X offset
*/
WEST,
/**
* +X offset
*/
EAST;
}

View File

@ -0,0 +1,49 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.event;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
/**
* An event in the PacketEvents EventManager system.
*/
public abstract class PacketEvent {
public static ServerVersion version;
private long timestamp = System.currentTimeMillis();
/**
* Timestamp of the packet
*
* @return timestamp in milliseconds
*/
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
}

View File

@ -0,0 +1,33 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.event;
/**
* A Packet listener.
* Implement this interface in your listeners.
*/
@Deprecated
public interface PacketListener {
}

View File

@ -0,0 +1,65 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.event;
import io.github.retrooper.packetevents.event.impl.*;
public abstract class PacketListenerDynamic {
private final byte priority;
public PacketListenerDynamic(final byte priority) {
this.priority = priority;
}
public final byte getPriority() {
return priority;
}
public void onPacketStatus(PacketStatusEvent event) {
}
public void onPacketLogin(PacketLoginEvent event) {
}
public void onPacketReceive(PacketReceiveEvent event) {
}
public void onPacketSend(PacketSendEvent event) {
}
public void onPostPacketReceive(PostPacketReceiveEvent event) {
}
public void onPostPacketSend(PostPacketSendEvent event) {
}
public void onPlayerInject(PlayerInjectEvent event) {
}
public void onPlayerEject(PlayerEjectEvent event) {
}
public void onPacketEvent(PacketEvent event) {
}
}

View File

@ -0,0 +1,35 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.event.annotation;
import io.github.retrooper.packetevents.event.priority.PacketEventPriority;
import java.lang.annotation.*;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface PacketHandler {
byte priority() default PacketEventPriority.NORMAL;
}

View File

@ -0,0 +1,56 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.event.eventtypes;
/**
* This indicates that it is possible to cancel an event,
* which should result in cancelling the planned action.
*/
public interface CancellableEvent {
/**
* Has the event been cancelled?
* @return is event cancelled
*/
boolean isCancelled();
/**
* Cancel or proceed with the event.
* @param val
*/
void setCancelled(boolean val);
/**
* Cancel the event.
* You can achieve the same result by just using {@link #setCancelled(boolean)}
*/
void cancel();
/**
* Uncancel the event.
* You can achieve the same result by just using {@link #setCancelled(boolean)}
*/
void uncancel();
}

View File

@ -0,0 +1,37 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.event.eventtypes;
import org.bukkit.entity.Player;
/**
* Event having to do with a player.
*/
public interface PlayerEvent {
/**
* Associated player.
*/
Player getPlayer();
}

View File

@ -0,0 +1,96 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.eventtypes.CancellableEvent;
import io.github.retrooper.packetevents.packettype.PacketType;
import io.github.retrooper.packetevents.utils.reflection.ClassUtil;
/**
* This event is called when we receive a login packet.
*/
public class PacketLoginEvent extends PacketEvent implements CancellableEvent {
private final Object channel;
private final Object packet;
private boolean cancelled;
public PacketLoginEvent(final Object channel, final Object packet) {
this.channel = channel;
this.packet = packet;
}
public Object getChannel() {
return channel;
}
/**
* Get the packet's name (NMS packet class simple name).
* The class simple name is cached.
*
* @return Name of the packet
*/
public String getPacketName() {
return ClassUtil.getClassSimpleName(packet.getClass());
}
/**
* Get the raw packet object
*
* @return packet object
*/
public Object getNMSPacket() {
return packet;
}
/**
* Get the ID of the packet
*
* @return packet id
*/
public byte getPacketId() {
return PacketType.Login.packetIds.getOrDefault(packet.getClass(), (byte) -1);
}
@Override
public void cancel() {
cancelled = true;
}
@Override
public void uncancel() {
cancelled = false;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean value) {
cancelled = value;
}
}

View File

@ -0,0 +1,109 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.eventtypes.CancellableEvent;
import io.github.retrooper.packetevents.event.eventtypes.PlayerEvent;
import io.github.retrooper.packetevents.packettype.PacketType;
import io.github.retrooper.packetevents.utils.reflection.ClassUtil;
import org.bukkit.entity.Player;
/**
* This event is called each time a packet is received from a client.
*/
public final class PacketReceiveEvent extends PacketEvent implements CancellableEvent, PlayerEvent {
private final Player player;
private final Object packet;
private boolean cancelled;
private byte packetID = -1;
public PacketReceiveEvent(final Player player, final Object packet) {
this.player = player;
this.packet = packet;
}
/**
* Get the packet sender
*
* @return player
*/
@Override
public Player getPlayer() {
return player;
}
/**
* Get the packet's name (NMS packet class simple name).
* The class simple name is cached.
*
* @return Name of the packet
*/
public String getPacketName() {
return ClassUtil.getClassSimpleName(packet.getClass());
}
/**
* Get the raw packet object
*
* @return packet object
*/
public Object getNMSPacket() {
return packet;
}
/**
* Get the ID of the packet
*
* @return packet id
*/
public byte getPacketId() {
if (packetID == -1) {
packetID = PacketType.Client.packetIds.getOrDefault(packet.getClass(), (byte) -1);
}
return packetID;
}
@Override
public void cancel() {
cancelled = true;
}
@Override
public void uncancel() {
cancelled = false;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean value) {
cancelled = value;
}
}

View File

@ -0,0 +1,104 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.eventtypes.CancellableEvent;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.eventtypes.PlayerEvent;
import io.github.retrooper.packetevents.packettype.PacketType;
import io.github.retrooper.packetevents.utils.reflection.ClassUtil;
import org.bukkit.entity.Player;
/**
* This event is called each time the server sends a packet to the client.
*/
public final class PacketSendEvent extends PacketEvent implements CancellableEvent, PlayerEvent {
private final Player player;
private final Object packet;
private boolean cancelled;
private byte packetID = -1;
public PacketSendEvent(final Player player, final Object packet) {
this.player = player;
this.packet = packet;
this.cancelled = false;
}
@Override
public Player getPlayer() {
return player;
}
/**
* Get the packet's name (NMS packet class simple name).
* The class simple name is cached.
* @return Name of the packet
*/
public String getPacketName() {
return ClassUtil.getClassSimpleName(packet.getClass());
}
/**
* Get the ID of the packet
*
* @return packet id
*/
public byte getPacketId() {
if(packetID == -1) {
packetID = PacketType.Server.packetIds.getOrDefault(packet.getClass(), (byte) -1);
}
return packetID;
}
/**
* Get the NMS packet object
*
* @return packet object
*/
public Object getNMSPacket() {
return packet;
}
@Override
public void cancel() {
cancelled = true;
}
@Override
public void uncancel() {
cancelled = false;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean value) {
cancelled = value;
}
}

View File

@ -0,0 +1,97 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.eventtypes.CancellableEvent;
import io.github.retrooper.packetevents.packettype.PacketType;
import io.github.retrooper.packetevents.utils.reflection.ClassUtil;
public class PacketStatusEvent extends PacketEvent implements CancellableEvent {
private final Object channel;
private final Object packet;
private boolean cancelled;
private byte packetID = -1;
public PacketStatusEvent(final Object channel, final Object packet) {
this.channel = channel;
this.packet = packet;
}
public Object getChannel() {
return channel;
}
/**
* Get the packet's name (NMS packet class simple name).
* The class simple name is cached.
*
* @return Name of the packet
*/
public String getPacketName() {
return ClassUtil.getClassSimpleName(packet.getClass());
}
/**
* Get the raw packet object
*
* @return packet object
*/
public Object getNMSPacket() {
return packet;
}
/**
* Get the ID of the packet
*
* @return packet id
*/
public byte getPacketId() {
if (packetID == -1) {
packetID = PacketType.Status.packetIds.getOrDefault(packet.getClass(), (byte) -1);
}
return packetID;
}
@Override
public void cancel() {
cancelled = true;
}
@Override
public void uncancel() {
cancelled = false;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean value) {
cancelled = value;
}
}

View File

@ -0,0 +1,78 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.eventtypes.CancellableEvent;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.eventtypes.PlayerEvent;
import org.bukkit.entity.Player;
/**
* This event is called each time you eject a player.
*/
public final class PlayerEjectEvent extends PacketEvent implements CancellableEvent, PlayerEvent {
private final Player player;
private final boolean async;
private boolean cancelled;
public PlayerEjectEvent(final Player player, final boolean isAsync) {
this.player = player;
this.async = isAsync;
}
public PlayerEjectEvent(final Player player) {
this.player = player;
this.async = true; //default value
}
@Override
public void cancel() {
cancelled = true;
}
@Override
public void uncancel() {
cancelled = false;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean value) {
cancelled = value;
}
@Override
public Player getPlayer() {
return player;
}
public boolean isAsync() {
return async;
}
}

View File

@ -0,0 +1,77 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.eventtypes.CancellableEvent;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.eventtypes.PlayerEvent;
import org.bukkit.entity.Player;
/**
* This event is called each time you inject a player.
*/
public final class PlayerInjectEvent extends PacketEvent implements CancellableEvent, PlayerEvent {
private final Player player;
private final boolean async;
private boolean cancelled;
public PlayerInjectEvent(final Player player) {
this(player, false);
}
public PlayerInjectEvent(final Player player, boolean isAsync) {
this.player= player;
this.async = isAsync;
}
@Override
public void cancel() {
cancelled = true;
}
@Override
public void uncancel() {
cancelled = false;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean value) {
cancelled = value;
}
@Override
public Player getPlayer() {
return player;
}
public boolean isAsync() {
return async;
}
}

View File

@ -0,0 +1,78 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.eventtypes.PlayerEvent;
import io.github.retrooper.packetevents.packettype.PacketType;
import io.github.retrooper.packetevents.utils.reflection.ClassUtil;
import org.bukkit.entity.Player;
public class PostPacketReceiveEvent extends PacketEvent implements PlayerEvent {
private final Player player;
private final Object packet;
private byte packetID = -1;
public PostPacketReceiveEvent(final Player player, final Object packet) {
this.player = player;
this.packet = packet;
}
/**
* Get the packet sender
* @return player
*/
@Override
public Player getPlayer() {
return player;
}
/**
* Get the packet's name (NMS packet class simple name).
* The class simple name is cached.
* @return Name of the packet
*/
public String getPacketName() {
return ClassUtil.getClassSimpleName(packet.getClass());
}
/**
* Get the raw packet object
* @return packet object
*/
public Object getNMSPacket() {
return packet;
}
/**
* Get the ID of the packet
* @return packet id
*/
public byte getPacketId() {
if(packetID == -1) {
packetID = PacketType.Client.packetIds.getOrDefault(packet.getClass(), (byte) -1);
}
return packetID;
}
}

View File

@ -0,0 +1,83 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.eventtypes.PlayerEvent;
import io.github.retrooper.packetevents.packettype.PacketType;
import io.github.retrooper.packetevents.utils.reflection.ClassUtil;
import org.bukkit.entity.Player;
public class PostPacketSendEvent extends PacketEvent implements PlayerEvent {
private final Player player;
private final Object packet;
private byte packetID = -1;
public PostPacketSendEvent(final Player player, final Object packet) {
this.player = player;
this.packet = packet;
}
/**
* Get the packet sender
*
* @return player
*/
@Override
public Player getPlayer() {
return player;
}
/**
* Get the packet's name (NMS packet class simple name).
* The class simple name is cached.
*
* @return Name of the packet
*/
public String getPacketName() {
return ClassUtil.getClassSimpleName(packet.getClass());
}
/**
* Get the raw packet object
*
* @return packet object
*/
public Object getNMSPacket() {
return packet;
}
/**
* Get the ID of the packet
*
* @return packet id
*/
public byte getPacketId() {
if (packetID == -1) {
packetID = PacketType.Server.packetIds.getOrDefault(packet.getClass(), (byte) -1);
}
return packetID;
}
}

View File

@ -0,0 +1,52 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
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.eventtypes.PlayerEvent;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.player.ClientVersion;
import org.bukkit.entity.Player;
public class PostPlayerInjectEvent extends PacketEvent implements PlayerEvent {
private final Player player;
public PostPlayerInjectEvent(Player player) {
this.player = player;
}
@Override
public Player getPlayer() {
return player;
}
public Object getChannel() {
return NMSUtils.getChannel(player);
}
public ClientVersion getClientVersion() {
return PacketEvents.getAPI().getPlayerUtils().clientVersionsMap.get(getChannel());
}
}

View File

@ -0,0 +1,80 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
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.PacketListenerDynamic;
public final class EventManager {
private final EventManagerLegacy legacyEventManager = new EventManagerLegacy();
private final EventManagerDynamic dynamicEventManager = new EventManagerDynamic();
public void callEvent(PacketEvent event) {
dynamicEventManager.callEvent(event);
legacyEventManager.callEvent(event);
}
@Deprecated
public void registerListener(PacketListener listener) {
legacyEventManager.registerListener(listener);
}
@Deprecated
public void registerListeners(PacketListener... listeners) {
legacyEventManager.registerListeners(listeners);
}
@Deprecated
public void unregisterListener(PacketListener listener) {
legacyEventManager.unregisterListener(listener);
}
@Deprecated
public void unregisterListeners(PacketListener... listeners) {
legacyEventManager.unregisterListeners(listeners);
}
public void registerListener(PacketListenerDynamic listener) {
dynamicEventManager.registerListener(listener);
}
public void registerListeners(PacketListenerDynamic... listeners) {
dynamicEventManager.registerListeners(listeners);
}
public void unregisterListener(PacketListenerDynamic listener) {
dynamicEventManager.unregisterListener(listener);
}
public void unregisterListeners(PacketListenerDynamic... listeners) {
dynamicEventManager.unregisterListeners(listeners);
}
public void unregisterAllListeners() {
dynamicEventManager.unregisterAllListeners();
legacyEventManager.unregisterAllListeners();
}
}

View File

@ -0,0 +1,117 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.event.manager;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.PacketListenerDynamic;
import io.github.retrooper.packetevents.event.eventtypes.CancellableEvent;
import io.github.retrooper.packetevents.event.impl.*;
import io.github.retrooper.packetevents.event.priority.PacketEventPriority;
import io.github.retrooper.packetevents.exceptions.PacketEventsMethodInvokeException;
import io.github.retrooper.packetevents.utils.reflection.ClassUtil;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
class EventManagerDynamic {
private final Map<Byte, List<PacketListenerDynamic>> map = new HashMap<>();
public void callEvent(PacketEvent event) {
boolean isCancelled = false;
for (byte i = PacketEventPriority.LOWEST; i <= PacketEventPriority.MONITOR; i++) {
if (map.get(i) != null) {
for (PacketListenerDynamic listener : map.get(i)) {
try {
listener.onPacketEvent(event);
if (event instanceof PacketStatusEvent) {
listener.onPacketStatus((PacketStatusEvent) event);
} else if (event instanceof PacketLoginEvent) {
listener.onPacketLogin((PacketLoginEvent) event);
} else if (event instanceof PacketReceiveEvent) {
listener.onPacketReceive((PacketReceiveEvent) event);
} else if (event instanceof PacketSendEvent) {
listener.onPacketSend((PacketSendEvent) event);
} else if (event instanceof PostPacketReceiveEvent) {
listener.onPostPacketReceive((PostPacketReceiveEvent) event);
} else if (event instanceof PostPacketSendEvent) {
listener.onPostPacketSend((PostPacketSendEvent) event);
} else if (event instanceof PlayerInjectEvent) {
listener.onPlayerInject((PlayerInjectEvent) event);
} else if (event instanceof PlayerEjectEvent) {
listener.onPlayerEject((PlayerEjectEvent) event);
}
} catch (Exception ex) {
ex.printStackTrace();
}
if (event instanceof CancellableEvent) {
CancellableEvent ce = (CancellableEvent) event;
isCancelled = ce.isCancelled();
}
}
}
}
if (event instanceof CancellableEvent) {
CancellableEvent ce = (CancellableEvent) event;
ce.setCancelled(isCancelled);
}
}
public void registerListener(PacketListenerDynamic listener) {
List<PacketListenerDynamic> listeners = map.get(listener.getPriority());
if (listeners == null) {
map.put(listener.getPriority(), new ArrayList<>());
listeners = map.get(listener.getPriority());
}
listeners.add(listener);
}
public void registerListeners(PacketListenerDynamic... listeners) {
for (PacketListenerDynamic listener : listeners) {
registerListener(listener);
}
}
public void unregisterListener(PacketListenerDynamic listener) {
List<PacketListenerDynamic> listeners = map.get(listener.getPriority());
if (listeners == null) {
return;
}
listeners.remove(listener);
}
public void unregisterListeners(PacketListenerDynamic... listeners) {
for (PacketListenerDynamic listener : listeners) {
unregisterListener(listener);
}
}
public void unregisterAllListeners() {
map.clear();
}
}

View File

@ -0,0 +1,112 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
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 io.github.retrooper.packetevents.event.priority.PacketEventPriority;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
class EventManagerLegacy {
private final Map<PacketListener, List<Method>> staticRegisteredMethods = new HashMap<>();
public void callEvent(final PacketEvent e) {
boolean isCancelled = false;
byte eventPriority = PacketEventPriority.LOWEST;
//STATIC LISTENERS
for (final PacketListener listener : staticRegisteredMethods.keySet()) {
List<Method> methods = staticRegisteredMethods.get(listener);
for (Method method : methods) {
Class<?> parameterType = method.getParameterTypes()[0];
if (parameterType.equals(PacketEvent.class)
|| parameterType.isInstance(e)) {
PacketHandler annotation = method.getAnnotation(PacketHandler.class);
try {
method.invoke(listener, e);
} catch (IllegalAccessException | InvocationTargetException ex) {
ex.printStackTrace();
}
if (e instanceof CancellableEvent) {
CancellableEvent ce = (CancellableEvent) e;
if (annotation.priority() >= eventPriority) {
eventPriority = annotation.priority();
isCancelled = ce.isCancelled();
}
}
}
}
}
if(e instanceof CancellableEvent) {
CancellableEvent ce = (CancellableEvent)e;
ce.setCancelled(isCancelled);
}
}
public void registerListener(final PacketListener listener) {
final List<Method> methods = new ArrayList<>();
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);
}
}
public void registerListeners(final PacketListener... listeners) {
for (final PacketListener listener : listeners) {
registerListener(listener);
}
}
public void unregisterListener(final PacketListener e) {
staticRegisteredMethods.remove(e);
}
public void unregisterListeners(final PacketListener... listeners) {
for (final PacketListener listener : listeners) {
unregisterListener(listener);
}
}
public void unregisterAllListeners() {
staticRegisteredMethods.clear();
}
}

View File

@ -0,0 +1,34 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.event.priority;
public interface PacketEventPriority {
byte LOWEST = 0;
byte LOW = 1;
byte NORMAL = 2;
byte HIGH = 3;
byte HIGHEST = 4;
byte MONITOR = 5;
}

View File

@ -0,0 +1,56 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.example;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.event.PacketListenerDynamic;
import io.github.retrooper.packetevents.event.impl.PacketReceiveEvent;
import io.github.retrooper.packetevents.event.priority.PacketEventPriority;
import io.github.retrooper.packetevents.packettype.PacketType;
import io.github.retrooper.packetevents.packetwrappers.in.useentity.WrappedPacketInUseEntity;
import io.github.retrooper.packetevents.utils.player.ClientHand;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
import org.bukkit.plugin.java.JavaPlugin;
public class MainExample extends JavaPlugin {
@Override
public void onLoad() {
PacketEvents.load();
}
@Override
public void onEnable() {
PacketEvents.getSettings().injectAsync(true)
.ejectAsync(true).backupServerVersion(ServerVersion.v_1_7_10)
.checkForUpdates(true).injectEarly(true)
.packetHandlingThreadCount(1);
PacketEvents.init(this);
}
@Override
public void onDisable() {
PacketEvents.stop();
}
}

View File

@ -0,0 +1,43 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.exceptions;
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 successfully load...");
}
public PacketEventsLoadFailureException(Throwable cause) {
this("PacketEvents failed to successfully load...", cause);
}
}

View File

@ -0,0 +1,41 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.exceptions;
import io.github.retrooper.packetevents.event.PacketListener;
import io.github.retrooper.packetevents.utils.reflection.ClassUtil;
import java.lang.reflect.Method;
public class PacketEventsMethodAccessException extends RuntimeException {
public PacketEventsMethodAccessException(String message) {
super(message);
}
public PacketEventsMethodAccessException(Method method, PacketListener listener) {
this("PacketEvents failed to access the "
+ method.getName() + " method in " + ClassUtil.getClassSimpleName(listener.getClass()));
}
}

View File

@ -0,0 +1,50 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.exceptions;
import io.github.retrooper.packetevents.event.PacketListener;
import io.github.retrooper.packetevents.utils.reflection.ClassUtil;
import java.lang.reflect.Method;
public class PacketEventsMethodInvokeException extends RuntimeException {
public PacketEventsMethodInvokeException(String message) {
super(message);
}
public PacketEventsMethodInvokeException(String message, Throwable cause) {
super(message, cause);
}
public PacketEventsMethodInvokeException(Method method, PacketListener listener) {
this("PacketEvents failed to call the " + method.getName() + " method in "
+ ClassUtil.getClassSimpleName(listener.getClass()));
}
public PacketEventsMethodInvokeException(Method method, PacketListener listener, Throwable cause) {
this("PacketEvents failed to call the " + method.getName() + " method in "
+ ClassUtil.getClassSimpleName(listener.getClass()), cause);
}
}

View File

@ -0,0 +1,37 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.exceptions;
import io.github.retrooper.packetevents.utils.reflection.ClassUtil;
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!");
}
}

View File

@ -0,0 +1,292 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetmanager;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.event.impl.*;
import io.github.retrooper.packetevents.packetmanager.netty.NettyPacketManager;
import io.github.retrooper.packetevents.packetmanager.tinyprotocol.TinyProtocol;
import io.github.retrooper.packetevents.packettype.PacketType;
import io.github.retrooper.packetevents.packetwrappers.login.in.WrappedPacketLoginHandshake;
import io.github.retrooper.packetevents.utils.player.ClientVersion;
import io.github.retrooper.packetevents.utils.reflection.ClassUtil;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import java.util.HashMap;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
public class PacketManager {
private final Plugin plugin;
private final boolean tinyProtocolMode;
public final TinyProtocol tinyProtocol;
public final NettyPacketManager nettyProtocol;
private final HashMap<UUID, Long> keepAliveMap = new HashMap<>();
public PacketManager(Plugin plugin, boolean tinyProtocolMode) {
this.plugin = plugin;
this.tinyProtocolMode = tinyProtocolMode;
if (tinyProtocolMode) {
tinyProtocol = new TinyProtocol(plugin);
nettyProtocol = null;
} else {
nettyProtocol = new NettyPacketManager(plugin);
tinyProtocol = null;
}
}
public void injectPlayer(Player player) {
if (PacketEvents.getSettings().shouldInjectAsync()) {
injectPlayerAsync(player);
} else {
injectPlayerSync(player);
}
}
public void ejectPlayer(Player player) {
if (PacketEvents.getSettings().shouldEjectAsync()) {
ejectPlayerAsync(player);
} else {
ejectPlayerSync(player);
}
}
public void injectPlayerSync(Player player) {
PlayerInjectEvent injectEvent = new PlayerInjectEvent(player, false);
PacketEvents.getAPI().getEventManager().callEvent(injectEvent);
if (!injectEvent.isCancelled()) {
if (tinyProtocolMode) {
tinyProtocol.injectPlayer(player);
} else {
nettyProtocol.injectPlayer(player);
}
}
}
public void injectPlayerAsync(Player player) {
PlayerInjectEvent injectEvent = new PlayerInjectEvent(player, true);
PacketEvents.getAPI().getEventManager().callEvent(injectEvent);
if (!injectEvent.isCancelled()) {
if (tinyProtocolMode) {
assert tinyProtocol != null;
tinyProtocol.injectPlayerAsync(player);
} else {
assert nettyProtocol != null;
nettyProtocol.injectPlayerAsync(player);
}
}
}
public void ejectPlayerSync(Player player) {
PlayerEjectEvent ejectEvent = new PlayerEjectEvent(player, false);
PacketEvents.getAPI().getEventManager().callEvent(ejectEvent);
if (!ejectEvent.isCancelled()) {
keepAliveMap.remove(player.getUniqueId());
if (tinyProtocolMode) {
tinyProtocol.ejectPlayer(player);
} else {
nettyProtocol.ejectPlayer(player);
}
}
}
public void ejectPlayerAsync(Player player) {
PlayerEjectEvent ejectEvent = new PlayerEjectEvent(player, true);
PacketEvents.getAPI().getEventManager().callEvent(ejectEvent);
if (!ejectEvent.isCancelled()) {
keepAliveMap.remove(player.getUniqueId());
if (tinyProtocolMode) {
tinyProtocol.ejectPlayerAsync(player);
} else {
nettyProtocol.ejectPlayerAsync(player);
}
}
}
public void ejectChannel(Object channel) {
if (!PacketEvents.getSettings().shouldEjectAsync()) {
ejectChannelSync(channel);
} else {
ejectChannelAsync(channel);
}
}
public void ejectChannelSync(Object channel) {
if (tinyProtocolMode) {
tinyProtocol.ejectChannelSync(channel);
} else {
nettyProtocol.ejectChannelSync(channel);
}
}
public void ejectChannelAsync(Object channel) {
if (tinyProtocolMode) {
tinyProtocol.ejectChannelAsync(channel);
} else {
nettyProtocol.ejectChannelAsync(channel);
}
}
public void sendPacket(Object channel, Object packet) {
if (tinyProtocolMode) {
tinyProtocol.sendPacket(channel, packet);
} else {
nettyProtocol.sendPacket(channel, packet);
}
}
public String getNettyHandlerName() {
return "pe-" + plugin.getName();
}
public Object read(Player player, Object channel, Object packet) {
if (player == null) {
String simpleClassName = ClassUtil.getClassSimpleName(packet.getClass());
//Status packet
if (simpleClassName.startsWith("PacketS")) {
final PacketStatusEvent packetStatusEvent = new PacketStatusEvent(channel, packet);
PacketEvents.getAPI().getEventManager().callEvent(packetStatusEvent);
interceptStatus(packetStatusEvent);
if (packetStatusEvent.isCancelled()) {
packet = null;
}
} else {
//Login packet
final PacketLoginEvent packetLoginEvent = new PacketLoginEvent(channel, packet);
PacketEvents.getAPI().getEventManager().callEvent(packetLoginEvent);
interceptLogin(packetLoginEvent);
if (packetLoginEvent.isCancelled()) {
packet = null;
}
}
} else {
final PacketReceiveEvent packetReceiveEvent = new PacketReceiveEvent(player, packet);
PacketEvents.getAPI().getEventManager().callEvent(packetReceiveEvent);
interceptRead(packetReceiveEvent);
if (packetReceiveEvent.isCancelled()) {
packet = null;
}
}
return packet;
}
public Object write(Player player, Object channel, Object packet) {
if (player == null) {
String simpleClassName = ClassUtil.getClassSimpleName(packet.getClass());
//Status packet
if (simpleClassName.startsWith("PacketS")) {
final PacketStatusEvent packetStatusEvent = new PacketStatusEvent(channel, packet);
PacketEvents.getAPI().getEventManager().callEvent(packetStatusEvent);
interceptStatus(packetStatusEvent);
if (packetStatusEvent.isCancelled()) {
packet = null;
}
}
//Login packet
else {
final PacketLoginEvent packetLoginEvent = new PacketLoginEvent(channel, packet);
PacketEvents.getAPI().getEventManager().callEvent(packetLoginEvent);
interceptLogin(packetLoginEvent);
if (packetLoginEvent.isCancelled()) {
packet = null;
}
}
} else {
final PacketSendEvent packetSendEvent = new PacketSendEvent(player, packet);
PacketEvents.getAPI().getEventManager().callEvent(packetSendEvent);
interceptWrite(packetSendEvent);
if (packetSendEvent.isCancelled()) {
packet = null;
}
}
return packet;
}
public void postRead(Player player, Object packet) {
switch (ClassUtil.getClassSimpleName(packet.getClass())) {
case "PacketHandshakingInSetProtocol":
case "PacketLoginInCustomPayload":
case "PacketLoginInStart":
case "PacketLoginInEncryptionBegin":
case "PacketStatusInPing":
break;
default:
PacketEvents.getAPI().getEventManager().callEvent(new PostPacketReceiveEvent(player, packet));
break;
}
}
public void postWrite(Player player, Object packet) {
switch (ClassUtil.getClassSimpleName(packet.getClass())) {
case "PacketLoginOutDisconnect":
case "PacketLoginOutEncryptionBegin":
case "PacketLoginOutSetCompression":
case "PacketLoginOutSuccess":
case "PacketStatusOutPong":
case "PacketStatusOutServerInfo":
break;
default:
PacketEvents.getAPI().getEventManager().callEvent(new PostPacketSendEvent(player, packet));
break;
}
}
private void interceptRead(PacketReceiveEvent event) {
if (event.getPacketId() == PacketType.Client.KEEP_ALIVE) {
UUID uuid = event.getPlayer().getUniqueId();
long timestamp = keepAliveMap.getOrDefault(uuid, event.getTimestamp());
long currentTime = event.getTimestamp();
long ping = currentTime - timestamp;
long smoothedPing = (PacketEvents.getAPI().getPlayerUtils().getSmoothedPing(event.getPlayer()) * 3 + ping) / 4;
PacketEvents.getAPI().getPlayerUtils().playerPingMap.put(uuid, (short) ping);
PacketEvents.getAPI().getPlayerUtils().playerSmoothedPingMap.put(uuid, (short) smoothedPing);
}
}
private void interceptWrite(PacketSendEvent event) {
if (event.getPacketId() == PacketType.Server.KEEP_ALIVE) {
keepAliveMap.put(event.getPlayer().getUniqueId(), event.getTimestamp());
}
}
private void interceptLogin(PacketLoginEvent event) {
if (event.getPacketId() == PacketType.Login.HANDSHAKE
&& PacketEvents.getAPI().getServerUtils().getVersion() != ServerVersion.v_1_7_10
&& !PacketEvents.getAPI().getServerUtils().isBungeeCordEnabled()) {
WrappedPacketLoginHandshake handshake = new WrappedPacketLoginHandshake(event.getNMSPacket());
int protocolVersion = handshake.getProtocolVersion();
ClientVersion version = ClientVersion.getClientVersion(protocolVersion);
PacketEvents.getAPI().getPlayerUtils().clientVersionsMap.put(event.getChannel(), version);
}
}
private void interceptStatus(PacketStatusEvent event) {
}
}

View File

@ -0,0 +1,156 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetmanager.netty;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class NettyPacketManager {
public static final boolean v1_7_nettyMode;
static {
boolean v1_7_nettyMode1;
try {
Class.forName("net.minecraft.util.io.netty.channel.Channel");
v1_7_nettyMode1 = true;
} catch (ClassNotFoundException e) {
v1_7_nettyMode1 = false;
}
v1_7_nettyMode = v1_7_nettyMode1;
}
private final Object npm;
public NettyPacketManager(Plugin plugin) {
if (v1_7_nettyMode) {
npm = new NettyPacketManager_7();
} else {
npm = new NettyPacketManager_8();
}
}
/**
* Synchronously inject a player
*
* @param player Target player to inject
*/
public void injectPlayer(final Player player) {
if (v1_7_nettyMode) {
NettyPacketManager_7 npm_7 = (NettyPacketManager_7) npm;
npm_7.injectPlayer(player);
} else {
NettyPacketManager_8 npm_8 = (NettyPacketManager_8) npm;
npm_8.injectPlayer(player);
}
}
/**
* Asynchronously inject a player
*
* @param player
*/
public void injectPlayerAsync(final Player player) {
//Redundant channel variable created just so we can cache it synchronously.
Object channel = NMSUtils.getChannel(player);
PacketEvents.packetHandlingExecutorService.execute(() -> {
if (v1_7_nettyMode) {
NettyPacketManager_7 npm_7 = (NettyPacketManager_7) npm;
npm_7.injectPlayer(player);
} else {
NettyPacketManager_8 npm_8 = (NettyPacketManager_8) npm;
npm_8.injectPlayer(player);
}
});
}
/**
* Synchronously eject a player.
*
* @param player
*/
public void ejectPlayer(final Player player) {
if (v1_7_nettyMode) {
NettyPacketManager_7 npm_7 = (NettyPacketManager_7) npm;
npm_7.ejectPlayer(player);
} else {
NettyPacketManager_8 npm_8 = (NettyPacketManager_8) npm;
npm_8.ejectPlayer(player);
}
}
/**
* Asynchronously eject a player
*
* @param player
*/
public void ejectPlayerAsync(final Player player) {
PacketEvents.packetHandlingExecutorService.execute(() -> {
if (v1_7_nettyMode) {
NettyPacketManager_7 npm_7 = (NettyPacketManager_7) npm;
npm_7.ejectPlayer(player);
} else {
NettyPacketManager_8 npm_8 = (NettyPacketManager_8) npm;
npm_8.ejectPlayer(player);
}
});
}
public void ejectChannelSync(Object channel) {
if (v1_7_nettyMode) {
NettyPacketManager_7 npm_7 = (NettyPacketManager_7) npm;
npm_7.ejectChannel(channel);
} else {
NettyPacketManager_8 npm_8 = (NettyPacketManager_8) npm;
npm_8.ejectChannel(channel);
}
}
public void ejectChannelAsync(Object channel) {
PacketEvents.packetHandlingExecutorService.execute(() -> {
if (v1_7_nettyMode) {
NettyPacketManager_7 npm_7 = (NettyPacketManager_7) npm;
npm_7.ejectChannel(channel);
} else {
NettyPacketManager_8 npm_8 = (NettyPacketManager_8) npm;
npm_8.ejectChannel(channel);
}
});
}
public void sendPacket(Object channel, Object packet) {
if (v1_7_nettyMode) {
NettyPacketManager_7 npm_7 = (NettyPacketManager_7) npm;
npm_7.sendPacket(channel, packet);
} else {
NettyPacketManager_8 npm_8 = (NettyPacketManager_8) npm;
npm_8.sendPacket(channel, packet);
}
}
}

View File

@ -0,0 +1,85 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetmanager.netty;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import net.minecraft.util.io.netty.channel.Channel;
import net.minecraft.util.io.netty.channel.ChannelDuplexHandler;
import net.minecraft.util.io.netty.channel.ChannelHandlerContext;
import net.minecraft.util.io.netty.channel.ChannelPipeline;
import net.minecraft.util.io.netty.channel.ChannelPromise;
import org.bukkit.entity.Player;
final class NettyPacketManager_7 {
NettyPacketManager_7() {
}
/**
* Inject a player using 1.7.10's netty import location
* @param player
*/
public void injectPlayer(final Player player) {
final ChannelDuplexHandler channelDuplexHandler = new ChannelDuplexHandler() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Object packet = PacketEvents.getAPI().packetManager.read(player, ctx.channel(), msg);
if (packet == null) {
return;
}
super.channelRead(ctx, msg);
PacketEvents.getAPI().packetManager.postRead(player, packet);
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
Object packet = PacketEvents.getAPI().packetManager.write(player, ctx.channel(),msg);
if (packet == null) {
return;
}
super.write(ctx, msg, promise);
PacketEvents.getAPI().packetManager.postWrite(player, packet);
}
};
final ChannelPipeline pipeline = ((Channel) NMSUtils.getChannel(player)).pipeline();
pipeline.addBefore("packet_handler", PacketEvents.getAPI().packetManager.getNettyHandlerName(), channelDuplexHandler);
}
public void ejectPlayer(Player player) {
Channel channel = (Channel) NMSUtils.getChannel(player);
assert channel != null;
ejectChannel(channel);
}
public void ejectChannel(Object ch) {
Channel channel = (Channel) ch;
channel.pipeline().remove(PacketEvents.getAPI().packetManager.getNettyHandlerName());
}
public void sendPacket(Object rawChannel, Object packet) {
Channel channel = (Channel) rawChannel;
channel.pipeline().writeAndFlush(packet);
}
}

View File

@ -0,0 +1,89 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetmanager.netty;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.netty.channel.Channel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import org.bukkit.entity.Player;
final class NettyPacketManager_8 {
NettyPacketManager_8() {
}
/**
* Inject a player with 1.8+ netty import location.
* @param player
*/
public void injectPlayer(final Player player) {
final ChannelDuplexHandler channelDuplexHandler = new ChannelDuplexHandler() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Object packet = PacketEvents.getAPI().packetManager.read(player, ctx.channel(),msg);
if (packet == null) {
return;
}
super.channelRead(ctx, msg);
PacketEvents.getAPI().packetManager.postRead(player, packet);
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
Object packet = PacketEvents.getAPI().packetManager.write(player, ctx.channel(),msg);
if (packet == null) {
return;
}
super.write(ctx, msg, promise);
PacketEvents.getAPI().packetManager.postWrite(player, packet);
}
};
final ChannelPipeline pipeline = ((Channel) NMSUtils.getChannel(player)).pipeline();
pipeline.addBefore("packet_handler", PacketEvents.getAPI().packetManager.getNettyHandlerName(), channelDuplexHandler);
}
/**
* Eject a player with 1.8+ netty import location.
* @param player
*/
public void ejectPlayer(final Player player) {
final Channel channel = (Channel) NMSUtils.getChannel(player);
assert channel != null;
ejectChannel(channel);
}
public void ejectChannel(Object channel) {
Channel ch = (Channel)channel;
ch.pipeline().remove(PacketEvents.getAPI().packetManager.getNettyHandlerName());
}
public void sendPacket(Object rawChannel, Object packet) {
Channel channel = (Channel)rawChannel;
channel.pipeline().writeAndFlush(packet);
}
}

View File

@ -0,0 +1,376 @@
package io.github.retrooper.packetevents.packetmanager.tinyprotocol;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.bukkit.Bukkit;
/**
* An utility class that simplifies reflection in Bukkit plugins.
*
* @author Kristian
*/
public final class Reflection {
/**
* An interface for invoking a specific constructor.
*/
public interface ConstructorInvoker {
/**
* Invoke a constructor for a specific class.
*
* @param arguments - the arguments to pass to the constructor.
* @return The constructed object.
*/
Object invoke(Object... arguments);
}
/**
* An interface for invoking a specific method.
*/
public interface MethodInvoker {
/**
* Invoke a method on a specific target object.
*
* @param target - the target object, or NULL for a static method.
* @param arguments - the arguments to pass to the method.
* @return The return value, or NULL if is void.
*/
Object invoke(Object target, Object... arguments);
}
/**
* An interface for retrieving the field content.
*
* @param <T> - field type.
*/
public interface FieldAccessor<T> {
/**
* Retrieve the content of a field.
*
* @param target - the target object, or NULL for a static field.
* @return The value of the field.
*/
T get(Object target);
/**
* Set the content of a field.
*
* @param target - the target object, or NULL for a static field.
* @param value - the new value of the field.
*/
void set(Object target, Object value);
/**
* Determine if the given object has this field.
*
* @param target - the object to test.
* @return TRUE if it does, FALSE otherwise.
*/
boolean hasField(Object target);
}
// Deduce the net.minecraft.server.v* package
private static String OBC_PREFIX = Bukkit.getServer().getClass().getPackage().getName();
private static String NMS_PREFIX = OBC_PREFIX.replace("org.bukkit.craftbukkit", "net.minecraft.server");
private static String VERSION = OBC_PREFIX.replace("org.bukkit.craftbukkit", "").replace(".", "");
// Variable replacement
private static Pattern MATCH_VARIABLE = Pattern.compile("\\{([^\\}]+)\\}");
private Reflection() {
// Seal class
}
/**
* Retrieve a field accessor for a specific field type and name.
*
* @param target - the target type.
* @param name - the name of the field, or NULL to ignore.
* @param fieldType - a compatible field type.
* @return The field accessor.
*/
public static <T> FieldAccessor<T> getField(Class<?> target, String name, Class<T> fieldType) {
return getField(target, name, fieldType, 0);
}
/**
* Retrieve a field accessor for a specific field type and name.
*
* @param className - lookup name of the class, see {@link #getClass(String)}.
* @param name - the name of the field, or NULL to ignore.
* @param fieldType - a compatible field type.
* @return The field accessor.
*/
public static <T> FieldAccessor<T> getField(String className, String name, Class<T> fieldType) {
return getField(getClass(className), name, fieldType, 0);
}
/**
* Retrieve a field accessor for a specific field type and name.
*
* @param target - the target type.
* @param fieldType - a compatible field type.
* @param index - the number of compatible fields to skip.
* @return The field accessor.
*/
public static <T> FieldAccessor<T> getField(Class<?> target, Class<T> fieldType, int index) {
return getField(target, null, fieldType, index);
}
/**
* Retrieve a field accessor for a specific field type and name.
*
* @param className - lookup name of the class, see {@link #getClass(String)}.
* @param fieldType - a compatible field type.
* @param index - the number of compatible fields to skip.
* @return The field accessor.
*/
public static <T> FieldAccessor<T> getField(String className, Class<T> fieldType, int index) {
return getField(getClass(className), fieldType, index);
}
// Common method
private static <T> FieldAccessor<T> getField(Class<?> target, String name, Class<T> fieldType, int index) {
for (final Field field : target.getDeclaredFields()) {
if ((name == null || field.getName().equals(name)) && fieldType.isAssignableFrom(field.getType()) && index-- <= 0) {
field.setAccessible(true);
// A function for retrieving a specific field value
return new FieldAccessor<T>() {
@Override
@SuppressWarnings("unchecked")
public T get(Object target) {
try {
return (T) field.get(target);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot access reflection.", e);
}
}
@Override
public void set(Object target, Object value) {
try {
field.set(target, value);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot access reflection.", e);
}
}
@Override
public boolean hasField(Object target) {
// target instanceof DeclaringClass
return field.getDeclaringClass().isAssignableFrom(target.getClass());
}
};
}
}
// Search in parent classes
if (target.getSuperclass() != null)
return getField(target.getSuperclass(), name, fieldType, index);
throw new IllegalArgumentException("Cannot find field with type " + fieldType);
}
/**
* Search for the first publicly and privately defined method of the given name and parameter count.
*
* @param className - lookup name of the class, see {@link #getClass(String)}.
* @param methodName - the method name, or NULL to skip.
* @param params - the expected parameters.
* @return An object that invokes this specific method.
* @throws IllegalStateException If we cannot find this method.
*/
public static MethodInvoker getMethod(String className, String methodName, Class<?>... params) {
return getTypedMethod(getClass(className), methodName, null, params);
}
/**
* Search for the first publicly and privately defined method of the given name and parameter count.
*
* @param clazz - a class to start with.
* @param methodName - the method name, or NULL to skip.
* @param params - the expected parameters.
* @return An object that invokes this specific method.
* @throws IllegalStateException If we cannot find this method.
*/
public static MethodInvoker getMethod(Class<?> clazz, String methodName, Class<?>... params) {
return getTypedMethod(clazz, methodName, null, params);
}
/**
* Search for the first publicly and privately defined method of the given name and parameter count.
*
* @param clazz - a class to start with.
* @param methodName - the method name, or NULL to skip.
* @param returnType - the expected return type, or NULL to ignore.
* @param params - the expected parameters.
* @return An object that invokes this specific method.
* @throws IllegalStateException If we cannot find this method.
*/
public static MethodInvoker getTypedMethod(Class<?> clazz, String methodName, Class<?> returnType, Class<?>... params) {
for (final Method method : clazz.getDeclaredMethods()) {
if ((methodName == null || method.getName().equals(methodName))
&& (returnType == null || method.getReturnType().equals(returnType))
&& Arrays.equals(method.getParameterTypes(), params)) {
method.setAccessible(true);
return new MethodInvoker() {
@Override
public Object invoke(Object target, Object... arguments) {
try {
return method.invoke(target, arguments);
} catch (Exception e) {
throw new RuntimeException("Cannot invoke method " + method, e);
}
}
};
}
}
// Search in every superclass
if (clazz.getSuperclass() != null)
return getMethod(clazz.getSuperclass(), methodName, params);
throw new IllegalStateException(String.format("Unable to find method %s (%s).", methodName, Arrays.asList(params)));
}
/**
* Search for the first publically and privately defined constructor of the given name and parameter count.
*
* @param className - lookup name of the class, see {@link #getClass(String)}.
* @param params - the expected parameters.
* @return An object that invokes this constructor.
* @throws IllegalStateException If we cannot find this method.
*/
public static ConstructorInvoker getConstructor(String className, Class<?>... params) {
return getConstructor(getClass(className), params);
}
/**
* Search for the first publically and privately defined constructor of the given name and parameter count.
*
* @param clazz - a class to start with.
* @param params - the expected parameters.
* @return An object that invokes this constructor.
* @throws IllegalStateException If we cannot find this method.
*/
public static ConstructorInvoker getConstructor(Class<?> clazz, Class<?>... params) {
for (final Constructor<?> constructor : clazz.getDeclaredConstructors()) {
if (Arrays.equals(constructor.getParameterTypes(), params)) {
constructor.setAccessible(true);
return new ConstructorInvoker() {
@Override
public Object invoke(Object... arguments) {
try {
return constructor.newInstance(arguments);
} catch (Exception e) {
throw new RuntimeException("Cannot invoke constructor " + constructor, e);
}
}
};
}
}
throw new IllegalStateException(String.format("Unable to find constructor for %s (%s).", clazz, Arrays.asList(params)));
}
/**
* Retrieve a class from its full name, without knowing its type on compile time.
* <p>
* This is useful when looking up fields by a NMS or OBC type.
* <p>
*
* See {@link #getClass()} for more information.
* @param lookupName - the class name with variables.
* @return The class.
*/
public static Class<Object> getUntypedClass(String lookupName) {
@SuppressWarnings({ "rawtypes", "unchecked" })
Class<Object> clazz = (Class) getClass(lookupName);
return clazz;
}
public static Class<?> getClass(String lookupName) {
return getCanonicalClass(expandVariables(lookupName));
}
/**
* Retrieve a class in the net.minecraft.server.VERSION.* package.
*
* @param name - the name of the class, excluding the package.
* @throws IllegalArgumentException If the class doesn't exist.
*/
public static Class<?> getMinecraftClass(String name) {
return getCanonicalClass(NMS_PREFIX + "." + name);
}
/**
* Retrieve a class in the org.bukkit.craftbukkit.VERSION.* package.
*
* @param name - the name of the class, excluding the package.
* @throws IllegalArgumentException If the class doesn't exist.
*/
public static Class<?> getCraftBukkitClass(String name) {
return getCanonicalClass(OBC_PREFIX + "." + name);
}
/**
* Retrieve a class by its canonical name.
*
* @param canonicalName - the canonical name.
* @return The class.
*/
private static Class<?> getCanonicalClass(String canonicalName) {
try {
return Class.forName(canonicalName);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("Cannot find " + canonicalName, e);
}
}
/**
* Expand variables such as "{nms}" and "{obc}" to their corresponding packages.
*
* @param name - the full name of the class.
* @return The expanded string.
*/
private static String expandVariables(String name) {
StringBuffer output = new StringBuffer();
Matcher matcher = MATCH_VARIABLE.matcher(name);
while (matcher.find()) {
String variable = matcher.group(1);
String replacement = "";
// Expand all detected variables
if ("nms".equalsIgnoreCase(variable))
replacement = NMS_PREFIX;
else if ("obc".equalsIgnoreCase(variable))
replacement = OBC_PREFIX;
else if ("version".equalsIgnoreCase(variable))
replacement = VERSION;
else
throw new IllegalArgumentException("Unknown variable: " + variable);
// Assume the expanded variables are all packages, and append a dot
if (replacement.length() > 0 && matcher.end() < name.length() && name.charAt(matcher.end()) != '.')
replacement += ".";
matcher.appendReplacement(output, Matcher.quoteReplacement(replacement));
}
matcher.appendTail(output);
return output.toString();
}
}

View File

@ -0,0 +1,135 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetmanager.tinyprotocol;
import io.github.retrooper.packetevents.packetmanager.netty.NettyPacketManager;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
public class TinyProtocol {
private final Object tinyProt;
public TinyProtocol(Plugin plugin) {
if (NettyPacketManager.v1_7_nettyMode) {
tinyProt = new TinyProtocol7(plugin);
} else {
tinyProt = new TinyProtocol8(plugin);
}
}
public void injectPlayer(Player player) {
if (!NettyPacketManager.v1_7_nettyMode) {
TinyProtocol8 tp8 = (TinyProtocol8) tinyProt;
tp8.injectPlayer(player);
} else {
TinyProtocol7 tp7 = (TinyProtocol7) tinyProt;
tp7.injectPlayer(player);
}
}
public void injectPlayerAsync(Player player) {
if (!NettyPacketManager.v1_7_nettyMode) {
TinyProtocol8 tp8 = (TinyProtocol8) tinyProt;
tp8.injectPlayerAsync(player);
} else {
TinyProtocol7 tp7 = (TinyProtocol7) tinyProt;
tp7.injectPlayerAsync(player);
}
}
public void ejectPlayer(Player player) {
if (!NettyPacketManager.v1_7_nettyMode) {
TinyProtocol8 tp8 = (TinyProtocol8) tinyProt;
tp8.uninjectPlayer(player);
} else {
TinyProtocol7 tp7 = (TinyProtocol7) tinyProt;
tp7.uninjectPlayer(player);
}
}
public void ejectPlayerAsync(Player player) {
if (!NettyPacketManager.v1_7_nettyMode) {
TinyProtocol8 tp8 = (TinyProtocol8) tinyProt;
tp8.uninjectPlayerAsync(player);
} else {
TinyProtocol7 tp7 = (TinyProtocol7) tinyProt;
tp7.uninjectPlayerAsync(player);
}
}
public void ejectChannelSync(Object channel) {
if (!NettyPacketManager.v1_7_nettyMode) {
TinyProtocol8 tp8 = (TinyProtocol8) tinyProt;
tp8.ejectChannelSync(channel);
} else {
TinyProtocol7 tp7 = (TinyProtocol7) tinyProt;
tp7.ejectChannelSync(channel);
}
}
public void ejectChannelAsync(Object channel) {
if (!NettyPacketManager.v1_7_nettyMode) {
TinyProtocol8 tp8 = (TinyProtocol8) tinyProt;
tp8.ejectChannelAsync(channel);
} else {
TinyProtocol7 tp7 = (TinyProtocol7) tinyProt;
tp7.ejectChannelAsync(channel);
}
}
public void sendPacket(Object channel, Object packet) {
if (!NettyPacketManager.v1_7_nettyMode) {
TinyProtocol8 tp8 = (TinyProtocol8) tinyProt;
tp8.sendPacket(channel, packet);
} else {
TinyProtocol7 tp7 = (TinyProtocol7) tinyProt;
tp7.sendPacket(channel, packet);
}
}
public Object getChannel(Player player) {
if (NettyPacketManager.v1_7_nettyMode) {
TinyProtocol7 tp7 = (TinyProtocol7) tinyProt;
return tp7.getChannel(player);
} else {
TinyProtocol8 tp8 = (TinyProtocol8) tinyProt;
return tp8.getChannel(player);
}
}
public void unregisterChannelHandler() {
}
public void handleQueuedKicks() {
if (NettyPacketManager.v1_7_nettyMode) {
TinyProtocol7 tp7 = (TinyProtocol7) tinyProt;
tp7.handleQueuedKicks();
} else {
TinyProtocol8 tp8 = (TinyProtocol8) tinyProt;
tp8.handleQueuedKicks();
}
}
}

View File

@ -0,0 +1,514 @@
package io.github.retrooper.packetevents.packetmanager.tinyprotocol;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.packetmanager.tinyprotocol.Reflection.FieldAccessor;
import io.github.retrooper.packetevents.packetmanager.tinyprotocol.Reflection.MethodInvoker;
import io.github.retrooper.packetevents.packetwrappers.out.kickdisconnect.WrappedPacketOutKickDisconnect;
import net.minecraft.util.com.google.common.collect.Lists;
import net.minecraft.util.com.google.common.collect.MapMaker;
import net.minecraft.util.com.mojang.authlib.GameProfile;
import net.minecraft.util.io.netty.channel.*;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
/**
* Represents a very tiny alternative to ProtocolLib.
* <p>
* It now supports intercepting packets during login and status ping (such as OUT_SERVER_PING)!
*
* @author Kristian
*/
//BROKEN: NPEs when player joins while server is starting, and using PlayerJoinEvent instead will cause NPE for protocol version lookup.
//Protocol version number lookup method from DeprecatedLuke's version of TinyProtocol
public class TinyProtocol7 {
private static final AtomicInteger ID = new AtomicInteger();
// Used in order to lookup a channel
private static final MethodInvoker getPlayerHandle = Reflection.getMethod("{obc}.entity.CraftPlayer", "getHandle");
private static final FieldAccessor<Object> getConnection = Reflection.getField("{nms}.EntityPlayer", "playerConnection", Object.class);
private static final FieldAccessor<Object> getManager = Reflection.getField("{nms}.PlayerConnection", "networkManager", Object.class);
private static final FieldAccessor<Channel> getChannel = Reflection.getField("{nms}.NetworkManager", Channel.class, 0);
// Looking up ServerConnection
private static final Class<Object> minecraftServerClass = Reflection.getUntypedClass("{nms}.MinecraftServer");
private static final Class<Object> serverConnectionClass = Reflection.getUntypedClass("{nms}.ServerConnection");
private static final FieldAccessor<Object> getMinecraftServer = Reflection.getField("{obc}.CraftServer", minecraftServerClass, 0);
private static final FieldAccessor<Object> getServerConnection = Reflection.getField(minecraftServerClass, serverConnectionClass, 0);
private static final MethodInvoker getNetworkMarkers = Reflection.getTypedMethod(serverConnectionClass, null, List.class, serverConnectionClass);
// Packets we have to intercept
private static final Class<?> PACKET_LOGIN_IN_START = Reflection.getMinecraftClass("PacketLoginInStart");
private static final Class<?> PACKET_HANDSHAKING_IN_SET_PROTOCOL = Reflection.getMinecraftClass("PacketHandshakingInSetProtocol");
private static final FieldAccessor<GameProfile> getGameProfile = Reflection.getField(PACKET_LOGIN_IN_START, GameProfile.class, 0);
// Speedup channel/protocol lookup
private final Map<String, Channel> channelLookup = new MapMaker().weakValues().makeMap();
// List of network markers
private List<Object> networkManagers;
// Injected channel handlers
private final List<Channel> serverChannels = Lists.newArrayList();
private ChannelInboundHandlerAdapter serverChannelHandler;
private ChannelInitializer<Channel> beginInitProtocol;
private ChannelInitializer<Channel> endInitProtocol;
public final ConcurrentLinkedQueue<Channel> queueingChannelKicks = new ConcurrentLinkedQueue<>();
// Current handler name
private final String handlerName;
protected volatile boolean closed;
protected Plugin plugin;
/**
* Construct a new instance of TinyProtocol, and start intercepting packets for all connected clients and future clients.
* <p>
* You can construct multiple instances per plugin.
*
* @param plugin - the plugin.
*/
public TinyProtocol7(final Plugin plugin) {
this.plugin = plugin;
// Compute handler name
this.handlerName = getHandlerName();
try {
registerChannelHandler();
registerPlayers(plugin);
} catch (IllegalArgumentException ex) {
// Damn you, late bind
plugin.getLogger().info("Delaying server channel injection due to late bind.");
new BukkitRunnable() {
@Override
public void run() {
registerChannelHandler();
registerPlayers(plugin);
plugin.getLogger().info("Late bind injection successful.");
}
}.runTask(plugin);
}
}
private void createServerChannelHandler() {
// Handle connected channels
endInitProtocol = new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel channel) throws Exception {
try {
// This can take a while, so we need to stop the main thread from interfering
synchronized (networkManagers) {
// Stop injecting channels
if (!closed) {
channel.eventLoop().submit(() -> injectChannelInternal(channel));
}
}
} catch (Exception e) {
plugin.getLogger().log(Level.SEVERE, "Cannot inject incomming channel " + channel, e);
}
}
};
// This is executed before Minecraft's channel handler
beginInitProtocol = new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel channel) throws Exception {
channel.pipeline().addLast(endInitProtocol);
}
};
serverChannelHandler = new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Channel channel = (Channel) msg;
// Prepare to initialize ths channel
channel.pipeline().addFirst(beginInitProtocol);
ctx.fireChannelRead(msg);
}
};
}
@SuppressWarnings("unchecked")
private void registerChannelHandler() {
Object mcServer = getMinecraftServer.get(Bukkit.getServer());
Object serverConnection = getServerConnection.get(mcServer);
boolean looking = true;
// We need to synchronize against this list
networkManagers = (List<Object>) getNetworkMarkers.invoke(null, serverConnection);
createServerChannelHandler();
// Find the correct list, or implicitly throw an exception
for (int i = 0; looking; i++) {
List<Object> list = Reflection.getField(serverConnection.getClass(), List.class, i).get(serverConnection);
for (Object item : list) {
if (!(item instanceof ChannelFuture))
break;
// Channel future that contains the server connection
Channel serverChannel = ((ChannelFuture) item).channel();
serverChannels.add(serverChannel);
serverChannel.pipeline().addFirst(serverChannelHandler);
looking = false;
}
}
}
private void unregisterChannelHandler() {
if (serverChannelHandler == null)
return;
for (Channel serverChannel : serverChannels) {
final ChannelPipeline pipeline = serverChannel.pipeline();
// Remove channel handler
serverChannel.eventLoop().execute(new Runnable() {
@Override
public void run() {
try {
pipeline.remove(serverChannelHandler);
} catch (NoSuchElementException e) {
// That's fine
}
}
});
}
}
public void handleQueuedKicks() {
for (Channel channel : queueingChannelKicks) {
Object packet = new WrappedPacketOutKickDisconnect("We failed to inject you. Please try rejoining!").asNMSPacket();
sendPacket(channel, packet);
}
}
private void registerPlayers(Plugin plugin) {
for (Player player : plugin.getServer().getOnlinePlayers()) {
injectPlayer(player);
}
}
/**
* Invoked when the server is starting to send a packet to a player.
* <p>
* Note that this is not executed on the main thread.
*
* @param receiver - the receiving player, NULL for early login/status packets.
* @param channel - the channel that received the packet. Never NULL.
* @param packet - the packet being sent.
* @return The packet to send instead, or NULL to cancel the transmission.
*/
public Object onPacketOutAsync(Player receiver, Channel channel, Object packet) {
return PacketEvents.getAPI().packetManager.write(receiver, channel, packet);
}
/**
* Invoked when the server has received a packet from a given player.
* <p>
* Use {@link Channel#remoteAddress()} to get the remote address of the client.
*
* @param sender - the player that sent the packet, NULL for early login/status packets.
* @param channel - channel that received the packet. Never NULL.
* @param packet - the packet being received.
* @return The packet to recieve instead, or NULL to cancel.
*/
public Object onPacketInAsync(Player sender, Channel channel, Object packet) {
return PacketEvents.getAPI().packetManager.read(sender, channel, packet);
}
/**
* Send a packet to a particular player.
* <p>
* Note that {@link #onPacketOutAsync(Player, Channel, Object)} will be invoked with this packet.
*
* @param player - the destination player.
* @param packet - the packet to send.
*/
public void sendPacket(Player player, Object packet) {
sendPacket(getChannel(player), packet);
}
/**
* Send a packet to a particular client.
* <p>
* Note that {@link #onPacketOutAsync(Player, Channel, Object)} will be invoked with this packet.
*
* @param channel - client identified by a channel.
* @param packet - the packet to send.
*/
public void sendPacket(Channel channel, Object packet) {
channel.pipeline().writeAndFlush(packet);
}
public void sendPacket(Object channel, Object packet) {
sendPacket((Channel) channel, packet);
}
/**
* Pretend that a given packet has been received from a player.
* <p>
* Note that {@link #onPacketInAsync(Player, Channel, Object)} will be invoked with this packet.
*
* @param player - the player that sent the packet.
* @param packet - the packet that will be received by the server.
*/
public void receivePacket(Player player, Object packet) {
receivePacket(getChannel(player), packet);
}
/**
* Pretend that a given packet has been received from a given client.
* <p>
* Note that {@link #onPacketInAsync(Player, Channel, Object)} will be invoked with this packet.
*
* @param channel - client identified by a channel.
* @param packet - the packet that will be received by the server.
*/
public void receivePacket(Channel channel, Object packet) {
channel.pipeline().context("encoder").fireChannelRead(packet);
}
/**
* Retrieve the name of the channel injector, default implementation is "tiny-" + plugin name + "-" + a unique ID.
* <p>
* Note that this method will only be invoked once. It is no longer necessary to override this to support multiple instances.
*
* @return A unique channel handler name.
*/
protected String getHandlerName() {
return "PacketEvents-" + ID.incrementAndGet();
}
/**
* Add a custom channel handler to the given player's channel pipeline, allowing us to intercept sent and received packets.
* <p>
* This will automatically be called when a player has logged in.
*
* @param player - the player to inject.
*/
public void injectPlayer(Player player) {
injectChannelInternal(getChannel(player)).player = player;
}
public void injectPlayerAsync(Player player) {
Channel channel = getChannel(player);
injectChannelInternalAsync(channel).player = player;
}
/**
* Add a custom channel handler to the given channel.
*
* @param channel - the channel to inject.
*/
public void injectChannel(Channel channel) {
injectChannelInternal(channel);
}
public void injectChannelAsync(Channel channel) {
injectChannelInternalAsync(channel);
}
/**
* Add a custom channel handler to the given channel.
*
* @param channel - the channel to inject.
* @return The packet interceptor.
*/
private PacketInterceptor injectChannelInternal(Channel channel) {
try {
PacketInterceptor interceptor = (PacketInterceptor) channel.pipeline().get(handlerName);
// Inject our packet interceptor
if (interceptor == null) {
interceptor = new PacketInterceptor();
channel.pipeline().addBefore("packet_handler", handlerName, interceptor);
}
return interceptor;
} catch (IllegalArgumentException e) {
// Try again
return (PacketInterceptor) channel.pipeline().get(handlerName);
}
}
private PacketInterceptor injectChannelInternalAsync(Channel channel) {
try {
PacketInterceptor interceptor = (PacketInterceptor) channel.pipeline().get(handlerName);
// Inject our packet interceptor
if (interceptor == null) {
interceptor = new PacketInterceptor();
final PacketInterceptor pi = interceptor;
PacketEvents.packetHandlingExecutorService.execute(new Runnable() {
@Override
public void run() {
try {
channel.pipeline().addBefore("packet_handler", handlerName, pi);
} catch (Exception ex) {
//kick them
Object packet = new WrappedPacketOutKickDisconnect("We unfortunately failed to inject you. Please try rejoining!").asNMSPacket();
sendPacket(channel, packet);
}
}
});
}
return interceptor;
} catch (IllegalArgumentException e) {
// Try again
return (PacketInterceptor) channel.pipeline().get(handlerName);
}
}
/**
* Retrieve the Netty channel associated with a player. This is cached.
*
* @param player - the player.
* @return The Netty channel.
*/
public Channel getChannel(Player player) {
Channel channel = channelLookup.get(player.getName());
// Lookup channel again
if (channel == null) {
Object connection = getConnection.get(getPlayerHandle.invoke(player));
Object manager = getManager.get(connection);
channelLookup.put(player.getName(), channel = getChannel.get(manager));
}
return channel;
}
/**
* Uninject a specific player.
*
* @param player - the injected player.
*/
public void uninjectPlayer(Player player) {
uninjectChannel(getChannel(player));
}
public void uninjectPlayerAsync(Player player) {
Channel channel = getChannel(player);
uninjectChannelAsync(channel);
}
public void ejectChannelSync(Object ch) {
uninjectChannel((Channel) ch);
}
public void ejectChannelAsync(Object ch) {
uninjectChannelAsync((Channel) ch);
}
/**
* Uninject a specific channel.
* <p>
* This will also disable the automatic channel injection that occurs when a player has properly logged in.
*
* @param channel - the injected channel.
*/
public void uninjectChannel(final Channel channel) {
// See ChannelInjector in ProtocolLib, line 590
channel.pipeline().remove(handlerName);
}
public void uninjectChannelAsync(Channel channel) {
// See ChannelInjector in ProtocolLib, line 590
PacketEvents.packetHandlingExecutorService.execute(new Runnable() {
@Override
public void run() {
channel.pipeline().remove(handlerName);
}
});
}
/**
* Determine if the given player has been injected by TinyProtocol.
*
* @param player - the player.
* @return TRUE if it is, FALSE otherwise.
*/
public boolean hasInjected(Player player) {
return hasInjected(getChannel(player));
}
/**
* Determine if the given channel has been injected by TinyProtocol.
*
* @param channel - the channel.
* @return TRUE if it is, FALSE otherwise.
*/
public boolean hasInjected(Channel channel) {
return channel.pipeline().get(handlerName) != null;
}
/**
* Cease listening for packets. This is called automatically when your plugin is disabled.
*/
/**
* Channel handler that is inserted into the player's channel pipeline, allowing us to intercept sent and received packets.
*
* @author Kristian
*/
private final class PacketInterceptor extends ChannelDuplexHandler {
// Updated by the login event
public volatile Player player;
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// Intercept channel
final Channel channel = ctx.channel();
handleLoginStart(channel, msg);
msg = onPacketInAsync(player, channel, msg);
if (msg != null) {
super.channelRead(ctx, msg);
PacketEvents.getAPI().packetManager.postRead(player, msg);
}
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
msg = onPacketOutAsync(player, ctx.channel(), msg);
if (msg != null) {
super.write(ctx, msg, promise);
PacketEvents.getAPI().packetManager.postWrite(player, msg);
}
}
private void handleLoginStart(Channel channel, Object packet) {
if (PACKET_LOGIN_IN_START.isInstance(packet)) {
GameProfile profile = getGameProfile.get(packet);
channelLookup.put(profile.getName(), channel);
}
}
}
}

View File

@ -0,0 +1,547 @@
package io.github.retrooper.packetevents.packetmanager.tinyprotocol;
import com.google.common.collect.Lists;
import com.google.common.collect.MapMaker;
import com.mojang.authlib.GameProfile;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.packetmanager.tinyprotocol.Reflection.FieldAccessor;
import io.github.retrooper.packetevents.packetmanager.tinyprotocol.Reflection.MethodInvoker;
import io.github.retrooper.packetevents.packetwrappers.out.kickdisconnect.WrappedPacketOutKickDisconnect;
import io.netty.channel.*;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
/**
* Represents a very tiny alternative to ProtocolLib.
* <p>
* It now supports intercepting packets during login and status ping (such as OUT_SERVER_PING)!
*
* @author Kristian
*/
//BROKEN: NPEs when player joins while server is starting, and using PlayerJoinEvent instead will cause NPE for protocol version lookup.
//Protocol version number lookup method from DeprecatedLuke's version of TinyProtocol
public class TinyProtocol8 {
private static final AtomicInteger ID = new AtomicInteger();
// Used in order to lookup a channel
private static final MethodInvoker getPlayerHandle = Reflection.getMethod("{obc}.entity.CraftPlayer", "getHandle");
private static final FieldAccessor<Object> getConnection = Reflection.getField("{nms}.EntityPlayer", "playerConnection", Object.class);
private static final FieldAccessor<Object> getManager = Reflection.getField("{nms}.PlayerConnection", "networkManager", Object.class);
private static final FieldAccessor<Channel> getChannel = Reflection.getField("{nms}.NetworkManager", Channel.class, 0);
// Looking up ServerConnection
private static final Class<Object> minecraftServerClass = Reflection.getUntypedClass("{nms}.MinecraftServer");
private static final Class<Object> serverConnectionClass = Reflection.getUntypedClass("{nms}.ServerConnection");
private static final FieldAccessor<Object> getMinecraftServer = Reflection.getField("{obc}.CraftServer", minecraftServerClass, 0);
private static final FieldAccessor<Object> getServerConnection = Reflection.getField(minecraftServerClass, serverConnectionClass, 0);
private static final MethodInvoker getNetworkMarkers;
// Packets we have to intercept
private static final Class<?> PACKET_LOGIN_IN_START = Reflection.getMinecraftClass("PacketLoginInStart");
private static final FieldAccessor<GameProfile> getGameProfile = Reflection.getField(PACKET_LOGIN_IN_START, GameProfile.class, 0);
static {
MethodInvoker tempNetworkMarkers;
try {
tempNetworkMarkers = Reflection.getTypedMethod(serverConnectionClass, null, List.class, serverConnectionClass);
} catch (Exception ex) {
tempNetworkMarkers = null;
}
getNetworkMarkers = tempNetworkMarkers;
}
// Speedup channel/protocol lookup
private final Map<String, Channel> channelLookup = new MapMaker().weakValues().makeMap();
// List of network markers
private List<Object> networkManagers;
// Injected channel handlers
private final List<Channel> serverChannels = Lists.newArrayList();
private ChannelInboundHandlerAdapter serverChannelHandler;
private ChannelInitializer<Channel> beginInitProtocol;
private ChannelInitializer<Channel> endInitProtocol;
public final ConcurrentLinkedQueue<Channel> queueingChannelKicks = new ConcurrentLinkedQueue<>();
// Current handler name
private final String handlerName;
protected volatile boolean closed;
protected Plugin plugin;
/**
* Construct a new instance of TinyProtocol, and start intercepting packets for all connected clients and future clients.
* <p>
* You can construct multiple instances per plugin.
*
* @param plugin - the plugin.
*/
public TinyProtocol8(final Plugin plugin) {
this.plugin = plugin;
// Compute handler name
this.handlerName = getHandlerName();
try {
registerChannelHandler();
registerPlayers(plugin);
} catch (IllegalArgumentException ex) {
// Damn you, late bind
plugin.getLogger().info("Delaying server channel injection due to late bind.");
new BukkitRunnable() {
@Override
public void run() {
registerChannelHandler();
registerPlayers(plugin);
plugin.getLogger().info("Late bind injection successful.");
}
}.runTask(plugin);
}
}
private void createServerChannelHandler() {
// Handle connected channels
endInitProtocol = new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel channel) throws Exception {
try {
// This can take a while, so we need to stop the main thread from interfering
synchronized (networkManagers) {
// Stop injecting channels
if (!closed) {
channel.eventLoop().submit(() -> injectChannelInternal(channel));
}
}
} catch (Exception e) {
plugin.getLogger().log(Level.SEVERE, "Cannot inject incoming channel " + channel, e);
}
}
};
// This is executed before Minecraft's channel handler
beginInitProtocol = new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel channel) throws Exception {
channel.pipeline().addLast(endInitProtocol);
}
};
serverChannelHandler = new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Channel channel = (Channel) msg;
// Prepare to initialize ths channel
channel.pipeline().addFirst(beginInitProtocol);
ctx.fireChannelRead(msg);
}
};
}
/**
* Register bukkit events.
*/
@SuppressWarnings("unchecked")
private void registerChannelHandler() {
Object mcServer = getMinecraftServer.get(Bukkit.getServer());
Object serverConnection = getServerConnection.get(mcServer);
boolean looking = true;
// We need to synchronize against this list
if (getNetworkMarkers != null) {
networkManagers = (List<Object>) getNetworkMarkers.invoke(null, serverConnection);
} else {
networkManagers = new ArrayList<>();
}
createServerChannelHandler();
// Find the correct list, or implicitly throw an exception
for (int i = 0; looking; i++) {
List<Object> list = Reflection.getField(serverConnection.getClass(), List.class, i).get(serverConnection);
for (Object item : list) {
if (!(item instanceof ChannelFuture))
break;
// Channel future that contains the server connection
Channel serverChannel = ((ChannelFuture) item).channel();
serverChannels.add(serverChannel);
serverChannel.pipeline().addFirst(serverChannelHandler);
looking = false;
}
}
}
private void unregisterChannelHandler() {
if (serverChannelHandler == null)
return;
for (Channel serverChannel : serverChannels) {
final ChannelPipeline pipeline = serverChannel.pipeline();
// Remove channel handler
serverChannel.eventLoop().execute(new Runnable() {
@Override
public void run() {
try {
pipeline.remove(serverChannelHandler);
} catch (NoSuchElementException e) {
// That's fine
}
}
});
}
}
private void registerPlayers(Plugin plugin) {
for (Player player : plugin.getServer().getOnlinePlayers()) {
injectPlayer(player);
}
}
/**
* Invoked when the server is starting to send a packet to a player.
* <p>
* Note that this is not executed on the main thread.
*
* @param receiver - the receiving player, NULL for early login/status packets.
* @param channel - the channel that received the packet. Never NULL.
* @param packet - the packet being sent.
* @return The packet to send instead, or NULL to cancel the transmission.
*/
public Object onPacketOutAsync(Player receiver, Channel channel, Object packet) {
return PacketEvents.getAPI().packetManager.write(receiver, channel, packet);
}
/**
* Invoked when the server has received a packet from a given player.
* <p>
* Use {@link Channel#remoteAddress()} to get the remote address of the client.
*
* @param sender - the player that sent the packet, NULL for early login/status packets.
* @param channel - channel that received the packet. Never NULL.
* @param packet - the packet being received.
* @return The packet to recieve instead, or NULL to cancel.
*/
public Object onPacketInAsync(Player sender, Channel channel, Object packet) {
return PacketEvents.getAPI().packetManager.read(sender, channel, packet);
}
/**
* Send a packet to a particular player.
* <p>
* Note that {@link #onPacketOutAsync(Player, Channel, Object)} will be invoked with this packet.
*
* @param player - the destination player.
* @param packet - the packet to send.
*/
public void sendPacket(Player player, Object packet) {
sendPacket(getChannel(player), packet);
}
/**
* Send a packet to a particular client.
* <p>
* Note that {@link #onPacketOutAsync(Player, Channel, Object)} will be invoked with this packet.
*
* @param channel - client identified by a channel.
* @param packet - the packet to send.
*/
public void sendPacket(Channel channel, Object packet) {
channel.pipeline().writeAndFlush(packet);
}
public void sendPacket(Object channel, Object packet) {
sendPacket((Channel) channel, packet);
}
/**
* Pretend that a given packet has been received from a player.
* <p>
* Note that {@link #onPacketInAsync(Player, Channel, Object)} will be invoked with this packet.
*
* @param player - the player that sent the packet.
* @param packet - the packet that will be received by the server.
*/
public void receivePacket(Player player, Object packet) {
receivePacket(getChannel(player), packet);
}
/**
* Pretend that a given packet has been received from a given client.
* <p>
* Note that {@link #onPacketInAsync(Player, Channel, Object)} will be invoked with this packet.
*
* @param channel - client identified by a channel.
* @param packet - the packet that will be received by the server.
*/
public void receivePacket(Channel channel, Object packet) {
channel.pipeline().context("encoder").fireChannelRead(packet);
}
/**
* Retrieve the name of the channel injector, default implementation is "tiny-" + plugin name + "-" + a unique ID.
* <p>
* Note that this method will only be invoked once. It is no longer necessary to override this to support multiple instances.
*
* @return A unique channel handler name.
*/
protected String getHandlerName() {
return "PacketEvents-" + ID.incrementAndGet();
}
/**
* Add a custom channel handler to the given player's channel pipeline, allowing us to intercept sent and received packets.
* <p>
* This will automatically be called when a player has logged in.
*
* @param player - the player to inject.
*/
public void injectPlayer(Player player) {
injectChannelInternal(getChannel(player)).player = player;
}
public void injectPlayerAsync(Player player) {
Channel channel = getChannel(player);
injectChannelInternalAsync(channel).player = player;
}
/**
* Add a custom channel handler to the given channel.
*
* @param channel - the channel to inject.
*/
public void injectChannel(Channel channel) {
injectChannelInternal(channel);
}
public void injectChannelAsync(Channel channel) {
injectChannelInternalAsync(channel);
}
/**
* Add a custom channel handler to the given channel.
*
* @param channel - the channel to inject.
* @return The packet interceptor.
*/
private PacketInterceptor injectChannelInternal(Channel channel) {
try {
PacketInterceptor interceptor = (PacketInterceptor) channel.pipeline().get(handlerName);
// Inject our packet interceptor
if (interceptor == null) {
interceptor = new PacketInterceptor();
channel.pipeline().addBefore("packet_handler", handlerName, interceptor);
}
return interceptor;
} catch (IllegalArgumentException e) {
// Try again
return (PacketInterceptor) channel.pipeline().get(handlerName);
}
}
private PacketInterceptor injectChannelInternalAsync(Channel channel) {
try {
PacketInterceptor interceptor = (PacketInterceptor) channel.pipeline().get(handlerName);
// Inject our packet interceptor
if (interceptor == null) {
interceptor = new PacketInterceptor();
final PacketInterceptor pi = interceptor;
PacketEvents.packetHandlingExecutorService.execute(new Runnable() {
@Override
public void run() {
try {
channel.pipeline().addBefore("packet_handler", handlerName, pi);
}
catch(Exception ex) {
//kick them
Object packet = new WrappedPacketOutKickDisconnect("We unfortunately failed to inject you. Please try rejoining!").asNMSPacket();
sendPacket(channel, packet);
}
}
});
}
return interceptor;
} catch (IllegalArgumentException e) {
// Try again
return (PacketInterceptor) channel.pipeline().get(handlerName);
}
}
/**
* Retrieve the Netty channel associated with a player. This is cached.
*
* @param player - the player.
* @return The Netty channel.
*/
public Channel getChannel(Player player) {
Channel channel = channelLookup.get(player.getName());
// Lookup channel again
if (channel == null) {
Object connection = getConnection.get(getPlayerHandle.invoke(player));
Object manager = getManager.get(connection);
channelLookup.put(player.getName(), channel = getChannel.get(manager));
}
return channel;
}
/**
* Uninject a specific player.
*
* @param player - the injected player.
*/
public void uninjectPlayer(Player player) {
uninjectChannel(getChannel(player));
}
public void uninjectPlayerAsync(Player player) {
Channel channel = getChannel(player);
uninjectChannelAsync(channel);
}
public void ejectChannelSync(Object ch) {
uninjectChannel((Channel) ch);
}
public void ejectChannelAsync(Object ch) {
uninjectChannelAsync((Channel) ch);
}
/**
* Uninject a specific channel.
* <p>
* This will also disable the automatic channel injection that occurs when a player has properly logged in.
*
* @param channel - the injected channel.
*/
public void uninjectChannel(final Channel channel) {
// See ChannelInjector in ProtocolLib, line 590
channel.pipeline().remove(handlerName);
}
public void uninjectChannelAsync(Channel channel) {
// See ChannelInjector in ProtocolLib, line 590
PacketEvents.packetHandlingExecutorService.execute(new Runnable() {
@Override
public void run() {
channel.pipeline().remove(handlerName);
}
});
}
/**
* Determine if the given player has been injected by TinyProtocol.
*
* @param player - the player.
* @return TRUE if it is, FALSE otherwise.
*/
public boolean hasInjected(Player player) {
return hasInjected(getChannel(player));
}
/**
* Determine if the given channel has been injected by TinyProtocol.
*
* @param channel - the channel.
* @return TRUE if it is, FALSE otherwise.
*/
public boolean hasInjected(Channel channel) {
return channel.pipeline().get(handlerName) != null;
}
/**
* Cease listening for packets. This is called automatically when your plugin is disabled.
*/
public final void close() {
if (!closed) {
closed = true;
// Remove our handlers
for (Player player : plugin.getServer().getOnlinePlayers()) {
uninjectPlayer(player);
}
// Clean up Bukkit
unregisterChannelHandler();
}
}
public void handleQueuedKicks() {
for(Channel channel : queueingChannelKicks) {
Object packet = new WrappedPacketOutKickDisconnect("We failed to inject you. Please try rejoining!").asNMSPacket();
sendPacket(channel, packet);
}
}
/**
* Channel handler that is inserted into the player's channel pipeline, allowing us to intercept sent and received packets.
*
* @author Kristian
*/
private final class PacketInterceptor extends ChannelDuplexHandler {
// Updated by the login event
public volatile Player player;
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// Intercept channel
final Channel channel = ctx.channel();
handleLoginStart(channel, msg);
msg = onPacketInAsync(player, channel, msg);
if (msg != null) {
super.channelRead(ctx, msg);
PacketEvents.getAPI().packetManager.postRead(player, msg);
}
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
msg = onPacketOutAsync(player, ctx.channel(), msg);
if (msg != null) {
super.write(ctx, msg, promise);
PacketEvents.getAPI().packetManager.postWrite(player, msg);
}
}
private void handleLoginStart(Channel channel, Object packet) {
if (PACKET_LOGIN_IN_START.isInstance(packet)) {
GameProfile profile = getGameProfile.get(packet);
channelLookup.put(profile.getName(), channel);
}
}
}
}

View File

@ -0,0 +1,283 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packettype;
import java.util.HashMap;
import java.util.Map;
public class PacketType {
public static class Status {
public static final Map<Class<?>, Byte> packetIds = new HashMap<>();
public static final byte IN_START = 0, PING = 1, PONG = 2, SERVER_INFO = 3;
public static void init() {
packetIds.put(PacketTypeClasses.Status.IN_START, IN_START);
packetIds.put(PacketTypeClasses.Status.PING, PING);
packetIds.put(PacketTypeClasses.Status.PONG, PONG);
packetIds.put(PacketTypeClasses.Status.SERVER_INFO, SERVER_INFO);
}
}
public static class Login {
public static final Map<Class<?>, Byte> packetIds = new HashMap<>();
public static final byte HANDSHAKE = 0,
IN_CUSTOM_PAYLOAD = 1, OUT_CUSTOM_PAYLOAD = 2, IN_START = 3, IN_ENCRYPTION_BEGIN = 4,
DISCONNECT = 5, OUT_ENCRYPTION_BEGIN = 6, OUT_SUCCESS = 7;
public static void init() {
packetIds.put(PacketTypeClasses.Login.HANDSHAKE, HANDSHAKE);
packetIds.put(PacketTypeClasses.Login.IN_CUSTOM_PAYLOAD, IN_CUSTOM_PAYLOAD);
packetIds.put(PacketTypeClasses.Login.OUT_CUSTOM_PAYLOAD, OUT_CUSTOM_PAYLOAD);
packetIds.put(PacketTypeClasses.Login.IN_START, IN_START);
packetIds.put(PacketTypeClasses.Login.IN_ENCRYPTION_BEGIN, IN_ENCRYPTION_BEGIN);
packetIds.put(PacketTypeClasses.Login.DISCONNECT, DISCONNECT);
packetIds.put(PacketTypeClasses.Login.OUT_ENCRYPTION_BEGIN, OUT_ENCRYPTION_BEGIN);
packetIds.put(PacketTypeClasses.Login.OUT_SUCCESS, OUT_SUCCESS);
}
}
public static class Client {
public static final Map<Class<?>, Byte> packetIds = new HashMap<>();
public static final byte TELEPORT_ACCEPT = 0,
TILE_NBT_QUERY = 1, DIFFICULTY_CHANGE = 2, CHAT = 3, CLIENT_COMMAND = 4,
SETTINGS = 5, TAB_COMPLETE = 6, TRANSACTION = 7, ENCHANT_ITEM = 8,
WINDOW_CLICK = 9, CLOSE_WINDOW = 10, CUSTOM_PAYLOAD = 11, B_EDIT = 12,
ENTITY_NBT_QUERY = 13, USE_ENTITY = 14, JIGSAW_GENERATE = 15, KEEP_ALIVE = 16,
DIFFICULTY_LOCK = 17, POSITION = 18, POSITION_LOOK = 19, LOOK = 20,
FLYING = 21, VEHICLE_MOVE = 22, BOAT_MOVE = 23, PICK_ITEM = 24,
AUTO_RECIPE = 25, ABILITIES = 26, BLOCK_DIG = 27, ENTITY_ACTION = 28,
STEER_VEHICLE = 29, RECIPE_DISPLAYED = 30, ITEM_NAME = 31, RESOURCE_PACK_STATUS = 32,
ADVANCEMENTS = 33, TR_SEL = 34, BEACON = 35, HELD_ITEM_SLOT = 36,
SET_COMMAND_BLOCK = 37, SET_COMMAND_MINECART = 38, SET_CREATIVE_SLOT = 39, SET_JIGSAW = 40,
STRUCT = 41, UPDATE_SIGN = 42, ARM_ANIMATION = 43, SPECTATE = 44,
USE_ITEM = 45, BLOCK_PLACE = 46;
public static void init() {
packetIds.put(PacketTypeClasses.Client.TELEPORT_ACCEPT, TELEPORT_ACCEPT);
packetIds.put(PacketTypeClasses.Client.TILE_NBT_QUERY, TILE_NBT_QUERY);
packetIds.put(PacketTypeClasses.Client.DIFFICULTY_CHANGE, DIFFICULTY_CHANGE);
packetIds.put(PacketTypeClasses.Client.CHAT, CHAT);
packetIds.put(PacketTypeClasses.Client.CLIENT_COMMAND, CLIENT_COMMAND);
packetIds.put(PacketTypeClasses.Client.SETTINGS, SETTINGS);
packetIds.put(PacketTypeClasses.Client.TAB_COMPLETE, TAB_COMPLETE);
packetIds.put(PacketTypeClasses.Client.TRANSACTION, TRANSACTION);
packetIds.put(PacketTypeClasses.Client.ENCHANT_ITEM, ENCHANT_ITEM);
packetIds.put(PacketTypeClasses.Client.WINDOW_CLICK, WINDOW_CLICK);
packetIds.put(PacketTypeClasses.Client.CLOSE_WINDOW, CLOSE_WINDOW);
packetIds.put(PacketTypeClasses.Client.CUSTOM_PAYLOAD, CUSTOM_PAYLOAD);
packetIds.put(PacketTypeClasses.Client.B_EDIT, B_EDIT);
packetIds.put(PacketTypeClasses.Client.ENTITY_NBT_QUERY, ENTITY_NBT_QUERY);
packetIds.put(PacketTypeClasses.Client.USE_ENTITY, USE_ENTITY);
packetIds.put(PacketTypeClasses.Client.JIGSAW_GENERATE, JIGSAW_GENERATE);
packetIds.put(PacketTypeClasses.Client.KEEP_ALIVE, KEEP_ALIVE);
packetIds.put(PacketTypeClasses.Client.DIFFICULTY_LOCK, DIFFICULTY_LOCK);
packetIds.put(PacketTypeClasses.Client.POSITION, POSITION);
packetIds.put(PacketTypeClasses.Client.POSITION_LOOK, POSITION_LOOK);
packetIds.put(PacketTypeClasses.Client.LOOK, LOOK);
packetIds.put(PacketTypeClasses.Client.FLYING, FLYING);
packetIds.put(PacketTypeClasses.Client.VEHICLE_MOVE, VEHICLE_MOVE);
packetIds.put(PacketTypeClasses.Client.BOAT_MOVE, BOAT_MOVE);
packetIds.put(PacketTypeClasses.Client.PICK_ITEM, PICK_ITEM);
packetIds.put(PacketTypeClasses.Client.AUTO_RECIPE, AUTO_RECIPE);
packetIds.put(PacketTypeClasses.Client.ABILITIES, ABILITIES);
packetIds.put(PacketTypeClasses.Client.BLOCK_DIG, BLOCK_DIG);
packetIds.put(PacketTypeClasses.Client.ENTITY_ACTION, ENTITY_ACTION);
packetIds.put(PacketTypeClasses.Client.STEER_VEHICLE, STEER_VEHICLE);
packetIds.put(PacketTypeClasses.Client.RECIPE_DISPLAYED, RECIPE_DISPLAYED);
packetIds.put(PacketTypeClasses.Client.ITEM_NAME, ITEM_NAME);
packetIds.put(PacketTypeClasses.Client.RESOURCE_PACK_STATUS, RESOURCE_PACK_STATUS);
packetIds.put(PacketTypeClasses.Client.ADVANCEMENTS, ADVANCEMENTS);
packetIds.put(PacketTypeClasses.Client.TR_SEL, TR_SEL);
packetIds.put(PacketTypeClasses.Client.BEACON, BEACON);
packetIds.put(PacketTypeClasses.Client.HELD_ITEM_SLOT, HELD_ITEM_SLOT);
packetIds.put(PacketTypeClasses.Client.SET_COMMAND_BLOCK, SET_COMMAND_BLOCK);
packetIds.put(PacketTypeClasses.Client.SET_COMMAND_MINECART, SET_COMMAND_MINECART);
packetIds.put(PacketTypeClasses.Client.SET_CREATIVE_SLOT, SET_CREATIVE_SLOT);
packetIds.put(PacketTypeClasses.Client.SET_JIGSAW, SET_JIGSAW);
packetIds.put(PacketTypeClasses.Client.STRUCT, STRUCT);
packetIds.put(PacketTypeClasses.Client.UPDATE_SIGN, UPDATE_SIGN);
packetIds.put(PacketTypeClasses.Client.ARM_ANIMATION, ARM_ANIMATION);
packetIds.put(PacketTypeClasses.Client.SPECTATE, SPECTATE);
packetIds.put(PacketTypeClasses.Client.USE_ITEM, USE_ITEM);
packetIds.put(PacketTypeClasses.Client.BLOCK_PLACE, BLOCK_PLACE);
}
public static class Util {
/**
* Is the packet an instance of the PacketPlayInFlying packet?
*
* @param packetID
* @return packetID == FLYING or POSITION or POSITION_LOOK or LOOK
*/
public static boolean isInstanceOfFlying(final byte packetID) {
return packetID == FLYING
|| packetID == POSITION
|| packetID == POSITION_LOOK
|| packetID == LOOK;
}
}
}
public static class Server {
public static final Map<Class<?>, Byte> packetIds = new HashMap<>();
public static final byte SPAWN_ENTITY = 0, SPAWN_ENTITY_EXPERIENCE_ORB = 1, SPAWN_ENTITY_WEATHER = 2, SPAWN_ENTITY_LIVING = 3,
SPAWN_ENTITY_PAINTING = 4, SPAWN_ENTITY_SPAWN = 5, ANIMATION = 6, STATISTIC = 7,
BLOCK_BREAK = 8, BLOCK_BREAK_ANIMATION = 9, TILE_ENTITY_DATA = 10, BLOCK_ACTION = 11,
BLOCK_CHANGE = 12, BOSS = 13, SERVER_DIFFICULTY = 14, CHAT = 15, MULTI_BLOCK_CHANGE = 16,
TAB_COMPLETE = 17, COMMANDS = 18, TRANSACTION = 19, CLOSE_WINDOW = 20,
WINDOW_ITEMS = 21, WINDOW_DATA = 22, SET_SLOT = 23, SET_COOLDOWN = 24,
CUSTOM_PAYLOAD = 25, CUSTOM_SOUND_EFFECT = 26, KICK_DISCONNECT = 27, ENTITY_STATUS = 28,
EXPLOSION = 29, UNLOAD_CHUNK = 30, GAME_STATE_CHANGE = 31, OPEN_WINDOW_HORSE = 32,
KEEP_ALIVE = 33, MAP_CHUNK = 34, WORLD_EVENT = 35, WORLD_PARTICLES = 36,
LIGHT_UPDATE = 37, LOGIN = 38, MAP = 39, OPEN_WINDOW_MERCHANT = 40,
REL_ENTITY_MOVE = 41, REL_ENTITY_MOVE_LOOK = 42, ENTITY_LOOK = 43, ENTITY = 44,
VEHICLE_MOVE = 45, OPEN_BOOK = 46, OPEN_WINDOW = 47, OPEN_SIGN_EDITOR = 48,
AUTO_RECIPE = 49, ABILITIES = 50, COMBAT_EVENT = 51, PLAYER_INFO = 52,
LOOK_AT = 53, POSITION = 54, RECIPES = 55, ENTITY_DESTROY = 56,
REMOVE_ENTITY_EFFECT = 57, RESOURCE_PACK_SEND = 58, RESPAWN = 59, ENTITY_HEAD_ROTATION = 60,
SELECT_ADVANCEMENT_TAB = 61, WORLD_BORDER = 62, CAMERA = 63, HELD_ITEM_SLOT = 64,
VIEW_CENTRE = 65, VIEW_DISTANCE = 66, SCOREBOARD_DISPLAY_OBJECTIVE = 67, ENTITY_METADATA = 68,
ATTACH_ENTITY = 69, ENTITY_VELOCITY = 70, ENTITY_EQUIPMENT = 71, EXPERIENCE = 72,
UPDATE_HEALTH = 73, SCOREBOARD_OBJECTIVE = 74, MOUNT = 75, SCOREBOARD_TEAM = 76,
SCOREBOARD_SCORE = 77, SPAWN_POSITION = 78, UPDATE_TIME = 79, TITLE = 80,
ENTITY_SOUND = 81, NAMED_SOUND_EFFECT = 82, STOP_SOUND = 83, PLAYER_LIST_HEADER_FOOTER = 84,
NBT_QUERY = 85, COLLECT = 86, ENTITY_TELEPORT = 87, ADVANCEMENTS = 88, UPDATE_ATTRIBUTES = 89,
ENTITY_EFFECT = 90, RECIPE_UPDATE = 91, TAGS = 92, MAP_CHUNK_BULK = 93;
public static void init() {
packetIds.put(PacketTypeClasses.Server.SPAWN_ENTITY, SPAWN_ENTITY);
packetIds.put(PacketTypeClasses.Server.SPAWN_ENTITY_EXPERIENCE_ORB, SPAWN_ENTITY_EXPERIENCE_ORB);
packetIds.put(PacketTypeClasses.Server.SPAWN_ENTITY_WEATHER, SPAWN_ENTITY_WEATHER);
packetIds.put(PacketTypeClasses.Server.SPAWN_ENTITY_LIVING, SPAWN_ENTITY_LIVING);
packetIds.put(PacketTypeClasses.Server.SPAWN_ENTITY_PAINTING, SPAWN_ENTITY_PAINTING);
packetIds.put(PacketTypeClasses.Server.SPAWN_ENTITY_SPAWN, SPAWN_ENTITY_SPAWN);
packetIds.put(PacketTypeClasses.Server.ANIMATION, ANIMATION);
packetIds.put(PacketTypeClasses.Server.STATISTIC, STATISTIC);
packetIds.put(PacketTypeClasses.Server.BLOCK_BREAK, BLOCK_BREAK);
packetIds.put(PacketTypeClasses.Server.BLOCK_BREAK_ANIMATION, BLOCK_BREAK_ANIMATION);
packetIds.put(PacketTypeClasses.Server.TILE_ENTITY_DATA, TILE_ENTITY_DATA);
packetIds.put(PacketTypeClasses.Server.BLOCK_ACTION, BLOCK_ACTION);
packetIds.put(PacketTypeClasses.Server.BLOCK_CHANGE, BLOCK_CHANGE);
packetIds.put(PacketTypeClasses.Server.BOSS, BOSS);
packetIds.put(PacketTypeClasses.Server.SPAWN_ENTITY, SPAWN_ENTITY);
packetIds.put(PacketTypeClasses.Server.SERVER_DIFFICULTY, SERVER_DIFFICULTY);
packetIds.put(PacketTypeClasses.Server.CHAT, CHAT);
packetIds.put(PacketTypeClasses.Server.MULTI_BLOCK_CHANGE, MULTI_BLOCK_CHANGE);
packetIds.put(PacketTypeClasses.Server.TAB_COMPLETE, TAB_COMPLETE);
packetIds.put(PacketTypeClasses.Server.COMMANDS, COMMANDS);
packetIds.put(PacketTypeClasses.Server.TRANSACTION, TRANSACTION);
packetIds.put(PacketTypeClasses.Server.CLOSE_WINDOW, CLOSE_WINDOW);
packetIds.put(PacketTypeClasses.Server.WINDOW_ITEMS, WINDOW_ITEMS);
packetIds.put(PacketTypeClasses.Server.WINDOW_DATA, WINDOW_DATA);
packetIds.put(PacketTypeClasses.Server.SET_SLOT, SET_SLOT);
packetIds.put(PacketTypeClasses.Server.SET_COOLDOWN, SET_COOLDOWN);
packetIds.put(PacketTypeClasses.Server.CUSTOM_PAYLOAD, CUSTOM_PAYLOAD);
packetIds.put(PacketTypeClasses.Server.CUSTOM_SOUND_EFFECT, CUSTOM_SOUND_EFFECT);
packetIds.put(PacketTypeClasses.Server.KICK_DISCONNECT, KICK_DISCONNECT);
packetIds.put(PacketTypeClasses.Server.ENTITY_STATUS, ENTITY_STATUS);
packetIds.put(PacketTypeClasses.Server.EXPLOSION, EXPLOSION);
packetIds.put(PacketTypeClasses.Server.UNLOAD_CHUNK, UNLOAD_CHUNK);
packetIds.put(PacketTypeClasses.Server.GAME_STATE_CHANGE, GAME_STATE_CHANGE);
packetIds.put(PacketTypeClasses.Server.OPEN_WINDOW_HORSE, OPEN_WINDOW_HORSE);
packetIds.put(PacketTypeClasses.Server.KEEP_ALIVE, KEEP_ALIVE);
packetIds.put(PacketTypeClasses.Server.MAP_CHUNK, MAP_CHUNK);
packetIds.put(PacketTypeClasses.Server.WORLD_EVENT, WORLD_EVENT);
packetIds.put(PacketTypeClasses.Server.WORLD_EVENT, SPAWN_ENTITY);
packetIds.put(PacketTypeClasses.Server.WORLD_PARTICLES, WORLD_PARTICLES);
packetIds.put(PacketTypeClasses.Server.LIGHT_UPDATE, LIGHT_UPDATE);
packetIds.put(PacketTypeClasses.Server.LOGIN, LOGIN);
packetIds.put(PacketTypeClasses.Server.MAP, MAP);
packetIds.put(PacketTypeClasses.Server.OPEN_WINDOW_MERCHANT, OPEN_WINDOW_MERCHANT);
packetIds.put(PacketTypeClasses.Server.REL_ENTITY_MOVE, REL_ENTITY_MOVE);
packetIds.put(PacketTypeClasses.Server.REL_ENTITY_MOVE_LOOK, REL_ENTITY_MOVE_LOOK);
packetIds.put(PacketTypeClasses.Server.ENTITY_LOOK, ENTITY_LOOK);
packetIds.put(PacketTypeClasses.Server.ENTITY, ENTITY);
packetIds.put(PacketTypeClasses.Server.VEHICLE_MOVE, VEHICLE_MOVE);
packetIds.put(PacketTypeClasses.Server.OPEN_BOOK, OPEN_BOOK);
packetIds.put(PacketTypeClasses.Server.OPEN_WINDOW, OPEN_WINDOW);
packetIds.put(PacketTypeClasses.Server.OPEN_SIGN_EDITOR, OPEN_SIGN_EDITOR);
packetIds.put(PacketTypeClasses.Server.AUTO_RECIPE, AUTO_RECIPE);
packetIds.put(PacketTypeClasses.Server.ABILITIES, ABILITIES);
packetIds.put(PacketTypeClasses.Server.COMBAT_EVENT, COMBAT_EVENT);
packetIds.put(PacketTypeClasses.Server.PLAYER_INFO, PLAYER_INFO);
packetIds.put(PacketTypeClasses.Server.LOOK_AT, LOOK_AT);
packetIds.put(PacketTypeClasses.Server.POSITION, POSITION);
packetIds.put(PacketTypeClasses.Server.RECIPES, RECIPES);
packetIds.put(PacketTypeClasses.Server.ENTITY_DESTROY, ENTITY_DESTROY);
packetIds.put(PacketTypeClasses.Server.REMOVE_ENTITY_EFFECT, REMOVE_ENTITY_EFFECT);
packetIds.put(PacketTypeClasses.Server.RESOURCE_PACK_SEND, RESOURCE_PACK_SEND);
packetIds.put(PacketTypeClasses.Server.RESPAWN, RESPAWN);
packetIds.put(PacketTypeClasses.Server.ENTITY_HEAD_ROTATION, ENTITY_HEAD_ROTATION);
packetIds.put(PacketTypeClasses.Server.SELECT_ADVANCEMENT_TAB, SELECT_ADVANCEMENT_TAB);
packetIds.put(PacketTypeClasses.Server.WORLD_BORDER, WORLD_BORDER);
packetIds.put(PacketTypeClasses.Server.CAMERA, CAMERA);
packetIds.put(PacketTypeClasses.Server.HELD_ITEM_SLOT, HELD_ITEM_SLOT);
packetIds.put(PacketTypeClasses.Server.VIEW_CENTRE, VIEW_CENTRE);
packetIds.put(PacketTypeClasses.Server.VIEW_DISTANCE, VIEW_DISTANCE);
packetIds.put(PacketTypeClasses.Server.SCOREBOARD_DISPLAY_OBJECTIVE, SCOREBOARD_DISPLAY_OBJECTIVE);
packetIds.put(PacketTypeClasses.Server.ENTITY_METADATA, ENTITY_METADATA);
packetIds.put(PacketTypeClasses.Server.ATTACH_ENTITY, ATTACH_ENTITY);
packetIds.put(PacketTypeClasses.Server.ENTITY_VELOCITY, ENTITY_VELOCITY);
packetIds.put(PacketTypeClasses.Server.ENTITY_EQUIPMENT, ENTITY_EQUIPMENT);
packetIds.put(PacketTypeClasses.Server.EXPERIENCE, EXPERIENCE);
packetIds.put(PacketTypeClasses.Server.UPDATE_HEALTH, UPDATE_HEALTH);
packetIds.put(PacketTypeClasses.Server.SCOREBOARD_OBJECTIVE, SCOREBOARD_OBJECTIVE);
packetIds.put(PacketTypeClasses.Server.MOUNT, MOUNT);
packetIds.put(PacketTypeClasses.Server.SCOREBOARD_TEAM, SCOREBOARD_TEAM);
packetIds.put(PacketTypeClasses.Server.SCOREBOARD_SCORE, SCOREBOARD_SCORE);
packetIds.put(PacketTypeClasses.Server.SPAWN_POSITION, SPAWN_POSITION);
packetIds.put(PacketTypeClasses.Server.UPDATE_TIME, UPDATE_TIME);
packetIds.put(PacketTypeClasses.Server.TITLE, TITLE);
packetIds.put(PacketTypeClasses.Server.ENTITY_SOUND, ENTITY_SOUND);
packetIds.put(PacketTypeClasses.Server.NAMED_SOUND_EFFECT, NAMED_SOUND_EFFECT);
packetIds.put(PacketTypeClasses.Server.STOP_SOUND, STOP_SOUND);
packetIds.put(PacketTypeClasses.Server.PLAYER_LIST_HEADER_FOOTER, PLAYER_LIST_HEADER_FOOTER);
packetIds.put(PacketTypeClasses.Server.NBT_QUERY, NBT_QUERY);
packetIds.put(PacketTypeClasses.Server.COLLECT, COLLECT);
packetIds.put(PacketTypeClasses.Server.ENTITY_TELEPORT, ENTITY_TELEPORT);
packetIds.put(PacketTypeClasses.Server.ADVANCEMENTS, ADVANCEMENTS);
packetIds.put(PacketTypeClasses.Server.UPDATE_ATTRIBUTES, UPDATE_ATTRIBUTES);
packetIds.put(PacketTypeClasses.Server.ENTITY_EFFECT, ENTITY_EFFECT);
packetIds.put(PacketTypeClasses.Server.RECIPE_UPDATE, RECIPE_UPDATE);
packetIds.put(PacketTypeClasses.Server.TAGS, TAGS);
packetIds.put(PacketTypeClasses.Server.MAP_CHUNK_BULK, MAP_CHUNK_BULK);
}
public static class Util {
/**
* Is the packet an instance of the PacketPlayOutEntity packet?
*
* @param packetID
* @return packetID == ENTITY or REL_ENTITY_MOVE or REL_ENTITY_MOVE_LOOK or ENTITY_LOOK
*/
public static boolean isInstanceOfEntity(final byte packetID) {
return packetID == ENTITY || packetID == REL_ENTITY_MOVE ||
packetID == REL_ENTITY_MOVE_LOOK || packetID == ENTITY_LOOK;
}
}
}
}

View File

@ -0,0 +1,286 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packettype;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.reflection.SubclassUtil;
public class PacketTypeClasses {
public static class Status {
public static Class<?> IN_START, PING, PONG, SERVER_INFO;
public static void load() {
IN_START = NMSUtils.getNMSClassWithoutException("PacketStatusInStart");
PING = NMSUtils.getNMSClassWithoutException("PacketStatusInPing");
PONG = NMSUtils.getNMSClassWithoutException("PacketStatusOutPong");
SERVER_INFO = NMSUtils.getNMSClassWithoutException("PacketStatusOutServerInfo");
PacketType.Status.init();
}
}
public static class Login {
public static Class<?> HANDSHAKE,
IN_CUSTOM_PAYLOAD, OUT_CUSTOM_PAYLOAD, IN_START, IN_ENCRYPTION_BEGIN,
DISCONNECT, OUT_ENCRYPTION_BEGIN, OUT_SUCCESS;
public static void load() {
HANDSHAKE = NMSUtils.getNMSClassWithoutException("PacketHandshakingInSetProtocol");
//In and Out custom payload login packets have been here since AROUND 1.13.2.
IN_CUSTOM_PAYLOAD = NMSUtils.getNMSClassWithoutException("PacketLoginInCustomPayload");
OUT_CUSTOM_PAYLOAD = NMSUtils.getNMSClassWithoutException("PacketLoginOutCustomPayload");
IN_START = NMSUtils.getNMSClassWithoutException("PacketLoginInStart");
IN_ENCRYPTION_BEGIN = NMSUtils.getNMSClassWithoutException("PacketLoginInEncryptionBegin");
DISCONNECT = NMSUtils.getNMSClassWithoutException("PacketLoginOutDisconnect");
OUT_ENCRYPTION_BEGIN = NMSUtils.getNMSClassWithoutException("PacketLoginOutEncryptionBegin");
OUT_SUCCESS = NMSUtils.getNMSClassWithoutException("PacketLoginOutSuccess");
PacketType.Login.init();
}
}
public static class Client {
private static final String c = "PacketPlayIn";
public static Class<?> FLYING, POSITION, POSITION_LOOK, LOOK, 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;
/**
* Initiate all server-bound packet classes.
*/
public static void load() {
FLYING = NMSUtils.getNMSClassWithoutException(c + "Flying");
try {
POSITION = NMSUtils.getNMSClass(c + "Position");
POSITION_LOOK = NMSUtils.getNMSClass(c + "PositionLook");
LOOK = NMSUtils.getNMSClass(c + "Look");
} catch (ClassNotFoundException e) {
POSITION = SubclassUtil.getSubClass(FLYING, c + "Position");
POSITION_LOOK = SubclassUtil.getSubClass(FLYING, c + "PositionLook");
LOOK = SubclassUtil.getSubClass(FLYING, c + "Look");
}
try {
SETTINGS = NMSUtils.getNMSClass(c + "Settings");
ENCHANT_ITEM = NMSUtils.getNMSClass(c + "EnchantItem");
CLIENT_COMMAND = NMSUtils.getNMSClass(c + "ClientCommand");
TRANSACTION = NMSUtils.getNMSClass(c + "Transaction");
BLOCK_DIG = NMSUtils.getNMSClass(c + "BlockDig");
ENTITY_ACTION = NMSUtils.getNMSClass(c + "EntityAction");
USE_ENTITY = NMSUtils.getNMSClass(c + "UseEntity");
WINDOW_CLICK = NMSUtils.getNMSClass(c + "WindowClick");
STEER_VEHICLE = NMSUtils.getNMSClass(c + "SteerVehicle");
CUSTOM_PAYLOAD = NMSUtils.getNMSClass(c + "CustomPayload");
ARM_ANIMATION = NMSUtils.getNMSClass(c + "ArmAnimation");
ABILITIES = NMSUtils.getNMSClass(c + "Abilities");
HELD_ITEM_SLOT = NMSUtils.getNMSClass(c + "HeldItemSlot");
CLOSE_WINDOW = NMSUtils.getNMSClass(c + "CloseWindow");
TAB_COMPLETE = NMSUtils.getNMSClass(c + "TabComplete");
CHAT = NMSUtils.getNMSClass(c + "Chat");
SET_CREATIVE_SLOT = NMSUtils.getNMSClass(c + "SetCreativeSlot");
KEEP_ALIVE = NMSUtils.getNMSClass(c + "KeepAlive");
UPDATE_SIGN = NMSUtils.getNMSClassWithoutException(c + "UpdateSign");
TELEPORT_ACCEPT = NMSUtils.getNMSClassWithoutException(c + "TeleportAccept");
TILE_NBT_QUERY = NMSUtils.getNMSClassWithoutException(c + "TileNBTQuery");
DIFFICULTY_CHANGE = NMSUtils.getNMSClassWithoutException(c + "DifficultyChange");
B_EDIT = NMSUtils.getNMSClassWithoutException(c + "BEdit");
ENTITY_NBT_QUERY = NMSUtils.getNMSClassWithoutException(c + "EntityNBTQuery");
JIGSAW_GENERATE = NMSUtils.getNMSClassWithoutException(c + "JigsawGenerate");
DIFFICULTY_LOCK = NMSUtils.getNMSClassWithoutException(c + "DifficultyLock");
VEHICLE_MOVE = NMSUtils.getNMSClassWithoutException(c + "VehicleMove");
BOAT_MOVE = NMSUtils.getNMSClassWithoutException(c + "BoatMove");
PICK_ITEM = NMSUtils.getNMSClassWithoutException(c + "PickItem");
AUTO_RECIPE = NMSUtils.getNMSClassWithoutException(c + "AutoRecipe");
RECIPE_DISPLAYED = NMSUtils.getNMSClassWithoutException(c + "RecipeDisplayed");
ITEM_NAME = NMSUtils.getNMSClassWithoutException(c + "ItemName");
//1.8+
RESOURCE_PACK_STATUS = NMSUtils.getNMSClassWithoutException(c + "ResourcePackStatus");
ADVANCEMENTS = NMSUtils.getNMSClassWithoutException(c + "Advancements");
TR_SEL = NMSUtils.getNMSClassWithoutException(c + "TrSel");
BEACON = NMSUtils.getNMSClassWithoutException(c + "Beacon");
SET_COMMAND_BLOCK = NMSUtils.getNMSClassWithoutException(c + "SetCommandBlock");
SET_COMMAND_MINECART = NMSUtils.getNMSClassWithoutException(c + "SetCommandMinecart");
SET_JIGSAW = NMSUtils.getNMSClassWithoutException(c + "SetJigsaw");
STRUCT = NMSUtils.getNMSClassWithoutException(c + "Struct");
SPECTATE = NMSUtils.getNMSClassWithoutException(c + "Spectate");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
BLOCK_PLACE = NMSUtils.getNMSClass(c + "BlockPlace");
USE_ITEM = NMSUtils.getNMSClass(c + "UseItem");
} catch (ClassNotFoundException ignored) {
}
PacketType.Client.init();
}
}
public static class Server {
private static final String s = "PacketPlayOut";
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;
/**
* Initiate all client-bound packet classes.
*/
public static void load() {
SPAWN_ENTITY = NMSUtils.getNMSClassWithoutException(s + "SpawnEntity");
SPAWN_ENTITY_EXPERIENCE_ORB = NMSUtils.getNMSClassWithoutException(s + "SpawnEntityExperienceOrb");
SPAWN_ENTITY_WEATHER = NMSUtils.getNMSClassWithoutException(s + "SpawnEntityWeather");
SPAWN_ENTITY_LIVING = NMSUtils.getNMSClassWithoutException(s + "SpawnEntityLiving");
SPAWN_ENTITY_PAINTING = NMSUtils.getNMSClassWithoutException(s + "SpawnEntityPainting");
SPAWN_ENTITY_SPAWN = NMSUtils.getNMSClassWithoutException(s + "SpawnEntitySpawn");
ANIMATION = NMSUtils.getNMSClassWithoutException(s + "Animation");
STATISTIC = NMSUtils.getNMSClassWithoutException(s + "Statistic");
BLOCK_BREAK = NMSUtils.getNMSClassWithoutException(s + "BlockBreak");
BLOCK_BREAK_ANIMATION = NMSUtils.getNMSClassWithoutException(s + "BlockBreakAnimation");
TILE_ENTITY_DATA = NMSUtils.getNMSClassWithoutException(s + "TileEntityData");
BLOCK_ACTION = NMSUtils.getNMSClassWithoutException(s + "BlockAction");
BLOCK_CHANGE = NMSUtils.getNMSClassWithoutException(s + "BlockChange");
BOSS = NMSUtils.getNMSClassWithoutException(s + "Boss");
SERVER_DIFFICULTY = NMSUtils.getNMSClassWithoutException(s + "ServerDifficulty");
CHAT = NMSUtils.getNMSClassWithoutException(s + "Chat");
MULTI_BLOCK_CHANGE = NMSUtils.getNMSClassWithoutException(s + "MultiBlockChange");
TAB_COMPLETE = NMSUtils.getNMSClassWithoutException(s + "TabComplete");
COMMANDS = NMSUtils.getNMSClassWithoutException(s + "Commands");
TRANSACTION = NMSUtils.getNMSClassWithoutException(s + "Transaction");
CLOSE_WINDOW = NMSUtils.getNMSClassWithoutException(s + "CloseWindow");
WINDOW_ITEMS = NMSUtils.getNMSClassWithoutException(s + "WindowItems");
WINDOW_DATA = NMSUtils.getNMSClassWithoutException(s + "WindowData");
SET_SLOT = NMSUtils.getNMSClassWithoutException(s + "SetSlot");
SET_COOLDOWN = NMSUtils.getNMSClassWithoutException(s + "SetCooldown");
CUSTOM_PAYLOAD = NMSUtils.getNMSClassWithoutException(s + "CustomPayload");
CUSTOM_SOUND_EFFECT = NMSUtils.getNMSClassWithoutException(s + "CustomSoundEffect");
KICK_DISCONNECT = NMSUtils.getNMSClassWithoutException(s + "KickDisconnect");
ENTITY_STATUS = NMSUtils.getNMSClassWithoutException(s + "EntityStatus");
EXPLOSION = NMSUtils.getNMSClassWithoutException(s + "Explosion");
UNLOAD_CHUNK = NMSUtils.getNMSClassWithoutException(s + "UnloadChunk");
GAME_STATE_CHANGE = NMSUtils.getNMSClassWithoutException(s + "GameStateChange");
OPEN_WINDOW_HORSE = NMSUtils.getNMSClassWithoutException(s + "OpenWindowHorse");
KEEP_ALIVE = NMSUtils.getNMSClassWithoutException(s + "KeepAlive");
MAP_CHUNK = NMSUtils.getNMSClassWithoutException(s + "MapChunk");
WORLD_EVENT = NMSUtils.getNMSClassWithoutException(s + "WorldEvent");
WORLD_PARTICLES = NMSUtils.getNMSClassWithoutException(s + "WorldParticles");
LIGHT_UPDATE = NMSUtils.getNMSClassWithoutException(s + "LightUpdate");
LOGIN = NMSUtils.getNMSClassWithoutException(s + "Login");
MAP = NMSUtils.getNMSClassWithoutException(s + "Map");
OPEN_WINDOW_MERCHANT = NMSUtils.getNMSClassWithoutException(s + "OpenWindowMerchant");
ENTITY = NMSUtils.getNMSClassWithoutException(s + "Entity");
REL_ENTITY_MOVE = SubclassUtil.getSubClass(ENTITY, s + "RelEntityMove");
REL_ENTITY_MOVE_LOOK = SubclassUtil.getSubClass(ENTITY, s + "RelEntityMoveLook");
ENTITY_LOOK = SubclassUtil.getSubClass(ENTITY, s + "EntityLook");
if (REL_ENTITY_MOVE == null) {
//is not a subclass and should be accessed normally
REL_ENTITY_MOVE = NMSUtils.getNMSClassWithoutException(s + "RelEntityMove");
REL_ENTITY_MOVE_LOOK = NMSUtils.getNMSClassWithoutException(s + "RelEntityMoveLook");
ENTITY_LOOK = NMSUtils.getNMSClassWithoutException(s + "RelEntityLook");
}
VEHICLE_MOVE = NMSUtils.getNMSClassWithoutException(s + "VehicleMove");
OPEN_BOOK = NMSUtils.getNMSClassWithoutException(s + "OpenBook");
OPEN_WINDOW = NMSUtils.getNMSClassWithoutException(s + "OpenWindow");
OPEN_SIGN_EDITOR = NMSUtils.getNMSClassWithoutException(s + "OpenSignEditor");
AUTO_RECIPE = NMSUtils.getNMSClassWithoutException(s + "AutoRecipe");
ABILITIES = NMSUtils.getNMSClassWithoutException(s + "Abilities");
COMBAT_EVENT = NMSUtils.getNMSClassWithoutException(s + "CombatEvent");
PLAYER_INFO = NMSUtils.getNMSClassWithoutException(s + "PlayerInfo");
LOOK_AT = NMSUtils.getNMSClassWithoutException(s + "LookAt");
POSITION = NMSUtils.getNMSClassWithoutException(s + "Position");
RECIPES = NMSUtils.getNMSClassWithoutException(s + "Recipes");
ENTITY_DESTROY = NMSUtils.getNMSClassWithoutException(s + "EntityDestroy");
REMOVE_ENTITY_EFFECT = NMSUtils.getNMSClassWithoutException(s + "RemoveEntityEffect");
RESOURCE_PACK_SEND = NMSUtils.getNMSClassWithoutException(s + "ResourcePackSend");
RESPAWN = NMSUtils.getNMSClassWithoutException(s + "Respawn");
ENTITY_HEAD_ROTATION = NMSUtils.getNMSClassWithoutException(s + "EntityHeadRotation");
SELECT_ADVANCEMENT_TAB = NMSUtils.getNMSClassWithoutException(s + "SelectAdvancementTab");
WORLD_BORDER = NMSUtils.getNMSClassWithoutException(s + "WorldBorder");
CAMERA = NMSUtils.getNMSClassWithoutException(s + "Camera");
HELD_ITEM_SLOT = NMSUtils.getNMSClassWithoutException(s + "HeldItemSlot");
VIEW_CENTRE = NMSUtils.getNMSClassWithoutException(s + "ViewCentre");
VIEW_DISTANCE = NMSUtils.getNMSClassWithoutException(s + "ViewDistance");
SCOREBOARD_DISPLAY_OBJECTIVE = NMSUtils.getNMSClassWithoutException(s + "ScoreboardDisplayObjective");
ENTITY_METADATA = NMSUtils.getNMSClassWithoutException(s + "EntityMetadata");
ATTACH_ENTITY = NMSUtils.getNMSClassWithoutException(s + "AttachEntity");
ENTITY_VELOCITY = NMSUtils.getNMSClassWithoutException(s + "EntityVelocity");
ENTITY_EQUIPMENT = NMSUtils.getNMSClassWithoutException(s + "EntityEquipment");
EXPERIENCE = NMSUtils.getNMSClassWithoutException(s + "Experience");
UPDATE_HEALTH = NMSUtils.getNMSClassWithoutException(s + "UpdateHealth");
SCOREBOARD_OBJECTIVE = NMSUtils.getNMSClassWithoutException(s + "ScoreboardObjective");
MOUNT = NMSUtils.getNMSClassWithoutException(s + "Mount");
SCOREBOARD_TEAM = NMSUtils.getNMSClassWithoutException(s + "ScoreboardTeam");
SCOREBOARD_SCORE = NMSUtils.getNMSClassWithoutException(s + "ScoreboardScore");
SPAWN_POSITION = NMSUtils.getNMSClassWithoutException(s + "SpawnPosition");
UPDATE_TIME = NMSUtils.getNMSClassWithoutException(s + "UpdateTime");
TITLE = NMSUtils.getNMSClassWithoutException(s + "Title");
ENTITY_SOUND = NMSUtils.getNMSClassWithoutException(s + "EntitySound");
NAMED_SOUND_EFFECT = NMSUtils.getNMSClassWithoutException(s + "NamedSoundEffect");
STOP_SOUND = NMSUtils.getNMSClassWithoutException(s + "StopSound");
PLAYER_LIST_HEADER_FOOTER = NMSUtils.getNMSClassWithoutException(s + "PlayerListHeaderFooter");
NBT_QUERY = NMSUtils.getNMSClassWithoutException(s + "NBTQuery");
COLLECT = NMSUtils.getNMSClassWithoutException(s + "Collect");
ENTITY_TELEPORT = NMSUtils.getNMSClassWithoutException(s + "EntityTeleport");
ADVANCEMENTS = NMSUtils.getNMSClassWithoutException(s + "Advancements");
UPDATE_ATTRIBUTES = NMSUtils.getNMSClassWithoutException(s + "UpdateAttributes");
ENTITY_EFFECT = NMSUtils.getNMSClassWithoutException(s + "EntityEffect");
RECIPE_UPDATE = NMSUtils.getNMSClassWithoutException(s + "RecipeUpdate");
TAGS = NMSUtils.getNMSClassWithoutException(s + "Tags");
MAP_CHUNK_BULK = NMSUtils.getNMSClassWithoutException(s + "MapChunkBulk");
PacketType.Server.init();
}
}
}

View File

@ -0,0 +1,32 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers;
/**
* This interface indicates that a packet wrapper supports being sent to a client.
*/
public interface SendableWrapper {
Object asNMSPacket();
}

View File

@ -0,0 +1,614 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers;
import io.github.retrooper.packetevents.exceptions.WrapperFieldNotFoundException;
import io.github.retrooper.packetevents.packettype.PacketTypeClasses;
import io.github.retrooper.packetevents.packetwrappers.in.blockdig.WrappedPacketInBlockDig;
import io.github.retrooper.packetevents.packetwrappers.in.blockplace.WrappedPacketInBlockPlace;
import io.github.retrooper.packetevents.packetwrappers.in.clientcommand.WrappedPacketInClientCommand;
import io.github.retrooper.packetevents.packetwrappers.in.custompayload.WrappedPacketInCustomPayload;
import io.github.retrooper.packetevents.packetwrappers.in.entityaction.WrappedPacketInEntityAction;
import io.github.retrooper.packetevents.packetwrappers.in.keepalive.WrappedPacketInKeepAlive;
import io.github.retrooper.packetevents.packetwrappers.in.settings.WrappedPacketInSettings;
import io.github.retrooper.packetevents.packetwrappers.in.updatesign.WrappedPacketInUpdateSign;
import io.github.retrooper.packetevents.packetwrappers.in.useentity.WrappedPacketInUseEntity;
import io.github.retrooper.packetevents.packetwrappers.in.windowclick.WrappedPacketInWindowClick;
import io.github.retrooper.packetevents.packetwrappers.out.abilities.WrappedPacketOutAbilities;
import io.github.retrooper.packetevents.packetwrappers.out.animation.WrappedPacketOutAnimation;
import io.github.retrooper.packetevents.packetwrappers.out.chat.WrappedPacketOutChat;
import io.github.retrooper.packetevents.packetwrappers.out.custompayload.WrappedPacketOutCustomPayload;
import io.github.retrooper.packetevents.packetwrappers.out.entity.WrappedPacketOutEntity;
import io.github.retrooper.packetevents.packetwrappers.out.entitystatus.WrappedPacketOutEntityStatus;
import io.github.retrooper.packetevents.packetwrappers.out.entityteleport.WrappedPacketOutEntityTeleport;
import io.github.retrooper.packetevents.packetwrappers.out.entityvelocity.WrappedPacketOutEntityVelocity;
import io.github.retrooper.packetevents.packetwrappers.out.experience.WrappedPacketOutExperience;
import io.github.retrooper.packetevents.packetwrappers.out.explosion.WrappedPacketOutExplosion;
import io.github.retrooper.packetevents.packetwrappers.out.gamestatechange.WrappedPacketOutGameStateChange;
import io.github.retrooper.packetevents.packetwrappers.out.helditemslot.WrappedPacketOutHeldItemSlot;
import io.github.retrooper.packetevents.packetwrappers.out.keepalive.WrappedPacketOutKeepAlive;
import io.github.retrooper.packetevents.packetwrappers.out.kickdisconnect.WrappedPacketOutKickDisconnect;
import io.github.retrooper.packetevents.packetwrappers.out.position.WrappedPacketOutPosition;
import io.github.retrooper.packetevents.packetwrappers.out.transaction.WrappedPacketOutTransaction;
import io.github.retrooper.packetevents.packetwrappers.out.updatehealth.WrappedPacketOutUpdateHealth;
import io.github.retrooper.packetevents.utils.reflection.ClassUtil;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class WrappedPacket implements WrapperPacketReader, WrapperPacketWriter {
private static final Map<Class<?>, Map<Class<?>, Field[]>> fieldCache = new HashMap<>();
public static ServerVersion version;
protected Object packet;
private Class<?> packetClass;
public WrappedPacket() {
}
public WrappedPacket(final Object packet) {
this(packet, packet.getClass());
}
public WrappedPacket(final Object packet, Class<?> packetClass) {
if (packet.getClass().getSuperclass().equals(PacketTypeClasses.Client.FLYING)) {
packetClass = PacketTypeClasses.Client.FLYING;
} else if (packet.getClass().getSuperclass().equals(PacketTypeClasses.Server.ENTITY)) {
packetClass = PacketTypeClasses.Server.ENTITY;
}
this.packetClass = packetClass;
if (!fieldCache.containsKey(packetClass)) {
final Field[] declaredFields = packetClass.getDeclaredFields();
for (Field f : declaredFields) {
f.setAccessible(true);
}
List<Field> boolFields = getFields(boolean.class, declaredFields);
List<Field> byteFields = getFields(byte.class, declaredFields);
List<Field> shortFields = getFields(short.class, declaredFields);
List<Field> intFields = getFields(int.class, declaredFields);
List<Field> longFields = getFields(long.class, declaredFields);
List<Field> floatFields = getFields(float.class, declaredFields);
List<Field> doubleFields = getFields(double.class, declaredFields);
List<Field> stringFields = getFields(String.class, declaredFields);
List<Field> boolArrayFields = getFields(boolean[].class, declaredFields);
List<Field> byteArrayFields = getFields(byte[].class, declaredFields);
List<Field> shortArrayFields = getFields(short[].class, declaredFields);
List<Field> intArrayFields = getFields(int[].class, declaredFields);
List<Field> longArrayFields = getFields(long[].class, declaredFields);
List<Field> floatArrayFields = getFields(float[].class, declaredFields);
List<Field> doubleArrayFields = getFields(double[].class, declaredFields);
List<Field> stringArrayFields = getFields(String[].class, declaredFields);
Field[] tmp = new Field[0];
Map<Class<?>, Field[]> map = new HashMap<>();
map.put(boolean.class, boolFields.toArray(tmp));
map.put(byte.class, byteFields.toArray(tmp));
map.put(short.class, shortFields.toArray(tmp));
map.put(int.class, intFields.toArray(tmp));
map.put(long.class, longFields.toArray(tmp));
map.put(float.class, floatFields.toArray(tmp));
map.put(double.class, doubleFields.toArray(tmp));
map.put(String.class, stringFields.toArray(tmp));
map.put(boolean[].class, boolArrayFields.toArray(tmp));
map.put(byte[].class, byteArrayFields.toArray(tmp));
map.put(short[].class, shortArrayFields.toArray(tmp));
map.put(int[].class, intArrayFields.toArray(tmp));
map.put(long[].class, longArrayFields.toArray(tmp));
map.put(float[].class, floatArrayFields.toArray(tmp));
map.put(double[].class, doubleArrayFields.toArray(tmp));
map.put(String[].class, stringArrayFields.toArray(tmp));
fieldCache.put(packetClass, map);
}
this.packet = packet;
setup();
}
public static void loadAllWrappers() {
//SERVER BOUND
WrappedPacketInBlockDig.load();
WrappedPacketInBlockPlace.load();
WrappedPacketInClientCommand.load();
WrappedPacketInCustomPayload.load();
WrappedPacketInEntityAction.load();
WrappedPacketInKeepAlive.load();
WrappedPacketInSettings.load();
WrappedPacketInUseEntity.load();
WrappedPacketInUpdateSign.load();
WrappedPacketInWindowClick.load();
//CLIENTBOUND
WrappedPacketOutAbilities.load();
WrappedPacketOutAnimation.load();
WrappedPacketOutChat.load();
WrappedPacketOutEntity.load();
WrappedPacketOutEntityVelocity.load();
WrappedPacketOutEntityTeleport.load();
WrappedPacketOutKeepAlive.load();
WrappedPacketOutKickDisconnect.load();
WrappedPacketOutPosition.load();
WrappedPacketOutTransaction.load();
WrappedPacketOutUpdateHealth.load();
WrappedPacketOutGameStateChange.load();
WrappedPacketOutCustomPayload.load();
WrappedPacketOutExplosion.load();
WrappedPacketOutEntityStatus.load();
WrappedPacketOutExperience.load();
WrappedPacketOutHeldItemSlot.load();
}
protected void setup() {
}
@Override
public boolean readBoolean(int index) {
return (boolean) read(boolean.class, index);
}
@Override
public byte readByte(int index) {
return (byte) read(byte.class, index);
}
@Override
public short readShort(int index) {
return (short) read(short.class, index);
}
@Override
public int readInt(int index) {
return (int) read(int.class, index);
}
@Override
public long readLong(int index) {
return (long) read(long.class, index);
}
@Override
public float readFloat(int index) {
return (float) read(float.class, index);
}
@Override
public double readDouble(int index) {
return (double) read(double.class, index);
}
@Override
public boolean[] readBooleanArray(int index) {
Map<Class<?>, Field[]> cached = fieldCache.get(packetClass);
if (cached != null) {
try {
return (boolean[]) cached.get(boolean[].class)[index].get(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
int currentIndex = 0;
for (Field f : packetClass.getDeclaredFields()) {
f.setAccessible(true);
if (boolean[].class.isAssignableFrom(f.getType())) {
if (index == currentIndex++) {
try {
return (boolean[]) f.get(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
throw new WrapperFieldNotFoundException(packetClass, boolean[].class, index);
}
@Override
public byte[] readByteArray(int index) {
Map<Class<?>, Field[]> cached = fieldCache.get(packetClass);
if (cached != null) {
try {
return (byte[]) cached.get(byte[].class)[index].get(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
int currentIndex = 0;
for (Field f : packetClass.getDeclaredFields()) {
f.setAccessible(true);
if (byte[].class.isAssignableFrom(f.getType())) {
if (index == currentIndex++) {
try {
return (byte[]) f.get(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
throw new WrapperFieldNotFoundException(packetClass, byte[].class, index);
}
@Override
public short[] readShortArray(int index) {
Map<Class<?>, Field[]> cached = fieldCache.get(packetClass);
if (cached != null) {
try {
return (short[]) cached.get(short[].class)[index].get(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
int currentIndex = 0;
for (Field f : packetClass.getDeclaredFields()) {
f.setAccessible(true);
if (short[].class.isAssignableFrom(f.getType())) {
if (index == currentIndex++) {
try {
return (short[]) f.get(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
throw new WrapperFieldNotFoundException(packetClass, short[].class, index);
}
@Override
public int[] readIntArray(int index) {
Map<Class<?>, Field[]> cached = fieldCache.get(packetClass);
if (cached != null) {
try {
return (int[]) cached.get(int[].class)[index].get(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
int currentIndex = 0;
for (Field f : packetClass.getDeclaredFields()) {
f.setAccessible(true);
if (int[].class.isAssignableFrom(f.getType())) {
if (index == currentIndex++) {
try {
return (int[]) f.get(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
throw new WrapperFieldNotFoundException(packetClass, int[].class, index);
}
@Override
public long[] readLongArray(int index) {
Map<Class<?>, Field[]> cached = fieldCache.get(packetClass);
if (cached != null) {
try {
return (long[]) cached.get(long[].class)[index].get(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
int currentIndex = 0;
for (Field f : packetClass.getDeclaredFields()) {
f.setAccessible(true);
if (long[].class.isAssignableFrom(f.getType())) {
if (index == currentIndex++) {
try {
return (long[]) f.get(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
throw new WrapperFieldNotFoundException(packetClass, long[].class, index);
}
@Override
public float[] readFloatArray(int index) {
Map<Class<?>, Field[]> cached = fieldCache.get(packetClass);
if (cached != null) {
try {
return (float[]) cached.get(float[].class)[index].get(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
int currentIndex = 0;
for (Field f : packetClass.getDeclaredFields()) {
f.setAccessible(true);
if (float.class.isAssignableFrom(f.getType())) {
if (index == currentIndex++) {
try {
return (float[]) f.get(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
throw new WrapperFieldNotFoundException(packetClass, float[].class, index);
}
@Override
public double[] readDoubleArray(int index) {
Map<Class<?>, Field[]> cached = fieldCache.get(packetClass);
if (cached != null) {
try {
return (double[]) cached.get(double[].class)[index].get(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
int currentIndex = 0;
for (Field f : packetClass.getDeclaredFields()) {
f.setAccessible(true);
if (double[].class.isAssignableFrom(f.getType())) {
if (index == currentIndex++) {
try {
return (double[]) f.get(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
throw new WrapperFieldNotFoundException(packetClass, double[].class, index);
}
@Override
public String[] readStringArray(int index) {
Map<Class<?>, Field[]> cached = fieldCache.get(packetClass);
if (cached != null) {
try {
Object[] array = (Object[]) cached.get(String[].class)[index].get(packet);
int len = array.length;
String[] stringArray = new String[len];
for (int i = 0; i < len; i++) {
stringArray[i] = array[i].toString();
}
return stringArray;
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
throw new WrapperFieldNotFoundException(packetClass, String[].class, index);
}
@Override
public String readString(int index) {
return (String) read(String.class, index);
}
public Object readAnyObject(int index) {
try {
Field f = packetClass.getDeclaredFields()[index];
if (!f.isAccessible()) {
f.setAccessible(true);
}
try {
return f.get(packet);
} catch (IllegalAccessException 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;
}
public Object readObject(int index, Class<?> type) {
Map<Class<?>, Field[]> cached = fieldCache.get(packetClass);
if (cached != null) {
Field[] cachedFields = cached.get(type);
if (cachedFields == null) {
List<Field> typeFields = new ArrayList<>();
for (Field f : packetClass.getDeclaredFields()) {
f.setAccessible(true);
if (f.getType().equals(type)) {
typeFields.add(f);
}
}
if (!typeFields.isEmpty()) {
cached.put(type, typeFields.toArray(new Field[0]));
cachedFields = cached.get(type);
} else {
throw new WrapperFieldNotFoundException("The class you are trying to read fields from does not contain any fields!");
}
}
try {
return cachedFields[index].get(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
throw new WrapperFieldNotFoundException(packetClass, type, index);
}
public boolean doesObjectExist(int index, Class<?> type) {
Map<Class<?>, Field[]> cached = fieldCache.get(packetClass);
if (cached != null) {
Field[] cachedFields = cached.get(type);
if (cachedFields == null) {
List<Field> typeFields = new ArrayList<>();
for (Field f : packetClass.getDeclaredFields()) {
f.setAccessible(true);
if (f.getType().equals(type)) {
typeFields.add(f);
}
}
if (!typeFields.isEmpty()) {
cached.put(type, typeFields.toArray(new Field[0]));
cachedFields = cached.get(type);
} else {
return false;
}
}
if (cachedFields == null) {
return false;
} else return index <= cachedFields.length + 1;
}
return false;
}
public Object[] readObjectArray(int index, Class<?> type) {
if (type.equals(String.class)) {
return readStringArray(index);
}
try {
return (Object[]) readObject(index, getArrayClass(type));
} catch (ClassNotFoundException e) {
throw new IllegalStateException("PacketEvents failed to find the array class of type " + type.getName());
}
}
@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);
}
private 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, value);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
private Object read(Class<?> type, int index) throws WrapperFieldNotFoundException {
Field field = getField(type, index);
if (field == null) {
throw new WrapperFieldNotFoundException(packetClass, type, index);
}
try {
return field.get(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
private Field getField(Class<?> type, int index) {
Map<Class<?>, Field[]> cached = fieldCache.get(packetClass);
if (cached == null) {
return null;
}
Field[] fields = cached.get(type);
if (fields != null) {
return fields[index];
}
return null;
}
private List<Field> getFields(Class<?> type, Field[] fields) {
List<Field> ret = new ArrayList<>();
for (Field field : fields) {
if (field.getType() == type) {
ret.add(field);
}
}
return ret;
}
private Class<?> getArrayClass(Class<?> componentType) throws ClassNotFoundException {
ClassLoader classLoader = componentType.getClassLoader();
String name;
if (componentType.isArray()) {
// just add a leading "["
name = "[" + componentType.getName();
} else if (componentType == boolean.class) {
name = "[Z";
} else if (componentType == byte.class) {
name = "[B";
} else if (componentType == char.class) {
name = "[C";
} else if (componentType == double.class) {
name = "[D";
} else if (componentType == float.class) {
name = "[F";
} else if (componentType == int.class) {
name = "[I";
} else if (componentType == long.class) {
name = "[J";
} else if (componentType == short.class) {
name = "[S";
} else {
// must be an object non-array class
name = "[L" + componentType.getName() + ";";
}
return classLoader != null ? classLoader.loadClass(name) : Class.forName(name);
}
}

View File

@ -0,0 +1,66 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers;
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);
Object readObject(int index, Class<?> type);
Object readAnyObject(int index);
Object[] readObjectArray(int index, Class<?> type);
}

View File

@ -0,0 +1,45 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers;
public interface WrapperPacketWriter {
// TODO write for the arrays
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);
}

View File

@ -0,0 +1,95 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.in.abilities;
import io.github.retrooper.packetevents.annotations.NotNull;
import io.github.retrooper.packetevents.annotations.Nullable;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
public final class WrappedPacketInAbilities extends WrappedPacket {
public WrappedPacketInAbilities(Object packet) {
super(packet);
}
/**
* This will return null if the server version is not available in 1.16.x and above
*
* @return Whether the player is vulnerable to damage or not.
*/
@Deprecated
@Nullable
public boolean isVulnerable() {
return readBoolean(0);
}
@NotNull
public boolean isFlying() {
return readBoolean(1);
}
/**
* This will return null if the server version is not available in 1.16.x and above
*
* @return Whether or not the player can fly.
*/
@Deprecated
@Nullable
public boolean isFlightAllowed() {
return readBoolean(2);
}
/**
* This will return null if the server version is not available in 1.16.x and above
*
* @return Whether or not the player can break blocks instantly.
*/
@Deprecated
@Nullable
public boolean canInstantlyBuild() {
return readBoolean(3);
}
/**
* This will return null if the server version is not available in 1.16.x and above
*
* @return The speed at which the player can fly, as a float.
*/
@Deprecated
@Nullable
public float getFlySpeed() {
return readFloat(0);
}
/**
* This will return null if the server version is not available in 1.16.x and above
*
* @return The speed at which the player can walk, as a float.
*/
@Deprecated
@Nullable
public float getWalkSpeed() {
return readFloat(1);
}
}

View File

@ -0,0 +1,172 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.in.blockdig;
import io.github.retrooper.packetevents.enums.Direction;
import io.github.retrooper.packetevents.packettype.PacketTypeClasses;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.reflection.Reflection;
import io.github.retrooper.packetevents.utils.reflection.SubclassUtil;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
import java.lang.reflect.InvocationTargetException;
public final class WrappedPacketInBlockDig extends WrappedPacket {
private static Class<?> blockDigClass, blockPositionClass, enumDirectionClass, digTypeClass;
private static boolean isVersionLowerThan_v_1_8;
private Object blockPosObj;
private Object enumDirObj;
public WrappedPacketInBlockDig(Object packet) {
super(packet);
}
public static void load() {
blockDigClass = PacketTypeClasses.Client.BLOCK_DIG;
try {
if (version.isHigherThan(ServerVersion.v_1_7_10)) {
blockPositionClass = NMSUtils.getNMSClass("BlockPosition");
enumDirectionClass = NMSUtils.getNMSClass("EnumDirection");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
isVersionLowerThan_v_1_8 = version.isLowerThan(ServerVersion.v_1_8);
if (version != ServerVersion.v_1_7_10) {
try {
digTypeClass = NMSUtils.getNMSClass("EnumPlayerDigType");
} catch (ClassNotFoundException e) {
//It is probably a subclass
digTypeClass = SubclassUtil.getSubClass(blockDigClass, "EnumPlayerDigType");
}
}
}
/**
* Get X position of the block
* @return Block Position X
*/
public int getX() {
if(isVersionLowerThan_v_1_8) {
return readInt(0);
}
else {
if(blockPosObj == null) {
blockPosObj = readObject(0, blockPositionClass);
}
try {
return (int) Reflection.getMethod(blockPosObj.getClass().getSuperclass(), "getX", 0).invoke(blockPosObj);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return -1;
}
}
/**
* Get Y position of the block
* @return Block Position Y
*/
public int getY() {
if(isVersionLowerThan_v_1_8) {
return readInt(1);
}
else {
if(blockPosObj == null) {
blockPosObj = readObject(0, blockPositionClass);
}
try {
return (int) Reflection.getMethod(blockPosObj.getClass().getSuperclass(), "getY", 0).invoke(blockPosObj);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return -1;
}
}
/**
* Get Z position of the block
* @return Block Position Z
*/
public int getZ() {
if(isVersionLowerThan_v_1_8) {
return readInt(2);
}
else {
if(blockPosObj == null) {
blockPosObj = readObject(0, blockPositionClass);
}
try {
return (int) Reflection.getMethod(blockPosObj.getClass().getSuperclass(), "getZ", 0).invoke(blockPosObj);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return -1;
}
}
/**
* Get the direction / Get the face.
* @return Direction
*/
public Direction getDirection() {
if(isVersionLowerThan_v_1_8) {
return Direction.values()[readInt(3)];
}
else {
if(enumDirObj == null) {
enumDirObj = readObject(0, enumDirectionClass);
}
return Direction.valueOf(((Enum)enumDirObj).name());
}
}
/**
* 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.valueOf(((Enum)readObject(0, digTypeClass)).name());
}
}
public enum PlayerDigType {
START_DESTROY_BLOCK,
ABORT_DESTROY_BLOCK,
STOP_DESTROY_BLOCK,
DROP_ALL_ITEMS,
DROP_ITEM,
RELEASE_USE_ITEM,
SWAP_HELD_ITEMS,
SWAP_ITEM_WITH_OFFHAND,
WRONG_PACKET
}
}

View File

@ -0,0 +1,98 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.in.blockplace;
import io.github.retrooper.packetevents.enums.Direction;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
public final class WrappedPacketInBlockPlace extends WrappedPacket {
private static boolean isHigherThan_v_1_8_8, isHigherThan_v_1_7_10;
public WrappedPacketInBlockPlace(final Object packet) {
super(packet);
}
public static void load() {
isHigherThan_v_1_8_8 = version.isHigherThan(ServerVersion.v_1_8_8);
isHigherThan_v_1_7_10 = version.isHigherThan(ServerVersion.v_1_7_10);
WrappedPacketInBlockPlace_1_9.load();
}
public Direction getDirection() {
if (isHigherThan_v_1_8_8) {
WrappedPacketInBlockPlace_1_9 blockPlace_1_9 = new WrappedPacketInBlockPlace_1_9(packet);
return Direction.valueOf(((Enum) blockPlace_1_9.getEnumDirectionObject()).name());
} else if (isHigherThan_v_1_7_10) {
WrappedPacketInBlockPlace_1_8 blockPlace_1_8 = new WrappedPacketInBlockPlace_1_8(packet);
return Direction.values()[blockPlace_1_8.getFace()];
} else {
WrappedPacketInBlockPlace_1_7_10 blockPlace_1_7_10 = new WrappedPacketInBlockPlace_1_7_10(packet);
return Direction.values()[blockPlace_1_7_10.face];
}
}
public int getX() {
if (isHigherThan_v_1_8_8) {
WrappedPacketInBlockPlace_1_9 blockPlace_1_9 = new WrappedPacketInBlockPlace_1_9(packet);
return blockPlace_1_9.getX();
} else if (isHigherThan_v_1_7_10) {
WrappedPacketInBlockPlace_1_8 blockPlace_1_8 = new WrappedPacketInBlockPlace_1_8(packet);
return blockPlace_1_8.getX();
} else {
WrappedPacketInBlockPlace_1_7_10 blockPlace_1_7_10 = new WrappedPacketInBlockPlace_1_7_10(packet);
return blockPlace_1_7_10.x;
}
}
public int getY() {
if (isHigherThan_v_1_8_8) {
WrappedPacketInBlockPlace_1_9 blockPlace_1_9 = new WrappedPacketInBlockPlace_1_9(packet);
return blockPlace_1_9.getY();
} else if (isHigherThan_v_1_7_10) {
WrappedPacketInBlockPlace_1_8 blockPlace_1_8 = new WrappedPacketInBlockPlace_1_8(packet);
return blockPlace_1_8.getY();
} else {
WrappedPacketInBlockPlace_1_7_10 blockPlace_1_7_10 = new WrappedPacketInBlockPlace_1_7_10(packet);
return blockPlace_1_7_10.y;
}
}
public int getZ() {
if (isHigherThan_v_1_8_8) {
WrappedPacketInBlockPlace_1_9 blockPlace_1_9 = new WrappedPacketInBlockPlace_1_9(packet);
return blockPlace_1_9.getZ();
} else if (isHigherThan_v_1_7_10) {
WrappedPacketInBlockPlace_1_8 blockPlace_1_8 = new WrappedPacketInBlockPlace_1_8(packet);
return blockPlace_1_8.getZ();
} else {
WrappedPacketInBlockPlace_1_7_10 blockPlace_1_7_10 = new WrappedPacketInBlockPlace_1_7_10(packet);
return blockPlace_1_7_10.z;
}
}
}

View File

@ -0,0 +1,54 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.in.blockplace;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import org.bukkit.inventory.ItemStack;
final class WrappedPacketInBlockPlace_1_7_10 extends WrappedPacket {
public int x, y, z;
public ItemStack itemStack;
public int face;
WrappedPacketInBlockPlace_1_7_10(final Object packet) {
super(packet);
}
@Override
protected void setup() {
final net.minecraft.server.v1_7_R4.PacketPlayInBlockPlace blockPlace =
(net.minecraft.server.v1_7_R4.PacketPlayInBlockPlace) packet;
x = blockPlace.c();
y = blockPlace.d();
z = blockPlace.e();
this.face = blockPlace.d();
net.minecraft.server.v1_7_R4.ItemStack stack = blockPlace.getItemStack();
this.itemStack = org.bukkit.craftbukkit.v1_7_R4.inventory.CraftItemStack.asBukkitCopy(stack);
}
}

View File

@ -0,0 +1,85 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.in.blockplace;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.reflection.Reflection;
import org.bukkit.inventory.ItemStack;
import java.lang.reflect.InvocationTargetException;
final class WrappedPacketInBlockPlace_1_8 extends WrappedPacket {
private Object blockPosObj;
WrappedPacketInBlockPlace_1_8(final Object packet) {
super(packet);
}
public int getX() {
if(blockPosObj == null) {
blockPosObj = readObject(1, NMSUtils.blockPosClass);
}
try {
return (int) Reflection.getMethod(blockPosObj.getClass().getSuperclass(), "getX", 0).invoke(blockPosObj);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return 0;
}
public int getY() {
if(blockPosObj == null) {
blockPosObj = readObject(1, NMSUtils.blockPosClass);
}
try {
return (int) Reflection.getMethod(blockPosObj.getClass().getSuperclass(), "getY", 0).invoke(blockPosObj);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return 0;
}
public int getZ() {
if(blockPosObj == null) {
blockPosObj = readObject(1, NMSUtils.blockPosClass);
}
try {
return (int) Reflection.getMethod(blockPosObj.getClass().getSuperclass(), "getZ", 0).invoke(blockPosObj);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return 0;
}
public ItemStack getItemStack() {
return NMSUtils.toBukkitItemStack(readObject(0, NMSUtils.nmsItemStackClass));
}
public int getFace() {
return readInt(0);
}
}

View File

@ -0,0 +1,109 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.in.blockplace;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.reflection.Reflection;
import java.lang.reflect.InvocationTargetException;
final class WrappedPacketInBlockPlace_1_9 extends WrappedPacket {
private Object blockPosObj;
private static Class<?> movingObjectPositionBlockClass;
public static void load() {
movingObjectPositionBlockClass = NMSUtils.getNMSClassWithoutException("MovingObjectPositionBlock");
}
public WrappedPacketInBlockPlace_1_9(final Object packet) {
super(packet);
}
public int getX() {
if (blockPosObj == null) {
if (movingObjectPositionBlockClass == null) {
blockPosObj = readObject(0, NMSUtils.blockPosClass);
} else {
Object movingObjectPos = readObject(0, movingObjectPositionBlockClass);
WrappedPacket movingObjectPosWrapper = new WrappedPacket(movingObjectPos);
blockPosObj = movingObjectPosWrapper.readObject(0, NMSUtils.blockPosClass);
}
}
try {
return (int) Reflection.getMethod(blockPosObj.getClass().getSuperclass(), "getX", 0).invoke(blockPosObj);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return 0;
}
public int getY() {
if (blockPosObj == null) {
if (movingObjectPositionBlockClass == null) {
blockPosObj = readObject(0, NMSUtils.blockPosClass);
} else {
Object movingObjectPos = readObject(0, movingObjectPositionBlockClass);
WrappedPacket movingObjectPosWrapper = new WrappedPacket(movingObjectPos);
blockPosObj = movingObjectPosWrapper.readObject(0, NMSUtils.blockPosClass);
}
}
try {
return (int) Reflection.getMethod(blockPosObj.getClass().getSuperclass(), "getY", 0).invoke(blockPosObj);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return 0;
}
public int getZ() {
if (blockPosObj == null) {
if (movingObjectPositionBlockClass == null) {
blockPosObj = readObject(0, NMSUtils.blockPosClass);
} else {
Object movingObjectPos = readObject(0, movingObjectPositionBlockClass);
WrappedPacket movingObjectPosWrapper = new WrappedPacket(movingObjectPos);
blockPosObj = movingObjectPosWrapper.readObject(0, NMSUtils.blockPosClass);
}
}
try {
return (int) Reflection.getMethod(blockPosObj.getClass().getSuperclass(), "getZ", 0).invoke(blockPosObj);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return 0;
}
public Object getEnumDirectionObject() {
if (movingObjectPositionBlockClass == null) {
return readObject(0, NMSUtils.enumDirectionClass);
} else {
Object movingObjectPos = readObject(0, movingObjectPositionBlockClass);
WrappedPacket movingObjectPosWrapper = new WrappedPacket(movingObjectPos);
return movingObjectPosWrapper.readObject(0, NMSUtils.enumDirectionClass);
}
}
}

View File

@ -0,0 +1,42 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.in.chat;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
public final class WrappedPacketInChat extends WrappedPacket {
public WrappedPacketInChat(Object packet) {
super(packet);
}
/**
* Get the message.
*
* @return Chat Message
*/
public String getMessage() {
return readString(0);
}
}

View File

@ -0,0 +1,69 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.in.clientcommand;
import io.github.retrooper.packetevents.packettype.PacketTypeClasses;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.reflection.SubclassUtil;
public final class WrappedPacketInClientCommand extends WrappedPacket {
private static Class<?> enumClientCommandClass;
private Object enumObj;
public WrappedPacketInClientCommand(Object packet) {
super(packet);
}
public static void load() {
Class<?> packetClass = PacketTypeClasses.Client.CLIENT_COMMAND;
try {
enumClientCommandClass = NMSUtils.getNMSClass("EnumClientCommand");
} catch (ClassNotFoundException e) {
//Probably a subclass
enumClientCommandClass = SubclassUtil.getSubClass(packetClass, "EnumClientCommand");
}
}
/**
* Get the Client Command enum sent in the packet
*
* @return ClientCommand
*/
public ClientCommand getClientCommand() {
if(enumObj == null) {
enumObj = readObject(0, enumClientCommandClass);
}
return ClientCommand.valueOf(enumObj.toString());
}
public enum ClientCommand {
PERFORM_RESPAWN,
REQUEST_STATS,
OPEN_INVENTORY_ACHIEVEMENT
}
}

View File

@ -0,0 +1,82 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.in.custompayload;
import io.github.retrooper.packetevents.packettype.PacketTypeClasses;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.bytebuf.ByteBufUtil;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.reflection.Reflection;
public final class WrappedPacketInCustomPayload extends WrappedPacket {
private static Class<?> nmsMinecraftKey, packetDataSerializerClass, byteBufClass;
private static boolean strPresent, byteArrayPresent;
public WrappedPacketInCustomPayload(Object packet) {
super(packet);
}
public static void load() {
Class<?> packetClass = PacketTypeClasses.Client.CUSTOM_PAYLOAD;
strPresent = Reflection.getField(packetClass, String.class, 0) != null;
byteArrayPresent = Reflection.getField(packetClass, byte[].class, 0) != null;
packetDataSerializerClass = NMSUtils.getNMSClassWithoutException("PacketDataSerializer");
try {
byteBufClass = NMSUtils.getNettyClass("buffer.ByteBuf");
} catch (ClassNotFoundException ignored) {
}
try {
//Only on 1.13+
nmsMinecraftKey = NMSUtils.getNMSClass("MinecraftKey");
} catch (ClassNotFoundException e) {
//Its okay, this means they are on versions 1.7.10 - 1.12.2
}
}
public String getTag() {
if (strPresent) {
return readString(0);
} else {
Object minecraftKey = readObject(0, nmsMinecraftKey);
WrappedPacket minecraftKeyWrapper = new WrappedPacket(minecraftKey);
return minecraftKeyWrapper.readString(1);
}
}
public byte[] getData() {
if (byteArrayPresent) {
return readByteArray(0);
} else {
Object dataSerializer = readObject(0, packetDataSerializerClass);
WrappedPacket byteBufWrapper = new WrappedPacket(dataSerializer);
Object byteBuf = byteBufWrapper.readObject(0, byteBufClass);
return ByteBufUtil.getBytes(byteBuf);
}
}
}

View File

@ -0,0 +1,140 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.in.entityaction;
import io.github.retrooper.packetevents.annotations.Nullable;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.reflection.SubclassUtil;
import org.bukkit.entity.Entity;
import java.util.HashMap;
public final class WrappedPacketInEntityAction extends WrappedPacket {
private static final HashMap<String, PlayerAction> cachedPlayerActionNames = new HashMap<>();
private static final HashMap<Integer, PlayerAction> cachedPlayerActionIDs = new HashMap<>();
@Nullable
private static Class<?> enumPlayerActionClass;
private static boolean isLowerThan_v_1_8;
private Entity entity;
private int entityId = -1;
public WrappedPacketInEntityAction(final Object packet) {
super(packet);
}
public static void load() {
Class<?> entityActionClass = NMSUtils.getNMSClassWithoutException("PacketPlayInEntityAction");
isLowerThan_v_1_8 = version.isLowerThan(ServerVersion.v_1_8);
if (!isLowerThan_v_1_8) {
enumPlayerActionClass = SubclassUtil.getSubClass(entityActionClass, "EnumPlayerAction");
}
//All the already existing values
for (PlayerAction val : PlayerAction.values()) {
cachedPlayerActionNames.put(val.name(), val);
}
cachedPlayerActionNames.put("PRESS_SHIFT_KEY", PlayerAction.START_SNEAKING);
cachedPlayerActionNames.put("RELEASE_SHIFT_KEY", PlayerAction.STOP_SNEAKING);
cachedPlayerActionNames.put("RIDING_JUMP", PlayerAction.START_RIDING_JUMP);
cachedPlayerActionIDs.put(1, PlayerAction.START_SNEAKING);
cachedPlayerActionIDs.put(2, PlayerAction.STOP_SNEAKING);
cachedPlayerActionIDs.put(3, PlayerAction.STOP_SLEEPING);
cachedPlayerActionIDs.put(4, PlayerAction.START_SPRINTING);
cachedPlayerActionIDs.put(5, PlayerAction.STOP_SPRINTING);
cachedPlayerActionIDs.put(6, PlayerAction.START_RIDING_JUMP); //riding jump
cachedPlayerActionIDs.put(7, PlayerAction.OPEN_INVENTORY); //horse interaction
}
/**
* Lookup the associated entity by the ID that was sent in the packet.
*
* @return Entity
*/
public Entity getEntity() {
if(entity == null) {
return entity = NMSUtils.getEntityById(getEntityId());
}
return entity;
}
/**
* Get the ID of the entity.
* If you do not want to use {@link #getEntity()},
* you lookup the entity by yourself with this entity ID.
*
* @return Entity ID
*/
public int getEntityId() {
if(entityId == -1) {
entityId = readInt(0);
}
return entityId;
}
/**
* Get the player action.
*
* @return Player Action
*/
public PlayerAction getAction() {
if (isLowerThan_v_1_8) {
int animationIndex = readInt(1);
return cachedPlayerActionIDs.get(animationIndex);
} else {
final Object enumObj = readObject(0, enumPlayerActionClass);
final String enumValueName = enumObj.toString();
return cachedPlayerActionNames.get(enumValueName);
}
}
/**
* Get the jump boost integer.
*
* @return Jump Boost
*/
public int getJumpBoost() {
if (isLowerThan_v_1_8) {
return readInt(2);
} else {
return readInt(1);
}
}
public enum PlayerAction {
START_SNEAKING,
STOP_SNEAKING,
STOP_SLEEPING,
START_SPRINTING,
STOP_SPRINTING,
START_RIDING_JUMP,
STOP_RIDING_JUMP,
OPEN_INVENTORY,
START_FALL_FLYING
}
}

View File

@ -0,0 +1,66 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.in.flying;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
public class WrappedPacketInFlying extends WrappedPacket {
public WrappedPacketInFlying(Object packet) {
super(packet);
}
public double getX() {
return readDouble(0);
}
public double getY() {
return readDouble(1);
}
public double getZ() {
return readDouble(2);
}
public float getYaw() {
return readFloat(0);
}
public float getPitch() {
return readFloat(1);
}
public boolean isOnGround() {
return readBoolean(0);
}
public final boolean isPosition() {
return readBoolean(1);
}
public final boolean isLook() {
return readBoolean(2);
}
}

View File

@ -0,0 +1,42 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.in.helditemslot;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
public final class WrappedPacketInHeldItemSlot extends WrappedPacket {
public WrappedPacketInHeldItemSlot(Object packet) {
super(packet);
}
/**
* Get the index of the item we currently have in hand.
* @return Item in hand Index
*/
public int getCurrentSelectedSlot() {
return readInt(0);
}
}

View File

@ -0,0 +1,58 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.in.keepalive;
import io.github.retrooper.packetevents.packettype.PacketTypeClasses;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.reflection.Reflection;
public final class WrappedPacketInKeepAlive extends WrappedPacket {
private static boolean integerPresentInIndex0;
public WrappedPacketInKeepAlive(final Object packet) {
super(packet);
}
public static void load() {
Class<?> packetClass = PacketTypeClasses.Client.KEEP_ALIVE;
integerPresentInIndex0 = Reflection.getField(packetClass, int.class, 0) != null;
}
/**
* Get the ID response from the client.
*
* You may cast this down to an int if you are on 1.7.10 - 1.12.2.
* On 1.13.2 - 1.16.3 a long is sent.
* @return response ID
*/
public long getId() {
if(!integerPresentInIndex0) {
return readLong(0);
}
else {
return readInt(0);
}
}
}

View File

@ -0,0 +1,170 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.in.settings;
import io.github.retrooper.packetevents.annotations.Nullable;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.reflection.SubclassUtil;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
import java.util.HashMap;
public class WrappedPacketInSettings extends WrappedPacket {
private static Class<?> chatVisibilityEnumClass;
private static boolean isLowerThan_v_1_8;
private Object chatVisibilityEnumObj;
private HashMap<DisplayedSkinPart, Boolean> displayedSkinParts = new HashMap<>();
public WrappedPacketInSettings(final Object packet) {
super(packet);
}
public static void load() {
isLowerThan_v_1_8 = version.isLowerThan(ServerVersion.v_1_8);
try {
chatVisibilityEnumClass = NMSUtils.getNMSClass("EnumChatVisibility");
} catch (ClassNotFoundException e) {
Class<?> entityHumanClass = NMSUtils.getNMSClassWithoutException("EntityHuman");
//They are just on an outdated version
assert entityHumanClass != null;
chatVisibilityEnumClass = SubclassUtil.getSubClass(entityHumanClass, "EnumChatVisibility");
}
}
/**
* Get language client setting
*
* @return String Locale
*/
public String getLocale() {
return readString(0);
}
/**
* Get client view distance.
*
* @return View Distance
*/
public int getViewDistance() {
return readInt(0);
}
/**
* Get Chat Visibility
*
* @return Chat Visibility
*/
public ChatVisibility getChatVisibility() {
if (chatVisibilityEnumObj == null) {
chatVisibilityEnumObj = readObject(0, chatVisibilityEnumClass);
}
String enumValueAsString = chatVisibilityEnumObj.toString();
if (enumValueAsString.equals("FULL")) {
return ChatVisibility.ENABLED;
} else if (enumValueAsString.equals("SYSTEM")) {
return ChatVisibility.COMMANDS_ONLY;
} else {
return ChatVisibility.HIDDEN;
}
}
/**
* Is chat colors
*
* @return Chat Colors
*/
public boolean isChatColors() {
return readBoolean(0);
}
/**
* Get Displayed skin parts.
* <p>
* It is possible for some keys to not exist.
* If that is the case, the server version is 1.7.10.
* 1.7.10 only sends the cape skin part.
*
* @return A map with a Skin Parts as a key, and a boolean as a value.
*/
@Nullable
public HashMap<DisplayedSkinPart, Boolean> getDisplayedSkinPartsMap() {
if (displayedSkinParts.isEmpty()) {
if (isLowerThan_v_1_8) {
//in 1.7.10 only the cape display skin part is sent
boolean capeEnabled = readBoolean(1);
displayedSkinParts.put(DisplayedSkinPart.CAPE, capeEnabled);
} else {
//in 1.8, all the skin parts are sent
int skinPartFlags = readInt(1);
displayedSkinParts.put(DisplayedSkinPart.CAPE, (skinPartFlags & 0x01) != 0);
displayedSkinParts.put(DisplayedSkinPart.JACKET, (skinPartFlags & 0x02) != 0);
displayedSkinParts.put(DisplayedSkinPart.LEFT_SLEEVE, (skinPartFlags & 0x04) != 0);
displayedSkinParts.put(DisplayedSkinPart.RIGHT_SLEEVE, (skinPartFlags & 0x08) != 0);
displayedSkinParts.put(DisplayedSkinPart.LEFT_PANTS, (skinPartFlags & 0x10) != 0);
displayedSkinParts.put(DisplayedSkinPart.RIGHT_PANTS, (skinPartFlags & 0x20) != 0);
displayedSkinParts.put(DisplayedSkinPart.HAT, (skinPartFlags & 0x40) != 0);
}
}
return displayedSkinParts;
}
/**
* Is the skin part enabled.
* <p>
* On 1.7.10, some skin parts will default to 'false' as 1.7.10
* only sends the 'cape' skin part.
*
* @param part The skin part to check the status of.
* @return Is the skin part enabled
*/
public boolean isDisplaySkinPartEnabled(DisplayedSkinPart part) {
if(displayedSkinParts.isEmpty()) {
displayedSkinParts = getDisplayedSkinPartsMap();
}
//1.7.10, we will default the other skin parts to return false.
if (!displayedSkinParts.containsKey(part)) {
return false;
}
return displayedSkinParts.get(part);
}
/**
* Enum for the client chat visibility setting
*/
public enum ChatVisibility {
ENABLED, COMMANDS_ONLY, HIDDEN
}
/**
* Enum for the client displayed skin parts settings
*/
public enum DisplayedSkinPart {
CAPE, JACKET, LEFT_SLEEVE, RIGHT_SLEEVE, LEFT_PANTS, RIGHT_PANTS, HAT
}
}

View File

@ -0,0 +1,73 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.in.steervehicle;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
public class WrappedPacketInSteerVehicle extends WrappedPacket {
public WrappedPacketInSteerVehicle(Object packet) {
super(packet);
}
/**
* Get the side value.
* <p>
* If positive, they are moving to the left, if negative, they are moving to the right.
*
* @return Side Value
*/
public float getSideValue() {
return readFloat(0);
}
/**
* Get the forward value.
* <p>
* If positive, they are moving forward, if negative, they are moving backwards.
*
* @return Forward Value
*/
public float getForwardValue() {
return readFloat(1);
}
/**
* Is a Jump
*
* @return Is Jump
*/
public boolean isJump() {
return readBoolean(0);
}
/**
* Is an unmount
*
* @return Is Unmounting
*/
public boolean isUnmount() {
return readBoolean(1);
}
}

View File

@ -0,0 +1,60 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.in.transaction;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
public final class WrappedPacketInTransaction extends WrappedPacket {
public WrappedPacketInTransaction(final Object packet) {
super(packet);
}
/**
* Get the window ID.
*
* @return Window ID
*/
public int getWindowId() {
return readInt(0);
}
/**
* Get the action number.
*
* @return Action number
*/
public short getActionNumber() {
return readShort(0);
}
/**
* Is transaction accepted.
*
* @return Transaction Accepted
*/
public boolean isAccepted() {
return readBoolean(0);
}
}

View File

@ -0,0 +1,129 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.in.updatesign;
import io.github.retrooper.packetevents.packettype.PacketTypeClasses;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.packetwrappers.out.chat.WrappedPacketOutChat;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.reflection.Reflection;
import java.lang.reflect.InvocationTargetException;
public class WrappedPacketInUpdateSign extends WrappedPacket {
private static boolean v_1_7_mode, strArrayMode;
private static Class<?> blockPosClass, iChatBaseComponentClass;
private Object blockPosObj;
public static void load() {
v_1_7_mode = Reflection.getField(PacketTypeClasses.Client.UPDATE_SIGN, int.class, 0) != null;
strArrayMode = Reflection.getField(PacketTypeClasses.Client.UPDATE_SIGN, String[].class, 0) != null;
try {
blockPosClass = NMSUtils.getNMSClass("BlockPosition");
} catch (ClassNotFoundException e) {
if (!v_1_7_mode) {
e.printStackTrace();
}
}
try {
iChatBaseComponentClass = NMSUtils.getNMSClass("IChatBaseComponent");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public WrappedPacketInUpdateSign(Object packet) {
super(packet);
}
public int getX() {
if (v_1_7_mode) {
return readInt(0);
} else {
if (blockPosObj == null) {
blockPosObj = readObject(0, blockPosClass);
}
try {
return (int) Reflection.getMethod(blockPosObj.getClass().getSuperclass(), "getX", 0).invoke(blockPosObj);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return -1;
}
}
public int getY() {
if (v_1_7_mode) {
return readInt(1);
} else {
if (blockPosObj == null) {
blockPosObj = readObject(0, blockPosClass);
}
try {
return (int) Reflection.getMethod(blockPosObj.getClass().getSuperclass(), "getY", 0).invoke(blockPosObj);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return -1;
}
}
public int getZ() {
if (v_1_7_mode) {
return readInt(2);
} else {
if (blockPosObj == null) {
blockPosObj = readObject(0, blockPosClass);
}
try {
return (int) Reflection.getMethod(blockPosObj.getClass().getSuperclass(), "getZ", 0).invoke(blockPosObj);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return -1;
}
}
public String[] getTextLines() {
if (strArrayMode) {
//1.7.10 and the newest versions use this
return readStringArray(0);
} else {
//1.8 uses this for example
Object[] iChatComponents = (Object[]) readAnyObject(1);
String[] lines = new String[iChatComponents.length];
for (int i = 0; i < iChatComponents.length; i++) {
lines[i] = WrappedPacketOutChat.
toStringFromIChatBaseComponent(iChatComponents[i]);
}
return lines;
}
}
}

View File

@ -0,0 +1,92 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.in.useentity;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.player.ClientHand;
import io.github.retrooper.packetevents.utils.reflection.SubclassUtil;
import org.bukkit.entity.Entity;
public final class WrappedPacketInUseEntity extends WrappedPacket {
private static Class<?> enumEntityUseActionClass, enumHandClass;
private Entity entity;
private int entityID = -1;
public WrappedPacketInUseEntity(final Object packet) {
super(packet);
}
public static void load() {
Class<?> useEntityClass = NMSUtils.getNMSClassWithoutException("PacketPlayInUseEntity");
enumHandClass = NMSUtils.getNMSClassWithoutException("EnumHand");
try {
enumEntityUseActionClass = NMSUtils.getNMSClass("EnumEntityUseAction");
} catch (ClassNotFoundException e) {
//That is fine, it is probably a subclass
assert useEntityClass != null;
enumEntityUseActionClass = SubclassUtil.getSubClass(useEntityClass, "EnumEntityUseAction");
}
}
/**
* Lookup the associated entity by the ID that was sent in the packet.
* @return Entity
*/
public Entity getEntity() {
if(entity != null) {
return entity;
}
return entity = NMSUtils.getEntityById(getEntityID());
}
/**
* Get the ID of the entity.
* If you do not want to use {@link #getEntity()},
* you lookup the entity by yourself with this entity ID.
* @return Entity ID
*/
public int getEntityID() {
if(entityID != -1) {
return entityID;
}
else {
return entityID = readInt(0);
}
}
/**
* Get the associated action.
* @return Get EntityUseAction
*/
public EntityUseAction getAction() {
final Object useActionEnum = readObject(0, enumEntityUseActionClass);
return EntityUseAction.valueOf(useActionEnum.toString());
}
public enum EntityUseAction {
INTERACT, INTERACT_AT, ATTACK, INVALID
}
}

View File

@ -0,0 +1,53 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.in.vehiclemove;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
public class WrappedPacketInVehicleMove extends WrappedPacket {
public WrappedPacketInVehicleMove(Object packet) {
super(packet);
}
public double getX() {
return readDouble(0);
}
public double getY() {
return readDouble(1);
}
public double getZ() {
return readDouble(2);
}
public float getYaw() {
return readFloat(0);
}
public float getPitch() {
return readFloat(1);
}
}

View File

@ -0,0 +1,222 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.in.windowclick;
import io.github.retrooper.packetevents.packettype.PacketTypeClasses;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.reflection.Reflection;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
public class WrappedPacketInWindowClick extends WrappedPacket {
private static final HashMap<String, Integer> invClickTypeMapCache = new HashMap<>();
private static final HashMap<Integer, ArrayList<WindowClickType>> windowClickTypeCache = new HashMap<>();
private static Class<?> invClickTypeClass;
private static boolean isClickModePrimitive;
// TODO: All the fields below are useless cuz there is never a value assigned to them - change this
private int id;
private int slot;
private int button;
private short actionNumber;
private int mode;
private ItemStack clickedItem;
public WrappedPacketInWindowClick(Object packet) {
super(packet);
}
public static void load() {
Class<?> packetClass = PacketTypeClasses.Client.WINDOW_CLICK;
invClickTypeClass = NMSUtils.getNMSClassWithoutException("InventoryClickType");
invClickTypeMapCache.put("PICKUP", 0);
invClickTypeMapCache.put("QUICK_MOVE", 1);
invClickTypeMapCache.put("SWAP", 2);
invClickTypeMapCache.put("CLONE", 3);
invClickTypeMapCache.put("THROW", 4);
invClickTypeMapCache.put("QUICK_CRAFT", 5);
invClickTypeMapCache.put("PICKUP_ALL", 6);
//MODE 0
windowClickTypeCache.put(0, getArrayListOfWindowClickTypes(WindowClickType.LEFT_MOUSE_CLICK,
WindowClickType.RIGHT_MOUSE_CLICK));
//MODE 1
windowClickTypeCache.put(1, getArrayListOfWindowClickTypes(WindowClickType.SHIFT_LEFT_MOUSE_CLICK,
WindowClickType.SHIFT_RIGHT_MOUSE_CLICK));
//MODE 2
windowClickTypeCache.put(2, getArrayListOfWindowClickTypes(
WindowClickType.KEY_NUMBER1,
WindowClickType.KEY_NUMBER2,
WindowClickType.KEY_NUMBER3,
WindowClickType.KEY_NUMBER4,
WindowClickType.KEY_NUMBER5,
WindowClickType.KEY_NUMBER6,
WindowClickType.KEY_NUMBER7,
WindowClickType.KEY_NUMBER8,
WindowClickType.KEY_NUMBER9));
//MODE 3
windowClickTypeCache.put(3, getArrayListOfWindowClickTypes(WindowClickType.UNKNOWN, WindowClickType.UNKNOWN, WindowClickType.CREATIVE_MIDDLE_CLICK));
//MODE 4
windowClickTypeCache.put(4, getArrayListOfWindowClickTypes(WindowClickType.KEY_DROP,
WindowClickType.KEY_DROP_STACK));
//MODE 5
windowClickTypeCache.put(5, getArrayListOfWindowClickTypes(
WindowClickType.STARTING_LEFT_MOUSE_DRAG,
WindowClickType.ADD_SLOT_LEFT_MOUSE_DRAG,
WindowClickType.ENDING_LEFT_MOUSE_DRAG,
WindowClickType.UNKNOWN,
WindowClickType.STARTING_RIGHT_MOUSE_DRAG,
WindowClickType.ADD_SLOT_RIGHT_MOUSE_DRAG,
WindowClickType.CREATIVE_STARTING_MIDDLE_MOUSE_DRAG,
WindowClickType.ADD_SLOT_MIDDLE_MOUSE_DRAG,
WindowClickType.ENDING_MIDDLE_MOUSE_DRAG));
windowClickTypeCache.put(6, getArrayListOfWindowClickTypes(WindowClickType.DOUBLE_CLICK));
isClickModePrimitive = Reflection.getField(packetClass, int.class, 3) != null;
invClickTypeClass = NMSUtils.getNMSClassWithoutException("InventoryClickType");
}
private static ArrayList<WindowClickType> getArrayListOfWindowClickTypes(WindowClickType... types) {
ArrayList<WindowClickType> arrayList = new ArrayList<WindowClickType>(types.length);
arrayList.addAll(Arrays.asList(types));
return arrayList;
}
/**
* Get the Window ID.
* @return Get Window ID
*/
public int getWindowID() {
return readInt(0);
}
/**
* Get the Window slot.
* @return Get Window Slot
*/
public int getWindowSlot() {
return readInt(1);
}
/**
* Get the Window button.
* @return Get Window Button
*/
public int getWindowButton() {
return readInt(2);
}
/**
* Get the action number.
* @return Get Action Number
*/
public short getActionNumber() {
return readShort(0);
}
/**
* Get the window click type.
* @return Get Window Click Type
*/
public WindowClickType getWindowClickType() {
if (windowClickTypeCache.get(mode) == null) {
return WindowClickType.UNKNOWN;
}
if (button + 1 > windowClickTypeCache.size()) {
return WindowClickType.UNKNOWN;
}
// TODO: This has no use cuz the fields used are never getting assigned a value to them
if (mode == 4) {
if (slot == -999) {
if (button == 0) {
return WindowClickType.LEFT_CLICK_OUTSIDE_WINDOW_HOLDING_NOTHING;
} else if (button == 1) {
return WindowClickType.RIGHT_CLICK_OUTSIDE_WINDOW_HOLDING_NOTHING;
}
}
}
return windowClickTypeCache.get(mode).get(button);
}
/**
* Get the Window mode.
* @return Get Window Mode.
*/
public int getMode() {
if (isClickModePrimitive) {
return readInt(3);
} else {
return invClickTypeMapCache.get(readObject(5, invClickTypeClass).toString());
}
}
/**
* Get the clicked item.
* @return Get Clicked ItemStack
*/
public ItemStack getClickedItem() {
Object nmsItemStack = readObject(0, NMSUtils.nmsItemStackClass);
return NMSUtils.toBukkitItemStack(nmsItemStack);
}
public enum WindowClickType {
LEFT_MOUSE_CLICK, RIGHT_MOUSE_CLICK,
SHIFT_LEFT_MOUSE_CLICK, SHIFT_RIGHT_MOUSE_CLICK,
CREATIVE_MIDDLE_CLICK, CREATIVE_STARTING_MIDDLE_MOUSE_DRAG,
KEY_NUMBER1, KEY_NUMBER2, KEY_NUMBER3, KEY_NUMBER4,
KEY_NUMBER5, KEY_NUMBER6, KEY_NUMBER7, KEY_NUMBER8,
KEY_NUMBER9, KEY_DROP, KEY_DROP_STACK,
LEFT_CLICK_OUTSIDE_WINDOW_HOLDING_NOTHING,
RIGHT_CLICK_OUTSIDE_WINDOW_HOLDING_NOTHING,
STARTING_LEFT_MOUSE_DRAG,
STARTING_RIGHT_MOUSE_DRAG,
ADD_SLOT_LEFT_MOUSE_DRAG,
ADD_SLOT_RIGHT_MOUSE_DRAG,
ADD_SLOT_MIDDLE_MOUSE_DRAG,
ENDING_LEFT_MOUSE_DRAG,
ENDING_RIGHT_MOUSE_DRAG,
ENDING_MIDDLE_MOUSE_DRAG,
DOUBLE_CLICK,
UNKNOWN
}
}

View File

@ -0,0 +1,45 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.login.in;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
public class WrappedPacketLoginHandshake extends WrappedPacket {
public WrappedPacketLoginHandshake(Object packet) {
super(packet);
}
public int getProtocolVersion() {
return readInt(0);
}
public String getHostName() {
return readString(0);
}
public int getPort() {
return readInt(1);
}
}

View File

@ -0,0 +1,42 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.login.in;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
public class WrappedPacketLoginInCustomPayload extends WrappedPacket {
public WrappedPacketLoginInCustomPayload(Object packet) {
super(packet);
}
/* TODO wrappers
* net.minecraft.server.v1_16_R2.PacketLoginInCustomPayload inCP;
* net.minecraft.server.v1_16_R2.PacketLoginOutCustomPayload outCP;
* net.minecraft.server.v1_16_R2.PacketPlayOutLogin outLogin;
* Find out about the Status Response packet
*/
}

View File

@ -0,0 +1,40 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.login.in;
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(Object packet) {
super(packet);
}
public WrappedGameProfile getGameProfile() {
return GameProfileUtil.getWrappedGameProfile(readObject(0, NMSUtils.gameProfileClass));
}
}

View File

@ -0,0 +1,41 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.login.in;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
public class WrapppedPacketLoginInEncryptionBegin extends WrappedPacket {
public WrapppedPacketLoginInEncryptionBegin(Object packet) {
super(packet);
}
public byte[] getPublicKey() {
return readByteArray(0);
}
public byte[] getVerifyToken() {
return readByteArray(1);
}
}

View File

@ -0,0 +1,37 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.status;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
public class WrappedPacketStatusPing extends WrappedPacket {
public WrappedPacketStatusPing(Object packet) {
super(packet);
}
public long getPayload() {
return readLong(0);
}
}

View File

@ -0,0 +1,37 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.status;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
public class WrappedPacketStatusPong extends WrappedPacket {
public WrappedPacketStatusPong(Object packet) {
super(packet);
}
public long getPayload() {
return readLong(0);
}
}

View File

@ -0,0 +1,92 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.settings;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
public class PacketEventsSettings {
private ServerVersion backupServerVersion = ServerVersion.v_1_7_10;
private boolean injectAsync = true;
private boolean ejectAsync = true;
private boolean checkForUpdates = true;
private boolean injectEarly = true;
private int packetHandlingThreadCount = 1;
public PacketEventsSettings backupServerVersion(ServerVersion serverVersion) {
this.backupServerVersion = serverVersion;
return this;
}
public PacketEventsSettings injectAsync(boolean injectAsync) {
this.injectAsync = injectAsync;
return this;
}
public PacketEventsSettings ejectAsync(boolean ejectAsync) {
this.ejectAsync = ejectAsync;
return this;
}
public PacketEventsSettings checkForUpdates(boolean checkForUpdates) {
this.checkForUpdates = checkForUpdates;
return this;
}
public PacketEventsSettings injectEarly(boolean injectEarly) {
this.injectEarly = injectEarly;
return this;
}
public PacketEventsSettings packetHandlingThreadCount(int threadCount) {
this.packetHandlingThreadCount = threadCount;
return this;
}
public ServerVersion getBackupServerVersion() {
return backupServerVersion;
}
public boolean shouldInjectAsync() {
return injectAsync;
}
public boolean shouldEjectAsync() {
return ejectAsync;
}
public boolean shouldCheckForUpdates() {
return checkForUpdates;
}
public boolean shouldInjectEarly() {
return injectEarly;
}
public int getPacketHandlingThreadCount() {
return packetHandlingThreadCount;
}
}

View File

@ -0,0 +1,79 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.updatechecker;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.utils.server.PEVersion;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
public class UpdateChecker {
public void handleUpdate() {
PEVersion localVersion = PacketEvents.getVersion();
inform("[PacketEvents] Checking for an update, please wait...");
String line;
try {
line = readLatestVersion();
} catch (IOException exception) {
report("[PacketEvents] We failed to find the latest released version of PacketEvents. Your build: (" + localVersion.toString() + ")");
return;
}
PEVersion newVersion = new PEVersion(line);
if (localVersion.isOlder(newVersion)) {
inform("[PacketEvents] There is an update available for the PacketEvents API! Your build: (" + localVersion.toString() + ") | Latest released build: (" + newVersion.toString() + ")");
} else if (localVersion.isNewer(newVersion)) {
inform("[PacketEvents] You are on a dev or pre released build of PacketEvents. Your build: (" + localVersion.toString() + ") | Latest released build: (" + newVersion.toString() + ")");
}
else if (localVersion.equals(newVersion)) {
inform("[PacketEvents] You are on the latest released version of PacketEvents. (" + newVersion.toString() + ")");
}
else {
report("[PacketEvents] Something went wrong while checking for an update. Your build: (" + localVersion.toString() + ") | Latest released build: (" + newVersion.toString() + ")");
}
}
private void inform(String message) {
Bukkit.getLogger().info(message);
}
private void report(String message) {
Bukkit.getLogger().info(ChatColor.DARK_RED + message);
}
private String readLatestVersion() throws IOException {
URLConnection connection = new URL("https://api.spigotmc.org/legacy/update.php?resource=80279").openConnection();
connection.addRequestProperty("User-Agent", "Mozilla/4.0");
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line = reader.readLine();
reader.close();
return line;
}
}

View File

@ -0,0 +1,46 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.bytebuf;
import io.github.retrooper.packetevents.packetmanager.netty.NettyPacketManager;
public class ByteBufUtil {
public static Object copiedBuffer(byte[] bytes) {
if (NettyPacketManager.v1_7_nettyMode) {
return ByteBufUtil_7.copiedBuffer(bytes);
} else {
return ByteBufUtil_8.copiedBuffer(bytes);
}
}
public static byte[] getBytes(Object byteBuf) {
if(NettyPacketManager.v1_7_nettyMode) {
return ByteBufUtil_7.getBytes(byteBuf);
}
else {
return ByteBufUtil_8.getBytes(byteBuf);
}
}
}

View File

@ -0,0 +1,46 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.bytebuf;
import net.minecraft.util.io.netty.buffer.ByteBuf;
import net.minecraft.util.io.netty.buffer.Unpooled;
class ByteBufUtil_7 {
public static Object copiedBuffer(byte[] bytes) {
return Unpooled.copiedBuffer(bytes);
}
public static byte[] getBytes(Object byteBuf) {
ByteBuf bb = (ByteBuf)byteBuf;
byte[] bytes;
if (bb.hasArray()) {
bytes = bb.array();
} else {
bytes = new byte[bb.readableBytes()];
bb.getBytes(bb.readerIndex(), bytes);
}
return bytes;
}
}

View File

@ -0,0 +1,46 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.bytebuf;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
class ByteBufUtil_8 {
public static Object copiedBuffer(byte[] bytes) {
return Unpooled.copiedBuffer(bytes);
}
public static byte[] getBytes(Object byteBuf) {
ByteBuf bb = (ByteBuf)byteBuf;
byte[] bytes;
if (bb.hasArray()) {
bytes = bb.array();
} else {
bytes = new byte[bb.readableBytes()];
bb.getBytes(bb.readerIndex(), bytes);
}
return bytes;
}
}

View File

@ -0,0 +1,121 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.entityfinder;
import io.github.retrooper.packetevents.annotations.Nullable;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public final class EntityFinderUtils {
public static ServerVersion version;
private static Class<?> worldServerClass;
private static Class<?> craftWorldClass;
private static Class<?> entityClass;
private static Method getEntityByIdMethod;
private static Method craftWorldGetHandle;
private static Method getBukkitEntity;
private static boolean isServerVersion_v_1_8_x;
public static void load() {
try {
worldServerClass = NMSUtils.getNMSClass("WorldServer");
craftWorldClass = NMSUtils.getOBCClass("CraftWorld");
entityClass = NMSUtils.getNMSClass("Entity");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
getEntityByIdMethod = worldServerClass.getMethod((version.getProtocolVersion() == (short) 47)
? "a" : "getEntity", int.class);
craftWorldGetHandle = craftWorldClass.getMethod("getHandle");
getBukkitEntity = entityClass.getMethod("getBukkitEntity");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
/**
* Get an entity by their ID.
* @param id
* @return Entity
*/
public static Entity getEntityById(final int id) {
for (final World world : Bukkit.getWorlds()) {
final Entity entity = getEntityByIdWithWorld(world, id);
if (entity != null) {
return entity;
}
}
return null;
}
/**
* Get an entity by their ID, guaranteed to be in the specified world.
* @param world
* @param id
* @return Entity
*/
@Nullable
public static Entity getEntityByIdWithWorld(final World world, final int id) {
if (world == null) {
return null;
}
else if(craftWorldClass == null) {
throw new IllegalStateException("PacketEvents failed to locate the CraftWorld class.");
}
Object craftWorld = craftWorldClass.cast(world);
Object worldServer = null;
try {
worldServer = craftWorldGetHandle.invoke(craftWorld);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
Object nmsEntity = null;
try {
nmsEntity = getEntityByIdMethod.invoke(worldServer, id);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
if (nmsEntity == null) {
return null;
}
try {
return (Entity) getBukkitEntity.invoke(nmsEntity);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}

View File

@ -0,0 +1,49 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.gameprofile;
import io.github.retrooper.packetevents.packetmanager.netty.NettyPacketManager;
import java.util.UUID;
public class GameProfileUtil {
public static Object getGameProfile(UUID uuid, String username) {
if(NettyPacketManager.v1_7_nettyMode) {
return GameProfileUtil_7.getGameProfile(uuid, username);
}
else {
return GameProfileUtil_8.getGameProfile(uuid, username);
}
}
public static WrappedGameProfile getWrappedGameProfile(Object gameProfile) {
if(NettyPacketManager.v1_7_nettyMode) {
return GameProfileUtil_7.getWrappedGameProfile(gameProfile);
}
else {
return GameProfileUtil_8.getWrappedGameProfile(gameProfile);
}
}
}

View File

@ -0,0 +1,40 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.gameprofile;
import net.minecraft.util.com.mojang.authlib.GameProfile;
import java.util.UUID;
class GameProfileUtil_7 {
public static Object getGameProfile(UUID uuid, String username) {
return new GameProfile(uuid, username);
}
public static WrappedGameProfile getWrappedGameProfile(Object gameProfile) {
GameProfile gp = (GameProfile) gameProfile;
return new WrappedGameProfile(gp.getId(), gp.getName(), gp.isLegacy());
}
}

View File

@ -0,0 +1,40 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.gameprofile;
import com.mojang.authlib.GameProfile;
import java.util.UUID;
class GameProfileUtil_8 {
public static Object getGameProfile(UUID uuid, String username) {
return new GameProfile(uuid, username);
}
public static WrappedGameProfile getWrappedGameProfile(Object gameProfile) {
GameProfile gp = (GameProfile)gameProfile;
return new WrappedGameProfile(gp.getId(), gp.getName(), gp.isLegacy());
}
}

View File

@ -0,0 +1,67 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.gameprofile;
import java.util.UUID;
public class WrappedGameProfile {
public UUID id;
public String name;
public boolean legacy;
public WrappedGameProfile(UUID id, String name, boolean legacy) {
this.id = id;
this.name = name;
this.legacy = legacy;
}
public UUID getId() {
return id;
}
public String getName() {
return name;
}
public boolean isLegacy() {
return legacy;
}
public boolean isComplete() {
return id != null && !isBlank(name);
}
private boolean isBlank(CharSequence cs) {
int strLen;
if (cs != null && (strLen = cs.length()) != 0) {
for (int i = 0; i < strLen; ++i) {
if (!Character.isWhitespace(cs.charAt(i))) {
return false;
}
}
}
return true;
}
}

View File

@ -0,0 +1,314 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.nms;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.annotations.Nullable;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.entityfinder.EntityFinderUtils;
import io.github.retrooper.packetevents.utils.reflection.Reflection;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.UUID;
public final class NMSUtils {
public static ServerVersion version;
private static final String nmsDir = ServerVersion.getNMSDirectory();
private static final String obcDir = ServerVersion.getOBCDirectory();
public static String nettyPrefix = "io.netty";
public static Class<?> nmsEntityClass, minecraftServerClass, craftWorldClass, playerInteractManagerClass, entityPlayerClass, playerConnectionClass, craftServerClass,
craftPlayerClass, serverConnectionClass, craftEntityClass,
craftItemStack, nmsItemStackClass, networkManagerClass, nettyChannelClass, gameProfileClass, iChatBaseComponentClass,
blockPosClass, enumDirectionClass;
private static Method craftWorldGetHandle;
private static Method getCraftPlayerHandle;
private static Method getCraftEntityHandle;
private static Method asBukkitCopy;
private static Method getBukkitEntity;
private static Field entityPlayerPingField, playerConnectionField;
public static final HashMap<UUID, Object> channelCache = new HashMap<>();
public static void load() {
try {
Class.forName(nettyPrefix + ".channel.Channel");
} catch (ClassNotFoundException e) {
nettyPrefix = "net.minecraft.util.io.netty";
try {
Class.forName(nettyPrefix + ".channel.Channel");
} catch (ClassNotFoundException e2) {
throw new IllegalStateException("PacketEvents failed to locate Netty's location.");
}
}
try {
nettyChannelClass = getNettyClass("channel.Channel");
nmsEntityClass = getNMSClass("Entity");
minecraftServerClass = getNMSClass("MinecraftServer");
craftWorldClass = getOBCClass("CraftWorld");
craftPlayerClass = getOBCClass("entity.CraftPlayer");
craftServerClass = getOBCClass("CraftServer");
entityPlayerClass = getNMSClass("EntityPlayer");
playerConnectionClass = getNMSClass("PlayerConnection");
serverConnectionClass = getNMSClass("ServerConnection");
craftEntityClass = getOBCClass("entity.CraftEntity");
craftItemStack = getOBCClass("inventory.CraftItemStack");
nmsItemStackClass = getNMSClass("ItemStack");
networkManagerClass = getNMSClass("NetworkManager");
playerInteractManagerClass = getNMSClass("PlayerInteractManager");
try {
gameProfileClass = Class.forName("com.mojang.authlib.GameProfile");
} catch (ClassNotFoundException e) {
gameProfileClass = Class.forName("net.minecraft.util.com.mojang.authlib.GameProfile");
}
iChatBaseComponentClass = NMSUtils.getNMSClass("IChatBaseComponent");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
blockPosClass = NMSUtils.getNMSClassWithoutException("BlockPosition");
enumDirectionClass = NMSUtils.getNMSClassWithoutException("EnumDirection");
//METHODS
try {
getCraftPlayerHandle = craftPlayerClass.getMethod("getHandle");
getCraftEntityHandle = craftEntityClass.getMethod("getHandle");
asBukkitCopy = craftItemStack.getMethod("asBukkitCopy", nmsItemStackClass);
craftWorldGetHandle = craftWorldClass.getMethod("getHandle");
getBukkitEntity = nmsEntityClass.getMethod("getBukkitEntity");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
entityPlayerPingField = entityPlayerClass.getField("ping");
playerConnectionField = entityPlayerClass.getField("playerConnection");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
public static Object getMinecraftServerInstance() throws InvocationTargetException, IllegalAccessException {
return Reflection.getMethod(minecraftServerClass, "getServer", 0).invoke(null);
}
public static Object getMinecraftServerConnection() {
WrappedPacket wrapper = null;
try {
wrapper = new WrappedPacket(getMinecraftServerInstance());
} catch (InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
if (wrapper == null) {
return null;
}
return wrapper.readObject(0, serverConnectionClass);
}
public static double[] recentTPS() throws IllegalAccessException, InvocationTargetException {
final Object minecraftServerObj = getMinecraftServerInstance();
return (double[]) Reflection.getField(minecraftServerClass, double[].class, 0).get(minecraftServerObj);
}
public static Class<?> getNMSClass(String name) throws ClassNotFoundException {
return Class.forName(nmsDir + "." + name);
}
public static Class<?> getNMSClassWithoutException(String name) {
try {
return getNMSClass(name);
} catch (ClassNotFoundException e) {
return null;
}
}
public static Class<?> getOBCClass(String name) throws ClassNotFoundException {
return Class.forName(obcDir + "." + name);
}
public static Class<?> getNettyClass(String name) throws ClassNotFoundException {
return Class.forName(nettyPrefix + "." + name);
}
public static String getChannelFutureListFieldName() {
if (version.isLowerThan(ServerVersion.v_1_8)) {
return "e";
}
if (version.isLowerThan(ServerVersion.v_1_13)) {
return "g";
}
return "f";
}
@Nullable
public static Entity getEntityById(final int id) {
return EntityFinderUtils.getEntityById(id);
}
@Nullable
public static Entity getEntityByIdWithWorld(final World world, final int id) {
return EntityFinderUtils.getEntityByIdWithWorld(world, id);
}
public static Object getNMSEntity(final Entity entity) {
final Object craftEntity = craftEntityClass.cast(entity);
try {
return getCraftEntityHandle.invoke(craftEntity);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
public static Entity getBukkitEntity(final Object nmsEntity) {
try {
return (Entity) getBukkitEntity.invoke(nmsEntity);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
public static Object getCraftPlayer(final Player player) {
return craftPlayerClass.cast(player);
}
public static Object getEntityPlayer(final Player player) {
try {
return getCraftPlayerHandle.invoke(getCraftPlayer(player));
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
public static Object getPlayerConnection(final Player player) {
try {
return playerConnectionField.get(getEntityPlayer(player));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
public static Object getNetworkManager(final Player player) {
WrappedPacket wrapper = new WrappedPacket(getPlayerConnection(player));
return wrapper.readObject(0, networkManagerClass);
}
public static Object getChannel(final Player player) {
if (PacketEvents.getAPI().packetManager.tinyProtocol == null) {
UUID uuid = player.getUniqueId();
Object channel = channelCache.get(uuid);
if (channel == null) {
Object newChannel = getChannelNoCache(player);
channelCache.put(uuid, newChannel);
return newChannel;
}
return channel;
} else {
return PacketEvents.getAPI().packetManager.tinyProtocol.getChannel(player);
}
}
public static Object getChannelNoCache(final Player player) {
if (PacketEvents.getAPI().packetManager.tinyProtocol == null) {
WrappedPacket wrapper = new WrappedPacket(getNetworkManager(player));
return wrapper.readObject(0, nettyChannelClass);
} else {
return PacketEvents.getAPI().packetManager.tinyProtocol.getChannel(player);
}
}
public static int getPlayerPing(final Player player) {
Object entityPlayer = getEntityPlayer(player);
try {
return entityPlayerPingField.getInt(entityPlayer);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return -1;
}
public static ItemStack toBukkitItemStack(final Object nmsItemstack) {
try {
return (ItemStack) asBukkitCopy.invoke(null, nmsItemstack);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
public static Object convertBukkitServerToNMSServer(Server server) {
Object craftServer = craftServerClass.cast(server);
WrappedPacket wrapper = new WrappedPacket(craftServer);
return wrapper.readObject(0, minecraftServerClass);
}
public static Object convertBukkitWorldToNMSWorld(World world) {
Object craftWorld = craftWorldClass.cast(world);
try {
return craftWorldGetHandle.invoke(craftWorld);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
public static Object createNewEntityPlayer(Server server, World world, Object gameProfile) {
Object nmsServer = convertBukkitServerToNMSServer(server);
Object nmsWorld = convertBukkitWorldToNMSWorld(world);
return privateCreateNewEntityPlayer(nmsServer, nmsWorld, gameProfile);
}
private static Object privateCreateNewEntityPlayer(Object nmsServer, Object nmsWorld, Object gameProfile) {
Object playerInteractManager = null;
try {
playerInteractManager = playerInteractManagerClass.getConstructor(nmsWorld.getClass()).newInstance(nmsWorld);
} catch (InstantiationException | IllegalAccessException
| InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
try {
return entityPlayerClass.getConstructor(nmsServer.getClass(), nmsWorld.getClass(),
gameProfile.getClass(), playerConnectionClass).
newInstance(nmsServer, nmsWorld, gameProfile, playerInteractManager);
} catch (InstantiationException | IllegalAccessException
| InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
}

View File

@ -0,0 +1,30 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.player;
public enum ClientHand {
MAIN_HAND,
OFF_HAND;
}

View File

@ -0,0 +1,117 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.player;
public enum ClientVersion {
LOWER_THAN_SUPPORTED_VERSIONS(4),
v_1_7_10(5),
v_1_8(47),
v_1_9(107),
v_1_9_1(108),
v_1_9_2(109),
v_1_9_3(110),
v_1_10(210),
v_1_11(315),
v_1_11_1(316),
v_1_12(335),
v_1_12_1(338),
v_1_12_2(340),
v_1_13(393),
v_1_13_1(401),
v_1_13_2(404),
v_1_14(477),
v_1_14_1(480),
v_1_14_2(485),
v_1_14_3(490),
v_1_14_4(498),
v_1_15(573),
v_1_15_1(575),
v_1_15_2(578),
v_1_16(735),
v_1_16_1(736),
v_1_16_2(751),
v_1_16_3(753),
v_1_16_4(754),
HIGHER_THAN_SUPPORTED_VERSIONS(755),
/**
* Pre releases just aren't supported, we would end up with so many enum constants.
*/
ANY_PRE_RELEASE_VERSION(0),
UNRESOLVED(-1);
private final int protocolVersion;
private static final int lowestSupportedProtocolVersion = LOWER_THAN_SUPPORTED_VERSIONS.protocolVersion;
private static final int highestSupportedProtocolVersion = HIGHER_THAN_SUPPORTED_VERSIONS.protocolVersion;
ClientVersion(int protocolVersion) {
this.protocolVersion = protocolVersion;
}
public int getProtocolVersion() {
return protocolVersion;
}
public static boolean isHigherThan(ClientVersion a, ClientVersion b) {
return a.getProtocolVersion() > b.getProtocolVersion();
}
public static boolean isLowerThan(ClientVersion a, ClientVersion b) {
return a.getProtocolVersion() < b.getProtocolVersion();
}
public boolean isHigherThan(ClientVersion target) {
return protocolVersion > target.getProtocolVersion();
}
public boolean isLowerThan(ClientVersion target) {
return protocolVersion < target.getProtocolVersion();
}
public boolean equals(ClientVersion target) {
return protocolVersion == target.getProtocolVersion();
}
public static ClientVersion getClientVersion(int protocolVersion) {
if (protocolVersion == -1) {
return ClientVersion.UNRESOLVED;
}
for (ClientVersion version : ClientVersion.values()) {
if (version.protocolVersion > protocolVersion) {
break;
} else if (version.protocolVersion == protocolVersion) {
return version;
}
}
if (protocolVersion <= lowestSupportedProtocolVersion) {
return LOWER_THAN_SUPPORTED_VERSIONS;
} else if (protocolVersion >= highestSupportedProtocolVersion) {
return HIGHER_THAN_SUPPORTED_VERSIONS;
} else {
return ANY_PRE_RELEASE_VERSION;
}
}
}

View File

@ -0,0 +1,121 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.player;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.event.impl.PlayerEjectEvent;
import io.github.retrooper.packetevents.packetwrappers.SendableWrapper;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.UUID;
public final class PlayerUtils {
public final HashMap<UUID, Short> playerPingMap = new HashMap<>();
public final HashMap<UUID, Short> playerSmoothedPingMap = new HashMap<>();
/**
* This map stores each player's client version.
*/
public final HashMap<Object, ClientVersion> clientVersionsMap = new HashMap<>();
/**
* Use reflection to read the ping value NMS calculates for the player.
* NMS smooths the player ping.
* @param player
* @return Get NMS smoothed Player Ping
*/
public int getNMSPing(final Player player) {
return NMSUtils.getPlayerPing(player);
}
/**
* Use the ping PacketEvents calculates for the player. (Updates every incoming Keep Alive packet)
* @param player Player
* @return Get Ping
*/
public short getPing(final Player player) {
return playerPingMap.getOrDefault(player.getUniqueId(), (short)0);
}
public short getSmoothedPing(final Player player) {
return playerSmoothedPingMap.getOrDefault(player.getUniqueId(), (short)0);
}
public short getPing(UUID uuid) {
return playerPingMap.getOrDefault(uuid, (short)0);
}
public short getSmoothedPing(UUID uuid) {
return playerSmoothedPingMap.getOrDefault(uuid, (short)0);
}
/**
* Get the client version by a player object.
* @param player
* @return Get Client Version
*/
public ClientVersion getClientVersion(final Player player) {
return clientVersionsMap.get(NMSUtils.getChannel(player));
}
/**
* Inject a player.
*
* (This also calls the {@link io.github.retrooper.packetevents.event.impl.PlayerInjectEvent})
* @param player
*/
public void injectPlayer(final Player player) {
PacketEvents.getAPI().packetManager.injectPlayer(player);
}
/**
* Eject a player.
* (This also calls the {@link PlayerEjectEvent})
* @param player
*/
public void ejectPlayer(final Player player) {
PacketEvents.getAPI().packetManager.ejectPlayer(player);
}
/**
* Send a {@link SendableWrapper} wrapper to a player.
* @param player
* @param sendableWrapper
*/
public void sendPacket(final Player player, final SendableWrapper sendableWrapper) {
PacketEvents.getAPI().packetManager.sendPacket(NMSUtils.getChannel(player), sendableWrapper.asNMSPacket());
}
/**
* Send a raw NMS packet to a player.
* @param player
* @param nmsPacket
*/
public void sendNMSPacket(final Player player, Object nmsPacket) {
PacketEvents.getAPI().packetManager.sendPacket(NMSUtils.getChannel(player), nmsPacket);
}
}

View File

@ -0,0 +1,43 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.reflection;
import java.util.HashMap;
import java.util.Map;
public class ClassUtil {
private static final Map<String, String> classSimpleNameCache = new HashMap<>();
public static String getClassSimpleName(Class<?> cls) {
final String className = cls.getName();
final String simpleClassName;
if (!classSimpleNameCache.containsKey(className)) {
classSimpleNameCache.put(className, simpleClassName = cls.getSimpleName());
} else {
simpleClassName = classSimpleNameCache.get(className);
}
return simpleClassName;
}
}

View File

@ -0,0 +1,138 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.reflection;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
public final class Reflection {
//FIELDS
@Deprecated
public static Field[] getFields(Class<?> cls) {
Field[] declaredFields = cls.getDeclaredFields();
for (Field f : declaredFields) {
f.setAccessible(true);
}
return declaredFields;
}
@Deprecated
public static Field getField(final Class<?> cls, final String name) {
for (final Field f : getFields(cls)) {
if (f.getName().equals(name)) {
return f;
}
}
return null;
}
@Deprecated
public static Field getField(final Class<?> cls, final Class<?> dataType, final int index) {
int currentIndex = 0;
for (final Field f : getFields(cls)) {
if (f.getType().equals(dataType)) {
if (currentIndex++ == index) {
return f;
}
}
}
return null;
}
@Deprecated
public static Field getField(final Class<?> cls, final int index) {
return getFields(cls)[index];
}
//METHODS
public static Method[] getMethods(final Class<?> cls) {
Method[] declaredMethods = cls.getDeclaredMethods();
for (Method m : declaredMethods) {
m.setAccessible(true);
}
return declaredMethods;
}
public static Method getMethod(final Class<?> cls, final int index, final Class<?>... params) {
int currentIndex = 0;
for (final Method m : getMethods(cls)) {
if (Arrays.equals(m.getParameterTypes(), params) && index == currentIndex++) {
return m;
}
}
return null;
}
public static Method getMethod(Class<?> cls, Class<?> returning, int index, Class<?>... params) {
int currentIndex = 0;
for(Method m : getMethods(cls)) {
if(Arrays.equals(m.getParameterTypes(), params) && m.getReturnType().equals(returning) && index == currentIndex++) {
return m;
}
}
return null;
}
public static Method getMethod(final Class<?> cls, final String name, Class<?> returning, Class<?>... params) {
for (final Method m : getMethods(cls)) {
if (m.getName().equals(name) && Arrays.equals(m.getParameterTypes(), params) && m.getReturnType().equals(returning)) {
return m;
}
}
return null;
}
public static Method getMethod(final Class<?> cls, final String name, final int index) {
int currentIndex = 0;
for (final Method m : getMethods(cls)) {
if (m.getName().equals(name) && index == currentIndex++) {
return m;
}
}
return null;
}
public static Method getMethod(final Class<?> cls, final Class<?> returning, final int index) {
int currentIndex = 0;
for (final Method m : getMethods(cls)) {
if (returning.equals(m.getReturnType()) && index == currentIndex++) {
return m;
}
}
return null;
}
public static Method getMethod(final Class<?> cls, final String name, final Class<?> returning) {
for (final Method m : getMethods(cls)) {
if (m.getName().equals(name) && m.getReturnType().equals(returning)) {
return m;
}
}
return null;
}
}

View File

@ -0,0 +1,60 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.reflection;
import java.lang.annotation.Annotation;
public class SubclassUtil {
public static Class<?> getSubClass(Class<?> cls, String name) {
for (Class<?> subClass : cls.getDeclaredClasses()) {
if (ClassUtil.getClassSimpleName(subClass).equals(name)) {
return subClass;
}
}
return null;
}
public static Class<?> getSubClass(Class<?> cls, int index) {
int currentIndex = 0;
for (Class<?> subClass : cls.getDeclaredClasses()) {
if (index == currentIndex++) {
return subClass;
}
}
return null;
}
public static Class<?> getSubClass(Class<?> cls, Annotation annotation, int index) {
int currentIndex = 0;
for(Class<?> subClass : cls.getDeclaredClasses()) {
if(subClass.getAnnotation(annotation.getClass()) != null) {
if(index == currentIndex++) {
return subClass;
}
}
}
return null;
}
}

View File

@ -0,0 +1,142 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.server;
import java.util.Arrays;
import java.util.List;
//I was lazy while making this class, I know
public class PEVersion {
private final int[] version = new int[4];
public PEVersion(int... version) throws IllegalArgumentException {
if (version.length > 4) {
throw new IllegalArgumentException("You are not allowed to have more than 4 arguments!");
} else if (version.length < 2) {
throw new IllegalArgumentException("You need at least two arguments.");
}
System.arraycopy(version, 0, this.version, 0, version.length);
}
public PEVersion(String text) {
this(stringConstructor(text));
}
private static int[] stringConstructor(String text) {
//1.2.3.4
text += ".";
char[] chars = text.toCharArray();
//1.2.3.4.
int arrayIndex = 0;
int[] version = new int[4];
// String t = "1.2.3.4";
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
if (c == '.') {
version[arrayIndex++] =
Integer.parseInt(Character.toString(chars[i - 1]));
}
}
return version;
}
public boolean isNewer(PEVersion other) {
//Our equals check is quite cheap.
//If they are equal, then they aren't older nor newer
if (equals(other)) {
return false;
}
//The version length if guaranteed to be 4.
for (int i = 0; i < version.length; i++) {
if (version[i] > other.getVersion()[i]) {
return true;
} else if (version[i] < other.getVersion()[i]) {
return false;
}
}
return false;
}
public boolean equals(PEVersion version) {
return Arrays.equals(getVersion(), version.getVersion());
}
public boolean isOlder(PEVersion other) {
//Our equals check is quite cheap.
//If they are equal, then they aren't older nor newer
if (equals(other)) {
return false;
}
//The version length if guaranteed to be 4.
for (int i = 0; i < version.length; i++) {
if (version[i] < other.getVersion()[i]) {
return true;
} else if (version[i] > other.getVersion()[i]) {
return false;
}
}
return false;
}
public final int[] getVersion() {
return version;
}
public final int[] getVersionShortened() {
int length = 2;
if (version[2] != 0) {
length++;
}
if (version[3] != 0) {
length++;
}
int[] shortened = new int[length];
System.arraycopy(version, 0, shortened, 0, length);
return shortened;
}
private int[] convertIntListToIntArray(List<Integer> list) {
int[] versionArray = new int[list.size()];
for (int i = 0; i < versionArray.length; i++) {
versionArray[i] = list.get(i);
}
return versionArray;
}
@Override
public String toString() {
int[] shortenedVersion = getVersionShortened();
StringBuilder text = new StringBuilder();
for (int v : shortenedVersion) {
text.append(".").append(v);
}
return text.substring(1);
}
}

View File

@ -0,0 +1,73 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.server;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import org.spigotmc.SpigotConfig;
import java.lang.reflect.InvocationTargetException;
public final class ServerUtils {
/**
* Get the server version.
* @return Get Server Version
*/
public ServerVersion getVersion() {
return ServerVersion.getVersion();
}
/**
* Get recent TPS array from NMS.
* @return Get Recent TPS
*/
public double[] getRecentTPS() {
try {
return NMSUtils.recentTPS();
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return new double[0];
}
/**
* Get the current TPS.
* @return Get Current TPS
*/
public double getTPS() {
return getRecentTPS()[0];
}
/**
* Get the operating system of the local machine
* @return Get Operating System
*/
public SystemOS getOS() {
return SystemOS.getOperatingSystem();
}
public boolean isBungeeCordEnabled() {
return SpigotConfig.bungee;
}
}

View File

@ -0,0 +1,158 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.server;
import io.github.retrooper.packetevents.PacketEvents;
import org.bukkit.Bukkit;
/**
* @author retrooper
*/
public enum ServerVersion {
v_1_7_10((short) 5), v_1_8((short) 47), v_1_8_3((short) 47), v_1_8_4((short) 47), v_1_8_5((short) 47),
v_1_8_6((short) 47), v_1_8_7((short) 47), v_1_8_8((short) 47), v_1_9((short) 107), v_1_9_2((short) 109),
v_1_9_4((short) 110), v_1_10((short) 210), v_1_10_2((short) 210), v_1_11((short) 315), v_1_11_1((short) 316),
v_1_11_2((short) 316), v_1_12((short) 335), v_1_12_1((short) 338), v_1_12_2((short) 340), v_1_13((short) 393),
v_1_13_1((short) 401), v_1_13_2((short) 404), v_1_14((short) 477), v_1_14_1((short) 480), v_1_14_2((short) 485),
v_1_14_3((short) 490), v_1_14_4((short) 498), v_1_15((short) 573), v_1_15_1((short) 575), v_1_15_2((short) 578),
v_1_16((short) 735), v_1_16_1((short) 736), v_1_16_2((short) 751), v_1_16_3((short) 753), v_1_16_4((short)754),ERROR((short) -1);
private static final String nmsVersionSuffix = Bukkit.getServer().getClass().getPackage().getName()
.replace(".", ",").split(",")[3];
public static ServerVersion[] reversedValues = new ServerVersion[values().length];
private static ServerVersion cachedVersion;
private final short protocolId;
ServerVersion(short protocolId) {
this.protocolId = protocolId;
}
public short getProtocolVersion() {
return protocolId;
}
private static ServerVersion getVersionNoCache() {
if (reversedValues[0] == null) {
reversedValues = ServerVersion.reverse(values());
}
if(reversedValues == null) {
throw new IllegalStateException("Failed to reverse the ServerVersion enum constant values.");
}
for (final ServerVersion val : reversedValues) {
String valName = val.name().substring(2).replace("_", ".");
if (Bukkit.getBukkitVersion().contains(valName)) {
return val;
}
}
if(PacketEvents.getSettings().getBackupServerVersion() != null) {
return PacketEvents.getSettings().getBackupServerVersion();
}
return ERROR;
}
public static ServerVersion getVersion() {
if (cachedVersion == null) {
cachedVersion = getVersionNoCache();
}
return cachedVersion;
}
public static ServerVersion[] reverse(final ServerVersion[] arr) {
ServerVersion[] array = arr.clone();
if (array == null) {
return null;
}
int i = 0;
int j = array.length - 1;
ServerVersion tmp;
while (j > i) {
tmp = array[j];
array[j--] = array[i];
array[i++] = tmp;
}
return array;
}
public static String getNmsSuffix() {
return nmsVersionSuffix;
}
public static String getNMSDirectory() {
return "net.minecraft.server." + getNmsSuffix();
}
public static String getOBCDirectory() {
return "org.bukkit.craftbukkit." + getNmsSuffix();
}
/**
* Returns if the current version is more up to date than the argument passed
* version
*
* @param version The version to compare to the server's value.
* @return True if the supplied version is lower, false if it is equal or higher
* than the server's version.
*/
public boolean isHigherThan(final ServerVersion version) {
return protocolId > version.protocolId;
}
/**
* Returns if the current version is more up to date than the argument passed
* version
*
* @param version The version to compare to the server's value.
* @return True if the supplied version is lower or equal, false if it is higher
* than the server's version.
*/
public boolean isHigherThanOrEquals(final ServerVersion version) {
return protocolId >= version.protocolId;
}
/**
* Returns if the current version is more older than the argument passed
* version
*
* @param version The version to compare to the server's value.
* @return True if the supplied version is higher, false if it is equal or lower
* than the server's version.
*/
public boolean isLowerThan(final ServerVersion version) {
return version.protocolId > protocolId;
}
/**
* Returns if the current version is more older than the argument passed
* version
*
* @param version The version to compare to the server's value.
* @return True if the supplied version is higher or equal, false if it is lower
* than the server's version.
*/
public boolean isLowerThanOrEquals(final ServerVersion version) {
return version.protocolId >= protocolId;
}
}

View File

@ -0,0 +1,57 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.server;
public enum SystemOS {
WINDOWS, MACOS, LINUX, OTHER;
private static SystemOS value;
private static SystemOS getOS() {
final String os = System.getProperty("os.name");
for (final String osName : getOperatingSystemNames()) {
if (os.toLowerCase().contains(osName.toLowerCase())) {
return SystemOS.valueOf(osName);
}
}
return OTHER;
}
public static SystemOS getOperatingSystem() {
if (value == null) {
value = getOS();
}
return value;
}
public static String[] getOperatingSystemNames() {
final SystemOS[] values = values();
final String[] arr = new String[values.length - 1];
for (int i = 0; i < values.length - 1; i++) {
arr[i] = values[i].name();
}
return arr;
}
}

View File

@ -0,0 +1,54 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.vector;
public class Vector3i {
public int x, y, z;
public Vector3i() {}
public Vector3i(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public Vector3i(int[] coordinates) {
x = coordinates[0];
y = coordinates[1];
z = coordinates[2];
}
public final int getX() {
return x;
}
public final int getY() {
return y;
}
public final int getZ() {
return z;
}
}

View File

@ -0,0 +1,49 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.versionlookup;
import io.github.retrooper.packetevents.utils.versionlookup.protocollib.ProtocolLibVersionLookupUtils;
import io.github.retrooper.packetevents.utils.versionlookup.protocolsupport.ProtocolSupportVersionLookupUtils;
import io.github.retrooper.packetevents.utils.versionlookup.viaversion.ViaVersionLookupUtils;
import org.bukkit.entity.Player;
public class VersionLookupUtils {
public static boolean isDependencyAvailable() {
return ViaVersionLookupUtils.isAvailable()
|| ProtocolLibVersionLookupUtils.isAvailable()
|| ProtocolSupportVersionLookupUtils.isAvailable();
}
public static int getProtocolVersion(Player player) {
if (ViaVersionLookupUtils.isAvailable()) {
return ViaVersionLookupUtils.getProtocolVersion(player);
} else if (ProtocolLibVersionLookupUtils.isAvailable()) {
return ProtocolLibVersionLookupUtils.getProtocolVersion(player);
} else if (ProtocolSupportVersionLookupUtils.isAvailable()) {
return ProtocolSupportVersionLookupUtils.getProtocolVersion(player);
}
return -1;
}
}

View File

@ -0,0 +1,39 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.versionlookup.protocollib;
import com.comphenix.protocol.ProtocolLibrary;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
public class ProtocolLibVersionLookupUtils {
public static boolean isAvailable() {
return Bukkit.getPluginManager().isPluginEnabled("ProtocolLib");
}
public static int getProtocolVersion(Player player) {
return ProtocolLibrary.getProtocolManager().getProtocolVersion(player);
}
}

View File

@ -0,0 +1,39 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.versionlookup.protocolsupport;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import protocolsupport.api.ProtocolSupportAPI;
public class ProtocolSupportVersionLookupUtils {
public static boolean isAvailable() {
return Bukkit.getPluginManager().isPluginEnabled("ProtocolSupport");
}
public static int getProtocolVersion(Player player) {
return ProtocolSupportAPI.getProtocolVersion(player).getId();
}
}

Some files were not shown because too many files have changed in this diff Show More