mirror of
https://github.com/dmulloy2/ProtocolLib.git
synced 2026-11-04 08:52:09 -05:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
39808bc64f | ||
|
|
771a530fe2 | ||
|
|
ca9b5bbb80 | ||
|
|
d790ded81f | ||
|
|
f357ac85d0 | ||
|
|
66cdb5b69d |
No files matched your search
@@ -0,0 +1,43 @@
|
||||
name: ProtocolLib development build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '21'
|
||||
cache: 'gradle'
|
||||
|
||||
- name: Run gradle build lifecycle
|
||||
run: |
|
||||
COMMIT_SHA=${{ github.sha }} ./gradlew build shadowJar --no-daemon
|
||||
|
||||
- name: Upload plugin file
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ProtocolLib
|
||||
path: build/libs/ProtocolLib.jar
|
||||
|
||||
- name: Create or update GitHub pre-release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
COMMIT_MSG=$(git log -1 --pretty=%B)
|
||||
SHORT_HASH=$(echo "${{ github.sha }}" | cut -c1-7)
|
||||
RELEASE_NOTES=$(gh release view dev-build --repo ${{ github.repository }} --json body -q ".body" 2>/dev/null || echo "")
|
||||
gh release view dev-build --repo ${{ github.repository }} || \
|
||||
gh release create dev-build --prerelease --title "Development Build" --notes "## Changelog" --repo ${{ github.repository }}
|
||||
NEW_NOTES="$RELEASE_NOTES"$'\n'"* [$SHORT_HASH] $COMMIT_MSG"
|
||||
gh release edit dev-build --notes "$NEW_NOTES" --repo ${{ github.repository }}
|
||||
gh release upload dev-build build/libs/ProtocolLib.jar#ProtocolLib.jar --clobber --repo ${{ github.repository }}
|
||||
@@ -14,6 +14,7 @@ lead to more subtle bugs.
|
||||
|
||||
* [Spigot Page](https://spigotmc.org/resources/protocollib.1997/)
|
||||
* [Releases](https://github.com/dmulloy2/ProtocolLib/releases)
|
||||
* [Dev Build](https://github.com/dmulloy2/ProtocolLib/releases/tag/dev-build)
|
||||
* [JavaDoc](https://dmulloy2.net/ProtocolLib/javadoc/)
|
||||
* [Protocol Wiki](https://minecraft.wiki/w/Minecraft_Wiki:Projects/wiki.vg_merge/Protocol)
|
||||
|
||||
|
||||
+39
-34
@@ -1,14 +1,16 @@
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
import io.github.patrick.gradle.remapper.RemapTask
|
||||
//import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
//import io.github.patrick.gradle.remapper.RemapTask
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar.Companion.shadowJar
|
||||
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
|
||||
|
||||
plugins {
|
||||
`java-library`
|
||||
`maven-publish`
|
||||
`signing`
|
||||
id("com.gradleup.shadow") version "9.0.0-beta13"
|
||||
id("io.github.patrick.remapper") version "1.4.2"
|
||||
id("com.gradleup.shadow") version "9.0.2"
|
||||
// id("io.github.patrick.remapper") version "1.4.2"
|
||||
id("com.vanniktech.maven.publish") version "0.34.0"
|
||||
id("io.papermc.paperweight.userdev") version "2.0.0-beta.18"
|
||||
}
|
||||
|
||||
group = "net.dmulloy2"
|
||||
@@ -16,11 +18,23 @@ description = "Provides access to the Minecraft protocol"
|
||||
|
||||
val mcVersion = "1.21.8"
|
||||
val isSnapshot = version.toString().endsWith("-SNAPSHOT")
|
||||
val buildNumber = System.getenv("BUILD_NUMBER") ?: ""
|
||||
val isJenkins = buildNumber.isNotEmpty()
|
||||
val commitHash = System.getenv("COMMIT_SHA") ?: ""
|
||||
val isCI = commitHash.isNotEmpty()
|
||||
|
||||
paperweight {
|
||||
reobfArtifactConfiguration = io.papermc.paperweight.userdev.ReobfArtifactConfiguration.REOBF_PRODUCTION
|
||||
}
|
||||
|
||||
tasks.assemble {
|
||||
dependsOn(tasks.reobfJar)
|
||||
}
|
||||
|
||||
/*tasks.shadowJar {
|
||||
dependsOn(tasks.assemble)
|
||||
}*/
|
||||
|
||||
repositories {
|
||||
if (!isJenkins) {
|
||||
if (!isCI) {
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
@@ -46,36 +60,35 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
implementation("net.bytebuddy:byte-buddy:1.17.5")
|
||||
compileOnly("org.spigotmc:spigot-api:${mcVersion}-R0.1-SNAPSHOT")
|
||||
compileOnly("org.spigotmc:spigot:${mcVersion}-R0.1-SNAPSHOT:remapped-mojang")
|
||||
// compileOnly("org.spigotmc:spigot-api:${mcVersion}-R0.1-SNAPSHOT")
|
||||
// compileOnly("org.spigotmc:spigot:${mcVersion}-R0.1-SNAPSHOT:remapped-mojang")
|
||||
compileOnly("io.netty:netty-all:4.0.23.Final")
|
||||
/*
|
||||
* TODO(fix): once you update kyori:adventure-text-serializer-gson please uncomment the TODO in
|
||||
* com.comphenix.protocol.wrappers.WrappedComponentStyleTest if the following issue got fixed:
|
||||
* https://github.com/KyoriPowered/adventure/issues/1194
|
||||
*/
|
||||
compileOnly("net.kyori:adventure-text-serializer-gson:4.21.0")
|
||||
compileOnly("net.kyori:adventure-text-serializer-gson:4.24.0")
|
||||
compileOnly("net.kyori:adventure-text-serializer-ansi:4.24.0")
|
||||
compileOnly("com.googlecode.json-simple:json-simple:1.1.1")
|
||||
|
||||
paperweight.paperDevBundle("1.21.8-R0.1-SNAPSHOT")
|
||||
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.0")
|
||||
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.0")
|
||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.10.0")
|
||||
testImplementation("org.mockito:mockito-core:5.6.0")
|
||||
testImplementation("io.netty:netty-common:4.1.97.Final")
|
||||
testImplementation("io.netty:netty-transport:4.1.97.Final")
|
||||
testImplementation("org.spigotmc:spigot:${mcVersion}-R0.1-SNAPSHOT:remapped-mojang")
|
||||
testImplementation("net.kyori:adventure-text-serializer-gson:4.14.0")
|
||||
testImplementation("net.kyori:adventure-text-serializer-plain:4.14.0")
|
||||
// testImplementation("org.spigotmc:spigot:${mcVersion}-R0.1-SNAPSHOT:remapped-mojang")
|
||||
testImplementation("net.kyori:adventure-text-serializer-gson:4.24.0")
|
||||
testImplementation("net.kyori:adventure-text-serializer-plain:4.24.0")
|
||||
testImplementation("net.kyori:adventure-text-serializer-ansi:4.24.0")
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
sourceCompatibility = JavaVersion.VERSION_21
|
||||
targetCompatibility = JavaVersion.VERSION_21
|
||||
}
|
||||
|
||||
tasks {
|
||||
processResources {
|
||||
val fullVersion = if (isSnapshot && isJenkins) "${version}-${buildNumber}" else version
|
||||
val fullVersion = if (isSnapshot && isCI) "${version}-${commitHash.take(7)}" else version
|
||||
|
||||
eachFile {
|
||||
expand("version" to fullVersion)
|
||||
@@ -95,25 +108,17 @@ tasks {
|
||||
}
|
||||
relocate("net.bytebuddy", "com.comphenix.net.bytebuddy")
|
||||
|
||||
manifest {
|
||||
/*manifest {
|
||||
attributes(
|
||||
"paperweight-mappings-namespace" to "mojang"
|
||||
)
|
||||
}
|
||||
}*/
|
||||
|
||||
archiveFileName = "ProtocolLib.jar"
|
||||
// archiveFileName = "ProtocolLib.jar"
|
||||
}
|
||||
|
||||
remap {
|
||||
dependsOn("shadowJar")
|
||||
|
||||
inputTask.set(getByName<ShadowJar>("shadowJar"))
|
||||
version.set(mcVersion)
|
||||
action.set(RemapTask.Action.MOJANG_TO_SPIGOT)
|
||||
}
|
||||
|
||||
assemble {
|
||||
dependsOn("remap")
|
||||
reobfJar {
|
||||
outputJar = layout.buildDirectory.file("libs/ProtocolLib.jar")
|
||||
}
|
||||
|
||||
javadoc {
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
version=5.4.0
|
||||
version=5.4.1-SNAPSHOT
|
||||
mavenCentralUsername=
|
||||
mavenCentralPassword=
|
||||
signing.keyId=
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.comphenix.protocol;
|
||||
|
||||
import com.comphenix.protocol.injector.PacketFilterManager;
|
||||
|
||||
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.PlayerQuitEvent;
|
||||
import org.bukkit.event.server.PluginDisableEvent;
|
||||
|
||||
class BukkitListener implements Listener {
|
||||
private final PacketFilterManager manager;
|
||||
|
||||
BukkitListener(PacketFilterManager manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
// @EventHandler(priority = EventPriority.LOWEST)
|
||||
// public void handleLogin(PlayerLoginEvent event) {
|
||||
// networkManagerInjector.getInjector(event.getPlayer()).inject();
|
||||
// }
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void handleJoin(PlayerJoinEvent event) {
|
||||
manager.injectPlayer(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void handleQuit(PlayerQuitEvent event) {
|
||||
manager.removePlayer(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void handlePluginUnload(PluginDisableEvent event) {
|
||||
manager.removePacketListeners(event.getPlugin());
|
||||
}
|
||||
}
|
||||
@@ -21,21 +21,19 @@ import java.util.ArrayDeque;
|
||||
import java.util.Arrays;
|
||||
import java.util.Deque;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.comphenix.protocol.error.ErrorReporter;
|
||||
import com.comphenix.protocol.error.Report;
|
||||
import com.comphenix.protocol.error.ReportType;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
/**
|
||||
* Base class for all our commands.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
abstract class CommandBase implements CommandExecutor {
|
||||
abstract class CommandBase {
|
||||
public static final ReportType REPORT_COMMAND_ERROR = new ReportType("Cannot execute command %s.");
|
||||
public static final ReportType REPORT_UNEXPECTED_COMMAND = new ReportType("Incorrect command assigned to %s.");
|
||||
|
||||
@@ -58,15 +56,8 @@ abstract class CommandBase implements CommandExecutor {
|
||||
this.minimumArgumentCount = minimumArgumentCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
public boolean onCommand(CommandSender sender, String[] args) {
|
||||
try {
|
||||
// Make sure we're dealing with the correct command
|
||||
if (!command.getName().equalsIgnoreCase(name)) {
|
||||
reporter.reportWarning(this, Report.newBuilder(REPORT_UNEXPECTED_COMMAND).messageParam(this));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (permission != null && !sender.hasPermission(permission)) {
|
||||
sender.sendMessage(ChatColor.RED + "You haven't got permission to run this command.");
|
||||
return true;
|
||||
@@ -81,7 +72,7 @@ abstract class CommandBase implements CommandExecutor {
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
reporter.reportDetailed(this,
|
||||
Report.newBuilder(REPORT_COMMAND_ERROR).error(ex).messageParam(name).callerParam(sender, label, args)
|
||||
Report.newBuilder(REPORT_COMMAND_ERROR).error(ex).messageParam(name).callerParam(sender, name, args)
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.comphenix.protocol;
|
||||
|
||||
import com.comphenix.protocol.injector.PacketFilterManager;
|
||||
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerLoginEvent;
|
||||
|
||||
class LegacyLoginListener implements Listener {
|
||||
private final PacketFilterManager manager;
|
||||
|
||||
LegacyLoginListener(PacketFilterManager manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void handleLogin(PlayerLoginEvent event) {
|
||||
manager.injectPlayer(event.getPlayer());
|
||||
}
|
||||
}
|
||||
@@ -16,22 +16,6 @@
|
||||
*/
|
||||
package com.comphenix.protocol;
|
||||
|
||||
import com.comphenix.protocol.PacketType.Protocol;
|
||||
import com.comphenix.protocol.PacketType.Sender;
|
||||
import com.comphenix.protocol.events.ListeningWhitelist;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
import com.comphenix.protocol.events.PacketListener;
|
||||
import com.comphenix.protocol.injector.netty.WirePacket;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -48,11 +32,28 @@ import java.util.logging.Level;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.comphenix.protocol.PacketType.Protocol;
|
||||
import com.comphenix.protocol.PacketType.Sender;
|
||||
import com.comphenix.protocol.error.ErrorReporter;
|
||||
import com.comphenix.protocol.events.ListeningWhitelist;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
import com.comphenix.protocol.events.PacketListener;
|
||||
import com.comphenix.protocol.injector.PacketFilterManager;
|
||||
import com.comphenix.protocol.injector.netty.WirePacket;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
/**
|
||||
* Logs packets to a given stream
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class PacketLogging implements CommandExecutor, PacketListener {
|
||||
public class PacketLogging extends CommandBase implements PacketListener {
|
||||
public static final String NAME = "packetlog";
|
||||
|
||||
private static MethodAccessor HEX_DUMP;
|
||||
@@ -69,93 +70,94 @@ public class PacketLogging implements CommandExecutor, PacketListener {
|
||||
private final ProtocolManager manager;
|
||||
private final Plugin plugin;
|
||||
|
||||
PacketLogging(Plugin plugin, ProtocolManager manager) {
|
||||
PacketLogging(ErrorReporter reporter, Plugin plugin, PacketFilterManager manager) {
|
||||
super(reporter, CommandBase.PERMISSION_ADMIN, NAME, 2);
|
||||
this.plugin = plugin;
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
public boolean handleCommand(CommandSender sender, String[] args) {
|
||||
PacketType type = null;
|
||||
|
||||
try {
|
||||
if (args.length > 2) {
|
||||
Protocol protocol;
|
||||
if (args.length <= 2) {
|
||||
sender.sendMessage(ChatColor.RED + "Invalid syntax: /packetlog <protocol> <sender> <packet> [location]");
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
protocol = Protocol.valueOf(args[0].toUpperCase());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
sender.sendMessage(ChatColor.RED + "Unknown protocol " + args[0]);
|
||||
return true;
|
||||
}
|
||||
Protocol protocol;
|
||||
|
||||
Sender pSender;
|
||||
try {
|
||||
protocol = Protocol.valueOf(args[0].toUpperCase());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
sender.sendMessage(ChatColor.RED + "Unknown protocol " + args[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
pSender = Sender.valueOf(args[1].toUpperCase());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
sender.sendMessage(ChatColor.RED + "Unknown sender: " + args[1]);
|
||||
return true;
|
||||
}
|
||||
Sender pSender;
|
||||
|
||||
try {
|
||||
try { // Try IDs first
|
||||
int id = Integer.parseInt(args[2]);
|
||||
type = PacketType.findCurrent(protocol, pSender, id);
|
||||
} catch (NumberFormatException ex) { // Check packet names
|
||||
String name = args[2];
|
||||
for (PacketType packet : PacketType.values()) {
|
||||
if (packet.getProtocol() == protocol && packet.getSender() == pSender) {
|
||||
if (packet.name().equalsIgnoreCase(name)) {
|
||||
try {
|
||||
pSender = Sender.valueOf(args[1].toUpperCase());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
sender.sendMessage(ChatColor.RED + "Unknown sender: " + args[1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
try { // Try IDs first
|
||||
int id = Integer.parseInt(args[2]);
|
||||
type = PacketType.findCurrent(protocol, pSender, id);
|
||||
} catch (NumberFormatException ex) { // Check packet names
|
||||
String name = args[2];
|
||||
for (PacketType packet : PacketType.values()) {
|
||||
if (packet.getProtocol() == protocol && packet.getSender() == pSender) {
|
||||
if (packet.name().equalsIgnoreCase(name)) {
|
||||
type = packet;
|
||||
break;
|
||||
}
|
||||
for (String className : packet.getClassNames()) {
|
||||
if (className.equalsIgnoreCase(name)) {
|
||||
type = packet;
|
||||
break;
|
||||
}
|
||||
for (String className : packet.getClassNames()) {
|
||||
if (className.equalsIgnoreCase(name)) {
|
||||
type = packet;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IllegalArgumentException ex) { // RIP
|
||||
type = null;
|
||||
}
|
||||
} catch (IllegalArgumentException ex) { // RIP
|
||||
type = null;
|
||||
}
|
||||
|
||||
if (type == null) {
|
||||
sender.sendMessage(ChatColor.RED + "Unknown packet: " + args[2]);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length > 3) {
|
||||
if (args[3].equalsIgnoreCase("console")) {
|
||||
this.location = LogLocation.CONSOLE;
|
||||
} else {
|
||||
this.location = LogLocation.FILE;
|
||||
}
|
||||
}
|
||||
|
||||
if (pSender == Sender.CLIENT) {
|
||||
if (receivingTypes.contains(type)) {
|
||||
receivingTypes.remove(type);
|
||||
} else {
|
||||
receivingTypes.add(type);
|
||||
}
|
||||
} else {
|
||||
if (sendingTypes.contains(type)) {
|
||||
sendingTypes.remove(type);
|
||||
} else {
|
||||
sendingTypes.add(type);
|
||||
}
|
||||
}
|
||||
|
||||
startLogging();
|
||||
sender.sendMessage(ChatColor.GREEN + "Now logging " + type.getPacketClass().getSimpleName());
|
||||
if (type == null) {
|
||||
sender.sendMessage(ChatColor.RED + "Unknown packet: " + args[2]);
|
||||
return true;
|
||||
}
|
||||
|
||||
sender.sendMessage(ChatColor.RED + "Invalid syntax: /packetlog <protocol> <sender> <packet> [location]");
|
||||
if (args.length > 3) {
|
||||
if (args[3].equalsIgnoreCase("console")) {
|
||||
this.location = LogLocation.CONSOLE;
|
||||
} else {
|
||||
this.location = LogLocation.FILE;
|
||||
}
|
||||
}
|
||||
|
||||
if (pSender == Sender.CLIENT) {
|
||||
if (receivingTypes.contains(type)) {
|
||||
receivingTypes.remove(type);
|
||||
} else {
|
||||
receivingTypes.add(type);
|
||||
}
|
||||
} else {
|
||||
if (sendingTypes.contains(type)) {
|
||||
sendingTypes.remove(type);
|
||||
} else {
|
||||
sendingTypes.add(type);
|
||||
}
|
||||
}
|
||||
|
||||
startLogging();
|
||||
sender.sendMessage(ChatColor.GREEN + "Now logging " + type.getPacketClass().getSimpleName());
|
||||
return true;
|
||||
} catch (Throwable ex) {
|
||||
sender.sendMessage(ChatColor.RED + "Failed to parse command: " + ex);
|
||||
|
||||
@@ -14,7 +14,7 @@ import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.apache.commons.lang.WordUtils;
|
||||
import com.comphenix.protocol.utility.WordUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import com.comphenix.protocol.PacketTypeLookup.ClassLookup;
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.comphenix.protocol;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import com.comphenix.protocol.injector.PacketFilterManager;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.papermc.paper.connection.PlayerConnection;
|
||||
import io.papermc.paper.connection.ReadablePlayerCookieConnectionImpl;
|
||||
import io.papermc.paper.event.connection.PlayerConnectionValidateLoginEvent;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
class PaperLoginListener implements Listener {
|
||||
private final PacketFilterManager manager;
|
||||
|
||||
PaperLoginListener(PacketFilterManager manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
private static FieldAccessor networkManagerField;
|
||||
private static FieldAccessor channelField;
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerConnectionValidateLogin(PlayerConnectionValidateLoginEvent event) {
|
||||
try {
|
||||
PlayerConnection connection = event.getConnection();
|
||||
ProtocolLogger.log("onPlayerConnectionValidateLogin: " + connection.getAddress());
|
||||
|
||||
if (networkManagerField == null) {
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(ReadablePlayerCookieConnectionImpl.class, true);
|
||||
Field field = fuzzy.getFieldByType("networkManager", MinecraftReflection.getNetworkManagerClass());
|
||||
networkManagerField = Accessors.getFieldAccessor(field);
|
||||
}
|
||||
|
||||
Object networkManager = networkManagerField.get(connection);
|
||||
|
||||
if (channelField == null) {
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromObject(networkManager, true);
|
||||
Field field = fuzzy.getFieldByType("channel", Channel.class);
|
||||
channelField = Accessors.getFieldAccessor(field);
|
||||
}
|
||||
|
||||
Channel channel = (Channel) channelField.get(networkManager);
|
||||
manager.injectChannel(channel);
|
||||
ProtocolLogger.log("Successfully injected channel " + channel);
|
||||
} catch (Throwable ex) {
|
||||
ProtocolLogger.log(Level.SEVERE, "Failed to inject channel", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,26 +15,6 @@
|
||||
*/
|
||||
package com.comphenix.protocol;
|
||||
|
||||
import com.comphenix.protocol.async.AsyncFilterManager;
|
||||
import com.comphenix.protocol.error.BasicErrorReporter;
|
||||
import com.comphenix.protocol.error.DelegatedErrorReporter;
|
||||
import com.comphenix.protocol.error.DetailedErrorReporter;
|
||||
import com.comphenix.protocol.error.ErrorReporter;
|
||||
import com.comphenix.protocol.error.Report;
|
||||
import com.comphenix.protocol.error.ReportType;
|
||||
import com.comphenix.protocol.injector.InternalManager;
|
||||
import com.comphenix.protocol.injector.PacketFilterManager;
|
||||
import com.comphenix.protocol.metrics.Statistics;
|
||||
import com.comphenix.protocol.scheduler.DefaultScheduler;
|
||||
import com.comphenix.protocol.scheduler.FoliaScheduler;
|
||||
import com.comphenix.protocol.scheduler.ProtocolScheduler;
|
||||
import com.comphenix.protocol.scheduler.Task;
|
||||
import com.comphenix.protocol.updater.Updater;
|
||||
import com.comphenix.protocol.updater.Updater.UpdateType;
|
||||
import com.comphenix.protocol.utility.*;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@@ -47,9 +27,29 @@ import java.util.logging.Level;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.comphenix.protocol.async.AsyncFilterManager;
|
||||
import com.comphenix.protocol.error.BasicErrorReporter;
|
||||
import com.comphenix.protocol.error.DelegatedErrorReporter;
|
||||
import com.comphenix.protocol.error.DetailedErrorReporter;
|
||||
import com.comphenix.protocol.error.ErrorReporter;
|
||||
import com.comphenix.protocol.error.Report;
|
||||
import com.comphenix.protocol.error.ReportType;
|
||||
import com.comphenix.protocol.injector.PacketFilterManager;
|
||||
import com.comphenix.protocol.metrics.Statistics;
|
||||
import com.comphenix.protocol.scheduler.DefaultScheduler;
|
||||
import com.comphenix.protocol.scheduler.FoliaScheduler;
|
||||
import com.comphenix.protocol.scheduler.ProtocolScheduler;
|
||||
import com.comphenix.protocol.scheduler.Task;
|
||||
import com.comphenix.protocol.updater.Updater;
|
||||
import com.comphenix.protocol.updater.Updater.UpdateType;
|
||||
import com.comphenix.protocol.utility.ByteBuddyFactory;
|
||||
import com.comphenix.protocol.utility.ChatExtensions;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.comphenix.protocol.utility.Util;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Iterables;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
@@ -58,7 +58,7 @@ import org.bukkit.plugin.java.JavaPlugin;
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public class ProtocolLib extends JavaPlugin {
|
||||
public abstract class ProtocolLib extends JavaPlugin {
|
||||
// Every possible error or warning report type
|
||||
public static final ReportType REPORT_CANNOT_DELETE_CONFIG = new ReportType(
|
||||
"Cannot delete old ProtocolLib configuration.");
|
||||
@@ -91,8 +91,8 @@ public class ProtocolLib extends JavaPlugin {
|
||||
// these fields are only existing once, we can make them static
|
||||
private static Logger logger;
|
||||
private static ProtocolConfig config;
|
||||
private static InternalManager protocolManager;
|
||||
private static ErrorReporter reporter = new BasicErrorReporter();
|
||||
protected static PacketFilterManager protocolManager;
|
||||
protected static ErrorReporter reporter = new BasicErrorReporter();
|
||||
|
||||
private Statistics statistics;
|
||||
|
||||
@@ -210,7 +210,7 @@ public class ProtocolLib extends JavaPlugin {
|
||||
this.commandPacket = new CommandPacket(reporter, this, logger, this.commandFilter, protocolManager);
|
||||
break;
|
||||
case LOGGING:
|
||||
this.packetLogging = new PacketLogging(this, protocolManager);
|
||||
this.packetLogging = new PacketLogging(reporter, this, protocolManager);
|
||||
break;
|
||||
}
|
||||
} catch (OutOfMemoryError e) {
|
||||
@@ -336,7 +336,11 @@ public class ProtocolLib extends JavaPlugin {
|
||||
this.registerCommand(PacketLogging.NAME, this.packetLogging);
|
||||
|
||||
// Player login and logout events
|
||||
protocolManager.registerEvents(manager, this);
|
||||
protocolManager.inject();
|
||||
|
||||
manager.registerEvents(new BukkitListener(protocolManager), this);
|
||||
|
||||
registerLoginListener();
|
||||
|
||||
// Worker that ensures that async packets are eventually sent
|
||||
// It also performs the update check.
|
||||
@@ -364,6 +368,8 @@ public class ProtocolLib extends JavaPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
abstract void registerLoginListener();
|
||||
|
||||
// Used to check Minecraft version
|
||||
private MinecraftVersion verifyMinecraftVersion() {
|
||||
MinecraftVersion minimum = new MinecraftVersion(ProtocolLibrary.MINIMUM_MINECRAFT_VERSION);
|
||||
@@ -437,26 +443,7 @@ public class ProtocolLib extends JavaPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
private void registerCommand(String name, CommandExecutor executor) {
|
||||
try {
|
||||
// Ignore these - they must have printed an error already
|
||||
if (executor == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
PluginCommand command = this.getCommand(name);
|
||||
|
||||
// Try to load the command
|
||||
if (command != null) {
|
||||
command.setExecutor(executor);
|
||||
} else {
|
||||
throw new RuntimeException("plugin.yml might be corrupt.");
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
reporter.reportWarning(this,
|
||||
Report.newBuilder(REPORT_CANNOT_REGISTER_COMMAND).messageParam(name, e.getMessage()).error(e));
|
||||
}
|
||||
}
|
||||
abstract void registerCommand(String name, CommandBase command);
|
||||
|
||||
/**
|
||||
* Disable the current plugin.
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.comphenix.protocol;
|
||||
|
||||
public final class ProtocolLibPaper extends ProtocolLib {
|
||||
|
||||
@Override
|
||||
void registerLoginListener() {
|
||||
try {
|
||||
Class.forName("io.papermc.paper.event.connection.PlayerConnectionValidateLoginEvent");
|
||||
getServer().getPluginManager().registerEvents(new com.comphenix.protocol.PaperLoginListener(protocolManager), this);
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
getServer().getPluginManager().registerEvents(new LegacyLoginListener(protocolManager), this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCommand(String name, CommandBase command) {
|
||||
registerCommand(name, (stack, args) -> command.onCommand(stack.getSender(), args));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.comphenix.protocol;
|
||||
|
||||
import com.comphenix.protocol.error.Report;
|
||||
|
||||
import org.bukkit.command.PluginCommand;
|
||||
|
||||
public final class ProtocolLibSpigot extends ProtocolLib {
|
||||
@Override
|
||||
void registerLoginListener() {
|
||||
getServer().getPluginManager().registerEvents(new LegacyLoginListener(protocolManager), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
void registerCommand(String name, CommandBase command) {
|
||||
try {
|
||||
PluginCommand pluginCmd = this.getCommand(name);
|
||||
|
||||
// Try to load the command
|
||||
if (pluginCmd != null) {
|
||||
pluginCmd.setExecutor((sender, _c, _l, args) ->
|
||||
command.onCommand(sender, args));
|
||||
} else {
|
||||
throw new RuntimeException("plugin.yml might be corrupt.");
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
reporter.reportWarning(this,
|
||||
Report.newBuilder(REPORT_CANNOT_REGISTER_COMMAND).messageParam(name, e.getMessage()).error(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ import com.comphenix.protocol.error.BasicErrorReporter;
|
||||
import com.comphenix.protocol.error.ErrorReporter;
|
||||
import com.comphenix.protocol.scheduler.ProtocolScheduler;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import com.comphenix.protocol.utility.Validate;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
/**
|
||||
@@ -48,8 +48,8 @@ public class ProtocolLibrary {
|
||||
private static ProtocolScheduler scheduler;
|
||||
private static ErrorReporter reporter = new BasicErrorReporter();
|
||||
|
||||
private static boolean updatesDisabled;
|
||||
private static boolean initialized;
|
||||
private static boolean updatesDisabled = false;
|
||||
private static boolean initialized = false;
|
||||
|
||||
protected static void init(Plugin plugin, ProtocolConfig config, ProtocolManager manager,
|
||||
ProtocolScheduler scheduler, ErrorReporter reporter) {
|
||||
|
||||
@@ -30,6 +30,8 @@ import com.comphenix.protocol.error.Report;
|
||||
import com.comphenix.protocol.error.ReportType;
|
||||
import com.comphenix.protocol.events.ListeningWhitelist;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.MinMaxPriorityQueue;
|
||||
|
||||
@@ -209,7 +211,7 @@ class PacketProcessingQueue {
|
||||
|
||||
public void cleanupAll() {
|
||||
// Cancel all the threads and every listener
|
||||
for (AsyncListenerHandler handler : map.values()) {
|
||||
for (AsyncListenerHandler handler : ImmutableList.copyOf(map.values())) {
|
||||
handler.cancel();
|
||||
}
|
||||
|
||||
|
||||
@@ -30,20 +30,17 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apache.commons.lang.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang.builder.ToStringStyle;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.comphenix.protocol.ProtocolConfig;
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.ProtocolLogger;
|
||||
import com.comphenix.protocol.collections.ExpireHashMap;
|
||||
import com.comphenix.protocol.error.Report.ReportBuilder;
|
||||
import com.comphenix.protocol.events.PacketAdapter;
|
||||
import com.comphenix.protocol.reflect.PrettyPrinter;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.primitives.Primitives;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
/**
|
||||
* Internal class used to handle exceptions.
|
||||
@@ -472,7 +469,7 @@ public class DetailedErrorReporter implements ErrorReporter {
|
||||
} if (isSimpleType(value) || value instanceof Class<?>) {
|
||||
return value.toString();
|
||||
} else {
|
||||
try {
|
||||
/*try {
|
||||
if (!apacheCommonsMissing)
|
||||
return ToStringBuilder.reflectionToString(value, ToStringStyle.MULTI_LINE_STYLE, false, null);
|
||||
} catch (LinkageError ex) {
|
||||
@@ -483,7 +480,7 @@ public class DetailedErrorReporter implements ErrorReporter {
|
||||
} catch (Throwable ex) {
|
||||
// Don't use the error logger to log errors in error logging (that could lead to infinite loops)
|
||||
ProtocolLogger.log(Level.WARNING, "Cannot convert to a String with Apache: " + ex.getMessage());
|
||||
}
|
||||
}*/
|
||||
|
||||
// Use our custom object printer instead
|
||||
try {
|
||||
|
||||
@@ -10,22 +10,8 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.WorldType;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.MerchantRecipe;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
@@ -68,7 +54,20 @@ import com.comphenix.protocol.wrappers.WrappedWatchableObject;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtBase;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.comphenix.protocol.utility.Validate;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.WorldType;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.MerchantRecipe;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public abstract class AbstractStructure {
|
||||
protected transient Object handle;
|
||||
|
||||
@@ -23,7 +23,7 @@ import java.util.concurrent.TimeUnit;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import com.comphenix.protocol.utility.Validate;
|
||||
|
||||
/**
|
||||
* Stores and retrieves metadata for applicable packet objects.
|
||||
|
||||
@@ -36,6 +36,7 @@ import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.ByteBuddyFactory;
|
||||
import com.comphenix.protocol.utility.Util;
|
||||
|
||||
import io.papermc.paper.persistence.PersistentDataContainerView;
|
||||
import net.bytebuddy.description.ByteCodeElement;
|
||||
import net.bytebuddy.description.modifier.Visibility;
|
||||
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
|
||||
@@ -60,7 +61,6 @@ import org.bukkit.World;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.profile.PlayerProfile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
@@ -157,11 +157,28 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param b
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public @org.jspecify.annotations.Nullable Location getRespawnLocation(boolean b) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getLocation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public PersistentDataContainerView getPersistentDataContainer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO do we need to implement this?
|
||||
|
||||
public void incrementStatistic(Statistic statistic) throws IllegalArgumentException {
|
||||
@@ -241,8 +258,11 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public @NotNull PlayerProfile getPlayerProfile() {
|
||||
public com.destroystokyo.paper.profile.PlayerProfile getPlayerProfile() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -288,6 +308,14 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable {
|
||||
return online;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWhitelisted() {
|
||||
return whitelisted;
|
||||
|
||||
@@ -39,7 +39,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import com.comphenix.protocol.utility.Validate;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package com.comphenix.protocol.injector;
|
||||
|
||||
import com.comphenix.protocol.ProtocolManager;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
/**
|
||||
* Yields access to the internal hook configuration.
|
||||
@@ -11,14 +9,6 @@ import org.bukkit.plugin.PluginManager;
|
||||
*/
|
||||
public interface InternalManager extends ProtocolManager {
|
||||
|
||||
/**
|
||||
* Register this protocol manager on Bukkit.
|
||||
*
|
||||
* @param manager - Bukkit plugin manager that provides player join/leave events.
|
||||
* @param plugin - the parent plugin.
|
||||
*/
|
||||
void registerEvents(PluginManager manager, final Plugin plugin);
|
||||
|
||||
/**
|
||||
* Called when ProtocolLib is closing.
|
||||
*/
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package com.comphenix.protocol.injector;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLib;
|
||||
import com.comphenix.protocol.async.AsyncFilterManager;
|
||||
import com.comphenix.protocol.error.ErrorReporter;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
@@ -112,7 +114,7 @@ public class PacketFilterBuilder {
|
||||
*
|
||||
* @return A new packet filter manager.
|
||||
*/
|
||||
public InternalManager build() {
|
||||
public PacketFilterManager build() {
|
||||
if (this.reporter == null) {
|
||||
throw new IllegalArgumentException("reporter cannot be NULL.");
|
||||
}
|
||||
|
||||
@@ -8,21 +8,6 @@ import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Entity;
|
||||
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.event.server.PluginDisableEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
import com.comphenix.protocol.AsynchronousManager;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
@@ -47,7 +32,15 @@ import com.comphenix.protocol.injector.netty.WirePacket;
|
||||
import com.comphenix.protocol.injector.netty.manager.NetworkManagerInjector;
|
||||
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import io.netty.channel.Channel;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class PacketFilterManager implements ListenerManager, InternalManager {
|
||||
|
||||
@@ -327,24 +320,30 @@ public class PacketFilterManager implements ListenerManager, InternalManager {
|
||||
|
||||
@Override
|
||||
public void removePacketListener(PacketListener listener) {
|
||||
if (!this.closed && this.registeredListeners.remove(listener)) {
|
||||
ListeningWhitelist outbound = listener.getSendingWhitelist();
|
||||
ListeningWhitelist inbound = listener.getReceivingWhitelist();
|
||||
if (this.closed || !this.registeredListeners.remove(listener)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// remove outbound listeners (if any)
|
||||
if (outbound != null && outbound.isEnabled()) {
|
||||
this.outboundListeners.removeListener(listener);
|
||||
}
|
||||
ListeningWhitelist outbound = listener.getSendingWhitelist();
|
||||
ListeningWhitelist inbound = listener.getReceivingWhitelist();
|
||||
|
||||
// remove inbound listeners (if any)
|
||||
if (inbound != null && inbound.isEnabled()) {
|
||||
this.inboundListeners.removeListener(listener);
|
||||
}
|
||||
// remove outbound listeners (if any)
|
||||
if (outbound != null && outbound.isEnabled()) {
|
||||
this.outboundListeners.removeListener(listener);
|
||||
}
|
||||
|
||||
// remove inbound listeners (if any)
|
||||
if (inbound != null && inbound.isEnabled()) {
|
||||
this.inboundListeners.removeListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePacketListeners(Plugin plugin) {
|
||||
if (this.closed || this.plugin.equals(plugin)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (PacketListener listener : this.getPacketListeners()) {
|
||||
if (Objects.equals(listener.getPlugin(), plugin)) {
|
||||
this.removePacketListener(listener);
|
||||
@@ -421,40 +420,26 @@ public class PacketFilterManager implements ListenerManager, InternalManager {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerEvents(PluginManager manager, Plugin plugin) {
|
||||
if (!this.closed && !this.injected) {
|
||||
// prevent duplicate event registrations / injections
|
||||
this.injected = true;
|
||||
this.networkManagerInjector.inject();
|
||||
public void removePlayer(Player player) {
|
||||
asyncFilterManager.removePlayer(player);
|
||||
}
|
||||
|
||||
// all listeners we need, this is a bit messy, but it makes the job correctly
|
||||
manager.registerEvents(new Listener() {
|
||||
public void injectPlayer(Player player) {
|
||||
networkManagerInjector.getInjector(player).inject();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void handleLogin(PlayerLoginEvent event) {
|
||||
networkManagerInjector.getInjector(event.getPlayer()).inject();
|
||||
}
|
||||
public void injectChannel(Channel channel) {
|
||||
networkManagerInjector.getInjector(channel).inject();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void handleJoin(PlayerJoinEvent event) {
|
||||
networkManagerInjector.getInjector(event.getPlayer()).inject();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void handleQuit(PlayerQuitEvent event) {
|
||||
PacketFilterManager.this.asyncFilterManager.removePlayer(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void handlePluginUnload(PluginDisableEvent event) {
|
||||
// don't do this for our plugin!
|
||||
if (event.getPlugin() != PacketFilterManager.this.plugin) {
|
||||
PacketFilterManager.this.removePacketListeners(event.getPlugin());
|
||||
}
|
||||
}
|
||||
}, plugin);
|
||||
public void inject() {
|
||||
if (this.closed || this.injected) {
|
||||
return;
|
||||
}
|
||||
|
||||
// prevent duplicate event registrations / injections
|
||||
this.injected = true;
|
||||
this.networkManagerInjector.inject();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2,12 +2,12 @@ package com.comphenix.protocol.injector.netty;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.PacketType.Protocol;
|
||||
import com.comphenix.protocol.events.NetworkMarker;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
/**
|
||||
* Represents an injected client connection.
|
||||
*
|
||||
@@ -74,6 +74,8 @@ public interface Injector {
|
||||
*/
|
||||
void setPlayer(Player player);
|
||||
|
||||
boolean hasValidPlayer();
|
||||
|
||||
boolean isConnected();
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,13 +2,14 @@ package com.comphenix.protocol.injector.netty.channel;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.PacketType.Protocol;
|
||||
import com.comphenix.protocol.events.NetworkMarker;
|
||||
import com.comphenix.protocol.injector.netty.Injector;
|
||||
import com.comphenix.protocol.injector.netty.WirePacket;
|
||||
import com.comphenix.protocol.injector.temporary.TemporaryPlayer;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
final class EmptyInjector implements Injector {
|
||||
|
||||
@@ -72,6 +73,11 @@ final class EmptyInjector implements Injector {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasValidPlayer() {
|
||||
return player != null && !(player instanceof TemporaryPlayer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
return false;
|
||||
|
||||
@@ -16,12 +16,9 @@ package com.comphenix.protocol.injector.netty.channel;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLogger;
|
||||
import com.comphenix.protocol.error.ErrorReporter;
|
||||
import com.comphenix.protocol.injector.ListenerManager;
|
||||
import com.comphenix.protocol.injector.netty.Injector;
|
||||
@@ -29,10 +26,12 @@ import com.comphenix.protocol.injector.temporary.TemporaryPlayerFactory;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftFields;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.google.common.collect.MapMaker;
|
||||
|
||||
import com.google.common.collect.MapMaker;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
/**
|
||||
* Represents an injector factory.
|
||||
@@ -85,12 +84,8 @@ public class InjectionFactory {
|
||||
|
||||
// try to get the injector using the player reference first
|
||||
Injector injector = this.playerLookup.get(player);
|
||||
if (injector == null) {
|
||||
injector = this.getTemporaryInjector(player);
|
||||
}
|
||||
|
||||
// check if we found an injector
|
||||
if (injector != null && !injector.isClosed()) {
|
||||
ProtocolLogger.log(player.getName() + " has a cached injector. Player valid: " + injector.hasValidPlayer());
|
||||
return injector;
|
||||
}
|
||||
|
||||
@@ -110,7 +105,10 @@ public class InjectionFactory {
|
||||
this.playerLookup.remove(injector.getPlayer());
|
||||
this.cacheInjector(player, injector);
|
||||
// re-set the player of the injection
|
||||
ProtocolLogger.log("Reusing existing injector and setting player to " + player.getName());
|
||||
injector.setPlayer(player);
|
||||
} else {
|
||||
ProtocolLogger.log(player.getName() + "'s channel already has an injector. Player valid: " + injector.hasValidPlayer());
|
||||
}
|
||||
} else {
|
||||
// construct a new injector as it seems like we have none yet
|
||||
|
||||
+10
-6
@@ -11,9 +11,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.PacketType.Protocol;
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
@@ -29,6 +26,7 @@ import com.comphenix.protocol.injector.NetworkProcessor;
|
||||
import com.comphenix.protocol.injector.netty.Injector;
|
||||
import com.comphenix.protocol.injector.netty.WirePacket;
|
||||
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
||||
import com.comphenix.protocol.injector.temporary.TemporaryPlayer;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
@@ -43,6 +41,8 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.EventLoop;
|
||||
import io.netty.util.AttributeKey;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class NettyChannelInjector implements Injector {
|
||||
|
||||
@@ -289,8 +289,7 @@ public class NettyChannelInjector implements Injector {
|
||||
|
||||
this.ensureInEventLoop(() -> {
|
||||
try {
|
||||
// try to invoke the method, this should normally not fail
|
||||
this.listenerInvoker.read(packet);
|
||||
this.channel.pipeline().context(INBOUND_INTERCEPTOR_NAME).fireChannelRead(packet);
|
||||
} catch (Exception exception) {
|
||||
this.errorReporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_READ_PACKET)
|
||||
.messageParam(packet, this.playerName)
|
||||
@@ -344,7 +343,7 @@ public class NettyChannelInjector implements Injector {
|
||||
@Override
|
||||
public Player getPlayer() {
|
||||
// if the player was already resolved there is no need to do further lookups
|
||||
if (this.player != null) {
|
||||
if (this.player != null && !(this.player instanceof TemporaryPlayer)) {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
@@ -371,6 +370,11 @@ public class NettyChannelInjector implements Injector {
|
||||
this.injectionFactory.cacheInjector(player.getName(), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasValidPlayer() {
|
||||
return this.player != null && !(player instanceof TemporaryPlayer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
return this.channel.isActive();
|
||||
|
||||
+4
-25
@@ -14,13 +14,11 @@ import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
|
||||
/**
|
||||
* This class facilitates the invocation of methods on the current packet listener.
|
||||
* It attempts to execute the <code>send</code>, <code>read</code>, and <code>disconnect</code>
|
||||
* methods and, upon failure (either due to the absence of the method or the packet
|
||||
* listener being of an incorrect type), it delegates the call to the network manager.
|
||||
* It attempts to execute the <code>send</code>, and <code>disconnect</code> methods, upon failure
|
||||
* (either due to the absence of the method or the packet listener being of an incorrect type),
|
||||
* it delegates the call to the network manager.
|
||||
*
|
||||
* <p>Supported packet listener types include CONFIGURATION and PLAY. If the packet
|
||||
* listener does not match these types, or if the required method is missing, the
|
||||
@@ -43,7 +41,6 @@ public class PacketListenerInvoker {
|
||||
private static final boolean DOES_PACKET_LISTENER_DISCONNECT_USE_COMPONENT = doesPacketListenerDisconnectUseComponent();
|
||||
|
||||
private static final MethodAccessor NETWORK_MANAGER_SEND = getNetworkManagerSend();
|
||||
private static final MethodAccessor NETWORK_MANAGER_READ = getNetworkManagerRead();
|
||||
private static final MethodAccessor NETWORK_MANAGER_DISCONNECT = getNetworkManagerDisconnect();
|
||||
private static final MethodAccessor NETWORK_MANAGER_PACKET_LISTENER = getNetworkManagerPacketListener();
|
||||
|
||||
@@ -117,15 +114,6 @@ public class PacketListenerInvoker {
|
||||
return Accessors.getMethodAccessor(send);
|
||||
}
|
||||
|
||||
private static MethodAccessor getNetworkManagerRead() {
|
||||
FuzzyReflection networkManager = FuzzyReflection.fromClass(MinecraftReflection.getNetworkManagerClass(), true);
|
||||
|
||||
Method read = networkManager
|
||||
.getMethodByParameters("read", ChannelHandlerContext.class, MinecraftReflection.getPacketClass());
|
||||
|
||||
return Accessors.getMethodAccessor(read);
|
||||
}
|
||||
|
||||
private static MethodAccessor getNetworkManagerDisconnect() {
|
||||
FuzzyReflection networkManager = FuzzyReflection.fromClass(MinecraftReflection.getNetworkManagerClass());
|
||||
|
||||
@@ -190,7 +178,7 @@ public class PacketListenerInvoker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a packet using the current packet listener if available and valid; otherwise,
|
||||
* Sends a packet using the current packet listener if available and valid; otherwise,
|
||||
* falls back to the network manager.
|
||||
*
|
||||
* @param packet The packet to be sent.
|
||||
@@ -204,15 +192,6 @@ public class PacketListenerInvoker {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a packet directly using the network manager.
|
||||
*
|
||||
* @param packet The packet to be read.
|
||||
*/
|
||||
public void read(Object packet) {
|
||||
NETWORK_MANAGER_READ.invoke(this.networkManager, null, packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects the player using the current packet listener if available and valid; otherwise,
|
||||
* falls back to the network manager.
|
||||
|
||||
+7
-3
@@ -7,9 +7,6 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLogger;
|
||||
import com.comphenix.protocol.error.ErrorReporter;
|
||||
import com.comphenix.protocol.injector.ListenerManager;
|
||||
@@ -23,7 +20,10 @@ import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.Pair;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class NetworkManagerInjector {
|
||||
|
||||
@@ -57,6 +57,10 @@ public class NetworkManagerInjector {
|
||||
return this.injectionFactory.fromPlayer(player);
|
||||
}
|
||||
|
||||
public Injector getInjector(Channel channel) {
|
||||
return injectionFactory.fromChannel(channel);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void inject() {
|
||||
if (this.closed || this.injected) {
|
||||
|
||||
@@ -1899,4 +1899,16 @@ public final class MinecraftReflection {
|
||||
|
||||
return isMojangMapped;
|
||||
}
|
||||
|
||||
public static Optional<Class<?>> getDataComponentMapClass() {
|
||||
return getOptionalNMS("core.component.DataComponentMap");
|
||||
}
|
||||
|
||||
public static Optional<Class<?>> getDataComponentHolderClass() {
|
||||
return getOptionalNMS("core.component.DataComponentHolder");
|
||||
}
|
||||
|
||||
public static Optional<Class<?>> getTypedDataComponentClass() {
|
||||
return getOptionalNMS("core.component.TypedDataComponent");
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.comphenix.protocol.utility;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import com.comphenix.protocol.wrappers.codecs.WrappedDynamicOps;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
@@ -17,6 +18,7 @@ public class MinecraftRegistryAccess {
|
||||
|
||||
private static MethodAccessor GET_SERVER = null;
|
||||
private static MethodAccessor REGISTRY_ACCESS = null;
|
||||
private static MethodAccessor CREATE_SERIALIZATION_CONTEXT = null;
|
||||
|
||||
// lazy initialized
|
||||
private static Object registryAccess = null;
|
||||
@@ -36,6 +38,14 @@ public class MinecraftRegistryAccess {
|
||||
.banModifier(Modifier.STATIC)
|
||||
.returnDerivedOf(MinecraftReflection.getRegistryAccessClass())
|
||||
.build()));
|
||||
|
||||
CREATE_SERIALIZATION_CONTEXT = Accessors.getMethodAccessor(
|
||||
FuzzyReflection.fromClass(MinecraftReflection.getHolderLookupProviderClass(), false)
|
||||
.getMethod(FuzzyMethodContract.newBuilder()
|
||||
.banModifier(Modifier.STATIC)
|
||||
.returnDerivedOf(MinecraftReflection.getDynamicOpsClass())
|
||||
.parameterDerivedOf(MinecraftReflection.getDynamicOpsClass())
|
||||
.build()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,4 +67,13 @@ public class MinecraftRegistryAccess {
|
||||
|
||||
return registryAccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a RegistryOps using the given DynamicOps as the underlying ops.
|
||||
*
|
||||
* @return a RegistryOps
|
||||
*/
|
||||
public static WrappedDynamicOps createSerializationContext(WrappedDynamicOps dynamicOps) {
|
||||
return WrappedDynamicOps.fromHandle(CREATE_SERIALIZATION_CONTEXT.invoke(get(), dynamicOps.getHandle()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.comphenix.protocol.utility;
|
||||
|
||||
public final class Validate {
|
||||
private Validate() {}
|
||||
|
||||
public static void notNull(Object obj, String err) {
|
||||
if (obj == null) {
|
||||
throw new IllegalArgumentException(err);
|
||||
}
|
||||
}
|
||||
|
||||
public static void isTrue(boolean bool, String err) {
|
||||
if (!bool) {
|
||||
throw new IllegalArgumentException(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.comphenix.protocol.utility;
|
||||
|
||||
public final class WordUtils {
|
||||
private WordUtils() {}
|
||||
|
||||
public static String capitalize(String str) {
|
||||
if (str == null || str.isEmpty()) {
|
||||
return str;
|
||||
}
|
||||
return str.substring(0, 1).toUpperCase() + str.substring(1).toLowerCase();
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import com.comphenix.protocol.utility.Validate;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.GameMode;
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject;
|
||||
import com.comphenix.protocol.wrappers.collection.ConvertedMap;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import com.comphenix.protocol.utility.Validate;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Entity;
|
||||
|
||||
|
||||
@@ -53,7 +53,14 @@ public class MinecraftKey {
|
||||
* @param key The key
|
||||
*/
|
||||
public MinecraftKey(String key) {
|
||||
this("minecraft", key);
|
||||
if (key.contains(":")) {
|
||||
String[] split = key.split(":", 2);
|
||||
this.prefix = split[0];
|
||||
this.key = split[1];
|
||||
} else {
|
||||
this.prefix = "minecraft";
|
||||
this.key = key;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
public class ResourceKey {
|
||||
private static final AutoWrapper<ResourceKey> AUTO_WRAPPER = AutoWrapper.wrap(ResourceKey.class, MinecraftReflection.getResourceKey())
|
||||
.field(0, MinecraftKey.getConverter())
|
||||
.field(1, MinecraftKey.getConverter());
|
||||
|
||||
MinecraftKey registryName;
|
||||
MinecraftKey location;
|
||||
|
||||
ResourceKey() {
|
||||
|
||||
}
|
||||
|
||||
public ResourceKey(MinecraftKey registryName, MinecraftKey location) {
|
||||
this.registryName = registryName;
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public MinecraftKey getRegistryName() {
|
||||
return registryName;
|
||||
}
|
||||
|
||||
public MinecraftKey getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public void setRegistryName(MinecraftKey registryName) {
|
||||
this.registryName = registryName;
|
||||
}
|
||||
|
||||
public void setLocation(MinecraftKey location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public static ResourceKey fromGeneric(Object generic) {
|
||||
return AUTO_WRAPPER.wrap(generic);
|
||||
}
|
||||
|
||||
public Object toGeneric() {
|
||||
return AUTO_WRAPPER.unwrap(this);
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ public abstract class WrappedBlockData extends AbstractWrapper implements Clonab
|
||||
private static MethodAccessor TO_LEGACY_DATA;
|
||||
private static MethodAccessor GET_BLOCK;
|
||||
private static MethodAccessor BLOCK_FROM_MATERIAL;
|
||||
private static MethodAccessor GET_BLOCK_DATA;
|
||||
private static MethodAccessor DEFAULT_BLOCK_DATA;
|
||||
private static MethodAccessor FROM_LEGACY_DATA;
|
||||
private static MethodAccessor GET_HANDLE;
|
||||
|
||||
@@ -100,7 +100,7 @@ public abstract class WrappedBlockData extends AbstractWrapper implements Clonab
|
||||
.parameterCount(0)
|
||||
.returnTypeExact(IBLOCK_DATA)
|
||||
.build();
|
||||
GET_BLOCK_DATA = Accessors.getMethodAccessor(fuzzy.getMethod(contract));
|
||||
DEFAULT_BLOCK_DATA = Accessors.getMethodAccessor(fuzzy.getMethod(contract));
|
||||
|
||||
fuzzy = FuzzyReflection.fromClass(MinecraftReflection.getCraftBukkitClass("block.data.CraftBlockData"));
|
||||
contract = FuzzyMethodContract
|
||||
@@ -131,7 +131,7 @@ public abstract class WrappedBlockData extends AbstractWrapper implements Clonab
|
||||
@Override
|
||||
public void setType(Material material) {
|
||||
Object block = BLOCK_FROM_MATERIAL.invoke(null, material);
|
||||
setHandle(GET_BLOCK_DATA.invoke(block));
|
||||
setHandle(DEFAULT_BLOCK_DATA.invoke(block));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -141,7 +141,7 @@ public abstract class WrappedBlockData extends AbstractWrapper implements Clonab
|
||||
|
||||
@Override
|
||||
public void setTypeAndData(Material material, int data) {
|
||||
setHandle(TO_LEGACY_DATA.invoke(null, material, (byte) data));
|
||||
setHandle(FROM_LEGACY_DATA.invoke(null, material, (byte) data));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -151,7 +151,7 @@ public abstract class WrappedBlockData extends AbstractWrapper implements Clonab
|
||||
|
||||
private static WrappedBlockData createNewData(Material material) {
|
||||
Object block = BLOCK_FROM_MATERIAL.invoke(null, material);
|
||||
return new NewBlockData(GET_BLOCK_DATA.invoke(block));
|
||||
return new NewBlockData(DEFAULT_BLOCK_DATA.invoke(block));
|
||||
}
|
||||
|
||||
private static WrappedBlockData createNewData(Material material, int data) {
|
||||
|
||||
@@ -6,7 +6,6 @@ import java.util.Optional;
|
||||
|
||||
import com.comphenix.protocol.wrappers.codecs.WrappedCodec;
|
||||
import com.comphenix.protocol.wrappers.codecs.WrappedDynamicOps;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonParser;
|
||||
import org.bukkit.ChatColor;
|
||||
@@ -42,6 +41,7 @@ public class WrappedChatComponent extends AbstractWrapper implements ClonableWra
|
||||
private static ConstructorAccessor CONSTRUCT_TEXT_COMPONENT = null;
|
||||
|
||||
private static WrappedCodec CODEC;
|
||||
private static WrappedDynamicOps REGISTRY_JSON_OPS;
|
||||
|
||||
static {
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(SERIALIZER, true);
|
||||
@@ -49,6 +49,7 @@ public class WrappedChatComponent extends AbstractWrapper implements ClonableWra
|
||||
if (MinecraftVersion.v1_21_6.atOrAbove()) {
|
||||
Field codecField = fuzzy.getFieldByType("CODEC", MinecraftReflection.getCodecClass());
|
||||
CODEC = WrappedCodec.fromHandle(Accessors.getFieldAccessor(codecField).get(null));
|
||||
REGISTRY_JSON_OPS = MinecraftRegistryAccess.createSerializationContext(WrappedDynamicOps.json(false));
|
||||
} else if (MinecraftVersion.v1_20_5.atOrAbove()) {
|
||||
SERIALIZE_COMPONENT = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract.newBuilder()
|
||||
.returnTypeExact(String.class)
|
||||
@@ -98,7 +99,7 @@ public class WrappedChatComponent extends AbstractWrapper implements ClonableWra
|
||||
|
||||
private static Object serialize(Object handle) {
|
||||
if (CODEC != null) {
|
||||
Object jobj = CODEC.encode(handle, WrappedDynamicOps.json(false)).getOrThrow(JsonParseException::new);
|
||||
Object jobj = CODEC.encode(handle, REGISTRY_JSON_OPS).getOrThrow(JsonParseException::new);
|
||||
return jobj.toString();
|
||||
}
|
||||
|
||||
@@ -111,7 +112,7 @@ public class WrappedChatComponent extends AbstractWrapper implements ClonableWra
|
||||
|
||||
private static Object deserialize(String json) {
|
||||
if (CODEC != null) {
|
||||
return CODEC.parse(JsonParser.parseString(json), WrappedDynamicOps.json(false)).getOrThrow(JsonParseException::new);
|
||||
return CODEC.parse(JsonParser.parseString(json), REGISTRY_JSON_OPS).getOrThrow(JsonParseException::new);
|
||||
}
|
||||
|
||||
if (MinecraftVersion.v1_20_5.atOrAbove()) {
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.lang.reflect.RecordComponent;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.reflect.cloning.AggregateCloner;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
/**
|
||||
* Represents a single data component in Minecraft, which is a key-value pair
|
||||
* used to store metadata about game objects such as items, mobs, and block entities.
|
||||
* <p>
|
||||
* This class provides methods to create, access, and manipulate data components,
|
||||
* as well as to convert them to and from their underlying NMS handles.
|
||||
*
|
||||
* @see WrappedDataComponentHolder
|
||||
*/
|
||||
public final class WrappedDataComponent {
|
||||
private static final Optional<Class<?>> HANDLE_TYPE = MinecraftReflection.getTypedDataComponentClass();
|
||||
|
||||
private static MethodAccessor TYPE_ACCESSOR;
|
||||
private static MethodAccessor VALUE_ACCESSOR;
|
||||
private static ConstructorAccessor CTOR_ACCESSOR;
|
||||
|
||||
private final Object keyHandle;
|
||||
private final String key;
|
||||
|
||||
private Object value;
|
||||
|
||||
static {
|
||||
initialize();
|
||||
}
|
||||
|
||||
private static void initialize() {
|
||||
if (HANDLE_TYPE.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Class<?> clazz = HANDLE_TYPE.get();
|
||||
RecordComponent typeComponent = clazz.getRecordComponents()[0];
|
||||
TYPE_ACCESSOR = Accessors.getMethodAccessor(typeComponent.getAccessor());
|
||||
|
||||
RecordComponent valueComponent = clazz.getRecordComponents()[1];
|
||||
VALUE_ACCESSOR = Accessors.getMethodAccessor(valueComponent.getAccessor());
|
||||
|
||||
CTOR_ACCESSOR = Accessors.getConstructorAccessor(clazz, typeComponent.getType(), valueComponent.getType());
|
||||
}
|
||||
|
||||
WrappedDataComponent(Object keyHandle, String key, Object value) {
|
||||
this.keyHandle = keyHandle;
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the key of this data component, e.g. "minecraft:custom_data".
|
||||
*/
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the in-memory value of this data component.
|
||||
* <br>
|
||||
* <b>NOTE:</b> this does <b>NOT</b> update the underlying handle
|
||||
* @param value new NMS value
|
||||
*/
|
||||
public void setValue(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the current in-memory value of this data component
|
||||
* @param <T> desired return type
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getValue() {
|
||||
return (T) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new WrappedDataComponent from an existing NMS handle.
|
||||
* @param handle NMS handle
|
||||
* @return new WrappedDataComponent instance
|
||||
*/
|
||||
public static WrappedDataComponent fromHandle(Object handle) {
|
||||
if (TYPE_ACCESSOR == null || VALUE_ACCESSOR == null) {
|
||||
throw new IllegalStateException("Unable to access TypedDataComponent");
|
||||
}
|
||||
|
||||
Object typeHandle = TYPE_ACCESSOR.invoke(handle);
|
||||
Object value = VALUE_ACCESSOR.invoke(handle);
|
||||
|
||||
WrappedRegistry componentTypeRegistry = WrappedRegistry.getDataComponentTypeRegistry();
|
||||
String key = componentTypeRegistry.getKey(typeHandle).getFullKey();
|
||||
|
||||
return new WrappedDataComponent(typeHandle, key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new NMS handle for this data component using the current value.
|
||||
* @return new NMS handle
|
||||
*/
|
||||
public Object getHandle() {
|
||||
if (CTOR_ACCESSOR == null) {
|
||||
throw new IllegalStateException("Unable to access TypedDataComponent constructor");
|
||||
}
|
||||
|
||||
return CTOR_ACCESSOR.invoke(keyHandle, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new WrappedDataComponent with the specified key and no value.
|
||||
* @param key the key of the data component, e.g. "minecraft:custom_data".
|
||||
* @return new WrappedDataComponent instance
|
||||
*/
|
||||
public static WrappedDataComponent create(String key) {
|
||||
return create(key, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new WrappedDataComponent with the specified key and value.
|
||||
* @param key the key of the data component, e.g. "minecraft:custom_data".
|
||||
* @param value the NMS value of the data component, e.g. an ItemStack or Integer.
|
||||
* @return new WrappedDataComponent instance
|
||||
*/
|
||||
public static WrappedDataComponent create(String key, Object value) {
|
||||
WrappedRegistry componentTypeRegistry = WrappedRegistry.getDataComponentTypeRegistry();
|
||||
Object keyHandle = componentTypeRegistry.get(key);
|
||||
|
||||
if (keyHandle == null) {
|
||||
throw new IllegalArgumentException("Invalid key: " + key);
|
||||
}
|
||||
|
||||
return new WrappedDataComponent(keyHandle, key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a shallow clone of this WrappedDataComponent, which means it copies the key and value references,
|
||||
* but does not clone the value itself. This should cover most cases where the value is immutable
|
||||
* (e.g. strings, numbers, enums).
|
||||
* @return a new WrappedDataComponent instance with the same key and value references
|
||||
*/
|
||||
public WrappedDataComponent shallowClone() {
|
||||
return new WrappedDataComponent(keyHandle, key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a deep clone of this WrappedDataComponent, which means it clones the value as well.
|
||||
* This is useful when the value is mutable (e.g. books, NBT data) and you want to ensure that
|
||||
* changes to the cloned component do not affect the original component.
|
||||
* @return a new WrappedDataComponent instance with a cloned value
|
||||
*/
|
||||
public WrappedDataComponent deepClone() {
|
||||
Object clonedValue = AggregateCloner.DEFAULT.clone(value);
|
||||
return new WrappedDataComponent(keyHandle, key, clonedValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WrappedDataComponent[" + key + "=>" + value + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof WrappedDataComponent other)) return false;
|
||||
|
||||
return key.equals(other.key) && value.equals(other.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = key.hashCode();
|
||||
result = 31 * result + (value != null ? value.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
/**
|
||||
* Provides access to a DataComponentHolder, which is an object that can hold
|
||||
* various (meta)data components
|
||||
*/
|
||||
public final class WrappedDataComponentHolder extends AbstractWrapper {
|
||||
private static MethodAccessor GET_COMPONENTS;
|
||||
private static MethodAccessor GET_COMPONENT;
|
||||
|
||||
private static Optional<Class<?>> DATA_COMPONENT_MAP_CLASS = MinecraftReflection.getDataComponentMapClass();
|
||||
private static Optional<Class<?>> DATA_COMPONENT_HOLDER_CLASS = MinecraftReflection.getDataComponentHolderClass();
|
||||
|
||||
static {
|
||||
initialize();
|
||||
}
|
||||
|
||||
private static void initialize() {
|
||||
if (DATA_COMPONENT_MAP_CLASS.isEmpty() || DATA_COMPONENT_HOLDER_CLASS.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Class<?> mapClass = DATA_COMPONENT_MAP_CLASS.get();
|
||||
Class<?> holderClass = DATA_COMPONENT_HOLDER_CLASS.get();
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(holderClass, true);
|
||||
GET_COMPONENTS = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract.newBuilder()
|
||||
.parameterCount(0)
|
||||
.returnTypeExact(mapClass)
|
||||
.build()));
|
||||
GET_COMPONENT = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract.newBuilder()
|
||||
.parameterCount(1)
|
||||
//.requireModifier(Modifier.PUBLIC)
|
||||
.banModifier(Modifier.STATIC)
|
||||
.parameterExactType(MinecraftReflection.getMinecraftClass("core.component.DataComponentType"))
|
||||
.build()));
|
||||
}
|
||||
|
||||
public WrappedDataComponentHolder(Object handle) {
|
||||
super(DATA_COMPONENT_HOLDER_CLASS.orElseThrow(() -> new IllegalStateException("DataComponentHolder class is not available in this version")));
|
||||
setHandle(handle);
|
||||
}
|
||||
|
||||
public Map<String, WrappedDataComponent> getAllComponents() {
|
||||
Iterable<?> components = (Iterable<?>) GET_COMPONENTS.invoke(handle);
|
||||
Map<String, WrappedDataComponent> wrapped = new HashMap<>();
|
||||
for (Object componentHandle : components) {
|
||||
WrappedDataComponent component = WrappedDataComponent.fromHandle(componentHandle);
|
||||
wrapped.put(component.getKey(), component);
|
||||
}
|
||||
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
public WrappedDataComponent getComponent(String key) {
|
||||
Object keyHandle = WrappedRegistry.getDataComponentTypeRegistry().get(key);
|
||||
Object valueHandle = GET_COMPONENT.invoke(handle, keyHandle);
|
||||
return new WrappedDataComponent(keyHandle, key, valueHandle);
|
||||
}
|
||||
|
||||
public static WrappedDataComponentHolder fromItemStack(ItemStack itemStack) {
|
||||
Object nmsStack = MinecraftReflection.getMinecraftItemStack(itemStack);
|
||||
return new WrappedDataComponentHolder(nmsStack);
|
||||
}
|
||||
}
|
||||
@@ -36,12 +36,12 @@ import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.comphenix.protocol.utility.Validate;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.Direction;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.EntityPose;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
||||
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -1,14 +1,5 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMatchers;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
@@ -19,21 +10,79 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMatchers;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
public class WrappedRegistry {
|
||||
// map of NMS class to registry instance
|
||||
private static final Map<Class<?>, WrappedRegistry> REGISTRY;
|
||||
private static final Map<Class<?>, WrappedRegistry> BY_CLASS;
|
||||
private static final Map<String, WrappedRegistry> BY_KEY;
|
||||
|
||||
private static final MethodAccessor GET;
|
||||
private static final MethodAccessor GET_ID;
|
||||
private static final MethodAccessor GET_KEY;
|
||||
private static final MethodAccessor GET_BY_KEY;
|
||||
private static final MethodAccessor GET_ITEM_ID;
|
||||
private static final MethodAccessor GET_ITEM_KEY;
|
||||
private static final MethodAccessor GET_REGISTRY_KEY;
|
||||
|
||||
private static final MethodAccessor GET_HOLDER;
|
||||
|
||||
static {
|
||||
Map<Class<?>, WrappedRegistry> regMap = new HashMap<>();
|
||||
Class<?> iRegistry = MinecraftReflection.getIRegistry();
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(iRegistry, false);
|
||||
|
||||
GET_BY_KEY = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract
|
||||
.newBuilder()
|
||||
.parameterCount(1)
|
||||
.returnTypeMatches(FuzzyMatchers.and(FuzzyMatchers.assignable(Object.class), FuzzyMatchers.except(Optional.class)))
|
||||
.requireModifier(Modifier.ABSTRACT)
|
||||
.parameterExactType(MinecraftReflection.getMinecraftKeyClass())
|
||||
.build()));
|
||||
GET_ITEM_ID = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract
|
||||
.newBuilder()
|
||||
.parameterCount(1)
|
||||
.returnTypeExact(int.class)
|
||||
.requireModifier(Modifier.ABSTRACT)
|
||||
.parameterDerivedOf(Object.class)
|
||||
.build()));
|
||||
GET_ITEM_KEY = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract
|
||||
.newBuilder()
|
||||
.parameterCount(1)
|
||||
.returnTypeExact(MinecraftReflection.getMinecraftKeyClass())
|
||||
.build()));
|
||||
GET_REGISTRY_KEY = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract
|
||||
.newBuilder()
|
||||
.parameterCount(0)
|
||||
.returnTypeExact(MinecraftReflection.getResourceKey())
|
||||
.build()));
|
||||
|
||||
MethodAccessor getHolder = null;
|
||||
|
||||
if (MinecraftVersion.FEATURE_PREVIEW_UPDATE.atOrAbove()) {
|
||||
try {
|
||||
getHolder = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract
|
||||
.newBuilder()
|
||||
.parameterCount(1)
|
||||
.banModifier(Modifier.STATIC)
|
||||
.returnTypeExact(MinecraftReflection.getHolderClass())
|
||||
.requireModifier(Modifier.PUBLIC)
|
||||
.build()));
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
GET_HOLDER = getHolder;
|
||||
|
||||
Map<Class<?>, WrappedRegistry> byClass = new HashMap<>();
|
||||
Map<String, WrappedRegistry> byKey = new HashMap<>();
|
||||
|
||||
// get the possible registry fields
|
||||
Class<?> iRegistry = MinecraftReflection.getIRegistry();
|
||||
|
||||
Class<?> builtInRegistries = MinecraftReflection.getBuiltInRegistries();
|
||||
Set<Field> registries = FuzzyReflection.combineArrays(
|
||||
iRegistry == null ? null : iRegistry.getFields(),
|
||||
@@ -43,95 +92,75 @@ public class WrappedRegistry {
|
||||
for (Field field : registries) {
|
||||
try {
|
||||
// make sure it's actually a registry
|
||||
if (iRegistry.isAssignableFrom(field.getType())) {
|
||||
Type genType = field.getGenericType();
|
||||
if (genType instanceof ParameterizedType) {
|
||||
ParameterizedType par = (ParameterizedType) genType;
|
||||
Type paramType = par.getActualTypeArguments()[0];
|
||||
if (paramType instanceof Class) {
|
||||
// for example Registry<Item>
|
||||
regMap.put((Class<?>) paramType, new WrappedRegistry(field.get(null)));
|
||||
} else if (paramType instanceof ParameterizedType) {
|
||||
// for example Registry<EntityType<?>>
|
||||
par = (ParameterizedType) paramType;
|
||||
paramType = par.getActualTypeArguments()[0];
|
||||
if (paramType instanceof WildcardType) {
|
||||
// some registry types are even more nested, but we don't want them
|
||||
// for example Registry<Codec<ChunkGenerator>>, Registry<Codec<WorldChunkManager>>
|
||||
WildcardType wildcard = (WildcardType) paramType;
|
||||
if (wildcard.getUpperBounds().length != 1 || wildcard.getLowerBounds().length > 0) {
|
||||
continue;
|
||||
}
|
||||
if (!iRegistry.isAssignableFrom(field.getType())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// we only want types with an undefined upper bound (aka. ?)
|
||||
if (wildcard.getUpperBounds()[0] != Object.class) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Type genType = field.getGenericType();
|
||||
if (!(genType instanceof ParameterizedType par)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
paramType = par.getRawType();
|
||||
if (paramType instanceof Class<?>) {
|
||||
// there might be duplicate registries, like the codec registries
|
||||
// we don't want them to be registered here
|
||||
regMap.put((Class<?>) paramType, new WrappedRegistry(field.get(null)));
|
||||
}
|
||||
Class<?> registryClass = null;
|
||||
|
||||
Type paramType = par.getActualTypeArguments()[0];
|
||||
if (paramType instanceof Class<?> paramClass) {
|
||||
// for example Registry<Item>
|
||||
registryClass = paramClass;
|
||||
} else if (paramType instanceof ParameterizedType) {
|
||||
// for example Registry<EntityType<?>>
|
||||
par = (ParameterizedType) paramType;
|
||||
paramType = par.getActualTypeArguments()[0];
|
||||
if (paramType instanceof WildcardType wildcard) {
|
||||
// some registry types are even more nested, but we don't want them
|
||||
// for example Registry<Codec<ChunkGenerator>>, Registry<Codec<WorldChunkManager>>
|
||||
if (wildcard.getUpperBounds().length != 1 || wildcard.getLowerBounds().length > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// we only want types with an undefined upper bound (aka. ?)
|
||||
if (wildcard.getUpperBounds()[0] != Object.class) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
paramType = par.getRawType();
|
||||
if (paramType instanceof Class<?> paramClass) {
|
||||
// there might be duplicate registries, like the codec registries
|
||||
// we don't want them to be registered here
|
||||
registryClass = paramClass;
|
||||
}
|
||||
}
|
||||
|
||||
Object handle = field.get(null);
|
||||
ResourceKey key = ResourceKey.fromGeneric(GET_REGISTRY_KEY.invoke(handle));
|
||||
WrappedRegistry wrapped = new WrappedRegistry(handle, key);
|
||||
|
||||
if (registryClass != null) {
|
||||
byClass.put(registryClass, wrapped);
|
||||
}
|
||||
|
||||
String registryName = key.getLocation().getFullKey();
|
||||
byKey.put(registryName, wrapped);
|
||||
} catch (ReflectiveOperationException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REGISTRY = ImmutableMap.copyOf(regMap);
|
||||
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(iRegistry, false);
|
||||
GET = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract
|
||||
.newBuilder()
|
||||
.parameterCount(1)
|
||||
.returnTypeMatches(FuzzyMatchers.and(FuzzyMatchers.assignable(Object.class), FuzzyMatchers.except(Optional.class)))
|
||||
.requireModifier(Modifier.ABSTRACT)
|
||||
.parameterExactType(MinecraftReflection.getMinecraftKeyClass())
|
||||
.build()));
|
||||
GET_ID = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract
|
||||
.newBuilder()
|
||||
.parameterCount(1)
|
||||
.returnTypeExact(int.class)
|
||||
.requireModifier(Modifier.ABSTRACT)
|
||||
.parameterDerivedOf(Object.class)
|
||||
.build()));
|
||||
GET_KEY = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract
|
||||
.newBuilder()
|
||||
.parameterCount(1)
|
||||
.returnTypeExact(MinecraftReflection.getMinecraftKeyClass())
|
||||
.build()));
|
||||
|
||||
MethodAccessor getHolder = null;
|
||||
|
||||
if (MinecraftVersion.FEATURE_PREVIEW_UPDATE.atOrAbove()) {
|
||||
try {
|
||||
getHolder = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract
|
||||
.newBuilder()
|
||||
.parameterCount(1)
|
||||
.banModifier(Modifier.STATIC)
|
||||
.returnTypeExact(MinecraftReflection.getHolderClass())
|
||||
.requireModifier(Modifier.PUBLIC)
|
||||
.build()));
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
GET_HOLDER = getHolder;
|
||||
BY_CLASS = ImmutableMap.copyOf(byClass);
|
||||
BY_KEY = ImmutableMap.copyOf(byKey);
|
||||
}
|
||||
|
||||
private final Object handle;
|
||||
private final ResourceKey key;
|
||||
|
||||
private WrappedRegistry(Object handle) {
|
||||
private WrappedRegistry(Object handle, ResourceKey key) {
|
||||
this.handle = handle;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public Object get(MinecraftKey key) {
|
||||
return GET.invoke(handle, MinecraftKey.getConverter().getGeneric(key));
|
||||
return GET_BY_KEY.invoke(handle, MinecraftKey.getConverter().getGeneric(key));
|
||||
}
|
||||
|
||||
public Object get(String key) {
|
||||
@@ -139,7 +168,11 @@ public class WrappedRegistry {
|
||||
}
|
||||
|
||||
public MinecraftKey getKey(Object generic) {
|
||||
return MinecraftKey.getConverter().getSpecific(GET_KEY.invoke(handle, generic));
|
||||
return MinecraftKey.getConverter().getSpecific(GET_ITEM_KEY.invoke(handle, generic));
|
||||
}
|
||||
|
||||
public ResourceKey getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public int getId(MinecraftKey key) {
|
||||
@@ -151,7 +184,7 @@ public class WrappedRegistry {
|
||||
}
|
||||
|
||||
public int getId(Object entry) {
|
||||
return (int) GET_ID.invoke(this.handle, entry);
|
||||
return (int) GET_ITEM_ID.invoke(this.handle, entry);
|
||||
}
|
||||
|
||||
public Object getHolder(Object generic) {
|
||||
@@ -170,7 +203,15 @@ public class WrappedRegistry {
|
||||
return getRegistry(MinecraftReflection.getSoundEffectClass());
|
||||
}
|
||||
|
||||
public static WrappedRegistry getDataComponentTypeRegistry() {
|
||||
return getByKey("minecraft:data_component_type");
|
||||
}
|
||||
|
||||
public static WrappedRegistry getRegistry(Class<?> type) {
|
||||
return REGISTRY.get(type);
|
||||
return BY_CLASS.get(type);
|
||||
}
|
||||
|
||||
public static WrappedRegistry getByKey(String key) {
|
||||
return BY_KEY.get(key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
name: ProtocolLib
|
||||
version: ${version}
|
||||
main: com.comphenix.protocol.ProtocolLibPaper
|
||||
api-version: '1.21.8'
|
||||
website: https://github.com/dmulloy2/ProtocolLib
|
||||
load: STARTUP
|
||||
@@ -3,7 +3,7 @@ version: ${version}
|
||||
description: Provides read/write access to the Minecraft protocol.
|
||||
authors: [dmulloy2, comphenix]
|
||||
|
||||
main: com.comphenix.protocol.ProtocolLib
|
||||
main: com.comphenix.protocol.ProtocolLibSpigot
|
||||
load: STARTUP
|
||||
database: false
|
||||
api-version: "1.13"
|
||||
|
||||
@@ -31,9 +31,8 @@ public class WrappedComponentStyleTest {
|
||||
|
||||
@Test
|
||||
public void testStyleAdventureConversion() {
|
||||
Style adventureStyle = Style.style(NamedTextColor.GREEN, TextDecoration.BOLD);
|
||||
// TODO(fix): wait for https://github.com/KyoriPowered/adventure/issues/1194 to be fixed
|
||||
// .clickEvent(ClickEvent.changePage(10));
|
||||
Style adventureStyle = Style.style(NamedTextColor.GREEN, TextDecoration.BOLD)
|
||||
.clickEvent(ClickEvent.changePage(10));
|
||||
|
||||
WrappedComponentStyle wrapped = AdventureComponentConverter.fromStyle(adventureStyle);
|
||||
assertEquals(adventureStyle, AdventureComponentConverter.fromWrapper(wrapped));
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
|
||||
public class WrappedDataComponentHolderTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeAll() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromItemStack() {
|
||||
WrappedDataComponentHolder holder = WrappedDataComponentHolder.fromItemStack(new org.bukkit.inventory.ItemStack(Material.DIAMOND_SWORD));
|
||||
Map<String, WrappedDataComponent> components = holder.getAllComponents();
|
||||
assertFalse(components.isEmpty(), "Components should not be empty");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class WrappedDataComponentTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeAll() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShallowClone() {
|
||||
WrappedDataComponentHolder holder = new WrappedDataComponentHolder(new ItemStack(Items.DIAMOND_AXE));
|
||||
Map<String, WrappedDataComponent> components = holder.getAllComponents();
|
||||
assertFalse(components.isEmpty(), "Components should not be empty");
|
||||
|
||||
for (WrappedDataComponent component : components.values()) {
|
||||
WrappedDataComponent clone = component.shallowClone();
|
||||
assertNotSame(component, clone, "Clone should not be the same instance");
|
||||
assertEquals(component, clone, "Clone should be equal to the original component");
|
||||
assertTrue(component.getValue().equals(clone.getValue()), "Clone value should match original");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeepCloneWithPrimitive() {
|
||||
WrappedDataComponent component = WrappedDataComponent.create("minecraft:damage", 10);
|
||||
WrappedDataComponent clone = component.deepClone();
|
||||
assertNotSame(component, clone, "Clone should not be the same instance");
|
||||
assertEquals(component, clone, "Clone should be equal to the original component");
|
||||
assertEquals(10, (int)clone.getValue(), "Clone value should match original");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeepCloneWithEnum() {
|
||||
WrappedDataComponent component = WrappedDataComponent.create("minecraft:item_model", Items.DIAMOND_SHOVEL);
|
||||
WrappedDataComponent clone = component.deepClone();
|
||||
assertNotSame(component, clone, "Clone should not be the same instance");
|
||||
assertEquals(component, clone, "Clone should be equal to the original component");
|
||||
assertEquals(Items.DIAMOND_SHOVEL, clone.getValue(), "Clone value should match original");
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user