All source projects
MrUltimateLibrary Source
Standalone source project / 68 files
MrUltimateLibrary is the backbone of all my plugins; it offers features that facilitate plugin creation, maintenance, and updates.
java
MrUltimateLibrary/src/main/java/eu/mrneznamy/mrultimatelibrary/gui/MrLibFormNative.java
JAVA · Read-only source
package eu.mrneznamy.mrultimatelibrary.gui;
import eu.mrneznamy.mrultimatelibrary.MrUltimateLibrary;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.EventExecutor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.logging.Level;
/**
* Native Paper Dialog implementation using reflection.
* Handles inputs using correct DialogResponseView methods: getText(), getBoolean(), getFloat().
*/
public class MrLibFormNative {
private static final Map<UUID, Consumer<Object>> pendingConfirm = new ConcurrentHashMap<>();
private static final Map<UUID, Runnable> pendingCancel = new ConcurrentHashMap<>();
private static final Map<String, Consumer<Object>> inputSubmitHandlers = new ConcurrentHashMap<>();
private static final Map<String, Runnable> inputCancelHandlers = new ConcurrentHashMap<>();
private static boolean eventRegistered = false;
private static Method findDeserializeMethod(Object serializer) {
if (serializer == null) return null;
Class<?> clazz = serializer.getClass();
Method m = findMethodInHierarchy(clazz, "deserialize", String.class);
if (m != null) return m;
try {
for (Method method : clazz.getMethods()) {
if (method.getName().equals("deserialize") && method.getParameterCount() == 1 && method.getParameterTypes()[0] == String.class) {
try {
method.setAccessible(true);
} catch (Throwable ignored) {}
return method;
}
}
} catch (Throwable ignored) {}
return null;
}
private static Method findMethodInHierarchy(Class<?> clazz, String name, Class<?>... params) {
if (java.lang.reflect.Modifier.isPublic(clazz.getModifiers())) {
try {
return clazz.getMethod(name, params);
} catch (NoSuchMethodException ignored) {}
}
for (Class<?> iface : clazz.getInterfaces()) {
Method m = findMethodInHierarchy(iface, name, params);
if (m != null) return m;
}
Class<?> superclass = clazz.getSuperclass();
if (superclass != null && superclass != Object.class) {
return findMethodInHierarchy(superclass, name, params);
}
return null;
}
public static void open(Player player,
String title,
List<MrLibForm.FormElement> elements,
Consumer<MrLibForm.FormResult> onSubmit,
Runnable onCancel) {
try {
ClassLoader loader = MrLibFormNative.class.getClassLoader();
if (loader == null) {
loader = Bukkit.class.getClassLoader();
}
Class<?> dialogClass = Class.forName("io.papermc.paper.dialog.Dialog", true, loader);
Class<?> dialogBaseClass = Class.forName("io.papermc.paper.registry.data.dialog.DialogBase", true, loader);
Class<?> dialogBodyClass = Class.forName("io.papermc.paper.registry.data.dialog.body.DialogBody", true, loader);
Class<?> dialogInputClass = Class.forName("io.papermc.paper.registry.data.dialog.input.DialogInput", true, loader);
Class<?> dialogTypeClass = Class.forName("io.papermc.paper.registry.data.dialog.type.DialogType", true, loader);
Class<?> componentClass = Class.forName("net.kyori.adventure.text.Component", true, loader);
Class<?> actionButtonClass = Class.forName("io.papermc.paper.registry.data.dialog.ActionButton", true, loader);
Class<?> consumerClass = Class.forName("java.util.function.Consumer", true, loader);
Class<?> dialogActionClass = null;
for (String pkg : new String[]{
"io.papermc.paper.registry.data.dialog.action.DialogAction",
"io.papermc.paper.registry.data.dialog.DialogAction"}) {
try { dialogActionClass = Class.forName(pkg, true, loader); break; }
catch (ClassNotFoundException ignored) {}
}
Class<?> keyClass = null;
try { keyClass = Class.forName("net.kyori.adventure.key.Key", true, loader); }
catch (ClassNotFoundException ignored) {}
Object sectionSerializerObj = null;
Method sectionDeserializeMethod = null;
try {
Class<?> legacySerializerClass = Class.forName("net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer", true, loader);
Class<?> builderClass = Class.forName("net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer$Builder", true, loader);
Method builderMethod = legacySerializerClass.getMethod("builder");
Object builderObj = builderMethod.invoke(null);
Method characterMethod = builderClass.getMethod("character", char.class);
builderObj = characterMethod.invoke(builderObj, '§');
Method hexColorsMethod = builderClass.getMethod("hexColors");
builderObj = hexColorsMethod.invoke(builderObj);
Method buildMethod = builderClass.getMethod("build");
sectionSerializerObj = buildMethod.invoke(builderObj);
sectionDeserializeMethod = findDeserializeMethod(sectionSerializerObj);
} catch (Throwable e) {
try {
Class<?> legacySerializerClass = Class.forName("net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer", true, loader);
Method legacySection = legacySerializerClass.getMethod("legacySection");
sectionSerializerObj = legacySection.invoke(null);
sectionDeserializeMethod = findDeserializeMethod(sectionSerializerObj);
} catch (Throwable ignored) {}
}
Object ampersandSerializerObj = null;
Method ampersandDeserializeMethod = null;
try {
Class<?> legacySerializerClass = Class.forName("net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer", true, loader);
Class<?> builderClass = Class.forName("net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer$Builder", true, loader);
Method builderMethod = legacySerializerClass.getMethod("builder");
Object builderObj = builderMethod.invoke(null);
Method characterMethod = builderClass.getMethod("character", char.class);
builderObj = characterMethod.invoke(builderObj, '&');
Method hexColorsMethod = builderClass.getMethod("hexColors");
builderObj = hexColorsMethod.invoke(builderObj);
Method buildMethod = builderClass.getMethod("build");
ampersandSerializerObj = buildMethod.invoke(builderObj);
ampersandDeserializeMethod = findDeserializeMethod(ampersandSerializerObj);
} catch (Throwable e) {
try {
Class<?> legacySerializerClass = Class.forName("net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer", true, loader);
Method legacyAmpersand = legacySerializerClass.getMethod("ampersand");
ampersandSerializerObj = legacyAmpersand.invoke(null);
ampersandDeserializeMethod = findDeserializeMethod(ampersandSerializerObj);
} catch (Throwable ignored) {}
}
Object miniMessageObj = null;
Method miniMessageDeserializeMethod = null;
try {
Class<?> mmClass = Class.forName("net.kyori.adventure.text.minimessage.MiniMessage", true, loader);
Method mmMethod = mmClass.getMethod("miniMessage");
miniMessageObj = mmMethod.invoke(null);
miniMessageDeserializeMethod = findDeserializeMethod(miniMessageObj);
} catch (Throwable e) {
Bukkit.getLogger().warning("[MrUltimateLibrary] Failed to load MiniMessage class: " + e.getMessage());
}
Object bungeeSerializerObj = null;
Method bungeeDeserializeMethod = null;
try {
Class<?> bungeeSerializerClass = Class.forName("net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer", true, loader);
Method getMethod = bungeeSerializerClass.getMethod("get");
bungeeSerializerObj = getMethod.invoke(null);
Class<?> baseComponentClass = Class.forName("net.md_5.bungee.api.chat.BaseComponent", true, loader);
Class<?> baseComponentArrayClass = java.lang.reflect.Array.newInstance(baseComponentClass, 0).getClass();
bungeeDeserializeMethod = bungeeSerializerClass.getMethod("deserialize", baseComponentArrayClass);
} catch (Throwable ignored) {}
Method fromLegacyTextMethod = null;
try {
Class<?> textComponentClass = Class.forName("net.md_5.bungee.api.chat.TextComponent", true, loader);
fromLegacyTextMethod = textComponentClass.getMethod("fromLegacyText", String.class);
} catch (Throwable ignored) {}
final Method finalFromLegacy = fromLegacyTextMethod;
final Object finalBungeeSerializer = bungeeSerializerObj;
final Method finalBungeeDeserialize = bungeeDeserializeMethod;
final Object finalMM = miniMessageObj;
final Method finalMMDeserialize = miniMessageDeserializeMethod;
final Object sectionSerializer = sectionSerializerObj;
final Method sectionDeserialize = sectionDeserializeMethod;
final Object ampersandSerializer = ampersandSerializerObj;
final Method ampersandDeserialize = ampersandDeserializeMethod;
final Method plainTextMethod = componentClass.getMethod("text", String.class);
java.util.function.Function<String, Object> createComp = (text) -> {
if (text == null) return null;
try {
if (finalMM != null && finalMMDeserialize != null) {
try {
try {
Object comp = finalMMDeserialize.invoke(finalMM, text);
if (comp != null) return comp;
} catch (Throwable ignored) {}
String mmString = legacyToMiniMessage(text);
Object comp = finalMMDeserialize.invoke(finalMM, mmString);
if (comp != null) return comp;
} catch (Throwable ignored) {}
}
String colored = text;
try {
colored = eu.mrneznamy.mrultimatelibrary.utils.MrLibColors.colorize(text);
} catch (Throwable ignored) {}
if (finalFromLegacy != null && finalBungeeSerializer != null && finalBungeeDeserialize != null) {
try {
Object baseComponents = finalFromLegacy.invoke(null, colored);
Object comp = finalBungeeDeserialize.invoke(finalBungeeSerializer, baseComponents);
if (comp != null) return comp;
} catch (Exception ignored) {}
}
if (sectionDeserialize != null && sectionSerializer != null) {
return sectionDeserialize.invoke(sectionSerializer, colored);
}
if (ampersandDeserialize != null && ampersandSerializer != null) {
return ampersandDeserialize.invoke(ampersandSerializer, text.replace("§", "&"));
}
} catch (Exception ignored) {}
try {
return plainTextMethod.invoke(null, text);
} catch (Exception ignored) {
return null;
}
};
Object titleComp = createComp.apply(title);
List<Object> bodies = new ArrayList<>();
List<Object> inputs = new ArrayList<>();
boolean hasInputs = false;
for (MrLibForm.FormElement el : elements) {
switch (el.type) {
case MESSAGE:
try {
Method m = dialogBodyClass.getMethod("plainMessage", componentClass);
bodies.add(m.invoke(null, createComp.apply(el.label)));
} catch (Exception ignored) {}
break;
case ITEM:
try {
Method m = dialogBodyClass.getMethod("item", ItemStack.class);
bodies.add(m.invoke(null, el.data));
} catch (Exception ignored) {}
break;
case TEXT:
hasInputs = true;
try {
Method m = dialogInputClass.getMethod("text", String.class, componentClass);
Object b = m.invoke(null, el.id, createComp.apply(el.label));
try {
Method maxLengthMethod = b.getClass().getMethod("maxLength", int.class);
Object returnedBuilder = maxLengthMethod.invoke(b, 5000);
if (returnedBuilder != null) b = returnedBuilder;
} catch (Exception ignored) {}
try {
Class<?> multilineOptionsClass = Class.forName("io.papermc.paper.registry.data.dialog.input.TextDialogInput$MultilineOptions", true, loader);
Method createMethod = multilineOptionsClass.getMethod("create", int.class, Integer.class);
Object options = createMethod.invoke(null, 5, null);
Method multilineMethod = b.getClass().getMethod("multiline", multilineOptionsClass);
Object returnedBuilder = multilineMethod.invoke(b, options);
if (returnedBuilder != null) b = returnedBuilder;
} catch (Exception ignored) {}
if (el.data != null) {
try {
Method initialMethod = b.getClass().getMethod("initial", String.class);
Object returnedBuilder = initialMethod.invoke(b, (String) el.data);
if (returnedBuilder != null) b = returnedBuilder;
} catch (Exception e) {
Bukkit.getLogger().warning("[MrUltimateLibrary] Failed to set text default: " + e.getMessage());
}
}
inputs.add(b.getClass().getMethod("build").invoke(b));
} catch (Exception e) {
Bukkit.getLogger().log(Level.SEVERE, "[MrUltimateLibrary] Failed to build TEXT element: " + el.id, e);
}
break;
case CHECKBOX:
hasInputs = true;
try {
Method m = dialogInputClass.getMethod("bool", String.class, componentClass);
Object b = m.invoke(null, el.id, createComp.apply(el.label));
if (el.data != null) {
try {
Method initialMethod = b.getClass().getMethod("initial", boolean.class);
Object returnedBuilder = initialMethod.invoke(b, (Boolean) el.data);
if (returnedBuilder != null) b = returnedBuilder;
} catch (Exception e) {
Bukkit.getLogger().warning("[MrUltimateLibrary] Failed to set boolean default: " + e.getMessage());
}
}
inputs.add(b.getClass().getMethod("build").invoke(b));
} catch (Exception e) {
Bukkit.getLogger().log(Level.SEVERE, "[MrUltimateLibrary] Failed to build CHECKBOX element: " + el.id, e);
}
break;
case DROPDOWN:
hasInputs = true;
try {
Class<?> optionEntryClass = Class.forName("io.papermc.paper.registry.data.dialog.input.SingleOptionDialogInput$OptionEntry", true, loader);
Method createEntry = optionEntryClass.getMethod("create", String.class, componentClass, boolean.class);
List<Object> entries = new ArrayList<>();
List<String> options = (List<String>) el.data;
for (int i = 0; i < options.size(); i++) {
String opt = options.get(i);
Object entry = createEntry.invoke(null, opt, createComp.apply(opt), i == 0);
entries.add(entry);
}
Method m = dialogInputClass.getMethod("singleOption", String.class, componentClass, List.class);
Object b = m.invoke(null, el.id, createComp.apply(el.label), entries);
inputs.add(b.getClass().getMethod("build").invoke(b));
} catch (Exception e) {
Bukkit.getLogger().log(Level.SEVERE, "[MrUltimateLibrary] Failed to build DROPDOWN element: " + el.id, e);
}
break;
case SLIDER:
hasInputs = true;
try {
float[] range = (float[]) el.data;
Method m = dialogInputClass.getMethod("numberRange", String.class, componentClass, float.class, float.class);
Object b = m.invoke(null, el.id, createComp.apply(el.label), range[0], range[1]);
if (range.length > 3) {
float step = range[3];
try {
Method stepMethod = findMethodInHierarchy(b.getClass(), "step", float.class);
if (stepMethod == null) stepMethod = findMethodInHierarchy(b.getClass(), "step", double.class);
if (stepMethod == null) stepMethod = findMethodInHierarchy(b.getClass(), "step", Number.class);
if (stepMethod != null) {
try { stepMethod.setAccessible(true); } catch (Throwable ignored) {}
Object returnedBuilder = stepMethod.invoke(b, step);
if (returnedBuilder != null) b = returnedBuilder;
}
} catch (Exception e) {
Bukkit.getLogger().warning("[MrUltimateLibrary] Failed to set slider step: " + e.getMessage());
}
}
if (range.length > 2) {
try {
Method initialMethod = findMethodInHierarchy(b.getClass(), "initial", float.class);
if (initialMethod == null) initialMethod = findMethodInHierarchy(b.getClass(), "initial", Float.class);
if (initialMethod == null) initialMethod = findMethodInHierarchy(b.getClass(), "initial", Number.class);
if (initialMethod != null) {
try { initialMethod.setAccessible(true); } catch (Throwable ignored) {}
Object returnedBuilder = initialMethod.invoke(b, range[2]);
if (returnedBuilder != null) b = returnedBuilder;
}
} catch (Exception e) {
Bukkit.getLogger().warning("[MrUltimateLibrary] Failed to set slider default: " + e.getMessage());
}
}
inputs.add(b.getClass().getMethod("build").invoke(b));
} catch (Exception e) {
Bukkit.getLogger().log(Level.SEVERE, "[MrUltimateLibrary] Failed to build SLIDER element: " + el.id, e);
}
break;
}
}
Method baseBuilderMethod = dialogBaseClass.getMethod("builder", componentClass);
Object baseBuilder = baseBuilderMethod.invoke(null, titleComp);
try { baseBuilder.getClass().getMethod("body", List.class).invoke(baseBuilder, bodies); }
catch (Exception ignored) {}
try { baseBuilder.getClass().getMethod("inputs", List.class).invoke(baseBuilder, inputs); }
catch (Exception ignored) {}
Object dialogBase = baseBuilder.getClass().getMethod("build").invoke(baseBuilder);
String session = UUID.randomUUID().toString().replace("-", "").substring(0, 10);
String confirmKey = "mrlibform:ok_" + session;
String cancelKey = "mrlibform:no_" + session;
Method btnMethod = actionButtonClass.getMethod("builder", componentClass);
Object confirmBtn = buildButton(btnMethod, createComp, "<color:#AEFFC1><b>Confirm</b></color>", confirmKey,
dialogActionClass, keyClass);
Object cancelBtn = buildButton(btnMethod, createComp, "<color:#FF8B8E><b>Cancel</b></color>", cancelKey,
dialogActionClass, keyClass);
Method confirmTypeMethod = dialogTypeClass.getMethod("confirmation", actionButtonClass, actionButtonClass);
final Object dialogType = confirmTypeMethod.invoke(null, confirmBtn, cancelBtn);
Object dialog = null;
try {
Method direct = dialogClass.getMethod("dialog", dialogBaseClass, dialogTypeClass);
dialog = direct.invoke(null, dialogBase, dialogType);
} catch (Exception ignored) {}
if (dialog == null) {
final Object finalBase = dialogBase;
final Object finalType = dialogType;
InvocationHandler handler = (proxy, method, args) -> {
if (method.getName().equals("accept")) {
Object b = args[0];
try {
Method baseM = findMethod(b.getClass(), dialogBaseClass, true);
if (baseM != null) {
try {
Object b2 = baseM.invoke(b, finalBase);
if (b2 == null) b2 = b;
Method typeM = findMethod(b2.getClass(), dialogTypeClass, false);
if (typeM != null) { typeM.invoke(b2, finalType); return null; }
} catch (Exception directEx) { /* fall through */ }
}
Method emptyM = b.getClass().getMethod("empty");
Object b3 = emptyM.invoke(b);
if (b3 == null) b3 = b;
Method baseM2 = findMethod(b3.getClass(), dialogBaseClass, true);
Object b4 = baseM2.invoke(b3, finalBase);
if (b4 == null) b4 = b3;
Method typeM2 = findMethod(b4.getClass(), dialogTypeClass, false);
typeM2.invoke(b4, finalType);
} catch (Exception ex) { ex.printStackTrace(); }
}
return null;
};
Object proxy = Proxy.newProxyInstance(loader, new Class[]{consumerClass}, handler);
dialog = dialogClass.getMethod("create", consumerClass).invoke(null, proxy);
}
registerPlayerCallback(player.getUniqueId(), confirmKey, cancelKey,
hasInputs, elements, onSubmit, onCancel);
Method showDialog = null;
for (Method m : player.getClass().getMethods()) {
if (m.getName().equals("showDialog") && m.getParameterCount() == 1) {
showDialog = m; break;
}
}
if (showDialog == null) throw new NoSuchMethodException("Player#showDialog not found");
Object future = showDialog.invoke(player, dialog);
if (future != null) {
try {
InvocationHandler fh = (proxy, method, args) -> {
if (method.getName().equals("accept")) {
Object response = args[0];
UUID uuid = player.getUniqueId();
pendingConfirm.remove(uuid);
pendingCancel.remove(uuid);
inputSubmitHandlers.remove(confirmKey);
inputCancelHandlers.remove(cancelKey);
try {
boolean confirmed = (boolean) response.getClass()
.getMethod("isConfirmed").invoke(response);
Bukkit.getScheduler().runTask(MrUltimateLibrary.getInstance(), () ->
dispatchResult(uuid, confirmed, response, elements, onSubmit, onCancel));
} catch (Exception ex) { ex.printStackTrace(); }
}
return null;
};
Object fp = Proxy.newProxyInstance(loader, new Class[]{consumerClass}, fh);
future.getClass().getMethod("thenAccept", consumerClass).invoke(future, fp);
} catch (Exception ignored) {}
}
} catch (Exception e) {
Bukkit.getLogger().severe("[MrUltimateLibrary] Dialog open failed: " + e.getMessage());
e.printStackTrace();
new MrLibFormFallback(title, elements, onSubmit, onCancel).open(player);
}
}
private static Object getInputValue(Object responseView, MrLibForm.FormElement el) {
if (responseView == null || el == null || el.id == null) return null;
try {
switch (el.type) {
case TEXT:
case DROPDOWN:
try {
return responseView.getClass().getMethod("getText", String.class).invoke(responseView, el.id);
} catch (Exception ignored) {}
break;
case CHECKBOX:
try {
return responseView.getClass().getMethod("getBoolean", String.class).invoke(responseView, el.id);
} catch (Exception ignored) {}
break;
case SLIDER:
try {
return responseView.getClass().getMethod("getFloat", String.class).invoke(responseView, el.id);
} catch (Exception ignored) {}
break;
}
for (String mName : new String[]{"getText", "getBoolean", "getFloat"}) {
try {
Object val = responseView.getClass().getMethod(mName, String.class).invoke(responseView, el.id);
if (val != null) return val;
} catch (Exception ignored) {}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static Object buildButton(Method btnMethod, java.util.function.Function<String, Object> createComp,
String label, String keyStr,
Class<?> dialogActionClass, Class<?> keyClass) throws Exception {
Object labelComp = createComp.apply(label);
Object builder = btnMethod.invoke(null, labelComp);
if (dialogActionClass != null && keyClass != null) {
try {
Object keyObj = buildKey(keyClass, keyStr);
Method customClick = null;
for (Method m : dialogActionClass.getMethods()) {
if (m.getName().equals("customClick") && m.getParameterCount() >= 1) {
Class<?> firstParam = m.getParameterTypes()[0];
if (firstParam.isAssignableFrom(keyClass)) {
customClick = m;
break;
}
}
}
if (customClick != null && keyObj != null) {
Object action = customClick.getParameterCount() == 1
? customClick.invoke(null, keyObj)
: customClick.invoke(null, keyObj, null);
boolean actionSet = false;
for (Method m : builder.getClass().getMethods()) {
if (m.getName().equals("action") && m.getParameterCount() == 1) {
Object ret = m.invoke(builder, action);
if (ret != null && ret != builder) builder = ret;
actionSet = true;
break;
}
}
if (!actionSet) {
throw new NoSuchMethodException("Button builder 'action' method not found");
}
} else {
throw new NoSuchMethodException("customClick method or Key object not found");
}
} catch (Exception e) {
throw new RuntimeException("Failed to setup dialog click action: " + e.getMessage(), e);
}
} else {
throw new ClassNotFoundException("DialogAction or Key class not found");
}
return builder.getClass().getMethod("build").invoke(builder);
}
private static Object buildKey(Class<?> keyClass, String full) {
try {
Method m = keyClass.getMethod("key", String.class);
return m.invoke(null, full);
} catch (Exception e1) {
try {
String[] p = full.split(":", 2);
Method m = keyClass.getMethod("key", String.class, String.class);
return m.invoke(null, p[0], p[1]);
} catch (Exception e2) { return null; }
}
}
private static void registerPlayerCallback(UUID uuid,
String confirmKey, String cancelKey,
boolean hasInputs,
List<MrLibForm.FormElement> elements,
Consumer<MrLibForm.FormResult> onSubmit,
Runnable onCancel) {
ensureEventListenerRegistered();
pendingConfirm.put(uuid, responseView -> {
pendingConfirm.remove(uuid);
pendingCancel.remove(uuid);
inputSubmitHandlers.remove(confirmKey);
inputCancelHandlers.remove(cancelKey);
MrLibForm.FormResult result = new MrLibForm.FormResult();
if (hasInputs && responseView != null) {
for (MrLibForm.FormElement el : elements) {
if (el.id != null) {
Object val = getInputValue(responseView, el);
result.put(el.id, val != null ? val : "");
}
}
}
if (onSubmit != null) onSubmit.accept(result);
});
pendingCancel.put(uuid, () -> {
pendingConfirm.remove(uuid);
pendingCancel.remove(uuid);
inputSubmitHandlers.remove(confirmKey);
inputCancelHandlers.remove(cancelKey);
if (onCancel != null) onCancel.run();
});
inputSubmitHandlers.put(confirmKey, responseView -> {
Consumer<Object> cb = pendingConfirm.remove(uuid);
pendingCancel.remove(uuid);
if (cb != null) {
Bukkit.getScheduler().runTask(MrUltimateLibrary.getInstance(), () -> cb.accept(responseView));
}
});
inputCancelHandlers.put(cancelKey, () -> {
pendingConfirm.remove(uuid);
Runnable cb = pendingCancel.remove(uuid);
if (cb != null) {
Bukkit.getScheduler().runTask(MrUltimateLibrary.getInstance(), cb);
}
});
}
@SuppressWarnings("unchecked")
private static void ensureEventListenerRegistered() {
if (eventRegistered) return;
eventRegistered = true;
try {
ClassLoader loader = Bukkit.class.getClassLoader();
Class<? extends Event> eventClass = (Class<? extends Event>)
Class.forName("io.papermc.paper.event.player.PlayerCustomClickEvent", true, loader);
Bukkit.getPluginManager().registerEvent(
eventClass,
new Listener() {},
EventPriority.NORMAL,
new EventExecutor() {
@Override
public void execute(Listener listener, Event event) {
try {
Object identifier = event.getClass().getMethod("getIdentifier").invoke(event);
String keyStr = identifier.toString();
Player player = null;
try {
player = (Player) event.getClass().getMethod("getPlayer").invoke(event);
} catch (Exception ignored) {}
if (player == null) {
Object conn = event.getClass().getMethod("getCommonConnection").invoke(event);
player = (Player) conn.getClass().getMethod("getPlayer").invoke(conn);
}
Object responseView = null;
try {
responseView = event.getClass().getMethod("getDialogResponseView").invoke(event);
} catch (Exception ignored) {}
if (inputSubmitHandlers.containsKey(keyStr)) {
inputSubmitHandlers.remove(keyStr).accept(responseView);
} else if (inputCancelHandlers.containsKey(keyStr)) {
inputCancelHandlers.remove(keyStr).run();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
},
MrUltimateLibrary.getInstance()
);
} catch (Exception e) {
Bukkit.getLogger().warning("[MrUltimateLibrary] Could not register PlayerCustomClickEvent: " + e.getMessage());
eventRegistered = false;
}
}
private static Method findMethod(Class<?> cls, Class<?> targetType, boolean assignable) {
for (Method m : cls.getMethods()) {
if (m.getParameterCount() == 1) {
Class<?> p = m.getParameterTypes()[0];
if (assignable ? p.isAssignableFrom(targetType) : p.equals(targetType)) return m;
}
}
return null;
}
private static void dispatchResult(UUID uuid, boolean confirmed, Object response,
List<MrLibForm.FormElement> elements,
Consumer<MrLibForm.FormResult> onSubmit,
Runnable onCancel) {
if (confirmed) {
MrLibForm.FormResult result = new MrLibForm.FormResult();
if (response != null) {
for (MrLibForm.FormElement el : elements) {
if (el.id != null) {
Object val = getInputValue(response, el);
result.put(el.id, val != null ? val : "");
}
}
}
if (onSubmit != null) onSubmit.accept(result);
} else {
if (onCancel != null) onCancel.run();
}
}
private static String legacyToMiniMessage(String input) {
if (input == null) return "";
String s = input.replace("&", "§");
java.util.regex.Pattern gradPattern = java.util.regex.Pattern.compile("\\{#([0-9A-Fa-f]{6})>\\}(.*?)\\{#([0-9A-Fa-f]{6})<\\}");
java.util.regex.Matcher gradMatcher = gradPattern.matcher(s);
StringBuffer sb = new StringBuffer();
while (gradMatcher.find()) {
String startColor = gradMatcher.group(1);
String text = gradMatcher.group(2);
String endColor = gradMatcher.group(3);
gradMatcher.appendReplacement(sb, "<gradient:#" + startColor + ":#" + endColor + ">" + java.util.regex.Matcher.quoteReplacement(text) + "</gradient>");
}
gradMatcher.appendTail(sb);
s = sb.toString();
java.util.regex.Pattern hexPattern = java.util.regex.Pattern.compile("\\{#([0-9A-Fa-f]{6})\\}");
java.util.regex.Matcher hexMatcher = hexPattern.matcher(s);
sb = new StringBuffer();
while (hexMatcher.find()) {
String hex = hexMatcher.group(1);
hexMatcher.appendReplacement(sb, "<color:#" + hex + ">");
}
hexMatcher.appendTail(sb);
s = sb.toString();
java.util.regex.Pattern anglePattern = java.util.regex.Pattern.compile("<#([0-9A-Fa-f]{6})>");
java.util.regex.Matcher angleMatcher = anglePattern.matcher(s);
sb = new StringBuffer();
while (angleMatcher.find()) {
String hex = angleMatcher.group(1);
angleMatcher.appendReplacement(sb, "<color:#" + hex + ">");
}
angleMatcher.appendTail(sb);
s = sb.toString();
s = s.replace("§0", "<black>");
s = s.replace("§1", "<dark_blue>");
s = s.replace("§2", "<dark_green>");
s = s.replace("§3", "<dark_aqua>");
s = s.replace("§4", "<dark_red>");
s = s.replace("§5", "<dark_purple>");
s = s.replace("§6", "<gold>");
s = s.replace("§7", "<gray>");
s = s.replace("§8", "<dark_gray>");
s = s.replace("§9", "<blue>");
s = s.replace("§a", "<green>").replace("§A", "<green>");
s = s.replace("§b", "<aqua>").replace("§B", "<aqua>");
s = s.replace("§c", "<red>").replace("§C", "<red>");
s = s.replace("§d", "<light_purple>").replace("§D", "<light_purple>");
s = s.replace("§e", "<yellow>").replace("§E", "<yellow>");
s = s.replace("§f", "<white>").replace("§F", "<white>");
s = s.replace("§l", "<bold>").replace("§L", "<bold>");
s = s.replace("§o", "<italic>").replace("§O", "<italic>");
s = s.replace("§n", "<underlined>").replace("§N", "<underlined>");
s = s.replace("§m", "<strikethrough>").replace("§M", "<strikethrough>");
s = s.replace("§k", "<obfuscated>").replace("§K", "<obfuscated>");
s = s.replace("§r", "<reset>").replace("§R", "<reset>");
s = s.replace("§", "");
return s;
}
}
833 linesGNU GENERAL PUBLIC LICENSE · Version 3, 29 June 2007 · UTF-8 · Read only