9
0
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:
XiaoMoMi
2025-03-28 20:11:29 +08:00
parent ebca2deef5
commit 29de340676
5 changed files with 194 additions and 13 deletions

View File

@@ -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;

View File

@@ -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();

View File

@@ -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;
}
}

View File

@@ -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);
} }

View File

@@ -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
)
);
} }