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;
|
||||
}
|
||||
|
||||
@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
|
||||
public static Method getMethod(final Class<?> clazz, Class<?> returnType, int index) {
|
||||
int i = 0;
|
||||
|
||||
@@ -66,7 +66,12 @@ public abstract class AbstractRequirementManager implements RequirementManager {
|
||||
}
|
||||
|
||||
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) -> {
|
||||
Section section = ConfigUtils.safeCast(args, Section.class);
|
||||
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 me.clip.placeholderapi.PlaceholderAPI;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.momirealms.customnameplates.api.CNPlayer;
|
||||
import net.momirealms.customnameplates.api.ConfigManager;
|
||||
import net.momirealms.customnameplates.api.CustomNameplates;
|
||||
@@ -43,6 +44,7 @@ import org.bukkit.Location;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -56,6 +58,7 @@ public class BukkitPlatform implements Platform {
|
||||
private final boolean geyser;
|
||||
private final boolean floodGate;
|
||||
private final boolean libsDisguises;
|
||||
private static Object serializer;
|
||||
|
||||
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.floodGate = Bukkit.getPluginManager().getPlugin("floodgate") != 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 {
|
||||
@@ -101,19 +110,33 @@ public class BukkitPlatform implements Platform {
|
||||
if (!player.shouldCNTakeOverActionBar()) return;
|
||||
try {
|
||||
// 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 contents = Reflections.method$Component$getContents.invoke(component);
|
||||
if (contents == null) {
|
||||
return;
|
||||
Object component = Reflections.field$ClientboundSetActionBarTextPacket$text.get(packet);
|
||||
if (component == null && !VersionHelper.isVersionNewerThan1_20_5()) {
|
||||
// paper api, must be from other plugins
|
||||
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) {
|
||||
CustomNameplates.getInstance().getPluginLogger().severe("Failed to handle ClientboundSetActionBarTextPacket", e);
|
||||
}
|
||||
|
||||
@@ -1162,4 +1162,58 @@ public class Reflections {
|
||||
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