Added Networking API (#180)

* sent data to client

* send more data + debug + add docs + switch to handshake

* add diff between container and normal changes

* fix docs

* changes according guidelines

* make requested changes + cleanup

* correct documentation

* Improved Networking API documentation

* Moved networking API channel registration out of main class

* Cleanup

* Removed debug on chat/command lookups

* Optimized array merging

* Fixed ClassCastException when running console commands

* Skip preparing networking data if not a channel player

* Renamed "networking-debug" to "network-debug"

* Fixed failed handshake still registering players

* Adjusted networking phrases

* Renamed pluginchannel to channel

Co-authored-by: Intelli <contact@intelli.software>
This commit is contained in:
vacla 2022-03-24 01:49:46 +01:00 committed by GitHub
parent e848d65b93
commit 8cdf99429d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 554 additions and 3 deletions

99
docs/api/networking.md Normal file
View File

@ -0,0 +1,99 @@
# Networking API
The CoreProtect Networking API allows clients to receive data using packets.
| Networking Details | |
|-------------------------|--------|
| **Networking Version:** | 1 |
| **Plugin Version:** | v21.3+ |
---
## Packets
The server will not respond unless the player has the correct permission, which is `coreprotect.networking`.
---
## Server to Client
### Data Packet
Sends data from the database.
* Channel: `coreprotect:data`
| Type: `Int` | 1 | 2 | 3 | 4 |
|-------------|------------------------|------------------------|--------------------|--------------------|
| | Time: `long` | Time: `long` | Time: `long` | Time: `long` |
| | Phrase selector: `UTF` | Phrase selector: `UTF` | Result User: `UTF` | Result User: `UTF` |
| | Result User: `UTF` | Result User: `UTF` | Message: `UTF` | Target: `UTF` |
| | Target: `UTF` | Amount: `Int` | Sign: `Boolean` | |
| | Amount: `Int` | X: `Int` | X: `Int` | |
| | X: `Int` | Y: `Int` | Y: `Int` | |
| | Y: `Int` | Z: `Int` | Z: `Int` | |
| | Z: `Int` | World name: `UTF` | World name: `UTF` | |
| | World name: `UTF` | | | |
| | Rolledback: `Boolean` | | | |
| | isContainer: `Boolean` | | | |
| | Added: `Boolean` | | | |
Example (Fabric):
```
ByteArrayInputStream in = new ByteArrayInputStream(buf.getWrittenBytes());
DataInputStream dis = new DataInputStream(in);
int type = dis.readInt();
long time = dis.readLong();
String selector = dis.readUTF();
String resultUser = dis.readUTF();
String target = dis.readUTF();
int amount = dis.readInt();
int x = dis.readInt();
int y = dis.readInt();
int z = dis.readInt();
String worldName = dis.readUTF();
boolean rolledback = dis.readBoolean();
boolean isContainer = dis.readBoolean();
boolean added = dis.readBoolean();
```
### Handshake Packet
Sends handshake if player is registered.
* Channel: `coreprotect:handshake`
* Registered: `Boolean`
---
## Client to Server
### Handshake Packet
Sends handshake to register
* Channel: `coreprotect:handshake`
* Mod Version: `UTF`
* Mod Id: `UTF`
* CoreProtect Protocol: `Int`
Example (Fabric):
```
PacketByteBuf packetByteBuf = new PacketByteBuf(Unpooled.buffer());
ByteArrayOutputStream msgBytes = new ByteArrayOutputStream();
DataOutputStream msgOut = new DataOutputStream(msgBytes);
msgOut.writeUTF(modVersion);
msgOut.writeUTF(modId);
msgOut.writeInt(coreprotectProtocol);
packetByteBuf.writeBytes(msgBytes.toByteArray());
```
---
## Debugging
### /co network-debug
Allows you to debug the networking API if you are registered and have correct permissions.
To utilize the command, `network-debug: true` must be set in the CoreProtect `config.yml`.
**Example**
`/co network-debug <type>`
___

View File

@ -38,6 +38,9 @@ The following permissions can be used to restrict functionality within the plugi
&nbsp;
* **coreprotect.consumer** *(default: op)*
Allows access to the CoreProtect consumer command.
&nbsp;
* **coreprotect.networking** *(default: op)*
Allows access to the CoreProtect networking API.
---

View File

@ -125,6 +125,8 @@ MISSING_PARAMETERS: "Please use \"{0}\"."
MISSING_ROLLBACK_RADIUS: "You did not specify a {rollback|restore} radius."
MISSING_ROLLBACK_USER: "You did not specify a {rollback|restore} user."
MYSQL_UNAVAILABLE: "Unable to connect to MySQL server."
NETWORK_CONNECTION: "Connection by {0} {successful|failed}. Using {1} {2}."
NETWORK_TEST: "Network test data has been successful sent."
NO_DATA: "No data found at {0}."
NO_DATA_LOCATION: "No {data|transactions|interactions|messages} found at this location."
NO_PERMISSION: "You do not have permission to do that."

View File

@ -14,7 +14,6 @@ import net.coreprotect.config.Config;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.consumer.Consumer;
import net.coreprotect.consumer.process.Process;
import net.coreprotect.database.Database;
import net.coreprotect.language.Language;
import net.coreprotect.language.Phrase;
import net.coreprotect.listener.ListenerHandler;
@ -200,7 +199,7 @@ public final class CoreProtect extends JavaPlugin {
Thread.sleep(100);
}
Database.closeConnection();
ConfigHandler.performDisable();
Chat.console(Phrase.build(Phrase.DISABLE_SUCCESS, "CoreProtect v" + plugin.getDescription().getVersion()));
}
catch (Exception e) {

View File

@ -1196,6 +1196,9 @@ public class CommandHandler implements CommandExecutor {
else if (user.hasPermission("coreprotect.consumer") && corecommand.equals("consumer")) {
permission = true;
}
else if (user.hasPermission("coreprotect.networking") && corecommand.equals("network-debug")) {
permission = true;
}
}
if (corecommand.equals("rollback") || corecommand.equals("restore") || corecommand.equals("rb") || corecommand.equals("rs") || corecommand.equals("ro") || corecommand.equals("re")) {
@ -1237,6 +1240,9 @@ public class CommandHandler implements CommandExecutor {
else if (corecommand.equals("consumer")) {
ConsumerCommand.runCommand(user, permission, argumentArray);
}
else if (corecommand.equals("network-debug")) {
NetworkDebugCommand.runCommand(user, permission, argumentArray);
}
else {
Chat.sendMessage(user, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.COMMAND_NOT_FOUND, Color.WHITE, "/co " + corecommand));
}

View File

@ -34,6 +34,8 @@ import net.coreprotect.database.lookup.SignMessageLookup;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.language.Phrase;
import net.coreprotect.language.Selector;
import net.coreprotect.listener.channel.PluginChannelHandshakeListener;
import net.coreprotect.listener.channel.PluginChannelListener;
import net.coreprotect.utility.Chat;
import net.coreprotect.utility.ChatMessage;
import net.coreprotect.utility.Color;
@ -832,6 +834,13 @@ public class LookupCommand {
String message = data[2];
String timeago = Util.getTimeSince(Integer.parseInt(time), unixtimestamp, true);
Chat.sendComponent(player2, timeago + " " + Color.WHITE + "- " + Color.DARK_AQUA + dplayer + ": " + Color.WHITE, message);
if (PluginChannelHandshakeListener.getInstance().isPluginChannelPlayer(player2)) {
int wid = Integer.parseInt(data[3]);
int x = Integer.parseInt(data[4]);
int y = Integer.parseInt(data[5]);
int z = Integer.parseInt(data[6]);
PluginChannelListener.getInstance().sendMessageData(player2, Integer.parseInt(time), dplayer, message, false, x, y, z, wid);
}
}
}
else if (finalArgAction.contains(8)) { // login/logouts
@ -856,6 +865,7 @@ public class LookupCommand {
String tag = (action != 0 ? Color.GREEN + "+" : Color.RED + "-");
Chat.sendComponent(player2, timeago + " " + tag + " " + Color.DARK_AQUA + Phrase.build(Phrase.LOOKUP_LOGIN, Color.DARK_AQUA + dplayer + Color.WHITE, (action != 0 ? Selector.FIRST : Selector.SECOND)));
Chat.sendComponent(player2, Color.WHITE + leftPadding + Color.GREY + "^ " + Util.getCoordinates(command.getName(), wid, x, y, z, true, true) + "");
PluginChannelListener.getInstance().sendInfoData(player2, Integer.parseInt(time), Phrase.LOOKUP_LOGIN, (action != 0 ? Selector.FIRST : Selector.SECOND), dplayer, -1, x, y, z, wid);
}
}
else if (finalArgAction.contains(9)) { // username-changes
@ -865,6 +875,7 @@ public class LookupCommand {
String username = data[2];
String timeago = Util.getTimeSince(Integer.parseInt(time), unixtimestamp, true);
Chat.sendComponent(player2, timeago + " " + Color.WHITE + "- " + Phrase.build(Phrase.LOOKUP_USERNAME, Color.DARK_AQUA + user + Color.WHITE, Color.DARK_AQUA + username + Color.WHITE));
PluginChannelListener.getInstance().sendUsernameData(player2, Integer.parseInt(time), user, username);
}
}
else if (finalArgAction.contains(10)) { // sign messages
@ -888,6 +899,7 @@ public class LookupCommand {
Chat.sendComponent(player2, timeago + " " + Color.WHITE + "- " + Color.DARK_AQUA + dplayer + ": " + Color.WHITE, message);
Chat.sendComponent(player2, Color.WHITE + leftPadding + Color.GREY + "^ " + Util.getCoordinates(command.getName(), wid, x, y, z, true, true) + "");
PluginChannelListener.getInstance().sendMessageData(player2, Integer.parseInt(time), dplayer, message, true, x, y, z, wid);
}
}
else if (finalArgAction.contains(4) && finalArgAction.contains(11)) { // inventory transactions
@ -898,6 +910,10 @@ public class LookupCommand {
int ddata = Integer.parseInt(data[6]);
int daction = Integer.parseInt(data[7]);
int amount = Integer.parseInt(data[10]);
int wid = Integer.parseInt(data[9]);
int x = Integer.parseInt(data[2]);
int y = Integer.parseInt(data[3]);
int z = Integer.parseInt(data[4]);
String rbd = ((Integer.parseInt(data[8]) == 2 || Integer.parseInt(data[8]) == 3) ? Color.STRIKETHROUGH : "");
String timeago = Util.getTimeSince(Integer.parseInt(time), unixtimestamp, true);
Material blockType = Util.itemFilter(Util.getType(Integer.parseInt(dtype)), (Integer.parseInt(data[13]) == 0));
@ -931,6 +947,7 @@ public class LookupCommand {
}
Chat.sendComponent(player2, timeago + " " + tag + " " + Phrase.build(Phrase.LOOKUP_CONTAINER, Color.DARK_AQUA + rbd + dplayer + Color.WHITE + rbd, "x" + amount, Color.DARK_AQUA + rbd + dname + Color.WHITE, selector));
PluginChannelListener.getInstance().sendData(player2, Integer.parseInt(time), Phrase.LOOKUP_CONTAINER, selector, dplayer, dname, amount, x, y, z, wid, rbd, true, tag.contains("+"));
}
}
else {
@ -1024,6 +1041,7 @@ public class LookupCommand {
}
Chat.sendComponent(player2, timeago + " " + tag + " " + Phrase.build(phrase, Color.DARK_AQUA + rbd + dplayer + Color.WHITE + rbd, "x" + amount, Color.DARK_AQUA + rbd + dname + Color.WHITE, selector));
PluginChannelListener.getInstance().sendData(player2, Integer.parseInt(time), phrase, selector, dplayer, dname, (tag.contains("+") ? 1 : -1), x, y, z, wid, rbd, action.contains("container"), tag.contains("+"));
}
else {
if (daction == 2 || daction == 3) {
@ -1039,6 +1057,7 @@ public class LookupCommand {
}
Chat.sendComponent(player2, timeago + " " + tag + " " + Phrase.build(phrase, Color.DARK_AQUA + rbd + dplayer + Color.WHITE + rbd, Color.DARK_AQUA + rbd + dname + Color.WHITE, selector));
PluginChannelListener.getInstance().sendData(player2, Integer.parseInt(time), phrase, selector, dplayer, dname, (tag.contains("+") ? 1 : -1), x, y, z, wid, rbd, false, tag.contains("+"));
}
action = (finalArgAction.size() == 0 ? " (" + action + ")" : "");

View File

@ -0,0 +1,25 @@
package net.coreprotect.command;
import org.bukkit.command.CommandSender;
import net.coreprotect.config.Config;
import net.coreprotect.language.Phrase;
import net.coreprotect.listener.channel.PluginChannelListener;
import net.coreprotect.utility.Chat;
import net.coreprotect.utility.Color;
public class NetworkDebugCommand {
protected static void runCommand(CommandSender player, boolean permission, String[] args) {
if (!permission || !Config.getGlobal().NETWORK_DEBUG) {
Chat.sendMessage(player, Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.NO_PERMISSION));
return;
}
try {
PluginChannelListener.getInstance().sendTest(player, args.length == 2 ? args[1] : "");
}
catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -48,6 +48,7 @@ public class Config extends Language {
public boolean LOG_CANCELLED_CHAT;
public boolean HOPPER_FILTER_META;
public boolean EXCLUDE_TNT;
public boolean NETWORK_DEBUG;
public boolean MYSQL;
public boolean CHECK_UPDATES;
public boolean API_ENABLED;
@ -189,6 +190,7 @@ public class Config extends Language {
this.LOG_CANCELLED_CHAT = this.getBoolean("log-cancelled-chat", true);
this.HOPPER_FILTER_META = this.getBoolean("hopper-filter-meta", false);
this.EXCLUDE_TNT = this.getBoolean("exclude-tnt", false);
this.NETWORK_DEBUG = this.getBoolean("network-debug", false);
this.DONATION_KEY = this.getString("donation-key");
this.MYSQL = this.getBoolean("use-mysql");
this.PREFIX = this.getString("table-prefix");

View File

@ -28,6 +28,7 @@ import net.coreprotect.consumer.Queue;
import net.coreprotect.database.Database;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.language.Phrase;
import net.coreprotect.listener.ListenerHandler;
import net.coreprotect.model.BlockGroup;
import net.coreprotect.paper.PaperAdapter;
import net.coreprotect.patch.Patch;
@ -411,7 +412,7 @@ public class ConfigHandler extends Queue {
ConfigHandler.loadConfig(); // Load (or create) the configuration file.
ConfigHandler.loadDatabase(); // Initialize MySQL and create tables if necessary.
ListenerHandler.registerNetworking(); // Register channels for networking API
}
catch (Exception e) {
e.printStackTrace();
@ -455,4 +456,14 @@ public class ConfigHandler extends Queue {
return false;
}
public static void performDisable() {
try {
Database.closeConnection();
ListenerHandler.unregisterNetworking(); // Unregister channels for networking API
}
catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -22,6 +22,7 @@ import net.coreprotect.consumer.Consumer;
import net.coreprotect.consumer.Queue;
import net.coreprotect.database.logger.ItemLogger;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.listener.channel.PluginChannelHandshakeListener;
import net.coreprotect.thread.CacheHandler;
import net.coreprotect.utility.Util;
@ -147,6 +148,13 @@ public class Lookup extends Queue {
String resultMessage = results.getString("message");
Object[] dataArray = new Object[] { resultId, resultTime, resultUserId, resultMessage };
if (PluginChannelHandshakeListener.getInstance().isPluginChannelPlayer(user)) {
int resultWorldId = results.getInt("wid");
int resultX = results.getInt("x");
int resultY = results.getInt("y");
int resultZ = results.getInt("z");
dataArray = new Object[] { resultId, resultTime, resultUserId, resultMessage, resultWorldId, resultX, resultY, resultZ };
}
list.add(dataArray);
}
else if (actionList.contains(8)) {
@ -619,6 +627,9 @@ public class Lookup extends Queue {
else if (actionList.contains(6) || actionList.contains(7)) {
queryTable = "chat";
rows = "rowid as id,time,user,message";
if (PluginChannelHandshakeListener.getInstance().isPluginChannelPlayer(user)) {
rows += ",wid,x,y,z";
}
if (actionList.contains(7)) {
queryTable = "command";

View File

@ -12,6 +12,7 @@ import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.language.Phrase;
import net.coreprotect.language.Selector;
import net.coreprotect.listener.channel.PluginChannelListener;
import net.coreprotect.utility.Color;
import net.coreprotect.utility.Util;
@ -130,6 +131,7 @@ public class BlockLookup {
}
resultTextBuilder.append(timeAgo + " " + tag + " ").append(Phrase.build(phrase, Color.DARK_AQUA + rbFormat + resultUser + Color.WHITE + rbFormat, Color.DARK_AQUA + rbFormat + target + Color.WHITE, selector)).append("\n");
PluginChannelListener.getInstance().sendData(commandSender, resultTime, phrase, selector, resultUser, target, -1, x, y, z, worldId, rbFormat, false, tag.contains("+"));
}
resultText = resultTextBuilder.toString();

View File

@ -12,6 +12,7 @@ import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.language.Phrase;
import net.coreprotect.language.Selector;
import net.coreprotect.listener.channel.PluginChannelListener;
import net.coreprotect.utility.Color;
import net.coreprotect.utility.Util;
@ -117,6 +118,7 @@ public class ChestTransactionLookup {
}
resultBuilder.append(timeAgo + " " + tag + " ").append(Phrase.build(Phrase.LOOKUP_CONTAINER, Color.DARK_AQUA + rbFormat + resultUser + Color.WHITE + rbFormat, "x" + resultAmount, Color.DARK_AQUA + rbFormat + target + Color.WHITE, selector)).append("\n");
PluginChannelListener.getInstance().sendData(commandSender, resultTime, Phrase.LOOKUP_CONTAINER, selector, resultUser, target, resultAmount, x, y, z, worldId, rbFormat, true, tag.contains("+"));
}
result = resultBuilder.toString();
results.close();

View File

@ -12,6 +12,7 @@ import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.language.Phrase;
import net.coreprotect.language.Selector;
import net.coreprotect.listener.channel.PluginChannelListener;
import net.coreprotect.utility.Color;
import net.coreprotect.utility.Util;
@ -108,6 +109,7 @@ public class InteractionLookup {
}
resultBuilder.append(timeAgo + " " + Color.WHITE + "- ").append(Phrase.build(Phrase.LOOKUP_INTERACTION, Color.DARK_AQUA + rbFormat + resultUser + Color.WHITE + rbFormat, Color.DARK_AQUA + rbFormat + target + Color.WHITE, Selector.FIRST)).append("\n");
PluginChannelListener.getInstance().sendData(commandSender, resultTime, Phrase.LOOKUP_INTERACTION, Selector.FIRST, resultUser, target, -1, x, y, z, worldId, rbFormat, false, false);
}
result = resultBuilder.toString();
results.close();

View File

@ -12,6 +12,7 @@ import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.language.Phrase;
import net.coreprotect.language.Selector;
import net.coreprotect.listener.channel.PluginChannelListener;
import net.coreprotect.utility.Color;
import net.coreprotect.utility.Util;
@ -109,6 +110,7 @@ public class SignMessageLookup {
}
found = true;
result.add(timeAgo + Color.WHITE + " - " + Color.DARK_AQUA + resultUser + ": " + Color.WHITE + "\n" + message.toString() + Color.WHITE);
PluginChannelListener.getInstance().sendMessageData(commandSender, resultTime, resultUser, message.toString(), true, x, y, z, worldId);
}
results.close();

View File

@ -154,6 +154,8 @@ public class Language {
phrases.put(Phrase.MISSING_ROLLBACK_RADIUS, "You did not specify a {rollback|restore} radius.");
phrases.put(Phrase.MISSING_ROLLBACK_USER, "You did not specify a {rollback|restore} user.");
phrases.put(Phrase.MYSQL_UNAVAILABLE, "Unable to connect to MySQL server.");
phrases.put(Phrase.NETWORK_CONNECTION, "Connection by {0} {successful|failed}. Using {1} {2}.");
phrases.put(Phrase.NETWORK_TEST, "Network test data has been successful sent.");
phrases.put(Phrase.NO_DATA, "No data found at {0}.");
phrases.put(Phrase.NO_DATA_LOCATION, "No {data|transactions|interactions|messages} found at this location.");
phrases.put(Phrase.NO_PERMISSION, "You do not have permission to do that.");

View File

@ -3,6 +3,8 @@ package net.coreprotect.language;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.coreprotect.utility.ChatMessage;
import net.coreprotect.utility.Color;
@ -135,6 +137,8 @@ public enum Phrase {
MISSING_ROLLBACK_RADIUS,
MISSING_ROLLBACK_USER,
MYSQL_UNAVAILABLE,
NETWORK_CONNECTION,
NETWORK_TEST,
NO_DATA,
NO_DATA_LOCATION,
NO_PERMISSION,
@ -287,4 +291,16 @@ public enum Phrase {
return output;
}
public static String getPhraseSelector(Phrase phrase, String selector) {
String translatedPhrase = phrase.getTranslatedPhrase();
Pattern phrasePattern = Pattern.compile("(\\{[a-zA-Z| ]+})");
Matcher patternMatch = phrasePattern.matcher(translatedPhrase);
String match = "";
if (patternMatch.find()) {
match = patternMatch.group(1);
match = Selector.processSelection(match, selector, "");
}
return match;
}
}

View File

@ -15,6 +15,8 @@ import net.coreprotect.listener.block.BlockIgniteListener;
import net.coreprotect.listener.block.BlockPistonListener;
import net.coreprotect.listener.block.BlockPlaceListener;
import net.coreprotect.listener.block.BlockSpreadListener;
import net.coreprotect.listener.channel.PluginChannelHandshakeListener;
import net.coreprotect.listener.channel.PluginChannelListener;
import net.coreprotect.listener.entity.CreatureSpawnListener;
import net.coreprotect.listener.entity.EntityBlockFormListener;
import net.coreprotect.listener.entity.EntityChangeBlockListener;
@ -122,6 +124,20 @@ public final class ListenerHandler {
pluginManager.registerEvents(new PlayerChatListener(), plugin);
}
// Plugin channel events
pluginManager.registerEvents(new PluginChannelListener(), plugin);
}
public static void registerNetworking() {
CoreProtect.getInstance().getServer().getMessenger().registerIncomingPluginChannel(CoreProtect.getInstance(), PluginChannelHandshakeListener.pluginChannel, new PluginChannelHandshakeListener());
CoreProtect.getInstance().getServer().getMessenger().registerOutgoingPluginChannel(CoreProtect.getInstance(), PluginChannelHandshakeListener.pluginChannel);
CoreProtect.getInstance().getServer().getMessenger().registerOutgoingPluginChannel(CoreProtect.getInstance(), PluginChannelListener.pluginChannel);
}
public static void unregisterNetworking() {
CoreProtect.getInstance().getServer().getMessenger().unregisterIncomingPluginChannel(CoreProtect.getInstance(), PluginChannelHandshakeListener.pluginChannel);
CoreProtect.getInstance().getServer().getMessenger().unregisterOutgoingPluginChannel(CoreProtect.getInstance(), PluginChannelHandshakeListener.pluginChannel);
CoreProtect.getInstance().getServer().getMessenger().unregisterOutgoingPluginChannel(CoreProtect.getInstance(), PluginChannelListener.pluginChannel);
}
}

View File

@ -0,0 +1,109 @@
package net.coreprotect.listener.channel;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.plugin.messaging.PluginMessageListener;
import net.coreprotect.CoreProtect;
import net.coreprotect.config.Config;
import net.coreprotect.language.Phrase;
import net.coreprotect.language.Selector;
import net.coreprotect.utility.Chat;
public class PluginChannelHandshakeListener implements PluginMessageListener, Listener {
public static final String pluginChannel = "coreprotect:handshake";
private final int networkingProtocolVersion = 1;
private final Set<UUID> pluginChannelPlayers;
private static PluginChannelHandshakeListener instance;
public PluginChannelHandshakeListener() {
instance = this;
pluginChannelPlayers = new HashSet<>();
}
public static PluginChannelHandshakeListener getInstance() {
return instance;
}
public Set<UUID> getPluginChannelPlayers() {
return pluginChannelPlayers;
}
public boolean isPluginChannelPlayer(CommandSender commandSender) {
if (!(commandSender instanceof Player)) {
return false;
}
return getPluginChannelPlayers().contains(((Player) commandSender).getUniqueId());
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
getPluginChannelPlayers().remove(event.getPlayer().getUniqueId());
}
@Override
public void onPluginMessageReceived(String s, Player player, byte[] bytes) {
handleHandshake(s, player, bytes);
}
private void handleHandshake(String channel, Player player, byte[] bytes) {
if (!player.hasPermission("coreprotect.networking")) {
return;
}
if (!channel.equals(pluginChannel)) {
return;
}
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
DataInputStream dis = new DataInputStream(in);
try {
String modVersion = dis.readUTF();
String modId = dis.readUTF();
int protocolVersion = dis.readInt();
if (Config.getGlobal().NETWORK_DEBUG) {
Chat.console(new String(bytes));
Chat.console(modVersion);
Chat.console(modId);
Chat.console(String.valueOf(protocolVersion));
}
if (protocolVersion != networkingProtocolVersion) {
Chat.console(Phrase.build(Phrase.NETWORK_CONNECTION, player.getName(), modId, modVersion, Selector.SECOND));
return;
}
getPluginChannelPlayers().add(player.getUniqueId());
Chat.console(Phrase.build(Phrase.NETWORK_CONNECTION, player.getName(), modId, modVersion, Selector.FIRST));
player.sendPluginMessage(CoreProtect.getInstance(), pluginChannel, sendRegistered());
}
catch (Exception exception) {
Chat.console(exception.toString());
exception.printStackTrace();
}
}
private byte[] sendRegistered() throws IOException {
ByteArrayOutputStream msgBytes = new ByteArrayOutputStream();
DataOutputStream msgOut = new DataOutputStream(msgBytes);
msgOut.writeBoolean(true);
return msgBytes.toByteArray();
}
}

View File

@ -0,0 +1,218 @@
package net.coreprotect.listener.channel;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Random;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import net.coreprotect.CoreProtect;
import net.coreprotect.config.Config;
import net.coreprotect.language.Phrase;
import net.coreprotect.language.Selector;
import net.coreprotect.utility.Chat;
import net.coreprotect.utility.Color;
import net.coreprotect.utility.Util;
public class PluginChannelListener implements Listener {
public static final String pluginChannel = "coreprotect:data";
private static PluginChannelListener instance;
public PluginChannelListener() {
instance = this;
}
public static PluginChannelListener getInstance() {
return instance;
}
public void sendData(CommandSender commandSender, long timeAgo, Phrase phrase, String selector, String resultUser, String target, int amount, int x, int y, int z, int worldId, String rbFormat, boolean isContainer, boolean added) throws IOException {
if (!PluginChannelHandshakeListener.getInstance().isPluginChannelPlayer(commandSender)) {
return;
}
String phraseSelector = Phrase.getPhraseSelector(phrase, selector);
String worldName = Util.getWorldName(worldId);
ByteArrayOutputStream msgBytes = new ByteArrayOutputStream();
DataOutputStream msgOut = new DataOutputStream(msgBytes);
msgOut.writeInt(1);
msgOut.writeLong(timeAgo * 1000);
msgOut.writeUTF(phraseSelector);
msgOut.writeUTF(resultUser);
msgOut.writeUTF(target);
msgOut.writeInt(amount);
msgOut.writeInt(x);
msgOut.writeInt(y);
msgOut.writeInt(z);
msgOut.writeUTF(worldName);
msgOut.writeBoolean(!rbFormat.isEmpty());
msgOut.writeBoolean(isContainer);
msgOut.writeBoolean(added);
if (Config.getGlobal().NETWORK_DEBUG) {
Chat.console(String.valueOf(timeAgo * 1000));
Chat.console(phraseSelector);
Chat.console(resultUser);
Chat.console(target);
Chat.console(String.valueOf(amount));
Chat.console(String.valueOf(x));
Chat.console(String.valueOf(y));
Chat.console(String.valueOf(z));
Chat.console(worldName);
Chat.console(String.valueOf(!rbFormat.isEmpty()));
Chat.console(String.valueOf(isContainer));
Chat.console(String.valueOf(added));
Chat.console("");
}
send(commandSender, msgBytes.toByteArray());
}
public void sendInfoData(CommandSender commandSender, long timeAgo, Phrase phrase, String selector, String resultUser, int amount, int x, int y, int z, int worldId) throws IOException {
if (!PluginChannelHandshakeListener.getInstance().isPluginChannelPlayer(commandSender)) {
return;
}
String phraseSelector = Phrase.getPhraseSelector(phrase, selector);
String worldName = Util.getWorldName(worldId);
ByteArrayOutputStream msgBytes = new ByteArrayOutputStream();
DataOutputStream msgOut = new DataOutputStream(msgBytes);
msgOut.writeInt(2);
msgOut.writeLong(timeAgo * 1000);
msgOut.writeUTF(phraseSelector);
msgOut.writeUTF(resultUser);
msgOut.writeInt(amount);
msgOut.writeInt(x);
msgOut.writeInt(y);
msgOut.writeInt(z);
msgOut.writeUTF(worldName);
if (Config.getGlobal().NETWORK_DEBUG) {
Chat.console(String.valueOf(timeAgo * 1000));
Chat.console(phraseSelector);
Chat.console(resultUser);
Chat.console(String.valueOf(amount));
Chat.console(String.valueOf(x));
Chat.console(String.valueOf(y));
Chat.console(String.valueOf(z));
Chat.console(worldName);
Chat.console("");
}
send(commandSender, msgBytes.toByteArray());
}
public void sendMessageData(CommandSender commandSender, long timeAgo, String resultUser, String message, boolean sign, int x, int y, int z, int worldId) throws IOException {
if (!PluginChannelHandshakeListener.getInstance().isPluginChannelPlayer(commandSender)) {
return;
}
String worldName = Util.getWorldName(worldId);
ByteArrayOutputStream msgBytes = new ByteArrayOutputStream();
DataOutputStream msgOut = new DataOutputStream(msgBytes);
msgOut.writeInt(3);
msgOut.writeLong(timeAgo * 1000);
msgOut.writeUTF(resultUser);
msgOut.writeUTF(message);
msgOut.writeBoolean(sign);
msgOut.writeInt(x);
msgOut.writeInt(y);
msgOut.writeInt(z);
msgOut.writeUTF(worldName);
if (Config.getGlobal().NETWORK_DEBUG) {
Chat.console(String.valueOf(timeAgo * 1000));
Chat.console(resultUser);
Chat.console(message);
Chat.console(String.valueOf(sign));
Chat.console(String.valueOf(x));
Chat.console(String.valueOf(y));
Chat.console(String.valueOf(z));
Chat.console(worldName);
Chat.console("");
}
send(commandSender, msgBytes.toByteArray());
}
public void sendUsernameData(CommandSender commandSender, long timeAgo, String resultUser, String target) throws IOException {
if (!PluginChannelHandshakeListener.getInstance().isPluginChannelPlayer(commandSender)) {
return;
}
ByteArrayOutputStream msgBytes = new ByteArrayOutputStream();
DataOutputStream msgOut = new DataOutputStream(msgBytes);
msgOut.writeInt(4);
msgOut.writeLong(timeAgo * 1000);
msgOut.writeUTF(resultUser);
msgOut.writeUTF(target);
if (Config.getGlobal().NETWORK_DEBUG) {
Chat.console(String.valueOf(timeAgo * 1000));
Chat.console(resultUser);
Chat.console(target);
Chat.console("");
}
send(commandSender, msgBytes.toByteArray());
}
public void sendTest(CommandSender commandSender, String type) throws IOException {
if (!PluginChannelHandshakeListener.getInstance().isPluginChannelPlayer(commandSender)) {
return;
}
int worldId = 1;
Random rand = new Random();
int timeAgo = rand.nextInt(20);
String selector = Selector.FIRST;
String resultUser = "Anne";
int amount = 5;
int x = rand.nextInt(10);
int y = rand.nextInt(10);
int z = rand.nextInt(10);
String rbFormat = "test";
String message = "This is a test";
boolean sign = true;
switch (type) {
case "2":
sendInfoData(commandSender, timeAgo, Phrase.LOOKUP_LOGIN, selector, resultUser, amount, x, y, z, worldId);
break;
case "3":
sendMessageData(commandSender, timeAgo, resultUser, message, sign, x, y, z, worldId);
break;
case "4":
sendUsernameData(commandSender, timeAgo, resultUser, "Arne");
break;
default:
sendData(commandSender, timeAgo, Phrase.LOOKUP_CONTAINER, selector, resultUser, "clay_ball", amount, x, y, z, worldId, rbFormat, false, true);
break;
}
commandSender.sendMessage(Color.DARK_AQUA + "CoreProtect " + Color.WHITE + "- " + Phrase.build(Phrase.NETWORK_TEST));
}
private void send(CommandSender commandSender, byte[] msgBytes) {
if (!(commandSender instanceof Player)) {
return;
}
PluginChannelListener.getInstance().sendCoreProtectData((Player) commandSender, msgBytes);
}
private void sendCoreProtectData(Player player, byte[] data) {
if (!player.hasPermission("coreprotect.networking")) {
return;
}
player.sendPluginMessage(CoreProtect.getInstance(), pluginChannel, data);
}
}

View File

@ -50,6 +50,8 @@ permissions:
coreprotect.teleport: true
coreprotect.reload: true
coreprotect.status: true
coreprotect.consumer: true
coreprotect.networking: true
coreprotect.co:
description: Has permission to access the CoreProtect /co command
default: true
@ -137,4 +139,7 @@ permissions:
default: op
coreprotect.consumer:
description: Has permission to use the consumer command
default: op
coreprotect.networking:
description: Has permission to use the networking API
default: op