From 3df6d66efbdc48fb134907845ea30fd2eb90170a Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Tue, 19 Nov 2024 16:46:01 +0800 Subject: [PATCH] better support --- .../api/AbstractCNPlayer.java | 96 +++++++++++++------ .../customnameplates/api/MainTask.java | 44 +++++---- .../api/helper/VersionHelper.java | 30 ++++++ .../backend/feature/tag/TagRendererImpl.java | 9 +- backend/src/main/resources/config.yml | 4 +- .../bukkit/BukkitCNPlayer.java | 2 +- .../bukkit/scheduler/impl/BukkitExecutor.java | 7 +- gradle.properties | 2 +- 8 files changed, 135 insertions(+), 59 deletions(-) diff --git a/api/src/main/java/net/momirealms/customnameplates/api/AbstractCNPlayer.java b/api/src/main/java/net/momirealms/customnameplates/api/AbstractCNPlayer.java index 214291c..354e4b5 100644 --- a/api/src/main/java/net/momirealms/customnameplates/api/AbstractCNPlayer.java +++ b/api/src/main/java/net/momirealms/customnameplates/api/AbstractCNPlayer.java @@ -37,6 +37,8 @@ import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; public abstract class AbstractCNPlayer implements CNPlayer { @@ -45,19 +47,20 @@ public abstract class AbstractCNPlayer implements CNPlayer { protected Object player; - private boolean isLoaded = false; - - private boolean tempPreviewing = false; - private boolean toggleablePreviewing = false; + private volatile boolean isLoaded = false; + private volatile boolean tempPreviewing = false; + private volatile boolean toggleablePreviewing = false; private String equippedNameplate; private String equippedBubble; private final TeamView teamView = new TeamView(); + // these two maps can be visited by other threads private final Map> cachedValues = new ConcurrentHashMap<>(128); private final Map>> cachedRelationalValues = new ConcurrentHashMap<>(128); + // these two maps can only be modified in the same thread private final Map> cachedRequirements = new Int2ObjectOpenHashMap<>(32); private final Map>> cachedRelationalRequirements = new Int2ObjectOpenHashMap<>(32); @@ -65,7 +68,8 @@ public abstract class AbstractCNPlayer implements CNPlayer { private final Map> placeholder2Features = new ConcurrentHashMap<>(); private final Map> feature2Placeholders = new ConcurrentHashMap<>(); - private final Map trackers = Collections.synchronizedMap(new WeakHashMap<>()); + private final Map trackers = new WeakHashMap<>(); + private final ReadWriteLock trackerLock = new ReentrantReadWriteLock(); protected AbstractCNPlayer(CustomNameplates plugin, Channel channel) { this.plugin = plugin; @@ -437,58 +441,90 @@ public abstract class AbstractCNPlayer implements CNPlayer { @Override public Tracker addPlayerToTracker(CNPlayer another) { - Tracker tracker = trackers.get(another); - if (tracker != null) { + trackerLock.writeLock().lock(); + try { + Tracker tracker = trackers.get(another); + if (tracker != null) { + return tracker; + } + tracker = new Tracker(another); + trackers.put(another, tracker); return tracker; + } finally { + trackerLock.writeLock().unlock(); } - tracker = new Tracker(another); - trackers.put(another, tracker); -// for (Placeholder placeholder : activePlaceholders()) { -// if (placeholder instanceof RelationalPlaceholder relationalPlaceholder) { -// String value = relationalPlaceholder.request(this, another); -// setRelationalValue(relationalPlaceholder, another, value); -// } -// } - return tracker; } @Override public void removePlayerFromTracker(CNPlayer another) { - trackers.remove(another); + trackerLock.writeLock().lock(); + try { + trackers.remove(another); + } finally { + trackerLock.writeLock().unlock(); + } } @Override public Collection nearbyPlayers() { - return new ObjectArrayList<>(trackers.keySet()); + trackerLock.readLock().lock(); + try { + // Create a snapshot of keys to avoid concurrent modification + return new ObjectArrayList<>(trackers.keySet()); + } finally { + trackerLock.readLock().unlock(); + } } @Override public void trackPassengers(CNPlayer another, int... passengers) { - Tracker tracker = trackers.get(another); - if (tracker != null) { - for (int passenger : passengers) { - tracker.addPassengerID(passenger); - } - } + trackerLock.writeLock().lock(); + try { + Tracker tracker = trackers.get(another); + if (tracker != null) { + for (int passenger : passengers) { + tracker.addPassengerID(passenger); + } + } + } finally { + trackerLock.writeLock().unlock(); + } } @Override public void untrackPassengers(CNPlayer another, int... passengers) { - Optional.ofNullable(trackers.get(another)).ifPresent(tracker -> { - for (int passenger : passengers) { - tracker.removePassengerID(passenger); + trackerLock.writeLock().lock(); + try { + Tracker tracker = trackers.get(another); + if (tracker != null) { + for (int passenger : passengers) { + tracker.removePassengerID(passenger); + } } - }); + } finally { + trackerLock.writeLock().unlock(); + } } @Override public Set getTrackedPassengerIds(CNPlayer another) { - return Optional.ofNullable(trackers.get(another)).map(Tracker::getPassengerIDs).orElse(new ObjectOpenHashSet<>()); + trackerLock.readLock().lock(); + try { + Tracker tracker = trackers.get(another); + return tracker != null ? tracker.getPassengerIDs() : new ObjectOpenHashSet<>(); + } finally { + trackerLock.readLock().unlock(); + } } @Override public Tracker getTracker(CNPlayer another) { - return trackers.get(another); + trackerLock.readLock().lock(); + try { + return trackers.get(another); + } finally { + trackerLock.readLock().unlock(); + } } @Override diff --git a/api/src/main/java/net/momirealms/customnameplates/api/MainTask.java b/api/src/main/java/net/momirealms/customnameplates/api/MainTask.java index e2d1ac7..f552377 100644 --- a/api/src/main/java/net/momirealms/customnameplates/api/MainTask.java +++ b/api/src/main/java/net/momirealms/customnameplates/api/MainTask.java @@ -34,6 +34,7 @@ public class MainTask implements Runnable { private int timer; private final CustomNameplates plugin; + private boolean state; public MainTask(CustomNameplates plugin) { this.plugin = plugin; @@ -53,24 +54,31 @@ public class MainTask implements Runnable { @Override public void run() { - RUN_TICKS++; - requestedSharedPlaceholders.clear(); - long time1 = System.nanoTime(); - plugin.actionBarManager.refreshConditions(); - plugin.bossBarManager.onTick(); - plugin.unlimitedTagManager.onTick(); - long time2 = System.nanoTime(); - plugin.placeholderManager.refreshPlaceholders(); - long time3 = System.nanoTime(); - plugin.actionBarManager.checkHeartBeats(); - int diff1 = (int) (time2 - time1); - TIME_1.put(timer, diff1); - int diff2 = (int) (time3 - time2); - TIME_2.put(timer, diff2); - timer++; - if (timer >= 1200) timer = 0; - if (RUN_TICKS < 0) { - CustomNameplates.getInstance().reload(); + // we should skip the task if the server is heavily loaded + if (this.state) return; + this.state = true; + try { + RUN_TICKS++; + requestedSharedPlaceholders.clear(); + long time1 = System.nanoTime(); + plugin.actionBarManager.refreshConditions(); + plugin.bossBarManager.onTick(); + plugin.unlimitedTagManager.onTick(); + long time2 = System.nanoTime(); + plugin.placeholderManager.refreshPlaceholders(); + long time3 = System.nanoTime(); + plugin.actionBarManager.checkHeartBeats(); + int diff1 = (int) (time2 - time1); + TIME_1.put(timer, diff1); + int diff2 = (int) (time3 - time2); + TIME_2.put(timer, diff2); + timer++; + if (timer >= 1200) timer = 0; + if (RUN_TICKS < 0) { + CustomNameplates.getInstance().reload(); + } + } finally { + this.state = false; } } diff --git a/api/src/main/java/net/momirealms/customnameplates/api/helper/VersionHelper.java b/api/src/main/java/net/momirealms/customnameplates/api/helper/VersionHelper.java index fb706f6..dfb93a0 100644 --- a/api/src/main/java/net/momirealms/customnameplates/api/helper/VersionHelper.java +++ b/api/src/main/java/net/momirealms/customnameplates/api/helper/VersionHelper.java @@ -61,12 +61,18 @@ public class VersionHelper { private static float version; private static boolean mojmap; private static boolean folia; + private static boolean mohist; + private static boolean paper; public static void init(String serverVersion) { String[] split = serverVersion.split("\\."); version = Float.parseFloat(split[1] + "." + (split.length == 3 ? split[2] : "0")); checkMojMap(); checkFolia(); + checkMohist(); + checkPaper(); + boolean isModdedServer = mohist; + paper = paper && !isModdedServer; } public static float version() { @@ -90,6 +96,22 @@ public class VersionHelper { } } + private static void checkMohist() { + try { + Class.forName("com.mohistmc.api.ServerAPI"); + mohist = true; + } catch (ClassNotFoundException ignored) { + } + } + + private static void checkPaper() { + try { + Class.forName("com.destroystokyo.paper.Metrics"); + paper = true; + } catch (ClassNotFoundException ignored) { + } + } + public static boolean isVersionNewerThan1_21_2() { return version >= 21.19; } @@ -118,6 +140,14 @@ public class VersionHelper { return folia; } + public static boolean isMohist() { + return mohist; + } + + public static boolean isPaperOrItsForks() { + return paper; + } + public static boolean isMojmap() { return mojmap; } diff --git a/backend/src/main/java/net/momirealms/customnameplates/backend/feature/tag/TagRendererImpl.java b/backend/src/main/java/net/momirealms/customnameplates/backend/feature/tag/TagRendererImpl.java index 7a5b872..37bbcec 100644 --- a/backend/src/main/java/net/momirealms/customnameplates/backend/feature/tag/TagRendererImpl.java +++ b/backend/src/main/java/net/momirealms/customnameplates/backend/feature/tag/TagRendererImpl.java @@ -25,6 +25,7 @@ import net.momirealms.customnameplates.api.feature.tag.NameTagConfig; import net.momirealms.customnameplates.api.feature.tag.Tag; import net.momirealms.customnameplates.api.feature.tag.TagRenderer; import net.momirealms.customnameplates.api.feature.tag.UnlimitedTagManager; +import net.momirealms.customnameplates.api.helper.VersionHelper; import net.momirealms.customnameplates.api.network.Tracker; import java.util.*; @@ -301,7 +302,13 @@ public class TagRendererImpl implements TagRenderer { passengers[index++] = passenger; } Object packet = CustomNameplates.getInstance().getPlatform().setPassengersPacket(owner.entityID(), passengers); - CustomNameplates.getInstance().getPacketSender().sendPacket(another, packet); + if (VersionHelper.isPaperOrItsForks()) { + CustomNameplates.getInstance().getPacketSender().sendPacket(another, packet); + } else { + CustomNameplates.getInstance().getScheduler().sync().runLater(() -> { + CustomNameplates.getInstance().getPacketSender().sendPacket(another, packet); + }, 0, null); + } } public void handleEntityDataChange(CNPlayer another, boolean isCrouching) { diff --git a/backend/src/main/resources/config.yml b/backend/src/main/resources/config.yml index ef89825..31d68b4 100644 --- a/backend/src/main/resources/config.yml +++ b/backend/src/main/resources/config.yml @@ -66,8 +66,8 @@ other-settings: display-system-actionbar: true # Should the plugin display system actionbar and temporarily hide the custom actionbar? hide-team-names: true # Hide the team name sent by other plugins or vanilla team system unsafe-chat-event: false # Listen for canceled(unsafe) chat events from unknown plugins - default-condition-refresh-interval: 20 # Set default condition refresh interval - default-placeholder-refresh-interval: 1 # Set default placeholder refresh interval + default-condition-refresh-interval: 10 # Set default condition refresh interval in ticks + default-placeholder-refresh-interval: 1 # Set default placeholder refresh interval in ticks placeholder-refresh-interval: # Custom placeholder refresh intervals for performance optimization "%player_name%": 100 "%vault_prefix%": 20 diff --git a/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/BukkitCNPlayer.java b/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/BukkitCNPlayer.java index 90565c3..18d1fc9 100644 --- a/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/BukkitCNPlayer.java +++ b/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/BukkitCNPlayer.java @@ -80,7 +80,7 @@ public class BukkitCNPlayer extends AbstractCNPlayer { @Override public Vector3 position() { Location location = player().getLocation(); - return new Vector3(location.x(), location.y(), location.z()); + return new Vector3(location.getX(), location.getY(), location.getZ()); } @Override diff --git a/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/scheduler/impl/BukkitExecutor.java b/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/scheduler/impl/BukkitExecutor.java index ae56c76..a5b164e 100644 --- a/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/scheduler/impl/BukkitExecutor.java +++ b/bukkit/src/main/java/net/momirealms/customnameplates/bukkit/scheduler/impl/BukkitExecutor.java @@ -52,12 +52,7 @@ public class BukkitExecutor implements RegionExecutor { @Override public SchedulerTask runLater(Runnable r, long delayTicks, Location l) { if (delayTicks == 0) { - if (Bukkit.isPrimaryThread()) { - r.run(); - return new DummyTask(); - } else { - return new BukkitTask(Bukkit.getScheduler().runTask(plugin, r)); - } + return new BukkitTask(Bukkit.getScheduler().runTask(plugin, r)); } return new BukkitTask(Bukkit.getScheduler().runTaskLater(plugin, r, delayTicks)); } diff --git a/gradle.properties b/gradle.properties index 9158428..6f4c17e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=3.0.12.1 +project_version=3.0.13 config_version=32 project_group=net.momirealms