mirror of
https://github.com/Xiao-MoMi/Custom-Nameplates.git
synced 2025-12-24 01:19:17 +00:00
added native adventure component support
This commit is contained in:
@@ -200,6 +200,30 @@ public class ReflectionUtils {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static Method getMethod(final Class<?> clazz, Class<?> returnType, final String[] possibleMethodNames, final Class<?>... parameterTypes) {
|
||||||
|
outer:
|
||||||
|
for (Method method : clazz.getMethods()) {
|
||||||
|
if (method.getParameterCount() != parameterTypes.length) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Class<?>[] types = method.getParameterTypes();
|
||||||
|
for (int i = 0; i < types.length; i++) {
|
||||||
|
if (types[i] != parameterTypes[i]) {
|
||||||
|
continue outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (String name : possibleMethodNames) {
|
||||||
|
if (name.equals(method.getName())) {
|
||||||
|
if (returnType.isAssignableFrom(method.getReturnType())) {
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static Method getMethod(final Class<?> clazz, Class<?> returnType, int index) {
|
public static Method getMethod(final Class<?> clazz, Class<?> returnType, int index) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|||||||
@@ -66,7 +66,12 @@ public abstract class AbstractRequirementManager implements RequirementManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void registerInternalRequirements() {
|
private void registerInternalRequirements() {
|
||||||
this.registerRequirement((args, interval) -> new LaggyRequirement(interval, (int) args), "laggy");
|
this.registerRequirement((args, interval) -> new LaggyRequirement(interval, (int) args), "laggy-test");
|
||||||
|
this.registerRequirement((args, interval) -> {
|
||||||
|
Section section = ConfigUtils.safeCast(args, Section.class);
|
||||||
|
Requirement[] requirements = parseRequirements(section);
|
||||||
|
return new InvertedRequirement(interval, requirements);
|
||||||
|
}, "inverted");
|
||||||
this.registerRequirement((args, interval) -> {
|
this.registerRequirement((args, interval) -> {
|
||||||
Section section = ConfigUtils.safeCast(args, Section.class);
|
Section section = ConfigUtils.safeCast(args, Section.class);
|
||||||
if (section == null) return Requirement.empty();
|
if (section == null) return Requirement.empty();
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) <2024> <XiaoMoMi>
|
||||||
|
*
|
||||||
|
* 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 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.momirealms.customnameplates.backend.requirement.builtin;
|
||||||
|
|
||||||
|
import net.momirealms.customnameplates.api.CNPlayer;
|
||||||
|
import net.momirealms.customnameplates.api.requirement.Requirement;
|
||||||
|
import net.momirealms.customnameplates.backend.requirement.AbstractRequirement;
|
||||||
|
|
||||||
|
public class InvertedRequirement extends AbstractRequirement {
|
||||||
|
|
||||||
|
private final Requirement[] requirements;
|
||||||
|
|
||||||
|
public InvertedRequirement(int refreshInterval, Requirement[] requirements) {
|
||||||
|
super(refreshInterval);
|
||||||
|
this.requirements = requirements;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSatisfied(CNPlayer p1, CNPlayer p2) {
|
||||||
|
if (requirements.length == 0) return false;
|
||||||
|
for (Requirement requirement : requirements) {
|
||||||
|
if (requirement.isSatisfied(p1, p2)) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String type() {
|
||||||
|
return "inverted";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
|
if (this == object) return true;
|
||||||
|
if (object == null || getClass() != object.getClass()) return false;
|
||||||
|
InvertedRequirement that = (InvertedRequirement) object;
|
||||||
|
int length = requirements.length;
|
||||||
|
if (that.requirements.length != length)
|
||||||
|
return false;
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
Object e1 = requirements[i];
|
||||||
|
Object e2 = that.requirements[i];
|
||||||
|
if (e1 == e2)
|
||||||
|
continue;
|
||||||
|
if (!e1.equals(e2)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int hash = 271;
|
||||||
|
for (Requirement requirement : requirements) {
|
||||||
|
hash += requirement.hashCode();
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ package net.momirealms.customnameplates.bukkit;
|
|||||||
|
|
||||||
import it.unimi.dsi.fastutil.ints.IntList;
|
import it.unimi.dsi.fastutil.ints.IntList;
|
||||||
import me.clip.placeholderapi.PlaceholderAPI;
|
import me.clip.placeholderapi.PlaceholderAPI;
|
||||||
|
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||||
import net.momirealms.customnameplates.api.CNPlayer;
|
import net.momirealms.customnameplates.api.CNPlayer;
|
||||||
import net.momirealms.customnameplates.api.ConfigManager;
|
import net.momirealms.customnameplates.api.ConfigManager;
|
||||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||||
@@ -43,6 +44,7 @@ import org.bukkit.Location;
|
|||||||
import org.bukkit.OfflinePlayer;
|
import org.bukkit.OfflinePlayer;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@@ -56,6 +58,7 @@ public class BukkitPlatform implements Platform {
|
|||||||
private final boolean geyser;
|
private final boolean geyser;
|
||||||
private final boolean floodGate;
|
private final boolean floodGate;
|
||||||
private final boolean libsDisguises;
|
private final boolean libsDisguises;
|
||||||
|
private static Object serializer;
|
||||||
|
|
||||||
private static final HashMap<String, TriConsumer<CNPlayer, PacketEvent, Object>> packetFunctions = new HashMap<>();
|
private static final HashMap<String, TriConsumer<CNPlayer, PacketEvent, Object>> packetFunctions = new HashMap<>();
|
||||||
|
|
||||||
@@ -87,6 +90,12 @@ public class BukkitPlatform implements Platform {
|
|||||||
this.geyser = Bukkit.getPluginManager().getPlugin("Geyser-Spigot") != null;
|
this.geyser = Bukkit.getPluginManager().getPlugin("Geyser-Spigot") != null;
|
||||||
this.floodGate = Bukkit.getPluginManager().getPlugin("floodgate") != null;
|
this.floodGate = Bukkit.getPluginManager().getPlugin("floodgate") != null;
|
||||||
this.libsDisguises = Bukkit.getPluginManager().getPlugin("LibsDisguises") != null;
|
this.libsDisguises = Bukkit.getPluginManager().getPlugin("LibsDisguises") != null;
|
||||||
|
try {
|
||||||
|
Object builder = Reflections.method$GsonComponentSerializer$builder.invoke(null);
|
||||||
|
serializer = Reflections.method$GsonComponentSerializer$Builder$build.invoke(builder);
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@@ -101,19 +110,33 @@ public class BukkitPlatform implements Platform {
|
|||||||
if (!player.shouldCNTakeOverActionBar()) return;
|
if (!player.shouldCNTakeOverActionBar()) return;
|
||||||
try {
|
try {
|
||||||
// some plugins would send null to clear the actionbar, what a bad solution
|
// some plugins would send null to clear the actionbar, what a bad solution
|
||||||
Object component = Optional.ofNullable(Reflections.field$ClientboundSetActionBarTextPacket$text.get(packet)).orElse(Reflections.instance$Component$empty);
|
Object component = Reflections.field$ClientboundSetActionBarTextPacket$text.get(packet);
|
||||||
Object contents = Reflections.method$Component$getContents.invoke(component);
|
if (component == null && !VersionHelper.isVersionNewerThan1_20_5()) {
|
||||||
if (contents == null) {
|
// paper api, must be from other plugins
|
||||||
return;
|
Object adventureComponent = Reflections.field$ClientboundSetActionBarTextPacket$adventure$text.get(packet);
|
||||||
|
if (adventureComponent != null) {
|
||||||
|
String json = (String) Reflections.method$ComponentSerializer$serialize.invoke(serializer, adventureComponent);
|
||||||
|
CustomNameplates.getInstance().getScheduler().async().execute(() -> {
|
||||||
|
((ActionBarManagerImpl) CustomNameplates.getInstance().getActionBarManager()).handleActionBarPacket(player, AdventureHelper.jsonToMiniMessage(json));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// bungeecord components ?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// mc components
|
||||||
|
Object contents = Reflections.method$Component$getContents.invoke(component);
|
||||||
|
if (contents == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Reflections.clazz$ScoreContents.isAssignableFrom(contents.getClass())) {
|
||||||
|
//String name = scoreContentNameFunction.apply(Reflections.field$ScoreContents$name.get(contents));
|
||||||
|
String objective = (String) Reflections.field$ScoreContents$objective.get(contents);
|
||||||
|
if ("actionbar".equals(objective)) return;
|
||||||
|
}
|
||||||
|
CustomNameplates.getInstance().getScheduler().async().execute(() -> {
|
||||||
|
((ActionBarManagerImpl) CustomNameplates.getInstance().getActionBarManager()).handleActionBarPacket(player, AdventureHelper.minecraftComponentToMiniMessage(component));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (Reflections.clazz$ScoreContents.isAssignableFrom(contents.getClass())) {
|
|
||||||
//String name = scoreContentNameFunction.apply(Reflections.field$ScoreContents$name.get(contents));
|
|
||||||
String objective = (String) Reflections.field$ScoreContents$objective.get(contents);
|
|
||||||
if ("actionbar".equals(objective)) return;
|
|
||||||
}
|
|
||||||
CustomNameplates.getInstance().getScheduler().async().execute(() -> {
|
|
||||||
((ActionBarManagerImpl) CustomNameplates.getInstance().getActionBarManager()).handleActionBarPacket(player, AdventureHelper.minecraftComponentToMiniMessage(component));
|
|
||||||
});
|
|
||||||
} catch (ReflectiveOperationException e) {
|
} catch (ReflectiveOperationException e) {
|
||||||
CustomNameplates.getInstance().getPluginLogger().severe("Failed to handle ClientboundSetActionBarTextPacket", e);
|
CustomNameplates.getInstance().getPluginLogger().severe("Failed to handle ClientboundSetActionBarTextPacket", e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1162,4 +1162,58 @@ public class Reflections {
|
|||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final Class<?> clazz$AdventureComponent = requireNonNull(
|
||||||
|
ReflectionUtils.getClazz(
|
||||||
|
"net{}kyori{}adventure{}text{}Component".replace("{}", ".")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// <= 1.20.4
|
||||||
|
public static final Field field$ClientboundSetActionBarTextPacket$adventure$text =
|
||||||
|
ReflectionUtils.getDeclaredField(
|
||||||
|
clazz$ClientboundSetActionBarTextPacket, clazz$AdventureComponent, 0
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Class<?> clazz$ComponentSerializer = requireNonNull(
|
||||||
|
ReflectionUtils.getClazz(
|
||||||
|
"net{}kyori{}adventure{}text{}serializer{}ComponentSerializer".replace("{}", ".")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Class<?> clazz$GsonComponentSerializer = requireNonNull(
|
||||||
|
ReflectionUtils.getClazz(
|
||||||
|
"net{}kyori{}adventure{}text{}serializer{}gson{}GsonComponentSerializer".replace("{}", ".")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Class<?> clazz$GsonComponentSerializer$Builder = requireNonNull(
|
||||||
|
ReflectionUtils.getClazz(
|
||||||
|
"net{}kyori{}adventure{}text{}serializer{}gson{}GsonComponentSerializer$Builder".replace("{}", ".")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Method method$GsonComponentSerializer$builder = requireNonNull(
|
||||||
|
ReflectionUtils.getMethod(
|
||||||
|
clazz$GsonComponentSerializer, clazz$GsonComponentSerializer$Builder
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Method method$GsonComponentSerializer$Builder$build = requireNonNull(
|
||||||
|
ReflectionUtils.getMethod(
|
||||||
|
clazz$GsonComponentSerializer$Builder, clazz$GsonComponentSerializer
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Method method$ComponentSerializer$serialize = requireNonNull(
|
||||||
|
ReflectionUtils.getMethod(
|
||||||
|
clazz$ComponentSerializer, Object.class, new String[] {"serialize"}, clazz$AdventureComponent
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Method method$ComponentSerializer$deserialize = requireNonNull(
|
||||||
|
ReflectionUtils.getMethod(
|
||||||
|
clazz$ComponentSerializer, Object.class, new String[] {"deserialize"}, Object.class
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user