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