resolve conflicts

This commit is contained in:
derklaro 2022-12-08 09:14:04 +01:00
commit 115cc83040
No known key found for this signature in database
GPG Key ID: FEB0E33393FE6B91
33 changed files with 5468 additions and 5468 deletions

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
* text=auto eol=lf

334
Readme.md
View File

@ -1,167 +1,167 @@
# ProtocolLib # ProtocolLib
Certain tasks are impossible to perform with the standard Bukkit API, and may require Certain tasks are impossible to perform with the standard Bukkit API, and may require
working with and even modifying Minecraft directly. A common technique is to modify incoming working with and even modifying Minecraft directly. A common technique is to modify incoming
and outgoing [packets](https://www.wiki.vg/Protocol), or inject custom packets into the and outgoing [packets](https://www.wiki.vg/Protocol), or inject custom packets into the
stream. This is quite cumbersome to do, however, and most implementations will break stream. This is quite cumbersome to do, however, and most implementations will break
as soon as a new version of Minecraft has been released, mostly due to obfuscation. as soon as a new version of Minecraft has been released, mostly due to obfuscation.
Critically, different plugins that use this approach may _hook_ into the same classes, Critically, different plugins that use this approach may _hook_ into the same classes,
with unpredictable outcomes. More than often this causes plugins to crash, but it may also with unpredictable outcomes. More than often this causes plugins to crash, but it may also
lead to more subtle bugs. lead to more subtle bugs.
Currently maintained by dmulloy2 on behalf of [Spigot](https://www.spigotmc.org/). Currently maintained by dmulloy2 on behalf of [Spigot](https://www.spigotmc.org/).
### Resources ### Resources
* [Resource Page](https://www.spigotmc.org/resources/protocollib.1997/) * [Resource Page](https://www.spigotmc.org/resources/protocollib.1997/)
* [Dev Builds](https://ci.dmulloy2.net/job/ProtocolLib) * [Dev Builds](https://ci.dmulloy2.net/job/ProtocolLib)
* [JavaDoc](https://ci.dmulloy2.net/job/ProtocolLib/javadoc/index.html) * [JavaDoc](https://ci.dmulloy2.net/job/ProtocolLib/javadoc/index.html)
### Compilation ### Compilation
ProtocolLib is built with [Maven](https://maven.apache.org/). If you have it installed, just run ProtocolLib is built with [Maven](https://maven.apache.org/). If you have it installed, just run
`mvn package` in the root project folder. `mvn package` in the root project folder.
### A new API ### A new API
__ProtocolLib__ attempts to solve this problem by providing an event API, much like Bukkit, __ProtocolLib__ attempts to solve this problem by providing an event API, much like Bukkit,
that allows plugins to monitor, modify, or cancel packets sent and received. But, more importantly, that allows plugins to monitor, modify, or cancel packets sent and received. But, more importantly,
the API also hides all the gritty, obfuscated classes with a simple index based read/write system. the API also hides all the gritty, obfuscated classes with a simple index based read/write system.
You no longer have to reference CraftBukkit! You no longer have to reference CraftBukkit!
### Using ProtocolLib ### Using ProtocolLib
To use this library, first add ProtocolLib.jar to your Java build path. Then, add ProtocolLib To use this library, first add ProtocolLib.jar to your Java build path. Then, add ProtocolLib
as a dependency or soft dependency to your plugin.yml file like any other plugin: as a dependency or soft dependency to your plugin.yml file like any other plugin:
````yml ````yml
depend: [ ProtocolLib ] depend: [ ProtocolLib ]
```` ````
You can also add ProtocolLib as a Maven dependency: You can also add ProtocolLib as a Maven dependency:
````xml ````xml
<repositories> <repositories>
<repository> <repository>
<id>dmulloy2-repo</id> <id>dmulloy2-repo</id>
<url>https://repo.dmulloy2.net/repository/public/</url> <url>https://repo.dmulloy2.net/repository/public/</url>
</repository> </repository>
</repositories> </repositories>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.comphenix.protocol</groupId> <groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId> <artifactId>ProtocolLib</artifactId>
<version>4.7.0</version> <version>4.7.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
</dependencies> </dependencies>
```` ````
Or use the maven dependency with gradle: Or use the maven dependency with gradle:
```gradle ```gradle
repositories { repositories {
maven { url "https://repo.dmulloy2.net/repository/public/" } maven { url "https://repo.dmulloy2.net/repository/public/" }
} }
dependencies { dependencies {
compileOnly group: "com.comphenix.protocol", name: "ProtocolLib", version: "4.7.0"; compileOnly group: "com.comphenix.protocol", name: "ProtocolLib", version: "4.7.0";
} }
``` ```
Then get a reference to ProtocolManager in onLoad() or onEnable() and you're good to go. Then get a reference to ProtocolManager in onLoad() or onEnable() and you're good to go.
````java ````java
private ProtocolManager protocolManager; private ProtocolManager protocolManager;
public void onLoad() { public void onLoad() {
protocolManager = ProtocolLibrary.getProtocolManager(); protocolManager = ProtocolLibrary.getProtocolManager();
} }
```` ````
To listen for packets sent by the server to a client, add a server-side listener: To listen for packets sent by the server to a client, add a server-side listener:
````java ````java
// Disable all sound effects // Disable all sound effects
protocolManager.addPacketListener(new PacketAdapter( protocolManager.addPacketListener(new PacketAdapter(
this, this,
ListenerPriority.NORMAL, ListenerPriority.NORMAL,
PacketType.Play.Server.NAMED_SOUND_EFFECT PacketType.Play.Server.NAMED_SOUND_EFFECT
) { ) {
@Override @Override
public void onPacketSending(PacketEvent event) { public void onPacketSending(PacketEvent event) {
event.setCancelled(true); event.setCancelled(true);
} }
}); });
```` ````
It's also possible to read and modify the content of these packets. For instance, you can create a global It's also possible to read and modify the content of these packets. For instance, you can create a global
censor by listening for Packet3Chat events: censor by listening for Packet3Chat events:
````java ````java
// Censor // Censor
protocolManager.addPacketListener(new PacketAdapter( protocolManager.addPacketListener(new PacketAdapter(
this, this,
ListenerPriority.NORMAL, ListenerPriority.NORMAL,
PacketType.Play.Client.CHAT PacketType.Play.Client.CHAT
) { ) {
@Override @Override
public void onPacketReceiving(PacketEvent event) { public void onPacketReceiving(PacketEvent event) {
PacketContainer packet = event.getPacket(); PacketContainer packet = event.getPacket();
String message = packet.getStrings().read(0); String message = packet.getStrings().read(0);
if (message.contains("shit") || message.contains("damn")) { if (message.contains("shit") || message.contains("damn")) {
event.setCancelled(true); event.setCancelled(true);
event.getPlayer().sendMessage("Bad manners!"); event.getPlayer().sendMessage("Bad manners!");
} }
} }
}); });
```` ````
### Sending packets ### Sending packets
Normally, you might have to do something ugly like the following: Normally, you might have to do something ugly like the following:
````java ````java
PacketPlayOutExplosion fakeExplosion = new PacketPlayOutExplosion( PacketPlayOutExplosion fakeExplosion = new PacketPlayOutExplosion(
player.getLocation().getX(), player.getLocation().getX(),
player.getLocation().getY(), player.getLocation().getY(),
player.getLocation().getZ(), player.getLocation().getZ(),
3.0F, 3.0F,
new ArrayList<>(), new ArrayList<>(),
new Vec3D( new Vec3D(
player.getVelocity().getX() + 1, player.getVelocity().getX() + 1,
player.getVelocity().getY() + 1, player.getVelocity().getY() + 1,
player.getVelocity().getZ() + 1 player.getVelocity().getZ() + 1
) )
); );
((CraftPlayer) player).getHandle().b.a(fakeExplosion); ((CraftPlayer) player).getHandle().b.a(fakeExplosion);
```` ````
But with ProtocolLib, you can turn that into something more manageable: But with ProtocolLib, you can turn that into something more manageable:
````java ````java
PacketContainer fakeExplosion = new PacketContainer(PacketType.Play.Server.EXPLOSION); PacketContainer fakeExplosion = new PacketContainer(PacketType.Play.Server.EXPLOSION);
fakeExplosion.getDoubles() fakeExplosion.getDoubles()
.write(0, player.getLocation().getX()) .write(0, player.getLocation().getX())
.write(1, player.getLocation().getY()) .write(1, player.getLocation().getY())
.write(2, player.getLocation().getZ()); .write(2, player.getLocation().getZ());
fakeExplosion.getFloat().write(0, 3.0F); fakeExplosion.getFloat().write(0, 3.0F);
fakeExplosion.getBlockPositionCollectionModifier().write(0, new ArrayList<>()); fakeExplosion.getBlockPositionCollectionModifier().write(0, new ArrayList<>());
fakeExplosion.getVectors().write(0, player.getVelocity().add(new Vector(1, 1, 1))); fakeExplosion.getVectors().write(0, player.getVelocity().add(new Vector(1, 1, 1)));
protocolManager.sendServerPacket(player, fakeExplosion); protocolManager.sendServerPacket(player, fakeExplosion);
```` ````
### Compatibility ### Compatibility
One of the main goals of this project was to achieve maximum compatibility with CraftBukkit. And the end One of the main goals of this project was to achieve maximum compatibility with CraftBukkit. And the end
result is quite flexible. It's likely that I won't have to update ProtocolLib for anything but bug fixes result is quite flexible. It's likely that I won't have to update ProtocolLib for anything but bug fixes
and new features. and new features.
How is this possible? It all comes down to reflection in the end. Essentially, no name is hard coded - How is this possible? It all comes down to reflection in the end. Essentially, no name is hard coded -
every field, method and class is deduced by looking at field types, package names or parameter every field, method and class is deduced by looking at field types, package names or parameter
types. It's remarkably consistent across different versions. types. It's remarkably consistent across different versions.

View File

@ -1,284 +1,284 @@
/** /**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2017 Dan Mulloy * Copyright (C) 2017 Dan Mulloy
* *
* This program is free software; you can redistribute it and/or modify it under the terms of the * This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of * GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version. * the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License along with this program; * You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA * 02111-1307 USA
*/ */
package com.comphenix.protocol; package com.comphenix.protocol;
import com.comphenix.protocol.PacketType.Protocol; import com.comphenix.protocol.PacketType.Protocol;
import com.comphenix.protocol.PacketType.Sender; import com.comphenix.protocol.PacketType.Sender;
import com.comphenix.protocol.events.ListeningWhitelist; import com.comphenix.protocol.events.ListeningWhitelist;
import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.events.PacketListener; import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.injector.netty.WirePacket; import com.comphenix.protocol.injector.netty.WirePacket;
import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.accessors.Accessors; import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.MethodAccessor; import com.comphenix.protocol.reflect.accessors.MethodAccessor;
import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.utility.MinecraftReflection;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.logging.FileHandler; import java.util.logging.FileHandler;
import java.util.logging.Formatter; import java.util.logging.Formatter;
import java.util.logging.Handler; import java.util.logging.Handler;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.LogRecord; import java.util.logging.LogRecord;
import java.util.logging.Logger; import java.util.logging.Logger;
/** /**
* Logs packets to a given stream * Logs packets to a given stream
* @author dmulloy2 * @author dmulloy2
*/ */
public class PacketLogging implements CommandExecutor, PacketListener { public class PacketLogging implements CommandExecutor, PacketListener {
public static final String NAME = "packetlog"; public static final String NAME = "packetlog";
private static MethodAccessor HEX_DUMP; private static MethodAccessor HEX_DUMP;
private List<PacketType> sendingTypes = new ArrayList<>(); private List<PacketType> sendingTypes = new ArrayList<>();
private List<PacketType> receivingTypes = new ArrayList<>(); private List<PacketType> receivingTypes = new ArrayList<>();
private ListeningWhitelist sendingWhitelist; private ListeningWhitelist sendingWhitelist;
private ListeningWhitelist receivingWhitelist; private ListeningWhitelist receivingWhitelist;
private Logger fileLogger; private Logger fileLogger;
private LogLocation location = LogLocation.FILE; private LogLocation location = LogLocation.FILE;
private final ProtocolManager manager; private final ProtocolManager manager;
private final Plugin plugin; private final Plugin plugin;
PacketLogging(Plugin plugin, ProtocolManager manager) { PacketLogging(Plugin plugin, ProtocolManager manager) {
this.plugin = plugin; this.plugin = plugin;
this.manager = manager; this.manager = manager;
} }
@Override @Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
PacketType type = null; PacketType type = null;
try { try {
if (args.length > 2) { if (args.length > 2) {
Protocol protocol; Protocol protocol;
try { try {
protocol = Protocol.valueOf(args[0].toUpperCase()); protocol = Protocol.valueOf(args[0].toUpperCase());
} catch (IllegalArgumentException ex) { } catch (IllegalArgumentException ex) {
sender.sendMessage(ChatColor.RED + "Unknown protocol " + args[0]); sender.sendMessage(ChatColor.RED + "Unknown protocol " + args[0]);
return true; return true;
} }
Sender pSender; Sender pSender;
try { try {
pSender = Sender.valueOf(args[1].toUpperCase()); pSender = Sender.valueOf(args[1].toUpperCase());
} catch (IllegalArgumentException ex) { } catch (IllegalArgumentException ex) {
sender.sendMessage(ChatColor.RED + "Unknown sender: " + args[1]); sender.sendMessage(ChatColor.RED + "Unknown sender: " + args[1]);
return true; return true;
} }
try { try {
try { // Try IDs first try { // Try IDs first
int id = Integer.parseInt(args[2]); int id = Integer.parseInt(args[2]);
type = PacketType.findCurrent(protocol, pSender, id); type = PacketType.findCurrent(protocol, pSender, id);
} catch (NumberFormatException ex) { // Check packet names } catch (NumberFormatException ex) { // Check packet names
String name = args[2]; String name = args[2];
for (PacketType packet : PacketType.values()) { for (PacketType packet : PacketType.values()) {
if (packet.getProtocol() == protocol && packet.getSender() == pSender) { if (packet.getProtocol() == protocol && packet.getSender() == pSender) {
if (packet.name().equalsIgnoreCase(name)) { if (packet.name().equalsIgnoreCase(name)) {
type = packet; type = packet;
break; break;
} }
for (String className : packet.getClassNames()) { for (String className : packet.getClassNames()) {
if (className.equalsIgnoreCase(name)) { if (className.equalsIgnoreCase(name)) {
type = packet; type = packet;
break; break;
} }
} }
} }
} }
} }
} catch (IllegalArgumentException ex) { // RIP } catch (IllegalArgumentException ex) { // RIP
type = null; type = null;
} }
if (type == null) { if (type == null) {
sender.sendMessage(ChatColor.RED + "Unknown packet: " + args[2]); sender.sendMessage(ChatColor.RED + "Unknown packet: " + args[2]);
return true; return true;
} }
if (args.length > 3) { if (args.length > 3) {
if (args[3].equalsIgnoreCase("console")) { if (args[3].equalsIgnoreCase("console")) {
this.location = LogLocation.CONSOLE; this.location = LogLocation.CONSOLE;
} else { } else {
this.location = LogLocation.FILE; this.location = LogLocation.FILE;
} }
} }
if (pSender == Sender.CLIENT) { if (pSender == Sender.CLIENT) {
if (receivingTypes.contains(type)) { if (receivingTypes.contains(type)) {
receivingTypes.remove(type); receivingTypes.remove(type);
} else { } else {
receivingTypes.add(type); receivingTypes.add(type);
} }
} else { } else {
if (sendingTypes.contains(type)) { if (sendingTypes.contains(type)) {
sendingTypes.remove(type); sendingTypes.remove(type);
} else { } else {
sendingTypes.add(type); sendingTypes.add(type);
} }
} }
startLogging(); startLogging();
sender.sendMessage(ChatColor.GREEN + "Now logging " + type.getPacketClass().getSimpleName()); sender.sendMessage(ChatColor.GREEN + "Now logging " + type.getPacketClass().getSimpleName());
return true; return true;
} }
sender.sendMessage(ChatColor.RED + "Invalid syntax: /packetlog <protocol> <sender> <packet> [location]"); sender.sendMessage(ChatColor.RED + "Invalid syntax: /packetlog <protocol> <sender> <packet> [location]");
return true; return true;
} catch (Throwable ex) { } catch (Throwable ex) {
sender.sendMessage(ChatColor.RED + "Failed to parse command: " + ex.toString()); sender.sendMessage(ChatColor.RED + "Failed to parse command: " + ex.toString());
return true; return true;
} }
} }
private void startLogging() { private void startLogging() {
manager.removePacketListener(this); manager.removePacketListener(this);
if (sendingTypes.isEmpty() && receivingTypes.isEmpty()) { if (sendingTypes.isEmpty() && receivingTypes.isEmpty()) {
return; return;
} }
this.sendingWhitelist = ListeningWhitelist.newBuilder().types(sendingTypes).build(); this.sendingWhitelist = ListeningWhitelist.newBuilder().types(sendingTypes).build();
this.receivingWhitelist = ListeningWhitelist.newBuilder().types(receivingTypes).build(); this.receivingWhitelist = ListeningWhitelist.newBuilder().types(receivingTypes).build();
// Setup the file logger if it hasn't been already // Setup the file logger if it hasn't been already
if (location == LogLocation.FILE && fileLogger == null) { if (location == LogLocation.FILE && fileLogger == null) {
fileLogger = Logger.getLogger("ProtocolLib-FileLogging"); fileLogger = Logger.getLogger("ProtocolLib-FileLogging");
for (Handler handler : fileLogger.getHandlers()) for (Handler handler : fileLogger.getHandlers())
fileLogger.removeHandler(handler); fileLogger.removeHandler(handler);
fileLogger.setUseParentHandlers(false); fileLogger.setUseParentHandlers(false);
try { try {
File logFile = new File(plugin.getDataFolder(), "log.log"); File logFile = new File(plugin.getDataFolder(), "log.log");
FileHandler handler = new FileHandler(logFile.getAbsolutePath(), true); FileHandler handler = new FileHandler(logFile.getAbsolutePath(), true);
handler.setFormatter(new LogFormatter()); handler.setFormatter(new LogFormatter());
fileLogger.addHandler(handler); fileLogger.addHandler(handler);
} catch (IOException ex) { } catch (IOException ex) {
plugin.getLogger().log(Level.SEVERE, "Failed to obtain log file:", ex); plugin.getLogger().log(Level.SEVERE, "Failed to obtain log file:", ex);
return; return;
} }
} }
manager.addPacketListener(this); manager.addPacketListener(this);
} }
@Override @Override
public void onPacketSending(PacketEvent event) { public void onPacketSending(PacketEvent event) {
log(event); log(event);
} }
@Override @Override
public void onPacketReceiving(PacketEvent event) { public void onPacketReceiving(PacketEvent event) {
log(event); log(event);
} }
// Here's where the magic happens // Here's where the magic happens
private static String hexDump(byte[] bytes) throws IOException { private static String hexDump(byte[] bytes) throws IOException {
try (ByteArrayOutputStream output = new ByteArrayOutputStream()) { try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
if (HEX_DUMP == null) { if (HEX_DUMP == null) {
Class<?> hexDumpClass = MinecraftReflection.getLibraryClass("org.apache.commons.io.HexDump"); Class<?> hexDumpClass = MinecraftReflection.getLibraryClass("org.apache.commons.io.HexDump");
HEX_DUMP = Accessors.getMethodAccessor(FuzzyReflection.fromClass(hexDumpClass) HEX_DUMP = Accessors.getMethodAccessor(FuzzyReflection.fromClass(hexDumpClass)
.getMethodByParameters("dump", byte[].class, long.class, OutputStream.class, int.class)); .getMethodByParameters("dump", byte[].class, long.class, OutputStream.class, int.class));
} }
HEX_DUMP.invoke(null, bytes, 0, output, 0); HEX_DUMP.invoke(null, bytes, 0, output, 0);
return new String(output.toByteArray(), StandardCharsets.UTF_8); return new String(output.toByteArray(), StandardCharsets.UTF_8);
} }
} }
private void log(PacketEvent event) { private void log(PacketEvent event) {
try { try {
byte[] bytes = WirePacket.bytesFromPacket(event.getPacket()); byte[] bytes = WirePacket.bytesFromPacket(event.getPacket());
String hexDump = hexDump(bytes); String hexDump = hexDump(bytes);
if (location == LogLocation.FILE) { if (location == LogLocation.FILE) {
fileLogger.log(Level.INFO, event.getPacketType() + ":"); fileLogger.log(Level.INFO, event.getPacketType() + ":");
fileLogger.log(Level.INFO, hexDump); fileLogger.log(Level.INFO, hexDump);
fileLogger.log(Level.INFO, ""); fileLogger.log(Level.INFO, "");
} else { } else {
System.out.println(event.getPacketType() + ":"); System.out.println(event.getPacketType() + ":");
System.out.println(hexDump); System.out.println(hexDump);
System.out.println(); System.out.println();
} }
} catch (Throwable ex) { } catch (Throwable ex) {
plugin.getLogger().log(Level.WARNING, "Failed to log packet " + event.getPacketType() + ":", ex); plugin.getLogger().log(Level.WARNING, "Failed to log packet " + event.getPacketType() + ":", ex);
plugin.getLogger().log(Level.WARNING, "Clearing packet logger..."); plugin.getLogger().log(Level.WARNING, "Clearing packet logger...");
sendingTypes.clear(); sendingTypes.clear();
receivingTypes.clear(); receivingTypes.clear();
startLogging(); startLogging();
} }
} }
@Override @Override
public ListeningWhitelist getSendingWhitelist() { public ListeningWhitelist getSendingWhitelist() {
return sendingWhitelist; return sendingWhitelist;
} }
@Override @Override
public ListeningWhitelist getReceivingWhitelist() { public ListeningWhitelist getReceivingWhitelist() {
return receivingWhitelist; return receivingWhitelist;
} }
@Override @Override
public Plugin getPlugin() { public Plugin getPlugin() {
return plugin; return plugin;
} }
private enum LogLocation { private enum LogLocation {
CONSOLE, FILE CONSOLE, FILE
} }
private static class LogFormatter extends Formatter { private static class LogFormatter extends Formatter {
private static final SimpleDateFormat DATE = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); private static final SimpleDateFormat DATE = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private static final String LINE_SEPARATOR = System.getProperty("line.separator"); private static final String LINE_SEPARATOR = System.getProperty("line.separator");
private static final String FORMAT = "[{0}] {1}"; private static final String FORMAT = "[{0}] {1}";
@Override @Override
public String format(LogRecord record) { public String format(LogRecord record) {
String string = formatMessage(record); String string = formatMessage(record);
if (string.isEmpty()) { if (string.isEmpty()) {
return LINE_SEPARATOR; return LINE_SEPARATOR;
} }
StringBuilder message = new StringBuilder(); StringBuilder message = new StringBuilder();
message.append(MessageFormat.format(FORMAT, DATE.format(record.getMillis()), string)); message.append(MessageFormat.format(FORMAT, DATE.format(record.getMillis()), string));
message.append(LINE_SEPARATOR); message.append(LINE_SEPARATOR);
return message.toString(); return message.toString();
} }
} }
} }

View File

@ -1,143 +1,143 @@
/** /**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2017 dmulloy2 * Copyright (C) 2017 dmulloy2
* *
* This program is free software; you can redistribute it and/or modify it under the terms of the * This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of * GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version. * the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License along with this program; * You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA * 02111-1307 USA
*/ */
package com.comphenix.protocol.events; package com.comphenix.protocol.events;
import java.util.*; import java.util.*;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import com.google.common.cache.Cache; import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
/** /**
* Stores and retrieves metadata for applicable packet objects. * Stores and retrieves metadata for applicable packet objects.
* @author dmulloy2 * @author dmulloy2
*/ */
class PacketMetadata { class PacketMetadata {
private static class MetaObject<T> { private static class MetaObject<T> {
private final String key; private final String key;
private final T value; private final T value;
private MetaObject(String key, T value) { private MetaObject(String key, T value) {
this.key = key; this.key = key;
this.value = value; this.value = value;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(key, value); return Objects.hash(key, value);
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (o == this) return true; if (o == this) return true;
if (o instanceof MetaObject) { if (o instanceof MetaObject) {
MetaObject that = (MetaObject) o; MetaObject that = (MetaObject) o;
return that.key.equals(this.key) && return that.key.equals(this.key) &&
that.value.equals(this.value); that.value.equals(this.value);
} }
return false; return false;
} }
@Override @Override
public String toString() { public String toString() {
return "MetaObject[" + key + "=" + value + "]"; return "MetaObject[" + key + "=" + value + "]";
} }
} }
// Packet meta cache // Packet meta cache
private static Cache<Object, List<MetaObject>> META_CACHE; private static Cache<Object, List<MetaObject>> META_CACHE;
public static <T> Optional<T> get(Object packet, String key) { public static <T> Optional<T> get(Object packet, String key) {
Validate.notNull(key, "Null keys are not permitted!"); Validate.notNull(key, "Null keys are not permitted!");
if (META_CACHE == null) { if (META_CACHE == null) {
return Optional.empty(); return Optional.empty();
} }
List<MetaObject> meta = META_CACHE.getIfPresent(packet); List<MetaObject> meta = META_CACHE.getIfPresent(packet);
if (meta == null) { if (meta == null) {
return Optional.empty(); return Optional.empty();
} }
for (MetaObject object : meta) { for (MetaObject object : meta) {
if (object.key.equals(key)) { if (object.key.equals(key)) {
return Optional.of((T) object.value); return Optional.of((T) object.value);
} }
} }
return Optional.empty(); return Optional.empty();
} }
private static void createCache() { private static void createCache() {
META_CACHE = CacheBuilder META_CACHE = CacheBuilder
.newBuilder() .newBuilder()
.expireAfterWrite(1, TimeUnit.MINUTES) .expireAfterWrite(1, TimeUnit.MINUTES)
.build(); .build();
} }
public static <T> void set(Object packet, String key, T value) { public static <T> void set(Object packet, String key, T value) {
Validate.notNull(key, "Null keys are not permitted!"); Validate.notNull(key, "Null keys are not permitted!");
if (META_CACHE == null) { if (META_CACHE == null) {
createCache(); createCache();
} }
List<MetaObject> packetMeta; List<MetaObject> packetMeta;
try { try {
packetMeta = META_CACHE.get(packet, ArrayList::new); packetMeta = META_CACHE.get(packet, ArrayList::new);
} catch (ExecutionException ex) { } catch (ExecutionException ex) {
// Not possible, but let's humor the array list constructor having an issue // Not possible, but let's humor the array list constructor having an issue
packetMeta = new ArrayList<>(); packetMeta = new ArrayList<>();
} }
packetMeta.removeIf(meta -> meta.key.equals(key)); packetMeta.removeIf(meta -> meta.key.equals(key));
packetMeta.add(new MetaObject<>(key, value)); packetMeta.add(new MetaObject<>(key, value));
META_CACHE.put(packet, packetMeta); META_CACHE.put(packet, packetMeta);
} }
public static <T> Optional<T> remove(Object packet, String key) { public static <T> Optional<T> remove(Object packet, String key) {
Validate.notNull(key, "Null keys are not permitted!"); Validate.notNull(key, "Null keys are not permitted!");
if (META_CACHE == null) { if (META_CACHE == null) {
return Optional.empty(); return Optional.empty();
} }
List<MetaObject> packetMeta = META_CACHE.getIfPresent(packet); List<MetaObject> packetMeta = META_CACHE.getIfPresent(packet);
if (packetMeta == null) { if (packetMeta == null) {
return Optional.empty(); return Optional.empty();
} }
Optional<T> value = Optional.empty(); Optional<T> value = Optional.empty();
Iterator<MetaObject> iter = packetMeta.iterator(); Iterator<MetaObject> iter = packetMeta.iterator();
while (iter.hasNext()) { while (iter.hasNext()) {
MetaObject meta = iter.next(); MetaObject meta = iter.next();
if (meta.key.equals(key)) { if (meta.key.equals(key)) {
value = Optional.of((T) meta.value); value = Optional.of((T) meta.value);
iter.remove(); iter.remove();
} }
} }
return value; return value;
} }
} }

View File

@ -1,43 +1,43 @@
/** /**
* (c) 2018 dmulloy2 * (c) 2018 dmulloy2
*/ */
package com.comphenix.protocol.reflect.cloning; package com.comphenix.protocol.reflect.cloning;
import java.util.Optional; import java.util.Optional;
import java.util.OptionalInt; import java.util.OptionalInt;
/** /**
* A cloner that can clone Java Optional objects * A cloner that can clone Java Optional objects
* @author dmulloy2 * @author dmulloy2
*/ */
public class JavaOptionalCloner implements Cloner { public class JavaOptionalCloner implements Cloner {
protected Cloner wrapped; protected Cloner wrapped;
public JavaOptionalCloner(Cloner wrapped) { public JavaOptionalCloner(Cloner wrapped) {
this.wrapped = wrapped; this.wrapped = wrapped;
} }
@Override @Override
public boolean canClone(Object source) { public boolean canClone(Object source) {
return source instanceof Optional || source instanceof OptionalInt; return source instanceof Optional || source instanceof OptionalInt;
} }
@Override @Override
public Object clone(Object source) { public Object clone(Object source) {
if (source instanceof Optional) { if (source instanceof Optional) {
Optional<?> optional = (Optional<?>) source; Optional<?> optional = (Optional<?>) source;
return optional.map(o -> wrapped.clone(o)); return optional.map(o -> wrapped.clone(o));
} else if (source instanceof OptionalInt) { } else if (source instanceof OptionalInt) {
// why Java felt the need to make each optional class distinct is beyond me // why Java felt the need to make each optional class distinct is beyond me
// like why couldn't they have given us at least a common interface or something // like why couldn't they have given us at least a common interface or something
OptionalInt optional = (OptionalInt) source; OptionalInt optional = (OptionalInt) source;
return optional.isPresent() ? OptionalInt.of(optional.getAsInt()) : OptionalInt.empty(); return optional.isPresent() ? OptionalInt.of(optional.getAsInt()) : OptionalInt.empty();
} }
return null; return null;
} }
public Cloner getWrapped() { public Cloner getWrapped() {
return wrapped; return wrapped;
} }
} }

View File

@ -17,15 +17,16 @@
package com.comphenix.protocol.utility; package com.comphenix.protocol.utility;
import com.comphenix.protocol.ProtocolLibrary;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Ordering;
import java.io.Serializable; import java.io.Serializable;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Locale; import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import com.comphenix.protocol.ProtocolLibrary;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Ordering;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Server; import org.bukkit.Server;

View File

@ -1,194 +1,194 @@
/** /**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2017 Dan Mulloy * Copyright (C) 2017 Dan Mulloy
* *
* This program is free software; you can redistribute it and/or modify it under the terms of the * This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of * GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version. * the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License along with this program; * You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA * 02111-1307 USA
*/ */
package com.comphenix.protocol.wrappers; package com.comphenix.protocol.wrappers;
import com.comphenix.protocol.reflect.accessors.Accessors; import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor; import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
import com.comphenix.protocol.reflect.accessors.FieldAccessor; import com.comphenix.protocol.reflect.accessors.FieldAccessor;
import com.google.common.base.Defaults; import com.google.common.base.Defaults;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import com.comphenix.protocol.reflect.EquivalentConverter; import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.utility.MinecraftReflection;
/** /**
* Automatically wraps an internal NMS class to a non-versioned, deofbuscated class. * Automatically wraps an internal NMS class to a non-versioned, deofbuscated class.
* Requirements: * Requirements:
* <ul> * <ul>
* <li>The wrapper must be public</li> * <li>The wrapper must be public</li>
* <li>If the wrapper is an internal class, it must be static</li> * <li>If the wrapper is an internal class, it must be static</li>
* <li>The wrapper must have one public constructor with no arguments (the default constructor is acceptable)</li> * <li>The wrapper must have one public constructor with no arguments (the default constructor is acceptable)</li>
* <li>The wrapper must have the the same number of fields as the NMS class</li> * <li>The wrapper must have the the same number of fields as the NMS class</li>
* <li>Each field should correspond, in order, to its NMS counterpart</li> * <li>Each field should correspond, in order, to its NMS counterpart</li>
* <li>Non-generic fields must have a converter</li> * <li>Non-generic fields must have a converter</li>
* </ul> * </ul>
* *
* @author dmulloy2 * @author dmulloy2
*/ */
public class AutoWrapper<T> implements EquivalentConverter<T> { public class AutoWrapper<T> implements EquivalentConverter<T> {
private static final Object[] NO_ARGS = new Object[0]; private static final Object[] NO_ARGS = new Object[0];
private Map<Integer, Function<Object, Object>> wrappers = new HashMap<>(); private Map<Integer, Function<Object, Object>> wrappers = new HashMap<>();
private Map<Integer, Function<Object, Object>> unwrappers = new HashMap<>(); private Map<Integer, Function<Object, Object>> unwrappers = new HashMap<>();
// lazy // lazy
private FieldAccessor[] nmsAccessors; private FieldAccessor[] nmsAccessors;
private FieldAccessor[] wrapperAccessors; private FieldAccessor[] wrapperAccessors;
private Object[] nmsDefaultArgs; private Object[] nmsDefaultArgs;
private ConstructorAccessor nmsInstanceCreator; private ConstructorAccessor nmsInstanceCreator;
private Class<T> wrapperClass; private Class<T> wrapperClass;
private Class<?> nmsClass; private Class<?> nmsClass;
private AutoWrapper(Class<T> wrapperClass, Class<?> nmsClass) { private AutoWrapper(Class<T> wrapperClass, Class<?> nmsClass) {
this.wrapperClass = wrapperClass; this.wrapperClass = wrapperClass;
this.nmsClass = nmsClass; this.nmsClass = nmsClass;
} }
public static <T> AutoWrapper<T> wrap(Class<T> wrapperClass, Class<?> nmsClass) { public static <T> AutoWrapper<T> wrap(Class<T> wrapperClass, Class<?> nmsClass) {
return new AutoWrapper<>(wrapperClass, nmsClass); return new AutoWrapper<>(wrapperClass, nmsClass);
} }
public static <T> AutoWrapper<T> wrap(Class<T> wrapperClass, String nmsClassName) { public static <T> AutoWrapper<T> wrap(Class<T> wrapperClass, String nmsClassName) {
return wrap(wrapperClass, MinecraftReflection.getMinecraftClass(nmsClassName)); return wrap(wrapperClass, MinecraftReflection.getMinecraftClass(nmsClassName));
} }
public static <T> AutoWrapper<T> wrap(Class<T> wrapperClass, String nmsClassName, String... aliases) { public static <T> AutoWrapper<T> wrap(Class<T> wrapperClass, String nmsClassName, String... aliases) {
return wrap(wrapperClass, MinecraftReflection.getMinecraftClass(nmsClassName, aliases)); return wrap(wrapperClass, MinecraftReflection.getMinecraftClass(nmsClassName, aliases));
} }
public AutoWrapper<T> field(int index, Function<Object, Object> wrapper, Function<Object, Object> unwrapper) { public AutoWrapper<T> field(int index, Function<Object, Object> wrapper, Function<Object, Object> unwrapper) {
wrappers.put(index, wrapper); wrappers.put(index, wrapper);
unwrappers.put(index, unwrapper); unwrappers.put(index, unwrapper);
return this; return this;
} }
public AutoWrapper<T> field(int index, EquivalentConverter converter) { public AutoWrapper<T> field(int index, EquivalentConverter converter) {
return field(index, converter::getSpecific, specific -> converter.getGeneric(specific)); return field(index, converter::getSpecific, specific -> converter.getGeneric(specific));
} }
public T wrap(Object nmsObject) { public T wrap(Object nmsObject) {
T instance; T instance;
try { try {
instance = wrapperClass.newInstance(); instance = wrapperClass.newInstance();
} catch (ReflectiveOperationException ex) { } catch (ReflectiveOperationException ex) {
throw new InvalidWrapperException(wrapperClass.getSimpleName() + " is not accessible!", ex); throw new InvalidWrapperException(wrapperClass.getSimpleName() + " is not accessible!", ex);
} }
// ensures that all accessors are present // ensures that all accessors are present
computeFieldAccessors(); computeFieldAccessors();
for (int i = 0; i < wrapperAccessors.length; i++) { for (int i = 0; i < wrapperAccessors.length; i++) {
FieldAccessor source = nmsAccessors[i]; FieldAccessor source = nmsAccessors[i];
FieldAccessor target = wrapperAccessors[i]; FieldAccessor target = wrapperAccessors[i];
Object value = source.get(nmsObject); Object value = source.get(nmsObject);
if (wrappers.containsKey(i)) if (wrappers.containsKey(i))
value = wrappers.get(i).apply(value); value = wrappers.get(i).apply(value);
target.set(instance, value); target.set(instance, value);
} }
return instance; return instance;
} }
public Object unwrap(Object wrapper) { public Object unwrap(Object wrapper) {
// ensures that all accessors are present // ensures that all accessors are present
computeFieldAccessors(); computeFieldAccessors();
computeNmsConstructorAccess(); computeNmsConstructorAccess();
Object instance = nmsInstanceCreator.invoke(nmsDefaultArgs); Object instance = nmsInstanceCreator.invoke(nmsDefaultArgs);
for (int i = 0; i < wrapperAccessors.length; i++) { for (int i = 0; i < wrapperAccessors.length; i++) {
FieldAccessor source = wrapperAccessors[i]; FieldAccessor source = wrapperAccessors[i];
FieldAccessor target = nmsAccessors[i]; FieldAccessor target = nmsAccessors[i];
Object value = source.get(wrapper); Object value = source.get(wrapper);
if (unwrappers.containsKey(i)) if (unwrappers.containsKey(i))
value = unwrappers.get(i).apply(value); value = unwrappers.get(i).apply(value);
target.set(instance, value); target.set(instance, value);
} }
return instance; return instance;
} }
private void computeFieldAccessors() { private void computeFieldAccessors() {
if (nmsAccessors == null) { if (nmsAccessors == null) {
nmsAccessors = Arrays nmsAccessors = Arrays
.stream(nmsClass.getDeclaredFields()) .stream(nmsClass.getDeclaredFields())
.filter(field -> !Modifier.isStatic(field.getModifiers())) .filter(field -> !Modifier.isStatic(field.getModifiers()))
.map(field -> Accessors.getFieldAccessor(field)) .map(field -> Accessors.getFieldAccessor(field))
.toArray(FieldAccessor[]::new); .toArray(FieldAccessor[]::new);
} }
if (wrapperAccessors == null) { if (wrapperAccessors == null) {
wrapperAccessors = Arrays wrapperAccessors = Arrays
.stream(wrapperClass.getDeclaredFields()) .stream(wrapperClass.getDeclaredFields())
.map(field -> Accessors.getFieldAccessor(field)) .map(field -> Accessors.getFieldAccessor(field))
.toArray(FieldAccessor[]::new); .toArray(FieldAccessor[]::new);
} }
} }
private void computeNmsConstructorAccess() { private void computeNmsConstructorAccess() {
if (nmsInstanceCreator == null) { if (nmsInstanceCreator == null) {
ConstructorAccessor noArgs = Accessors.getConstructorAccessorOrNull(nmsClass); ConstructorAccessor noArgs = Accessors.getConstructorAccessorOrNull(nmsClass);
if (noArgs != null) { if (noArgs != null) {
// no args constructor is available - use it // no args constructor is available - use it
nmsInstanceCreator = noArgs; nmsInstanceCreator = noArgs;
nmsDefaultArgs = NO_ARGS; nmsDefaultArgs = NO_ARGS;
} else { } else {
// use the first constructor of the class // use the first constructor of the class
nmsInstanceCreator = Accessors.getConstructorAccessor(nmsClass.getDeclaredConstructors()[0]); nmsInstanceCreator = Accessors.getConstructorAccessor(nmsClass.getDeclaredConstructors()[0]);
nmsDefaultArgs = Arrays nmsDefaultArgs = Arrays
.stream(nmsInstanceCreator.getConstructor().getParameterTypes()) .stream(nmsInstanceCreator.getConstructor().getParameterTypes())
.map(type -> type.isPrimitive() ? Defaults.defaultValue(type) : null) .map(type -> type.isPrimitive() ? Defaults.defaultValue(type) : null)
.toArray(Object[]::new); .toArray(Object[]::new);
} }
} }
} }
// ---- Equivalent conversion // ---- Equivalent conversion
@Override @Override
public T getSpecific(Object generic) { public T getSpecific(Object generic) {
return wrap(generic); return wrap(generic);
} }
@Override @Override
public Object getGeneric(Object specific) { public Object getGeneric(Object specific) {
return unwrap(specific); return unwrap(specific);
} }
@Override @Override
public Class<T> getSpecificType() { public Class<T> getSpecificType() {
return wrapperClass; return wrapperClass;
} }
public static class InvalidWrapperException extends RuntimeException { public static class InvalidWrapperException extends RuntimeException {
private InvalidWrapperException(String message, Throwable cause) { private InvalidWrapperException(String message, Throwable cause) {
super(message, cause); super(message, cause);
} }
} }
} }

View File

@ -1,7 +1,7 @@
package com.comphenix.protocol.wrappers; package com.comphenix.protocol.wrappers;
public interface ClonableWrapper { public interface ClonableWrapper {
Object getHandle(); Object getHandle();
ClonableWrapper deepClone(); ClonableWrapper deepClone();
} }

View File

@ -1,75 +1,75 @@
/** /**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2016 dmulloy2 * Copyright (C) 2016 dmulloy2
* *
* This program is free software; you can redistribute it and/or modify it under the terms of the * This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of * GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version. * the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License along with this program; * You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA * 02111-1307 USA
*/ */
package com.comphenix.protocol.wrappers; package com.comphenix.protocol.wrappers;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.io.StringReader; import java.io.StringReader;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
/** /**
* Handles component parsing in 1.8 * Handles component parsing in 1.8
* @author dmulloy2 * @author dmulloy2
*/ */
public class ComponentParser { public class ComponentParser {
private static Constructor readerConstructor; private static Constructor readerConstructor;
private static Method setLenient; private static Method setLenient;
private static Method getAdapter; private static Method getAdapter;
private static Method read; private static Method read;
private ComponentParser() { private ComponentParser() {
} }
public static Object deserialize(Object gson, Class<?> component, StringReader str) { public static Object deserialize(Object gson, Class<?> component, StringReader str) {
try { try {
com.google.gson.stream.JsonReader reader = new com.google.gson.stream.JsonReader(str); com.google.gson.stream.JsonReader reader = new com.google.gson.stream.JsonReader(str);
reader.setLenient(true); reader.setLenient(true);
return ((com.google.gson.Gson) gson).getAdapter(component).read(reader); return ((com.google.gson.Gson) gson).getAdapter(component).read(reader);
} catch (IOException ex) { } catch (IOException ex) {
throw new RuntimeException("Failed to read JSON", ex); throw new RuntimeException("Failed to read JSON", ex);
} catch (LinkageError er) { } catch (LinkageError er) {
return deserializeLegacy(gson, component, str); return deserializeLegacy(gson, component, str);
} }
} }
// Should only be needed on 1.8. // Should only be needed on 1.8.
private static Object deserializeLegacy(Object gson, Class<?> component, StringReader str) { private static Object deserializeLegacy(Object gson, Class<?> component, StringReader str) {
try { try {
if (readerConstructor == null) { if (readerConstructor == null) {
Class<?> readerClass = Class.forName("org.bukkit.craftbukkit.libs.com.google.gson.stream.JsonReader"); Class<?> readerClass = Class.forName("org.bukkit.craftbukkit.libs.com.google.gson.stream.JsonReader");
readerConstructor = readerClass.getDeclaredConstructor(Reader.class); readerConstructor = readerClass.getDeclaredConstructor(Reader.class);
readerConstructor.setAccessible(true); readerConstructor.setAccessible(true);
setLenient = readerClass.getDeclaredMethod("setLenient", boolean.class); setLenient = readerClass.getDeclaredMethod("setLenient", boolean.class);
setLenient.setAccessible(true); setLenient.setAccessible(true);
getAdapter = gson.getClass().getDeclaredMethod("getAdapter", Class.class); getAdapter = gson.getClass().getDeclaredMethod("getAdapter", Class.class);
getAdapter.setAccessible(true); getAdapter.setAccessible(true);
Object adapter = getAdapter.invoke(gson, component); Object adapter = getAdapter.invoke(gson, component);
read = adapter.getClass().getDeclaredMethod("read", readerClass); read = adapter.getClass().getDeclaredMethod("read", readerClass);
read.setAccessible(true); read.setAccessible(true);
} }
Object reader = readerConstructor.newInstance(str); Object reader = readerConstructor.newInstance(str);
setLenient.invoke(reader, true); setLenient.invoke(reader, true);
Object adapter = getAdapter.invoke(gson, component); Object adapter = getAdapter.invoke(gson, component);
return read.invoke(adapter, reader); return read.invoke(adapter, reader);
} catch (ReflectiveOperationException ex) { } catch (ReflectiveOperationException ex) {
throw new RuntimeException("Failed to read JSON", ex); throw new RuntimeException("Failed to read JSON", ex);
} }
} }
} }

View File

@ -1,18 +1,16 @@
/** /**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2017 Dan Mulloy
* Copyright (C) 2017 Dan Mulloy * <p>
* * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public
* This program is free software; you can redistribute it and/or modify it under the terms of the * License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later
* GNU General Public License as published by the Free Software Foundation; either version 2 of * version.
* the License, or (at your option) any later version. * <p>
* * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * details.
* See the GNU General Public License for more details. * <p>
* * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free
* You should have received a copy of the GNU General Public License along with this program; * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/ */
package com.comphenix.protocol.wrappers; package com.comphenix.protocol.wrappers;

View File

@ -1,103 +1,103 @@
package com.comphenix.protocol.wrappers; package com.comphenix.protocol.wrappers;
import com.comphenix.protocol.reflect.EquivalentConverter; import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.reflect.StructureModifier; import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.reflect.accessors.Accessors; import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor; import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.wrappers.EnumWrappers.Direction; import com.comphenix.protocol.wrappers.EnumWrappers.Direction;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
public class MovingObjectPositionBlock implements Cloneable { public class MovingObjectPositionBlock implements Cloneable {
private static final Class<?> NMS_CLASS = MinecraftReflection.getNullableNMS( private static final Class<?> NMS_CLASS = MinecraftReflection.getNullableNMS(
"world.phys.MovingObjectPositionBlock", "world.phys.BlockHitResult", "MovingObjectPositionBlock"); "world.phys.MovingObjectPositionBlock", "world.phys.BlockHitResult", "MovingObjectPositionBlock");
private BlockPosition position; private BlockPosition position;
private Vector posVector; private Vector posVector;
private Direction direction; private Direction direction;
private boolean insideBlock; private boolean insideBlock;
public MovingObjectPositionBlock() { } public MovingObjectPositionBlock() { }
public MovingObjectPositionBlock(BlockPosition position, Vector posVector, Direction direction, boolean insideBlock) { public MovingObjectPositionBlock(BlockPosition position, Vector posVector, Direction direction, boolean insideBlock) {
this.position = position; this.position = position;
this.posVector = posVector; this.posVector = posVector;
this.direction = direction; this.direction = direction;
this.insideBlock = insideBlock; this.insideBlock = insideBlock;
} }
public static Class<?> getNmsClass() { public static Class<?> getNmsClass() {
return NMS_CLASS; return NMS_CLASS;
} }
public BlockPosition getBlockPosition() { public BlockPosition getBlockPosition() {
return position; return position;
} }
public void setBlockPosition(BlockPosition position) { public void setBlockPosition(BlockPosition position) {
this.position = position; this.position = position;
} }
public Vector getPosVector() { public Vector getPosVector() {
return posVector; return posVector;
} }
public void setPosVector(Vector vector) { public void setPosVector(Vector vector) {
this.posVector = vector; this.posVector = vector;
} }
public Direction getDirection() { public Direction getDirection() {
return direction; return direction;
} }
public void setDirection(Direction direction) { public void setDirection(Direction direction) {
this.direction = direction; this.direction = direction;
} }
public boolean isInsideBlock() { public boolean isInsideBlock() {
return insideBlock; return insideBlock;
} }
public void setInsideBlock(boolean insideBlock) { public void setInsideBlock(boolean insideBlock) {
this.insideBlock = insideBlock; this.insideBlock = insideBlock;
} }
private static ConstructorAccessor constructor; private static ConstructorAccessor constructor;
public static EquivalentConverter<MovingObjectPositionBlock> getConverter() { public static EquivalentConverter<MovingObjectPositionBlock> getConverter() {
return Converters.ignoreNull(new EquivalentConverter<MovingObjectPositionBlock>() { return Converters.ignoreNull(new EquivalentConverter<MovingObjectPositionBlock>() {
@Override @Override
public Object getGeneric(MovingObjectPositionBlock specific) { public Object getGeneric(MovingObjectPositionBlock specific) {
if (constructor == null) { if (constructor == null) {
constructor = Accessors.getConstructorAccessor(NMS_CLASS, constructor = Accessors.getConstructorAccessor(NMS_CLASS,
MinecraftReflection.getVec3DClass(), MinecraftReflection.getVec3DClass(),
EnumWrappers.getDirectionClass(), EnumWrappers.getDirectionClass(),
MinecraftReflection.getBlockPositionClass(), MinecraftReflection.getBlockPositionClass(),
boolean.class); boolean.class);
} }
Object nmsVector = BukkitConverters.getVectorConverter().getGeneric(specific.posVector); Object nmsVector = BukkitConverters.getVectorConverter().getGeneric(specific.posVector);
Object nmsDirection = EnumWrappers.getDirectionConverter().getGeneric(specific.direction); Object nmsDirection = EnumWrappers.getDirectionConverter().getGeneric(specific.direction);
Object nmsBlockPos = BlockPosition.getConverter().getGeneric(specific.position); Object nmsBlockPos = BlockPosition.getConverter().getGeneric(specific.position);
return constructor.invoke(nmsVector, nmsDirection, nmsBlockPos, specific.insideBlock); return constructor.invoke(nmsVector, nmsDirection, nmsBlockPos, specific.insideBlock);
} }
@Override @Override
public MovingObjectPositionBlock getSpecific(Object generic) { public MovingObjectPositionBlock getSpecific(Object generic) {
StructureModifier<Object> modifier = new StructureModifier<>(generic.getClass()).withTarget(generic); StructureModifier<Object> modifier = new StructureModifier<>(generic.getClass()).withTarget(generic);
Direction direction = modifier.withType(EnumWrappers.getDirectionClass(), EnumWrappers.getDirectionConverter()).read(0); Direction direction = modifier.withType(EnumWrappers.getDirectionClass(), EnumWrappers.getDirectionConverter()).read(0);
BlockPosition blockPos = modifier.withType(MinecraftReflection.getBlockPositionClass(), BlockPosition.getConverter()).read(0); BlockPosition blockPos = modifier.withType(MinecraftReflection.getBlockPositionClass(), BlockPosition.getConverter()).read(0);
Vector posVector = modifier.withType(MinecraftReflection.getVec3DClass(), BukkitConverters.getVectorConverter()).read(0); Vector posVector = modifier.withType(MinecraftReflection.getVec3DClass(), BukkitConverters.getVectorConverter()).read(0);
boolean insideBlock = (boolean) modifier.withType(boolean.class).read(1); boolean insideBlock = (boolean) modifier.withType(boolean.class).read(1);
return new MovingObjectPositionBlock(blockPos, posVector, direction, insideBlock); return new MovingObjectPositionBlock(blockPos, posVector, direction, insideBlock);
} }
@Override @Override
public Class<MovingObjectPositionBlock> getSpecificType() { public Class<MovingObjectPositionBlock> getSpecificType() {
return MovingObjectPositionBlock.class; return MovingObjectPositionBlock.class;
} }
}); });
} }
} }

View File

@ -1,43 +1,43 @@
package com.comphenix.protocol.wrappers; package com.comphenix.protocol.wrappers;
import java.util.Objects; import java.util.Objects;
public class Pair<A, B> { public class Pair<A, B> {
private A first; private A first;
private B second; private B second;
public Pair(A first, B second) { public Pair(A first, B second) {
this.first = first; this.first = first;
this.second = second; this.second = second;
} }
public A getFirst() { public A getFirst() {
return first; return first;
} }
public B getSecond() { public B getSecond() {
return second; return second;
} }
public void setFirst(A first) { public void setFirst(A first) {
this.first = first; this.first = first;
} }
public void setSecond(B second) { public void setSecond(B second) {
this.second = second; this.second = second;
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
Pair<?, ?> pair = (Pair<?, ?>) o; Pair<?, ?> pair = (Pair<?, ?>) o;
return Objects.equals(first, pair.first) && return Objects.equals(first, pair.first) &&
Objects.equals(second, pair.second); Objects.equals(second, pair.second);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(first, second); return Objects.hash(first, second);
} }
} }

View File

@ -1,127 +1,127 @@
/** /**
* (c) 2016 dmulloy2 * (c) 2016 dmulloy2
*/ */
package com.comphenix.protocol.wrappers; package com.comphenix.protocol.wrappers;
import com.comphenix.protocol.reflect.EquivalentConverter; import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.reflect.StructureModifier; import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.utility.MinecraftReflection;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
/** /**
* @author dmulloy2 * @author dmulloy2
*/ */
public class Vector3F { public class Vector3F {
protected float x; protected float x;
protected float y; protected float y;
protected float z; protected float z;
public Vector3F() { public Vector3F() {
this(0, 0, 0); this(0, 0, 0);
} }
public Vector3F(float x, float y, float z) { public Vector3F(float x, float y, float z) {
this.x = x; this.x = x;
this.y = y; this.y = y;
this.z = z; this.z = z;
} }
public float getX() { public float getX() {
return x; return x;
} }
public Vector3F setX(float x) { public Vector3F setX(float x) {
this.x = x; this.x = x;
return this; return this;
} }
public float getY() { public float getY() {
return y; return y;
} }
public Vector3F setY(float y) { public Vector3F setY(float y) {
this.y = y; this.y = y;
return this; return this;
} }
public float getZ() { public float getZ() {
return z; return z;
} }
public Vector3F setZ(float z) { public Vector3F setZ(float z) {
this.z = z; this.z = z;
return this; return this;
} }
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = 1; int result = 1;
result = prime * result + Float.floatToIntBits(x); result = prime * result + Float.floatToIntBits(x);
result = prime * result + Float.floatToIntBits(y); result = prime * result + Float.floatToIntBits(y);
result = prime * result + Float.floatToIntBits(z); result = prime * result + Float.floatToIntBits(z);
return result; return result;
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) return true; if (this == obj) return true;
if (obj instanceof Vector3F) { if (obj instanceof Vector3F) {
Vector3F that = (Vector3F) obj; Vector3F that = (Vector3F) obj;
if (Float.floatToIntBits(x) != Float.floatToIntBits(that.x)) if (Float.floatToIntBits(x) != Float.floatToIntBits(that.x))
return false; return false;
if (Float.floatToIntBits(y) != Float.floatToIntBits(that.y)) if (Float.floatToIntBits(y) != Float.floatToIntBits(that.y))
return false; return false;
if (Float.floatToIntBits(z) != Float.floatToIntBits(that.z)) if (Float.floatToIntBits(z) != Float.floatToIntBits(that.z))
return false; return false;
return true; return true;
} }
return false; return false;
} }
private static Constructor<?> constructor = null; private static Constructor<?> constructor = null;
private static final Class<?> NMS_CLASS = MinecraftReflection.getNullableNMS("core.Vector3f", "core.Rotations", "Vector3f"); private static final Class<?> NMS_CLASS = MinecraftReflection.getNullableNMS("core.Vector3f", "core.Rotations", "Vector3f");
public static Class<?> getMinecraftClass() { public static Class<?> getMinecraftClass() {
return NMS_CLASS; return NMS_CLASS;
} }
public static EquivalentConverter<Vector3F> getConverter() { public static EquivalentConverter<Vector3F> getConverter() {
return Converters.ignoreNull(new EquivalentConverter<Vector3F>() { return Converters.ignoreNull(new EquivalentConverter<Vector3F>() {
@Override @Override
public Class<Vector3F> getSpecificType() { public Class<Vector3F> getSpecificType() {
return Vector3F.class; return Vector3F.class;
} }
@Override @Override
public Object getGeneric(Vector3F specific) { public Object getGeneric(Vector3F specific) {
if (constructor == null) { if (constructor == null) {
try { try {
constructor = NMS_CLASS.getConstructor(float.class, float.class, float.class); constructor = NMS_CLASS.getConstructor(float.class, float.class, float.class);
} catch (ReflectiveOperationException ex) { } catch (ReflectiveOperationException ex) {
throw new RuntimeException("Failed to find constructor for Vector3f", ex); throw new RuntimeException("Failed to find constructor for Vector3f", ex);
} }
} }
try { try {
return constructor.newInstance(specific.x, specific.y, specific.z); return constructor.newInstance(specific.x, specific.y, specific.z);
} catch (ReflectiveOperationException ex) { } catch (ReflectiveOperationException ex) {
throw new RuntimeException("Failed to create new instance of Vector3f", ex); throw new RuntimeException("Failed to create new instance of Vector3f", ex);
} }
} }
@Override @Override
public Vector3F getSpecific(Object generic) { public Vector3F getSpecific(Object generic) {
StructureModifier<Float> modifier = new StructureModifier<Float>(generic.getClass()) StructureModifier<Float> modifier = new StructureModifier<Float>(generic.getClass())
.withTarget(generic).withType(float.class); .withTarget(generic).withType(float.class);
float x = modifier.read(0); float x = modifier.read(0);
float y = modifier.read(1); float y = modifier.read(1);
float z = modifier.read(2); float z = modifier.read(2);
return new Vector3F(x, y, z); return new Vector3F(x, y, z);
} }
}); });
} }
} }

View File

@ -1,84 +1,84 @@
package com.comphenix.protocol.wrappers; package com.comphenix.protocol.wrappers;
import com.comphenix.protocol.reflect.EquivalentConverter; import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.reflect.StructureModifier; import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.reflect.accessors.Accessors; import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor; import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.utility.MinecraftReflection;
public class WrappedVillagerData extends AbstractWrapper implements ClonableWrapper { public class WrappedVillagerData extends AbstractWrapper implements ClonableWrapper {
private static final Class<?> NMS_CLASS = MinecraftReflection.getNullableNMS( private static final Class<?> NMS_CLASS = MinecraftReflection.getNullableNMS(
"world.entity.npc.VillagerData","VillagerData"); "world.entity.npc.VillagerData","VillagerData");
private static final Class<?> TYPE_CLASS = MinecraftReflection.getNullableNMS( private static final Class<?> TYPE_CLASS = MinecraftReflection.getNullableNMS(
"world.entity.npc.VillagerType", "VillagerType"); "world.entity.npc.VillagerType", "VillagerType");
private static final Class<?> PROF_CLASS = MinecraftReflection.getNullableNMS( private static final Class<?> PROF_CLASS = MinecraftReflection.getNullableNMS(
"world.entity.npc.VillagerProfession", "VillagerProfession"); "world.entity.npc.VillagerProfession", "VillagerProfession");
private static EquivalentConverter<Type> TYPE_CONVERTER; private static EquivalentConverter<Type> TYPE_CONVERTER;
private static EquivalentConverter<Profession> PROF_CONVERTER; private static EquivalentConverter<Profession> PROF_CONVERTER;
static { static {
if (NMS_CLASS != null) { if (NMS_CLASS != null) {
TYPE_CONVERTER = new EnumWrappers.FauxEnumConverter<>(Type.class, TYPE_CLASS); TYPE_CONVERTER = new EnumWrappers.FauxEnumConverter<>(Type.class, TYPE_CLASS);
PROF_CONVERTER = new EnumWrappers.FauxEnumConverter<>(Profession.class, PROF_CLASS); PROF_CONVERTER = new EnumWrappers.FauxEnumConverter<>(Profession.class, PROF_CLASS);
} }
} }
public enum Type { public enum Type {
DESERT, JUNGLE, PLAINS, SAVANNA, SNOW, SWAMP, TAIGA DESERT, JUNGLE, PLAINS, SAVANNA, SNOW, SWAMP, TAIGA
} }
public enum Profession { public enum Profession {
NONE, ARMORER, BUTCHER, CARTOGRAPHER, CLERIC, FARMER, FISHERMAN, NONE, ARMORER, BUTCHER, CARTOGRAPHER, CLERIC, FARMER, FISHERMAN,
FLETCHER, LEATHERWORKER, LIBRARIAN, MASON, NITWIT, SHEPHERD, FLETCHER, LEATHERWORKER, LIBRARIAN, MASON, NITWIT, SHEPHERD,
TOOLSMITH, WEAPONSMITH TOOLSMITH, WEAPONSMITH
} }
private StructureModifier<Object> modifier; private StructureModifier<Object> modifier;
private WrappedVillagerData(Object handle) { private WrappedVillagerData(Object handle) {
super(NMS_CLASS); super(NMS_CLASS);
setHandle(handle); setHandle(handle);
modifier = new StructureModifier<>(NMS_CLASS).withTarget(handle); modifier = new StructureModifier<>(NMS_CLASS).withTarget(handle);
} }
public static WrappedVillagerData fromHandle(Object handle) { public static WrappedVillagerData fromHandle(Object handle) {
return new WrappedVillagerData(handle); return new WrappedVillagerData(handle);
} }
private static ConstructorAccessor CONSTRUCTOR; private static ConstructorAccessor CONSTRUCTOR;
public static WrappedVillagerData fromValues(Type type, Profession profession, int level) { public static WrappedVillagerData fromValues(Type type, Profession profession, int level) {
Object genericType = TYPE_CONVERTER.getGeneric(type); Object genericType = TYPE_CONVERTER.getGeneric(type);
Object genericProf = PROF_CONVERTER.getGeneric(profession); Object genericProf = PROF_CONVERTER.getGeneric(profession);
if (CONSTRUCTOR == null) { if (CONSTRUCTOR == null) {
CONSTRUCTOR = Accessors.getConstructorAccessor(NMS_CLASS, TYPE_CLASS, PROF_CLASS, int.class); CONSTRUCTOR = Accessors.getConstructorAccessor(NMS_CLASS, TYPE_CLASS, PROF_CLASS, int.class);
} }
Object handle = CONSTRUCTOR.invoke(genericType, genericProf, level); Object handle = CONSTRUCTOR.invoke(genericType, genericProf, level);
return fromHandle(handle); return fromHandle(handle);
} }
public static Class<?> getNmsClass() { public static Class<?> getNmsClass() {
return NMS_CLASS; return NMS_CLASS;
} }
public int getLevel() { public int getLevel() {
return modifier.<Integer>withType(int.class).read(0); return modifier.<Integer>withType(int.class).read(0);
} }
public Type getType() { public Type getType() {
return modifier.withType(TYPE_CLASS, TYPE_CONVERTER).read(0); return modifier.withType(TYPE_CLASS, TYPE_CONVERTER).read(0);
} }
public Profession getProfession() { public Profession getProfession() {
return modifier.withType(PROF_CLASS, PROF_CONVERTER).read(0); return modifier.withType(PROF_CLASS, PROF_CONVERTER).read(0);
} }
@Override @Override
public WrappedVillagerData deepClone() { public WrappedVillagerData deepClone() {
return WrappedVillagerData.fromValues(getType(), getProfession(), getLevel()); return WrappedVillagerData.fromValues(getType(), getProfession(), getLevel());
} }
} }

View File

@ -1,45 +1,45 @@
name: ProtocolLib name: ProtocolLib
version: ${project.fullVersion} version: ${project.fullVersion}
description: Provides read/write access to the Minecraft protocol. description: Provides read/write access to the Minecraft protocol.
authors: [dmulloy2, comphenix] authors: [dmulloy2, comphenix]
main: com.comphenix.protocol.ProtocolLib main: com.comphenix.protocol.ProtocolLib
load: STARTUP load: STARTUP
database: false database: false
api-version: "1.13" api-version: "1.13"
commands: commands:
protocol: protocol:
description: Performs administrative tasks regarding ProtocolLib. description: Performs administrative tasks regarding ProtocolLib.
usage: /<command> config|check|update|timings|listeners|version|dump usage: /<command> config|check|update|timings|listeners|version|dump
permission: protocol.admin permission: protocol.admin
permission-message: You don't have <permission> permission-message: You don't have <permission>
packet: packet:
description: Add or remove a simple packet listener. description: Add or remove a simple packet listener.
usage: /<command> add|remove|names client|server [ID start]-[ID stop] [detailed] usage: /<command> add|remove|names client|server [ID start]-[ID stop] [detailed]
permission: protocol.admin permission: protocol.admin
permission-message: You don't have <permission> permission-message: You don't have <permission>
filter: filter:
description: Add or remove programmable filters to the packet listeners. description: Add or remove programmable filters to the packet listeners.
usage: /<command> add|remove name [ID start]-[ID stop] usage: /<command> add|remove name [ID start]-[ID stop]
aliases: [packet_filter] aliases: [packet_filter]
permission: protocol.admin permission: protocol.admin
permission-message: You don't have <permission> permission-message: You don't have <permission>
packetlog: packetlog:
description: Logs hex representations of packets to a file or console description: Logs hex representations of packets to a file or console
usage: /<command> <protocol> <sender> <packet> [location] usage: /<command> <protocol> <sender> <packet> [location]
permission: protocol.admin permission: protocol.admin
permission-message: You don't have <permission> permission-message: You don't have <permission>
permissions: permissions:
protocol.*: protocol.*:
description: Gives access to everything. description: Gives access to everything.
children: children:
protocol.admin: true protocol.admin: true
protocol.info: true protocol.info: true
protocol.admin: protocol.admin:
description: Able to initiate the update process, and can configure debug mode. description: Able to initiate the update process, and can configure debug mode.
default: op default: op
protocol.info: protocol.info:
description: Can read update notifications and error reports. description: Can read update notifications and error reports.
default: op default: op

View File

@ -1,126 +1,127 @@
package com.comphenix.protocol; package com.comphenix.protocol;
import static org.mockito.Mockito.mock; import java.util.Collections;
import static org.mockito.Mockito.when; import java.util.List;
import com.comphenix.protocol.reflect.accessors.Accessors; import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.FieldAccessor; import com.comphenix.protocol.reflect.accessors.FieldAccessor;
import com.comphenix.protocol.utility.MinecraftReflectionTestUtil; import com.comphenix.protocol.utility.MinecraftReflectionTestUtil;
import java.util.Collections; import net.minecraft.SharedConstants;
import java.util.List; import net.minecraft.core.IRegistry;
import net.minecraft.SharedConstants; import net.minecraft.server.DispenserRegistry;
import net.minecraft.core.IRegistry; import net.minecraft.server.level.WorldServer;
import net.minecraft.server.DispenserRegistry; import org.apache.logging.log4j.LogManager;
import net.minecraft.server.level.WorldServer; import org.bukkit.Bukkit;
import org.apache.logging.log4j.LogManager; import org.bukkit.Server;
import org.bukkit.Bukkit; import org.bukkit.World;
import org.bukkit.Server; import org.bukkit.craftbukkit.v1_19_R2.CraftServer;
import org.bukkit.World; import org.bukkit.craftbukkit.v1_19_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_19_R2.CraftServer; import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemFactory;
import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; import org.bukkit.craftbukkit.v1_19_R2.util.Versioning;
import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemFactory; import org.spigotmc.SpigotWorldConfig;
import org.bukkit.craftbukkit.v1_19_R2.util.Versioning;
import org.spigotmc.SpigotWorldConfig; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Used to ensure that ProtocolLib and Bukkit is prepared to be tested. /**
* * Used to ensure that ProtocolLib and Bukkit is prepared to be tested.
* @author Kristian *
*/ * @author Kristian
public class BukkitInitialization { */
public class BukkitInitialization {
private static final BukkitInitialization instance = new BukkitInitialization();
private boolean initialized; private static final BukkitInitialization instance = new BukkitInitialization();
private boolean packaged; private boolean initialized;
private boolean packaged;
private BukkitInitialization() {
System.out.println("Created new BukkitInitialization on " + Thread.currentThread().getName()); private BukkitInitialization() {
} System.out.println("Created new BukkitInitialization on " + Thread.currentThread().getName());
}
/**
* Statically initializes the mock server for unit testing /**
*/ * Statically initializes the mock server for unit testing
public static synchronized void initializeAll() { */
instance.initialize(); public static synchronized void initializeAll() {
} instance.initialize();
}
/**
* Initialize Bukkit and ProtocolLib such that we can perfrom unit testing /**
*/ * Initialize Bukkit and ProtocolLib such that we can perfrom unit testing
private void initialize() { */
if (!this.initialized) { private void initialize() {
// Denote that we're done if (!this.initialized) {
this.initialized = true; // Denote that we're done
this.initialized = true;
try {
LogManager.getLogger(); try {
} catch (Throwable ex) { LogManager.getLogger();
// Happens only on my Jenkins, but if it errors here it works when it matters } catch (Throwable ex) {
ex.printStackTrace(); // Happens only on my Jenkins, but if it errors here it works when it matters
} ex.printStackTrace();
}
instance.setPackage();
instance.setPackage();
SharedConstants.a();
DispenserRegistry.a(); SharedConstants.a();
DispenserRegistry.a();
try {
IRegistry.class.getName(); try {
} catch (Throwable ex) { IRegistry.class.getName();
ex.printStackTrace(); } catch (Throwable ex) {
} ex.printStackTrace();
}
String releaseTarget = MinecraftReflectionTestUtil.RELEASE_TARGET;
String serverVersion = CraftServer.class.getPackage().getImplementationVersion(); String releaseTarget = MinecraftReflectionTestUtil.RELEASE_TARGET;
String serverVersion = CraftServer.class.getPackage().getImplementationVersion();
// Mock the server object
Server mockedServer = mock(Server.class); // Mock the server object
Server mockedServer = mock(Server.class);
when(mockedServer.getLogger()).thenReturn(java.util.logging.Logger.getLogger("Minecraft"));
when(mockedServer.getName()).thenReturn("Mock Server"); when(mockedServer.getLogger()).thenReturn(java.util.logging.Logger.getLogger("Minecraft"));
when(mockedServer.getVersion()).thenReturn(serverVersion + " (MC: " + releaseTarget + ")"); when(mockedServer.getName()).thenReturn("Mock Server");
when(mockedServer.getBukkitVersion()).thenReturn(Versioning.getBukkitVersion()); when(mockedServer.getVersion()).thenReturn(serverVersion + " (MC: " + releaseTarget + ")");
when(mockedServer.getBukkitVersion()).thenReturn(Versioning.getBukkitVersion());
when(mockedServer.getItemFactory()).thenReturn(CraftItemFactory.instance());
when(mockedServer.isPrimaryThread()).thenReturn(true); when(mockedServer.getItemFactory()).thenReturn(CraftItemFactory.instance());
when(mockedServer.isPrimaryThread()).thenReturn(true);
WorldServer nmsWorld = mock(WorldServer.class);
WorldServer nmsWorld = mock(WorldServer.class);
SpigotWorldConfig mockWorldConfig = mock(SpigotWorldConfig.class);
SpigotWorldConfig mockWorldConfig = mock(SpigotWorldConfig.class);
try {
FieldAccessor spigotConfig = Accessors.getFieldAccessor(nmsWorld.getClass().getField("spigotConfig")); try {
spigotConfig.set(nmsWorld, mockWorldConfig); FieldAccessor spigotConfig = Accessors.getFieldAccessor(nmsWorld.getClass().getField("spigotConfig"));
} catch (ReflectiveOperationException ex) { spigotConfig.set(nmsWorld, mockWorldConfig);
throw new RuntimeException(ex); } catch (ReflectiveOperationException ex) {
} throw new RuntimeException(ex);
}
CraftWorld world = mock(CraftWorld.class);
when(world.getHandle()).thenReturn(nmsWorld); CraftWorld world = mock(CraftWorld.class);
when(world.getHandle()).thenReturn(nmsWorld);
List<World> worlds = Collections.singletonList(world);
when(mockedServer.getWorlds()).thenReturn(worlds); List<World> worlds = Collections.singletonList(world);
when(mockedServer.getWorlds()).thenReturn(worlds);
// Inject this fake server
Bukkit.setServer(mockedServer); // Inject this fake server
} Bukkit.setServer(mockedServer);
} }
}
/**
* Ensure that package names are correctly set up. /**
*/ * Ensure that package names are correctly set up.
private void setPackage() { */
if (!this.packaged) { private void setPackage() {
this.packaged = true; if (!this.packaged) {
this.packaged = true;
try {
LogManager.getLogger(); try {
} catch (Throwable ex) { LogManager.getLogger();
// Happens only on my Jenkins, but if it errors here it works when it matters } catch (Throwable ex) {
ex.printStackTrace(); // Happens only on my Jenkins, but if it errors here it works when it matters
} ex.printStackTrace();
}
MinecraftReflectionTestUtil.init();
} MinecraftReflectionTestUtil.init();
} }
} }
}

View File

@ -1,334 +1,334 @@
/** /**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2016 dmulloy2 * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2016 dmulloy2
* <p> * <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later * License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later
* version. * version.
* <p> * <p>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details. * details.
* <p> * <p>
* You should have received a copy of the GNU General Public License along with this program; if not, write to the Free * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
package com.comphenix.protocol; package com.comphenix.protocol;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import com.comphenix.protocol.PacketType.Protocol; import com.comphenix.protocol.PacketType.Protocol;
import com.comphenix.protocol.PacketType.Sender; import com.comphenix.protocol.PacketType.Sender;
import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.injector.packet.PacketRegistry; import com.comphenix.protocol.injector.packet.PacketRegistry;
import com.comphenix.protocol.utility.MinecraftReflectionTestUtil; import com.comphenix.protocol.utility.MinecraftReflectionTestUtil;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.TreeMap; import java.util.TreeMap;
import net.minecraft.network.EnumProtocol; import net.minecraft.network.EnumProtocol;
import net.minecraft.network.protocol.EnumProtocolDirection; import net.minecraft.network.protocol.EnumProtocolDirection;
import net.minecraft.network.protocol.login.PacketLoginInStart; import net.minecraft.network.protocol.login.PacketLoginInStart;
import org.apache.commons.lang.WordUtils; import org.apache.commons.lang.WordUtils;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
/** /**
* @author dmulloy2 * @author dmulloy2
*/ */
public class PacketTypeTest { public class PacketTypeTest {
@BeforeAll @BeforeAll
public static void beforeClass() { public static void beforeClass() {
BukkitInitialization.initializeAll(); BukkitInitialization.initializeAll();
// I'm well aware this is jank, but it does in fact work correctly and give the desired result // I'm well aware this is jank, but it does in fact work correctly and give the desired result
PacketType.onDynamicCreate = className -> { PacketType.onDynamicCreate = className -> {
throw new RuntimeException("Dynamically generated packet " + className); throw new RuntimeException("Dynamically generated packet " + className);
}; };
} }
@AfterAll @AfterAll
public static void afterClass() { public static void afterClass() {
PacketType.onDynamicCreate = __ -> { PacketType.onDynamicCreate = __ -> {
}; };
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
MinecraftReflectionTestUtil.init(); MinecraftReflectionTestUtil.init();
Set<Class<?>> allTypes = new HashSet<>(); Set<Class<?>> allTypes = new HashSet<>();
List<Class<?>> newTypes = new ArrayList<>(); List<Class<?>> newTypes = new ArrayList<>();
EnumProtocol[] protocols = EnumProtocol.values(); EnumProtocol[] protocols = EnumProtocol.values();
for (EnumProtocol protocol : protocols) { for (EnumProtocol protocol : protocols) {
System.out.println(WordUtils.capitalize(protocol.name().toLowerCase())); System.out.println(WordUtils.capitalize(protocol.name().toLowerCase()));
Field field = EnumProtocol.class.getDeclaredField("j"); Field field = EnumProtocol.class.getDeclaredField("j");
field.setAccessible(true); field.setAccessible(true);
Map<EnumProtocolDirection, Object> map = (Map<EnumProtocolDirection, Object>) field.get(protocol); Map<EnumProtocolDirection, Object> map = (Map<EnumProtocolDirection, Object>) field.get(protocol);
for (Entry<EnumProtocolDirection, Object> entry : map.entrySet()) { for (Entry<EnumProtocolDirection, Object> entry : map.entrySet()) {
Field mapField = entry.getValue().getClass().getDeclaredField("b"); Field mapField = entry.getValue().getClass().getDeclaredField("b");
mapField.setAccessible(true); mapField.setAccessible(true);
Map<Class<?>, Integer> reverseMap = (Map<Class<?>, Integer>) mapField.get(entry.getValue()); Map<Class<?>, Integer> reverseMap = (Map<Class<?>, Integer>) mapField.get(entry.getValue());
Map<Integer, Class<?>> treeMap = new TreeMap<>(); Map<Integer, Class<?>> treeMap = new TreeMap<>();
for (Entry<Class<?>, Integer> entry1 : reverseMap.entrySet()) { for (Entry<Class<?>, Integer> entry1 : reverseMap.entrySet()) {
treeMap.put(entry1.getValue(), entry1.getKey()); treeMap.put(entry1.getValue(), entry1.getKey());
} }
System.out.println(" " + entry.getKey()); System.out.println(" " + entry.getKey());
for (Entry<Integer, Class<?>> entry1 : treeMap.entrySet()) { for (Entry<Integer, Class<?>> entry1 : treeMap.entrySet()) {
System.out.println(generateNewType(entry1.getKey(), entry1.getValue())); System.out.println(generateNewType(entry1.getKey(), entry1.getValue()));
allTypes.add(entry1.getValue()); allTypes.add(entry1.getValue());
try { try {
PacketType.fromClass(entry1.getValue()); PacketType.fromClass(entry1.getValue());
} catch (Exception ex) { } catch (Exception ex) {
newTypes.add(entry1.getValue()); newTypes.add(entry1.getValue());
} }
} }
} }
} }
System.out.println("New types: " + newTypes); System.out.println("New types: " + newTypes);
for (PacketType type : PacketType.values()) { for (PacketType type : PacketType.values()) {
if (type.isDeprecated()) { if (type.isDeprecated()) {
continue; continue;
} }
if (!allTypes.contains(type.getPacketClass())) { if (!allTypes.contains(type.getPacketClass())) {
System.out.println(type + " was removed"); System.out.println(type + " was removed");
} }
} }
} }
private static String formatHex(int dec) { private static String formatHex(int dec) {
if (dec < 0) { if (dec < 0) {
return "0xFF"; return "0xFF";
} }
String hex = Integer.toHexString(dec).toUpperCase(); String hex = Integer.toHexString(dec).toUpperCase();
return "0x" + (hex.length() < 2 ? "0" : "") + hex; return "0x" + (hex.length() < 2 ? "0" : "") + hex;
} }
private static List<String> splitOnCaps(String string) { private static List<String> splitOnCaps(String string) {
List<String> list = new ArrayList<>(); List<String> list = new ArrayList<>();
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
char[] chars = string.toCharArray(); char[] chars = string.toCharArray();
for (int i = 0; i < chars.length; i++) { for (int i = 0; i < chars.length; i++) {
char c = chars[i]; char c = chars[i];
if (i != 0 && Character.isUpperCase(c)) { if (i != 0 && Character.isUpperCase(c)) {
list.add(builder.toString()); list.add(builder.toString());
builder = new StringBuilder(); builder = new StringBuilder();
} }
builder.append(c); builder.append(c);
} }
list.add(builder.toString()); list.add(builder.toString());
return list; return list;
} }
private static String generateNewType(int packetId, Class<?> clazz) { private static String generateNewType(int packetId, Class<?> clazz) {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append("\t\t\t"); builder.append("\t\t\t");
builder.append("public static final PacketType "); builder.append("public static final PacketType ");
String fullName = clazz.getName(); String fullName = clazz.getName();
fullName = fullName.substring(fullName.lastIndexOf(".") + 1); fullName = fullName.substring(fullName.lastIndexOf(".") + 1);
String className; String className;
List<String> classNames = new ArrayList<>(); List<String> classNames = new ArrayList<>();
if (fullName.endsWith("Packet")) { if (fullName.endsWith("Packet")) {
for (String name : fullName.split("\\$")) { for (String name : fullName.split("\\$")) {
List<String> split = splitOnCaps(name); List<String> split = splitOnCaps(name);
StringBuilder nameBuilder = new StringBuilder(); StringBuilder nameBuilder = new StringBuilder();
for (int i = 1; i < split.size() - 1; i++) { for (int i = 1; i < split.size() - 1; i++) {
nameBuilder.append(split.get(i)); nameBuilder.append(split.get(i));
} }
classNames.add(nameBuilder.toString()); classNames.add(nameBuilder.toString());
} }
} else { } else {
for (String name : fullName.split("\\$")) { for (String name : fullName.split("\\$")) {
List<String> split = splitOnCaps(name); List<String> split = splitOnCaps(name);
StringBuilder nameBuilder = new StringBuilder(); StringBuilder nameBuilder = new StringBuilder();
for (int i = 3; i < split.size(); i++) { for (int i = 3; i < split.size(); i++) {
nameBuilder.append(split.get(i)); nameBuilder.append(split.get(i));
} }
classNames.add(nameBuilder.toString()); classNames.add(nameBuilder.toString());
} }
} }
className = classNames.get(classNames.size() - 1); className = classNames.get(classNames.size() - 1);
// Format it like SET_PROTOCOL // Format it like SET_PROTOCOL
StringBuilder fieldName = new StringBuilder(); StringBuilder fieldName = new StringBuilder();
char[] chars = className.toCharArray(); char[] chars = className.toCharArray();
for (int i = 0; i < chars.length; i++) { for (int i = 0; i < chars.length; i++) {
char c = chars[i]; char c = chars[i];
if (i != 0 && Character.isUpperCase(c)) { if (i != 0 && Character.isUpperCase(c)) {
fieldName.append("_"); fieldName.append("_");
} }
fieldName.append(Character.toUpperCase(c)); fieldName.append(Character.toUpperCase(c));
} }
builder.append(fieldName.toString().replace("N_B_T", "NBT")); builder.append(fieldName.toString().replace("N_B_T", "NBT"));
builder.append(" = "); builder.append(" = ");
// Add spacing // Add spacing
if (builder.length() > 65) { if (builder.length() > 65) {
builder.append("\n"); builder.append("\n");
} else { } else {
while (builder.length() < 65) { while (builder.length() < 65) {
builder.append(" "); builder.append(" ");
} }
} }
builder.append("new "); builder.append("new ");
builder.append("PacketType(PROTOCOL, SENDER, "); builder.append("PacketType(PROTOCOL, SENDER, ");
builder.append(formatHex(packetId)); builder.append(formatHex(packetId));
builder.append(", "); builder.append(", ");
StringBuilder nameBuilder = new StringBuilder(); StringBuilder nameBuilder = new StringBuilder();
for (int i = 0; i < classNames.size(); i++) { for (int i = 0; i < classNames.size(); i++) {
if (i != 0) { if (i != 0) {
nameBuilder.append("$"); nameBuilder.append("$");
} }
nameBuilder.append(classNames.get(i)); nameBuilder.append(classNames.get(i));
} }
String name = nameBuilder.toString(); String name = nameBuilder.toString();
String namesArg = listToString(getAllNames(clazz, name)); String namesArg = listToString(getAllNames(clazz, name));
builder.append(namesArg); builder.append(namesArg);
builder.append(");"); builder.append(");");
return builder.toString(); return builder.toString();
} }
private static List<String> getAllNames(Class<?> packetClass, String newName) { private static List<String> getAllNames(Class<?> packetClass, String newName) {
List<String> names = new ArrayList<>(); List<String> names = new ArrayList<>();
names.add(newName); names.add(newName);
try { try {
PacketType type = PacketType.fromClass(packetClass); PacketType type = PacketType.fromClass(packetClass);
for (String alias : type.names) { for (String alias : type.names) {
alias = alias.substring(alias.lastIndexOf('.') + 1); alias = alias.substring(alias.lastIndexOf('.') + 1);
if (!names.contains(alias)) { if (!names.contains(alias)) {
names.add(alias); names.add(alias);
} }
} }
} catch (Exception ignored) { } catch (Exception ignored) {
} }
return names; return names;
} }
private static String listToString(List<String> list) { private static String listToString(List<String> list) {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
for (int i = 0; i < list.size(); i++) { for (int i = 0; i < list.size(); i++) {
if (i != 0) { if (i != 0) {
builder.append(", "); builder.append(", ");
} }
builder.append("\"").append(list.get(i)).append("\""); builder.append("\"").append(list.get(i)).append("\"");
} }
return builder.toString(); return builder.toString();
} }
@BeforeAll @BeforeAll
public static void initializeReflection() { public static void initializeReflection() {
BukkitInitialization.initializeAll(); BukkitInitialization.initializeAll();
} }
@Test @Test
public void testFindCurrent() { public void testFindCurrent() {
assertEquals(PacketType.Play.Client.STEER_VEHICLE, assertEquals(PacketType.Play.Client.STEER_VEHICLE,
PacketType.findCurrent(Protocol.PLAY, Sender.CLIENT, "SteerVehicle")); PacketType.findCurrent(Protocol.PLAY, Sender.CLIENT, "SteerVehicle"));
} }
@Test @Test
public void testLoginStart() { public void testLoginStart() {
// This packet is critical for handleLoin // This packet is critical for handleLoin
assertEquals(PacketLoginInStart.class, PacketType.Login.Client.START.getPacketClass()); assertEquals(PacketLoginInStart.class, PacketType.Login.Client.START.getPacketClass());
} }
@Test @Test
public void testDeprecation() { public void testDeprecation() {
assertTrue(PacketType.Status.Server.OUT_SERVER_INFO.isDeprecated(), "Packet isn't properly deprecated"); assertTrue(PacketType.Status.Server.OUT_SERVER_INFO.isDeprecated(), "Packet isn't properly deprecated");
assertTrue(PacketRegistry.getServerPacketTypes().contains(PacketType.Status.Server.OUT_SERVER_INFO), assertTrue(PacketRegistry.getServerPacketTypes().contains(PacketType.Status.Server.OUT_SERVER_INFO),
"Deprecated packet isn't properly included"); "Deprecated packet isn't properly included");
assertFalse(PacketType.Play.Server.CHAT.isDeprecated(), "Packet isn't properly deprecated"); assertFalse(PacketType.Play.Server.CHAT.isDeprecated(), "Packet isn't properly deprecated");
assertEquals(PacketType.Status.Server.OUT_SERVER_INFO, PacketType.Status.Server.SERVER_INFO, assertEquals(PacketType.Status.Server.OUT_SERVER_INFO, PacketType.Status.Server.SERVER_INFO,
"Deprecated packets aren't equal"); "Deprecated packets aren't equal");
} }
@Test @Test
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void ensureTypesAreCorrect() throws Exception { public void ensureTypesAreCorrect() throws Exception {
boolean fail = false; boolean fail = false;
EnumProtocol[] protocols = EnumProtocol.values(); EnumProtocol[] protocols = EnumProtocol.values();
for (EnumProtocol protocol : protocols) { for (EnumProtocol protocol : protocols) {
Field field = EnumProtocol.class.getDeclaredField("j"); Field field = EnumProtocol.class.getDeclaredField("j");
field.setAccessible(true); field.setAccessible(true);
Map<EnumProtocolDirection, Object> map = (Map<EnumProtocolDirection, Object>) field.get(protocol); Map<EnumProtocolDirection, Object> map = (Map<EnumProtocolDirection, Object>) field.get(protocol);
for (Entry<EnumProtocolDirection, Object> entry : map.entrySet()) { for (Entry<EnumProtocolDirection, Object> entry : map.entrySet()) {
Field mapField = entry.getValue().getClass().getDeclaredField("b"); Field mapField = entry.getValue().getClass().getDeclaredField("b");
mapField.setAccessible(true); mapField.setAccessible(true);
Map<Class<?>, Integer> reverseMap = (Map<Class<?>, Integer>) mapField.get(entry.getValue()); Map<Class<?>, Integer> reverseMap = (Map<Class<?>, Integer>) mapField.get(entry.getValue());
Map<Integer, Class<?>> treeMap = new TreeMap<>(); Map<Integer, Class<?>> treeMap = new TreeMap<>();
for (Entry<Class<?>, Integer> entry1 : reverseMap.entrySet()) { for (Entry<Class<?>, Integer> entry1 : reverseMap.entrySet()) {
treeMap.put(entry1.getValue(), entry1.getKey()); treeMap.put(entry1.getValue(), entry1.getKey());
} }
for (Entry<Integer, Class<?>> entry1 : treeMap.entrySet()) { for (Entry<Integer, Class<?>> entry1 : treeMap.entrySet()) {
try { try {
PacketType type = PacketType.fromClass(entry1.getValue()); PacketType type = PacketType.fromClass(entry1.getValue());
if (type.getCurrentId() != entry1.getKey()) { if (type.getCurrentId() != entry1.getKey()) {
throw new IllegalStateException( throw new IllegalStateException(
"Packet ID for " + type + " is incorrect. Expected " + entry1.getKey() + ", but got " "Packet ID for " + type + " is incorrect. Expected " + entry1.getKey() + ", but got "
+ type.getCurrentId()); + type.getCurrentId());
} }
} catch (Throwable ex) { } catch (Throwable ex) {
ex.printStackTrace(); ex.printStackTrace();
fail = true; fail = true;
} }
} }
} }
} }
assertFalse(fail, "Packet type(s) were incorrect!"); assertFalse(fail, "Packet type(s) were incorrect!");
} }
@Test @Test
public void testPacketCreation() { public void testPacketCreation() {
boolean fail = false; boolean fail = false;
for (PacketType type : PacketType.values()) { for (PacketType type : PacketType.values()) {
if (type.isSupported()) { if (type.isSupported()) {
try { try {
new PacketContainer(type); new PacketContainer(type);
} catch (Exception ex) { } catch (Exception ex) {
ex.printStackTrace(); ex.printStackTrace();
fail = true; fail = true;
} }
} }
} }
assertFalse(fail, "Packet type(s) failed to instantiate"); assertFalse(fail, "Packet type(s) failed to instantiate");
} }
} }

View File

@ -1,59 +1,60 @@
package com.comphenix.protocol.injector; package com.comphenix.protocol.injector;
import static com.comphenix.protocol.utility.TestUtils.setFinalField; import java.lang.reflect.Field;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import com.comphenix.protocol.BukkitInitialization;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.BukkitInitialization; import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
import com.comphenix.protocol.reflect.FuzzyReflection; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import net.minecraft.server.level.ChunkProviderServer;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import net.minecraft.server.level.PlayerChunkMap;
import java.lang.reflect.Field; import net.minecraft.server.level.PlayerChunkMap.EntityTracker;
import net.minecraft.server.level.ChunkProviderServer; import net.minecraft.server.level.WorldServer;
import net.minecraft.server.level.PlayerChunkMap; import net.minecraft.world.entity.Entity;
import net.minecraft.server.level.PlayerChunkMap.EntityTracker; import org.bukkit.craftbukkit.v1_19_R2.CraftWorld;
import net.minecraft.server.level.WorldServer; import org.bukkit.craftbukkit.v1_19_R2.entity.CraftEntity;
import net.minecraft.world.entity.Entity; import org.junit.jupiter.api.BeforeAll;
import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; import org.junit.jupiter.api.Test;
import org.bukkit.craftbukkit.v1_19_R2.entity.CraftEntity;
import org.junit.jupiter.api.BeforeAll; import static com.comphenix.protocol.utility.TestUtils.setFinalField;
import org.junit.jupiter.api.Test; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class EntityUtilitiesTest {
public class EntityUtilitiesTest {
@BeforeAll
public static void beforeClass() { @BeforeAll
BukkitInitialization.initializeAll(); public static void beforeClass() {
} BukkitInitialization.initializeAll();
}
@Test
public void testReflection() { @Test
CraftWorld bukkit = mock(CraftWorld.class); public void testReflection() {
WorldServer world = mock(WorldServer.class); CraftWorld bukkit = mock(CraftWorld.class);
when(bukkit.getHandle()).thenReturn(world); WorldServer world = mock(WorldServer.class);
when(bukkit.getHandle()).thenReturn(world);
ChunkProviderServer provider = mock(ChunkProviderServer.class);
when(world.k()).thenReturn(provider); ChunkProviderServer provider = mock(ChunkProviderServer.class);
when(world.k()).thenReturn(provider);
PlayerChunkMap chunkMap = mock(PlayerChunkMap.class);
Field chunkMapField = FuzzyReflection.fromClass(ChunkProviderServer.class, true) PlayerChunkMap chunkMap = mock(PlayerChunkMap.class);
.getField(FuzzyFieldContract.newBuilder().typeExact(PlayerChunkMap.class).build()); Field chunkMapField = FuzzyReflection.fromClass(ChunkProviderServer.class, true)
setFinalField(provider, chunkMapField, chunkMap); .getField(FuzzyFieldContract.newBuilder().typeExact(PlayerChunkMap.class).build());
setFinalField(provider, chunkMapField, chunkMap);
CraftEntity bukkitEntity = mock(CraftEntity.class);
Entity fakeEntity = mock(Entity.class); CraftEntity bukkitEntity = mock(CraftEntity.class);
when(fakeEntity.getBukkitEntity()).thenReturn(bukkitEntity); Entity fakeEntity = mock(Entity.class);
when(fakeEntity.getBukkitEntity()).thenReturn(bukkitEntity);
EntityTracker tracker = mock(EntityTracker.class);
Field trackerField = FuzzyReflection.fromClass(EntityTracker.class, true) EntityTracker tracker = mock(EntityTracker.class);
.getField(FuzzyFieldContract.newBuilder().typeExact(Entity.class).build()); Field trackerField = FuzzyReflection.fromClass(EntityTracker.class, true)
setFinalField(tracker, trackerField, fakeEntity); .getField(FuzzyFieldContract.newBuilder().typeExact(Entity.class).build());
setFinalField(tracker, trackerField, fakeEntity);
Int2ObjectMap<EntityTracker> trackerMap = new Int2ObjectOpenHashMap<>();
trackerMap.put(1, tracker); Int2ObjectMap<EntityTracker> trackerMap = new Int2ObjectOpenHashMap<>();
Field trackedEntitiesField = FuzzyReflection.fromClass(PlayerChunkMap.class, true) trackerMap.put(1, tracker);
.getField(FuzzyFieldContract.newBuilder().typeExact(Int2ObjectMap.class).build()); Field trackedEntitiesField = FuzzyReflection.fromClass(PlayerChunkMap.class, true)
setFinalField(chunkMap, trackedEntitiesField, trackerMap); .getField(FuzzyFieldContract.newBuilder().typeExact(Int2ObjectMap.class).build());
} setFinalField(chunkMap, trackedEntitiesField, trackerMap);
} }
}

View File

@ -1,69 +1,69 @@
/** /**
* (c) 2016 dmulloy2 * (c) 2016 dmulloy2
*/ */
package com.comphenix.protocol.injector; package com.comphenix.protocol.injector;
import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import com.comphenix.protocol.BukkitInitialization; import com.comphenix.protocol.BukkitInitialization;
import com.comphenix.protocol.PacketType; import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.injector.netty.WirePacket; import com.comphenix.protocol.injector.netty.WirePacket;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
/** /**
* @author dmulloy2 * @author dmulloy2
*/ */
public class WirePacketTest { public class WirePacketTest {
@BeforeAll @BeforeAll
public static void beforeClass() { public static void beforeClass() {
BukkitInitialization.initializeAll(); BukkitInitialization.initializeAll();
} }
// @Test // @Test
public void testPackets() { public void testPackets() {
List<String> failures = new ArrayList<>(); List<String> failures = new ArrayList<>();
for (PacketType type : PacketType.values()) { for (PacketType type : PacketType.values()) {
if (type.isDeprecated()) { if (type.isDeprecated()) {
continue; continue;
} }
try { try {
PacketContainer packet = new PacketContainer(type); PacketContainer packet = new PacketContainer(type);
WirePacket wire = WirePacket.fromPacket(packet); WirePacket wire = WirePacket.fromPacket(packet);
WirePacket handle = WirePacket.fromPacket(packet.getHandle()); WirePacket handle = WirePacket.fromPacket(packet.getHandle());
assertEquals(wire, handle); assertEquals(wire, handle);
} catch (Exception ex) { } catch (Exception ex) {
failures.add(type + " :: " + ex.getMessage()); failures.add(type + " :: " + ex.getMessage());
System.out.println(type); System.out.println(type);
ex.printStackTrace(); ex.printStackTrace();
} }
} }
assertEquals(failures, new ArrayList<>()); assertEquals(failures, new ArrayList<>());
} }
@Test @Test
public void testSerialization() { public void testSerialization() {
int id = 42; int id = 42;
byte[] array = {1, 3, 7, 21, 88, 67, 8}; byte[] array = {1, 3, 7, 21, 88, 67, 8};
WirePacket packet = new WirePacket(id, array); WirePacket packet = new WirePacket(id, array);
ByteBuf buf = packet.serialize(); ByteBuf buf = packet.serialize();
int backId = WirePacket.readVarInt(buf); int backId = WirePacket.readVarInt(buf);
byte[] backArray = new byte[buf.readableBytes()]; byte[] backArray = new byte[buf.readableBytes()];
buf.readBytes(backArray); buf.readBytes(backArray);
assertEquals(id, backId); assertEquals(id, backId);
assertArrayEquals(array, backArray); assertArrayEquals(array, backArray);
} }
} }

View File

@ -1,45 +1,45 @@
package com.comphenix.protocol.reflect.cloning; package com.comphenix.protocol.reflect.cloning;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import com.comphenix.protocol.BukkitInitialization; import com.comphenix.protocol.BukkitInitialization;
import com.comphenix.protocol.PacketType; import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketContainer;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import net.minecraft.core.NonNullList; import net.minecraft.core.NonNullList;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
public class AggregateClonerTest { public class AggregateClonerTest {
@BeforeAll @BeforeAll
public static void initializeBukkit() { public static void initializeBukkit() {
BukkitInitialization.initializeAll(); BukkitInitialization.initializeAll();
} }
@Test @Test
public void testArrays() { public void testArrays() {
List<Integer> input = Arrays.asList(1, 2, 3); List<Integer> input = Arrays.asList(1, 2, 3);
assertEquals(input, AggregateCloner.DEFAULT.clone(input)); assertEquals(input, AggregateCloner.DEFAULT.clone(input));
} }
// @Test // @Test
// Usages of NonNullList were removed in 1.17.1 // Usages of NonNullList were removed in 1.17.1
public void testNonNullList() { public void testNonNullList() {
PacketContainer packet = new PacketContainer(PacketType.Play.Server.WINDOW_ITEMS); PacketContainer packet = new PacketContainer(PacketType.Play.Server.WINDOW_ITEMS);
NonNullList<ItemStack> list = NonNullList.a(16, ItemStack.b); NonNullList<ItemStack> list = NonNullList.a(16, ItemStack.b);
packet.getModifier().write(1, list); packet.getModifier().write(1, list);
PacketContainer cloned = packet.deepClone(); PacketContainer cloned = packet.deepClone();
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
NonNullList<ItemStack> list1 = (NonNullList<ItemStack>) cloned.getModifier().read(1); NonNullList<ItemStack> list1 = (NonNullList<ItemStack>) cloned.getModifier().read(1);
assertEquals(list.size(), list1.size()); assertEquals(list.size(), list1.size());
Assertions.assertArrayEquals(list.toArray(), list1.toArray()); Assertions.assertArrayEquals(list.toArray(), list1.toArray());
} }
} }

View File

@ -1,159 +1,160 @@
package com.comphenix.protocol.utility; package com.comphenix.protocol.utility;
import static com.comphenix.protocol.utility.TestUtils.assertItemsEqual; import com.comphenix.protocol.BukkitInitialization;
import static org.junit.jupiter.api.Assertions.assertEquals; import com.mojang.authlib.GameProfile;
import static org.junit.jupiter.api.Assertions.assertNotNull; import net.minecraft.nbt.NBTCompressedStreamTools;
import static org.junit.jupiter.api.Assertions.assertNull; import net.minecraft.network.chat.IChatBaseComponent;
import static org.junit.jupiter.api.Assertions.assertThrows; import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes;
import static org.mockito.Mockito.mock; import net.minecraft.network.protocol.status.ServerPing;
import static org.mockito.Mockito.times; import net.minecraft.network.syncher.DataWatcher;
import static org.mockito.Mockito.verify; import net.minecraft.server.network.PlayerConnection;
import net.minecraft.util.MinecraftEncryption;
import com.comphenix.protocol.BukkitInitialization; import net.minecraft.world.level.ChunkCoordIntPair;
import com.mojang.authlib.GameProfile; import net.minecraft.world.level.block.state.IBlockData;
import net.minecraft.nbt.NBTCompressedStreamTools; import org.bukkit.Material;
import net.minecraft.network.chat.IChatBaseComponent; import org.bukkit.block.Block;
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes; import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemStack;
import net.minecraft.network.protocol.status.ServerPing; import org.bukkit.entity.Entity;
import net.minecraft.network.syncher.DataWatcher; import org.bukkit.inventory.ItemStack;
import net.minecraft.server.network.PlayerConnection; import org.junit.jupiter.api.AfterAll;
import net.minecraft.util.MinecraftEncryption; import org.junit.jupiter.api.BeforeAll;
import net.minecraft.world.level.ChunkCoordIntPair; import org.junit.jupiter.api.Test;
import net.minecraft.world.level.block.state.IBlockData;
import org.bukkit.Material; import static com.comphenix.protocol.utility.TestUtils.assertItemsEqual;
import org.bukkit.block.Block; import static org.junit.jupiter.api.Assertions.assertEquals;
import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemStack; import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.bukkit.entity.Entity; import static org.junit.jupiter.api.Assertions.assertNull;
import org.bukkit.inventory.ItemStack; import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.AfterAll; import static org.mockito.Mockito.mock;
import org.junit.jupiter.api.BeforeAll; import static org.mockito.Mockito.times;
import org.junit.jupiter.api.Test; import static org.mockito.Mockito.verify;
public class MinecraftReflectionTest { public class MinecraftReflectionTest {
@BeforeAll @BeforeAll
public static void initializeBukkit() { public static void initializeBukkit() {
BukkitInitialization.initializeAll(); BukkitInitialization.initializeAll();
} }
@AfterAll @AfterAll
public static void undoMocking() { public static void undoMocking() {
// NOP // NOP
MinecraftReflection.minecraftPackage = null; MinecraftReflection.minecraftPackage = null;
} }
@Test @Test
public void testBukkitMethod() { public void testBukkitMethod() {
FakeEntity entity = mock(FakeEntity.class); FakeEntity entity = mock(FakeEntity.class);
FakeBlock block = mock(FakeBlock.class); FakeBlock block = mock(FakeBlock.class);
MinecraftReflection.getBukkitEntity(entity); MinecraftReflection.getBukkitEntity(entity);
MinecraftReflection.getBukkitEntity(block); MinecraftReflection.getBukkitEntity(block);
verify(entity, times(1)).getBukkitEntity(); verify(entity, times(1)).getBukkitEntity();
verify(block, times(1)).getBukkitEntity(); verify(block, times(1)).getBukkitEntity();
} }
@Test @Test
public void testIllegalClass() { public void testIllegalClass() {
assertThrows(IllegalArgumentException.class, () -> MinecraftReflection.getBukkitEntity("Hello")); assertThrows(IllegalArgumentException.class, () -> MinecraftReflection.getBukkitEntity("Hello"));
} }
@Test @Test
public void testNullable() { public void testNullable() {
assertNull(MinecraftReflection.getNullableNMS("ProtocolLib")); assertNull(MinecraftReflection.getNullableNMS("ProtocolLib"));
} }
@Test @Test
public void testAttributeSnapshot() { public void testAttributeSnapshot() {
assertEquals(PacketPlayOutUpdateAttributes.AttributeSnapshot.class, assertEquals(PacketPlayOutUpdateAttributes.AttributeSnapshot.class,
MinecraftReflection.getAttributeSnapshotClass()); MinecraftReflection.getAttributeSnapshotClass());
} }
@Test @Test
public void testChatComponent() { public void testChatComponent() {
assertEquals(IChatBaseComponent.class, MinecraftReflection.getIChatBaseComponentClass()); assertEquals(IChatBaseComponent.class, MinecraftReflection.getIChatBaseComponentClass());
} }
@Test @Test
public void testChatSerializer() { public void testChatSerializer() {
assertEquals(IChatBaseComponent.ChatSerializer.class, MinecraftReflection.getChatSerializerClass()); assertEquals(IChatBaseComponent.ChatSerializer.class, MinecraftReflection.getChatSerializerClass());
} }
@Test @Test
public void testChunkCoordIntPair() { public void testChunkCoordIntPair() {
assertEquals(ChunkCoordIntPair.class, MinecraftReflection.getChunkCoordIntPair()); assertEquals(ChunkCoordIntPair.class, MinecraftReflection.getChunkCoordIntPair());
} }
@Test @Test
public void testIBlockData() { public void testIBlockData() {
assertEquals(IBlockData.class, MinecraftReflection.getIBlockDataClass()); assertEquals(IBlockData.class, MinecraftReflection.getIBlockDataClass());
} }
@Test @Test
public void testPlayerConnection() { public void testPlayerConnection() {
assertEquals(PlayerConnection.class, MinecraftReflection.getPlayerConnectionClass()); assertEquals(PlayerConnection.class, MinecraftReflection.getPlayerConnectionClass());
} }
@Test @Test
public void testServerPing() { public void testServerPing() {
assertEquals(ServerPing.class, MinecraftReflection.getServerPingClass()); assertEquals(ServerPing.class, MinecraftReflection.getServerPingClass());
} }
@Test @Test
public void testServerPingPlayerSample() { public void testServerPingPlayerSample() {
assertEquals(ServerPing.ServerPingPlayerSample.class, MinecraftReflection.getServerPingPlayerSampleClass()); assertEquals(ServerPing.ServerPingPlayerSample.class, MinecraftReflection.getServerPingPlayerSampleClass());
} }
@Test @Test
public void testServerPingServerData() { public void testServerPingServerData() {
assertEquals(ServerPing.ServerData.class, MinecraftReflection.getServerPingServerDataClass()); assertEquals(ServerPing.ServerData.class, MinecraftReflection.getServerPingServerDataClass());
} }
@Test @Test
public void testNbtStreamTools() { public void testNbtStreamTools() {
assertEquals(NBTCompressedStreamTools.class, MinecraftReflection.getNbtCompressedStreamToolsClass()); assertEquals(NBTCompressedStreamTools.class, MinecraftReflection.getNbtCompressedStreamToolsClass());
} }
@Test @Test
public void testDataWatcherItem() { public void testDataWatcherItem() {
assertEquals(DataWatcher.Item.class, MinecraftReflection.getDataWatcherItemClass()); assertEquals(DataWatcher.Item.class, MinecraftReflection.getDataWatcherItemClass());
} }
@Test @Test
public void testLoginSignature() { public void testLoginSignature() {
assertEquals(MinecraftEncryption.b.class, MinecraftReflection.getSaltedSignatureClass()); assertEquals(MinecraftEncryption.b.class, MinecraftReflection.getSaltedSignatureClass());
} }
@Test @Test
public void testItemStacks() { public void testItemStacks() {
ItemStack stack = new ItemStack(Material.GOLDEN_SWORD); ItemStack stack = new ItemStack(Material.GOLDEN_SWORD);
Object nmsStack = MinecraftReflection.getMinecraftItemStack(stack); Object nmsStack = MinecraftReflection.getMinecraftItemStack(stack);
assertItemsEqual(stack, MinecraftReflection.getBukkitItemStack(nmsStack)); assertItemsEqual(stack, MinecraftReflection.getBukkitItemStack(nmsStack));
// The NMS handle for CraftItemStack is null with Material.AIR, make sure it is handled correctly // The NMS handle for CraftItemStack is null with Material.AIR, make sure it is handled correctly
assertNotNull(MinecraftReflection.getMinecraftItemStack(CraftItemStack.asCraftCopy(new ItemStack(Material.AIR)))); assertNotNull(
} MinecraftReflection.getMinecraftItemStack(CraftItemStack.asCraftCopy(new ItemStack(Material.AIR))));
}
@Test
public void testGameProfile() { @Test
assertEquals(GameProfile.class, MinecraftReflection.getGameProfileClass()); public void testGameProfile() {
} assertEquals(GameProfile.class, MinecraftReflection.getGameProfileClass());
}
@Test
public void testEnumEntityUseAction() { @Test
// this class is package-private in PacketPlayInUseEntity, so we can only check if no exception is thrown during retrieval public void testEnumEntityUseAction() {
MinecraftReflection.getEnumEntityUseActionClass(); // this class is package-private in PacketPlayInUseEntity, so we can only check if no exception is thrown during retrieval
} MinecraftReflection.getEnumEntityUseActionClass();
}
// Mocking objects
private interface FakeEntity { // Mocking objects
private interface FakeEntity {
Entity getBukkitEntity();
} Entity getBukkitEntity();
}
private interface FakeBlock {
private interface FakeBlock {
Block getBukkitEntity();
} Block getBukkitEntity();
} }
}

View File

@ -1,52 +1,52 @@
package com.comphenix.protocol.utility; package com.comphenix.protocol.utility;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import com.comphenix.protocol.reflect.accessors.Accessors; import com.comphenix.protocol.reflect.accessors.Accessors;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.List; import java.util.List;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
public class TestUtils { public class TestUtils {
public static void assertItemCollectionsEqual(List<ItemStack> first, List<ItemStack> second) { public static void assertItemCollectionsEqual(List<ItemStack> first, List<ItemStack> second) {
assertEquals(first.size(), second.size()); assertEquals(first.size(), second.size());
for (int i = 0; i < first.size(); i++) { for (int i = 0; i < first.size(); i++) {
assertItemsEqual(first.get(i), second.get(i)); assertItemsEqual(first.get(i), second.get(i));
} }
} }
public static void assertItemsEqual(ItemStack first, ItemStack second) { public static void assertItemsEqual(ItemStack first, ItemStack second) {
if (first == null) { if (first == null) {
assertNull(second); assertNull(second);
} else { } else {
assertNotNull(first); assertNotNull(first);
// The legacy check in ItemStack#isSimilar causes a null pointer // The legacy check in ItemStack#isSimilar causes a null pointer
assertEquals(first.getType(), second.getType()); assertEquals(first.getType(), second.getType());
assertEquals(first.getDurability(), second.getDurability()); assertEquals(first.getDurability(), second.getDurability());
assertEquals(first.hasItemMeta(), second.hasItemMeta()); assertEquals(first.hasItemMeta(), second.hasItemMeta());
if (first.hasItemMeta()) { if (first.hasItemMeta()) {
assertTrue(Bukkit.getItemFactory().equals(first.getItemMeta(), second.getItemMeta())); assertTrue(Bukkit.getItemFactory().equals(first.getItemMeta(), second.getItemMeta()));
} }
} }
} }
public static boolean equivalentItem(ItemStack first, ItemStack second) { public static boolean equivalentItem(ItemStack first, ItemStack second) {
if (first == null) { if (first == null) {
return second == null; return second == null;
} else if (second == null) { } else if (second == null) {
return false; return false;
} else { } else {
return first.getType().equals(second.getType()); return first.getType().equals(second.getType());
} }
} }
public static void setFinalField(Object obj, Field field, Object newValue) { public static void setFinalField(Object obj, Field field, Object newValue) {
Accessors.getFieldAccessor(field).set(obj, newValue); Accessors.getFieldAccessor(field).set(obj, newValue);
} }
} }

View File

@ -1,58 +1,58 @@
package com.comphenix.protocol.wrappers; package com.comphenix.protocol.wrappers;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import com.comphenix.protocol.BukkitInitialization; import com.comphenix.protocol.BukkitInitialization;
import com.comphenix.protocol.reflect.EquivalentConverter; import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.wrappers.Either.Left; import com.comphenix.protocol.wrappers.Either.Left;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
public class BukkitConvertersTest { public class BukkitConvertersTest {
@BeforeAll @BeforeAll
public static void beforeClass() { public static void beforeClass() {
BukkitInitialization.initializeAll(); BukkitInitialization.initializeAll();
} }
@Test @Test
public void testItemStacks() { public void testItemStacks() {
ItemStack item = new ItemStack(Material.DIAMOND_SWORD, 16); ItemStack item = new ItemStack(Material.DIAMOND_SWORD, 16);
item.addEnchantment(Enchantment.DAMAGE_ALL, 4); item.addEnchantment(Enchantment.DAMAGE_ALL, 4);
ItemMeta meta = item.getItemMeta(); ItemMeta meta = item.getItemMeta();
meta.setDisplayName(ChatColor.GREEN + "Diamond Sword"); meta.setDisplayName(ChatColor.GREEN + "Diamond Sword");
item.setItemMeta(meta); item.setItemMeta(meta);
EquivalentConverter<ItemStack> converter = BukkitConverters.getItemStackConverter(); EquivalentConverter<ItemStack> converter = BukkitConverters.getItemStackConverter();
Object nmsStack = converter.getGeneric(item); Object nmsStack = converter.getGeneric(item);
ItemStack back = converter.getSpecific(nmsStack); ItemStack back = converter.getSpecific(nmsStack);
assertEquals(item.getType(), back.getType()); assertEquals(item.getType(), back.getType());
assertEquals(item.getDurability(), back.getDurability()); assertEquals(item.getDurability(), back.getDurability());
assertEquals(item.hasItemMeta(), back.hasItemMeta()); assertEquals(item.hasItemMeta(), back.hasItemMeta());
assertTrue(Bukkit.getItemFactory().equals(item.getItemMeta(), back.getItemMeta())); assertTrue(Bukkit.getItemFactory().equals(item.getItemMeta(), back.getItemMeta()));
} }
@Test @Test
public void testEither() { public void testEither() {
Either<String, String> test = new Left<>("bla"); Either<String, String> test = new Left<>("bla");
EquivalentConverter<Either<String, String>> converter = BukkitConverters.getEitherConverter( EquivalentConverter<Either<String, String>> converter = BukkitConverters.getEitherConverter(
Converters.passthrough(String.class), Converters.passthrough(String.class) Converters.passthrough(String.class), Converters.passthrough(String.class)
); );
com.mojang.datafixers.util.Either<String, String> nmsEither = (com.mojang.datafixers.util.Either<String, String>) converter.getGeneric(test); com.mojang.datafixers.util.Either<String, String> nmsEither = (com.mojang.datafixers.util.Either<String, String>) converter.getGeneric(test);
Either<String, String> wrapped = converter.getSpecific(nmsEither); Either<String, String> wrapped = converter.getSpecific(nmsEither);
assertEquals(wrapped.left(), nmsEither.left()); assertEquals(wrapped.left(), nmsEither.left());
assertEquals(wrapped.right(), nmsEither.right()); assertEquals(wrapped.right(), nmsEither.right());
} }
} }

View File

@ -1,31 +1,31 @@
package com.comphenix.protocol.wrappers; package com.comphenix.protocol.wrappers;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import com.comphenix.protocol.BukkitInitialization; import com.comphenix.protocol.BukkitInitialization;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
public class ChunkCoordIntPairTest { public class ChunkCoordIntPairTest {
@BeforeAll @BeforeAll
public static void initializeBukkit() { public static void initializeBukkit() {
BukkitInitialization.initializeAll(); BukkitInitialization.initializeAll();
} }
@Test @Test
public void test() { public void test() {
net.minecraft.world.level.ChunkCoordIntPair pair = new net.minecraft.world.level.ChunkCoordIntPair(1, 2); net.minecraft.world.level.ChunkCoordIntPair pair = new net.minecraft.world.level.ChunkCoordIntPair(1, 2);
ChunkCoordIntPair specific = ChunkCoordIntPair.getConverter().getSpecific(pair); ChunkCoordIntPair specific = ChunkCoordIntPair.getConverter().getSpecific(pair);
assertEquals(1, specific.getChunkX()); assertEquals(1, specific.getChunkX());
assertEquals(2, specific.getChunkZ()); assertEquals(2, specific.getChunkZ());
net.minecraft.world.level.ChunkCoordIntPair roundtrip = net.minecraft.world.level.ChunkCoordIntPair roundtrip =
(net.minecraft.world.level.ChunkCoordIntPair) ChunkCoordIntPair.getConverter(). (net.minecraft.world.level.ChunkCoordIntPair) ChunkCoordIntPair.getConverter().
getGeneric(specific); getGeneric(specific);
assertEquals(1, roundtrip.e); assertEquals(1, roundtrip.e);
assertEquals(2, roundtrip.f); assertEquals(2, roundtrip.f);
} }
} }

View File

@ -1,57 +1,58 @@
package com.comphenix.protocol.wrappers; package com.comphenix.protocol.wrappers;
import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertNotNull; import java.util.Map.Entry;
import static org.junit.jupiter.api.Assertions.fail; import java.util.Set;
import com.comphenix.protocol.BukkitInitialization; import com.comphenix.protocol.BukkitInitialization;
import com.comphenix.protocol.reflect.EquivalentConverter; import com.comphenix.protocol.reflect.EquivalentConverter;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import java.util.Map; import org.junit.jupiter.api.BeforeAll;
import java.util.Map.Entry; import org.junit.jupiter.api.Test;
import java.util.Set;
import org.junit.jupiter.api.BeforeAll; import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.fail;
public class EnumWrappersTest {
public class EnumWrappersTest {
private static final Set<String> KNOWN_INVALID = Sets.newHashSet(
"Particle", "WorldBorderAction", "CombatEventType", "TitleAction", "ChatType", "TitleAction" private static final Set<String> KNOWN_INVALID = Sets.newHashSet(
); "Particle", "WorldBorderAction", "CombatEventType", "TitleAction", "ChatType", "TitleAction"
);
@BeforeAll
public static void initializeBukkit() { @BeforeAll
BukkitInitialization.initializeAll(); public static void initializeBukkit() {
EnumWrappers.getPlayerInfoActionClass(); // just to initialize the classes and converters BukkitInitialization.initializeAll();
} EnumWrappers.getPlayerInfoActionClass(); // just to initialize the classes and converters
}
@Test
@SuppressWarnings("unchecked") @Test
public void validateAllEnumFieldsAreWrapped() { @SuppressWarnings("unchecked")
Map<Class<?>, EquivalentConverter<?>> nativeEnums = EnumWrappers.getFromNativeMap(); public void validateAllEnumFieldsAreWrapped() {
for (Entry<Class<?>, EquivalentConverter<?>> entry : nativeEnums.entrySet()) { Map<Class<?>, EquivalentConverter<?>> nativeEnums = EnumWrappers.getFromNativeMap();
for (Object nativeConstant : entry.getKey().getEnumConstants()) { for (Entry<Class<?>, EquivalentConverter<?>> entry : nativeEnums.entrySet()) {
try { for (Object nativeConstant : entry.getKey().getEnumConstants()) {
// yay, generics try {
EquivalentConverter<Object> converter = (EquivalentConverter<Object>) entry.getValue(); // yay, generics
EquivalentConverter<Object> converter = (EquivalentConverter<Object>) entry.getValue();
// try to convert the native constant to a wrapper and back
Object wrappedValue = converter.getSpecific(nativeConstant); // try to convert the native constant to a wrapper and back
assertNotNull(wrappedValue); Object wrappedValue = converter.getSpecific(nativeConstant);
assertNotNull(wrappedValue);
Object unwrappedValue = converter.getGeneric(wrappedValue);
assertNotNull(unwrappedValue); Object unwrappedValue = converter.getGeneric(wrappedValue);
assertNotNull(unwrappedValue);
assertEquals(nativeConstant, unwrappedValue);
} catch (Exception exception) { assertEquals(nativeConstant, unwrappedValue);
fail(exception); } catch (Exception exception) {
} fail(exception);
} }
} }
} }
}
@Test
public void testValidity() { @Test
assertEquals(EnumWrappers.INVALID, KNOWN_INVALID); public void testValidity() {
} assertEquals(EnumWrappers.INVALID, KNOWN_INVALID);
} }
}

View File

@ -1,104 +1,104 @@
package com.comphenix.protocol.wrappers; package com.comphenix.protocol.wrappers;
import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.ArrayList;
import static org.junit.jupiter.api.Assertions.assertNotSame; import java.util.List;
import static org.junit.jupiter.api.Assertions.assertTrue;
import com.comphenix.protocol.BukkitInitialization;
import com.comphenix.protocol.BukkitInitialization; import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.PacketType; import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.wrappers.WrappedAttributeModifier.Operation;
import com.comphenix.protocol.wrappers.WrappedAttributeModifier.Operation; import com.google.common.collect.Lists;
import com.google.common.collect.Lists; import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes.AttributeSnapshot;
import java.util.ArrayList; import net.minecraft.resources.MinecraftKey;
import java.util.List; import net.minecraft.world.entity.ai.attributes.AttributeBase;
import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes.AttributeSnapshot; import org.junit.jupiter.api.BeforeAll;
import net.minecraft.resources.MinecraftKey; import org.junit.jupiter.api.BeforeEach;
import net.minecraft.world.entity.ai.attributes.AttributeBase; import org.junit.jupiter.api.Test;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import org.junit.jupiter.api.BeforeAll; import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.BeforeEach; import static org.junit.jupiter.api.Assertions.assertNotSame;
import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertTrue;
public class WrappedAttributeTest { public class WrappedAttributeTest {
private WrappedAttributeModifier doubleModifier; private WrappedAttributeModifier doubleModifier;
private WrappedAttributeModifier constantModifier; private WrappedAttributeModifier constantModifier;
private WrappedAttribute attribute; private WrappedAttribute attribute;
@BeforeAll @BeforeAll
public static void initializeBukkit() { public static void initializeBukkit() {
BukkitInitialization.initializeAll(); BukkitInitialization.initializeAll();
} }
@BeforeEach @BeforeEach
public void setUp() { public void setUp() {
// Create a couple of modifiers // Create a couple of modifiers
this.doubleModifier = this.doubleModifier =
WrappedAttributeModifier.newBuilder(). WrappedAttributeModifier.newBuilder().
name("Double Damage"). name("Double Damage").
amount(1). amount(1).
operation(Operation.ADD_PERCENTAGE). operation(Operation.ADD_PERCENTAGE).
build(); build();
this.constantModifier = this.constantModifier =
WrappedAttributeModifier.newBuilder(). WrappedAttributeModifier.newBuilder().
name("Damage Bonus"). name("Damage Bonus").
amount(5). amount(5).
operation(Operation.ADD_NUMBER). operation(Operation.ADD_NUMBER).
build(); build();
// Create attribute // Create attribute
this.attribute = WrappedAttribute.newBuilder(). this.attribute = WrappedAttribute.newBuilder().
attributeKey("generic.attackDamage"). attributeKey("generic.attackDamage").
baseValue(2). baseValue(2).
packet(new PacketContainer(PacketType.Play.Server.UPDATE_ATTRIBUTES)). packet(new PacketContainer(PacketType.Play.Server.UPDATE_ATTRIBUTES)).
modifiers(Lists.newArrayList(this.constantModifier, this.doubleModifier)). modifiers(Lists.newArrayList(this.constantModifier, this.doubleModifier)).
build(); build();
} }
@Test @Test
public void testEquality() { public void testEquality() {
// Check wrapped equality // Check wrapped equality
assertEquals(this.doubleModifier, this.doubleModifier); assertEquals(this.doubleModifier, this.doubleModifier);
assertNotSame(this.constantModifier, this.doubleModifier); assertNotSame(this.constantModifier, this.doubleModifier);
assertEquals(this.doubleModifier.getHandle(), this.getModifierCopy(this.doubleModifier)); assertEquals(this.doubleModifier.getHandle(), this.getModifierCopy(this.doubleModifier));
assertEquals(this.constantModifier.getHandle(), this.getModifierCopy(this.constantModifier)); assertEquals(this.constantModifier.getHandle(), this.getModifierCopy(this.constantModifier));
} }
@Test @Test
public void testAttribute() { public void testAttribute() {
assertEquals(this.attribute, WrappedAttribute.fromHandle(this.getAttributeCopy(this.attribute))); assertEquals(this.attribute, WrappedAttribute.fromHandle(this.getAttributeCopy(this.attribute)));
assertTrue(this.attribute.hasModifier(this.doubleModifier.getUUID())); assertTrue(this.attribute.hasModifier(this.doubleModifier.getUUID()));
assertTrue(this.attribute.hasModifier(this.constantModifier.getUUID())); assertTrue(this.attribute.hasModifier(this.constantModifier.getUUID()));
} }
@Test @Test
public void testFromTemplate() { public void testFromTemplate() {
assertEquals(this.attribute, WrappedAttribute.newBuilder(this.attribute).build()); assertEquals(this.attribute, WrappedAttribute.newBuilder(this.attribute).build());
} }
/** /**
* Retrieve the equivalent NMS attribute. * Retrieve the equivalent NMS attribute.
* *
* @param attribute - the wrapped attribute. * @param attribute - the wrapped attribute.
* @return The equivalent NMS attribute. * @return The equivalent NMS attribute.
*/ */
private AttributeSnapshot getAttributeCopy(WrappedAttribute attribute) { private AttributeSnapshot getAttributeCopy(WrappedAttribute attribute) {
List<AttributeModifier> modifiers = new ArrayList<>(); List<AttributeModifier> modifiers = new ArrayList<>();
for (WrappedAttributeModifier wrapper : attribute.getModifiers()) { for (WrappedAttributeModifier wrapper : attribute.getModifiers()) {
modifiers.add((AttributeModifier) wrapper.getHandle()); modifiers.add((AttributeModifier) wrapper.getHandle());
} }
AttributeBase base = BuiltInRegistries.u.a(MinecraftKey.a(attribute.getAttributeKey())); AttributeBase base = BuiltInRegistries.u.a(MinecraftKey.a(attribute.getAttributeKey()));
return new AttributeSnapshot(base, attribute.getBaseValue(), modifiers); return new AttributeSnapshot(base, attribute.getBaseValue(), modifiers);
} }
private AttributeModifier getModifierCopy(WrappedAttributeModifier modifier) { private AttributeModifier getModifierCopy(WrappedAttributeModifier modifier) {
AttributeModifier.Operation operation = AttributeModifier.Operation.values()[modifier.getOperation().getId()]; AttributeModifier.Operation operation = AttributeModifier.Operation.values()[modifier.getOperation().getId()];
return new AttributeModifier(modifier.getUUID(), modifier.getName(), modifier.getAmount(), operation); return new AttributeModifier(modifier.getUUID(), modifier.getName(), modifier.getAmount(), operation);
} }
} }

View File

@ -1,70 +1,70 @@
/** /**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2015 dmulloy2 * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2015 dmulloy2
* <p> * <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later * License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later
* version. * version.
* <p> * <p>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details. * details.
* <p> * <p>
* You should have received a copy of the GNU General Public License along with this program; if not, write to the Free * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
package com.comphenix.protocol.wrappers; package com.comphenix.protocol.wrappers;
import static org.junit.jupiter.api.Assertions.assertEquals; import com.comphenix.protocol.BukkitInitialization;
import net.minecraft.world.level.block.state.IBlockData;
import com.comphenix.protocol.BukkitInitialization; import org.bukkit.Material;
import net.minecraft.world.level.block.state.IBlockData; import org.bukkit.block.BlockFace;
import org.bukkit.Material; import org.bukkit.block.data.type.GlassPane;
import org.bukkit.block.BlockFace; import org.bukkit.craftbukkit.v1_19_R2.block.data.CraftBlockData;
import org.bukkit.block.data.type.GlassPane; import org.bukkit.craftbukkit.v1_19_R2.block.impl.CraftStainedGlassPane;
import org.bukkit.craftbukkit.v1_19_R2.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_19_R2.util.CraftMagicNumbers;
import org.bukkit.craftbukkit.v1_19_R2.block.impl.CraftStainedGlassPane; import org.junit.jupiter.api.BeforeAll;
import org.bukkit.craftbukkit.v1_19_R2.util.CraftMagicNumbers; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals;
/** /**
* @author dmulloy2 * @author dmulloy2
*/ */
public class WrappedBlockDataTest { public class WrappedBlockDataTest {
@BeforeAll @BeforeAll
public static void initializeBukkit() { public static void initializeBukkit() {
BukkitInitialization.initializeAll(); BukkitInitialization.initializeAll();
} }
@Test @Test
public void testMaterialCreation() { public void testMaterialCreation() {
Material type = Material.BLUE_WOOL; Material type = Material.BLUE_WOOL;
WrappedBlockData wrapper = WrappedBlockData.createData(type); WrappedBlockData wrapper = WrappedBlockData.createData(type);
assertEquals(wrapper.getType(), type); assertEquals(wrapper.getType(), type);
//assertEquals(wrapper.getData(), data); //assertEquals(wrapper.getData(), data);
Object generic = BukkitConverters.getWrappedBlockDataConverter().getGeneric(wrapper); Object generic = BukkitConverters.getWrappedBlockDataConverter().getGeneric(wrapper);
WrappedBlockData back = BukkitConverters.getWrappedBlockDataConverter().getSpecific(generic); WrappedBlockData back = BukkitConverters.getWrappedBlockDataConverter().getSpecific(generic);
assertEquals(wrapper.getType(), back.getType()); assertEquals(wrapper.getType(), back.getType());
assertEquals(wrapper.getData(), back.getData()); assertEquals(wrapper.getData(), back.getData());
} }
@Test @Test
public void testDataCreation() { public void testDataCreation() {
IBlockData nmsData = CraftMagicNumbers.getBlock(Material.CYAN_STAINED_GLASS_PANE).n(); IBlockData nmsData = CraftMagicNumbers.getBlock(Material.CYAN_STAINED_GLASS_PANE).n();
GlassPane data = (GlassPane) CraftBlockData.fromData(nmsData); GlassPane data = (GlassPane) CraftBlockData.fromData(nmsData);
data.setFace(BlockFace.EAST, true); data.setFace(BlockFace.EAST, true);
WrappedBlockData wrapper = WrappedBlockData.createData(data); WrappedBlockData wrapper = WrappedBlockData.createData(data);
assertEquals(wrapper.getType(), Material.CYAN_STAINED_GLASS_PANE); assertEquals(wrapper.getType(), Material.CYAN_STAINED_GLASS_PANE);
GlassPane back = new CraftStainedGlassPane((IBlockData) wrapper.getHandle()); GlassPane back = new CraftStainedGlassPane((IBlockData) wrapper.getHandle());
assertEquals(back.hasFace(BlockFace.EAST), data.hasFace(BlockFace.EAST)); assertEquals(back.hasFace(BlockFace.EAST), data.hasFace(BlockFace.EAST));
assertEquals(back.hasFace(BlockFace.SOUTH), data.hasFace(BlockFace.SOUTH)); assertEquals(back.hasFace(BlockFace.SOUTH), data.hasFace(BlockFace.SOUTH));
} }
} }

View File

@ -1,115 +1,116 @@
/** /**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2016 dmulloy2 * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2016 dmulloy2
* <p> * <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later * License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later
* version. * version.
* <p> * <p>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details. * details.
* <p> * <p>
* You should have received a copy of the GNU General Public License along with this program; if not, write to the Free * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
package com.comphenix.protocol.wrappers; package com.comphenix.protocol.wrappers;
import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.UUID;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull; import com.comphenix.protocol.BukkitInitialization;
import static org.junit.jupiter.api.Assertions.assertNotSame; import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry;
import static org.junit.jupiter.api.Assertions.assertTrue; import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer;
import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject;
import com.comphenix.protocol.BukkitInitialization; import net.minecraft.world.entity.projectile.EntityEgg;
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry; import org.bukkit.craftbukkit.v1_19_R2.entity.CraftEgg;
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer; import org.bukkit.craftbukkit.v1_19_R2.entity.CraftEntity;
import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject; import org.junit.jupiter.api.BeforeAll;
import java.util.UUID; import org.junit.jupiter.api.Test;
import net.minecraft.world.entity.projectile.EntityEgg;
import org.bukkit.craftbukkit.v1_19_R2.entity.CraftEgg; import static org.junit.jupiter.api.Assertions.assertEquals;
import org.bukkit.craftbukkit.v1_19_R2.entity.CraftEntity; import static org.junit.jupiter.api.Assertions.assertFalse;
import org.junit.jupiter.api.BeforeAll; import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* @author dmulloy2 /**
*/ * @author dmulloy2
public class WrappedDataWatcherTest { */
public class WrappedDataWatcherTest {
@BeforeAll
public static void prepare() { @BeforeAll
BukkitInitialization.initializeAll(); public static void prepare() {
} BukkitInitialization.initializeAll();
}
@Test
public void testBytes() { @Test
// Create a fake lightning strike and get its watcher public void testBytes() {
EntityEgg nmsEgg = new EntityEgg(null, 0, 0, 0); // Create a fake lightning strike and get its watcher
CraftEntity craftEgg = new CraftEgg(null, nmsEgg); EntityEgg nmsEgg = new EntityEgg(null, 0, 0, 0);
WrappedDataWatcher wrapper = WrappedDataWatcher.getEntityWatcher(craftEgg); CraftEntity craftEgg = new CraftEgg(null, nmsEgg);
WrappedDataWatcher wrapper = WrappedDataWatcher.getEntityWatcher(craftEgg);
WrappedWatchableObject watchable = wrapper.getWatchableObject(0);
WrappedDataWatcherObject object = watchable.getWatcherObject(); WrappedWatchableObject watchable = wrapper.getWatchableObject(0);
WrappedDataWatcherObject object = watchable.getWatcherObject();
// Make sure the serializers work
assertEquals(object.getSerializer(), Registry.get(Byte.class)); // Make sure the serializers work
assertEquals(object.getSerializer(), Registry.get(Byte.class));
// Make sure we can set existing objects
wrapper.setObject(0, (byte) 21); // Make sure we can set existing objects
assertEquals(21, (byte) wrapper.getByte(0)); wrapper.setObject(0, (byte) 21);
} assertEquals(21, (byte) wrapper.getByte(0));
}
@Test
public void testStrings() { @Test
WrappedDataWatcher wrapper = new WrappedDataWatcher(); public void testStrings() {
WrappedDataWatcher wrapper = new WrappedDataWatcher();
// Make sure we can create watcher objects
Serializer serializer = Registry.get(String.class); // Make sure we can create watcher objects
WrappedDataWatcherObject object = new WrappedDataWatcherObject(3, serializer); Serializer serializer = Registry.get(String.class);
wrapper.setObject(object, "Test"); WrappedDataWatcherObject object = new WrappedDataWatcherObject(3, serializer);
wrapper.setObject(object, "Test");
assertEquals(wrapper.getString(3), "Test");
} assertEquals(wrapper.getString(3), "Test");
}
@Test
public void testFloats() { @Test
WrappedDataWatcher wrapper = new WrappedDataWatcher(); public void testFloats() {
WrappedDataWatcher wrapper = new WrappedDataWatcher();
// Make sure we can add new entries
Serializer serializer = Registry.get(Float.class); // Make sure we can add new entries
WrappedDataWatcherObject object = new WrappedDataWatcherObject(10, serializer); Serializer serializer = Registry.get(Float.class);
wrapper.setObject(object, 21.0F); WrappedDataWatcherObject object = new WrappedDataWatcherObject(10, serializer);
wrapper.setObject(object, 21.0F);
assertTrue(wrapper.hasIndex(10));
} assertTrue(wrapper.hasIndex(10));
}
@Test
public void testSerializers() { @Test
Serializer blockPos = Registry.get(net.minecraft.core.BlockPosition.class, false); public void testSerializers() {
Serializer optionalBlockPos = Registry.get(net.minecraft.core.BlockPosition.class, true); Serializer blockPos = Registry.get(net.minecraft.core.BlockPosition.class, false);
assertNotSame(blockPos, optionalBlockPos); Serializer optionalBlockPos = Registry.get(net.minecraft.core.BlockPosition.class, true);
assertNotSame(blockPos, optionalBlockPos);
// assertNull(Registry.get(ItemStack.class, false));
assertNotNull(Registry.get(UUID.class, true)); // assertNull(Registry.get(ItemStack.class, false));
} assertNotNull(Registry.get(UUID.class, true));
}
@Test
public void testHasIndex() { @Test
WrappedDataWatcher watcher = new WrappedDataWatcher(); public void testHasIndex() {
Serializer serializer = Registry.get(Integer.class); WrappedDataWatcher watcher = new WrappedDataWatcher();
Serializer serializer = Registry.get(Integer.class);
assertFalse(watcher.hasIndex(0));
watcher.setObject(0, serializer, 1); assertFalse(watcher.hasIndex(0));
assertTrue(watcher.hasIndex(0)); watcher.setObject(0, serializer, 1);
} assertTrue(watcher.hasIndex(0));
}
@Test
public void testDeepClone() { @Test
WrappedDataWatcher watcher = new WrappedDataWatcher(); public void testDeepClone() {
watcher.setObject(0, Registry.get(Integer.class), 1); WrappedDataWatcher watcher = new WrappedDataWatcher();
watcher.setObject(0, Registry.get(Integer.class), 1);
WrappedDataWatcher cloned = watcher.deepClone();
assertEquals(1, cloned.asMap().size()); WrappedDataWatcher cloned = watcher.deepClone();
assertEquals(1, (Object) cloned.getInteger(0)); assertEquals(1, cloned.asMap().size());
} assertEquals(1, (Object) cloned.getInteger(0));
} }
}

View File

@ -1,62 +1,62 @@
package com.comphenix.protocol.wrappers; package com.comphenix.protocol.wrappers;
import static com.comphenix.protocol.utility.TestUtils.assertItemsEqual; import static com.comphenix.protocol.utility.TestUtils.assertItemsEqual;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import com.comphenix.protocol.BukkitInitialization; import com.comphenix.protocol.BukkitInitialization;
import com.comphenix.protocol.PacketType; import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketContainer;
import org.bukkit.Color; import org.bukkit.Color;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.Particle; import org.bukkit.Particle;
import org.bukkit.Particle.DustOptions; import org.bukkit.Particle.DustOptions;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
public class WrappedParticleTest { public class WrappedParticleTest {
@BeforeAll @BeforeAll
public static void beforeClass() { public static void beforeClass() {
BukkitInitialization.initializeAll(); BukkitInitialization.initializeAll();
} }
@Test @Test
public void testBlockData() { public void testBlockData() {
PacketContainer packet = new PacketContainer(PacketType.Play.Server.WORLD_PARTICLES); PacketContainer packet = new PacketContainer(PacketType.Play.Server.WORLD_PARTICLES);
WrappedParticle before = WrappedParticle.create(Particle.BLOCK_CRACK, WrappedParticle before = WrappedParticle.create(Particle.BLOCK_CRACK,
WrappedBlockData.createData(Material.LAPIS_BLOCK)); WrappedBlockData.createData(Material.LAPIS_BLOCK));
packet.getNewParticles().write(0, before); packet.getNewParticles().write(0, before);
WrappedParticle after = packet.getNewParticles().read(0); WrappedParticle after = packet.getNewParticles().read(0);
assertEquals(before.getParticle(), after.getParticle()); assertEquals(before.getParticle(), after.getParticle());
assertEquals(before.getData(), after.getData()); assertEquals(before.getData(), after.getData());
} }
@Test @Test
public void testItemStacks() { public void testItemStacks() {
PacketContainer packet = new PacketContainer(PacketType.Play.Server.WORLD_PARTICLES); PacketContainer packet = new PacketContainer(PacketType.Play.Server.WORLD_PARTICLES);
WrappedParticle before = WrappedParticle.create(Particle.ITEM_CRACK, new ItemStack(Material.FLINT_AND_STEEL)); WrappedParticle before = WrappedParticle.create(Particle.ITEM_CRACK, new ItemStack(Material.FLINT_AND_STEEL));
packet.getNewParticles().write(0, before); packet.getNewParticles().write(0, before);
WrappedParticle after = packet.getNewParticles().read(0); WrappedParticle after = packet.getNewParticles().read(0);
assertEquals(before.getParticle(), after.getParticle()); assertEquals(before.getParticle(), after.getParticle());
assertItemsEqual((ItemStack) before.getData(), (ItemStack) after.getData()); assertItemsEqual((ItemStack) before.getData(), (ItemStack) after.getData());
} }
@Test @Test
public void testRedstone() { public void testRedstone() {
PacketContainer packet = new PacketContainer(PacketType.Play.Server.WORLD_PARTICLES); PacketContainer packet = new PacketContainer(PacketType.Play.Server.WORLD_PARTICLES);
WrappedParticle before = WrappedParticle.create(Particle.REDSTONE, new DustOptions(Color.BLUE, 1)); WrappedParticle before = WrappedParticle.create(Particle.REDSTONE, new DustOptions(Color.BLUE, 1));
packet.getNewParticles().write(0, before); packet.getNewParticles().write(0, before);
WrappedParticle after = packet.getNewParticles().read(0); WrappedParticle after = packet.getNewParticles().read(0);
assertEquals(before.getParticle(), after.getParticle()); assertEquals(before.getParticle(), after.getParticle());
DustOptions beforeDust = (DustOptions) before.getData(); DustOptions beforeDust = (DustOptions) before.getData();
DustOptions afterDust = (DustOptions) after.getData(); DustOptions afterDust = (DustOptions) after.getData();
assertEquals(beforeDust.getColor(), afterDust.getColor()); assertEquals(beforeDust.getColor(), afterDust.getColor());
assertEquals(beforeDust.getSize(), afterDust.getSize(), 0); assertEquals(beforeDust.getSize(), afterDust.getSize(), 0);
} }
} }

View File

@ -1,87 +1,87 @@
/* /*
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland * Copyright (C) 2012 Kristian S. Stangeland
* *
* This program is free software; you can redistribute it and/or modify it under the terms of the * This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of * GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version. * the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License along with this program; * You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA * 02111-1307 USA
*/ */
package com.comphenix.protocol.wrappers.nbt; package com.comphenix.protocol.wrappers.nbt;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import com.comphenix.protocol.BukkitInitialization; import com.comphenix.protocol.BukkitInitialization;
import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.wrappers.nbt.io.NbtBinarySerializer; import com.comphenix.protocol.wrappers.nbt.io.NbtBinarySerializer;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataInput; import java.io.DataInput;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutput; import java.io.DataOutput;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items; import net.minecraft.world.item.Items;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
public class NbtFactoryTest { public class NbtFactoryTest {
@BeforeAll @BeforeAll
public static void initializeBukkit() throws IllegalAccessException { public static void initializeBukkit() throws IllegalAccessException {
BukkitInitialization.initializeAll(); BukkitInitialization.initializeAll();
} }
@Test @Test
public void testFromStream() { public void testFromStream() {
WrappedCompound compound = WrappedCompound.fromName("tag"); WrappedCompound compound = WrappedCompound.fromName("tag");
compound.put("name", "Test Testerson"); compound.put("name", "Test Testerson");
compound.put("age", 42); compound.put("age", 42);
compound.put(NbtFactory.ofList("nicknames", "a", "b", "c")); compound.put(NbtFactory.ofList("nicknames", "a", "b", "c"));
ByteArrayOutputStream buffer = new ByteArrayOutputStream(); ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutput test = new DataOutputStream(buffer); DataOutput test = new DataOutputStream(buffer);
compound.write(test); compound.write(test);
ByteArrayInputStream source = new ByteArrayInputStream(buffer.toByteArray()); ByteArrayInputStream source = new ByteArrayInputStream(buffer.toByteArray());
DataInput input = new DataInputStream(source); DataInput input = new DataInputStream(source);
NbtCompound cloned = NbtBinarySerializer.DEFAULT.deserializeCompound(input); NbtCompound cloned = NbtBinarySerializer.DEFAULT.deserializeCompound(input);
assertEquals(compound.getString("name"), cloned.getString("name")); assertEquals(compound.getString("name"), cloned.getString("name"));
assertEquals(compound.getInteger("age"), cloned.getInteger("age")); assertEquals(compound.getInteger("age"), cloned.getInteger("age"));
assertEquals(compound.getList("nicknames"), cloned.getList("nicknames")); assertEquals(compound.getList("nicknames"), cloned.getList("nicknames"));
} }
@Test @Test
public void testItemTag() { public void testItemTag() {
ItemStack test = new ItemStack(Items.L); ItemStack test = new ItemStack(Items.L);
org.bukkit.inventory.ItemStack craftTest = MinecraftReflection.getBukkitItemStack(test); org.bukkit.inventory.ItemStack craftTest = MinecraftReflection.getBukkitItemStack(test);
NbtCompound compound = NbtFactory.ofCompound("tag"); NbtCompound compound = NbtFactory.ofCompound("tag");
compound.put("name", "Test Testerson"); compound.put("name", "Test Testerson");
compound.put("age", 42); compound.put("age", 42);
NbtFactory.setItemTag(craftTest, compound); NbtFactory.setItemTag(craftTest, compound);
assertEquals(compound, NbtFactory.fromItemTag(craftTest)); assertEquals(compound, NbtFactory.fromItemTag(craftTest));
} }
@Test @Test
public void testCreateTags() { public void testCreateTags() {
for (NbtType type : NbtType.values()) { for (NbtType type : NbtType.values()) {
if (type != NbtType.TAG_END) { if (type != NbtType.TAG_END) {
NbtFactory.ofWrapper(type, ""); NbtFactory.ofWrapper(type, "");
} }
} }
} }
} }

View File

@ -1,38 +1,38 @@
/** /**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2016 dmulloy2 * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2016 dmulloy2
* <p> * <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later * License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later
* version. * version.
* <p> * <p>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details. * details.
* <p> * <p>
* You should have received a copy of the GNU General Public License along with this program; if not, write to the Free * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
package com.comphenix.protocol.wrappers.nbt; package com.comphenix.protocol.wrappers.nbt;
import com.comphenix.protocol.BukkitInitialization; import com.comphenix.protocol.BukkitInitialization;
import org.bukkit.block.BlockState; import org.bukkit.block.BlockState;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
/** /**
* @author dmulloy2 * @author dmulloy2
*/ */
public class TileEntityTest { public class TileEntityTest {
@BeforeAll @BeforeAll
public static void beforeClass() { public static void beforeClass() {
BukkitInitialization.initializeAll(); BukkitInitialization.initializeAll();
} }
@Test @Test
public void test() { public void test() {
// Ensure the read and write methods exist // Ensure the read and write methods exist
TileEntityAccessor<BlockState> accessor = new TileEntityAccessor<>(); TileEntityAccessor<BlockState> accessor = new TileEntityAccessor<>();
accessor.findMethods(null, null); accessor.findMethods(null, null);
} }
} }