implement clickable message base - towards #68

This commit is contained in:
Luck 2016-12-07 21:08:30 +00:00
parent d820f153a9
commit 25511f898c
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
14 changed files with 315 additions and 2 deletions

View File

@ -50,6 +50,10 @@
</excludes>
</artifactSet>
<relocations>
<relocation>
<pattern>io.github.mkremins.fanciful</pattern>
<shadedPattern>me.lucko.luckperms.lib.fanciful</shadedPattern>
</relocation>
<relocation>
<pattern>org.slf4j</pattern>
<shadedPattern>me.lucko.luckperms.lib.slf4j</shadedPattern>
@ -108,8 +112,8 @@
<dependencies>
<!-- BukkitAPI -->
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.8.8-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>

View File

@ -22,6 +22,7 @@
package me.lucko.luckperms.bukkit;
import me.lucko.luckperms.bukkit.compat.MessageHandler;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.sender.SenderFactory;
import me.lucko.luckperms.common.constants.Constants;
@ -31,9 +32,14 @@ import org.bukkit.entity.Player;
import java.util.UUID;
import io.github.mkremins.fanciful.FancyMessage;
public class BukkitSenderFactory extends SenderFactory<CommandSender> {
private final MessageHandler messageHandler;
public BukkitSenderFactory(LuckPermsPlugin plugin) {
super(plugin);
messageHandler = new MessageHandler();
}
@Override
@ -57,6 +63,11 @@ public class BukkitSenderFactory extends SenderFactory<CommandSender> {
sender.sendMessage(s);
}
@Override
protected void sendMessage(CommandSender sender, FancyMessage message) {
messageHandler.sendJsonMessage(sender, message);
}
@Override
protected boolean hasPermission(CommandSender sender, String node) {
return sender.hasPermission(node);

View File

@ -0,0 +1,122 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.bukkit.compat;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class BukkitJsonMessageHandler {
private static boolean setup = false;
private static boolean triedAndFailed = false;
private static Method GET_HANDLE_METHOD;
private static Field PLAYER_CONNECTION_FIELD;
private static Method SEND_PACKET_METHOD;
private static Constructor<?> PACKET_CHAT_CONSTRUCTOR;
private static Method SERIALIZE_METHOD;
private static void setup(Object player) throws Exception {
Class<?> craftPlayerClass = player.getClass();
GET_HANDLE_METHOD = craftPlayerClass.getDeclaredMethod("getHandle");
Object handleObject = GET_HANDLE_METHOD.invoke(player);
Class<?> handleClass = handleObject.getClass();
PLAYER_CONNECTION_FIELD = handleClass.getDeclaredField("playerConnection");
Object playerConnectionObject = PLAYER_CONNECTION_FIELD.get(handleObject);
Method[] playerConnectionMethods = playerConnectionObject.getClass().getDeclaredMethods();
for (Method m : playerConnectionMethods) {
if (m.getName().equals("sendPacket")) {
SEND_PACKET_METHOD = m;
break;
}
}
Class<?> packetChatClass = Class.forName(getVersionedClassName("PacketPlayOutChat"));
Constructor[] packetConstructors = packetChatClass.getDeclaredConstructors();
for (Constructor c : packetConstructors) {
Class<?>[] parameters = c.getParameterTypes();
if (parameters.length == 1 && parameters[0].getName().endsWith("IChatBaseComponent")) {
PACKET_CHAT_CONSTRUCTOR = c;
break;
}
}
Class<?> baseComponentClass = Class.forName(getVersionedClassName("IChatBaseComponent"));
Class<?> chatSerializerClass = baseComponentClass.getClasses()[0];
SERIALIZE_METHOD = chatSerializerClass.getDeclaredMethod("a", String.class);
}
private static String getVersionedClassName(String className) {
Class server = Bukkit.getServer().getClass();
if (!server.getSimpleName().equals("CraftServer")) {
throw new RuntimeException("Couldn't reflect into server " + server);
}
String version;
if (server.getName().equals("org.bukkit.craftbukkit.CraftServer")) {
// Non versioned class
version = ".";
} else {
version = server.getName().substring("org.bukkit.craftbukkit".length());
version = version.substring(0, version.length() - "CraftServer".length());
}
return "net.minecraft.server" + version + className;
}
private static synchronized boolean trySetup(Object player) {
if (setup) return true;
if (triedAndFailed) return false;
try {
setup(player);
setup = true;
return true;
} catch (Exception e) {
triedAndFailed = true;
return false;
}
}
public boolean sendJsonMessage(Player player, String json) {
if (!trySetup(player)) {
return false;
}
try {
Object connection = PLAYER_CONNECTION_FIELD.get(GET_HANDLE_METHOD.invoke(player));
SEND_PACKET_METHOD.invoke(connection, PACKET_CHAT_CONSTRUCTOR.newInstance(SERIALIZE_METHOD.invoke(null, json)));
return true;
} catch (Exception e) {
return false;
}
}
}

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.bukkit.compat;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import io.github.mkremins.fanciful.FancyMessage;
public class MessageHandler {
private final BukkitJsonMessageHandler bukkitHandler;
private final SpigotJsonMessageHandler spigotHandler;
public MessageHandler() {
bukkitHandler = new BukkitJsonMessageHandler();
spigotHandler = isSpigot() ? new SpigotJsonMessageHandler() : null;
}
public void sendJsonMessage(CommandSender sender, FancyMessage message) {
if (sender instanceof Player) {
Player player = (Player) sender;
String json = message.toJSONString();
// Try Bukkit.
if (bukkitHandler.sendJsonMessage(player, json)) {
return;
}
// Try Spigot.
if (spigotHandler != null && spigotHandler.sendJsonMessage(player, json)) {
return;
}
}
// Fallback to Bukkit
sender.sendMessage(message.toOldMessageFormat());
}
private static boolean isSpigot() {
try {
Class.forName("net.md_5.bungee.chat.ComponentSerializer");
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.bukkit.compat;
import net.md_5.bungee.chat.ComponentSerializer;
import org.bukkit.entity.Player;
public class SpigotJsonMessageHandler {
public boolean sendJsonMessage(Player player, String json) {
try {
player.spigot().sendMessage(ComponentSerializer.parse(json));
return true;
} catch (Exception e) {
return false;
}
}
}

View File

@ -45,6 +45,10 @@
<configuration>
<minimizeJar>false</minimizeJar>
<relocations>
<relocation>
<pattern>io.github.mkremins.fanciful</pattern>
<shadedPattern>me.lucko.luckperms.lib.fanciful</shadedPattern>
</relocation>
<relocation>
<pattern>org.slf4j</pattern>
<shadedPattern>me.lucko.luckperms.lib.slf4j</shadedPattern>

View File

@ -29,9 +29,12 @@ import me.lucko.luckperms.common.constants.Constants;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.chat.ComponentSerializer;
import java.util.UUID;
import io.github.mkremins.fanciful.FancyMessage;
public class BungeeSenderFactory extends SenderFactory<CommandSender> {
public BungeeSenderFactory(LuckPermsPlugin plugin) {
super(plugin);
@ -58,6 +61,15 @@ public class BungeeSenderFactory extends SenderFactory<CommandSender> {
sender.sendMessage(new TextComponent(s));
}
@Override
protected void sendMessage(CommandSender sender, FancyMessage message) {
try {
sender.sendMessage(ComponentSerializer.parse(message.toJSONString()));
} catch (Exception e) {
sendMessage(sender, message.toOldMessageFormat());
}
}
@Override
protected boolean hasPermission(CommandSender sender, String node) {
return sender.hasPermission(node);

View File

@ -32,6 +32,13 @@
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<!-- fanciful -->
<dependency>
<groupId>io.github.mkremins</groupId>
<artifactId>fanciful</artifactId>
<version>1.1.0</version>
<scope>compile</scope>
</dependency>
<!-- HikariCP -->
<dependency>
<groupId>com.zaxxer</groupId>

View File

@ -31,6 +31,8 @@ import me.lucko.luckperms.common.constants.Permission;
import java.lang.ref.WeakReference;
import java.util.UUID;
import io.github.mkremins.fanciful.FancyMessage;
/**
* Simple implementation of {@link Sender} using a {@link SenderFactory}
*
@ -60,6 +62,14 @@ public class AbstractSender<T> implements Sender {
}
}
@Override
public void sendMessage(FancyMessage message) {
final T t = ref.get();
if (t != null) {
factory.sendMessage(t, message);
}
}
@Override
public boolean hasPermission(Permission permission) {
if (isConsole()) return true;

View File

@ -28,6 +28,8 @@ import me.lucko.luckperms.common.constants.Permission;
import java.util.UUID;
import io.github.mkremins.fanciful.FancyMessage;
/**
* Wrapper interface to represent a CommandSender/CommandSource within the common command implementations.
*/
@ -61,6 +63,13 @@ public interface Sender {
*/
void sendMessage(String s);
/**
* Send a json message to the Sender.
*
* @param message the message to send.
*/
void sendMessage(FancyMessage message);
/**
* Check if the Sender has a permission.
*

View File

@ -28,6 +28,8 @@ import me.lucko.luckperms.common.LuckPermsPlugin;
import java.util.UUID;
import io.github.mkremins.fanciful.FancyMessage;
/**
* Factory class to make a thread-safe sender instance
*
@ -43,6 +45,8 @@ public abstract class SenderFactory<T> {
protected abstract void sendMessage(T t, String s);
protected abstract void sendMessage(T t, FancyMessage message);
protected abstract boolean hasPermission(T t, String node);
public final Sender wrap(T t) {

View File

@ -44,6 +44,8 @@ import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import io.github.mkremins.fanciful.FancyMessage;
/**
* Class to handle import operations
*/
@ -212,6 +214,11 @@ public class Importer {
instance.logMessage(s);
}
@Override
public void sendMessage(FancyMessage message) {
instance.logMessage(message.toOldMessageFormat());
}
@Override
public boolean hasPermission(Permission permission) {
return true;

View File

@ -52,6 +52,10 @@
</excludes>
</artifactSet>
<relocations>
<relocation>
<pattern>io.github.mkremins.fanciful</pattern>
<shadedPattern>me.lucko.luckperms.lib.fanciful</shadedPattern>
</relocation>
<relocation>
<pattern>com.zaxxer.hikari</pattern>
<shadedPattern>me.lucko.luckperms.lib.hikari</shadedPattern>

View File

@ -32,6 +32,8 @@ import org.spongepowered.api.text.serializer.TextSerializers;
import java.util.UUID;
import io.github.mkremins.fanciful.FancyMessage;
public class SpongeSenderFactory extends SenderFactory<CommandSource> {
public SpongeSenderFactory(LuckPermsPlugin plugin) {
super(plugin);
@ -59,6 +61,15 @@ public class SpongeSenderFactory extends SenderFactory<CommandSource> {
source.sendMessage(TextSerializers.LEGACY_FORMATTING_CODE.deserialize(s));
}
@Override
protected void sendMessage(CommandSource source, FancyMessage message) {
try {
source.sendMessage(TextSerializers.JSON.deserialize(message.toJSONString()));
} catch (Exception e) {
sendMessage(source, message.toOldMessageFormat());
}
}
@Override
protected boolean hasPermission(CommandSource source, String node) {
return source.hasPermission(node);