Add back support for touch functionality

This commit is contained in:
filoghost 2021-07-28 15:11:07 +02:00
parent f3d3d07038
commit 438dcfb1dc
34 changed files with 531 additions and 62 deletions

View File

@ -36,4 +36,8 @@ public class EntityID {
return uuid;
}
public boolean hasInitializedNumericID() {
return numericID != null;
}
}

View File

@ -9,5 +9,7 @@ public class NMSErrors {
public static final String EXCEPTION_GETTING_ENTITY_ID_GENERATOR = "Could not get the NMS entity ID generator."
+ " There is a small chance of entity ID conflicts, causing client-side issues on single entities.";
public static final String EXCEPTION_ON_PACKET_READ = "Unexpected error while inspecting inbound network packet.";
public static final String EXCEPTION_MODIFYING_CHANNEL_PIPELINE = "Unexpected error while modifying the channel pipeline.";
}

View File

@ -5,10 +5,16 @@
*/
package me.filoghost.holographicdisplays.common.nms;
import org.bukkit.entity.Player;
public interface NMSManager {
EntityID newEntityID();
NMSPacketList createPacketList();
void injectPacketListener(Player player, PacketListener packetListener);
void uninjectPacketListener(Player player);
}

View File

@ -0,0 +1,20 @@
/*
* Copyright (C) filoghost and contributors
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package me.filoghost.holographicdisplays.common.nms;
import org.bukkit.entity.Player;
public interface PacketListener {
/**
* Called asynchronously (from network threads) when a player interacts with an entity.
*
* @param entityID the ID of the entity
* @return true if the packet should be cancelled, false otherwise
*/
boolean onAsyncEntityInteract(Player player, int entityID);
}

View File

@ -6,8 +6,10 @@
package me.filoghost.holographicdisplays.nms.v1_10_R1;
import me.filoghost.holographicdisplays.common.nms.EntityID;
import me.filoghost.holographicdisplays.common.nms.PacketListener;
import me.filoghost.holographicdisplays.common.nms.NMSManager;
import me.filoghost.holographicdisplays.common.nms.NMSPacketList;
import org.bukkit.entity.Player;
public class VersionNMSManager implements NMSManager {
@ -21,4 +23,14 @@ public class VersionNMSManager implements NMSManager {
return null;
}
@Override
public void injectPacketListener(Player player, PacketListener packetListener) {
}
@Override
public void uninjectPacketListener(Player player) {
}
}

View File

@ -6,8 +6,10 @@
package me.filoghost.holographicdisplays.nms.v1_11_R1;
import me.filoghost.holographicdisplays.common.nms.EntityID;
import me.filoghost.holographicdisplays.common.nms.PacketListener;
import me.filoghost.holographicdisplays.common.nms.NMSManager;
import me.filoghost.holographicdisplays.common.nms.NMSPacketList;
import org.bukkit.entity.Player;
public class VersionNMSManager implements NMSManager {
@ -21,4 +23,14 @@ public class VersionNMSManager implements NMSManager {
return null;
}
@Override
public void injectPacketListener(Player player, PacketListener packetListener) {
}
@Override
public void uninjectPacketListener(Player player) {
}
}

View File

@ -6,8 +6,10 @@
package me.filoghost.holographicdisplays.nms.v1_12_R1;
import me.filoghost.holographicdisplays.common.nms.EntityID;
import me.filoghost.holographicdisplays.common.nms.PacketListener;
import me.filoghost.holographicdisplays.common.nms.NMSManager;
import me.filoghost.holographicdisplays.common.nms.NMSPacketList;
import org.bukkit.entity.Player;
public class VersionNMSManager implements NMSManager {
@ -21,4 +23,14 @@ public class VersionNMSManager implements NMSManager {
return null;
}
@Override
public void injectPacketListener(Player player, PacketListener packetListener) {
}
@Override
public void uninjectPacketListener(Player player) {
}
}

View File

@ -6,8 +6,10 @@
package me.filoghost.holographicdisplays.nms.v1_13_R1;
import me.filoghost.holographicdisplays.common.nms.EntityID;
import me.filoghost.holographicdisplays.common.nms.PacketListener;
import me.filoghost.holographicdisplays.common.nms.NMSManager;
import me.filoghost.holographicdisplays.common.nms.NMSPacketList;
import org.bukkit.entity.Player;
public class VersionNMSManager implements NMSManager {
@ -21,4 +23,14 @@ public class VersionNMSManager implements NMSManager {
return null;
}
@Override
public void injectPacketListener(Player player, PacketListener packetListener) {
}
@Override
public void uninjectPacketListener(Player player) {
}
}

View File

@ -6,8 +6,10 @@
package me.filoghost.holographicdisplays.nms.v1_13_R2;
import me.filoghost.holographicdisplays.common.nms.EntityID;
import me.filoghost.holographicdisplays.common.nms.PacketListener;
import me.filoghost.holographicdisplays.common.nms.NMSManager;
import me.filoghost.holographicdisplays.common.nms.NMSPacketList;
import org.bukkit.entity.Player;
public class VersionNMSManager implements NMSManager {
@ -21,4 +23,14 @@ public class VersionNMSManager implements NMSManager {
return null;
}
@Override
public void injectPacketListener(Player player, PacketListener packetListener) {
}
@Override
public void uninjectPacketListener(Player player) {
}
}

View File

@ -6,8 +6,10 @@
package me.filoghost.holographicdisplays.nms.v1_14_R1;
import me.filoghost.holographicdisplays.common.nms.EntityID;
import me.filoghost.holographicdisplays.common.nms.PacketListener;
import me.filoghost.holographicdisplays.common.nms.NMSManager;
import me.filoghost.holographicdisplays.common.nms.NMSPacketList;
import org.bukkit.entity.Player;
public class VersionNMSManager implements NMSManager {
@ -21,4 +23,14 @@ public class VersionNMSManager implements NMSManager {
return null;
}
@Override
public void injectPacketListener(Player player, PacketListener packetListener) {
}
@Override
public void uninjectPacketListener(Player player) {
}
}

View File

@ -6,8 +6,10 @@
package me.filoghost.holographicdisplays.nms.v1_15_R1;
import me.filoghost.holographicdisplays.common.nms.EntityID;
import me.filoghost.holographicdisplays.common.nms.PacketListener;
import me.filoghost.holographicdisplays.common.nms.NMSManager;
import me.filoghost.holographicdisplays.common.nms.NMSPacketList;
import org.bukkit.entity.Player;
public class VersionNMSManager implements NMSManager {
@ -21,4 +23,14 @@ public class VersionNMSManager implements NMSManager {
return null;
}
@Override
public void injectPacketListener(Player player, PacketListener packetListener) {
}
@Override
public void uninjectPacketListener(Player player) {
}
}

View File

@ -6,8 +6,10 @@
package me.filoghost.holographicdisplays.nms.v1_16_R1;
import me.filoghost.holographicdisplays.common.nms.EntityID;
import me.filoghost.holographicdisplays.common.nms.PacketListener;
import me.filoghost.holographicdisplays.common.nms.NMSManager;
import me.filoghost.holographicdisplays.common.nms.NMSPacketList;
import org.bukkit.entity.Player;
public class VersionNMSManager implements NMSManager {
@ -21,4 +23,14 @@ public class VersionNMSManager implements NMSManager {
return null;
}
@Override
public void injectPacketListener(Player player, PacketListener packetListener) {
}
@Override
public void uninjectPacketListener(Player player) {
}
}

View File

@ -6,8 +6,10 @@
package me.filoghost.holographicdisplays.nms.v1_16_R2;
import me.filoghost.holographicdisplays.common.nms.EntityID;
import me.filoghost.holographicdisplays.common.nms.PacketListener;
import me.filoghost.holographicdisplays.common.nms.NMSManager;
import me.filoghost.holographicdisplays.common.nms.NMSPacketList;
import org.bukkit.entity.Player;
public class VersionNMSManager implements NMSManager {
@ -21,4 +23,14 @@ public class VersionNMSManager implements NMSManager {
return null;
}
@Override
public void injectPacketListener(Player player, PacketListener packetListener) {
}
@Override
public void uninjectPacketListener(Player player) {
}
}

View File

@ -6,8 +6,10 @@
package me.filoghost.holographicdisplays.nms.v1_16_R3;
import me.filoghost.holographicdisplays.common.nms.EntityID;
import me.filoghost.holographicdisplays.common.nms.PacketListener;
import me.filoghost.holographicdisplays.common.nms.NMSManager;
import me.filoghost.holographicdisplays.common.nms.NMSPacketList;
import org.bukkit.entity.Player;
public class VersionNMSManager implements NMSManager {
@ -21,4 +23,14 @@ public class VersionNMSManager implements NMSManager {
return null;
}
@Override
public void injectPacketListener(Player player, PacketListener packetListener) {
}
@Override
public void uninjectPacketListener(Player player) {
}
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (C) filoghost and contributors
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package me.filoghost.holographicdisplays.nms.v1_17_R1;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import me.filoghost.fcommons.logging.Log;
import me.filoghost.fcommons.reflection.ReflectField;
import me.filoghost.holographicdisplays.common.nms.PacketListener;
import me.filoghost.holographicdisplays.common.nms.NMSErrors;
import net.minecraft.network.protocol.game.PacketPlayInUseEntity;
import org.bukkit.entity.Player;
public class InboundPacketHandler extends ChannelInboundHandlerAdapter {
public static final String HANDLER_NAME = "holographic_displays_listener";
private static final ReflectField<Integer> ENTITY_ID_FIELD = ReflectField.lookup(int.class, PacketPlayInUseEntity.class, "a");
private final Player player;
private final PacketListener packetListener;
public InboundPacketHandler(Player player, PacketListener packetListener) {
this.player = player;
this.packetListener = packetListener;
}
@Override
public void channelRead(ChannelHandlerContext context, Object packet) throws Exception {
try {
if (packet instanceof PacketPlayInUseEntity) {
int entityID = ENTITY_ID_FIELD.get(packet);
boolean cancel = packetListener.onAsyncEntityInteract(player, entityID);
if (cancel) {
return;
}
}
} catch (Throwable t) {
Log.warning(NMSErrors.EXCEPTION_ON_PACKET_READ, t);
}
super.channelRead(context, packet);
}
}

View File

@ -5,16 +5,26 @@
*/
package me.filoghost.holographicdisplays.nms.v1_17_R1;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelPipeline;
import me.filoghost.fcommons.logging.ErrorCollector;
import me.filoghost.fcommons.logging.Log;
import me.filoghost.fcommons.reflection.ReflectField;
import me.filoghost.holographicdisplays.common.nms.PacketListener;
import me.filoghost.holographicdisplays.common.nms.EntityID;
import me.filoghost.holographicdisplays.common.nms.FallbackEntityIDGenerator;
import me.filoghost.holographicdisplays.common.nms.NMSErrors;
import me.filoghost.holographicdisplays.common.nms.NMSManager;
import me.filoghost.holographicdisplays.common.nms.NMSPacketList;
import net.minecraft.network.NetworkManager;
import net.minecraft.server.network.PlayerConnection;
import net.minecraft.world.entity.Entity;
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class VersionNMSManager implements NMSManager {
@ -49,4 +59,43 @@ public class VersionNMSManager implements NMSManager {
return new VersionNMSPacketList();
}
@Override
public void injectPacketListener(Player player, PacketListener packetListener) {
modifyPipeline(player, (ChannelPipeline pipeline) -> {
ChannelHandler currentListener = pipeline.get(InboundPacketHandler.HANDLER_NAME);
if (currentListener != null) {
pipeline.remove(InboundPacketHandler.HANDLER_NAME);
}
pipeline.addBefore("packet_handler", InboundPacketHandler.HANDLER_NAME, new InboundPacketHandler(player, packetListener));
});
}
@Override
public void uninjectPacketListener(Player player) {
modifyPipeline(player, (ChannelPipeline pipeline) -> {
ChannelHandler currentListener = pipeline.get(InboundPacketHandler.HANDLER_NAME);
if (currentListener != null) {
pipeline.remove(InboundPacketHandler.HANDLER_NAME);
}
});
}
/*
* Modifying the pipeline in the main thread can cause deadlocks, delays and other concurrency issues.
* Thanks to ProtocolLib for this insight.
*/
private void modifyPipeline(Player player, Consumer<ChannelPipeline> pipelineModifierTask) {
PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().b;
NetworkManager networkManager = playerConnection.a();
Channel channel = networkManager.k;
channel.eventLoop().execute(() -> {
try {
pipelineModifierTask.accept(channel.pipeline());
} catch (Exception e) {
Log.warning(NMSErrors.EXCEPTION_MODIFYING_CHANNEL_PIPELINE, e);
}
});
}
}

View File

@ -6,8 +6,10 @@
package me.filoghost.holographicdisplays.nms.v1_8_R2;
import me.filoghost.holographicdisplays.common.nms.EntityID;
import me.filoghost.holographicdisplays.common.nms.PacketListener;
import me.filoghost.holographicdisplays.common.nms.NMSManager;
import me.filoghost.holographicdisplays.common.nms.NMSPacketList;
import org.bukkit.entity.Player;
public class VersionNMSManager implements NMSManager {
@ -21,4 +23,14 @@ public class VersionNMSManager implements NMSManager {
return null;
}
@Override
public void injectPacketListener(Player player, PacketListener packetListener) {
}
@Override
public void uninjectPacketListener(Player player) {
}
}

View File

@ -6,8 +6,10 @@
package me.filoghost.holographicdisplays.nms.v1_8_R3;
import me.filoghost.holographicdisplays.common.nms.EntityID;
import me.filoghost.holographicdisplays.common.nms.PacketListener;
import me.filoghost.holographicdisplays.common.nms.NMSManager;
import me.filoghost.holographicdisplays.common.nms.NMSPacketList;
import org.bukkit.entity.Player;
public class VersionNMSManager implements NMSManager {
@ -21,4 +23,14 @@ public class VersionNMSManager implements NMSManager {
return null;
}
@Override
public void injectPacketListener(Player player, PacketListener packetListener) {
}
@Override
public void uninjectPacketListener(Player player) {
}
}

View File

@ -6,8 +6,10 @@
package me.filoghost.holographicdisplays.nms.v1_9_R1;
import me.filoghost.holographicdisplays.common.nms.EntityID;
import me.filoghost.holographicdisplays.common.nms.PacketListener;
import me.filoghost.holographicdisplays.common.nms.NMSManager;
import me.filoghost.holographicdisplays.common.nms.NMSPacketList;
import org.bukkit.entity.Player;
public class VersionNMSManager implements NMSManager {
@ -21,4 +23,14 @@ public class VersionNMSManager implements NMSManager {
return null;
}
@Override
public void injectPacketListener(Player player, PacketListener packetListener) {
}
@Override
public void uninjectPacketListener(Player player) {
}
}

View File

@ -6,8 +6,10 @@
package me.filoghost.holographicdisplays.nms.v1_9_R2;
import me.filoghost.holographicdisplays.common.nms.EntityID;
import me.filoghost.holographicdisplays.common.nms.PacketListener;
import me.filoghost.holographicdisplays.common.nms.NMSManager;
import me.filoghost.holographicdisplays.common.nms.NMSPacketList;
import org.bukkit.entity.Player;
public class VersionNMSManager implements NMSManager {
@ -21,4 +23,14 @@ public class VersionNMSManager implements NMSManager {
return null;
}
@Override
public void injectPacketListener(Player player, PacketListener packetListener) {
}
@Override
public void uninjectPacketListener(Player player) {
}
}

View File

@ -23,9 +23,10 @@ import me.filoghost.holographicdisplays.plugin.disk.Settings;
import me.filoghost.holographicdisplays.plugin.disk.upgrade.LegacySymbolsUpgrade;
import me.filoghost.holographicdisplays.plugin.hologram.api.APIHologramManager;
import me.filoghost.holographicdisplays.plugin.hologram.internal.InternalHologramManager;
import me.filoghost.holographicdisplays.plugin.hologram.tracking.LineTouchListener;
import me.filoghost.holographicdisplays.plugin.hologram.tracking.LineTrackerManager;
import me.filoghost.holographicdisplays.plugin.listener.ChunkListener;
import me.filoghost.holographicdisplays.plugin.listener.PlayerQuitListener;
import me.filoghost.holographicdisplays.plugin.listener.PlayerListener;
import me.filoghost.holographicdisplays.plugin.listener.UpdateNotificationListener;
import me.filoghost.holographicdisplays.plugin.log.PrintableErrorCollector;
import me.filoghost.holographicdisplays.plugin.placeholder.TickClock;
@ -38,6 +39,7 @@ import me.filoghost.holographicdisplays.plugin.util.NMSVersion;
import org.bstats.bukkit.MetricsLite;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
@ -46,6 +48,7 @@ public class HolographicDisplays extends FCommonsPlugin {
private static HolographicDisplays instance;
private NMSManager nmsManager;
private ConfigManager configManager;
private InternalHologramManager internalHologramManager;
private BungeeServerTracker bungeeServerTracker;
@ -87,7 +90,6 @@ public class HolographicDisplays extends FCommonsPlugin {
PrintableErrorCollector errorCollector = new PrintableErrorCollector();
NMSManager nmsManager;
try {
nmsManager = NMSVersion.getCurrent().createNMSManager(errorCollector);
} catch (Throwable t) {
@ -100,7 +102,8 @@ public class HolographicDisplays extends FCommonsPlugin {
placeholderRegistry = new PlaceholderRegistry();
TickClock tickClock = new TickClock();
PlaceholderTracker placeholderTracker = new PlaceholderTracker(placeholderRegistry, tickClock);
lineTrackerManager = new LineTrackerManager(nmsManager, placeholderTracker);
LineTouchListener lineTouchListener = new LineTouchListener();
lineTrackerManager = new LineTrackerManager(nmsManager, placeholderTracker, lineTouchListener);
internalHologramManager = new InternalHologramManager(lineTrackerManager);
APIHologramManager apiHologramManager = new APIHologramManager(lineTrackerManager);
@ -115,13 +118,17 @@ public class HolographicDisplays extends FCommonsPlugin {
PlaceholderAPIHook.setup();
TickingTask tickingTask = new TickingTask(tickClock, lineTrackerManager);
for (Player player : Bukkit.getOnlinePlayers()) {
nmsManager.injectPacketListener(player, lineTouchListener);
}
TickingTask tickingTask = new TickingTask(tickClock, lineTrackerManager, lineTouchListener);
Bukkit.getScheduler().scheduleSyncRepeatingTask(this, tickingTask, 0, 1);
HologramCommandManager commandManager = new HologramCommandManager(this, internalHologramManager, configManager);
commandManager.register(this);
registerListener(new PlayerQuitListener(lineTrackerManager));
registerListener(new PlayerListener(nmsManager, lineTrackerManager, lineTouchListener));
registerListener(new ChunkListener(this, lineTrackerManager));
UpdateNotificationListener updateNotificationListener = new UpdateNotificationListener();
registerListener(updateNotificationListener);
@ -177,7 +184,10 @@ public class HolographicDisplays extends FCommonsPlugin {
@Override
public void onDisable() {
lineTrackerManager.clearTrackedPlayers();
lineTrackerManager.clearTrackedPlayersAndSendPackets();
for (Player player : Bukkit.getOnlinePlayers()) {
nmsManager.uninjectPacketListener(player);
}
}
public static HolographicDisplays getInstance() {

View File

@ -11,6 +11,7 @@ import me.filoghost.holographicdisplays.common.hologram.StandardHologramLine;
import me.filoghost.holographicdisplays.plugin.hologram.tracking.LineTracker;
import me.filoghost.holographicdisplays.plugin.hologram.tracking.LineTrackerManager;
import org.bukkit.World;
import org.bukkit.entity.Player;
public abstract class BaseHologramLine extends BaseHologramComponent implements StandardHologramLine {
@ -31,10 +32,14 @@ public abstract class BaseHologramLine extends BaseHologramComponent implements
}
@Override
public void setChanged() {
public final void setChanged() {
tracker.setLineChanged();
}
protected final boolean isTrackedPlayer(Player player) {
return tracker.isTrackedPlayer(player);
}
@Override
public final void setLocation(World world, double x, double y, double z) {
super.setLocation(world, x, y, z);

View File

@ -32,11 +32,12 @@ public abstract class BaseTouchableLine extends BaseHologramLine implements Stan
@Override
public void onTouch(Player player) {
if (player.getGameMode() == GameMode.SPECTATOR) {
return;
}
if (touchHandler == null || !getHologram().isVisibleTo(player)) {
if (isDeleted()
|| !player.isOnline()
|| !isTrackedPlayer(player)
|| player.getGameMode() == GameMode.SPECTATOR
|| touchHandler == null
|| !getHologram().isVisibleTo(player)) {
return;
}

View File

@ -25,8 +25,8 @@ public class ItemLineTracker extends TouchableLineTracker<StandardItemLine> {
private boolean spawnItemEntities;
private boolean spawnItemEntitiesChanged;
public ItemLineTracker(StandardItemLine line, NMSManager nmsManager) {
super(line, nmsManager);
public ItemLineTracker(StandardItemLine line, NMSManager nmsManager, LineTouchListener lineTouchListener) {
super(line, nmsManager, lineTouchListener);
this.vehicleEntityID = nmsManager.newEntityID();
this.itemEntityID = nmsManager.newEntityID();
}

View File

@ -0,0 +1,93 @@
/*
* Copyright (C) filoghost and contributors
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package me.filoghost.holographicdisplays.plugin.hologram.tracking;
import me.filoghost.holographicdisplays.common.hologram.StandardTouchableLine;
import me.filoghost.holographicdisplays.common.nms.EntityID;
import me.filoghost.holographicdisplays.common.nms.PacketListener;
import org.bukkit.entity.Player;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class LineTouchListener implements PacketListener {
private final ConcurrentMap<Integer, StandardTouchableLine> linesByEntityID;
// It is necessary to queue async touch events to process them from the main thread.
// Use a set to avoid duplicate touch events to the same line.
private final Set<TouchEvent> queuedTouchEvents;
public LineTouchListener() {
linesByEntityID = new ConcurrentHashMap<>();
queuedTouchEvents = new HashSet<>();
}
@Override
public boolean onAsyncEntityInteract(Player player, int entityID) {
StandardTouchableLine line = linesByEntityID.get(entityID);
if (line != null) {
queuedTouchEvents.add(new TouchEvent(player, line));
return true;
} else {
return false;
}
}
public void processQueuedTouchEvents() {
for (TouchEvent touchEvent : queuedTouchEvents) {
touchEvent.line.onTouch(touchEvent.player);
}
queuedTouchEvents.clear();
}
public void registerLine(EntityID touchableEntityID, StandardTouchableLine line) {
linesByEntityID.put(touchableEntityID.getNumericID(), line);
}
public void unregisterLine(EntityID touchableEntityID) {
if (touchableEntityID.hasInitializedNumericID()) {
linesByEntityID.remove(touchableEntityID.getNumericID());
}
}
private static class TouchEvent {
private final Player player;
private final StandardTouchableLine line;
TouchEvent(Player player, StandardTouchableLine line) {
this.player = player;
this.line = line;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
TouchEvent other = (TouchEvent) obj;
return this.player.equals(other.player) && this.line.equals(other.line);
}
@Override
public int hashCode() {
int result = player.hashCode();
result = 31 * result + line.hashCode();
return result;
}
}
}

View File

@ -10,6 +10,7 @@ import me.filoghost.holographicdisplays.common.nms.NMSManager;
import me.filoghost.holographicdisplays.common.nms.NMSPacketList;
import org.bukkit.Chunk;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.MustBeInvokedByOverriders;
import java.util.Collection;
import java.util.HashSet;
@ -36,7 +37,7 @@ public abstract class LineTracker<T extends StandardHologramLine> {
lineChanged = true;
}
final void updateAndSendChanges(Collection<? extends Player> onlinePlayers) {
final void updateAndSendPackets(Collection<? extends Player> onlinePlayers) {
boolean sendChangesPackets = false;
// First, detect the changes if the flag is on and set it off
@ -61,7 +62,7 @@ public abstract class LineTracker<T extends StandardHologramLine> {
}
// Finally, add/remove tracked players sending them the full spawn/destroy packets
updateTrackedPlayers(onlinePlayers);
updateTrackedPlayersAndSendPackets(onlinePlayers);
}
protected abstract void detectChanges();
@ -70,9 +71,9 @@ public abstract class LineTracker<T extends StandardHologramLine> {
protected abstract boolean updatePlaceholders();
private void updateTrackedPlayers(Collection<? extends Player> onlinePlayers) {
private void updateTrackedPlayersAndSendPackets(Collection<? extends Player> onlinePlayers) {
if (!isActive()) {
clearTrackedPlayers();
clearTrackedPlayersAndSendPackets();
return;
}
@ -101,10 +102,15 @@ public abstract class LineTracker<T extends StandardHologramLine> {
}
}
final boolean isDeleted() {
final boolean shouldBeRemoved() {
return line.isDeleted() || line.getHologram().isDeleted();
}
@MustBeInvokedByOverriders
public void onRemoval() {
clearTrackedPlayersAndSendPackets();
}
protected abstract boolean isActive();
protected abstract boolean shouldTrackPlayer(Player player);
@ -113,11 +119,15 @@ public abstract class LineTracker<T extends StandardHologramLine> {
return !trackedPlayers.isEmpty();
}
public final boolean isTrackedPlayer(Player player) {
return trackedPlayers.contains(player);
}
protected final void removeTrackedPlayer(Player player) {
trackedPlayers.remove(player);
}
protected final void clearTrackedPlayers() {
protected final void clearTrackedPlayersAndSendPackets() {
if (!hasTrackedPlayers()) {
return;
}

View File

@ -21,27 +21,29 @@ public class LineTrackerManager {
private final NMSManager nmsManager;
private final PlaceholderTracker placeholderTracker;
private final LineTouchListener lineTouchListener;
private final Collection<LineTracker<?>> lineTrackers;
public LineTrackerManager(NMSManager nmsManager, PlaceholderTracker placeholderTracker) {
public LineTrackerManager(NMSManager nmsManager, PlaceholderTracker placeholderTracker, LineTouchListener lineTouchListener) {
this.nmsManager = nmsManager;
this.placeholderTracker = placeholderTracker;
this.lineTouchListener = lineTouchListener;
this.lineTrackers = new LinkedList<>();
}
public TextLineTracker startTracking(StandardTextLine line) {
TextLineTracker tracker = new TextLineTracker(line, nmsManager, placeholderTracker);
TextLineTracker tracker = new TextLineTracker(line, nmsManager, lineTouchListener, placeholderTracker);
lineTrackers.add(tracker);
return tracker;
}
public ItemLineTracker startTracking(StandardItemLine line) {
ItemLineTracker tracker = new ItemLineTracker(line, nmsManager);
ItemLineTracker tracker = new ItemLineTracker(line, nmsManager, lineTouchListener);
lineTrackers.add(tracker);
return tracker;
}
public void updateTrackersAndSendChanges() {
public void updateTrackersAndSendPackets() {
Collection<? extends Player> onlinePlayers = Bukkit.getOnlinePlayers();
Iterator<LineTracker<?>> iterator = lineTrackers.iterator();
@ -49,19 +51,19 @@ public class LineTrackerManager {
LineTracker<?> lineTracker = iterator.next();
// Remove deleted trackers, sending destroy packets to tracked players
if (lineTracker.isDeleted()) {
lineTracker.clearTrackedPlayers();
if (lineTracker.shouldBeRemoved()) {
iterator.remove();
lineTracker.onRemoval();
continue;
}
lineTracker.updateAndSendChanges(onlinePlayers);
lineTracker.updateAndSendPackets(onlinePlayers);
}
}
public void clearTrackedPlayers() {
public void clearTrackedPlayersAndSendPackets() {
for (LineTracker<?> tracker : lineTrackers) {
tracker.clearTrackedPlayers();
tracker.clearTrackedPlayersAndSendPackets();
}
}

View File

@ -22,8 +22,12 @@ public class TextLineTracker extends TouchableLineTracker<StandardTextLine> {
private boolean displayTextChanged;
private boolean allowPlaceholders;
public TextLineTracker(StandardTextLine line, NMSManager nmsManager, PlaceholderTracker placeholderTracker) {
super(line, nmsManager);
public TextLineTracker(
StandardTextLine line,
NMSManager nmsManager,
LineTouchListener lineTouchListener,
PlaceholderTracker placeholderTracker) {
super(line, nmsManager, lineTouchListener);
this.armorStandEntityID = nmsManager.newEntityID();
this.displayText = new DisplayText(placeholderTracker);
}

View File

@ -15,16 +15,25 @@ public abstract class TouchableLineTracker<T extends StandardTouchableLine> exte
private static final double SLIME_HEIGHT = 0.5;
private final LineTouchListener lineTouchListener;
private final EntityID vehicleEntityID;
private final EntityID slimeEntityID;
private boolean spawnSlimeEntities;
private boolean spawnSlimeEntitiesChanged;
public TouchableLineTracker(T line, NMSManager nmsManager) {
public TouchableLineTracker(T line, NMSManager nmsManager, LineTouchListener lineTouchListener) {
super(line, nmsManager);
this.vehicleEntityID = nmsManager.newEntityID();
this.slimeEntityID = nmsManager.newEntityID();
this.lineTouchListener = lineTouchListener;
}
@MustBeInvokedByOverriders
@Override
public void onRemoval() {
super.onRemoval();
lineTouchListener.unregisterLine(slimeEntityID);
}
@MustBeInvokedByOverriders
@ -36,6 +45,11 @@ public abstract class TouchableLineTracker<T extends StandardTouchableLine> exte
if (this.spawnSlimeEntities != spawnSlimeEntities) {
this.spawnSlimeEntities = spawnSlimeEntities;
this.spawnSlimeEntitiesChanged = true;
if (spawnSlimeEntities) {
lineTouchListener.registerLine(slimeEntityID, line);
} else {
lineTouchListener.unregisterLine(slimeEntityID);
}
}
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) filoghost and contributors
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package me.filoghost.holographicdisplays.plugin.listener;
import me.filoghost.holographicdisplays.common.nms.NMSManager;
import me.filoghost.holographicdisplays.plugin.hologram.tracking.LineTouchListener;
import me.filoghost.holographicdisplays.plugin.hologram.tracking.LineTrackerManager;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
public class PlayerListener implements Listener {
private final NMSManager nmsManager;
private final LineTrackerManager lineTrackerManager;
private final LineTouchListener lineTouchListener;
public PlayerListener(NMSManager nmsManager, LineTrackerManager lineTrackerManager, LineTouchListener lineTouchListener) {
this.nmsManager = nmsManager;
this.lineTrackerManager = lineTrackerManager;
this.lineTouchListener = lineTouchListener;
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
Player player = event.getPlayer();
nmsManager.injectPacketListener(player, lineTouchListener);
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer();
lineTrackerManager.onPlayerQuit(player);
nmsManager.uninjectPacketListener(player);
}
}

View File

@ -1,26 +0,0 @@
/*
* Copyright (C) filoghost and contributors
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package me.filoghost.holographicdisplays.plugin.listener;
import me.filoghost.holographicdisplays.plugin.hologram.tracking.LineTrackerManager;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
public class PlayerQuitListener implements Listener {
private final LineTrackerManager lineTrackerManager;
public PlayerQuitListener(LineTrackerManager lineTrackerManager) {
this.lineTrackerManager = lineTrackerManager;
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
lineTrackerManager.onPlayerQuit(event.getPlayer());
}
}

View File

@ -6,18 +6,21 @@
package me.filoghost.holographicdisplays.plugin.placeholder;
import me.filoghost.fcommons.logging.Log;
import me.filoghost.holographicdisplays.plugin.hologram.tracking.LineTouchListener;
import me.filoghost.holographicdisplays.plugin.hologram.tracking.LineTrackerManager;
public class TickingTask implements Runnable {
private final TickClock tickClock;
private final LineTrackerManager lineTrackerManager;
private final LineTouchListener lineTouchListener;
private long lastErrorLogTick;
public TickingTask(TickClock tickClock, LineTrackerManager lineTrackerManager) {
public TickingTask(TickClock tickClock, LineTrackerManager lineTrackerManager, LineTouchListener lineTouchListener) {
this.tickClock = tickClock;
this.lineTrackerManager = lineTrackerManager;
this.lineTouchListener = lineTouchListener;
}
@Override
@ -25,14 +28,17 @@ public class TickingTask implements Runnable {
tickClock.incrementTick();
try {
lineTrackerManager.updateTrackersAndSendChanges();
lineTrackerManager.updateTrackersAndSendPackets();
} catch (Throwable t) {
// Avoid spamming the console, log the error at most once every 20 ticks
// Catch all types of Throwable because we're using NMS code
if (tickClock.getCurrentTick() - lastErrorLogTick >= 20) {
// Avoid spamming the console, log the error at most once every 20 ticks
lastErrorLogTick = tickClock.getCurrentTick();
Log.severe("Error while ticking holograms", t);
}
}
lineTouchListener.processQueuedTouchEvents();
}
}

View File

@ -6,6 +6,7 @@
package me.filoghost.holographicdisplays.plugin.test;
import me.filoghost.holographicdisplays.plugin.hologram.api.APIHologramManager;
import me.filoghost.holographicdisplays.plugin.hologram.tracking.LineTouchListener;
import me.filoghost.holographicdisplays.plugin.hologram.tracking.LineTrackerManager;
import me.filoghost.holographicdisplays.plugin.placeholder.tracking.PlaceholderTracker;
@ -14,7 +15,7 @@ import static org.mockito.Mockito.*;
public class TestAPIHologramManager extends APIHologramManager {
public TestAPIHologramManager() {
super(new LineTrackerManager(new TestNMSManager(), mock(PlaceholderTracker.class)));
super(new LineTrackerManager(new TestNMSManager(), mock(PlaceholderTracker.class), new LineTouchListener()));
}
}

View File

@ -6,9 +6,11 @@
package me.filoghost.holographicdisplays.plugin.test;
import me.filoghost.holographicdisplays.common.nms.EntityID;
import me.filoghost.holographicdisplays.common.nms.PacketListener;
import me.filoghost.holographicdisplays.common.nms.FallbackEntityIDGenerator;
import me.filoghost.holographicdisplays.common.nms.NMSManager;
import me.filoghost.holographicdisplays.common.nms.NMSPacketList;
import org.bukkit.entity.Player;
import java.util.function.Supplier;
@ -34,4 +36,14 @@ public class TestNMSManager implements NMSManager {
return packetList;
}
@Override
public void injectPacketListener(Player player, PacketListener packetListener) {
}
@Override
public void uninjectPacketListener(Player player) {
}
}