mirror of
https://github.com/dmulloy2/ProtocolLib.git
synced 2024-11-27 05:05:24 +01:00
re-normalize line endings
This commit is contained in:
parent
86e586da26
commit
70d5ebc0ae
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
||||
* text=auto eol=lf
|
334
Readme.md
334
Readme.md
@ -1,167 +1,167 @@
|
||||
# ProtocolLib
|
||||
|
||||
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
|
||||
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
|
||||
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,
|
||||
with unpredictable outcomes. More than often this causes plugins to crash, but it may also
|
||||
lead to more subtle bugs.
|
||||
|
||||
Currently maintained by dmulloy2 on behalf of [Spigot](https://www.spigotmc.org/).
|
||||
|
||||
### Resources
|
||||
|
||||
* [Resource Page](https://www.spigotmc.org/resources/protocollib.1997/)
|
||||
* [Dev Builds](https://ci.dmulloy2.net/job/ProtocolLib)
|
||||
* [JavaDoc](https://ci.dmulloy2.net/job/ProtocolLib/javadoc/index.html)
|
||||
|
||||
### Compilation
|
||||
|
||||
ProtocolLib is built with [Maven](https://maven.apache.org/). If you have it installed, just run
|
||||
`mvn package` in the root project folder.
|
||||
|
||||
### A new API
|
||||
|
||||
__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,
|
||||
the API also hides all the gritty, obfuscated classes with a simple index based read/write system.
|
||||
You no longer have to reference CraftBukkit!
|
||||
|
||||
### Using 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:
|
||||
|
||||
````yml
|
||||
depend: [ ProtocolLib ]
|
||||
````
|
||||
|
||||
You can also add ProtocolLib as a Maven dependency:
|
||||
|
||||
````xml
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>dmulloy2-repo</id>
|
||||
<url>https://repo.dmulloy2.net/repository/public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.comphenix.protocol</groupId>
|
||||
<artifactId>ProtocolLib</artifactId>
|
||||
<version>4.7.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
````
|
||||
|
||||
Or use the maven dependency with gradle:
|
||||
|
||||
```gradle
|
||||
repositories {
|
||||
maven { url "https://repo.dmulloy2.net/repository/public/" }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
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.
|
||||
|
||||
````java
|
||||
private ProtocolManager protocolManager;
|
||||
|
||||
public void onLoad() {
|
||||
protocolManager = ProtocolLibrary.getProtocolManager();
|
||||
}
|
||||
````
|
||||
|
||||
To listen for packets sent by the server to a client, add a server-side listener:
|
||||
|
||||
````java
|
||||
// Disable all sound effects
|
||||
protocolManager.addPacketListener(new PacketAdapter(
|
||||
this,
|
||||
ListenerPriority.NORMAL,
|
||||
PacketType.Play.Server.NAMED_SOUND_EFFECT
|
||||
) {
|
||||
@Override
|
||||
public void onPacketSending(PacketEvent event) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
});
|
||||
````
|
||||
|
||||
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:
|
||||
|
||||
````java
|
||||
// Censor
|
||||
protocolManager.addPacketListener(new PacketAdapter(
|
||||
this,
|
||||
ListenerPriority.NORMAL,
|
||||
PacketType.Play.Client.CHAT
|
||||
) {
|
||||
@Override
|
||||
public void onPacketReceiving(PacketEvent event) {
|
||||
PacketContainer packet = event.getPacket();
|
||||
String message = packet.getStrings().read(0);
|
||||
|
||||
if (message.contains("shit") || message.contains("damn")) {
|
||||
event.setCancelled(true);
|
||||
event.getPlayer().sendMessage("Bad manners!");
|
||||
}
|
||||
}
|
||||
});
|
||||
````
|
||||
|
||||
### Sending packets
|
||||
|
||||
Normally, you might have to do something ugly like the following:
|
||||
|
||||
````java
|
||||
PacketPlayOutExplosion fakeExplosion = new PacketPlayOutExplosion(
|
||||
player.getLocation().getX(),
|
||||
player.getLocation().getY(),
|
||||
player.getLocation().getZ(),
|
||||
3.0F,
|
||||
new ArrayList<>(),
|
||||
new Vec3D(
|
||||
player.getVelocity().getX() + 1,
|
||||
player.getVelocity().getY() + 1,
|
||||
player.getVelocity().getZ() + 1
|
||||
)
|
||||
);
|
||||
|
||||
((CraftPlayer) player).getHandle().b.a(fakeExplosion);
|
||||
````
|
||||
|
||||
But with ProtocolLib, you can turn that into something more manageable:
|
||||
|
||||
````java
|
||||
PacketContainer fakeExplosion = new PacketContainer(PacketType.Play.Server.EXPLOSION);
|
||||
fakeExplosion.getDoubles()
|
||||
.write(0, player.getLocation().getX())
|
||||
.write(1, player.getLocation().getY())
|
||||
.write(2, player.getLocation().getZ());
|
||||
fakeExplosion.getFloat().write(0, 3.0F);
|
||||
fakeExplosion.getBlockPositionCollectionModifier().write(0, new ArrayList<>());
|
||||
fakeExplosion.getVectors().write(0, player.getVelocity().add(new Vector(1, 1, 1)));
|
||||
|
||||
protocolManager.sendServerPacket(player, fakeExplosion);
|
||||
````
|
||||
|
||||
### Compatibility
|
||||
|
||||
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
|
||||
and new features.
|
||||
|
||||
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
|
||||
types. It's remarkably consistent across different versions.
|
||||
# ProtocolLib
|
||||
|
||||
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
|
||||
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
|
||||
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,
|
||||
with unpredictable outcomes. More than often this causes plugins to crash, but it may also
|
||||
lead to more subtle bugs.
|
||||
|
||||
Currently maintained by dmulloy2 on behalf of [Spigot](https://www.spigotmc.org/).
|
||||
|
||||
### Resources
|
||||
|
||||
* [Resource Page](https://www.spigotmc.org/resources/protocollib.1997/)
|
||||
* [Dev Builds](https://ci.dmulloy2.net/job/ProtocolLib)
|
||||
* [JavaDoc](https://ci.dmulloy2.net/job/ProtocolLib/javadoc/index.html)
|
||||
|
||||
### Compilation
|
||||
|
||||
ProtocolLib is built with [Maven](https://maven.apache.org/). If you have it installed, just run
|
||||
`mvn package` in the root project folder.
|
||||
|
||||
### A new API
|
||||
|
||||
__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,
|
||||
the API also hides all the gritty, obfuscated classes with a simple index based read/write system.
|
||||
You no longer have to reference CraftBukkit!
|
||||
|
||||
### Using 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:
|
||||
|
||||
````yml
|
||||
depend: [ ProtocolLib ]
|
||||
````
|
||||
|
||||
You can also add ProtocolLib as a Maven dependency:
|
||||
|
||||
````xml
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>dmulloy2-repo</id>
|
||||
<url>https://repo.dmulloy2.net/repository/public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.comphenix.protocol</groupId>
|
||||
<artifactId>ProtocolLib</artifactId>
|
||||
<version>4.7.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
````
|
||||
|
||||
Or use the maven dependency with gradle:
|
||||
|
||||
```gradle
|
||||
repositories {
|
||||
maven { url "https://repo.dmulloy2.net/repository/public/" }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
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.
|
||||
|
||||
````java
|
||||
private ProtocolManager protocolManager;
|
||||
|
||||
public void onLoad() {
|
||||
protocolManager = ProtocolLibrary.getProtocolManager();
|
||||
}
|
||||
````
|
||||
|
||||
To listen for packets sent by the server to a client, add a server-side listener:
|
||||
|
||||
````java
|
||||
// Disable all sound effects
|
||||
protocolManager.addPacketListener(new PacketAdapter(
|
||||
this,
|
||||
ListenerPriority.NORMAL,
|
||||
PacketType.Play.Server.NAMED_SOUND_EFFECT
|
||||
) {
|
||||
@Override
|
||||
public void onPacketSending(PacketEvent event) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
});
|
||||
````
|
||||
|
||||
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:
|
||||
|
||||
````java
|
||||
// Censor
|
||||
protocolManager.addPacketListener(new PacketAdapter(
|
||||
this,
|
||||
ListenerPriority.NORMAL,
|
||||
PacketType.Play.Client.CHAT
|
||||
) {
|
||||
@Override
|
||||
public void onPacketReceiving(PacketEvent event) {
|
||||
PacketContainer packet = event.getPacket();
|
||||
String message = packet.getStrings().read(0);
|
||||
|
||||
if (message.contains("shit") || message.contains("damn")) {
|
||||
event.setCancelled(true);
|
||||
event.getPlayer().sendMessage("Bad manners!");
|
||||
}
|
||||
}
|
||||
});
|
||||
````
|
||||
|
||||
### Sending packets
|
||||
|
||||
Normally, you might have to do something ugly like the following:
|
||||
|
||||
````java
|
||||
PacketPlayOutExplosion fakeExplosion = new PacketPlayOutExplosion(
|
||||
player.getLocation().getX(),
|
||||
player.getLocation().getY(),
|
||||
player.getLocation().getZ(),
|
||||
3.0F,
|
||||
new ArrayList<>(),
|
||||
new Vec3D(
|
||||
player.getVelocity().getX() + 1,
|
||||
player.getVelocity().getY() + 1,
|
||||
player.getVelocity().getZ() + 1
|
||||
)
|
||||
);
|
||||
|
||||
((CraftPlayer) player).getHandle().b.a(fakeExplosion);
|
||||
````
|
||||
|
||||
But with ProtocolLib, you can turn that into something more manageable:
|
||||
|
||||
````java
|
||||
PacketContainer fakeExplosion = new PacketContainer(PacketType.Play.Server.EXPLOSION);
|
||||
fakeExplosion.getDoubles()
|
||||
.write(0, player.getLocation().getX())
|
||||
.write(1, player.getLocation().getY())
|
||||
.write(2, player.getLocation().getZ());
|
||||
fakeExplosion.getFloat().write(0, 3.0F);
|
||||
fakeExplosion.getBlockPositionCollectionModifier().write(0, new ArrayList<>());
|
||||
fakeExplosion.getVectors().write(0, player.getVelocity().add(new Vector(1, 1, 1)));
|
||||
|
||||
protocolManager.sendServerPacket(player, fakeExplosion);
|
||||
````
|
||||
|
||||
### Compatibility
|
||||
|
||||
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
|
||||
and new features.
|
||||
|
||||
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
|
||||
types. It's remarkably consistent across different versions.
|
||||
|
@ -1,284 +1,284 @@
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2017 Dan Mulloy
|
||||
*
|
||||
* 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 version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
package com.comphenix.protocol;
|
||||
|
||||
import com.comphenix.protocol.PacketType.Protocol;
|
||||
import com.comphenix.protocol.PacketType.Sender;
|
||||
import com.comphenix.protocol.events.ListeningWhitelist;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
import com.comphenix.protocol.events.PacketListener;
|
||||
import com.comphenix.protocol.injector.netty.WirePacket;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.MessageFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.FileHandler;
|
||||
import java.util.logging.Formatter;
|
||||
import java.util.logging.Handler;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Logs packets to a given stream
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class PacketLogging implements CommandExecutor, PacketListener {
|
||||
public static final String NAME = "packetlog";
|
||||
|
||||
private static MethodAccessor HEX_DUMP;
|
||||
|
||||
private List<PacketType> sendingTypes = new ArrayList<>();
|
||||
private List<PacketType> receivingTypes = new ArrayList<>();
|
||||
|
||||
private ListeningWhitelist sendingWhitelist;
|
||||
private ListeningWhitelist receivingWhitelist;
|
||||
|
||||
private Logger fileLogger;
|
||||
private LogLocation location = LogLocation.FILE;
|
||||
|
||||
private final ProtocolManager manager;
|
||||
private final Plugin plugin;
|
||||
|
||||
PacketLogging(Plugin plugin, ProtocolManager manager) {
|
||||
this.plugin = plugin;
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
PacketType type = null;
|
||||
|
||||
try {
|
||||
if (args.length > 2) {
|
||||
Protocol protocol;
|
||||
|
||||
try {
|
||||
protocol = Protocol.valueOf(args[0].toUpperCase());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
sender.sendMessage(ChatColor.RED + "Unknown protocol " + args[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
Sender pSender;
|
||||
|
||||
try {
|
||||
pSender = Sender.valueOf(args[1].toUpperCase());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
sender.sendMessage(ChatColor.RED + "Unknown sender: " + args[1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
try { // Try IDs first
|
||||
int id = Integer.parseInt(args[2]);
|
||||
type = PacketType.findCurrent(protocol, pSender, id);
|
||||
} catch (NumberFormatException ex) { // Check packet names
|
||||
String name = args[2];
|
||||
for (PacketType packet : PacketType.values()) {
|
||||
if (packet.getProtocol() == protocol && packet.getSender() == pSender) {
|
||||
if (packet.name().equalsIgnoreCase(name)) {
|
||||
type = packet;
|
||||
break;
|
||||
}
|
||||
for (String className : packet.getClassNames()) {
|
||||
if (className.equalsIgnoreCase(name)) {
|
||||
type = packet;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IllegalArgumentException ex) { // RIP
|
||||
type = null;
|
||||
}
|
||||
|
||||
if (type == null) {
|
||||
sender.sendMessage(ChatColor.RED + "Unknown packet: " + args[2]);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length > 3) {
|
||||
if (args[3].equalsIgnoreCase("console")) {
|
||||
this.location = LogLocation.CONSOLE;
|
||||
} else {
|
||||
this.location = LogLocation.FILE;
|
||||
}
|
||||
}
|
||||
|
||||
if (pSender == Sender.CLIENT) {
|
||||
if (receivingTypes.contains(type)) {
|
||||
receivingTypes.remove(type);
|
||||
} else {
|
||||
receivingTypes.add(type);
|
||||
}
|
||||
} else {
|
||||
if (sendingTypes.contains(type)) {
|
||||
sendingTypes.remove(type);
|
||||
} else {
|
||||
sendingTypes.add(type);
|
||||
}
|
||||
}
|
||||
|
||||
startLogging();
|
||||
sender.sendMessage(ChatColor.GREEN + "Now logging " + type.getPacketClass().getSimpleName());
|
||||
return true;
|
||||
}
|
||||
|
||||
sender.sendMessage(ChatColor.RED + "Invalid syntax: /packetlog <protocol> <sender> <packet> [location]");
|
||||
return true;
|
||||
} catch (Throwable ex) {
|
||||
sender.sendMessage(ChatColor.RED + "Failed to parse command: " + ex.toString());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void startLogging() {
|
||||
manager.removePacketListener(this);
|
||||
|
||||
if (sendingTypes.isEmpty() && receivingTypes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.sendingWhitelist = ListeningWhitelist.newBuilder().types(sendingTypes).build();
|
||||
this.receivingWhitelist = ListeningWhitelist.newBuilder().types(receivingTypes).build();
|
||||
|
||||
// Setup the file logger if it hasn't been already
|
||||
if (location == LogLocation.FILE && fileLogger == null) {
|
||||
fileLogger = Logger.getLogger("ProtocolLib-FileLogging");
|
||||
|
||||
for (Handler handler : fileLogger.getHandlers())
|
||||
fileLogger.removeHandler(handler);
|
||||
fileLogger.setUseParentHandlers(false);
|
||||
|
||||
try {
|
||||
File logFile = new File(plugin.getDataFolder(), "log.log");
|
||||
FileHandler handler = new FileHandler(logFile.getAbsolutePath(), true);
|
||||
handler.setFormatter(new LogFormatter());
|
||||
fileLogger.addHandler(handler);
|
||||
} catch (IOException ex) {
|
||||
plugin.getLogger().log(Level.SEVERE, "Failed to obtain log file:", ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
manager.addPacketListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketSending(PacketEvent event) {
|
||||
log(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceiving(PacketEvent event) {
|
||||
log(event);
|
||||
}
|
||||
|
||||
// Here's where the magic happens
|
||||
|
||||
private static String hexDump(byte[] bytes) throws IOException {
|
||||
try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
|
||||
if (HEX_DUMP == null) {
|
||||
Class<?> hexDumpClass = MinecraftReflection.getLibraryClass("org.apache.commons.io.HexDump");
|
||||
HEX_DUMP = Accessors.getMethodAccessor(FuzzyReflection.fromClass(hexDumpClass)
|
||||
.getMethodByParameters("dump", byte[].class, long.class, OutputStream.class, int.class));
|
||||
}
|
||||
|
||||
HEX_DUMP.invoke(null, bytes, 0, output, 0);
|
||||
return new String(output.toByteArray(), StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
|
||||
private void log(PacketEvent event) {
|
||||
try {
|
||||
byte[] bytes = WirePacket.bytesFromPacket(event.getPacket());
|
||||
String hexDump = hexDump(bytes);
|
||||
|
||||
if (location == LogLocation.FILE) {
|
||||
fileLogger.log(Level.INFO, event.getPacketType() + ":");
|
||||
fileLogger.log(Level.INFO, hexDump);
|
||||
fileLogger.log(Level.INFO, "");
|
||||
} else {
|
||||
System.out.println(event.getPacketType() + ":");
|
||||
System.out.println(hexDump);
|
||||
System.out.println();
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
plugin.getLogger().log(Level.WARNING, "Failed to log packet " + event.getPacketType() + ":", ex);
|
||||
plugin.getLogger().log(Level.WARNING, "Clearing packet logger...");
|
||||
|
||||
sendingTypes.clear();
|
||||
receivingTypes.clear();
|
||||
startLogging();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListeningWhitelist getSendingWhitelist() {
|
||||
return sendingWhitelist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListeningWhitelist getReceivingWhitelist() {
|
||||
return receivingWhitelist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Plugin getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
private enum LogLocation {
|
||||
CONSOLE, FILE
|
||||
}
|
||||
|
||||
private static class LogFormatter extends Formatter {
|
||||
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 FORMAT = "[{0}] {1}";
|
||||
|
||||
@Override
|
||||
public String format(LogRecord record) {
|
||||
String string = formatMessage(record);
|
||||
if (string.isEmpty()) {
|
||||
return LINE_SEPARATOR;
|
||||
}
|
||||
|
||||
StringBuilder message = new StringBuilder();
|
||||
message.append(MessageFormat.format(FORMAT, DATE.format(record.getMillis()), string));
|
||||
message.append(LINE_SEPARATOR);
|
||||
return message.toString();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2017 Dan Mulloy
|
||||
*
|
||||
* 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 version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
package com.comphenix.protocol;
|
||||
|
||||
import com.comphenix.protocol.PacketType.Protocol;
|
||||
import com.comphenix.protocol.PacketType.Sender;
|
||||
import com.comphenix.protocol.events.ListeningWhitelist;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
import com.comphenix.protocol.events.PacketListener;
|
||||
import com.comphenix.protocol.injector.netty.WirePacket;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.MessageFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.FileHandler;
|
||||
import java.util.logging.Formatter;
|
||||
import java.util.logging.Handler;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Logs packets to a given stream
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class PacketLogging implements CommandExecutor, PacketListener {
|
||||
public static final String NAME = "packetlog";
|
||||
|
||||
private static MethodAccessor HEX_DUMP;
|
||||
|
||||
private List<PacketType> sendingTypes = new ArrayList<>();
|
||||
private List<PacketType> receivingTypes = new ArrayList<>();
|
||||
|
||||
private ListeningWhitelist sendingWhitelist;
|
||||
private ListeningWhitelist receivingWhitelist;
|
||||
|
||||
private Logger fileLogger;
|
||||
private LogLocation location = LogLocation.FILE;
|
||||
|
||||
private final ProtocolManager manager;
|
||||
private final Plugin plugin;
|
||||
|
||||
PacketLogging(Plugin plugin, ProtocolManager manager) {
|
||||
this.plugin = plugin;
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
PacketType type = null;
|
||||
|
||||
try {
|
||||
if (args.length > 2) {
|
||||
Protocol protocol;
|
||||
|
||||
try {
|
||||
protocol = Protocol.valueOf(args[0].toUpperCase());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
sender.sendMessage(ChatColor.RED + "Unknown protocol " + args[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
Sender pSender;
|
||||
|
||||
try {
|
||||
pSender = Sender.valueOf(args[1].toUpperCase());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
sender.sendMessage(ChatColor.RED + "Unknown sender: " + args[1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
try { // Try IDs first
|
||||
int id = Integer.parseInt(args[2]);
|
||||
type = PacketType.findCurrent(protocol, pSender, id);
|
||||
} catch (NumberFormatException ex) { // Check packet names
|
||||
String name = args[2];
|
||||
for (PacketType packet : PacketType.values()) {
|
||||
if (packet.getProtocol() == protocol && packet.getSender() == pSender) {
|
||||
if (packet.name().equalsIgnoreCase(name)) {
|
||||
type = packet;
|
||||
break;
|
||||
}
|
||||
for (String className : packet.getClassNames()) {
|
||||
if (className.equalsIgnoreCase(name)) {
|
||||
type = packet;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IllegalArgumentException ex) { // RIP
|
||||
type = null;
|
||||
}
|
||||
|
||||
if (type == null) {
|
||||
sender.sendMessage(ChatColor.RED + "Unknown packet: " + args[2]);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length > 3) {
|
||||
if (args[3].equalsIgnoreCase("console")) {
|
||||
this.location = LogLocation.CONSOLE;
|
||||
} else {
|
||||
this.location = LogLocation.FILE;
|
||||
}
|
||||
}
|
||||
|
||||
if (pSender == Sender.CLIENT) {
|
||||
if (receivingTypes.contains(type)) {
|
||||
receivingTypes.remove(type);
|
||||
} else {
|
||||
receivingTypes.add(type);
|
||||
}
|
||||
} else {
|
||||
if (sendingTypes.contains(type)) {
|
||||
sendingTypes.remove(type);
|
||||
} else {
|
||||
sendingTypes.add(type);
|
||||
}
|
||||
}
|
||||
|
||||
startLogging();
|
||||
sender.sendMessage(ChatColor.GREEN + "Now logging " + type.getPacketClass().getSimpleName());
|
||||
return true;
|
||||
}
|
||||
|
||||
sender.sendMessage(ChatColor.RED + "Invalid syntax: /packetlog <protocol> <sender> <packet> [location]");
|
||||
return true;
|
||||
} catch (Throwable ex) {
|
||||
sender.sendMessage(ChatColor.RED + "Failed to parse command: " + ex.toString());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void startLogging() {
|
||||
manager.removePacketListener(this);
|
||||
|
||||
if (sendingTypes.isEmpty() && receivingTypes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.sendingWhitelist = ListeningWhitelist.newBuilder().types(sendingTypes).build();
|
||||
this.receivingWhitelist = ListeningWhitelist.newBuilder().types(receivingTypes).build();
|
||||
|
||||
// Setup the file logger if it hasn't been already
|
||||
if (location == LogLocation.FILE && fileLogger == null) {
|
||||
fileLogger = Logger.getLogger("ProtocolLib-FileLogging");
|
||||
|
||||
for (Handler handler : fileLogger.getHandlers())
|
||||
fileLogger.removeHandler(handler);
|
||||
fileLogger.setUseParentHandlers(false);
|
||||
|
||||
try {
|
||||
File logFile = new File(plugin.getDataFolder(), "log.log");
|
||||
FileHandler handler = new FileHandler(logFile.getAbsolutePath(), true);
|
||||
handler.setFormatter(new LogFormatter());
|
||||
fileLogger.addHandler(handler);
|
||||
} catch (IOException ex) {
|
||||
plugin.getLogger().log(Level.SEVERE, "Failed to obtain log file:", ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
manager.addPacketListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketSending(PacketEvent event) {
|
||||
log(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceiving(PacketEvent event) {
|
||||
log(event);
|
||||
}
|
||||
|
||||
// Here's where the magic happens
|
||||
|
||||
private static String hexDump(byte[] bytes) throws IOException {
|
||||
try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
|
||||
if (HEX_DUMP == null) {
|
||||
Class<?> hexDumpClass = MinecraftReflection.getLibraryClass("org.apache.commons.io.HexDump");
|
||||
HEX_DUMP = Accessors.getMethodAccessor(FuzzyReflection.fromClass(hexDumpClass)
|
||||
.getMethodByParameters("dump", byte[].class, long.class, OutputStream.class, int.class));
|
||||
}
|
||||
|
||||
HEX_DUMP.invoke(null, bytes, 0, output, 0);
|
||||
return new String(output.toByteArray(), StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
|
||||
private void log(PacketEvent event) {
|
||||
try {
|
||||
byte[] bytes = WirePacket.bytesFromPacket(event.getPacket());
|
||||
String hexDump = hexDump(bytes);
|
||||
|
||||
if (location == LogLocation.FILE) {
|
||||
fileLogger.log(Level.INFO, event.getPacketType() + ":");
|
||||
fileLogger.log(Level.INFO, hexDump);
|
||||
fileLogger.log(Level.INFO, "");
|
||||
} else {
|
||||
System.out.println(event.getPacketType() + ":");
|
||||
System.out.println(hexDump);
|
||||
System.out.println();
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
plugin.getLogger().log(Level.WARNING, "Failed to log packet " + event.getPacketType() + ":", ex);
|
||||
plugin.getLogger().log(Level.WARNING, "Clearing packet logger...");
|
||||
|
||||
sendingTypes.clear();
|
||||
receivingTypes.clear();
|
||||
startLogging();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListeningWhitelist getSendingWhitelist() {
|
||||
return sendingWhitelist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListeningWhitelist getReceivingWhitelist() {
|
||||
return receivingWhitelist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Plugin getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
private enum LogLocation {
|
||||
CONSOLE, FILE
|
||||
}
|
||||
|
||||
private static class LogFormatter extends Formatter {
|
||||
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 FORMAT = "[{0}] {1}";
|
||||
|
||||
@Override
|
||||
public String format(LogRecord record) {
|
||||
String string = formatMessage(record);
|
||||
if (string.isEmpty()) {
|
||||
return LINE_SEPARATOR;
|
||||
}
|
||||
|
||||
StringBuilder message = new StringBuilder();
|
||||
message.append(MessageFormat.format(FORMAT, DATE.format(record.getMillis()), string));
|
||||
message.append(LINE_SEPARATOR);
|
||||
return message.toString();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,143 +1,143 @@
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2017 dmulloy2
|
||||
*
|
||||
* 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 version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
package com.comphenix.protocol.events;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
|
||||
/**
|
||||
* Stores and retrieves metadata for applicable packet objects.
|
||||
* @author dmulloy2
|
||||
*/
|
||||
class PacketMetadata {
|
||||
|
||||
private static class MetaObject<T> {
|
||||
private final String key;
|
||||
private final T value;
|
||||
|
||||
private MetaObject(String key, T value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) return true;
|
||||
|
||||
if (o instanceof MetaObject) {
|
||||
MetaObject that = (MetaObject) o;
|
||||
return that.key.equals(this.key) &&
|
||||
that.value.equals(this.value);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MetaObject[" + key + "=" + value + "]";
|
||||
}
|
||||
}
|
||||
|
||||
// Packet meta cache
|
||||
private static Cache<Object, List<MetaObject>> META_CACHE;
|
||||
|
||||
public static <T> Optional<T> get(Object packet, String key) {
|
||||
Validate.notNull(key, "Null keys are not permitted!");
|
||||
|
||||
if (META_CACHE == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
List<MetaObject> meta = META_CACHE.getIfPresent(packet);
|
||||
if (meta == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
for (MetaObject object : meta) {
|
||||
if (object.key.equals(key)) {
|
||||
return Optional.of((T) object.value);
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private static void createCache() {
|
||||
META_CACHE = CacheBuilder
|
||||
.newBuilder()
|
||||
.expireAfterWrite(1, TimeUnit.MINUTES)
|
||||
.build();
|
||||
}
|
||||
|
||||
public static <T> void set(Object packet, String key, T value) {
|
||||
Validate.notNull(key, "Null keys are not permitted!");
|
||||
|
||||
if (META_CACHE == null) {
|
||||
createCache();
|
||||
}
|
||||
|
||||
List<MetaObject> packetMeta;
|
||||
|
||||
try {
|
||||
packetMeta = META_CACHE.get(packet, ArrayList::new);
|
||||
} catch (ExecutionException ex) {
|
||||
// Not possible, but let's humor the array list constructor having an issue
|
||||
packetMeta = new ArrayList<>();
|
||||
}
|
||||
|
||||
packetMeta.removeIf(meta -> meta.key.equals(key));
|
||||
packetMeta.add(new MetaObject<>(key, value));
|
||||
META_CACHE.put(packet, packetMeta);
|
||||
}
|
||||
|
||||
public static <T> Optional<T> remove(Object packet, String key) {
|
||||
Validate.notNull(key, "Null keys are not permitted!");
|
||||
|
||||
if (META_CACHE == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
List<MetaObject> packetMeta = META_CACHE.getIfPresent(packet);
|
||||
if (packetMeta == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
Optional<T> value = Optional.empty();
|
||||
Iterator<MetaObject> iter = packetMeta.iterator();
|
||||
while (iter.hasNext()) {
|
||||
MetaObject meta = iter.next();
|
||||
if (meta.key.equals(key)) {
|
||||
value = Optional.of((T) meta.value);
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2017 dmulloy2
|
||||
*
|
||||
* 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 version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
package com.comphenix.protocol.events;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
|
||||
/**
|
||||
* Stores and retrieves metadata for applicable packet objects.
|
||||
* @author dmulloy2
|
||||
*/
|
||||
class PacketMetadata {
|
||||
|
||||
private static class MetaObject<T> {
|
||||
private final String key;
|
||||
private final T value;
|
||||
|
||||
private MetaObject(String key, T value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) return true;
|
||||
|
||||
if (o instanceof MetaObject) {
|
||||
MetaObject that = (MetaObject) o;
|
||||
return that.key.equals(this.key) &&
|
||||
that.value.equals(this.value);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MetaObject[" + key + "=" + value + "]";
|
||||
}
|
||||
}
|
||||
|
||||
// Packet meta cache
|
||||
private static Cache<Object, List<MetaObject>> META_CACHE;
|
||||
|
||||
public static <T> Optional<T> get(Object packet, String key) {
|
||||
Validate.notNull(key, "Null keys are not permitted!");
|
||||
|
||||
if (META_CACHE == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
List<MetaObject> meta = META_CACHE.getIfPresent(packet);
|
||||
if (meta == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
for (MetaObject object : meta) {
|
||||
if (object.key.equals(key)) {
|
||||
return Optional.of((T) object.value);
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private static void createCache() {
|
||||
META_CACHE = CacheBuilder
|
||||
.newBuilder()
|
||||
.expireAfterWrite(1, TimeUnit.MINUTES)
|
||||
.build();
|
||||
}
|
||||
|
||||
public static <T> void set(Object packet, String key, T value) {
|
||||
Validate.notNull(key, "Null keys are not permitted!");
|
||||
|
||||
if (META_CACHE == null) {
|
||||
createCache();
|
||||
}
|
||||
|
||||
List<MetaObject> packetMeta;
|
||||
|
||||
try {
|
||||
packetMeta = META_CACHE.get(packet, ArrayList::new);
|
||||
} catch (ExecutionException ex) {
|
||||
// Not possible, but let's humor the array list constructor having an issue
|
||||
packetMeta = new ArrayList<>();
|
||||
}
|
||||
|
||||
packetMeta.removeIf(meta -> meta.key.equals(key));
|
||||
packetMeta.add(new MetaObject<>(key, value));
|
||||
META_CACHE.put(packet, packetMeta);
|
||||
}
|
||||
|
||||
public static <T> Optional<T> remove(Object packet, String key) {
|
||||
Validate.notNull(key, "Null keys are not permitted!");
|
||||
|
||||
if (META_CACHE == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
List<MetaObject> packetMeta = META_CACHE.getIfPresent(packet);
|
||||
if (packetMeta == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
Optional<T> value = Optional.empty();
|
||||
Iterator<MetaObject> iter = packetMeta.iterator();
|
||||
while (iter.hasNext()) {
|
||||
MetaObject meta = iter.next();
|
||||
if (meta.key.equals(key)) {
|
||||
value = Optional.of((T) meta.value);
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
@ -1,43 +1,43 @@
|
||||
/**
|
||||
* (c) 2018 dmulloy2
|
||||
*/
|
||||
package com.comphenix.protocol.reflect.cloning;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
/**
|
||||
* A cloner that can clone Java Optional objects
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class JavaOptionalCloner implements Cloner {
|
||||
protected Cloner wrapped;
|
||||
|
||||
public JavaOptionalCloner(Cloner wrapped) {
|
||||
this.wrapped = wrapped;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canClone(Object source) {
|
||||
return source instanceof Optional || source instanceof OptionalInt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone(Object source) {
|
||||
if (source instanceof Optional) {
|
||||
Optional<?> optional = (Optional<?>) source;
|
||||
return optional.map(o -> wrapped.clone(o));
|
||||
} else if (source instanceof OptionalInt) {
|
||||
// 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
|
||||
OptionalInt optional = (OptionalInt) source;
|
||||
return optional.isPresent() ? OptionalInt.of(optional.getAsInt()) : OptionalInt.empty();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Cloner getWrapped() {
|
||||
return wrapped;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* (c) 2018 dmulloy2
|
||||
*/
|
||||
package com.comphenix.protocol.reflect.cloning;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
/**
|
||||
* A cloner that can clone Java Optional objects
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class JavaOptionalCloner implements Cloner {
|
||||
protected Cloner wrapped;
|
||||
|
||||
public JavaOptionalCloner(Cloner wrapped) {
|
||||
this.wrapped = wrapped;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canClone(Object source) {
|
||||
return source instanceof Optional || source instanceof OptionalInt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone(Object source) {
|
||||
if (source instanceof Optional) {
|
||||
Optional<?> optional = (Optional<?>) source;
|
||||
return optional.map(o -> wrapped.clone(o));
|
||||
} else if (source instanceof OptionalInt) {
|
||||
// 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
|
||||
OptionalInt optional = (OptionalInt) source;
|
||||
return optional.isPresent() ? OptionalInt.of(optional.getAsInt()) : OptionalInt.empty();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Cloner getWrapped() {
|
||||
return wrapped;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,421 +1,421 @@
|
||||
/*
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2012 Kristian S. Stangeland
|
||||
*
|
||||
* 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 version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
|
||||
package com.comphenix.protocol.utility;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.google.common.collect.ComparisonChain;
|
||||
import com.google.common.collect.Ordering;
|
||||
import java.io.Serializable;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
|
||||
/**
|
||||
* Determine the current Minecraft version.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public final class MinecraftVersion implements Comparable<MinecraftVersion>, Serializable {
|
||||
|
||||
/**
|
||||
* Version 1.19 - the wild update
|
||||
*/
|
||||
public static final MinecraftVersion WILD_UPDATE = new MinecraftVersion("1.19");
|
||||
/**
|
||||
* Version 1.18 - caves and cliffs part 2
|
||||
*/
|
||||
public static final MinecraftVersion CAVES_CLIFFS_2 = new MinecraftVersion("1.18");
|
||||
/**
|
||||
* Version 1.17 - caves and cliffs part 1
|
||||
*/
|
||||
public static final MinecraftVersion CAVES_CLIFFS_1 = new MinecraftVersion("1.17");
|
||||
/**
|
||||
* Version 1.16.2 - breaking change to the nether update
|
||||
*/
|
||||
public static final MinecraftVersion NETHER_UPDATE_2 = new MinecraftVersion("1.16.2");
|
||||
/**
|
||||
* Version 1.16.0 - the nether update
|
||||
*/
|
||||
public static final MinecraftVersion NETHER_UPDATE = new MinecraftVersion("1.16");
|
||||
/**
|
||||
* Version 1.15 - the bee update
|
||||
*/
|
||||
public static final MinecraftVersion BEE_UPDATE = new MinecraftVersion("1.15");
|
||||
/**
|
||||
* Version 1.14 - village and pillage update.
|
||||
*/
|
||||
public static final MinecraftVersion VILLAGE_UPDATE = new MinecraftVersion("1.14");
|
||||
/**
|
||||
* Version 1.13 - update aquatic.
|
||||
*/
|
||||
public static final MinecraftVersion AQUATIC_UPDATE = new MinecraftVersion("1.13");
|
||||
/**
|
||||
* Version 1.12 - the world of color update.
|
||||
*/
|
||||
public static final MinecraftVersion COLOR_UPDATE = new MinecraftVersion("1.12");
|
||||
/**
|
||||
* Version 1.11 - the exploration update.
|
||||
*/
|
||||
public static final MinecraftVersion EXPLORATION_UPDATE = new MinecraftVersion("1.11");
|
||||
/**
|
||||
* Version 1.10 - the frostburn update.
|
||||
*/
|
||||
public static final MinecraftVersion FROSTBURN_UPDATE = new MinecraftVersion("1.10");
|
||||
/**
|
||||
* Version 1.9 - the combat update.
|
||||
*/
|
||||
public static final MinecraftVersion COMBAT_UPDATE = new MinecraftVersion("1.9");
|
||||
/**
|
||||
* Version 1.8 - the "bountiful" update.
|
||||
*/
|
||||
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)
|
||||
*/
|
||||
public static final MinecraftVersion SKIN_UPDATE = new MinecraftVersion("1.7.8");
|
||||
/**
|
||||
* Version 1.7.2 - the update that changed the world.
|
||||
*/
|
||||
public static final MinecraftVersion WORLD_UPDATE = new MinecraftVersion("1.7.2");
|
||||
/**
|
||||
* Version 1.6.1 - the horse update.
|
||||
*/
|
||||
public static final MinecraftVersion HORSE_UPDATE = new MinecraftVersion("1.6.1");
|
||||
/**
|
||||
* Version 1.5.0 - the redstone update.
|
||||
*/
|
||||
public static final MinecraftVersion REDSTONE_UPDATE = new MinecraftVersion("1.5.0");
|
||||
/**
|
||||
* Version 1.4.2 - the scary update (Wither Boss).
|
||||
*/
|
||||
public static final MinecraftVersion SCARY_UPDATE = new MinecraftVersion("1.4.2");
|
||||
|
||||
/**
|
||||
* The latest release version of minecraft.
|
||||
*/
|
||||
public static final MinecraftVersion LATEST = WILD_UPDATE;
|
||||
|
||||
// used when serializing
|
||||
private static final long serialVersionUID = -8695133558996459770L;
|
||||
|
||||
/**
|
||||
* Regular expression used to parse version strings.
|
||||
*/
|
||||
private static final Pattern VERSION_PATTERN = Pattern.compile(".*\\(.*MC.\\s*([a-zA-z0-9\\-.]+).*");
|
||||
|
||||
/**
|
||||
* The current version of minecraft, lazy initialized by MinecraftVersion.currentVersion()
|
||||
*/
|
||||
private static MinecraftVersion currentVersion;
|
||||
|
||||
private final int major;
|
||||
private final int minor;
|
||||
private final int build;
|
||||
// The development stage
|
||||
private final String development;
|
||||
|
||||
// Snapshot?
|
||||
private final SnapshotVersion snapshot;
|
||||
private volatile Boolean atCurrentOrAbove;
|
||||
|
||||
/**
|
||||
* Determine the current Minecraft version.
|
||||
*
|
||||
* @param server - the Bukkit server that will be used to examine the MC version.
|
||||
*/
|
||||
public MinecraftVersion(Server server) {
|
||||
this(extractVersion(server.getVersion()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a version object from the format major.minor.build, or the snapshot format.
|
||||
*
|
||||
* @param versionOnly - the version in text form.
|
||||
*/
|
||||
public MinecraftVersion(String versionOnly) {
|
||||
this(versionOnly, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a version format from the standard release version or the snapshot verison.
|
||||
*
|
||||
* @param versionOnly - the version.
|
||||
* @param parseSnapshot - TRUE to parse the snapshot, FALSE otherwise.
|
||||
*/
|
||||
private MinecraftVersion(String versionOnly, boolean parseSnapshot) {
|
||||
String[] section = versionOnly.split("-");
|
||||
SnapshotVersion snapshot = null;
|
||||
int[] numbers = new int[3];
|
||||
|
||||
try {
|
||||
numbers = this.parseVersion(section[0]);
|
||||
} catch (NumberFormatException cause) {
|
||||
// Skip snapshot parsing
|
||||
if (!parseSnapshot) {
|
||||
throw cause;
|
||||
}
|
||||
|
||||
try {
|
||||
// Determine if the snapshot is newer than the current release version
|
||||
snapshot = new SnapshotVersion(section[0]);
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
|
||||
|
||||
MinecraftVersion latest = new MinecraftVersion(ProtocolLibrary.MAXIMUM_MINECRAFT_VERSION, false);
|
||||
boolean newer = snapshot.getSnapshotDate().compareTo(
|
||||
format.parse(ProtocolLibrary.MINECRAFT_LAST_RELEASE_DATE)) > 0;
|
||||
|
||||
numbers[0] = latest.getMajor();
|
||||
numbers[1] = latest.getMinor() + (newer ? 1 : -1);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Cannot parse " + section[0], e);
|
||||
}
|
||||
}
|
||||
|
||||
this.major = numbers[0];
|
||||
this.minor = numbers[1];
|
||||
this.build = numbers[2];
|
||||
this.development = section.length > 1 ? section[1] : (snapshot != null ? "snapshot" : null);
|
||||
this.snapshot = snapshot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a version object directly.
|
||||
*
|
||||
* @param major - major version number.
|
||||
* @param minor - minor version number.
|
||||
* @param build - build version number.
|
||||
*/
|
||||
public MinecraftVersion(int major, int minor, int build) {
|
||||
this(major, minor, build, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a version object directly.
|
||||
*
|
||||
* @param major - major version number.
|
||||
* @param minor - minor version number.
|
||||
* @param build - build version number.
|
||||
* @param development - development stage.
|
||||
*/
|
||||
public MinecraftVersion(int major, int minor, int build, String development) {
|
||||
this.major = major;
|
||||
this.minor = minor;
|
||||
this.build = build;
|
||||
this.development = development;
|
||||
this.snapshot = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the Minecraft version from CraftBukkit itself.
|
||||
*
|
||||
* @param text - the server version in text form.
|
||||
* @return The underlying MC version.
|
||||
* @throws IllegalStateException If we could not parse the version string.
|
||||
*/
|
||||
public static String extractVersion(String text) {
|
||||
Matcher version = VERSION_PATTERN.matcher(text);
|
||||
|
||||
if (version.matches() && version.group(1) != null) {
|
||||
return version.group(1);
|
||||
} else {
|
||||
throw new IllegalStateException("Cannot parse version String '" + text + "'");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given server version into a Minecraft version.
|
||||
*
|
||||
* @param serverVersion - the server version.
|
||||
* @return The resulting Minecraft version.
|
||||
*/
|
||||
public static MinecraftVersion fromServerVersion(String serverVersion) {
|
||||
return new MinecraftVersion(extractVersion(serverVersion));
|
||||
}
|
||||
|
||||
public static MinecraftVersion getCurrentVersion() {
|
||||
if (currentVersion == null) {
|
||||
currentVersion = fromServerVersion(Bukkit.getVersion());
|
||||
}
|
||||
|
||||
return currentVersion;
|
||||
}
|
||||
|
||||
public static void setCurrentVersion(MinecraftVersion version) {
|
||||
currentVersion = version;
|
||||
}
|
||||
|
||||
public static boolean atOrAbove(MinecraftVersion version) {
|
||||
return getCurrentVersion().isAtLeast(version);
|
||||
}
|
||||
|
||||
private int[] parseVersion(String version) {
|
||||
String[] elements = version.split("\\.");
|
||||
int[] numbers = new int[3];
|
||||
|
||||
// Make sure it's even a valid version
|
||||
if (elements.length < 1) {
|
||||
throw new IllegalStateException("Corrupt MC version: " + version);
|
||||
}
|
||||
|
||||
// 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++) {
|
||||
numbers[i] = Integer.parseInt(elements[i].trim());
|
||||
}
|
||||
return numbers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Major version number
|
||||
*
|
||||
* @return Current major version number.
|
||||
*/
|
||||
public int getMajor() {
|
||||
return this.major;
|
||||
}
|
||||
|
||||
/**
|
||||
* Minor version number
|
||||
*
|
||||
* @return Current minor version number.
|
||||
*/
|
||||
public int getMinor() {
|
||||
return this.minor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build version number
|
||||
*
|
||||
* @return Current build version number.
|
||||
*/
|
||||
public int getBuild() {
|
||||
return this.build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the development stage.
|
||||
*
|
||||
* @return Development stage, or NULL if this is a release.
|
||||
*/
|
||||
public String getDevelopmentStage() {
|
||||
return this.development;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the snapshot version, or NULL if this is a release.
|
||||
*
|
||||
* @return The snapshot version.
|
||||
*/
|
||||
public SnapshotVersion getSnapshot() {
|
||||
return this.snapshot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this version is a snapshot.
|
||||
*
|
||||
* @return The snapshot version.
|
||||
*/
|
||||
public boolean isSnapshot() {
|
||||
return this.snapshot != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public boolean atOrAbove() {
|
||||
if (this.atCurrentOrAbove == null) {
|
||||
this.atCurrentOrAbove = MinecraftVersion.atOrAbove(this);
|
||||
}
|
||||
|
||||
return this.atCurrentOrAbove;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the version String (major.minor.build) only.
|
||||
*
|
||||
* @return A normal version string.
|
||||
*/
|
||||
public String getVersion() {
|
||||
if (this.getDevelopmentStage() == null) {
|
||||
return String.format("%s.%s.%s", this.getMajor(), this.getMinor(), this.getBuild());
|
||||
} else {
|
||||
return String.format("%s.%s.%s-%s%s", this.getMajor(), this.getMinor(), this.getBuild(),
|
||||
this.getDevelopmentStage(), this.isSnapshot() ? this.snapshot : "");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(MinecraftVersion o) {
|
||||
if (o == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return ComparisonChain.start()
|
||||
.compare(this.getMajor(), o.getMajor())
|
||||
.compare(this.getMinor(), o.getMinor())
|
||||
.compare(this.getBuild(), o.getBuild())
|
||||
.compare(this.getDevelopmentStage(), o.getDevelopmentStage(), Ordering.natural().nullsLast())
|
||||
.compare(this.getSnapshot(), o.getSnapshot(), Ordering.natural().nullsFirst())
|
||||
.result();
|
||||
}
|
||||
|
||||
public boolean isAtLeast(MinecraftVersion other) {
|
||||
if (other == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.compareTo(other) >= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj instanceof MinecraftVersion) {
|
||||
MinecraftVersion other = (MinecraftVersion) obj;
|
||||
|
||||
return this.getMajor() == other.getMajor() &&
|
||||
this.getMinor() == other.getMinor() &&
|
||||
this.getBuild() == other.getBuild() &&
|
||||
Objects.equals(this.getDevelopmentStage(), other.getDevelopmentStage());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.getMajor(), this.getMinor(), this.getBuild());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
// Convert to a String that we can parse back again
|
||||
return String.format("(MC: %s)", this.getVersion());
|
||||
}
|
||||
}
|
||||
/*
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2012 Kristian S. Stangeland
|
||||
*
|
||||
* 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 version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
|
||||
package com.comphenix.protocol.utility;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.google.common.collect.ComparisonChain;
|
||||
import com.google.common.collect.Ordering;
|
||||
import java.io.Serializable;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
|
||||
/**
|
||||
* Determine the current Minecraft version.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public final class MinecraftVersion implements Comparable<MinecraftVersion>, Serializable {
|
||||
|
||||
/**
|
||||
* Version 1.19 - the wild update
|
||||
*/
|
||||
public static final MinecraftVersion WILD_UPDATE = new MinecraftVersion("1.19");
|
||||
/**
|
||||
* Version 1.18 - caves and cliffs part 2
|
||||
*/
|
||||
public static final MinecraftVersion CAVES_CLIFFS_2 = new MinecraftVersion("1.18");
|
||||
/**
|
||||
* Version 1.17 - caves and cliffs part 1
|
||||
*/
|
||||
public static final MinecraftVersion CAVES_CLIFFS_1 = new MinecraftVersion("1.17");
|
||||
/**
|
||||
* Version 1.16.2 - breaking change to the nether update
|
||||
*/
|
||||
public static final MinecraftVersion NETHER_UPDATE_2 = new MinecraftVersion("1.16.2");
|
||||
/**
|
||||
* Version 1.16.0 - the nether update
|
||||
*/
|
||||
public static final MinecraftVersion NETHER_UPDATE = new MinecraftVersion("1.16");
|
||||
/**
|
||||
* Version 1.15 - the bee update
|
||||
*/
|
||||
public static final MinecraftVersion BEE_UPDATE = new MinecraftVersion("1.15");
|
||||
/**
|
||||
* Version 1.14 - village and pillage update.
|
||||
*/
|
||||
public static final MinecraftVersion VILLAGE_UPDATE = new MinecraftVersion("1.14");
|
||||
/**
|
||||
* Version 1.13 - update aquatic.
|
||||
*/
|
||||
public static final MinecraftVersion AQUATIC_UPDATE = new MinecraftVersion("1.13");
|
||||
/**
|
||||
* Version 1.12 - the world of color update.
|
||||
*/
|
||||
public static final MinecraftVersion COLOR_UPDATE = new MinecraftVersion("1.12");
|
||||
/**
|
||||
* Version 1.11 - the exploration update.
|
||||
*/
|
||||
public static final MinecraftVersion EXPLORATION_UPDATE = new MinecraftVersion("1.11");
|
||||
/**
|
||||
* Version 1.10 - the frostburn update.
|
||||
*/
|
||||
public static final MinecraftVersion FROSTBURN_UPDATE = new MinecraftVersion("1.10");
|
||||
/**
|
||||
* Version 1.9 - the combat update.
|
||||
*/
|
||||
public static final MinecraftVersion COMBAT_UPDATE = new MinecraftVersion("1.9");
|
||||
/**
|
||||
* Version 1.8 - the "bountiful" update.
|
||||
*/
|
||||
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)
|
||||
*/
|
||||
public static final MinecraftVersion SKIN_UPDATE = new MinecraftVersion("1.7.8");
|
||||
/**
|
||||
* Version 1.7.2 - the update that changed the world.
|
||||
*/
|
||||
public static final MinecraftVersion WORLD_UPDATE = new MinecraftVersion("1.7.2");
|
||||
/**
|
||||
* Version 1.6.1 - the horse update.
|
||||
*/
|
||||
public static final MinecraftVersion HORSE_UPDATE = new MinecraftVersion("1.6.1");
|
||||
/**
|
||||
* Version 1.5.0 - the redstone update.
|
||||
*/
|
||||
public static final MinecraftVersion REDSTONE_UPDATE = new MinecraftVersion("1.5.0");
|
||||
/**
|
||||
* Version 1.4.2 - the scary update (Wither Boss).
|
||||
*/
|
||||
public static final MinecraftVersion SCARY_UPDATE = new MinecraftVersion("1.4.2");
|
||||
|
||||
/**
|
||||
* The latest release version of minecraft.
|
||||
*/
|
||||
public static final MinecraftVersion LATEST = WILD_UPDATE;
|
||||
|
||||
// used when serializing
|
||||
private static final long serialVersionUID = -8695133558996459770L;
|
||||
|
||||
/**
|
||||
* Regular expression used to parse version strings.
|
||||
*/
|
||||
private static final Pattern VERSION_PATTERN = Pattern.compile(".*\\(.*MC.\\s*([a-zA-z0-9\\-.]+).*");
|
||||
|
||||
/**
|
||||
* The current version of minecraft, lazy initialized by MinecraftVersion.currentVersion()
|
||||
*/
|
||||
private static MinecraftVersion currentVersion;
|
||||
|
||||
private final int major;
|
||||
private final int minor;
|
||||
private final int build;
|
||||
// The development stage
|
||||
private final String development;
|
||||
|
||||
// Snapshot?
|
||||
private final SnapshotVersion snapshot;
|
||||
private volatile Boolean atCurrentOrAbove;
|
||||
|
||||
/**
|
||||
* Determine the current Minecraft version.
|
||||
*
|
||||
* @param server - the Bukkit server that will be used to examine the MC version.
|
||||
*/
|
||||
public MinecraftVersion(Server server) {
|
||||
this(extractVersion(server.getVersion()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a version object from the format major.minor.build, or the snapshot format.
|
||||
*
|
||||
* @param versionOnly - the version in text form.
|
||||
*/
|
||||
public MinecraftVersion(String versionOnly) {
|
||||
this(versionOnly, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a version format from the standard release version or the snapshot verison.
|
||||
*
|
||||
* @param versionOnly - the version.
|
||||
* @param parseSnapshot - TRUE to parse the snapshot, FALSE otherwise.
|
||||
*/
|
||||
private MinecraftVersion(String versionOnly, boolean parseSnapshot) {
|
||||
String[] section = versionOnly.split("-");
|
||||
SnapshotVersion snapshot = null;
|
||||
int[] numbers = new int[3];
|
||||
|
||||
try {
|
||||
numbers = this.parseVersion(section[0]);
|
||||
} catch (NumberFormatException cause) {
|
||||
// Skip snapshot parsing
|
||||
if (!parseSnapshot) {
|
||||
throw cause;
|
||||
}
|
||||
|
||||
try {
|
||||
// Determine if the snapshot is newer than the current release version
|
||||
snapshot = new SnapshotVersion(section[0]);
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
|
||||
|
||||
MinecraftVersion latest = new MinecraftVersion(ProtocolLibrary.MAXIMUM_MINECRAFT_VERSION, false);
|
||||
boolean newer = snapshot.getSnapshotDate().compareTo(
|
||||
format.parse(ProtocolLibrary.MINECRAFT_LAST_RELEASE_DATE)) > 0;
|
||||
|
||||
numbers[0] = latest.getMajor();
|
||||
numbers[1] = latest.getMinor() + (newer ? 1 : -1);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Cannot parse " + section[0], e);
|
||||
}
|
||||
}
|
||||
|
||||
this.major = numbers[0];
|
||||
this.minor = numbers[1];
|
||||
this.build = numbers[2];
|
||||
this.development = section.length > 1 ? section[1] : (snapshot != null ? "snapshot" : null);
|
||||
this.snapshot = snapshot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a version object directly.
|
||||
*
|
||||
* @param major - major version number.
|
||||
* @param minor - minor version number.
|
||||
* @param build - build version number.
|
||||
*/
|
||||
public MinecraftVersion(int major, int minor, int build) {
|
||||
this(major, minor, build, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a version object directly.
|
||||
*
|
||||
* @param major - major version number.
|
||||
* @param minor - minor version number.
|
||||
* @param build - build version number.
|
||||
* @param development - development stage.
|
||||
*/
|
||||
public MinecraftVersion(int major, int minor, int build, String development) {
|
||||
this.major = major;
|
||||
this.minor = minor;
|
||||
this.build = build;
|
||||
this.development = development;
|
||||
this.snapshot = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the Minecraft version from CraftBukkit itself.
|
||||
*
|
||||
* @param text - the server version in text form.
|
||||
* @return The underlying MC version.
|
||||
* @throws IllegalStateException If we could not parse the version string.
|
||||
*/
|
||||
public static String extractVersion(String text) {
|
||||
Matcher version = VERSION_PATTERN.matcher(text);
|
||||
|
||||
if (version.matches() && version.group(1) != null) {
|
||||
return version.group(1);
|
||||
} else {
|
||||
throw new IllegalStateException("Cannot parse version String '" + text + "'");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given server version into a Minecraft version.
|
||||
*
|
||||
* @param serverVersion - the server version.
|
||||
* @return The resulting Minecraft version.
|
||||
*/
|
||||
public static MinecraftVersion fromServerVersion(String serverVersion) {
|
||||
return new MinecraftVersion(extractVersion(serverVersion));
|
||||
}
|
||||
|
||||
public static MinecraftVersion getCurrentVersion() {
|
||||
if (currentVersion == null) {
|
||||
currentVersion = fromServerVersion(Bukkit.getVersion());
|
||||
}
|
||||
|
||||
return currentVersion;
|
||||
}
|
||||
|
||||
public static void setCurrentVersion(MinecraftVersion version) {
|
||||
currentVersion = version;
|
||||
}
|
||||
|
||||
public static boolean atOrAbove(MinecraftVersion version) {
|
||||
return getCurrentVersion().isAtLeast(version);
|
||||
}
|
||||
|
||||
private int[] parseVersion(String version) {
|
||||
String[] elements = version.split("\\.");
|
||||
int[] numbers = new int[3];
|
||||
|
||||
// Make sure it's even a valid version
|
||||
if (elements.length < 1) {
|
||||
throw new IllegalStateException("Corrupt MC version: " + version);
|
||||
}
|
||||
|
||||
// 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++) {
|
||||
numbers[i] = Integer.parseInt(elements[i].trim());
|
||||
}
|
||||
return numbers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Major version number
|
||||
*
|
||||
* @return Current major version number.
|
||||
*/
|
||||
public int getMajor() {
|
||||
return this.major;
|
||||
}
|
||||
|
||||
/**
|
||||
* Minor version number
|
||||
*
|
||||
* @return Current minor version number.
|
||||
*/
|
||||
public int getMinor() {
|
||||
return this.minor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build version number
|
||||
*
|
||||
* @return Current build version number.
|
||||
*/
|
||||
public int getBuild() {
|
||||
return this.build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the development stage.
|
||||
*
|
||||
* @return Development stage, or NULL if this is a release.
|
||||
*/
|
||||
public String getDevelopmentStage() {
|
||||
return this.development;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the snapshot version, or NULL if this is a release.
|
||||
*
|
||||
* @return The snapshot version.
|
||||
*/
|
||||
public SnapshotVersion getSnapshot() {
|
||||
return this.snapshot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this version is a snapshot.
|
||||
*
|
||||
* @return The snapshot version.
|
||||
*/
|
||||
public boolean isSnapshot() {
|
||||
return this.snapshot != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public boolean atOrAbove() {
|
||||
if (this.atCurrentOrAbove == null) {
|
||||
this.atCurrentOrAbove = MinecraftVersion.atOrAbove(this);
|
||||
}
|
||||
|
||||
return this.atCurrentOrAbove;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the version String (major.minor.build) only.
|
||||
*
|
||||
* @return A normal version string.
|
||||
*/
|
||||
public String getVersion() {
|
||||
if (this.getDevelopmentStage() == null) {
|
||||
return String.format("%s.%s.%s", this.getMajor(), this.getMinor(), this.getBuild());
|
||||
} else {
|
||||
return String.format("%s.%s.%s-%s%s", this.getMajor(), this.getMinor(), this.getBuild(),
|
||||
this.getDevelopmentStage(), this.isSnapshot() ? this.snapshot : "");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(MinecraftVersion o) {
|
||||
if (o == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return ComparisonChain.start()
|
||||
.compare(this.getMajor(), o.getMajor())
|
||||
.compare(this.getMinor(), o.getMinor())
|
||||
.compare(this.getBuild(), o.getBuild())
|
||||
.compare(this.getDevelopmentStage(), o.getDevelopmentStage(), Ordering.natural().nullsLast())
|
||||
.compare(this.getSnapshot(), o.getSnapshot(), Ordering.natural().nullsFirst())
|
||||
.result();
|
||||
}
|
||||
|
||||
public boolean isAtLeast(MinecraftVersion other) {
|
||||
if (other == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.compareTo(other) >= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj instanceof MinecraftVersion) {
|
||||
MinecraftVersion other = (MinecraftVersion) obj;
|
||||
|
||||
return this.getMajor() == other.getMajor() &&
|
||||
this.getMinor() == other.getMinor() &&
|
||||
this.getBuild() == other.getBuild() &&
|
||||
Objects.equals(this.getDevelopmentStage(), other.getDevelopmentStage());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.getMajor(), this.getMinor(), this.getBuild());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
// Convert to a String that we can parse back again
|
||||
return String.format("(MC: %s)", this.getVersion());
|
||||
}
|
||||
}
|
||||
|
@ -1,194 +1,194 @@
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2017 Dan Mulloy
|
||||
*
|
||||
* 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 version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.google.common.base.Defaults;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
/**
|
||||
* Automatically wraps an internal NMS class to a non-versioned, deofbuscated class.
|
||||
* Requirements:
|
||||
* <ul>
|
||||
* <li>The wrapper must be public</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 the the same number of fields as the NMS class</li>
|
||||
* <li>Each field should correspond, in order, to its NMS counterpart</li>
|
||||
* <li>Non-generic fields must have a converter</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class AutoWrapper<T> implements EquivalentConverter<T> {
|
||||
private static final Object[] NO_ARGS = new Object[0];
|
||||
|
||||
private Map<Integer, Function<Object, Object>> wrappers = new HashMap<>();
|
||||
private Map<Integer, Function<Object, Object>> unwrappers = new HashMap<>();
|
||||
|
||||
// lazy
|
||||
private FieldAccessor[] nmsAccessors;
|
||||
private FieldAccessor[] wrapperAccessors;
|
||||
|
||||
private Object[] nmsDefaultArgs;
|
||||
private ConstructorAccessor nmsInstanceCreator;
|
||||
|
||||
private Class<T> wrapperClass;
|
||||
private Class<?> nmsClass;
|
||||
|
||||
private AutoWrapper(Class<T> wrapperClass, Class<?> nmsClass) {
|
||||
this.wrapperClass = wrapperClass;
|
||||
this.nmsClass = nmsClass;
|
||||
}
|
||||
|
||||
public static <T> AutoWrapper<T> wrap(Class<T> wrapperClass, Class<?> nmsClass) {
|
||||
return new AutoWrapper<>(wrapperClass, nmsClass);
|
||||
}
|
||||
|
||||
public static <T> AutoWrapper<T> wrap(Class<T> wrapperClass, String nmsClassName) {
|
||||
return wrap(wrapperClass, MinecraftReflection.getMinecraftClass(nmsClassName));
|
||||
}
|
||||
|
||||
public static <T> AutoWrapper<T> wrap(Class<T> wrapperClass, String nmsClassName, String... aliases) {
|
||||
return wrap(wrapperClass, MinecraftReflection.getMinecraftClass(nmsClassName, aliases));
|
||||
}
|
||||
|
||||
public AutoWrapper<T> field(int index, Function<Object, Object> wrapper, Function<Object, Object> unwrapper) {
|
||||
wrappers.put(index, wrapper);
|
||||
unwrappers.put(index, unwrapper);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AutoWrapper<T> field(int index, EquivalentConverter converter) {
|
||||
return field(index, converter::getSpecific, specific -> converter.getGeneric(specific));
|
||||
}
|
||||
|
||||
public T wrap(Object nmsObject) {
|
||||
T instance;
|
||||
|
||||
try {
|
||||
instance = wrapperClass.newInstance();
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new InvalidWrapperException(wrapperClass.getSimpleName() + " is not accessible!", ex);
|
||||
}
|
||||
|
||||
// ensures that all accessors are present
|
||||
computeFieldAccessors();
|
||||
|
||||
for (int i = 0; i < wrapperAccessors.length; i++) {
|
||||
FieldAccessor source = nmsAccessors[i];
|
||||
FieldAccessor target = wrapperAccessors[i];
|
||||
|
||||
Object value = source.get(nmsObject);
|
||||
if (wrappers.containsKey(i))
|
||||
value = wrappers.get(i).apply(value);
|
||||
|
||||
target.set(instance, value);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public Object unwrap(Object wrapper) {
|
||||
// ensures that all accessors are present
|
||||
computeFieldAccessors();
|
||||
computeNmsConstructorAccess();
|
||||
|
||||
Object instance = nmsInstanceCreator.invoke(nmsDefaultArgs);
|
||||
|
||||
for (int i = 0; i < wrapperAccessors.length; i++) {
|
||||
FieldAccessor source = wrapperAccessors[i];
|
||||
FieldAccessor target = nmsAccessors[i];
|
||||
|
||||
Object value = source.get(wrapper);
|
||||
if (unwrappers.containsKey(i))
|
||||
value = unwrappers.get(i).apply(value);
|
||||
|
||||
target.set(instance, value);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
private void computeFieldAccessors() {
|
||||
if (nmsAccessors == null) {
|
||||
nmsAccessors = Arrays
|
||||
.stream(nmsClass.getDeclaredFields())
|
||||
.filter(field -> !Modifier.isStatic(field.getModifiers()))
|
||||
.map(field -> Accessors.getFieldAccessor(field))
|
||||
.toArray(FieldAccessor[]::new);
|
||||
}
|
||||
|
||||
if (wrapperAccessors == null) {
|
||||
wrapperAccessors = Arrays
|
||||
.stream(wrapperClass.getDeclaredFields())
|
||||
.map(field -> Accessors.getFieldAccessor(field))
|
||||
.toArray(FieldAccessor[]::new);
|
||||
}
|
||||
}
|
||||
|
||||
private void computeNmsConstructorAccess() {
|
||||
if (nmsInstanceCreator == null) {
|
||||
ConstructorAccessor noArgs = Accessors.getConstructorAccessorOrNull(nmsClass);
|
||||
if (noArgs != null) {
|
||||
// no args constructor is available - use it
|
||||
nmsInstanceCreator = noArgs;
|
||||
nmsDefaultArgs = NO_ARGS;
|
||||
} else {
|
||||
// use the first constructor of the class
|
||||
nmsInstanceCreator = Accessors.getConstructorAccessor(nmsClass.getDeclaredConstructors()[0]);
|
||||
nmsDefaultArgs = Arrays
|
||||
.stream(nmsInstanceCreator.getConstructor().getParameterTypes())
|
||||
.map(type -> type.isPrimitive() ? Defaults.defaultValue(type) : null)
|
||||
.toArray(Object[]::new);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Equivalent conversion
|
||||
|
||||
@Override
|
||||
public T getSpecific(Object generic) {
|
||||
return wrap(generic);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGeneric(Object specific) {
|
||||
return unwrap(specific);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T> getSpecificType() {
|
||||
return wrapperClass;
|
||||
}
|
||||
|
||||
public static class InvalidWrapperException extends RuntimeException {
|
||||
private InvalidWrapperException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2017 Dan Mulloy
|
||||
*
|
||||
* 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 version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.google.common.base.Defaults;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
/**
|
||||
* Automatically wraps an internal NMS class to a non-versioned, deofbuscated class.
|
||||
* Requirements:
|
||||
* <ul>
|
||||
* <li>The wrapper must be public</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 the the same number of fields as the NMS class</li>
|
||||
* <li>Each field should correspond, in order, to its NMS counterpart</li>
|
||||
* <li>Non-generic fields must have a converter</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class AutoWrapper<T> implements EquivalentConverter<T> {
|
||||
private static final Object[] NO_ARGS = new Object[0];
|
||||
|
||||
private Map<Integer, Function<Object, Object>> wrappers = new HashMap<>();
|
||||
private Map<Integer, Function<Object, Object>> unwrappers = new HashMap<>();
|
||||
|
||||
// lazy
|
||||
private FieldAccessor[] nmsAccessors;
|
||||
private FieldAccessor[] wrapperAccessors;
|
||||
|
||||
private Object[] nmsDefaultArgs;
|
||||
private ConstructorAccessor nmsInstanceCreator;
|
||||
|
||||
private Class<T> wrapperClass;
|
||||
private Class<?> nmsClass;
|
||||
|
||||
private AutoWrapper(Class<T> wrapperClass, Class<?> nmsClass) {
|
||||
this.wrapperClass = wrapperClass;
|
||||
this.nmsClass = nmsClass;
|
||||
}
|
||||
|
||||
public static <T> AutoWrapper<T> wrap(Class<T> wrapperClass, Class<?> nmsClass) {
|
||||
return new AutoWrapper<>(wrapperClass, nmsClass);
|
||||
}
|
||||
|
||||
public static <T> AutoWrapper<T> wrap(Class<T> wrapperClass, String nmsClassName) {
|
||||
return wrap(wrapperClass, MinecraftReflection.getMinecraftClass(nmsClassName));
|
||||
}
|
||||
|
||||
public static <T> AutoWrapper<T> wrap(Class<T> wrapperClass, String nmsClassName, String... aliases) {
|
||||
return wrap(wrapperClass, MinecraftReflection.getMinecraftClass(nmsClassName, aliases));
|
||||
}
|
||||
|
||||
public AutoWrapper<T> field(int index, Function<Object, Object> wrapper, Function<Object, Object> unwrapper) {
|
||||
wrappers.put(index, wrapper);
|
||||
unwrappers.put(index, unwrapper);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AutoWrapper<T> field(int index, EquivalentConverter converter) {
|
||||
return field(index, converter::getSpecific, specific -> converter.getGeneric(specific));
|
||||
}
|
||||
|
||||
public T wrap(Object nmsObject) {
|
||||
T instance;
|
||||
|
||||
try {
|
||||
instance = wrapperClass.newInstance();
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new InvalidWrapperException(wrapperClass.getSimpleName() + " is not accessible!", ex);
|
||||
}
|
||||
|
||||
// ensures that all accessors are present
|
||||
computeFieldAccessors();
|
||||
|
||||
for (int i = 0; i < wrapperAccessors.length; i++) {
|
||||
FieldAccessor source = nmsAccessors[i];
|
||||
FieldAccessor target = wrapperAccessors[i];
|
||||
|
||||
Object value = source.get(nmsObject);
|
||||
if (wrappers.containsKey(i))
|
||||
value = wrappers.get(i).apply(value);
|
||||
|
||||
target.set(instance, value);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public Object unwrap(Object wrapper) {
|
||||
// ensures that all accessors are present
|
||||
computeFieldAccessors();
|
||||
computeNmsConstructorAccess();
|
||||
|
||||
Object instance = nmsInstanceCreator.invoke(nmsDefaultArgs);
|
||||
|
||||
for (int i = 0; i < wrapperAccessors.length; i++) {
|
||||
FieldAccessor source = wrapperAccessors[i];
|
||||
FieldAccessor target = nmsAccessors[i];
|
||||
|
||||
Object value = source.get(wrapper);
|
||||
if (unwrappers.containsKey(i))
|
||||
value = unwrappers.get(i).apply(value);
|
||||
|
||||
target.set(instance, value);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
private void computeFieldAccessors() {
|
||||
if (nmsAccessors == null) {
|
||||
nmsAccessors = Arrays
|
||||
.stream(nmsClass.getDeclaredFields())
|
||||
.filter(field -> !Modifier.isStatic(field.getModifiers()))
|
||||
.map(field -> Accessors.getFieldAccessor(field))
|
||||
.toArray(FieldAccessor[]::new);
|
||||
}
|
||||
|
||||
if (wrapperAccessors == null) {
|
||||
wrapperAccessors = Arrays
|
||||
.stream(wrapperClass.getDeclaredFields())
|
||||
.map(field -> Accessors.getFieldAccessor(field))
|
||||
.toArray(FieldAccessor[]::new);
|
||||
}
|
||||
}
|
||||
|
||||
private void computeNmsConstructorAccess() {
|
||||
if (nmsInstanceCreator == null) {
|
||||
ConstructorAccessor noArgs = Accessors.getConstructorAccessorOrNull(nmsClass);
|
||||
if (noArgs != null) {
|
||||
// no args constructor is available - use it
|
||||
nmsInstanceCreator = noArgs;
|
||||
nmsDefaultArgs = NO_ARGS;
|
||||
} else {
|
||||
// use the first constructor of the class
|
||||
nmsInstanceCreator = Accessors.getConstructorAccessor(nmsClass.getDeclaredConstructors()[0]);
|
||||
nmsDefaultArgs = Arrays
|
||||
.stream(nmsInstanceCreator.getConstructor().getParameterTypes())
|
||||
.map(type -> type.isPrimitive() ? Defaults.defaultValue(type) : null)
|
||||
.toArray(Object[]::new);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Equivalent conversion
|
||||
|
||||
@Override
|
||||
public T getSpecific(Object generic) {
|
||||
return wrap(generic);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGeneric(Object specific) {
|
||||
return unwrap(specific);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T> getSpecificType() {
|
||||
return wrapperClass;
|
||||
}
|
||||
|
||||
public static class InvalidWrapperException extends RuntimeException {
|
||||
private InvalidWrapperException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
public interface ClonableWrapper {
|
||||
Object getHandle();
|
||||
ClonableWrapper deepClone();
|
||||
|
||||
}
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
public interface ClonableWrapper {
|
||||
Object getHandle();
|
||||
ClonableWrapper deepClone();
|
||||
|
||||
}
|
||||
|
@ -1,75 +1,75 @@
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2016 dmulloy2
|
||||
*
|
||||
* 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 version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
/**
|
||||
* Handles component parsing in 1.8
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class ComponentParser {
|
||||
|
||||
private static Constructor readerConstructor;
|
||||
private static Method setLenient;
|
||||
private static Method getAdapter;
|
||||
private static Method read;
|
||||
|
||||
private ComponentParser() {
|
||||
}
|
||||
|
||||
public static Object deserialize(Object gson, Class<?> component, StringReader str) {
|
||||
try {
|
||||
com.google.gson.stream.JsonReader reader = new com.google.gson.stream.JsonReader(str);
|
||||
reader.setLenient(true);
|
||||
return ((com.google.gson.Gson) gson).getAdapter(component).read(reader);
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException("Failed to read JSON", ex);
|
||||
} catch (LinkageError er) {
|
||||
return deserializeLegacy(gson, component, str);
|
||||
}
|
||||
}
|
||||
|
||||
// Should only be needed on 1.8.
|
||||
private static Object deserializeLegacy(Object gson, Class<?> component, StringReader str) {
|
||||
try {
|
||||
if (readerConstructor == null) {
|
||||
|
||||
Class<?> readerClass = Class.forName("org.bukkit.craftbukkit.libs.com.google.gson.stream.JsonReader");
|
||||
readerConstructor = readerClass.getDeclaredConstructor(Reader.class);
|
||||
readerConstructor.setAccessible(true);
|
||||
setLenient = readerClass.getDeclaredMethod("setLenient", boolean.class);
|
||||
setLenient.setAccessible(true);
|
||||
getAdapter = gson.getClass().getDeclaredMethod("getAdapter", Class.class);
|
||||
getAdapter.setAccessible(true);
|
||||
Object adapter = getAdapter.invoke(gson, component);
|
||||
read = adapter.getClass().getDeclaredMethod("read", readerClass);
|
||||
read.setAccessible(true);
|
||||
}
|
||||
Object reader = readerConstructor.newInstance(str);
|
||||
setLenient.invoke(reader, true);
|
||||
Object adapter = getAdapter.invoke(gson, component);
|
||||
return read.invoke(adapter, reader);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Failed to read JSON", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2016 dmulloy2
|
||||
*
|
||||
* 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 version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
/**
|
||||
* Handles component parsing in 1.8
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class ComponentParser {
|
||||
|
||||
private static Constructor readerConstructor;
|
||||
private static Method setLenient;
|
||||
private static Method getAdapter;
|
||||
private static Method read;
|
||||
|
||||
private ComponentParser() {
|
||||
}
|
||||
|
||||
public static Object deserialize(Object gson, Class<?> component, StringReader str) {
|
||||
try {
|
||||
com.google.gson.stream.JsonReader reader = new com.google.gson.stream.JsonReader(str);
|
||||
reader.setLenient(true);
|
||||
return ((com.google.gson.Gson) gson).getAdapter(component).read(reader);
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException("Failed to read JSON", ex);
|
||||
} catch (LinkageError er) {
|
||||
return deserializeLegacy(gson, component, str);
|
||||
}
|
||||
}
|
||||
|
||||
// Should only be needed on 1.8.
|
||||
private static Object deserializeLegacy(Object gson, Class<?> component, StringReader str) {
|
||||
try {
|
||||
if (readerConstructor == null) {
|
||||
|
||||
Class<?> readerClass = Class.forName("org.bukkit.craftbukkit.libs.com.google.gson.stream.JsonReader");
|
||||
readerConstructor = readerClass.getDeclaredConstructor(Reader.class);
|
||||
readerConstructor.setAccessible(true);
|
||||
setLenient = readerClass.getDeclaredMethod("setLenient", boolean.class);
|
||||
setLenient.setAccessible(true);
|
||||
getAdapter = gson.getClass().getDeclaredMethod("getAdapter", Class.class);
|
||||
getAdapter.setAccessible(true);
|
||||
Object adapter = getAdapter.invoke(gson, component);
|
||||
read = adapter.getClass().getDeclaredMethod("read", readerClass);
|
||||
read.setAccessible(true);
|
||||
}
|
||||
Object reader = readerConstructor.newInstance(str);
|
||||
setLenient.invoke(reader, true);
|
||||
Object adapter = getAdapter.invoke(gson, component);
|
||||
return read.invoke(adapter, reader);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Failed to read JSON", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,174 +1,174 @@
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2017 Dan Mulloy
|
||||
*
|
||||
* 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 version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
/**
|
||||
* Utility class for converters
|
||||
* @author dmulloy2
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class Converters {
|
||||
|
||||
/**
|
||||
* Returns a converter that ignores null elements, so that the underlying converter doesn't have to worry about them.
|
||||
* @param converter Underlying converter
|
||||
* @param <T> Element type
|
||||
* @return An ignore null converter
|
||||
*/
|
||||
public static <T> EquivalentConverter<T> ignoreNull(final EquivalentConverter<T> converter) {
|
||||
return new EquivalentConverter<T>() {
|
||||
@Override
|
||||
public T getSpecific(Object generic) {
|
||||
return generic != null ? converter.getSpecific(generic) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGeneric(T specific) {
|
||||
return specific != null ? converter.getGeneric(specific) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T> getSpecificType() {
|
||||
return converter.getSpecificType();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a converter that passes generic and specific values through without converting.
|
||||
* @param clazz Element class
|
||||
* @param <T> Element type
|
||||
* @return A passthrough converter
|
||||
*/
|
||||
public static <T> EquivalentConverter<T> passthrough(final Class<T> clazz) {
|
||||
return ignoreNull(new EquivalentConverter<T>() {
|
||||
@Override
|
||||
public T getSpecific(Object generic) {
|
||||
return (T) generic;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGeneric(T specific) {
|
||||
return specific;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T> getSpecificType() {
|
||||
return clazz;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()}).
|
||||
* @param toHandle Function from wrapper to handle (i.e. {@code getHandle()})
|
||||
* @param fromHandle Function from handle to wrapper (i.e. {@code fromHandle(Object)})
|
||||
* @param <T> Wrapper type
|
||||
* @return A handle converter
|
||||
*/
|
||||
public static <T> EquivalentConverter<T> handle(final Function<T, Object> toHandle,
|
||||
final Function<Object, T> fromHandle, final Class<T> specificType) {
|
||||
return new EquivalentConverter<T>() {
|
||||
@Override
|
||||
public T getSpecific(Object generic) {
|
||||
return fromHandle.apply(generic);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGeneric(T specific) {
|
||||
return toHandle.apply(specific);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T> getSpecificType() {
|
||||
return specificType;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a generic array converter. Converts a NMS object array to and from a wrapper array by converting
|
||||
* each element individually.
|
||||
*
|
||||
* @param nmsClass NMS class
|
||||
* @param converter Underlying converter
|
||||
* @param <T> Generic type
|
||||
* @return An array converter
|
||||
*/
|
||||
public static <T> EquivalentConverter<T[]> array(final Class<?> nmsClass, final EquivalentConverter<T> converter) {
|
||||
return new EquivalentConverter<T[]>() {
|
||||
@Override
|
||||
public T[] getSpecific(Object generic) {
|
||||
Object[] array = (Object[]) generic;
|
||||
Class<T[]> clazz = getSpecificType();
|
||||
T[] result = clazz.cast(Array.newInstance(clazz.getComponentType(), array.length));
|
||||
|
||||
// Unwrap every item
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = converter.getSpecific(array[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGeneric(T[] specific) {
|
||||
Object[] result = (Object[]) Array.newInstance(nmsClass, specific.length);
|
||||
|
||||
// Wrap every item
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = converter.getGeneric(specific[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T[]> getSpecificType() {
|
||||
return (Class<T[]>) MinecraftReflection.getArrayClass(converter.getSpecificType());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static <T> EquivalentConverter<Optional<T>> optional(final EquivalentConverter<T> converter) {
|
||||
return new EquivalentConverter<Optional<T>>() {
|
||||
@Override
|
||||
public Object getGeneric(Optional<T> specific) {
|
||||
return specific.map(converter::getGeneric);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<T> getSpecific(Object generic) {
|
||||
Optional<Object> optional = (Optional<Object>) generic;
|
||||
return optional.map(converter::getSpecific);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Optional<T>> getSpecificType() {
|
||||
return (Class<Optional<T>>) Optional.empty().getClass();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2017 Dan Mulloy
|
||||
*
|
||||
* 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 version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
/**
|
||||
* Utility class for converters
|
||||
* @author dmulloy2
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class Converters {
|
||||
|
||||
/**
|
||||
* Returns a converter that ignores null elements, so that the underlying converter doesn't have to worry about them.
|
||||
* @param converter Underlying converter
|
||||
* @param <T> Element type
|
||||
* @return An ignore null converter
|
||||
*/
|
||||
public static <T> EquivalentConverter<T> ignoreNull(final EquivalentConverter<T> converter) {
|
||||
return new EquivalentConverter<T>() {
|
||||
@Override
|
||||
public T getSpecific(Object generic) {
|
||||
return generic != null ? converter.getSpecific(generic) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGeneric(T specific) {
|
||||
return specific != null ? converter.getGeneric(specific) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T> getSpecificType() {
|
||||
return converter.getSpecificType();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a converter that passes generic and specific values through without converting.
|
||||
* @param clazz Element class
|
||||
* @param <T> Element type
|
||||
* @return A passthrough converter
|
||||
*/
|
||||
public static <T> EquivalentConverter<T> passthrough(final Class<T> clazz) {
|
||||
return ignoreNull(new EquivalentConverter<T>() {
|
||||
@Override
|
||||
public T getSpecific(Object generic) {
|
||||
return (T) generic;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGeneric(T specific) {
|
||||
return specific;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T> getSpecificType() {
|
||||
return clazz;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()}).
|
||||
* @param toHandle Function from wrapper to handle (i.e. {@code getHandle()})
|
||||
* @param fromHandle Function from handle to wrapper (i.e. {@code fromHandle(Object)})
|
||||
* @param <T> Wrapper type
|
||||
* @return A handle converter
|
||||
*/
|
||||
public static <T> EquivalentConverter<T> handle(final Function<T, Object> toHandle,
|
||||
final Function<Object, T> fromHandle, final Class<T> specificType) {
|
||||
return new EquivalentConverter<T>() {
|
||||
@Override
|
||||
public T getSpecific(Object generic) {
|
||||
return fromHandle.apply(generic);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGeneric(T specific) {
|
||||
return toHandle.apply(specific);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T> getSpecificType() {
|
||||
return specificType;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a generic array converter. Converts a NMS object array to and from a wrapper array by converting
|
||||
* each element individually.
|
||||
*
|
||||
* @param nmsClass NMS class
|
||||
* @param converter Underlying converter
|
||||
* @param <T> Generic type
|
||||
* @return An array converter
|
||||
*/
|
||||
public static <T> EquivalentConverter<T[]> array(final Class<?> nmsClass, final EquivalentConverter<T> converter) {
|
||||
return new EquivalentConverter<T[]>() {
|
||||
@Override
|
||||
public T[] getSpecific(Object generic) {
|
||||
Object[] array = (Object[]) generic;
|
||||
Class<T[]> clazz = getSpecificType();
|
||||
T[] result = clazz.cast(Array.newInstance(clazz.getComponentType(), array.length));
|
||||
|
||||
// Unwrap every item
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = converter.getSpecific(array[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGeneric(T[] specific) {
|
||||
Object[] result = (Object[]) Array.newInstance(nmsClass, specific.length);
|
||||
|
||||
// Wrap every item
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = converter.getGeneric(specific[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T[]> getSpecificType() {
|
||||
return (Class<T[]>) MinecraftReflection.getArrayClass(converter.getSpecificType());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static <T> EquivalentConverter<Optional<T>> optional(final EquivalentConverter<T> converter) {
|
||||
return new EquivalentConverter<Optional<T>>() {
|
||||
@Override
|
||||
public Object getGeneric(Optional<T> specific) {
|
||||
return specific.map(converter::getGeneric);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<T> getSpecific(Object generic) {
|
||||
Optional<Object> optional = (Optional<Object>) generic;
|
||||
return optional.map(converter::getSpecific);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Optional<T>> getSpecificType() {
|
||||
return (Class<Optional<T>>) Optional.empty().getClass();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,103 +1,103 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.Direction;
|
||||
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public class MovingObjectPositionBlock implements Cloneable {
|
||||
private static final Class<?> NMS_CLASS = MinecraftReflection.getNullableNMS(
|
||||
"world.phys.MovingObjectPositionBlock", "world.phys.BlockHitResult", "MovingObjectPositionBlock");
|
||||
|
||||
private BlockPosition position;
|
||||
private Vector posVector;
|
||||
private Direction direction;
|
||||
private boolean insideBlock;
|
||||
|
||||
public MovingObjectPositionBlock() { }
|
||||
|
||||
public MovingObjectPositionBlock(BlockPosition position, Vector posVector, Direction direction, boolean insideBlock) {
|
||||
this.position = position;
|
||||
this.posVector = posVector;
|
||||
this.direction = direction;
|
||||
this.insideBlock = insideBlock;
|
||||
}
|
||||
|
||||
public static Class<?> getNmsClass() {
|
||||
return NMS_CLASS;
|
||||
}
|
||||
|
||||
public BlockPosition getBlockPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void setBlockPosition(BlockPosition position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public Vector getPosVector() {
|
||||
return posVector;
|
||||
}
|
||||
|
||||
public void setPosVector(Vector vector) {
|
||||
this.posVector = vector;
|
||||
}
|
||||
|
||||
public Direction getDirection() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
public void setDirection(Direction direction) {
|
||||
this.direction = direction;
|
||||
}
|
||||
|
||||
public boolean isInsideBlock() {
|
||||
return insideBlock;
|
||||
}
|
||||
|
||||
public void setInsideBlock(boolean insideBlock) {
|
||||
this.insideBlock = insideBlock;
|
||||
}
|
||||
|
||||
private static ConstructorAccessor constructor;
|
||||
|
||||
public static EquivalentConverter<MovingObjectPositionBlock> getConverter() {
|
||||
return Converters.ignoreNull(new EquivalentConverter<MovingObjectPositionBlock>() {
|
||||
@Override
|
||||
public Object getGeneric(MovingObjectPositionBlock specific) {
|
||||
if (constructor == null) {
|
||||
constructor = Accessors.getConstructorAccessor(NMS_CLASS,
|
||||
MinecraftReflection.getVec3DClass(),
|
||||
EnumWrappers.getDirectionClass(),
|
||||
MinecraftReflection.getBlockPositionClass(),
|
||||
boolean.class);
|
||||
}
|
||||
|
||||
Object nmsVector = BukkitConverters.getVectorConverter().getGeneric(specific.posVector);
|
||||
Object nmsDirection = EnumWrappers.getDirectionConverter().getGeneric(specific.direction);
|
||||
Object nmsBlockPos = BlockPosition.getConverter().getGeneric(specific.position);
|
||||
|
||||
return constructor.invoke(nmsVector, nmsDirection, nmsBlockPos, specific.insideBlock);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MovingObjectPositionBlock getSpecific(Object generic) {
|
||||
StructureModifier<Object> modifier = new StructureModifier<>(generic.getClass()).withTarget(generic);
|
||||
Direction direction = modifier.withType(EnumWrappers.getDirectionClass(), EnumWrappers.getDirectionConverter()).read(0);
|
||||
BlockPosition blockPos = modifier.withType(MinecraftReflection.getBlockPositionClass(), BlockPosition.getConverter()).read(0);
|
||||
Vector posVector = modifier.withType(MinecraftReflection.getVec3DClass(), BukkitConverters.getVectorConverter()).read(0);
|
||||
boolean insideBlock = (boolean) modifier.withType(boolean.class).read(1);
|
||||
return new MovingObjectPositionBlock(blockPos, posVector, direction, insideBlock);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<MovingObjectPositionBlock> getSpecificType() {
|
||||
return MovingObjectPositionBlock.class;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.Direction;
|
||||
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public class MovingObjectPositionBlock implements Cloneable {
|
||||
private static final Class<?> NMS_CLASS = MinecraftReflection.getNullableNMS(
|
||||
"world.phys.MovingObjectPositionBlock", "world.phys.BlockHitResult", "MovingObjectPositionBlock");
|
||||
|
||||
private BlockPosition position;
|
||||
private Vector posVector;
|
||||
private Direction direction;
|
||||
private boolean insideBlock;
|
||||
|
||||
public MovingObjectPositionBlock() { }
|
||||
|
||||
public MovingObjectPositionBlock(BlockPosition position, Vector posVector, Direction direction, boolean insideBlock) {
|
||||
this.position = position;
|
||||
this.posVector = posVector;
|
||||
this.direction = direction;
|
||||
this.insideBlock = insideBlock;
|
||||
}
|
||||
|
||||
public static Class<?> getNmsClass() {
|
||||
return NMS_CLASS;
|
||||
}
|
||||
|
||||
public BlockPosition getBlockPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void setBlockPosition(BlockPosition position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public Vector getPosVector() {
|
||||
return posVector;
|
||||
}
|
||||
|
||||
public void setPosVector(Vector vector) {
|
||||
this.posVector = vector;
|
||||
}
|
||||
|
||||
public Direction getDirection() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
public void setDirection(Direction direction) {
|
||||
this.direction = direction;
|
||||
}
|
||||
|
||||
public boolean isInsideBlock() {
|
||||
return insideBlock;
|
||||
}
|
||||
|
||||
public void setInsideBlock(boolean insideBlock) {
|
||||
this.insideBlock = insideBlock;
|
||||
}
|
||||
|
||||
private static ConstructorAccessor constructor;
|
||||
|
||||
public static EquivalentConverter<MovingObjectPositionBlock> getConverter() {
|
||||
return Converters.ignoreNull(new EquivalentConverter<MovingObjectPositionBlock>() {
|
||||
@Override
|
||||
public Object getGeneric(MovingObjectPositionBlock specific) {
|
||||
if (constructor == null) {
|
||||
constructor = Accessors.getConstructorAccessor(NMS_CLASS,
|
||||
MinecraftReflection.getVec3DClass(),
|
||||
EnumWrappers.getDirectionClass(),
|
||||
MinecraftReflection.getBlockPositionClass(),
|
||||
boolean.class);
|
||||
}
|
||||
|
||||
Object nmsVector = BukkitConverters.getVectorConverter().getGeneric(specific.posVector);
|
||||
Object nmsDirection = EnumWrappers.getDirectionConverter().getGeneric(specific.direction);
|
||||
Object nmsBlockPos = BlockPosition.getConverter().getGeneric(specific.position);
|
||||
|
||||
return constructor.invoke(nmsVector, nmsDirection, nmsBlockPos, specific.insideBlock);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MovingObjectPositionBlock getSpecific(Object generic) {
|
||||
StructureModifier<Object> modifier = new StructureModifier<>(generic.getClass()).withTarget(generic);
|
||||
Direction direction = modifier.withType(EnumWrappers.getDirectionClass(), EnumWrappers.getDirectionConverter()).read(0);
|
||||
BlockPosition blockPos = modifier.withType(MinecraftReflection.getBlockPositionClass(), BlockPosition.getConverter()).read(0);
|
||||
Vector posVector = modifier.withType(MinecraftReflection.getVec3DClass(), BukkitConverters.getVectorConverter()).read(0);
|
||||
boolean insideBlock = (boolean) modifier.withType(boolean.class).read(1);
|
||||
return new MovingObjectPositionBlock(blockPos, posVector, direction, insideBlock);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<MovingObjectPositionBlock> getSpecificType() {
|
||||
return MovingObjectPositionBlock.class;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,43 +1,43 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class Pair<A, B> {
|
||||
private A first;
|
||||
private B second;
|
||||
|
||||
public Pair(A first, B second) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
public A getFirst() {
|
||||
return first;
|
||||
}
|
||||
|
||||
public B getSecond() {
|
||||
return second;
|
||||
}
|
||||
|
||||
public void setFirst(A first) {
|
||||
this.first = first;
|
||||
}
|
||||
|
||||
public void setSecond(B second) {
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Pair<?, ?> pair = (Pair<?, ?>) o;
|
||||
return Objects.equals(first, pair.first) &&
|
||||
Objects.equals(second, pair.second);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(first, second);
|
||||
}
|
||||
}
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class Pair<A, B> {
|
||||
private A first;
|
||||
private B second;
|
||||
|
||||
public Pair(A first, B second) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
public A getFirst() {
|
||||
return first;
|
||||
}
|
||||
|
||||
public B getSecond() {
|
||||
return second;
|
||||
}
|
||||
|
||||
public void setFirst(A first) {
|
||||
this.first = first;
|
||||
}
|
||||
|
||||
public void setSecond(B second) {
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Pair<?, ?> pair = (Pair<?, ?>) o;
|
||||
return Objects.equals(first, pair.first) &&
|
||||
Objects.equals(second, pair.second);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(first, second);
|
||||
}
|
||||
}
|
||||
|
@ -1,127 +1,127 @@
|
||||
/**
|
||||
* (c) 2016 dmulloy2
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
/**
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class Vector3F {
|
||||
protected float x;
|
||||
protected float y;
|
||||
protected float z;
|
||||
|
||||
public Vector3F() {
|
||||
this(0, 0, 0);
|
||||
}
|
||||
|
||||
public Vector3F(float x, float y, float z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public float getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public Vector3F setX(float x) {
|
||||
this.x = x;
|
||||
return this;
|
||||
}
|
||||
|
||||
public float getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public Vector3F setY(float y) {
|
||||
this.y = y;
|
||||
return this;
|
||||
}
|
||||
|
||||
public float getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
public Vector3F setZ(float z) {
|
||||
this.z = z;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + Float.floatToIntBits(x);
|
||||
result = prime * result + Float.floatToIntBits(y);
|
||||
result = prime * result + Float.floatToIntBits(z);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
|
||||
if (obj instanceof Vector3F) {
|
||||
Vector3F that = (Vector3F) obj;
|
||||
if (Float.floatToIntBits(x) != Float.floatToIntBits(that.x))
|
||||
return false;
|
||||
if (Float.floatToIntBits(y) != Float.floatToIntBits(that.y))
|
||||
return false;
|
||||
if (Float.floatToIntBits(z) != Float.floatToIntBits(that.z))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Constructor<?> constructor = null;
|
||||
private static final Class<?> NMS_CLASS = MinecraftReflection.getNullableNMS("core.Vector3f", "core.Rotations", "Vector3f");
|
||||
|
||||
public static Class<?> getMinecraftClass() {
|
||||
return NMS_CLASS;
|
||||
}
|
||||
|
||||
public static EquivalentConverter<Vector3F> getConverter() {
|
||||
return Converters.ignoreNull(new EquivalentConverter<Vector3F>() {
|
||||
@Override
|
||||
public Class<Vector3F> getSpecificType() {
|
||||
return Vector3F.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGeneric(Vector3F specific) {
|
||||
if (constructor == null) {
|
||||
try {
|
||||
constructor = NMS_CLASS.getConstructor(float.class, float.class, float.class);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Failed to find constructor for Vector3f", ex);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return constructor.newInstance(specific.x, specific.y, specific.z);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Failed to create new instance of Vector3f", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3F getSpecific(Object generic) {
|
||||
StructureModifier<Float> modifier = new StructureModifier<Float>(generic.getClass())
|
||||
.withTarget(generic).withType(float.class);
|
||||
float x = modifier.read(0);
|
||||
float y = modifier.read(1);
|
||||
float z = modifier.read(2);
|
||||
return new Vector3F(x, y, z);
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* (c) 2016 dmulloy2
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
/**
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class Vector3F {
|
||||
protected float x;
|
||||
protected float y;
|
||||
protected float z;
|
||||
|
||||
public Vector3F() {
|
||||
this(0, 0, 0);
|
||||
}
|
||||
|
||||
public Vector3F(float x, float y, float z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public float getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public Vector3F setX(float x) {
|
||||
this.x = x;
|
||||
return this;
|
||||
}
|
||||
|
||||
public float getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public Vector3F setY(float y) {
|
||||
this.y = y;
|
||||
return this;
|
||||
}
|
||||
|
||||
public float getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
public Vector3F setZ(float z) {
|
||||
this.z = z;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + Float.floatToIntBits(x);
|
||||
result = prime * result + Float.floatToIntBits(y);
|
||||
result = prime * result + Float.floatToIntBits(z);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
|
||||
if (obj instanceof Vector3F) {
|
||||
Vector3F that = (Vector3F) obj;
|
||||
if (Float.floatToIntBits(x) != Float.floatToIntBits(that.x))
|
||||
return false;
|
||||
if (Float.floatToIntBits(y) != Float.floatToIntBits(that.y))
|
||||
return false;
|
||||
if (Float.floatToIntBits(z) != Float.floatToIntBits(that.z))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Constructor<?> constructor = null;
|
||||
private static final Class<?> NMS_CLASS = MinecraftReflection.getNullableNMS("core.Vector3f", "core.Rotations", "Vector3f");
|
||||
|
||||
public static Class<?> getMinecraftClass() {
|
||||
return NMS_CLASS;
|
||||
}
|
||||
|
||||
public static EquivalentConverter<Vector3F> getConverter() {
|
||||
return Converters.ignoreNull(new EquivalentConverter<Vector3F>() {
|
||||
@Override
|
||||
public Class<Vector3F> getSpecificType() {
|
||||
return Vector3F.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGeneric(Vector3F specific) {
|
||||
if (constructor == null) {
|
||||
try {
|
||||
constructor = NMS_CLASS.getConstructor(float.class, float.class, float.class);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Failed to find constructor for Vector3f", ex);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return constructor.newInstance(specific.x, specific.y, specific.z);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Failed to create new instance of Vector3f", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3F getSpecific(Object generic) {
|
||||
StructureModifier<Float> modifier = new StructureModifier<Float>(generic.getClass())
|
||||
.withTarget(generic).withType(float.class);
|
||||
float x = modifier.read(0);
|
||||
float y = modifier.read(1);
|
||||
float z = modifier.read(2);
|
||||
return new Vector3F(x, y, z);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -1,169 +1,169 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.mojang.math.Vector3fa;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
/**
|
||||
* Represents an immutable wrapped ParticleParam in 1.13
|
||||
*/
|
||||
public class WrappedParticle<T> {
|
||||
private static MethodAccessor toBukkit;
|
||||
private static MethodAccessor toNMS;
|
||||
private static MethodAccessor toCraftData;
|
||||
|
||||
private static void ensureMethods() {
|
||||
if (toBukkit != null && toNMS != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(MinecraftReflection.getCraftBukkitClass("CraftParticle"));
|
||||
FuzzyMethodContract contract = FuzzyMethodContract
|
||||
.newBuilder()
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.returnTypeExact(Particle.class)
|
||||
.parameterExactType(MinecraftReflection.getParticleParam())
|
||||
.build();
|
||||
toBukkit = Accessors.getMethodAccessor(fuzzy.getMethod(contract));
|
||||
|
||||
contract = FuzzyMethodContract
|
||||
.newBuilder()
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.returnTypeExact(MinecraftReflection.getParticleParam())
|
||||
.parameterCount(2)
|
||||
.build();
|
||||
toNMS = Accessors.getMethodAccessor(fuzzy.getMethod(contract));
|
||||
|
||||
Class<?> cbData = MinecraftReflection.getCraftBukkitClass("block.data.CraftBlockData");
|
||||
fuzzy = FuzzyReflection.fromClass(cbData);
|
||||
contract = FuzzyMethodContract
|
||||
.newBuilder()
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.returnTypeExact(cbData)
|
||||
.parameterExactArray(MinecraftReflection.getIBlockDataClass())
|
||||
.build();
|
||||
toCraftData = Accessors.getMethodAccessor(fuzzy.getMethod(contract));
|
||||
}
|
||||
|
||||
private final Particle particle;
|
||||
private final T data;
|
||||
private final Object handle;
|
||||
|
||||
private WrappedParticle(Object handle, Particle particle, T data) {
|
||||
this.handle = handle;
|
||||
this.particle = particle;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return This particle's Bukkit type
|
||||
*/
|
||||
public Particle getParticle() {
|
||||
return particle;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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},
|
||||
* for Item crack particles, it will be an {@link ItemStack}, and for redstone particles it will
|
||||
* be {@link Particle.DustOptions}
|
||||
*
|
||||
* @return The particle data
|
||||
*/
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return NMS handle
|
||||
*/
|
||||
public Object getHandle() {
|
||||
return handle;
|
||||
}
|
||||
|
||||
public static WrappedParticle fromHandle(Object handle) {
|
||||
ensureMethods();
|
||||
|
||||
Particle bukkit = (Particle) toBukkit.invoke(null, handle);
|
||||
Object data = null;
|
||||
|
||||
switch (bukkit) {
|
||||
case BLOCK_CRACK:
|
||||
case BLOCK_DUST:
|
||||
case FALLING_DUST:
|
||||
data = getBlockData(handle);
|
||||
break;
|
||||
case ITEM_CRACK:
|
||||
data = getItem(handle);
|
||||
break;
|
||||
case REDSTONE:
|
||||
data = getRedstone(handle);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return new WrappedParticle<>(handle, bukkit, data);
|
||||
}
|
||||
|
||||
private static WrappedBlockData getBlockData(Object handle) {
|
||||
return new StructureModifier<>(handle.getClass())
|
||||
.withTarget(handle)
|
||||
.withType(MinecraftReflection.getIBlockDataClass(), BukkitConverters.getWrappedBlockDataConverter())
|
||||
.read(0);
|
||||
}
|
||||
|
||||
private static Object getItem(Object handle) {
|
||||
return new StructureModifier<>(handle.getClass())
|
||||
.withTarget(handle)
|
||||
.withType(MinecraftReflection.getItemStackClass(), BukkitConverters.getItemStackConverter())
|
||||
.read(0);
|
||||
}
|
||||
|
||||
private static Object getRedstone(Object handle) {
|
||||
int r, g, b;
|
||||
float alpha;
|
||||
|
||||
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
|
||||
StructureModifier<Object> modifier = new StructureModifier<>(handle.getClass()).withTarget(handle);
|
||||
Vector3fa rgb = (Vector3fa) modifier.withType(Vector3fa.class).read(0);
|
||||
|
||||
r = (int) (rgb.a() * 255);
|
||||
g = (int) (rgb.b() * 255);
|
||||
b = (int) (rgb.c() * 255);
|
||||
alpha = (float) modifier.withType(float.class).read(0);
|
||||
} else {
|
||||
StructureModifier<Float> modifier = new StructureModifier<>(handle.getClass()).withTarget(handle).withType(float.class);
|
||||
r = (int) (modifier.read(0) * 255);
|
||||
g = (int) (modifier.read(1) * 255);
|
||||
b = (int) (modifier.read(2) * 255);
|
||||
alpha = modifier.read(3);
|
||||
}
|
||||
|
||||
return new Particle.DustOptions(Color.fromRGB(r, g, b), alpha);
|
||||
}
|
||||
|
||||
public static <T> WrappedParticle<T> create(Particle particle, T data) {
|
||||
ensureMethods();
|
||||
|
||||
Object bukkitData = data;
|
||||
if (data instanceof WrappedBlockData) {
|
||||
WrappedBlockData blockData = (WrappedBlockData) data;
|
||||
bukkitData = toCraftData.invoke(null, blockData.getHandle());
|
||||
}
|
||||
|
||||
Object handle = toNMS.invoke(null, particle, bukkitData);
|
||||
return new WrappedParticle<>(handle, particle, data);
|
||||
}
|
||||
}
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.mojang.math.Vector3fa;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
/**
|
||||
* Represents an immutable wrapped ParticleParam in 1.13
|
||||
*/
|
||||
public class WrappedParticle<T> {
|
||||
private static MethodAccessor toBukkit;
|
||||
private static MethodAccessor toNMS;
|
||||
private static MethodAccessor toCraftData;
|
||||
|
||||
private static void ensureMethods() {
|
||||
if (toBukkit != null && toNMS != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(MinecraftReflection.getCraftBukkitClass("CraftParticle"));
|
||||
FuzzyMethodContract contract = FuzzyMethodContract
|
||||
.newBuilder()
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.returnTypeExact(Particle.class)
|
||||
.parameterExactType(MinecraftReflection.getParticleParam())
|
||||
.build();
|
||||
toBukkit = Accessors.getMethodAccessor(fuzzy.getMethod(contract));
|
||||
|
||||
contract = FuzzyMethodContract
|
||||
.newBuilder()
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.returnTypeExact(MinecraftReflection.getParticleParam())
|
||||
.parameterCount(2)
|
||||
.build();
|
||||
toNMS = Accessors.getMethodAccessor(fuzzy.getMethod(contract));
|
||||
|
||||
Class<?> cbData = MinecraftReflection.getCraftBukkitClass("block.data.CraftBlockData");
|
||||
fuzzy = FuzzyReflection.fromClass(cbData);
|
||||
contract = FuzzyMethodContract
|
||||
.newBuilder()
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.returnTypeExact(cbData)
|
||||
.parameterExactArray(MinecraftReflection.getIBlockDataClass())
|
||||
.build();
|
||||
toCraftData = Accessors.getMethodAccessor(fuzzy.getMethod(contract));
|
||||
}
|
||||
|
||||
private final Particle particle;
|
||||
private final T data;
|
||||
private final Object handle;
|
||||
|
||||
private WrappedParticle(Object handle, Particle particle, T data) {
|
||||
this.handle = handle;
|
||||
this.particle = particle;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return This particle's Bukkit type
|
||||
*/
|
||||
public Particle getParticle() {
|
||||
return particle;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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},
|
||||
* for Item crack particles, it will be an {@link ItemStack}, and for redstone particles it will
|
||||
* be {@link Particle.DustOptions}
|
||||
*
|
||||
* @return The particle data
|
||||
*/
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return NMS handle
|
||||
*/
|
||||
public Object getHandle() {
|
||||
return handle;
|
||||
}
|
||||
|
||||
public static WrappedParticle fromHandle(Object handle) {
|
||||
ensureMethods();
|
||||
|
||||
Particle bukkit = (Particle) toBukkit.invoke(null, handle);
|
||||
Object data = null;
|
||||
|
||||
switch (bukkit) {
|
||||
case BLOCK_CRACK:
|
||||
case BLOCK_DUST:
|
||||
case FALLING_DUST:
|
||||
data = getBlockData(handle);
|
||||
break;
|
||||
case ITEM_CRACK:
|
||||
data = getItem(handle);
|
||||
break;
|
||||
case REDSTONE:
|
||||
data = getRedstone(handle);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return new WrappedParticle<>(handle, bukkit, data);
|
||||
}
|
||||
|
||||
private static WrappedBlockData getBlockData(Object handle) {
|
||||
return new StructureModifier<>(handle.getClass())
|
||||
.withTarget(handle)
|
||||
.withType(MinecraftReflection.getIBlockDataClass(), BukkitConverters.getWrappedBlockDataConverter())
|
||||
.read(0);
|
||||
}
|
||||
|
||||
private static Object getItem(Object handle) {
|
||||
return new StructureModifier<>(handle.getClass())
|
||||
.withTarget(handle)
|
||||
.withType(MinecraftReflection.getItemStackClass(), BukkitConverters.getItemStackConverter())
|
||||
.read(0);
|
||||
}
|
||||
|
||||
private static Object getRedstone(Object handle) {
|
||||
int r, g, b;
|
||||
float alpha;
|
||||
|
||||
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
|
||||
StructureModifier<Object> modifier = new StructureModifier<>(handle.getClass()).withTarget(handle);
|
||||
Vector3fa rgb = (Vector3fa) modifier.withType(Vector3fa.class).read(0);
|
||||
|
||||
r = (int) (rgb.a() * 255);
|
||||
g = (int) (rgb.b() * 255);
|
||||
b = (int) (rgb.c() * 255);
|
||||
alpha = (float) modifier.withType(float.class).read(0);
|
||||
} else {
|
||||
StructureModifier<Float> modifier = new StructureModifier<>(handle.getClass()).withTarget(handle).withType(float.class);
|
||||
r = (int) (modifier.read(0) * 255);
|
||||
g = (int) (modifier.read(1) * 255);
|
||||
b = (int) (modifier.read(2) * 255);
|
||||
alpha = modifier.read(3);
|
||||
}
|
||||
|
||||
return new Particle.DustOptions(Color.fromRGB(r, g, b), alpha);
|
||||
}
|
||||
|
||||
public static <T> WrappedParticle<T> create(Particle particle, T data) {
|
||||
ensureMethods();
|
||||
|
||||
Object bukkitData = data;
|
||||
if (data instanceof WrappedBlockData) {
|
||||
WrappedBlockData blockData = (WrappedBlockData) data;
|
||||
bukkitData = toCraftData.invoke(null, blockData.getHandle());
|
||||
}
|
||||
|
||||
Object handle = toNMS.invoke(null, particle, bukkitData);
|
||||
return new WrappedParticle<>(handle, particle, data);
|
||||
}
|
||||
}
|
||||
|
@ -1,84 +1,84 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
public class WrappedVillagerData extends AbstractWrapper implements ClonableWrapper {
|
||||
private static final Class<?> NMS_CLASS = MinecraftReflection.getNullableNMS(
|
||||
"world.entity.npc.VillagerData","VillagerData");
|
||||
private static final Class<?> TYPE_CLASS = MinecraftReflection.getNullableNMS(
|
||||
"world.entity.npc.VillagerType", "VillagerType");
|
||||
private static final Class<?> PROF_CLASS = MinecraftReflection.getNullableNMS(
|
||||
"world.entity.npc.VillagerProfession", "VillagerProfession");
|
||||
|
||||
private static EquivalentConverter<Type> TYPE_CONVERTER;
|
||||
private static EquivalentConverter<Profession> PROF_CONVERTER;
|
||||
|
||||
static {
|
||||
if (NMS_CLASS != null) {
|
||||
TYPE_CONVERTER = new EnumWrappers.FauxEnumConverter<>(Type.class, TYPE_CLASS);
|
||||
PROF_CONVERTER = new EnumWrappers.FauxEnumConverter<>(Profession.class, PROF_CLASS);
|
||||
}
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
DESERT, JUNGLE, PLAINS, SAVANNA, SNOW, SWAMP, TAIGA
|
||||
}
|
||||
|
||||
public enum Profession {
|
||||
NONE, ARMORER, BUTCHER, CARTOGRAPHER, CLERIC, FARMER, FISHERMAN,
|
||||
FLETCHER, LEATHERWORKER, LIBRARIAN, MASON, NITWIT, SHEPHERD,
|
||||
TOOLSMITH, WEAPONSMITH
|
||||
}
|
||||
|
||||
private StructureModifier<Object> modifier;
|
||||
|
||||
private WrappedVillagerData(Object handle) {
|
||||
super(NMS_CLASS);
|
||||
setHandle(handle);
|
||||
|
||||
modifier = new StructureModifier<>(NMS_CLASS).withTarget(handle);
|
||||
}
|
||||
|
||||
public static WrappedVillagerData fromHandle(Object handle) {
|
||||
return new WrappedVillagerData(handle);
|
||||
}
|
||||
|
||||
private static ConstructorAccessor CONSTRUCTOR;
|
||||
|
||||
public static WrappedVillagerData fromValues(Type type, Profession profession, int level) {
|
||||
Object genericType = TYPE_CONVERTER.getGeneric(type);
|
||||
Object genericProf = PROF_CONVERTER.getGeneric(profession);
|
||||
|
||||
if (CONSTRUCTOR == null) {
|
||||
CONSTRUCTOR = Accessors.getConstructorAccessor(NMS_CLASS, TYPE_CLASS, PROF_CLASS, int.class);
|
||||
}
|
||||
|
||||
Object handle = CONSTRUCTOR.invoke(genericType, genericProf, level);
|
||||
return fromHandle(handle);
|
||||
}
|
||||
|
||||
public static Class<?> getNmsClass() {
|
||||
return NMS_CLASS;
|
||||
}
|
||||
|
||||
public int getLevel() {
|
||||
return modifier.<Integer>withType(int.class).read(0);
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return modifier.withType(TYPE_CLASS, TYPE_CONVERTER).read(0);
|
||||
}
|
||||
|
||||
public Profession getProfession() {
|
||||
return modifier.withType(PROF_CLASS, PROF_CONVERTER).read(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WrappedVillagerData deepClone() {
|
||||
return WrappedVillagerData.fromValues(getType(), getProfession(), getLevel());
|
||||
}
|
||||
}
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
public class WrappedVillagerData extends AbstractWrapper implements ClonableWrapper {
|
||||
private static final Class<?> NMS_CLASS = MinecraftReflection.getNullableNMS(
|
||||
"world.entity.npc.VillagerData","VillagerData");
|
||||
private static final Class<?> TYPE_CLASS = MinecraftReflection.getNullableNMS(
|
||||
"world.entity.npc.VillagerType", "VillagerType");
|
||||
private static final Class<?> PROF_CLASS = MinecraftReflection.getNullableNMS(
|
||||
"world.entity.npc.VillagerProfession", "VillagerProfession");
|
||||
|
||||
private static EquivalentConverter<Type> TYPE_CONVERTER;
|
||||
private static EquivalentConverter<Profession> PROF_CONVERTER;
|
||||
|
||||
static {
|
||||
if (NMS_CLASS != null) {
|
||||
TYPE_CONVERTER = new EnumWrappers.FauxEnumConverter<>(Type.class, TYPE_CLASS);
|
||||
PROF_CONVERTER = new EnumWrappers.FauxEnumConverter<>(Profession.class, PROF_CLASS);
|
||||
}
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
DESERT, JUNGLE, PLAINS, SAVANNA, SNOW, SWAMP, TAIGA
|
||||
}
|
||||
|
||||
public enum Profession {
|
||||
NONE, ARMORER, BUTCHER, CARTOGRAPHER, CLERIC, FARMER, FISHERMAN,
|
||||
FLETCHER, LEATHERWORKER, LIBRARIAN, MASON, NITWIT, SHEPHERD,
|
||||
TOOLSMITH, WEAPONSMITH
|
||||
}
|
||||
|
||||
private StructureModifier<Object> modifier;
|
||||
|
||||
private WrappedVillagerData(Object handle) {
|
||||
super(NMS_CLASS);
|
||||
setHandle(handle);
|
||||
|
||||
modifier = new StructureModifier<>(NMS_CLASS).withTarget(handle);
|
||||
}
|
||||
|
||||
public static WrappedVillagerData fromHandle(Object handle) {
|
||||
return new WrappedVillagerData(handle);
|
||||
}
|
||||
|
||||
private static ConstructorAccessor CONSTRUCTOR;
|
||||
|
||||
public static WrappedVillagerData fromValues(Type type, Profession profession, int level) {
|
||||
Object genericType = TYPE_CONVERTER.getGeneric(type);
|
||||
Object genericProf = PROF_CONVERTER.getGeneric(profession);
|
||||
|
||||
if (CONSTRUCTOR == null) {
|
||||
CONSTRUCTOR = Accessors.getConstructorAccessor(NMS_CLASS, TYPE_CLASS, PROF_CLASS, int.class);
|
||||
}
|
||||
|
||||
Object handle = CONSTRUCTOR.invoke(genericType, genericProf, level);
|
||||
return fromHandle(handle);
|
||||
}
|
||||
|
||||
public static Class<?> getNmsClass() {
|
||||
return NMS_CLASS;
|
||||
}
|
||||
|
||||
public int getLevel() {
|
||||
return modifier.<Integer>withType(int.class).read(0);
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return modifier.withType(TYPE_CLASS, TYPE_CONVERTER).read(0);
|
||||
}
|
||||
|
||||
public Profession getProfession() {
|
||||
return modifier.withType(PROF_CLASS, PROF_CONVERTER).read(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WrappedVillagerData deepClone() {
|
||||
return WrappedVillagerData.fromValues(getType(), getProfession(), getLevel());
|
||||
}
|
||||
}
|
||||
|
@ -1,45 +1,45 @@
|
||||
name: ProtocolLib
|
||||
version: ${project.fullVersion}
|
||||
description: Provides read/write access to the Minecraft protocol.
|
||||
authors: [dmulloy2, comphenix]
|
||||
|
||||
main: com.comphenix.protocol.ProtocolLib
|
||||
load: STARTUP
|
||||
database: false
|
||||
api-version: "1.13"
|
||||
|
||||
commands:
|
||||
protocol:
|
||||
description: Performs administrative tasks regarding ProtocolLib.
|
||||
usage: /<command> config|check|update|timings|listeners|version|dump
|
||||
permission: protocol.admin
|
||||
permission-message: You don't have <permission>
|
||||
packet:
|
||||
description: Add or remove a simple packet listener.
|
||||
usage: /<command> add|remove|names client|server [ID start]-[ID stop] [detailed]
|
||||
permission: protocol.admin
|
||||
permission-message: You don't have <permission>
|
||||
filter:
|
||||
description: Add or remove programmable filters to the packet listeners.
|
||||
usage: /<command> add|remove name [ID start]-[ID stop]
|
||||
aliases: [packet_filter]
|
||||
permission: protocol.admin
|
||||
permission-message: You don't have <permission>
|
||||
packetlog:
|
||||
description: Logs hex representations of packets to a file or console
|
||||
usage: /<command> <protocol> <sender> <packet> [location]
|
||||
permission: protocol.admin
|
||||
permission-message: You don't have <permission>
|
||||
|
||||
permissions:
|
||||
protocol.*:
|
||||
description: Gives access to everything.
|
||||
children:
|
||||
protocol.admin: true
|
||||
protocol.info: true
|
||||
protocol.admin:
|
||||
description: Able to initiate the update process, and can configure debug mode.
|
||||
default: op
|
||||
protocol.info:
|
||||
description: Can read update notifications and error reports.
|
||||
name: ProtocolLib
|
||||
version: ${project.fullVersion}
|
||||
description: Provides read/write access to the Minecraft protocol.
|
||||
authors: [dmulloy2, comphenix]
|
||||
|
||||
main: com.comphenix.protocol.ProtocolLib
|
||||
load: STARTUP
|
||||
database: false
|
||||
api-version: "1.13"
|
||||
|
||||
commands:
|
||||
protocol:
|
||||
description: Performs administrative tasks regarding ProtocolLib.
|
||||
usage: /<command> config|check|update|timings|listeners|version|dump
|
||||
permission: protocol.admin
|
||||
permission-message: You don't have <permission>
|
||||
packet:
|
||||
description: Add or remove a simple packet listener.
|
||||
usage: /<command> add|remove|names client|server [ID start]-[ID stop] [detailed]
|
||||
permission: protocol.admin
|
||||
permission-message: You don't have <permission>
|
||||
filter:
|
||||
description: Add or remove programmable filters to the packet listeners.
|
||||
usage: /<command> add|remove name [ID start]-[ID stop]
|
||||
aliases: [packet_filter]
|
||||
permission: protocol.admin
|
||||
permission-message: You don't have <permission>
|
||||
packetlog:
|
||||
description: Logs hex representations of packets to a file or console
|
||||
usage: /<command> <protocol> <sender> <packet> [location]
|
||||
permission: protocol.admin
|
||||
permission-message: You don't have <permission>
|
||||
|
||||
permissions:
|
||||
protocol.*:
|
||||
description: Gives access to everything.
|
||||
children:
|
||||
protocol.admin: true
|
||||
protocol.info: true
|
||||
protocol.admin:
|
||||
description: Able to initiate the update process, and can configure debug mode.
|
||||
default: op
|
||||
protocol.info:
|
||||
description: Can read update notifications and error reports.
|
||||
default: op
|
@ -1,126 +1,126 @@
|
||||
package com.comphenix.protocol;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflectionTestUtil;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.core.IRegistry;
|
||||
import net.minecraft.server.DispenserRegistry;
|
||||
import net.minecraft.server.level.WorldServer;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemFactory;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.util.Versioning;
|
||||
import org.spigotmc.SpigotWorldConfig;
|
||||
|
||||
/**
|
||||
* Used to ensure that ProtocolLib and Bukkit is prepared to be tested.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public class BukkitInitialization {
|
||||
|
||||
private static final BukkitInitialization instance = new BukkitInitialization();
|
||||
private boolean initialized;
|
||||
private boolean packaged;
|
||||
|
||||
private BukkitInitialization() {
|
||||
System.out.println("Created new BukkitInitialization on " + Thread.currentThread().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Statically initializes the mock server for unit testing
|
||||
*/
|
||||
public static synchronized void initializeAll() {
|
||||
instance.initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize Bukkit and ProtocolLib such that we can perfrom unit testing
|
||||
*/
|
||||
private void initialize() {
|
||||
if (!this.initialized) {
|
||||
// Denote that we're done
|
||||
this.initialized = true;
|
||||
|
||||
try {
|
||||
LogManager.getLogger();
|
||||
} catch (Throwable ex) {
|
||||
// Happens only on my Jenkins, but if it errors here it works when it matters
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
instance.setPackage();
|
||||
|
||||
SharedConstants.a();
|
||||
DispenserRegistry.a();
|
||||
|
||||
try {
|
||||
IRegistry.class.getName();
|
||||
} catch (Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
String releaseTarget = SharedConstants.b().getReleaseTarget();
|
||||
String serverVersion = CraftServer.class.getPackage().getImplementationVersion();
|
||||
|
||||
// Mock the server object
|
||||
Server mockedServer = mock(Server.class);
|
||||
|
||||
when(mockedServer.getLogger()).thenReturn(java.util.logging.Logger.getLogger("Minecraft"));
|
||||
when(mockedServer.getName()).thenReturn("Mock Server");
|
||||
when(mockedServer.getVersion()).thenReturn(serverVersion + " (MC: " + releaseTarget + ")");
|
||||
when(mockedServer.getBukkitVersion()).thenReturn(Versioning.getBukkitVersion());
|
||||
|
||||
when(mockedServer.getItemFactory()).thenReturn(CraftItemFactory.instance());
|
||||
when(mockedServer.isPrimaryThread()).thenReturn(true);
|
||||
|
||||
WorldServer nmsWorld = mock(WorldServer.class);
|
||||
|
||||
SpigotWorldConfig mockWorldConfig = mock(SpigotWorldConfig.class);
|
||||
|
||||
try {
|
||||
FieldAccessor spigotConfig = Accessors.getFieldAccessor(nmsWorld.getClass().getField("spigotConfig"));
|
||||
spigotConfig.set(nmsWorld, mockWorldConfig);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
CraftWorld world = mock(CraftWorld.class);
|
||||
when(world.getHandle()).thenReturn(nmsWorld);
|
||||
|
||||
List<World> worlds = Collections.singletonList(world);
|
||||
when(mockedServer.getWorlds()).thenReturn(worlds);
|
||||
|
||||
// Inject this fake server
|
||||
Bukkit.setServer(mockedServer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that package names are correctly set up.
|
||||
*/
|
||||
private void setPackage() {
|
||||
if (!this.packaged) {
|
||||
this.packaged = true;
|
||||
|
||||
try {
|
||||
LogManager.getLogger();
|
||||
} catch (Throwable ex) {
|
||||
// Happens only on my Jenkins, but if it errors here it works when it matters
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
MinecraftReflectionTestUtil.init();
|
||||
}
|
||||
}
|
||||
package com.comphenix.protocol;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflectionTestUtil;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.core.IRegistry;
|
||||
import net.minecraft.server.DispenserRegistry;
|
||||
import net.minecraft.server.level.WorldServer;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemFactory;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.util.Versioning;
|
||||
import org.spigotmc.SpigotWorldConfig;
|
||||
|
||||
/**
|
||||
* Used to ensure that ProtocolLib and Bukkit is prepared to be tested.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public class BukkitInitialization {
|
||||
|
||||
private static final BukkitInitialization instance = new BukkitInitialization();
|
||||
private boolean initialized;
|
||||
private boolean packaged;
|
||||
|
||||
private BukkitInitialization() {
|
||||
System.out.println("Created new BukkitInitialization on " + Thread.currentThread().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Statically initializes the mock server for unit testing
|
||||
*/
|
||||
public static synchronized void initializeAll() {
|
||||
instance.initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize Bukkit and ProtocolLib such that we can perfrom unit testing
|
||||
*/
|
||||
private void initialize() {
|
||||
if (!this.initialized) {
|
||||
// Denote that we're done
|
||||
this.initialized = true;
|
||||
|
||||
try {
|
||||
LogManager.getLogger();
|
||||
} catch (Throwable ex) {
|
||||
// Happens only on my Jenkins, but if it errors here it works when it matters
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
instance.setPackage();
|
||||
|
||||
SharedConstants.a();
|
||||
DispenserRegistry.a();
|
||||
|
||||
try {
|
||||
IRegistry.class.getName();
|
||||
} catch (Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
String releaseTarget = SharedConstants.b().getReleaseTarget();
|
||||
String serverVersion = CraftServer.class.getPackage().getImplementationVersion();
|
||||
|
||||
// Mock the server object
|
||||
Server mockedServer = mock(Server.class);
|
||||
|
||||
when(mockedServer.getLogger()).thenReturn(java.util.logging.Logger.getLogger("Minecraft"));
|
||||
when(mockedServer.getName()).thenReturn("Mock Server");
|
||||
when(mockedServer.getVersion()).thenReturn(serverVersion + " (MC: " + releaseTarget + ")");
|
||||
when(mockedServer.getBukkitVersion()).thenReturn(Versioning.getBukkitVersion());
|
||||
|
||||
when(mockedServer.getItemFactory()).thenReturn(CraftItemFactory.instance());
|
||||
when(mockedServer.isPrimaryThread()).thenReturn(true);
|
||||
|
||||
WorldServer nmsWorld = mock(WorldServer.class);
|
||||
|
||||
SpigotWorldConfig mockWorldConfig = mock(SpigotWorldConfig.class);
|
||||
|
||||
try {
|
||||
FieldAccessor spigotConfig = Accessors.getFieldAccessor(nmsWorld.getClass().getField("spigotConfig"));
|
||||
spigotConfig.set(nmsWorld, mockWorldConfig);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
CraftWorld world = mock(CraftWorld.class);
|
||||
when(world.getHandle()).thenReturn(nmsWorld);
|
||||
|
||||
List<World> worlds = Collections.singletonList(world);
|
||||
when(mockedServer.getWorlds()).thenReturn(worlds);
|
||||
|
||||
// Inject this fake server
|
||||
Bukkit.setServer(mockedServer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that package names are correctly set up.
|
||||
*/
|
||||
private void setPackage() {
|
||||
if (!this.packaged) {
|
||||
this.packaged = true;
|
||||
|
||||
try {
|
||||
LogManager.getLogger();
|
||||
} catch (Throwable ex) {
|
||||
// Happens only on my Jenkins, but if it errors here it works when it matters
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
MinecraftReflectionTestUtil.init();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,334 +1,334 @@
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2016 dmulloy2
|
||||
* <p>
|
||||
* 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
|
||||
* version.
|
||||
* <p>
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
* <p>
|
||||
* 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
|
||||
*/
|
||||
package com.comphenix.protocol;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.comphenix.protocol.PacketType.Protocol;
|
||||
import com.comphenix.protocol.PacketType.Sender;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
||||
import com.comphenix.protocol.utility.MinecraftReflectionTestUtil;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import net.minecraft.network.EnumProtocol;
|
||||
import net.minecraft.network.protocol.EnumProtocolDirection;
|
||||
import net.minecraft.network.protocol.login.PacketLoginInStart;
|
||||
import org.apache.commons.lang.WordUtils;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class PacketTypeTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() {
|
||||
BukkitInitialization.initializeAll();
|
||||
|
||||
// I'm well aware this is jank, but it does in fact work correctly and give the desired result
|
||||
PacketType.onDynamicCreate = className -> {
|
||||
throw new RuntimeException("Dynamically generated packet " + className);
|
||||
};
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void afterClass() {
|
||||
PacketType.onDynamicCreate = __ -> {
|
||||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void main(String[] args) throws Exception {
|
||||
MinecraftReflectionTestUtil.init();
|
||||
|
||||
Set<Class<?>> allTypes = new HashSet<>();
|
||||
List<Class<?>> newTypes = new ArrayList<>();
|
||||
|
||||
EnumProtocol[] protocols = EnumProtocol.values();
|
||||
for (EnumProtocol protocol : protocols) {
|
||||
System.out.println(WordUtils.capitalize(protocol.name().toLowerCase()));
|
||||
|
||||
Field field = EnumProtocol.class.getDeclaredField("j");
|
||||
field.setAccessible(true);
|
||||
|
||||
Map<EnumProtocolDirection, Object> map = (Map<EnumProtocolDirection, Object>) field.get(protocol);
|
||||
for (Entry<EnumProtocolDirection, Object> entry : map.entrySet()) {
|
||||
Field mapField = entry.getValue().getClass().getDeclaredField("b");
|
||||
mapField.setAccessible(true);
|
||||
|
||||
Map<Class<?>, Integer> reverseMap = (Map<Class<?>, Integer>) mapField.get(entry.getValue());
|
||||
|
||||
Map<Integer, Class<?>> treeMap = new TreeMap<>();
|
||||
for (Entry<Class<?>, Integer> entry1 : reverseMap.entrySet()) {
|
||||
treeMap.put(entry1.getValue(), entry1.getKey());
|
||||
}
|
||||
|
||||
System.out.println(" " + entry.getKey());
|
||||
for (Entry<Integer, Class<?>> entry1 : treeMap.entrySet()) {
|
||||
System.out.println(generateNewType(entry1.getKey(), entry1.getValue()));
|
||||
allTypes.add(entry1.getValue());
|
||||
|
||||
try {
|
||||
PacketType.fromClass(entry1.getValue());
|
||||
} catch (Exception ex) {
|
||||
newTypes.add(entry1.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("New types: " + newTypes);
|
||||
|
||||
for (PacketType type : PacketType.values()) {
|
||||
if (type.isDeprecated()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!allTypes.contains(type.getPacketClass())) {
|
||||
System.out.println(type + " was removed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String formatHex(int dec) {
|
||||
if (dec < 0) {
|
||||
return "0xFF";
|
||||
}
|
||||
|
||||
String hex = Integer.toHexString(dec).toUpperCase();
|
||||
return "0x" + (hex.length() < 2 ? "0" : "") + hex;
|
||||
}
|
||||
|
||||
private static List<String> splitOnCaps(String string) {
|
||||
List<String> list = new ArrayList<>();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
char[] chars = string.toCharArray();
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
char c = chars[i];
|
||||
if (i != 0 && Character.isUpperCase(c)) {
|
||||
list.add(builder.toString());
|
||||
builder = new StringBuilder();
|
||||
}
|
||||
|
||||
builder.append(c);
|
||||
}
|
||||
|
||||
list.add(builder.toString());
|
||||
return list;
|
||||
}
|
||||
|
||||
private static String generateNewType(int packetId, Class<?> clazz) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("\t\t\t");
|
||||
builder.append("public static final PacketType ");
|
||||
|
||||
String fullName = clazz.getName();
|
||||
fullName = fullName.substring(fullName.lastIndexOf(".") + 1);
|
||||
|
||||
String className;
|
||||
List<String> classNames = new ArrayList<>();
|
||||
|
||||
if (fullName.endsWith("Packet")) {
|
||||
for (String name : fullName.split("\\$")) {
|
||||
List<String> split = splitOnCaps(name);
|
||||
StringBuilder nameBuilder = new StringBuilder();
|
||||
for (int i = 1; i < split.size() - 1; i++) {
|
||||
nameBuilder.append(split.get(i));
|
||||
}
|
||||
classNames.add(nameBuilder.toString());
|
||||
}
|
||||
} else {
|
||||
for (String name : fullName.split("\\$")) {
|
||||
List<String> split = splitOnCaps(name);
|
||||
StringBuilder nameBuilder = new StringBuilder();
|
||||
for (int i = 3; i < split.size(); i++) {
|
||||
nameBuilder.append(split.get(i));
|
||||
}
|
||||
classNames.add(nameBuilder.toString());
|
||||
}
|
||||
}
|
||||
|
||||
className = classNames.get(classNames.size() - 1);
|
||||
|
||||
// Format it like SET_PROTOCOL
|
||||
StringBuilder fieldName = new StringBuilder();
|
||||
char[] chars = className.toCharArray();
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
char c = chars[i];
|
||||
if (i != 0 && Character.isUpperCase(c)) {
|
||||
fieldName.append("_");
|
||||
}
|
||||
fieldName.append(Character.toUpperCase(c));
|
||||
}
|
||||
|
||||
builder.append(fieldName.toString().replace("N_B_T", "NBT"));
|
||||
builder.append(" = ");
|
||||
|
||||
// Add spacing
|
||||
if (builder.length() > 65) {
|
||||
builder.append("\n");
|
||||
} else {
|
||||
while (builder.length() < 65) {
|
||||
builder.append(" ");
|
||||
}
|
||||
}
|
||||
builder.append("new ");
|
||||
builder.append("PacketType(PROTOCOL, SENDER, ");
|
||||
|
||||
builder.append(formatHex(packetId));
|
||||
builder.append(", ");
|
||||
|
||||
StringBuilder nameBuilder = new StringBuilder();
|
||||
for (int i = 0; i < classNames.size(); i++) {
|
||||
if (i != 0) {
|
||||
nameBuilder.append("$");
|
||||
}
|
||||
nameBuilder.append(classNames.get(i));
|
||||
}
|
||||
|
||||
String name = nameBuilder.toString();
|
||||
String namesArg = listToString(getAllNames(clazz, name));
|
||||
|
||||
builder.append(namesArg);
|
||||
builder.append(");");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static List<String> getAllNames(Class<?> packetClass, String newName) {
|
||||
List<String> names = new ArrayList<>();
|
||||
names.add(newName);
|
||||
|
||||
try {
|
||||
PacketType type = PacketType.fromClass(packetClass);
|
||||
for (String alias : type.names) {
|
||||
alias = alias.substring(alias.lastIndexOf('.') + 1);
|
||||
if (!names.contains(alias)) {
|
||||
names.add(alias);
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
private static String listToString(List<String> list) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
if (i != 0) {
|
||||
builder.append(", ");
|
||||
}
|
||||
builder.append("\"").append(list.get(i)).append("\"");
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
public static void initializeReflection() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindCurrent() {
|
||||
assertEquals(PacketType.Play.Client.STEER_VEHICLE,
|
||||
PacketType.findCurrent(Protocol.PLAY, Sender.CLIENT, "SteerVehicle"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoginStart() {
|
||||
// This packet is critical for handleLoin
|
||||
assertEquals(PacketLoginInStart.class, PacketType.Login.Client.START.getPacketClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeprecation() {
|
||||
assertTrue(PacketType.Status.Server.OUT_SERVER_INFO.isDeprecated(), "Packet isn't properly deprecated");
|
||||
assertTrue(PacketRegistry.getServerPacketTypes().contains(PacketType.Status.Server.OUT_SERVER_INFO),
|
||||
"Deprecated packet isn't properly included");
|
||||
assertFalse(PacketType.Play.Server.CHAT.isDeprecated(), "Packet isn't properly deprecated");
|
||||
assertEquals(PacketType.Status.Server.OUT_SERVER_INFO, PacketType.Status.Server.SERVER_INFO,
|
||||
"Deprecated packets aren't equal");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void ensureTypesAreCorrect() throws Exception {
|
||||
boolean fail = false;
|
||||
|
||||
EnumProtocol[] protocols = EnumProtocol.values();
|
||||
for (EnumProtocol protocol : protocols) {
|
||||
Field field = EnumProtocol.class.getDeclaredField("j");
|
||||
field.setAccessible(true);
|
||||
|
||||
Map<EnumProtocolDirection, Object> map = (Map<EnumProtocolDirection, Object>) field.get(protocol);
|
||||
for (Entry<EnumProtocolDirection, Object> entry : map.entrySet()) {
|
||||
Field mapField = entry.getValue().getClass().getDeclaredField("b");
|
||||
mapField.setAccessible(true);
|
||||
|
||||
Map<Class<?>, Integer> reverseMap = (Map<Class<?>, Integer>) mapField.get(entry.getValue());
|
||||
|
||||
Map<Integer, Class<?>> treeMap = new TreeMap<>();
|
||||
for (Entry<Class<?>, Integer> entry1 : reverseMap.entrySet()) {
|
||||
treeMap.put(entry1.getValue(), entry1.getKey());
|
||||
}
|
||||
|
||||
for (Entry<Integer, Class<?>> entry1 : treeMap.entrySet()) {
|
||||
try {
|
||||
PacketType type = PacketType.fromClass(entry1.getValue());
|
||||
if (type.getCurrentId() != entry1.getKey()) {
|
||||
throw new IllegalStateException(
|
||||
"Packet ID for " + type + " is incorrect. Expected " + entry1.getKey() + ", but got "
|
||||
+ type.getCurrentId());
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
fail = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertFalse(fail, "Packet type(s) were incorrect!");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPacketCreation() {
|
||||
boolean fail = false;
|
||||
for (PacketType type : PacketType.values()) {
|
||||
if (type.isSupported()) {
|
||||
try {
|
||||
new PacketContainer(type);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
fail = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
assertFalse(fail, "Packet type(s) failed to instantiate");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2016 dmulloy2
|
||||
* <p>
|
||||
* 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
|
||||
* version.
|
||||
* <p>
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
* <p>
|
||||
* 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
|
||||
*/
|
||||
package com.comphenix.protocol;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.comphenix.protocol.PacketType.Protocol;
|
||||
import com.comphenix.protocol.PacketType.Sender;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
||||
import com.comphenix.protocol.utility.MinecraftReflectionTestUtil;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import net.minecraft.network.EnumProtocol;
|
||||
import net.minecraft.network.protocol.EnumProtocolDirection;
|
||||
import net.minecraft.network.protocol.login.PacketLoginInStart;
|
||||
import org.apache.commons.lang.WordUtils;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class PacketTypeTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() {
|
||||
BukkitInitialization.initializeAll();
|
||||
|
||||
// I'm well aware this is jank, but it does in fact work correctly and give the desired result
|
||||
PacketType.onDynamicCreate = className -> {
|
||||
throw new RuntimeException("Dynamically generated packet " + className);
|
||||
};
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void afterClass() {
|
||||
PacketType.onDynamicCreate = __ -> {
|
||||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void main(String[] args) throws Exception {
|
||||
MinecraftReflectionTestUtil.init();
|
||||
|
||||
Set<Class<?>> allTypes = new HashSet<>();
|
||||
List<Class<?>> newTypes = new ArrayList<>();
|
||||
|
||||
EnumProtocol[] protocols = EnumProtocol.values();
|
||||
for (EnumProtocol protocol : protocols) {
|
||||
System.out.println(WordUtils.capitalize(protocol.name().toLowerCase()));
|
||||
|
||||
Field field = EnumProtocol.class.getDeclaredField("j");
|
||||
field.setAccessible(true);
|
||||
|
||||
Map<EnumProtocolDirection, Object> map = (Map<EnumProtocolDirection, Object>) field.get(protocol);
|
||||
for (Entry<EnumProtocolDirection, Object> entry : map.entrySet()) {
|
||||
Field mapField = entry.getValue().getClass().getDeclaredField("b");
|
||||
mapField.setAccessible(true);
|
||||
|
||||
Map<Class<?>, Integer> reverseMap = (Map<Class<?>, Integer>) mapField.get(entry.getValue());
|
||||
|
||||
Map<Integer, Class<?>> treeMap = new TreeMap<>();
|
||||
for (Entry<Class<?>, Integer> entry1 : reverseMap.entrySet()) {
|
||||
treeMap.put(entry1.getValue(), entry1.getKey());
|
||||
}
|
||||
|
||||
System.out.println(" " + entry.getKey());
|
||||
for (Entry<Integer, Class<?>> entry1 : treeMap.entrySet()) {
|
||||
System.out.println(generateNewType(entry1.getKey(), entry1.getValue()));
|
||||
allTypes.add(entry1.getValue());
|
||||
|
||||
try {
|
||||
PacketType.fromClass(entry1.getValue());
|
||||
} catch (Exception ex) {
|
||||
newTypes.add(entry1.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("New types: " + newTypes);
|
||||
|
||||
for (PacketType type : PacketType.values()) {
|
||||
if (type.isDeprecated()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!allTypes.contains(type.getPacketClass())) {
|
||||
System.out.println(type + " was removed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String formatHex(int dec) {
|
||||
if (dec < 0) {
|
||||
return "0xFF";
|
||||
}
|
||||
|
||||
String hex = Integer.toHexString(dec).toUpperCase();
|
||||
return "0x" + (hex.length() < 2 ? "0" : "") + hex;
|
||||
}
|
||||
|
||||
private static List<String> splitOnCaps(String string) {
|
||||
List<String> list = new ArrayList<>();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
char[] chars = string.toCharArray();
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
char c = chars[i];
|
||||
if (i != 0 && Character.isUpperCase(c)) {
|
||||
list.add(builder.toString());
|
||||
builder = new StringBuilder();
|
||||
}
|
||||
|
||||
builder.append(c);
|
||||
}
|
||||
|
||||
list.add(builder.toString());
|
||||
return list;
|
||||
}
|
||||
|
||||
private static String generateNewType(int packetId, Class<?> clazz) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("\t\t\t");
|
||||
builder.append("public static final PacketType ");
|
||||
|
||||
String fullName = clazz.getName();
|
||||
fullName = fullName.substring(fullName.lastIndexOf(".") + 1);
|
||||
|
||||
String className;
|
||||
List<String> classNames = new ArrayList<>();
|
||||
|
||||
if (fullName.endsWith("Packet")) {
|
||||
for (String name : fullName.split("\\$")) {
|
||||
List<String> split = splitOnCaps(name);
|
||||
StringBuilder nameBuilder = new StringBuilder();
|
||||
for (int i = 1; i < split.size() - 1; i++) {
|
||||
nameBuilder.append(split.get(i));
|
||||
}
|
||||
classNames.add(nameBuilder.toString());
|
||||
}
|
||||
} else {
|
||||
for (String name : fullName.split("\\$")) {
|
||||
List<String> split = splitOnCaps(name);
|
||||
StringBuilder nameBuilder = new StringBuilder();
|
||||
for (int i = 3; i < split.size(); i++) {
|
||||
nameBuilder.append(split.get(i));
|
||||
}
|
||||
classNames.add(nameBuilder.toString());
|
||||
}
|
||||
}
|
||||
|
||||
className = classNames.get(classNames.size() - 1);
|
||||
|
||||
// Format it like SET_PROTOCOL
|
||||
StringBuilder fieldName = new StringBuilder();
|
||||
char[] chars = className.toCharArray();
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
char c = chars[i];
|
||||
if (i != 0 && Character.isUpperCase(c)) {
|
||||
fieldName.append("_");
|
||||
}
|
||||
fieldName.append(Character.toUpperCase(c));
|
||||
}
|
||||
|
||||
builder.append(fieldName.toString().replace("N_B_T", "NBT"));
|
||||
builder.append(" = ");
|
||||
|
||||
// Add spacing
|
||||
if (builder.length() > 65) {
|
||||
builder.append("\n");
|
||||
} else {
|
||||
while (builder.length() < 65) {
|
||||
builder.append(" ");
|
||||
}
|
||||
}
|
||||
builder.append("new ");
|
||||
builder.append("PacketType(PROTOCOL, SENDER, ");
|
||||
|
||||
builder.append(formatHex(packetId));
|
||||
builder.append(", ");
|
||||
|
||||
StringBuilder nameBuilder = new StringBuilder();
|
||||
for (int i = 0; i < classNames.size(); i++) {
|
||||
if (i != 0) {
|
||||
nameBuilder.append("$");
|
||||
}
|
||||
nameBuilder.append(classNames.get(i));
|
||||
}
|
||||
|
||||
String name = nameBuilder.toString();
|
||||
String namesArg = listToString(getAllNames(clazz, name));
|
||||
|
||||
builder.append(namesArg);
|
||||
builder.append(");");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static List<String> getAllNames(Class<?> packetClass, String newName) {
|
||||
List<String> names = new ArrayList<>();
|
||||
names.add(newName);
|
||||
|
||||
try {
|
||||
PacketType type = PacketType.fromClass(packetClass);
|
||||
for (String alias : type.names) {
|
||||
alias = alias.substring(alias.lastIndexOf('.') + 1);
|
||||
if (!names.contains(alias)) {
|
||||
names.add(alias);
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
private static String listToString(List<String> list) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
if (i != 0) {
|
||||
builder.append(", ");
|
||||
}
|
||||
builder.append("\"").append(list.get(i)).append("\"");
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
public static void initializeReflection() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindCurrent() {
|
||||
assertEquals(PacketType.Play.Client.STEER_VEHICLE,
|
||||
PacketType.findCurrent(Protocol.PLAY, Sender.CLIENT, "SteerVehicle"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoginStart() {
|
||||
// This packet is critical for handleLoin
|
||||
assertEquals(PacketLoginInStart.class, PacketType.Login.Client.START.getPacketClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeprecation() {
|
||||
assertTrue(PacketType.Status.Server.OUT_SERVER_INFO.isDeprecated(), "Packet isn't properly deprecated");
|
||||
assertTrue(PacketRegistry.getServerPacketTypes().contains(PacketType.Status.Server.OUT_SERVER_INFO),
|
||||
"Deprecated packet isn't properly included");
|
||||
assertFalse(PacketType.Play.Server.CHAT.isDeprecated(), "Packet isn't properly deprecated");
|
||||
assertEquals(PacketType.Status.Server.OUT_SERVER_INFO, PacketType.Status.Server.SERVER_INFO,
|
||||
"Deprecated packets aren't equal");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void ensureTypesAreCorrect() throws Exception {
|
||||
boolean fail = false;
|
||||
|
||||
EnumProtocol[] protocols = EnumProtocol.values();
|
||||
for (EnumProtocol protocol : protocols) {
|
||||
Field field = EnumProtocol.class.getDeclaredField("j");
|
||||
field.setAccessible(true);
|
||||
|
||||
Map<EnumProtocolDirection, Object> map = (Map<EnumProtocolDirection, Object>) field.get(protocol);
|
||||
for (Entry<EnumProtocolDirection, Object> entry : map.entrySet()) {
|
||||
Field mapField = entry.getValue().getClass().getDeclaredField("b");
|
||||
mapField.setAccessible(true);
|
||||
|
||||
Map<Class<?>, Integer> reverseMap = (Map<Class<?>, Integer>) mapField.get(entry.getValue());
|
||||
|
||||
Map<Integer, Class<?>> treeMap = new TreeMap<>();
|
||||
for (Entry<Class<?>, Integer> entry1 : reverseMap.entrySet()) {
|
||||
treeMap.put(entry1.getValue(), entry1.getKey());
|
||||
}
|
||||
|
||||
for (Entry<Integer, Class<?>> entry1 : treeMap.entrySet()) {
|
||||
try {
|
||||
PacketType type = PacketType.fromClass(entry1.getValue());
|
||||
if (type.getCurrentId() != entry1.getKey()) {
|
||||
throw new IllegalStateException(
|
||||
"Packet ID for " + type + " is incorrect. Expected " + entry1.getKey() + ", but got "
|
||||
+ type.getCurrentId());
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
fail = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertFalse(fail, "Packet type(s) were incorrect!");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPacketCreation() {
|
||||
boolean fail = false;
|
||||
for (PacketType type : PacketType.values()) {
|
||||
if (type.isSupported()) {
|
||||
try {
|
||||
new PacketContainer(type);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
fail = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
assertFalse(fail, "Packet type(s) failed to instantiate");
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,59 +1,59 @@
|
||||
package com.comphenix.protocol.injector;
|
||||
|
||||
import static com.comphenix.protocol.utility.TestUtils.setFinalField;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import java.lang.reflect.Field;
|
||||
import net.minecraft.server.level.ChunkProviderServer;
|
||||
import net.minecraft.server.level.PlayerChunkMap;
|
||||
import net.minecraft.server.level.PlayerChunkMap.EntityTracker;
|
||||
import net.minecraft.server.level.WorldServer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftEntity;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class EntityUtilitiesTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReflection() {
|
||||
CraftWorld bukkit = mock(CraftWorld.class);
|
||||
WorldServer world = mock(WorldServer.class);
|
||||
when(bukkit.getHandle()).thenReturn(world);
|
||||
|
||||
ChunkProviderServer provider = mock(ChunkProviderServer.class);
|
||||
when(world.k()).thenReturn(provider);
|
||||
|
||||
PlayerChunkMap chunkMap = mock(PlayerChunkMap.class);
|
||||
Field chunkMapField = FuzzyReflection.fromClass(ChunkProviderServer.class, true)
|
||||
.getField(FuzzyFieldContract.newBuilder().typeExact(PlayerChunkMap.class).build());
|
||||
setFinalField(provider, chunkMapField, chunkMap);
|
||||
|
||||
CraftEntity bukkitEntity = mock(CraftEntity.class);
|
||||
Entity fakeEntity = mock(Entity.class);
|
||||
when(fakeEntity.getBukkitEntity()).thenReturn(bukkitEntity);
|
||||
|
||||
EntityTracker tracker = mock(EntityTracker.class);
|
||||
Field trackerField = FuzzyReflection.fromClass(EntityTracker.class, true)
|
||||
.getField(FuzzyFieldContract.newBuilder().typeExact(Entity.class).build());
|
||||
setFinalField(tracker, trackerField, fakeEntity);
|
||||
|
||||
Int2ObjectMap<EntityTracker> trackerMap = new Int2ObjectOpenHashMap<>();
|
||||
trackerMap.put(1, tracker);
|
||||
Field trackedEntitiesField = FuzzyReflection.fromClass(PlayerChunkMap.class, true)
|
||||
.getField(FuzzyFieldContract.newBuilder().typeExact(Int2ObjectMap.class).build());
|
||||
setFinalField(chunkMap, trackedEntitiesField, trackerMap);
|
||||
}
|
||||
}
|
||||
package com.comphenix.protocol.injector;
|
||||
|
||||
import static com.comphenix.protocol.utility.TestUtils.setFinalField;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import java.lang.reflect.Field;
|
||||
import net.minecraft.server.level.ChunkProviderServer;
|
||||
import net.minecraft.server.level.PlayerChunkMap;
|
||||
import net.minecraft.server.level.PlayerChunkMap.EntityTracker;
|
||||
import net.minecraft.server.level.WorldServer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftEntity;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class EntityUtilitiesTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReflection() {
|
||||
CraftWorld bukkit = mock(CraftWorld.class);
|
||||
WorldServer world = mock(WorldServer.class);
|
||||
when(bukkit.getHandle()).thenReturn(world);
|
||||
|
||||
ChunkProviderServer provider = mock(ChunkProviderServer.class);
|
||||
when(world.k()).thenReturn(provider);
|
||||
|
||||
PlayerChunkMap chunkMap = mock(PlayerChunkMap.class);
|
||||
Field chunkMapField = FuzzyReflection.fromClass(ChunkProviderServer.class, true)
|
||||
.getField(FuzzyFieldContract.newBuilder().typeExact(PlayerChunkMap.class).build());
|
||||
setFinalField(provider, chunkMapField, chunkMap);
|
||||
|
||||
CraftEntity bukkitEntity = mock(CraftEntity.class);
|
||||
Entity fakeEntity = mock(Entity.class);
|
||||
when(fakeEntity.getBukkitEntity()).thenReturn(bukkitEntity);
|
||||
|
||||
EntityTracker tracker = mock(EntityTracker.class);
|
||||
Field trackerField = FuzzyReflection.fromClass(EntityTracker.class, true)
|
||||
.getField(FuzzyFieldContract.newBuilder().typeExact(Entity.class).build());
|
||||
setFinalField(tracker, trackerField, fakeEntity);
|
||||
|
||||
Int2ObjectMap<EntityTracker> trackerMap = new Int2ObjectOpenHashMap<>();
|
||||
trackerMap.put(1, tracker);
|
||||
Field trackedEntitiesField = FuzzyReflection.fromClass(PlayerChunkMap.class, true)
|
||||
.getField(FuzzyFieldContract.newBuilder().typeExact(Int2ObjectMap.class).build());
|
||||
setFinalField(chunkMap, trackedEntitiesField, trackerMap);
|
||||
}
|
||||
}
|
||||
|
@ -1,69 +1,69 @@
|
||||
/**
|
||||
* (c) 2016 dmulloy2
|
||||
*/
|
||||
package com.comphenix.protocol.injector;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.netty.WirePacket;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class WirePacketTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
// @Test
|
||||
public void testPackets() {
|
||||
List<String> failures = new ArrayList<>();
|
||||
|
||||
for (PacketType type : PacketType.values()) {
|
||||
if (type.isDeprecated()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
PacketContainer packet = new PacketContainer(type);
|
||||
WirePacket wire = WirePacket.fromPacket(packet);
|
||||
WirePacket handle = WirePacket.fromPacket(packet.getHandle());
|
||||
assertEquals(wire, handle);
|
||||
} catch (Exception ex) {
|
||||
failures.add(type + " :: " + ex.getMessage());
|
||||
System.out.println(type);
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(failures, new ArrayList<>());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerialization() {
|
||||
int id = 42;
|
||||
byte[] array = {1, 3, 7, 21, 88, 67, 8};
|
||||
|
||||
WirePacket packet = new WirePacket(id, array);
|
||||
|
||||
ByteBuf buf = packet.serialize();
|
||||
|
||||
int backId = WirePacket.readVarInt(buf);
|
||||
byte[] backArray = new byte[buf.readableBytes()];
|
||||
buf.readBytes(backArray);
|
||||
|
||||
assertEquals(id, backId);
|
||||
assertArrayEquals(array, backArray);
|
||||
}
|
||||
/**
|
||||
* (c) 2016 dmulloy2
|
||||
*/
|
||||
package com.comphenix.protocol.injector;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.netty.WirePacket;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class WirePacketTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
// @Test
|
||||
public void testPackets() {
|
||||
List<String> failures = new ArrayList<>();
|
||||
|
||||
for (PacketType type : PacketType.values()) {
|
||||
if (type.isDeprecated()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
PacketContainer packet = new PacketContainer(type);
|
||||
WirePacket wire = WirePacket.fromPacket(packet);
|
||||
WirePacket handle = WirePacket.fromPacket(packet.getHandle());
|
||||
assertEquals(wire, handle);
|
||||
} catch (Exception ex) {
|
||||
failures.add(type + " :: " + ex.getMessage());
|
||||
System.out.println(type);
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(failures, new ArrayList<>());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerialization() {
|
||||
int id = 42;
|
||||
byte[] array = {1, 3, 7, 21, 88, 67, 8};
|
||||
|
||||
WirePacket packet = new WirePacket(id, array);
|
||||
|
||||
ByteBuf buf = packet.serialize();
|
||||
|
||||
int backId = WirePacket.readVarInt(buf);
|
||||
byte[] backArray = new byte[buf.readableBytes()];
|
||||
buf.readBytes(backArray);
|
||||
|
||||
assertEquals(id, backId);
|
||||
assertArrayEquals(array, backArray);
|
||||
}
|
||||
}
|
@ -1,45 +1,45 @@
|
||||
package com.comphenix.protocol.reflect.cloning;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class AggregateClonerTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void initializeBukkit() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArrays() {
|
||||
List<Integer> input = Arrays.asList(1, 2, 3);
|
||||
assertEquals(input, AggregateCloner.DEFAULT.clone(input));
|
||||
}
|
||||
|
||||
// @Test
|
||||
// Usages of NonNullList were removed in 1.17.1
|
||||
public void testNonNullList() {
|
||||
PacketContainer packet = new PacketContainer(PacketType.Play.Server.WINDOW_ITEMS);
|
||||
|
||||
NonNullList<ItemStack> list = NonNullList.a(16, ItemStack.b);
|
||||
packet.getModifier().write(1, list);
|
||||
|
||||
PacketContainer cloned = packet.deepClone();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
NonNullList<ItemStack> list1 = (NonNullList<ItemStack>) cloned.getModifier().read(1);
|
||||
|
||||
assertEquals(list.size(), list1.size());
|
||||
Assertions.assertArrayEquals(list.toArray(), list1.toArray());
|
||||
}
|
||||
}
|
||||
package com.comphenix.protocol.reflect.cloning;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class AggregateClonerTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void initializeBukkit() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArrays() {
|
||||
List<Integer> input = Arrays.asList(1, 2, 3);
|
||||
assertEquals(input, AggregateCloner.DEFAULT.clone(input));
|
||||
}
|
||||
|
||||
// @Test
|
||||
// Usages of NonNullList were removed in 1.17.1
|
||||
public void testNonNullList() {
|
||||
PacketContainer packet = new PacketContainer(PacketType.Play.Server.WINDOW_ITEMS);
|
||||
|
||||
NonNullList<ItemStack> list = NonNullList.a(16, ItemStack.b);
|
||||
packet.getModifier().write(1, list);
|
||||
|
||||
PacketContainer cloned = packet.deepClone();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
NonNullList<ItemStack> list1 = (NonNullList<ItemStack>) cloned.getModifier().read(1);
|
||||
|
||||
assertEquals(list.size(), list1.size());
|
||||
Assertions.assertArrayEquals(list.toArray(), list1.toArray());
|
||||
}
|
||||
}
|
||||
|
@ -1,159 +1,159 @@
|
||||
package com.comphenix.protocol.utility;
|
||||
|
||||
import static com.comphenix.protocol.utility.TestUtils.assertItemsEqual;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import net.minecraft.nbt.NBTCompressedStreamTools;
|
||||
import net.minecraft.network.chat.IChatBaseComponent;
|
||||
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes;
|
||||
import net.minecraft.network.protocol.status.ServerPing;
|
||||
import net.minecraft.network.syncher.DataWatcher;
|
||||
import net.minecraft.server.network.PlayerConnection;
|
||||
import net.minecraft.util.MinecraftEncryption;
|
||||
import net.minecraft.world.level.ChunkCoordIntPair;
|
||||
import net.minecraft.world.level.block.state.IBlockData;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class MinecraftReflectionTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void initializeBukkit() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void undoMocking() {
|
||||
// NOP
|
||||
MinecraftReflection.minecraftPackage = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBukkitMethod() {
|
||||
FakeEntity entity = mock(FakeEntity.class);
|
||||
FakeBlock block = mock(FakeBlock.class);
|
||||
|
||||
MinecraftReflection.getBukkitEntity(entity);
|
||||
MinecraftReflection.getBukkitEntity(block);
|
||||
|
||||
verify(entity, times(1)).getBukkitEntity();
|
||||
verify(block, times(1)).getBukkitEntity();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIllegalClass() {
|
||||
assertThrows(IllegalArgumentException.class, () -> MinecraftReflection.getBukkitEntity("Hello"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullable() {
|
||||
assertNull(MinecraftReflection.getNullableNMS("ProtocolLib"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttributeSnapshot() {
|
||||
assertEquals(PacketPlayOutUpdateAttributes.AttributeSnapshot.class,
|
||||
MinecraftReflection.getAttributeSnapshotClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChatComponent() {
|
||||
assertEquals(IChatBaseComponent.class, MinecraftReflection.getIChatBaseComponentClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChatSerializer() {
|
||||
assertEquals(IChatBaseComponent.ChatSerializer.class, MinecraftReflection.getChatSerializerClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChunkCoordIntPair() {
|
||||
assertEquals(ChunkCoordIntPair.class, MinecraftReflection.getChunkCoordIntPair());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIBlockData() {
|
||||
assertEquals(IBlockData.class, MinecraftReflection.getIBlockDataClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPlayerConnection() {
|
||||
assertEquals(PlayerConnection.class, MinecraftReflection.getPlayerConnectionClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerPing() {
|
||||
assertEquals(ServerPing.class, MinecraftReflection.getServerPingClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerPingPlayerSample() {
|
||||
assertEquals(ServerPing.ServerPingPlayerSample.class, MinecraftReflection.getServerPingPlayerSampleClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerPingServerData() {
|
||||
assertEquals(ServerPing.ServerData.class, MinecraftReflection.getServerPingServerDataClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNbtStreamTools() {
|
||||
assertEquals(NBTCompressedStreamTools.class, MinecraftReflection.getNbtCompressedStreamToolsClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDataWatcherItem() {
|
||||
assertEquals(DataWatcher.Item.class, MinecraftReflection.getDataWatcherItemClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoginSignature() {
|
||||
assertEquals(MinecraftEncryption.b.class, MinecraftReflection.getSaltedSignatureClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testItemStacks() {
|
||||
ItemStack stack = new ItemStack(Material.GOLDEN_SWORD);
|
||||
Object nmsStack = MinecraftReflection.getMinecraftItemStack(stack);
|
||||
assertItemsEqual(stack, MinecraftReflection.getBukkitItemStack(nmsStack));
|
||||
|
||||
// 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))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGameProfile() {
|
||||
assertEquals(GameProfile.class, MinecraftReflection.getGameProfileClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnumEntityUseAction() {
|
||||
// this class is package-private in PacketPlayInUseEntity, so we can only check if no exception is thrown during retrieval
|
||||
MinecraftReflection.getEnumEntityUseActionClass();
|
||||
}
|
||||
|
||||
// Mocking objects
|
||||
private interface FakeEntity {
|
||||
|
||||
Entity getBukkitEntity();
|
||||
}
|
||||
|
||||
private interface FakeBlock {
|
||||
|
||||
Block getBukkitEntity();
|
||||
}
|
||||
}
|
||||
package com.comphenix.protocol.utility;
|
||||
|
||||
import static com.comphenix.protocol.utility.TestUtils.assertItemsEqual;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import net.minecraft.nbt.NBTCompressedStreamTools;
|
||||
import net.minecraft.network.chat.IChatBaseComponent;
|
||||
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes;
|
||||
import net.minecraft.network.protocol.status.ServerPing;
|
||||
import net.minecraft.network.syncher.DataWatcher;
|
||||
import net.minecraft.server.network.PlayerConnection;
|
||||
import net.minecraft.util.MinecraftEncryption;
|
||||
import net.minecraft.world.level.ChunkCoordIntPair;
|
||||
import net.minecraft.world.level.block.state.IBlockData;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class MinecraftReflectionTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void initializeBukkit() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void undoMocking() {
|
||||
// NOP
|
||||
MinecraftReflection.minecraftPackage = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBukkitMethod() {
|
||||
FakeEntity entity = mock(FakeEntity.class);
|
||||
FakeBlock block = mock(FakeBlock.class);
|
||||
|
||||
MinecraftReflection.getBukkitEntity(entity);
|
||||
MinecraftReflection.getBukkitEntity(block);
|
||||
|
||||
verify(entity, times(1)).getBukkitEntity();
|
||||
verify(block, times(1)).getBukkitEntity();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIllegalClass() {
|
||||
assertThrows(IllegalArgumentException.class, () -> MinecraftReflection.getBukkitEntity("Hello"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullable() {
|
||||
assertNull(MinecraftReflection.getNullableNMS("ProtocolLib"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttributeSnapshot() {
|
||||
assertEquals(PacketPlayOutUpdateAttributes.AttributeSnapshot.class,
|
||||
MinecraftReflection.getAttributeSnapshotClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChatComponent() {
|
||||
assertEquals(IChatBaseComponent.class, MinecraftReflection.getIChatBaseComponentClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChatSerializer() {
|
||||
assertEquals(IChatBaseComponent.ChatSerializer.class, MinecraftReflection.getChatSerializerClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChunkCoordIntPair() {
|
||||
assertEquals(ChunkCoordIntPair.class, MinecraftReflection.getChunkCoordIntPair());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIBlockData() {
|
||||
assertEquals(IBlockData.class, MinecraftReflection.getIBlockDataClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPlayerConnection() {
|
||||
assertEquals(PlayerConnection.class, MinecraftReflection.getPlayerConnectionClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerPing() {
|
||||
assertEquals(ServerPing.class, MinecraftReflection.getServerPingClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerPingPlayerSample() {
|
||||
assertEquals(ServerPing.ServerPingPlayerSample.class, MinecraftReflection.getServerPingPlayerSampleClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerPingServerData() {
|
||||
assertEquals(ServerPing.ServerData.class, MinecraftReflection.getServerPingServerDataClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNbtStreamTools() {
|
||||
assertEquals(NBTCompressedStreamTools.class, MinecraftReflection.getNbtCompressedStreamToolsClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDataWatcherItem() {
|
||||
assertEquals(DataWatcher.Item.class, MinecraftReflection.getDataWatcherItemClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoginSignature() {
|
||||
assertEquals(MinecraftEncryption.b.class, MinecraftReflection.getSaltedSignatureClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testItemStacks() {
|
||||
ItemStack stack = new ItemStack(Material.GOLDEN_SWORD);
|
||||
Object nmsStack = MinecraftReflection.getMinecraftItemStack(stack);
|
||||
assertItemsEqual(stack, MinecraftReflection.getBukkitItemStack(nmsStack));
|
||||
|
||||
// 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))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGameProfile() {
|
||||
assertEquals(GameProfile.class, MinecraftReflection.getGameProfileClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnumEntityUseAction() {
|
||||
// this class is package-private in PacketPlayInUseEntity, so we can only check if no exception is thrown during retrieval
|
||||
MinecraftReflection.getEnumEntityUseActionClass();
|
||||
}
|
||||
|
||||
// Mocking objects
|
||||
private interface FakeEntity {
|
||||
|
||||
Entity getBukkitEntity();
|
||||
}
|
||||
|
||||
private interface FakeBlock {
|
||||
|
||||
Block getBukkitEntity();
|
||||
}
|
||||
}
|
||||
|
@ -1,52 +1,52 @@
|
||||
package com.comphenix.protocol.utility;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class TestUtils {
|
||||
|
||||
public static void assertItemCollectionsEqual(List<ItemStack> first, List<ItemStack> second) {
|
||||
assertEquals(first.size(), second.size());
|
||||
for (int i = 0; i < first.size(); i++) {
|
||||
assertItemsEqual(first.get(i), second.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
public static void assertItemsEqual(ItemStack first, ItemStack second) {
|
||||
if (first == null) {
|
||||
assertNull(second);
|
||||
} else {
|
||||
assertNotNull(first);
|
||||
|
||||
// The legacy check in ItemStack#isSimilar causes a null pointer
|
||||
assertEquals(first.getType(), second.getType());
|
||||
assertEquals(first.getDurability(), second.getDurability());
|
||||
assertEquals(first.hasItemMeta(), second.hasItemMeta());
|
||||
if (first.hasItemMeta()) {
|
||||
assertTrue(Bukkit.getItemFactory().equals(first.getItemMeta(), second.getItemMeta()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean equivalentItem(ItemStack first, ItemStack second) {
|
||||
if (first == null) {
|
||||
return second == null;
|
||||
} else if (second == null) {
|
||||
return false;
|
||||
} else {
|
||||
return first.getType().equals(second.getType());
|
||||
}
|
||||
}
|
||||
|
||||
public static void setFinalField(Object obj, Field field, Object newValue) {
|
||||
Accessors.getFieldAccessor(field).set(obj, newValue);
|
||||
}
|
||||
}
|
||||
package com.comphenix.protocol.utility;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class TestUtils {
|
||||
|
||||
public static void assertItemCollectionsEqual(List<ItemStack> first, List<ItemStack> second) {
|
||||
assertEquals(first.size(), second.size());
|
||||
for (int i = 0; i < first.size(); i++) {
|
||||
assertItemsEqual(first.get(i), second.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
public static void assertItemsEqual(ItemStack first, ItemStack second) {
|
||||
if (first == null) {
|
||||
assertNull(second);
|
||||
} else {
|
||||
assertNotNull(first);
|
||||
|
||||
// The legacy check in ItemStack#isSimilar causes a null pointer
|
||||
assertEquals(first.getType(), second.getType());
|
||||
assertEquals(first.getDurability(), second.getDurability());
|
||||
assertEquals(first.hasItemMeta(), second.hasItemMeta());
|
||||
if (first.hasItemMeta()) {
|
||||
assertTrue(Bukkit.getItemFactory().equals(first.getItemMeta(), second.getItemMeta()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean equivalentItem(ItemStack first, ItemStack second) {
|
||||
if (first == null) {
|
||||
return second == null;
|
||||
} else if (second == null) {
|
||||
return false;
|
||||
} else {
|
||||
return first.getType().equals(second.getType());
|
||||
}
|
||||
}
|
||||
|
||||
public static void setFinalField(Object obj, Field field, Object newValue) {
|
||||
Accessors.getFieldAccessor(field).set(obj, newValue);
|
||||
}
|
||||
}
|
||||
|
@ -1,58 +1,58 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.wrappers.Either.Left;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class BukkitConvertersTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testItemStacks() {
|
||||
ItemStack item = new ItemStack(Material.DIAMOND_SWORD, 16);
|
||||
item.addEnchantment(Enchantment.DAMAGE_ALL, 4);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName(ChatColor.GREEN + "Diamond Sword");
|
||||
item.setItemMeta(meta);
|
||||
|
||||
EquivalentConverter<ItemStack> converter = BukkitConverters.getItemStackConverter();
|
||||
Object nmsStack = converter.getGeneric(item);
|
||||
ItemStack back = converter.getSpecific(nmsStack);
|
||||
|
||||
assertEquals(item.getType(), back.getType());
|
||||
assertEquals(item.getDurability(), back.getDurability());
|
||||
assertEquals(item.hasItemMeta(), back.hasItemMeta());
|
||||
assertTrue(Bukkit.getItemFactory().equals(item.getItemMeta(), back.getItemMeta()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEither() {
|
||||
Either<String, String> test = new Left<>("bla");
|
||||
|
||||
EquivalentConverter<Either<String, String>> converter = BukkitConverters.getEitherConverter(
|
||||
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);
|
||||
Either<String, String> wrapped = converter.getSpecific(nmsEither);
|
||||
|
||||
assertEquals(wrapped.left(), nmsEither.left());
|
||||
assertEquals(wrapped.right(), nmsEither.right());
|
||||
}
|
||||
}
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.wrappers.Either.Left;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class BukkitConvertersTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testItemStacks() {
|
||||
ItemStack item = new ItemStack(Material.DIAMOND_SWORD, 16);
|
||||
item.addEnchantment(Enchantment.DAMAGE_ALL, 4);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName(ChatColor.GREEN + "Diamond Sword");
|
||||
item.setItemMeta(meta);
|
||||
|
||||
EquivalentConverter<ItemStack> converter = BukkitConverters.getItemStackConverter();
|
||||
Object nmsStack = converter.getGeneric(item);
|
||||
ItemStack back = converter.getSpecific(nmsStack);
|
||||
|
||||
assertEquals(item.getType(), back.getType());
|
||||
assertEquals(item.getDurability(), back.getDurability());
|
||||
assertEquals(item.hasItemMeta(), back.hasItemMeta());
|
||||
assertTrue(Bukkit.getItemFactory().equals(item.getItemMeta(), back.getItemMeta()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEither() {
|
||||
Either<String, String> test = new Left<>("bla");
|
||||
|
||||
EquivalentConverter<Either<String, String>> converter = BukkitConverters.getEitherConverter(
|
||||
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);
|
||||
Either<String, String> wrapped = converter.getSpecific(nmsEither);
|
||||
|
||||
assertEquals(wrapped.left(), nmsEither.left());
|
||||
assertEquals(wrapped.right(), nmsEither.right());
|
||||
}
|
||||
}
|
||||
|
@ -1,31 +1,31 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class ChunkCoordIntPairTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void initializeBukkit() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
net.minecraft.world.level.ChunkCoordIntPair pair = new net.minecraft.world.level.ChunkCoordIntPair(1, 2);
|
||||
ChunkCoordIntPair specific = ChunkCoordIntPair.getConverter().getSpecific(pair);
|
||||
|
||||
assertEquals(1, specific.getChunkX());
|
||||
assertEquals(2, specific.getChunkZ());
|
||||
|
||||
net.minecraft.world.level.ChunkCoordIntPair roundtrip =
|
||||
(net.minecraft.world.level.ChunkCoordIntPair) ChunkCoordIntPair.getConverter().
|
||||
getGeneric(specific);
|
||||
|
||||
assertEquals(1, roundtrip.e);
|
||||
assertEquals(2, roundtrip.f);
|
||||
}
|
||||
}
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class ChunkCoordIntPairTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void initializeBukkit() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
net.minecraft.world.level.ChunkCoordIntPair pair = new net.minecraft.world.level.ChunkCoordIntPair(1, 2);
|
||||
ChunkCoordIntPair specific = ChunkCoordIntPair.getConverter().getSpecific(pair);
|
||||
|
||||
assertEquals(1, specific.getChunkX());
|
||||
assertEquals(2, specific.getChunkZ());
|
||||
|
||||
net.minecraft.world.level.ChunkCoordIntPair roundtrip =
|
||||
(net.minecraft.world.level.ChunkCoordIntPair) ChunkCoordIntPair.getConverter().
|
||||
getGeneric(specific);
|
||||
|
||||
assertEquals(1, roundtrip.e);
|
||||
assertEquals(2, roundtrip.f);
|
||||
}
|
||||
}
|
||||
|
@ -1,57 +1,57 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.google.common.collect.Sets;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class EnumWrappersTest {
|
||||
|
||||
private static final Set<String> KNOWN_INVALID = Sets.newHashSet(
|
||||
"Particle", "WorldBorderAction", "CombatEventType", "TitleAction", "ChatType"
|
||||
);
|
||||
|
||||
@BeforeAll
|
||||
public static void initializeBukkit() {
|
||||
BukkitInitialization.initializeAll();
|
||||
EnumWrappers.getPlayerInfoActionClass(); // just to initialize the classes and converters
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void validateAllEnumFieldsAreWrapped() {
|
||||
Map<Class<?>, EquivalentConverter<?>> nativeEnums = EnumWrappers.getFromNativeMap();
|
||||
for (Entry<Class<?>, EquivalentConverter<?>> entry : nativeEnums.entrySet()) {
|
||||
for (Object nativeConstant : entry.getKey().getEnumConstants()) {
|
||||
try {
|
||||
// yay, generics
|
||||
EquivalentConverter<Object> converter = (EquivalentConverter<Object>) entry.getValue();
|
||||
|
||||
// try to convert the native constant to a wrapper and back
|
||||
Object wrappedValue = converter.getSpecific(nativeConstant);
|
||||
assertNotNull(wrappedValue);
|
||||
|
||||
Object unwrappedValue = converter.getGeneric(wrappedValue);
|
||||
assertNotNull(unwrappedValue);
|
||||
|
||||
assertEquals(nativeConstant, unwrappedValue);
|
||||
} catch (Exception exception) {
|
||||
fail(exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidity() {
|
||||
assertEquals(EnumWrappers.INVALID, KNOWN_INVALID);
|
||||
}
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.google.common.collect.Sets;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class EnumWrappersTest {
|
||||
|
||||
private static final Set<String> KNOWN_INVALID = Sets.newHashSet(
|
||||
"Particle", "WorldBorderAction", "CombatEventType", "TitleAction", "ChatType"
|
||||
);
|
||||
|
||||
@BeforeAll
|
||||
public static void initializeBukkit() {
|
||||
BukkitInitialization.initializeAll();
|
||||
EnumWrappers.getPlayerInfoActionClass(); // just to initialize the classes and converters
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void validateAllEnumFieldsAreWrapped() {
|
||||
Map<Class<?>, EquivalentConverter<?>> nativeEnums = EnumWrappers.getFromNativeMap();
|
||||
for (Entry<Class<?>, EquivalentConverter<?>> entry : nativeEnums.entrySet()) {
|
||||
for (Object nativeConstant : entry.getKey().getEnumConstants()) {
|
||||
try {
|
||||
// yay, generics
|
||||
EquivalentConverter<Object> converter = (EquivalentConverter<Object>) entry.getValue();
|
||||
|
||||
// try to convert the native constant to a wrapper and back
|
||||
Object wrappedValue = converter.getSpecific(nativeConstant);
|
||||
assertNotNull(wrappedValue);
|
||||
|
||||
Object unwrappedValue = converter.getGeneric(wrappedValue);
|
||||
assertNotNull(unwrappedValue);
|
||||
|
||||
assertEquals(nativeConstant, unwrappedValue);
|
||||
} catch (Exception exception) {
|
||||
fail(exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidity() {
|
||||
assertEquals(EnumWrappers.INVALID, KNOWN_INVALID);
|
||||
}
|
||||
}
|
@ -1,104 +1,104 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.wrappers.WrappedAttributeModifier.Operation;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import net.minecraft.core.IRegistry;
|
||||
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes.AttributeSnapshot;
|
||||
import net.minecraft.resources.MinecraftKey;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeBase;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class WrappedAttributeTest {
|
||||
|
||||
private WrappedAttributeModifier doubleModifier;
|
||||
private WrappedAttributeModifier constantModifier;
|
||||
private WrappedAttribute attribute;
|
||||
|
||||
@BeforeAll
|
||||
public static void initializeBukkit() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
// Create a couple of modifiers
|
||||
this.doubleModifier =
|
||||
WrappedAttributeModifier.newBuilder().
|
||||
name("Double Damage").
|
||||
amount(1).
|
||||
operation(Operation.ADD_PERCENTAGE).
|
||||
build();
|
||||
this.constantModifier =
|
||||
WrappedAttributeModifier.newBuilder().
|
||||
name("Damage Bonus").
|
||||
amount(5).
|
||||
operation(Operation.ADD_NUMBER).
|
||||
build();
|
||||
|
||||
// Create attribute
|
||||
this.attribute = WrappedAttribute.newBuilder().
|
||||
attributeKey("generic.attackDamage").
|
||||
baseValue(2).
|
||||
packet(new PacketContainer(PacketType.Play.Server.UPDATE_ATTRIBUTES)).
|
||||
modifiers(Lists.newArrayList(this.constantModifier, this.doubleModifier)).
|
||||
build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquality() {
|
||||
// Check wrapped equality
|
||||
assertEquals(this.doubleModifier, this.doubleModifier);
|
||||
assertNotSame(this.constantModifier, this.doubleModifier);
|
||||
|
||||
assertEquals(this.doubleModifier.getHandle(), this.getModifierCopy(this.doubleModifier));
|
||||
assertEquals(this.constantModifier.getHandle(), this.getModifierCopy(this.constantModifier));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttribute() {
|
||||
assertEquals(this.attribute, WrappedAttribute.fromHandle(this.getAttributeCopy(this.attribute)));
|
||||
|
||||
assertTrue(this.attribute.hasModifier(this.doubleModifier.getUUID()));
|
||||
assertTrue(this.attribute.hasModifier(this.constantModifier.getUUID()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromTemplate() {
|
||||
assertEquals(this.attribute, WrappedAttribute.newBuilder(this.attribute).build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the equivalent NMS attribute.
|
||||
*
|
||||
* @param attribute - the wrapped attribute.
|
||||
* @return The equivalent NMS attribute.
|
||||
*/
|
||||
private AttributeSnapshot getAttributeCopy(WrappedAttribute attribute) {
|
||||
List<AttributeModifier> modifiers = new ArrayList<>();
|
||||
|
||||
for (WrappedAttributeModifier wrapper : attribute.getModifiers()) {
|
||||
modifiers.add((AttributeModifier) wrapper.getHandle());
|
||||
}
|
||||
|
||||
AttributeBase base = IRegistry.ak.a(MinecraftKey.a(attribute.getAttributeKey()));
|
||||
return new AttributeSnapshot(base, attribute.getBaseValue(), modifiers);
|
||||
}
|
||||
|
||||
private AttributeModifier getModifierCopy(WrappedAttributeModifier modifier) {
|
||||
AttributeModifier.Operation operation = AttributeModifier.Operation.values()[modifier.getOperation().getId()];
|
||||
return new AttributeModifier(modifier.getUUID(), modifier.getName(), modifier.getAmount(), operation);
|
||||
}
|
||||
}
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.wrappers.WrappedAttributeModifier.Operation;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import net.minecraft.core.IRegistry;
|
||||
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes.AttributeSnapshot;
|
||||
import net.minecraft.resources.MinecraftKey;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeBase;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class WrappedAttributeTest {
|
||||
|
||||
private WrappedAttributeModifier doubleModifier;
|
||||
private WrappedAttributeModifier constantModifier;
|
||||
private WrappedAttribute attribute;
|
||||
|
||||
@BeforeAll
|
||||
public static void initializeBukkit() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
// Create a couple of modifiers
|
||||
this.doubleModifier =
|
||||
WrappedAttributeModifier.newBuilder().
|
||||
name("Double Damage").
|
||||
amount(1).
|
||||
operation(Operation.ADD_PERCENTAGE).
|
||||
build();
|
||||
this.constantModifier =
|
||||
WrappedAttributeModifier.newBuilder().
|
||||
name("Damage Bonus").
|
||||
amount(5).
|
||||
operation(Operation.ADD_NUMBER).
|
||||
build();
|
||||
|
||||
// Create attribute
|
||||
this.attribute = WrappedAttribute.newBuilder().
|
||||
attributeKey("generic.attackDamage").
|
||||
baseValue(2).
|
||||
packet(new PacketContainer(PacketType.Play.Server.UPDATE_ATTRIBUTES)).
|
||||
modifiers(Lists.newArrayList(this.constantModifier, this.doubleModifier)).
|
||||
build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquality() {
|
||||
// Check wrapped equality
|
||||
assertEquals(this.doubleModifier, this.doubleModifier);
|
||||
assertNotSame(this.constantModifier, this.doubleModifier);
|
||||
|
||||
assertEquals(this.doubleModifier.getHandle(), this.getModifierCopy(this.doubleModifier));
|
||||
assertEquals(this.constantModifier.getHandle(), this.getModifierCopy(this.constantModifier));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttribute() {
|
||||
assertEquals(this.attribute, WrappedAttribute.fromHandle(this.getAttributeCopy(this.attribute)));
|
||||
|
||||
assertTrue(this.attribute.hasModifier(this.doubleModifier.getUUID()));
|
||||
assertTrue(this.attribute.hasModifier(this.constantModifier.getUUID()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromTemplate() {
|
||||
assertEquals(this.attribute, WrappedAttribute.newBuilder(this.attribute).build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the equivalent NMS attribute.
|
||||
*
|
||||
* @param attribute - the wrapped attribute.
|
||||
* @return The equivalent NMS attribute.
|
||||
*/
|
||||
private AttributeSnapshot getAttributeCopy(WrappedAttribute attribute) {
|
||||
List<AttributeModifier> modifiers = new ArrayList<>();
|
||||
|
||||
for (WrappedAttributeModifier wrapper : attribute.getModifiers()) {
|
||||
modifiers.add((AttributeModifier) wrapper.getHandle());
|
||||
}
|
||||
|
||||
AttributeBase base = IRegistry.ak.a(MinecraftKey.a(attribute.getAttributeKey()));
|
||||
return new AttributeSnapshot(base, attribute.getBaseValue(), modifiers);
|
||||
}
|
||||
|
||||
private AttributeModifier getModifierCopy(WrappedAttributeModifier modifier) {
|
||||
AttributeModifier.Operation operation = AttributeModifier.Operation.values()[modifier.getOperation().getId()];
|
||||
return new AttributeModifier(modifier.getUUID(), modifier.getName(), modifier.getAmount(), operation);
|
||||
}
|
||||
}
|
||||
|
@ -1,70 +1,70 @@
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2015 dmulloy2
|
||||
* <p>
|
||||
* 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
|
||||
* version.
|
||||
* <p>
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
* <p>
|
||||
* 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
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import net.minecraft.world.level.block.state.IBlockData;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.BlockFace;
|
||||
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.impl.CraftStainedGlassPane;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.util.CraftMagicNumbers;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @author dmulloy2
|
||||
*/
|
||||
|
||||
public class WrappedBlockDataTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void initializeBukkit() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMaterialCreation() {
|
||||
Material type = Material.BLUE_WOOL;
|
||||
|
||||
WrappedBlockData wrapper = WrappedBlockData.createData(type);
|
||||
|
||||
assertEquals(wrapper.getType(), type);
|
||||
//assertEquals(wrapper.getData(), data);
|
||||
|
||||
Object generic = BukkitConverters.getWrappedBlockDataConverter().getGeneric(wrapper);
|
||||
WrappedBlockData back = BukkitConverters.getWrappedBlockDataConverter().getSpecific(generic);
|
||||
|
||||
assertEquals(wrapper.getType(), back.getType());
|
||||
assertEquals(wrapper.getData(), back.getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDataCreation() {
|
||||
IBlockData nmsData = CraftMagicNumbers.getBlock(Material.CYAN_STAINED_GLASS_PANE).m();
|
||||
GlassPane data = (GlassPane) CraftBlockData.fromData(nmsData);
|
||||
data.setFace(BlockFace.EAST, true);
|
||||
|
||||
WrappedBlockData wrapper = WrappedBlockData.createData(data);
|
||||
assertEquals(wrapper.getType(), Material.CYAN_STAINED_GLASS_PANE);
|
||||
|
||||
GlassPane back = new CraftStainedGlassPane((IBlockData) wrapper.getHandle());
|
||||
assertEquals(back.hasFace(BlockFace.EAST), data.hasFace(BlockFace.EAST));
|
||||
assertEquals(back.hasFace(BlockFace.SOUTH), data.hasFace(BlockFace.SOUTH));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2015 dmulloy2
|
||||
* <p>
|
||||
* 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
|
||||
* version.
|
||||
* <p>
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
* <p>
|
||||
* 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
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import net.minecraft.world.level.block.state.IBlockData;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.BlockFace;
|
||||
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.impl.CraftStainedGlassPane;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.util.CraftMagicNumbers;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @author dmulloy2
|
||||
*/
|
||||
|
||||
public class WrappedBlockDataTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void initializeBukkit() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMaterialCreation() {
|
||||
Material type = Material.BLUE_WOOL;
|
||||
|
||||
WrappedBlockData wrapper = WrappedBlockData.createData(type);
|
||||
|
||||
assertEquals(wrapper.getType(), type);
|
||||
//assertEquals(wrapper.getData(), data);
|
||||
|
||||
Object generic = BukkitConverters.getWrappedBlockDataConverter().getGeneric(wrapper);
|
||||
WrappedBlockData back = BukkitConverters.getWrappedBlockDataConverter().getSpecific(generic);
|
||||
|
||||
assertEquals(wrapper.getType(), back.getType());
|
||||
assertEquals(wrapper.getData(), back.getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDataCreation() {
|
||||
IBlockData nmsData = CraftMagicNumbers.getBlock(Material.CYAN_STAINED_GLASS_PANE).m();
|
||||
GlassPane data = (GlassPane) CraftBlockData.fromData(nmsData);
|
||||
data.setFace(BlockFace.EAST, true);
|
||||
|
||||
WrappedBlockData wrapper = WrappedBlockData.createData(data);
|
||||
assertEquals(wrapper.getType(), Material.CYAN_STAINED_GLASS_PANE);
|
||||
|
||||
GlassPane back = new CraftStainedGlassPane((IBlockData) wrapper.getHandle());
|
||||
assertEquals(back.hasFace(BlockFace.EAST), data.hasFace(BlockFace.EAST));
|
||||
assertEquals(back.hasFace(BlockFace.SOUTH), data.hasFace(BlockFace.SOUTH));
|
||||
}
|
||||
}
|
||||
|
@ -1,115 +1,115 @@
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2016 dmulloy2
|
||||
* <p>
|
||||
* 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
|
||||
* version.
|
||||
* <p>
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
* <p>
|
||||
* 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
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject;
|
||||
import java.util.UUID;
|
||||
import net.minecraft.world.entity.projectile.EntityEgg;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftEgg;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftEntity;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class WrappedDataWatcherTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void prepare() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBytes() {
|
||||
// Create a fake lightning strike and get its watcher
|
||||
EntityEgg nmsEgg = new EntityEgg(null, 0, 0, 0);
|
||||
CraftEntity craftEgg = new CraftEgg(null, nmsEgg);
|
||||
WrappedDataWatcher wrapper = WrappedDataWatcher.getEntityWatcher(craftEgg);
|
||||
|
||||
WrappedWatchableObject watchable = wrapper.getWatchableObject(0);
|
||||
WrappedDataWatcherObject object = watchable.getWatcherObject();
|
||||
|
||||
// Make sure the serializers work
|
||||
assertEquals(object.getSerializer(), Registry.get(Byte.class));
|
||||
|
||||
// Make sure we can set existing objects
|
||||
wrapper.setObject(0, (byte) 21);
|
||||
assertEquals(21, (byte) wrapper.getByte(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStrings() {
|
||||
WrappedDataWatcher wrapper = new WrappedDataWatcher();
|
||||
|
||||
// Make sure we can create watcher objects
|
||||
Serializer serializer = Registry.get(String.class);
|
||||
WrappedDataWatcherObject object = new WrappedDataWatcherObject(3, serializer);
|
||||
wrapper.setObject(object, "Test");
|
||||
|
||||
assertEquals(wrapper.getString(3), "Test");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFloats() {
|
||||
WrappedDataWatcher wrapper = new WrappedDataWatcher();
|
||||
|
||||
// Make sure we can add new entries
|
||||
Serializer serializer = Registry.get(Float.class);
|
||||
WrappedDataWatcherObject object = new WrappedDataWatcherObject(10, serializer);
|
||||
wrapper.setObject(object, 21.0F);
|
||||
|
||||
assertTrue(wrapper.hasIndex(10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerializers() {
|
||||
Serializer blockPos = Registry.get(net.minecraft.core.BlockPosition.class, false);
|
||||
Serializer optionalBlockPos = Registry.get(net.minecraft.core.BlockPosition.class, true);
|
||||
assertNotSame(blockPos, optionalBlockPos);
|
||||
|
||||
// assertNull(Registry.get(ItemStack.class, false));
|
||||
assertNotNull(Registry.get(UUID.class, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHasIndex() {
|
||||
WrappedDataWatcher watcher = new WrappedDataWatcher();
|
||||
Serializer serializer = Registry.get(Integer.class);
|
||||
|
||||
assertFalse(watcher.hasIndex(0));
|
||||
watcher.setObject(0, serializer, 1);
|
||||
assertTrue(watcher.hasIndex(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeepClone() {
|
||||
WrappedDataWatcher watcher = new WrappedDataWatcher();
|
||||
watcher.setObject(0, Registry.get(Integer.class), 1);
|
||||
|
||||
WrappedDataWatcher cloned = watcher.deepClone();
|
||||
assertEquals(1, cloned.asMap().size());
|
||||
assertEquals(1, (Object) cloned.getInteger(0));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2016 dmulloy2
|
||||
* <p>
|
||||
* 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
|
||||
* version.
|
||||
* <p>
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
* <p>
|
||||
* 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
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject;
|
||||
import java.util.UUID;
|
||||
import net.minecraft.world.entity.projectile.EntityEgg;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftEgg;
|
||||
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftEntity;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class WrappedDataWatcherTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void prepare() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBytes() {
|
||||
// Create a fake lightning strike and get its watcher
|
||||
EntityEgg nmsEgg = new EntityEgg(null, 0, 0, 0);
|
||||
CraftEntity craftEgg = new CraftEgg(null, nmsEgg);
|
||||
WrappedDataWatcher wrapper = WrappedDataWatcher.getEntityWatcher(craftEgg);
|
||||
|
||||
WrappedWatchableObject watchable = wrapper.getWatchableObject(0);
|
||||
WrappedDataWatcherObject object = watchable.getWatcherObject();
|
||||
|
||||
// Make sure the serializers work
|
||||
assertEquals(object.getSerializer(), Registry.get(Byte.class));
|
||||
|
||||
// Make sure we can set existing objects
|
||||
wrapper.setObject(0, (byte) 21);
|
||||
assertEquals(21, (byte) wrapper.getByte(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStrings() {
|
||||
WrappedDataWatcher wrapper = new WrappedDataWatcher();
|
||||
|
||||
// Make sure we can create watcher objects
|
||||
Serializer serializer = Registry.get(String.class);
|
||||
WrappedDataWatcherObject object = new WrappedDataWatcherObject(3, serializer);
|
||||
wrapper.setObject(object, "Test");
|
||||
|
||||
assertEquals(wrapper.getString(3), "Test");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFloats() {
|
||||
WrappedDataWatcher wrapper = new WrappedDataWatcher();
|
||||
|
||||
// Make sure we can add new entries
|
||||
Serializer serializer = Registry.get(Float.class);
|
||||
WrappedDataWatcherObject object = new WrappedDataWatcherObject(10, serializer);
|
||||
wrapper.setObject(object, 21.0F);
|
||||
|
||||
assertTrue(wrapper.hasIndex(10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerializers() {
|
||||
Serializer blockPos = Registry.get(net.minecraft.core.BlockPosition.class, false);
|
||||
Serializer optionalBlockPos = Registry.get(net.minecraft.core.BlockPosition.class, true);
|
||||
assertNotSame(blockPos, optionalBlockPos);
|
||||
|
||||
// assertNull(Registry.get(ItemStack.class, false));
|
||||
assertNotNull(Registry.get(UUID.class, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHasIndex() {
|
||||
WrappedDataWatcher watcher = new WrappedDataWatcher();
|
||||
Serializer serializer = Registry.get(Integer.class);
|
||||
|
||||
assertFalse(watcher.hasIndex(0));
|
||||
watcher.setObject(0, serializer, 1);
|
||||
assertTrue(watcher.hasIndex(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeepClone() {
|
||||
WrappedDataWatcher watcher = new WrappedDataWatcher();
|
||||
watcher.setObject(0, Registry.get(Integer.class), 1);
|
||||
|
||||
WrappedDataWatcher cloned = watcher.deepClone();
|
||||
assertEquals(1, cloned.asMap().size());
|
||||
assertEquals(1, (Object) cloned.getInteger(0));
|
||||
}
|
||||
}
|
||||
|
@ -1,62 +1,62 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import static com.comphenix.protocol.utility.TestUtils.assertItemsEqual;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.Particle.DustOptions;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class WrappedParticleTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBlockData() {
|
||||
PacketContainer packet = new PacketContainer(PacketType.Play.Server.WORLD_PARTICLES);
|
||||
|
||||
WrappedParticle before = WrappedParticle.create(Particle.BLOCK_CRACK,
|
||||
WrappedBlockData.createData(Material.LAPIS_BLOCK));
|
||||
packet.getNewParticles().write(0, before);
|
||||
|
||||
WrappedParticle after = packet.getNewParticles().read(0);
|
||||
assertEquals(before.getParticle(), after.getParticle());
|
||||
assertEquals(before.getData(), after.getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testItemStacks() {
|
||||
PacketContainer packet = new PacketContainer(PacketType.Play.Server.WORLD_PARTICLES);
|
||||
WrappedParticle before = WrappedParticle.create(Particle.ITEM_CRACK, new ItemStack(Material.FLINT_AND_STEEL));
|
||||
packet.getNewParticles().write(0, before);
|
||||
|
||||
WrappedParticle after = packet.getNewParticles().read(0);
|
||||
assertEquals(before.getParticle(), after.getParticle());
|
||||
assertItemsEqual((ItemStack) before.getData(), (ItemStack) after.getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedstone() {
|
||||
PacketContainer packet = new PacketContainer(PacketType.Play.Server.WORLD_PARTICLES);
|
||||
WrappedParticle before = WrappedParticle.create(Particle.REDSTONE, new DustOptions(Color.BLUE, 1));
|
||||
packet.getNewParticles().write(0, before);
|
||||
|
||||
WrappedParticle after = packet.getNewParticles().read(0);
|
||||
assertEquals(before.getParticle(), after.getParticle());
|
||||
|
||||
DustOptions beforeDust = (DustOptions) before.getData();
|
||||
DustOptions afterDust = (DustOptions) after.getData();
|
||||
assertEquals(beforeDust.getColor(), afterDust.getColor());
|
||||
assertEquals(beforeDust.getSize(), afterDust.getSize(), 0);
|
||||
}
|
||||
}
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import static com.comphenix.protocol.utility.TestUtils.assertItemsEqual;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.Particle.DustOptions;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class WrappedParticleTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBlockData() {
|
||||
PacketContainer packet = new PacketContainer(PacketType.Play.Server.WORLD_PARTICLES);
|
||||
|
||||
WrappedParticle before = WrappedParticle.create(Particle.BLOCK_CRACK,
|
||||
WrappedBlockData.createData(Material.LAPIS_BLOCK));
|
||||
packet.getNewParticles().write(0, before);
|
||||
|
||||
WrappedParticle after = packet.getNewParticles().read(0);
|
||||
assertEquals(before.getParticle(), after.getParticle());
|
||||
assertEquals(before.getData(), after.getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testItemStacks() {
|
||||
PacketContainer packet = new PacketContainer(PacketType.Play.Server.WORLD_PARTICLES);
|
||||
WrappedParticle before = WrappedParticle.create(Particle.ITEM_CRACK, new ItemStack(Material.FLINT_AND_STEEL));
|
||||
packet.getNewParticles().write(0, before);
|
||||
|
||||
WrappedParticle after = packet.getNewParticles().read(0);
|
||||
assertEquals(before.getParticle(), after.getParticle());
|
||||
assertItemsEqual((ItemStack) before.getData(), (ItemStack) after.getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedstone() {
|
||||
PacketContainer packet = new PacketContainer(PacketType.Play.Server.WORLD_PARTICLES);
|
||||
WrappedParticle before = WrappedParticle.create(Particle.REDSTONE, new DustOptions(Color.BLUE, 1));
|
||||
packet.getNewParticles().write(0, before);
|
||||
|
||||
WrappedParticle after = packet.getNewParticles().read(0);
|
||||
assertEquals(before.getParticle(), after.getParticle());
|
||||
|
||||
DustOptions beforeDust = (DustOptions) before.getData();
|
||||
DustOptions afterDust = (DustOptions) after.getData();
|
||||
assertEquals(beforeDust.getColor(), afterDust.getColor());
|
||||
assertEquals(beforeDust.getSize(), afterDust.getSize(), 0);
|
||||
}
|
||||
}
|
||||
|
@ -1,87 +1,87 @@
|
||||
/*
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2012 Kristian S. Stangeland
|
||||
*
|
||||
* 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 version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
|
||||
package com.comphenix.protocol.wrappers.nbt;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.nbt.io.NbtBinarySerializer;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutput;
|
||||
import java.io.DataOutputStream;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class NbtFactoryTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void initializeBukkit() throws IllegalAccessException {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromStream() {
|
||||
WrappedCompound compound = WrappedCompound.fromName("tag");
|
||||
compound.put("name", "Test Testerson");
|
||||
compound.put("age", 42);
|
||||
|
||||
compound.put(NbtFactory.ofList("nicknames", "a", "b", "c"));
|
||||
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
DataOutput test = new DataOutputStream(buffer);
|
||||
compound.write(test);
|
||||
|
||||
ByteArrayInputStream source = new ByteArrayInputStream(buffer.toByteArray());
|
||||
DataInput input = new DataInputStream(source);
|
||||
|
||||
NbtCompound cloned = NbtBinarySerializer.DEFAULT.deserializeCompound(input);
|
||||
|
||||
assertEquals(compound.getString("name"), cloned.getString("name"));
|
||||
assertEquals(compound.getInteger("age"), cloned.getInteger("age"));
|
||||
assertEquals(compound.getList("nicknames"), cloned.getList("nicknames"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testItemTag() {
|
||||
ItemStack test = new ItemStack(Items.L);
|
||||
org.bukkit.inventory.ItemStack craftTest = MinecraftReflection.getBukkitItemStack(test);
|
||||
|
||||
NbtCompound compound = NbtFactory.ofCompound("tag");
|
||||
compound.put("name", "Test Testerson");
|
||||
compound.put("age", 42);
|
||||
|
||||
NbtFactory.setItemTag(craftTest, compound);
|
||||
|
||||
assertEquals(compound, NbtFactory.fromItemTag(craftTest));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateTags() {
|
||||
for (NbtType type : NbtType.values()) {
|
||||
if (type != NbtType.TAG_END) {
|
||||
NbtFactory.ofWrapper(type, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2012 Kristian S. Stangeland
|
||||
*
|
||||
* 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 version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
|
||||
package com.comphenix.protocol.wrappers.nbt;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.nbt.io.NbtBinarySerializer;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutput;
|
||||
import java.io.DataOutputStream;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class NbtFactoryTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void initializeBukkit() throws IllegalAccessException {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromStream() {
|
||||
WrappedCompound compound = WrappedCompound.fromName("tag");
|
||||
compound.put("name", "Test Testerson");
|
||||
compound.put("age", 42);
|
||||
|
||||
compound.put(NbtFactory.ofList("nicknames", "a", "b", "c"));
|
||||
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
DataOutput test = new DataOutputStream(buffer);
|
||||
compound.write(test);
|
||||
|
||||
ByteArrayInputStream source = new ByteArrayInputStream(buffer.toByteArray());
|
||||
DataInput input = new DataInputStream(source);
|
||||
|
||||
NbtCompound cloned = NbtBinarySerializer.DEFAULT.deserializeCompound(input);
|
||||
|
||||
assertEquals(compound.getString("name"), cloned.getString("name"));
|
||||
assertEquals(compound.getInteger("age"), cloned.getInteger("age"));
|
||||
assertEquals(compound.getList("nicknames"), cloned.getList("nicknames"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testItemTag() {
|
||||
ItemStack test = new ItemStack(Items.L);
|
||||
org.bukkit.inventory.ItemStack craftTest = MinecraftReflection.getBukkitItemStack(test);
|
||||
|
||||
NbtCompound compound = NbtFactory.ofCompound("tag");
|
||||
compound.put("name", "Test Testerson");
|
||||
compound.put("age", 42);
|
||||
|
||||
NbtFactory.setItemTag(craftTest, compound);
|
||||
|
||||
assertEquals(compound, NbtFactory.fromItemTag(craftTest));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateTags() {
|
||||
for (NbtType type : NbtType.values()) {
|
||||
if (type != NbtType.TAG_END) {
|
||||
NbtFactory.ofWrapper(type, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,38 +1,38 @@
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2016 dmulloy2
|
||||
* <p>
|
||||
* 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
|
||||
* version.
|
||||
* <p>
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
* <p>
|
||||
* 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
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers.nbt;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class TileEntityTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
// Ensure the read and write methods exist
|
||||
TileEntityAccessor<BlockState> accessor = new TileEntityAccessor<>();
|
||||
accessor.findMethods(null, null);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2016 dmulloy2
|
||||
* <p>
|
||||
* 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
|
||||
* version.
|
||||
* <p>
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
* <p>
|
||||
* 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
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers.nbt;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class TileEntityTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
// Ensure the read and write methods exist
|
||||
TileEntityAccessor<BlockState> accessor = new TileEntityAccessor<>();
|
||||
accessor.findMethods(null, null);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user