re-normalize line endings

This commit is contained in:
Dan Mulloy 2022-12-07 13:50:01 -05:00
parent 86e586da26
commit 70d5ebc0ae
No known key found for this signature in database
GPG Key ID: BFACD592A5F0DFD6
34 changed files with 6226 additions and 6225 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

@ -1,421 +1,421 @@
/* /*
* 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.utility; package com.comphenix.protocol.utility;
import com.comphenix.protocol.ProtocolLibrary; import com.comphenix.protocol.ProtocolLibrary;
import com.google.common.collect.ComparisonChain; import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Ordering; 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 org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Server; import org.bukkit.Server;
/** /**
* Determine the current Minecraft version. * Determine the current Minecraft version.
* *
* @author Kristian * @author Kristian
*/ */
public final class MinecraftVersion implements Comparable<MinecraftVersion>, Serializable { public final class MinecraftVersion implements Comparable<MinecraftVersion>, Serializable {
/** /**
* Version 1.19 - the wild update * Version 1.19 - the wild update
*/ */
public static final MinecraftVersion WILD_UPDATE = new MinecraftVersion("1.19"); public static final MinecraftVersion WILD_UPDATE = new MinecraftVersion("1.19");
/** /**
* Version 1.18 - caves and cliffs part 2 * Version 1.18 - caves and cliffs part 2
*/ */
public static final MinecraftVersion CAVES_CLIFFS_2 = new MinecraftVersion("1.18"); public static final MinecraftVersion CAVES_CLIFFS_2 = new MinecraftVersion("1.18");
/** /**
* Version 1.17 - caves and cliffs part 1 * Version 1.17 - caves and cliffs part 1
*/ */
public static final MinecraftVersion CAVES_CLIFFS_1 = new MinecraftVersion("1.17"); public static final MinecraftVersion CAVES_CLIFFS_1 = new MinecraftVersion("1.17");
/** /**
* Version 1.16.2 - breaking change to the nether update * Version 1.16.2 - breaking change to the nether update
*/ */
public static final MinecraftVersion NETHER_UPDATE_2 = new MinecraftVersion("1.16.2"); public static final MinecraftVersion NETHER_UPDATE_2 = new MinecraftVersion("1.16.2");
/** /**
* Version 1.16.0 - the nether update * Version 1.16.0 - the nether update
*/ */
public static final MinecraftVersion NETHER_UPDATE = new MinecraftVersion("1.16"); public static final MinecraftVersion NETHER_UPDATE = new MinecraftVersion("1.16");
/** /**
* Version 1.15 - the bee update * Version 1.15 - the bee update
*/ */
public static final MinecraftVersion BEE_UPDATE = new MinecraftVersion("1.15"); public static final MinecraftVersion BEE_UPDATE = new MinecraftVersion("1.15");
/** /**
* Version 1.14 - village and pillage update. * Version 1.14 - village and pillage update.
*/ */
public static final MinecraftVersion VILLAGE_UPDATE = new MinecraftVersion("1.14"); public static final MinecraftVersion VILLAGE_UPDATE = new MinecraftVersion("1.14");
/** /**
* Version 1.13 - update aquatic. * Version 1.13 - update aquatic.
*/ */
public static final MinecraftVersion AQUATIC_UPDATE = new MinecraftVersion("1.13"); public static final MinecraftVersion AQUATIC_UPDATE = new MinecraftVersion("1.13");
/** /**
* Version 1.12 - the world of color update. * Version 1.12 - the world of color update.
*/ */
public static final MinecraftVersion COLOR_UPDATE = new MinecraftVersion("1.12"); public static final MinecraftVersion COLOR_UPDATE = new MinecraftVersion("1.12");
/** /**
* Version 1.11 - the exploration update. * Version 1.11 - the exploration update.
*/ */
public static final MinecraftVersion EXPLORATION_UPDATE = new MinecraftVersion("1.11"); public static final MinecraftVersion EXPLORATION_UPDATE = new MinecraftVersion("1.11");
/** /**
* Version 1.10 - the frostburn update. * Version 1.10 - the frostburn update.
*/ */
public static final MinecraftVersion FROSTBURN_UPDATE = new MinecraftVersion("1.10"); public static final MinecraftVersion FROSTBURN_UPDATE = new MinecraftVersion("1.10");
/** /**
* Version 1.9 - the combat update. * Version 1.9 - the combat update.
*/ */
public static final MinecraftVersion COMBAT_UPDATE = new MinecraftVersion("1.9"); public static final MinecraftVersion COMBAT_UPDATE = new MinecraftVersion("1.9");
/** /**
* Version 1.8 - the "bountiful" update. * Version 1.8 - the "bountiful" update.
*/ */
public static final MinecraftVersion BOUNTIFUL_UPDATE = new MinecraftVersion("1.8"); public static final MinecraftVersion BOUNTIFUL_UPDATE = new MinecraftVersion("1.8");
/** /**
* Version 1.7.8 - the update that changed the skin format (and distribution - R.I.P. player disguise) * Version 1.7.8 - the update that changed the skin format (and distribution - R.I.P. player disguise)
*/ */
public static final MinecraftVersion SKIN_UPDATE = new MinecraftVersion("1.7.8"); public static final MinecraftVersion SKIN_UPDATE = new MinecraftVersion("1.7.8");
/** /**
* Version 1.7.2 - the update that changed the world. * Version 1.7.2 - the update that changed the world.
*/ */
public static final MinecraftVersion WORLD_UPDATE = new MinecraftVersion("1.7.2"); public static final MinecraftVersion WORLD_UPDATE = new MinecraftVersion("1.7.2");
/** /**
* Version 1.6.1 - the horse update. * Version 1.6.1 - the horse update.
*/ */
public static final MinecraftVersion HORSE_UPDATE = new MinecraftVersion("1.6.1"); public static final MinecraftVersion HORSE_UPDATE = new MinecraftVersion("1.6.1");
/** /**
* Version 1.5.0 - the redstone update. * Version 1.5.0 - the redstone update.
*/ */
public static final MinecraftVersion REDSTONE_UPDATE = new MinecraftVersion("1.5.0"); public static final MinecraftVersion REDSTONE_UPDATE = new MinecraftVersion("1.5.0");
/** /**
* Version 1.4.2 - the scary update (Wither Boss). * Version 1.4.2 - the scary update (Wither Boss).
*/ */
public static final MinecraftVersion SCARY_UPDATE = new MinecraftVersion("1.4.2"); public static final MinecraftVersion SCARY_UPDATE = new MinecraftVersion("1.4.2");
/** /**
* The latest release version of minecraft. * The latest release version of minecraft.
*/ */
public static final MinecraftVersion LATEST = WILD_UPDATE; public static final MinecraftVersion LATEST = WILD_UPDATE;
// used when serializing // used when serializing
private static final long serialVersionUID = -8695133558996459770L; private static final long serialVersionUID = -8695133558996459770L;
/** /**
* Regular expression used to parse version strings. * Regular expression used to parse version strings.
*/ */
private static final Pattern VERSION_PATTERN = Pattern.compile(".*\\(.*MC.\\s*([a-zA-z0-9\\-.]+).*"); private static final Pattern VERSION_PATTERN = Pattern.compile(".*\\(.*MC.\\s*([a-zA-z0-9\\-.]+).*");
/** /**
* The current version of minecraft, lazy initialized by MinecraftVersion.currentVersion() * The current version of minecraft, lazy initialized by MinecraftVersion.currentVersion()
*/ */
private static MinecraftVersion currentVersion; private static MinecraftVersion currentVersion;
private final int major; private final int major;
private final int minor; private final int minor;
private final int build; private final int build;
// The development stage // The development stage
private final String development; private final String development;
// Snapshot? // Snapshot?
private final SnapshotVersion snapshot; private final SnapshotVersion snapshot;
private volatile Boolean atCurrentOrAbove; private volatile Boolean atCurrentOrAbove;
/** /**
* Determine the current Minecraft version. * Determine the current Minecraft version.
* *
* @param server - the Bukkit server that will be used to examine the MC version. * @param server - the Bukkit server that will be used to examine the MC version.
*/ */
public MinecraftVersion(Server server) { public MinecraftVersion(Server server) {
this(extractVersion(server.getVersion())); this(extractVersion(server.getVersion()));
} }
/** /**
* Construct a version object from the format major.minor.build, or the snapshot format. * Construct a version object from the format major.minor.build, or the snapshot format.
* *
* @param versionOnly - the version in text form. * @param versionOnly - the version in text form.
*/ */
public MinecraftVersion(String versionOnly) { public MinecraftVersion(String versionOnly) {
this(versionOnly, true); this(versionOnly, true);
} }
/** /**
* Construct a version format from the standard release version or the snapshot verison. * Construct a version format from the standard release version or the snapshot verison.
* *
* @param versionOnly - the version. * @param versionOnly - the version.
* @param parseSnapshot - TRUE to parse the snapshot, FALSE otherwise. * @param parseSnapshot - TRUE to parse the snapshot, FALSE otherwise.
*/ */
private MinecraftVersion(String versionOnly, boolean parseSnapshot) { private MinecraftVersion(String versionOnly, boolean parseSnapshot) {
String[] section = versionOnly.split("-"); String[] section = versionOnly.split("-");
SnapshotVersion snapshot = null; SnapshotVersion snapshot = null;
int[] numbers = new int[3]; int[] numbers = new int[3];
try { try {
numbers = this.parseVersion(section[0]); numbers = this.parseVersion(section[0]);
} catch (NumberFormatException cause) { } catch (NumberFormatException cause) {
// Skip snapshot parsing // Skip snapshot parsing
if (!parseSnapshot) { if (!parseSnapshot) {
throw cause; throw cause;
} }
try { try {
// Determine if the snapshot is newer than the current release version // Determine if the snapshot is newer than the current release version
snapshot = new SnapshotVersion(section[0]); snapshot = new SnapshotVersion(section[0]);
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.US); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
MinecraftVersion latest = new MinecraftVersion(ProtocolLibrary.MAXIMUM_MINECRAFT_VERSION, false); MinecraftVersion latest = new MinecraftVersion(ProtocolLibrary.MAXIMUM_MINECRAFT_VERSION, false);
boolean newer = snapshot.getSnapshotDate().compareTo( boolean newer = snapshot.getSnapshotDate().compareTo(
format.parse(ProtocolLibrary.MINECRAFT_LAST_RELEASE_DATE)) > 0; format.parse(ProtocolLibrary.MINECRAFT_LAST_RELEASE_DATE)) > 0;
numbers[0] = latest.getMajor(); numbers[0] = latest.getMajor();
numbers[1] = latest.getMinor() + (newer ? 1 : -1); numbers[1] = latest.getMinor() + (newer ? 1 : -1);
} catch (Exception e) { } catch (Exception e) {
throw new IllegalStateException("Cannot parse " + section[0], e); throw new IllegalStateException("Cannot parse " + section[0], e);
} }
} }
this.major = numbers[0]; this.major = numbers[0];
this.minor = numbers[1]; this.minor = numbers[1];
this.build = numbers[2]; this.build = numbers[2];
this.development = section.length > 1 ? section[1] : (snapshot != null ? "snapshot" : null); this.development = section.length > 1 ? section[1] : (snapshot != null ? "snapshot" : null);
this.snapshot = snapshot; this.snapshot = snapshot;
} }
/** /**
* Construct a version object directly. * Construct a version object directly.
* *
* @param major - major version number. * @param major - major version number.
* @param minor - minor version number. * @param minor - minor version number.
* @param build - build version number. * @param build - build version number.
*/ */
public MinecraftVersion(int major, int minor, int build) { public MinecraftVersion(int major, int minor, int build) {
this(major, minor, build, null); this(major, minor, build, null);
} }
/** /**
* Construct a version object directly. * Construct a version object directly.
* *
* @param major - major version number. * @param major - major version number.
* @param minor - minor version number. * @param minor - minor version number.
* @param build - build version number. * @param build - build version number.
* @param development - development stage. * @param development - development stage.
*/ */
public MinecraftVersion(int major, int minor, int build, String development) { public MinecraftVersion(int major, int minor, int build, String development) {
this.major = major; this.major = major;
this.minor = minor; this.minor = minor;
this.build = build; this.build = build;
this.development = development; this.development = development;
this.snapshot = null; this.snapshot = null;
} }
/** /**
* Extract the Minecraft version from CraftBukkit itself. * Extract the Minecraft version from CraftBukkit itself.
* *
* @param text - the server version in text form. * @param text - the server version in text form.
* @return The underlying MC version. * @return The underlying MC version.
* @throws IllegalStateException If we could not parse the version string. * @throws IllegalStateException If we could not parse the version string.
*/ */
public static String extractVersion(String text) { public static String extractVersion(String text) {
Matcher version = VERSION_PATTERN.matcher(text); Matcher version = VERSION_PATTERN.matcher(text);
if (version.matches() && version.group(1) != null) { if (version.matches() && version.group(1) != null) {
return version.group(1); return version.group(1);
} else { } else {
throw new IllegalStateException("Cannot parse version String '" + text + "'"); throw new IllegalStateException("Cannot parse version String '" + text + "'");
} }
} }
/** /**
* Parse the given server version into a Minecraft version. * Parse the given server version into a Minecraft version.
* *
* @param serverVersion - the server version. * @param serverVersion - the server version.
* @return The resulting Minecraft version. * @return The resulting Minecraft version.
*/ */
public static MinecraftVersion fromServerVersion(String serverVersion) { public static MinecraftVersion fromServerVersion(String serverVersion) {
return new MinecraftVersion(extractVersion(serverVersion)); return new MinecraftVersion(extractVersion(serverVersion));
} }
public static MinecraftVersion getCurrentVersion() { public static MinecraftVersion getCurrentVersion() {
if (currentVersion == null) { if (currentVersion == null) {
currentVersion = fromServerVersion(Bukkit.getVersion()); currentVersion = fromServerVersion(Bukkit.getVersion());
} }
return currentVersion; return currentVersion;
} }
public static void setCurrentVersion(MinecraftVersion version) { public static void setCurrentVersion(MinecraftVersion version) {
currentVersion = version; currentVersion = version;
} }
public static boolean atOrAbove(MinecraftVersion version) { public static boolean atOrAbove(MinecraftVersion version) {
return getCurrentVersion().isAtLeast(version); return getCurrentVersion().isAtLeast(version);
} }
private int[] parseVersion(String version) { private int[] parseVersion(String version) {
String[] elements = version.split("\\."); String[] elements = version.split("\\.");
int[] numbers = new int[3]; int[] numbers = new int[3];
// Make sure it's even a valid version // Make sure it's even a valid version
if (elements.length < 1) { if (elements.length < 1) {
throw new IllegalStateException("Corrupt MC version: " + version); throw new IllegalStateException("Corrupt MC version: " + version);
} }
// The String 1 or 1.2 is interpreted as 1.0.0 and 1.2.0 respectively. // The String 1 or 1.2 is interpreted as 1.0.0 and 1.2.0 respectively.
for (int i = 0; i < Math.min(numbers.length, elements.length); i++) { for (int i = 0; i < Math.min(numbers.length, elements.length); i++) {
numbers[i] = Integer.parseInt(elements[i].trim()); numbers[i] = Integer.parseInt(elements[i].trim());
} }
return numbers; return numbers;
} }
/** /**
* Major version number * Major version number
* *
* @return Current major version number. * @return Current major version number.
*/ */
public int getMajor() { public int getMajor() {
return this.major; return this.major;
} }
/** /**
* Minor version number * Minor version number
* *
* @return Current minor version number. * @return Current minor version number.
*/ */
public int getMinor() { public int getMinor() {
return this.minor; return this.minor;
} }
/** /**
* Build version number * Build version number
* *
* @return Current build version number. * @return Current build version number.
*/ */
public int getBuild() { public int getBuild() {
return this.build; return this.build;
} }
/** /**
* Retrieve the development stage. * Retrieve the development stage.
* *
* @return Development stage, or NULL if this is a release. * @return Development stage, or NULL if this is a release.
*/ */
public String getDevelopmentStage() { public String getDevelopmentStage() {
return this.development; return this.development;
} }
/** /**
* Retrieve the snapshot version, or NULL if this is a release. * Retrieve the snapshot version, or NULL if this is a release.
* *
* @return The snapshot version. * @return The snapshot version.
*/ */
public SnapshotVersion getSnapshot() { public SnapshotVersion getSnapshot() {
return this.snapshot; return this.snapshot;
} }
/** /**
* Determine if this version is a snapshot. * Determine if this version is a snapshot.
* *
* @return The snapshot version. * @return The snapshot version.
*/ */
public boolean isSnapshot() { public boolean isSnapshot() {
return this.snapshot != null; return this.snapshot != null;
} }
/** /**
* Checks if this version is at or above the current version the server is running. * Checks if this version is at or above the current version the server is running.
* *
* @return true if this version is equal or newer than the server version, false otherwise. * @return true if this version is equal or newer than the server version, false otherwise.
*/ */
public boolean atOrAbove() { public boolean atOrAbove() {
if (this.atCurrentOrAbove == null) { if (this.atCurrentOrAbove == null) {
this.atCurrentOrAbove = MinecraftVersion.atOrAbove(this); this.atCurrentOrAbove = MinecraftVersion.atOrAbove(this);
} }
return this.atCurrentOrAbove; return this.atCurrentOrAbove;
} }
/** /**
* Retrieve the version String (major.minor.build) only. * Retrieve the version String (major.minor.build) only.
* *
* @return A normal version string. * @return A normal version string.
*/ */
public String getVersion() { public String getVersion() {
if (this.getDevelopmentStage() == null) { if (this.getDevelopmentStage() == null) {
return String.format("%s.%s.%s", this.getMajor(), this.getMinor(), this.getBuild()); return String.format("%s.%s.%s", this.getMajor(), this.getMinor(), this.getBuild());
} else { } else {
return String.format("%s.%s.%s-%s%s", this.getMajor(), this.getMinor(), this.getBuild(), return String.format("%s.%s.%s-%s%s", this.getMajor(), this.getMinor(), this.getBuild(),
this.getDevelopmentStage(), this.isSnapshot() ? this.snapshot : ""); this.getDevelopmentStage(), this.isSnapshot() ? this.snapshot : "");
} }
} }
@Override @Override
public int compareTo(MinecraftVersion o) { public int compareTo(MinecraftVersion o) {
if (o == null) { if (o == null) {
return 1; return 1;
} }
return ComparisonChain.start() return ComparisonChain.start()
.compare(this.getMajor(), o.getMajor()) .compare(this.getMajor(), o.getMajor())
.compare(this.getMinor(), o.getMinor()) .compare(this.getMinor(), o.getMinor())
.compare(this.getBuild(), o.getBuild()) .compare(this.getBuild(), o.getBuild())
.compare(this.getDevelopmentStage(), o.getDevelopmentStage(), Ordering.natural().nullsLast()) .compare(this.getDevelopmentStage(), o.getDevelopmentStage(), Ordering.natural().nullsLast())
.compare(this.getSnapshot(), o.getSnapshot(), Ordering.natural().nullsFirst()) .compare(this.getSnapshot(), o.getSnapshot(), Ordering.natural().nullsFirst())
.result(); .result();
} }
public boolean isAtLeast(MinecraftVersion other) { public boolean isAtLeast(MinecraftVersion other) {
if (other == null) { if (other == null) {
return false; return false;
} }
return this.compareTo(other) >= 0; return this.compareTo(other) >= 0;
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj == null) { if (obj == null) {
return false; return false;
} }
if (obj == this) { if (obj == this) {
return true; return true;
} }
if (obj instanceof MinecraftVersion) { if (obj instanceof MinecraftVersion) {
MinecraftVersion other = (MinecraftVersion) obj; MinecraftVersion other = (MinecraftVersion) obj;
return this.getMajor() == other.getMajor() && return this.getMajor() == other.getMajor() &&
this.getMinor() == other.getMinor() && this.getMinor() == other.getMinor() &&
this.getBuild() == other.getBuild() && this.getBuild() == other.getBuild() &&
Objects.equals(this.getDevelopmentStage(), other.getDevelopmentStage()); Objects.equals(this.getDevelopmentStage(), other.getDevelopmentStage());
} }
return false; return false;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(this.getMajor(), this.getMinor(), this.getBuild()); return Objects.hash(this.getMajor(), this.getMinor(), this.getBuild());
} }
@Override @Override
public String toString() { public String toString() {
// Convert to a String that we can parse back again // Convert to a String that we can parse back again
return String.format("(MC: %s)", this.getVersion()); return String.format("(MC: %s)", this.getVersion());
} }
} }

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,174 +1,174 @@
/** /**
* 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 java.lang.reflect.Array; import java.lang.reflect.Array;
import java.util.Optional; import java.util.Optional;
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;
/** /**
* Utility class for converters * Utility class for converters
* @author dmulloy2 * @author dmulloy2
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class Converters { public class Converters {
/** /**
* Returns a converter that ignores null elements, so that the underlying converter doesn't have to worry about them. * Returns a converter that ignores null elements, so that the underlying converter doesn't have to worry about them.
* @param converter Underlying converter * @param converter Underlying converter
* @param <T> Element type * @param <T> Element type
* @return An ignore null converter * @return An ignore null converter
*/ */
public static <T> EquivalentConverter<T> ignoreNull(final EquivalentConverter<T> converter) { public static <T> EquivalentConverter<T> ignoreNull(final EquivalentConverter<T> converter) {
return new EquivalentConverter<T>() { return new EquivalentConverter<T>() {
@Override @Override
public T getSpecific(Object generic) { public T getSpecific(Object generic) {
return generic != null ? converter.getSpecific(generic) : null; return generic != null ? converter.getSpecific(generic) : null;
} }
@Override @Override
public Object getGeneric(T specific) { public Object getGeneric(T specific) {
return specific != null ? converter.getGeneric(specific) : null; return specific != null ? converter.getGeneric(specific) : null;
} }
@Override @Override
public Class<T> getSpecificType() { public Class<T> getSpecificType() {
return converter.getSpecificType(); return converter.getSpecificType();
} }
}; };
} }
/** /**
* Returns a converter that passes generic and specific values through without converting. * Returns a converter that passes generic and specific values through without converting.
* @param clazz Element class * @param clazz Element class
* @param <T> Element type * @param <T> Element type
* @return A passthrough converter * @return A passthrough converter
*/ */
public static <T> EquivalentConverter<T> passthrough(final Class<T> clazz) { public static <T> EquivalentConverter<T> passthrough(final Class<T> clazz) {
return ignoreNull(new EquivalentConverter<T>() { return ignoreNull(new EquivalentConverter<T>() {
@Override @Override
public T getSpecific(Object generic) { public T getSpecific(Object generic) {
return (T) generic; return (T) generic;
} }
@Override @Override
public Object getGeneric(T specific) { public Object getGeneric(T specific) {
return specific; return specific;
} }
@Override @Override
public Class<T> getSpecificType() { public Class<T> getSpecificType() {
return clazz; return clazz;
} }
}); });
} }
/** /**
* Creates a simple converter for wrappers with {@code getHandle()} and {@code fromHandle(...)} methods. With Java 8, * Creates a simple converter for wrappers with {@code getHandle()} and {@code fromHandle(...)} methods. With Java 8,
* converters can be reduced to a single line (see {@link BukkitConverters#getWrappedGameProfileConverter()}). * converters can be reduced to a single line (see {@link BukkitConverters#getWrappedGameProfileConverter()}).
* @param toHandle Function from wrapper to handle (i.e. {@code getHandle()}) * @param toHandle Function from wrapper to handle (i.e. {@code getHandle()})
* @param fromHandle Function from handle to wrapper (i.e. {@code fromHandle(Object)}) * @param fromHandle Function from handle to wrapper (i.e. {@code fromHandle(Object)})
* @param <T> Wrapper type * @param <T> Wrapper type
* @return A handle converter * @return A handle converter
*/ */
public static <T> EquivalentConverter<T> handle(final Function<T, Object> toHandle, public static <T> EquivalentConverter<T> handle(final Function<T, Object> toHandle,
final Function<Object, T> fromHandle, final Class<T> specificType) { final Function<Object, T> fromHandle, final Class<T> specificType) {
return new EquivalentConverter<T>() { return new EquivalentConverter<T>() {
@Override @Override
public T getSpecific(Object generic) { public T getSpecific(Object generic) {
return fromHandle.apply(generic); return fromHandle.apply(generic);
} }
@Override @Override
public Object getGeneric(T specific) { public Object getGeneric(T specific) {
return toHandle.apply(specific); return toHandle.apply(specific);
} }
@Override @Override
public Class<T> getSpecificType() { public Class<T> getSpecificType() {
return specificType; return specificType;
} }
}; };
} }
/** /**
* Creates a generic array converter. Converts a NMS object array to and from a wrapper array by converting * Creates a generic array converter. Converts a NMS object array to and from a wrapper array by converting
* each element individually. * each element individually.
* *
* @param nmsClass NMS class * @param nmsClass NMS class
* @param converter Underlying converter * @param converter Underlying converter
* @param <T> Generic type * @param <T> Generic type
* @return An array converter * @return An array converter
*/ */
public static <T> EquivalentConverter<T[]> array(final Class<?> nmsClass, final EquivalentConverter<T> converter) { public static <T> EquivalentConverter<T[]> array(final Class<?> nmsClass, final EquivalentConverter<T> converter) {
return new EquivalentConverter<T[]>() { return new EquivalentConverter<T[]>() {
@Override @Override
public T[] getSpecific(Object generic) { public T[] getSpecific(Object generic) {
Object[] array = (Object[]) generic; Object[] array = (Object[]) generic;
Class<T[]> clazz = getSpecificType(); Class<T[]> clazz = getSpecificType();
T[] result = clazz.cast(Array.newInstance(clazz.getComponentType(), array.length)); T[] result = clazz.cast(Array.newInstance(clazz.getComponentType(), array.length));
// Unwrap every item // Unwrap every item
for (int i = 0; i < result.length; i++) { for (int i = 0; i < result.length; i++) {
result[i] = converter.getSpecific(array[i]); result[i] = converter.getSpecific(array[i]);
} }
return result; return result;
} }
@Override @Override
public Object getGeneric(T[] specific) { public Object getGeneric(T[] specific) {
Object[] result = (Object[]) Array.newInstance(nmsClass, specific.length); Object[] result = (Object[]) Array.newInstance(nmsClass, specific.length);
// Wrap every item // Wrap every item
for (int i = 0; i < result.length; i++) { for (int i = 0; i < result.length; i++) {
result[i] = converter.getGeneric(specific[i]); result[i] = converter.getGeneric(specific[i]);
} }
return result; return result;
} }
@Override @Override
public Class<T[]> getSpecificType() { public Class<T[]> getSpecificType() {
return (Class<T[]>) MinecraftReflection.getArrayClass(converter.getSpecificType()); return (Class<T[]>) MinecraftReflection.getArrayClass(converter.getSpecificType());
} }
}; };
} }
public static <T> EquivalentConverter<Optional<T>> optional(final EquivalentConverter<T> converter) { public static <T> EquivalentConverter<Optional<T>> optional(final EquivalentConverter<T> converter) {
return new EquivalentConverter<Optional<T>>() { return new EquivalentConverter<Optional<T>>() {
@Override @Override
public Object getGeneric(Optional<T> specific) { public Object getGeneric(Optional<T> specific) {
return specific.map(converter::getGeneric); return specific.map(converter::getGeneric);
} }
@Override @Override
public Optional<T> getSpecific(Object generic) { public Optional<T> getSpecific(Object generic) {
Optional<Object> optional = (Optional<Object>) generic; Optional<Object> optional = (Optional<Object>) generic;
return optional.map(converter::getSpecific); return optional.map(converter::getSpecific);
} }
@Override @Override
public Class<Optional<T>> getSpecificType() { public Class<Optional<T>> getSpecificType() {
return (Class<Optional<T>>) Optional.empty().getClass(); return (Class<Optional<T>>) Optional.empty().getClass();
} }
}; };
} }
} }

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,169 +1,169 @@
package com.comphenix.protocol.wrappers; package com.comphenix.protocol.wrappers;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.FuzzyReflection;
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.MethodAccessor; import com.comphenix.protocol.reflect.accessors.MethodAccessor;
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract; import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion; import com.comphenix.protocol.utility.MinecraftVersion;
import com.mojang.math.Vector3fa; import com.mojang.math.Vector3fa;
import org.bukkit.Color; import org.bukkit.Color;
import org.bukkit.Particle; import org.bukkit.Particle;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
/** /**
* Represents an immutable wrapped ParticleParam in 1.13 * Represents an immutable wrapped ParticleParam in 1.13
*/ */
public class WrappedParticle<T> { public class WrappedParticle<T> {
private static MethodAccessor toBukkit; private static MethodAccessor toBukkit;
private static MethodAccessor toNMS; private static MethodAccessor toNMS;
private static MethodAccessor toCraftData; private static MethodAccessor toCraftData;
private static void ensureMethods() { private static void ensureMethods() {
if (toBukkit != null && toNMS != null) { if (toBukkit != null && toNMS != null) {
return; return;
} }
FuzzyReflection fuzzy = FuzzyReflection.fromClass(MinecraftReflection.getCraftBukkitClass("CraftParticle")); FuzzyReflection fuzzy = FuzzyReflection.fromClass(MinecraftReflection.getCraftBukkitClass("CraftParticle"));
FuzzyMethodContract contract = FuzzyMethodContract FuzzyMethodContract contract = FuzzyMethodContract
.newBuilder() .newBuilder()
.requireModifier(Modifier.STATIC) .requireModifier(Modifier.STATIC)
.returnTypeExact(Particle.class) .returnTypeExact(Particle.class)
.parameterExactType(MinecraftReflection.getParticleParam()) .parameterExactType(MinecraftReflection.getParticleParam())
.build(); .build();
toBukkit = Accessors.getMethodAccessor(fuzzy.getMethod(contract)); toBukkit = Accessors.getMethodAccessor(fuzzy.getMethod(contract));
contract = FuzzyMethodContract contract = FuzzyMethodContract
.newBuilder() .newBuilder()
.requireModifier(Modifier.STATIC) .requireModifier(Modifier.STATIC)
.returnTypeExact(MinecraftReflection.getParticleParam()) .returnTypeExact(MinecraftReflection.getParticleParam())
.parameterCount(2) .parameterCount(2)
.build(); .build();
toNMS = Accessors.getMethodAccessor(fuzzy.getMethod(contract)); toNMS = Accessors.getMethodAccessor(fuzzy.getMethod(contract));
Class<?> cbData = MinecraftReflection.getCraftBukkitClass("block.data.CraftBlockData"); Class<?> cbData = MinecraftReflection.getCraftBukkitClass("block.data.CraftBlockData");
fuzzy = FuzzyReflection.fromClass(cbData); fuzzy = FuzzyReflection.fromClass(cbData);
contract = FuzzyMethodContract contract = FuzzyMethodContract
.newBuilder() .newBuilder()
.requireModifier(Modifier.STATIC) .requireModifier(Modifier.STATIC)
.returnTypeExact(cbData) .returnTypeExact(cbData)
.parameterExactArray(MinecraftReflection.getIBlockDataClass()) .parameterExactArray(MinecraftReflection.getIBlockDataClass())
.build(); .build();
toCraftData = Accessors.getMethodAccessor(fuzzy.getMethod(contract)); toCraftData = Accessors.getMethodAccessor(fuzzy.getMethod(contract));
} }
private final Particle particle; private final Particle particle;
private final T data; private final T data;
private final Object handle; private final Object handle;
private WrappedParticle(Object handle, Particle particle, T data) { private WrappedParticle(Object handle, Particle particle, T data) {
this.handle = handle; this.handle = handle;
this.particle = particle; this.particle = particle;
this.data = data; this.data = data;
} }
/** /**
* @return This particle's Bukkit type * @return This particle's Bukkit type
*/ */
public Particle getParticle() { public Particle getParticle() {
return particle; return particle;
} }
/** /**
* Gets this Particle's Bukkit/ProtocolLib data. The type of this data depends on the * Gets this Particle's Bukkit/ProtocolLib data. The type of this data depends on the
* {@link #getParticle() Particle type}. For Block particles it will be {@link WrappedBlockData}, * {@link #getParticle() Particle type}. For Block particles it will be {@link WrappedBlockData},
* for Item crack particles, it will be an {@link ItemStack}, and for redstone particles it will * for Item crack particles, it will be an {@link ItemStack}, and for redstone particles it will
* be {@link Particle.DustOptions} * be {@link Particle.DustOptions}
* *
* @return The particle data * @return The particle data
*/ */
public T getData() { public T getData() {
return data; return data;
} }
/** /**
* @return NMS handle * @return NMS handle
*/ */
public Object getHandle() { public Object getHandle() {
return handle; return handle;
} }
public static WrappedParticle fromHandle(Object handle) { public static WrappedParticle fromHandle(Object handle) {
ensureMethods(); ensureMethods();
Particle bukkit = (Particle) toBukkit.invoke(null, handle); Particle bukkit = (Particle) toBukkit.invoke(null, handle);
Object data = null; Object data = null;
switch (bukkit) { switch (bukkit) {
case BLOCK_CRACK: case BLOCK_CRACK:
case BLOCK_DUST: case BLOCK_DUST:
case FALLING_DUST: case FALLING_DUST:
data = getBlockData(handle); data = getBlockData(handle);
break; break;
case ITEM_CRACK: case ITEM_CRACK:
data = getItem(handle); data = getItem(handle);
break; break;
case REDSTONE: case REDSTONE:
data = getRedstone(handle); data = getRedstone(handle);
break; break;
default: default:
break; break;
} }
return new WrappedParticle<>(handle, bukkit, data); return new WrappedParticle<>(handle, bukkit, data);
} }
private static WrappedBlockData getBlockData(Object handle) { private static WrappedBlockData getBlockData(Object handle) {
return new StructureModifier<>(handle.getClass()) return new StructureModifier<>(handle.getClass())
.withTarget(handle) .withTarget(handle)
.withType(MinecraftReflection.getIBlockDataClass(), BukkitConverters.getWrappedBlockDataConverter()) .withType(MinecraftReflection.getIBlockDataClass(), BukkitConverters.getWrappedBlockDataConverter())
.read(0); .read(0);
} }
private static Object getItem(Object handle) { private static Object getItem(Object handle) {
return new StructureModifier<>(handle.getClass()) return new StructureModifier<>(handle.getClass())
.withTarget(handle) .withTarget(handle)
.withType(MinecraftReflection.getItemStackClass(), BukkitConverters.getItemStackConverter()) .withType(MinecraftReflection.getItemStackClass(), BukkitConverters.getItemStackConverter())
.read(0); .read(0);
} }
private static Object getRedstone(Object handle) { private static Object getRedstone(Object handle) {
int r, g, b; int r, g, b;
float alpha; float alpha;
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) { if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
StructureModifier<Object> modifier = new StructureModifier<>(handle.getClass()).withTarget(handle); StructureModifier<Object> modifier = new StructureModifier<>(handle.getClass()).withTarget(handle);
Vector3fa rgb = (Vector3fa) modifier.withType(Vector3fa.class).read(0); Vector3fa rgb = (Vector3fa) modifier.withType(Vector3fa.class).read(0);
r = (int) (rgb.a() * 255); r = (int) (rgb.a() * 255);
g = (int) (rgb.b() * 255); g = (int) (rgb.b() * 255);
b = (int) (rgb.c() * 255); b = (int) (rgb.c() * 255);
alpha = (float) modifier.withType(float.class).read(0); alpha = (float) modifier.withType(float.class).read(0);
} else { } else {
StructureModifier<Float> modifier = new StructureModifier<>(handle.getClass()).withTarget(handle).withType(float.class); StructureModifier<Float> modifier = new StructureModifier<>(handle.getClass()).withTarget(handle).withType(float.class);
r = (int) (modifier.read(0) * 255); r = (int) (modifier.read(0) * 255);
g = (int) (modifier.read(1) * 255); g = (int) (modifier.read(1) * 255);
b = (int) (modifier.read(2) * 255); b = (int) (modifier.read(2) * 255);
alpha = modifier.read(3); alpha = modifier.read(3);
} }
return new Particle.DustOptions(Color.fromRGB(r, g, b), alpha); return new Particle.DustOptions(Color.fromRGB(r, g, b), alpha);
} }
public static <T> WrappedParticle<T> create(Particle particle, T data) { public static <T> WrappedParticle<T> create(Particle particle, T data) {
ensureMethods(); ensureMethods();
Object bukkitData = data; Object bukkitData = data;
if (data instanceof WrappedBlockData) { if (data instanceof WrappedBlockData) {
WrappedBlockData blockData = (WrappedBlockData) data; WrappedBlockData blockData = (WrappedBlockData) data;
bukkitData = toCraftData.invoke(null, blockData.getHandle()); bukkitData = toCraftData.invoke(null, blockData.getHandle());
} }
Object handle = toNMS.invoke(null, particle, bukkitData); Object handle = toNMS.invoke(null, particle, bukkitData);
return new WrappedParticle<>(handle, particle, data); return new WrappedParticle<>(handle, particle, data);
} }
} }

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,126 @@
package com.comphenix.protocol; package com.comphenix.protocol;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
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 java.util.Collections;
import java.util.List; import java.util.List;
import net.minecraft.SharedConstants; import net.minecraft.SharedConstants;
import net.minecraft.core.IRegistry; import net.minecraft.core.IRegistry;
import net.minecraft.server.DispenserRegistry; import net.minecraft.server.DispenserRegistry;
import net.minecraft.server.level.WorldServer; import net.minecraft.server.level.WorldServer;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.craftbukkit.v1_19_R1.CraftServer; import org.bukkit.craftbukkit.v1_19_R1.CraftServer;
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld; import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemFactory; import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemFactory;
import org.bukkit.craftbukkit.v1_19_R1.util.Versioning; import org.bukkit.craftbukkit.v1_19_R1.util.Versioning;
import org.spigotmc.SpigotWorldConfig; import org.spigotmc.SpigotWorldConfig;
/** /**
* 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 static final BukkitInitialization instance = new BukkitInitialization();
private boolean initialized; private boolean initialized;
private boolean packaged; private boolean packaged;
private BukkitInitialization() { private BukkitInitialization() {
System.out.println("Created new BukkitInitialization on " + Thread.currentThread().getName()); 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() { public static synchronized void initializeAll() {
instance.initialize(); 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() { private void initialize() {
if (!this.initialized) { if (!this.initialized) {
// Denote that we're done // Denote that we're done
this.initialized = true; this.initialized = true;
try { try {
LogManager.getLogger(); LogManager.getLogger();
} catch (Throwable ex) { } catch (Throwable ex) {
// Happens only on my Jenkins, but if it errors here it works when it matters // Happens only on my Jenkins, but if it errors here it works when it matters
ex.printStackTrace(); ex.printStackTrace();
} }
instance.setPackage(); instance.setPackage();
SharedConstants.a(); SharedConstants.a();
DispenserRegistry.a(); DispenserRegistry.a();
try { try {
IRegistry.class.getName(); IRegistry.class.getName();
} catch (Throwable ex) { } catch (Throwable ex) {
ex.printStackTrace(); ex.printStackTrace();
} }
String releaseTarget = SharedConstants.b().getReleaseTarget(); String releaseTarget = SharedConstants.b().getReleaseTarget();
String serverVersion = CraftServer.class.getPackage().getImplementationVersion(); String serverVersion = CraftServer.class.getPackage().getImplementationVersion();
// Mock the server object // Mock the server object
Server mockedServer = mock(Server.class); Server mockedServer = mock(Server.class);
when(mockedServer.getLogger()).thenReturn(java.util.logging.Logger.getLogger("Minecraft")); when(mockedServer.getLogger()).thenReturn(java.util.logging.Logger.getLogger("Minecraft"));
when(mockedServer.getName()).thenReturn("Mock Server"); when(mockedServer.getName()).thenReturn("Mock Server");
when(mockedServer.getVersion()).thenReturn(serverVersion + " (MC: " + releaseTarget + ")"); when(mockedServer.getVersion()).thenReturn(serverVersion + " (MC: " + releaseTarget + ")");
when(mockedServer.getBukkitVersion()).thenReturn(Versioning.getBukkitVersion()); when(mockedServer.getBukkitVersion()).thenReturn(Versioning.getBukkitVersion());
when(mockedServer.getItemFactory()).thenReturn(CraftItemFactory.instance()); when(mockedServer.getItemFactory()).thenReturn(CraftItemFactory.instance());
when(mockedServer.isPrimaryThread()).thenReturn(true); 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 { try {
FieldAccessor spigotConfig = Accessors.getFieldAccessor(nmsWorld.getClass().getField("spigotConfig")); FieldAccessor spigotConfig = Accessors.getFieldAccessor(nmsWorld.getClass().getField("spigotConfig"));
spigotConfig.set(nmsWorld, mockWorldConfig); spigotConfig.set(nmsWorld, mockWorldConfig);
} catch (ReflectiveOperationException ex) { } catch (ReflectiveOperationException ex) {
throw new RuntimeException(ex); throw new RuntimeException(ex);
} }
CraftWorld world = mock(CraftWorld.class); CraftWorld world = mock(CraftWorld.class);
when(world.getHandle()).thenReturn(nmsWorld); when(world.getHandle()).thenReturn(nmsWorld);
List<World> worlds = Collections.singletonList(world); List<World> worlds = Collections.singletonList(world);
when(mockedServer.getWorlds()).thenReturn(worlds); when(mockedServer.getWorlds()).thenReturn(worlds);
// Inject this fake server // Inject this fake server
Bukkit.setServer(mockedServer); Bukkit.setServer(mockedServer);
} }
} }
/** /**
* Ensure that package names are correctly set up. * Ensure that package names are correctly set up.
*/ */
private void setPackage() { private void setPackage() {
if (!this.packaged) { if (!this.packaged) {
this.packaged = true; this.packaged = true;
try { try {
LogManager.getLogger(); LogManager.getLogger();
} catch (Throwable ex) { } catch (Throwable ex) {
// Happens only on my Jenkins, but if it errors here it works when it matters // Happens only on my Jenkins, but if it errors here it works when it matters
ex.printStackTrace(); 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,59 @@
package com.comphenix.protocol.injector; package com.comphenix.protocol.injector;
import static com.comphenix.protocol.utility.TestUtils.setFinalField; import static com.comphenix.protocol.utility.TestUtils.setFinalField;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import com.comphenix.protocol.BukkitInitialization; import com.comphenix.protocol.BukkitInitialization;
import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract; import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import net.minecraft.server.level.ChunkProviderServer; import net.minecraft.server.level.ChunkProviderServer;
import net.minecraft.server.level.PlayerChunkMap; import net.minecraft.server.level.PlayerChunkMap;
import net.minecraft.server.level.PlayerChunkMap.EntityTracker; import net.minecraft.server.level.PlayerChunkMap.EntityTracker;
import net.minecraft.server.level.WorldServer; import net.minecraft.server.level.WorldServer;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld; import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftEntity; import org.bukkit.craftbukkit.v1_19_R1.entity.CraftEntity;
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 EntityUtilitiesTest { public class EntityUtilitiesTest {
@BeforeAll @BeforeAll
public static void beforeClass() { public static void beforeClass() {
BukkitInitialization.initializeAll(); BukkitInitialization.initializeAll();
} }
@Test @Test
public void testReflection() { public void testReflection() {
CraftWorld bukkit = mock(CraftWorld.class); CraftWorld bukkit = mock(CraftWorld.class);
WorldServer world = mock(WorldServer.class); WorldServer world = mock(WorldServer.class);
when(bukkit.getHandle()).thenReturn(world); when(bukkit.getHandle()).thenReturn(world);
ChunkProviderServer provider = mock(ChunkProviderServer.class); ChunkProviderServer provider = mock(ChunkProviderServer.class);
when(world.k()).thenReturn(provider); when(world.k()).thenReturn(provider);
PlayerChunkMap chunkMap = mock(PlayerChunkMap.class); PlayerChunkMap chunkMap = mock(PlayerChunkMap.class);
Field chunkMapField = FuzzyReflection.fromClass(ChunkProviderServer.class, true) Field chunkMapField = FuzzyReflection.fromClass(ChunkProviderServer.class, true)
.getField(FuzzyFieldContract.newBuilder().typeExact(PlayerChunkMap.class).build()); .getField(FuzzyFieldContract.newBuilder().typeExact(PlayerChunkMap.class).build());
setFinalField(provider, chunkMapField, chunkMap); setFinalField(provider, chunkMapField, chunkMap);
CraftEntity bukkitEntity = mock(CraftEntity.class); CraftEntity bukkitEntity = mock(CraftEntity.class);
Entity fakeEntity = mock(Entity.class); Entity fakeEntity = mock(Entity.class);
when(fakeEntity.getBukkitEntity()).thenReturn(bukkitEntity); when(fakeEntity.getBukkitEntity()).thenReturn(bukkitEntity);
EntityTracker tracker = mock(EntityTracker.class); EntityTracker tracker = mock(EntityTracker.class);
Field trackerField = FuzzyReflection.fromClass(EntityTracker.class, true) Field trackerField = FuzzyReflection.fromClass(EntityTracker.class, true)
.getField(FuzzyFieldContract.newBuilder().typeExact(Entity.class).build()); .getField(FuzzyFieldContract.newBuilder().typeExact(Entity.class).build());
setFinalField(tracker, trackerField, fakeEntity); setFinalField(tracker, trackerField, fakeEntity);
Int2ObjectMap<EntityTracker> trackerMap = new Int2ObjectOpenHashMap<>(); Int2ObjectMap<EntityTracker> trackerMap = new Int2ObjectOpenHashMap<>();
trackerMap.put(1, tracker); trackerMap.put(1, tracker);
Field trackedEntitiesField = FuzzyReflection.fromClass(PlayerChunkMap.class, true) Field trackedEntitiesField = FuzzyReflection.fromClass(PlayerChunkMap.class, true)
.getField(FuzzyFieldContract.newBuilder().typeExact(Int2ObjectMap.class).build()); .getField(FuzzyFieldContract.newBuilder().typeExact(Int2ObjectMap.class).build());
setFinalField(chunkMap, trackedEntitiesField, trackerMap); 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,159 @@
package com.comphenix.protocol.utility; package com.comphenix.protocol.utility;
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 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.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import com.comphenix.protocol.BukkitInitialization; import com.comphenix.protocol.BukkitInitialization;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import net.minecraft.nbt.NBTCompressedStreamTools; import net.minecraft.nbt.NBTCompressedStreamTools;
import net.minecraft.network.chat.IChatBaseComponent; import net.minecraft.network.chat.IChatBaseComponent;
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes; import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes;
import net.minecraft.network.protocol.status.ServerPing; import net.minecraft.network.protocol.status.ServerPing;
import net.minecraft.network.syncher.DataWatcher; import net.minecraft.network.syncher.DataWatcher;
import net.minecraft.server.network.PlayerConnection; import net.minecraft.server.network.PlayerConnection;
import net.minecraft.util.MinecraftEncryption; import net.minecraft.util.MinecraftEncryption;
import net.minecraft.world.level.ChunkCoordIntPair; import net.minecraft.world.level.ChunkCoordIntPair;
import net.minecraft.world.level.block.state.IBlockData; import net.minecraft.world.level.block.state.IBlockData;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
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;
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 @Test
public void testGameProfile() { public void testGameProfile() {
assertEquals(GameProfile.class, MinecraftReflection.getGameProfileClass()); assertEquals(GameProfile.class, MinecraftReflection.getGameProfileClass());
} }
@Test @Test
public void testEnumEntityUseAction() { public void testEnumEntityUseAction() {
// this class is package-private in PacketPlayInUseEntity, so we can only check if no exception is thrown during retrieval // this class is package-private in PacketPlayInUseEntity, so we can only check if no exception is thrown during retrieval
MinecraftReflection.getEnumEntityUseActionClass(); MinecraftReflection.getEnumEntityUseActionClass();
} }
// Mocking objects // Mocking objects
private interface FakeEntity { 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,57 @@
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.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
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 java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
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 EnumWrappersTest { public class EnumWrappersTest {
private static final Set<String> KNOWN_INVALID = Sets.newHashSet( private static final Set<String> KNOWN_INVALID = Sets.newHashSet(
"Particle", "WorldBorderAction", "CombatEventType", "TitleAction", "ChatType" "Particle", "WorldBorderAction", "CombatEventType", "TitleAction", "ChatType"
); );
@BeforeAll @BeforeAll
public static void initializeBukkit() { public static void initializeBukkit() {
BukkitInitialization.initializeAll(); BukkitInitialization.initializeAll();
EnumWrappers.getPlayerInfoActionClass(); // just to initialize the classes and converters EnumWrappers.getPlayerInfoActionClass(); // just to initialize the classes and converters
} }
@Test @Test
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void validateAllEnumFieldsAreWrapped() { public void validateAllEnumFieldsAreWrapped() {
Map<Class<?>, EquivalentConverter<?>> nativeEnums = EnumWrappers.getFromNativeMap(); Map<Class<?>, EquivalentConverter<?>> nativeEnums = EnumWrappers.getFromNativeMap();
for (Entry<Class<?>, EquivalentConverter<?>> entry : nativeEnums.entrySet()) { for (Entry<Class<?>, EquivalentConverter<?>> entry : nativeEnums.entrySet()) {
for (Object nativeConstant : entry.getKey().getEnumConstants()) { for (Object nativeConstant : entry.getKey().getEnumConstants()) {
try { try {
// yay, generics // yay, generics
EquivalentConverter<Object> converter = (EquivalentConverter<Object>) entry.getValue(); EquivalentConverter<Object> converter = (EquivalentConverter<Object>) entry.getValue();
// try to convert the native constant to a wrapper and back // try to convert the native constant to a wrapper and back
Object wrappedValue = converter.getSpecific(nativeConstant); Object wrappedValue = converter.getSpecific(nativeConstant);
assertNotNull(wrappedValue); assertNotNull(wrappedValue);
Object unwrappedValue = converter.getGeneric(wrappedValue); Object unwrappedValue = converter.getGeneric(wrappedValue);
assertNotNull(unwrappedValue); assertNotNull(unwrappedValue);
assertEquals(nativeConstant, unwrappedValue); assertEquals(nativeConstant, unwrappedValue);
} catch (Exception exception) { } catch (Exception exception) {
fail(exception); fail(exception);
} }
} }
} }
} }
@Test @Test
public void testValidity() { public void testValidity() {
assertEquals(EnumWrappers.INVALID, KNOWN_INVALID); 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 static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotSame; import static org.junit.jupiter.api.Assertions.assertNotSame;
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.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 java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import net.minecraft.core.IRegistry; import net.minecraft.core.IRegistry;
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes.AttributeSnapshot; import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes.AttributeSnapshot;
import net.minecraft.resources.MinecraftKey; import net.minecraft.resources.MinecraftKey;
import net.minecraft.world.entity.ai.attributes.AttributeBase; import net.minecraft.world.entity.ai.attributes.AttributeBase;
import net.minecraft.world.entity.ai.attributes.AttributeModifier; import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
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 = IRegistry.ak.a(MinecraftKey.a(attribute.getAttributeKey())); AttributeBase base = IRegistry.ak.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 static org.junit.jupiter.api.Assertions.assertEquals;
import com.comphenix.protocol.BukkitInitialization; import com.comphenix.protocol.BukkitInitialization;
import net.minecraft.world.level.block.state.IBlockData; import net.minecraft.world.level.block.state.IBlockData;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.block.data.type.GlassPane; import org.bukkit.block.data.type.GlassPane;
import org.bukkit.craftbukkit.v1_19_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_19_R1.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_19_R1.block.impl.CraftStainedGlassPane; import org.bukkit.craftbukkit.v1_19_R1.block.impl.CraftStainedGlassPane;
import org.bukkit.craftbukkit.v1_19_R1.util.CraftMagicNumbers; import org.bukkit.craftbukkit.v1_19_R1.util.CraftMagicNumbers;
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 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).m(); IBlockData nmsData = CraftMagicNumbers.getBlock(Material.CYAN_STAINED_GLASS_PANE).m();
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,115 @@
/** /**
* 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 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.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNotSame; import static org.junit.jupiter.api.Assertions.assertNotSame;
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.wrappers.WrappedDataWatcher.Registry; import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry;
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer; import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer;
import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject; import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject;
import java.util.UUID; import java.util.UUID;
import net.minecraft.world.entity.projectile.EntityEgg; import net.minecraft.world.entity.projectile.EntityEgg;
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftEgg; import org.bukkit.craftbukkit.v1_19_R1.entity.CraftEgg;
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftEntity; import org.bukkit.craftbukkit.v1_19_R1.entity.CraftEntity;
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 WrappedDataWatcherTest { public class WrappedDataWatcherTest {
@BeforeAll @BeforeAll
public static void prepare() { public static void prepare() {
BukkitInitialization.initializeAll(); BukkitInitialization.initializeAll();
} }
@Test @Test
public void testBytes() { public void testBytes() {
// Create a fake lightning strike and get its watcher // Create a fake lightning strike and get its watcher
EntityEgg nmsEgg = new EntityEgg(null, 0, 0, 0); EntityEgg nmsEgg = new EntityEgg(null, 0, 0, 0);
CraftEntity craftEgg = new CraftEgg(null, nmsEgg); CraftEntity craftEgg = new CraftEgg(null, nmsEgg);
WrappedDataWatcher wrapper = WrappedDataWatcher.getEntityWatcher(craftEgg); WrappedDataWatcher wrapper = WrappedDataWatcher.getEntityWatcher(craftEgg);
WrappedWatchableObject watchable = wrapper.getWatchableObject(0); WrappedWatchableObject watchable = wrapper.getWatchableObject(0);
WrappedDataWatcherObject object = watchable.getWatcherObject(); WrappedDataWatcherObject object = watchable.getWatcherObject();
// Make sure the serializers work // Make sure the serializers work
assertEquals(object.getSerializer(), Registry.get(Byte.class)); assertEquals(object.getSerializer(), Registry.get(Byte.class));
// Make sure we can set existing objects // Make sure we can set existing objects
wrapper.setObject(0, (byte) 21); wrapper.setObject(0, (byte) 21);
assertEquals(21, (byte) wrapper.getByte(0)); assertEquals(21, (byte) wrapper.getByte(0));
} }
@Test @Test
public void testStrings() { public void testStrings() {
WrappedDataWatcher wrapper = new WrappedDataWatcher(); WrappedDataWatcher wrapper = new WrappedDataWatcher();
// Make sure we can create watcher objects // Make sure we can create watcher objects
Serializer serializer = Registry.get(String.class); Serializer serializer = Registry.get(String.class);
WrappedDataWatcherObject object = new WrappedDataWatcherObject(3, serializer); WrappedDataWatcherObject object = new WrappedDataWatcherObject(3, serializer);
wrapper.setObject(object, "Test"); wrapper.setObject(object, "Test");
assertEquals(wrapper.getString(3), "Test"); assertEquals(wrapper.getString(3), "Test");
} }
@Test @Test
public void testFloats() { public void testFloats() {
WrappedDataWatcher wrapper = new WrappedDataWatcher(); WrappedDataWatcher wrapper = new WrappedDataWatcher();
// Make sure we can add new entries // Make sure we can add new entries
Serializer serializer = Registry.get(Float.class); Serializer serializer = Registry.get(Float.class);
WrappedDataWatcherObject object = new WrappedDataWatcherObject(10, serializer); WrappedDataWatcherObject object = new WrappedDataWatcherObject(10, serializer);
wrapper.setObject(object, 21.0F); wrapper.setObject(object, 21.0F);
assertTrue(wrapper.hasIndex(10)); assertTrue(wrapper.hasIndex(10));
} }
@Test @Test
public void testSerializers() { public void testSerializers() {
Serializer blockPos = Registry.get(net.minecraft.core.BlockPosition.class, false); Serializer blockPos = Registry.get(net.minecraft.core.BlockPosition.class, false);
Serializer optionalBlockPos = Registry.get(net.minecraft.core.BlockPosition.class, true); Serializer optionalBlockPos = Registry.get(net.minecraft.core.BlockPosition.class, true);
assertNotSame(blockPos, optionalBlockPos); assertNotSame(blockPos, optionalBlockPos);
// assertNull(Registry.get(ItemStack.class, false)); // assertNull(Registry.get(ItemStack.class, false));
assertNotNull(Registry.get(UUID.class, true)); assertNotNull(Registry.get(UUID.class, true));
} }
@Test @Test
public void testHasIndex() { public void testHasIndex() {
WrappedDataWatcher watcher = new WrappedDataWatcher(); WrappedDataWatcher watcher = new WrappedDataWatcher();
Serializer serializer = Registry.get(Integer.class); Serializer serializer = Registry.get(Integer.class);
assertFalse(watcher.hasIndex(0)); assertFalse(watcher.hasIndex(0));
watcher.setObject(0, serializer, 1); watcher.setObject(0, serializer, 1);
assertTrue(watcher.hasIndex(0)); assertTrue(watcher.hasIndex(0));
} }
@Test @Test
public void testDeepClone() { public void testDeepClone() {
WrappedDataWatcher watcher = new WrappedDataWatcher(); WrappedDataWatcher watcher = new WrappedDataWatcher();
watcher.setObject(0, Registry.get(Integer.class), 1); watcher.setObject(0, Registry.get(Integer.class), 1);
WrappedDataWatcher cloned = watcher.deepClone(); WrappedDataWatcher cloned = watcher.deepClone();
assertEquals(1, cloned.asMap().size()); assertEquals(1, cloned.asMap().size());
assertEquals(1, (Object) cloned.getInteger(0)); 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);
} }
} }