Optimization

This commit is contained in:
filoghost 2022-06-04 10:28:44 +02:00
parent d58adb7db8
commit c850488ba7
14 changed files with 143 additions and 87 deletions

View File

@ -13,13 +13,16 @@ import org.jetbrains.annotations.NotNull;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
public class DefaultVisibilitySettings implements VisibilitySettings {
private final AtomicInteger version;
private Visibility globalVisibility;
private Map<UUID, Visibility> individualVisibilities;
public DefaultVisibilitySettings() {
this.version = new AtomicInteger();
this.globalVisibility = Visibility.VISIBLE;
}
@ -35,6 +38,7 @@ public class DefaultVisibilitySettings implements VisibilitySettings {
}
this.globalVisibility = visibility;
version.incrementAndGet();
}
@Override
@ -43,7 +47,10 @@ public class DefaultVisibilitySettings implements VisibilitySettings {
if (individualVisibilities == null) {
individualVisibilities = new ConcurrentHashMap<>();
}
individualVisibilities.put(player.getUniqueId(), visibility);
Visibility previousVisibility = individualVisibilities.put(player.getUniqueId(), visibility);
if (visibility != previousVisibility) {
version.incrementAndGet();
}
}
@Override
@ -72,16 +79,24 @@ public class DefaultVisibilitySettings implements VisibilitySettings {
return;
}
individualVisibilities.remove(player.getUniqueId());
Visibility previousVisibility = individualVisibilities.remove(player.getUniqueId());
if (previousVisibility != null) {
version.incrementAndGet();
}
}
@Override
public void clearIndividualVisibilities() {
if (individualVisibilities == null) {
if (individualVisibilities == null || individualVisibilities.isEmpty()) {
return;
}
individualVisibilities.clear();
version.incrementAndGet();
}
public int getVersion() {
return version.get();
}
@Override

View File

@ -33,11 +33,11 @@ public abstract class BaseClickableHologramLine extends BaseHologramLine {
private boolean isInClickRange(Player player) {
Location playerLocation = player.getLocation();
PositionCoordinates position = this.getPosition();
PositionCoordinates positionCoordinates = this.getCoordinates();
double xDiff = playerLocation.getX() - position.getX();
double yDiff = playerLocation.getY() + 1.3 - position.getY(); // Use shoulder height
double zDiff = playerLocation.getZ() - position.getZ();
double xDiff = playerLocation.getX() - positionCoordinates.getX();
double yDiff = playerLocation.getY() + 1.3 - positionCoordinates.getY(); // Use shoulder height
double zDiff = playerLocation.getZ() - positionCoordinates.getZ();
double distanceSquared = (xDiff * xDiff) + (yDiff * yDiff) + (zDiff * zDiff);
return distanceSquared < 5 * 5;

View File

@ -100,7 +100,7 @@ public abstract class BaseHologram extends BaseHologramComponent {
@Override
public String toString() {
return "Hologram{"
+ "position=" + hologramPosition.getPosition()
+ "position=" + hologramPosition
+ ", lines=" + getLines()
+ ", deleted=" + isDeleted()
+ "}";

View File

@ -7,6 +7,7 @@ package me.filoghost.holographicdisplays.core.base;
import me.filoghost.fcommons.Preconditions;
import me.filoghost.holographicdisplays.common.PositionCoordinates;
import me.filoghost.holographicdisplays.core.api.current.DefaultVisibilitySettings;
import me.filoghost.holographicdisplays.core.tracking.LineTracker;
import me.filoghost.holographicdisplays.core.tracking.LineTrackerManager;
import org.bukkit.GameMode;
@ -21,7 +22,7 @@ public abstract class BaseHologramLine extends BaseHologramComponent implements
private final BaseHologram hologram;
private final LineTracker<?> tracker;
private PositionCoordinates position;
private PositionCoordinates coordinates;
protected BaseHologramLine(BaseHologram hologram) {
Preconditions.notNull(hologram, "hologram");
@ -40,16 +41,20 @@ public abstract class BaseHologramLine extends BaseHologramComponent implements
}
@Override
public final void setPosition(double x, double y, double z) {
position = new PositionCoordinates(x, y, z);
public final void setCoordinates(double x, double y, double z) {
coordinates = new PositionCoordinates(x, y, z);
setChanged();
}
public @NotNull PositionCoordinates getPosition() {
if (position == null) {
public @NotNull PositionCoordinates getCoordinates() {
if (coordinates == null) {
throw new IllegalStateException("position not set");
}
return position;
return coordinates;
}
public @NotNull String getWorldName() {
return hologram.getPosition().getWorldName();
}
public @Nullable World getWorldIfLoaded() {
@ -68,6 +73,10 @@ public abstract class BaseHologramLine extends BaseHologramComponent implements
return hologram.getCreatorPlugin();
}
public final DefaultVisibilitySettings getVisibilitySettings() {
return hologram.getVisibilitySettings();
}
protected boolean canInteract(Player player) {
return !isDeleted()
&& player.isOnline()

View File

@ -101,7 +101,7 @@ public class BaseHologramLines<T extends EditableHologramLine> implements Iterab
currentLineY -= spaceBetweenLines;
}
line.setPosition(hologramPosition.getX(), currentLineY, hologramPosition.getZ());
line.setCoordinates(hologramPosition.getX(), currentLineY, hologramPosition.getZ());
}
}

View File

@ -7,7 +7,7 @@ package me.filoghost.holographicdisplays.core.base;
public interface EditableHologramLine {
void setPosition(double x, double y, double z);
void setCoordinates(double x, double y, double z);
double getHeight();

View File

@ -99,6 +99,11 @@ class HologramPosition {
return position;
}
@Override
public String toString() {
return position.toString();
}
private enum ChunkLoadState {

View File

@ -11,15 +11,29 @@ import org.bukkit.entity.Player;
public class CachedPlayer {
private final Player player;
private final TickClock tickClock;
private Location location;
private long locationUpdateTick;
public CachedPlayer(Player player, TickClock tickClock) {
public CachedPlayer(Player player) {
this.player = player;
this.tickClock = tickClock;
this.locationUpdateTick = -1;
}
boolean onTick() {
Location newLocation = player.getLocation();
boolean moved = isDifferentPosition(location, newLocation);
location = newLocation;
return moved;
}
private boolean isDifferentPosition(Location oldLocation, Location newLocation) {
if (oldLocation == null) {
return true;
}
return newLocation.getWorld() != oldLocation.getWorld()
|| newLocation.getX() != oldLocation.getX()
|| newLocation.getY() != oldLocation.getY()
|| newLocation.getZ() != oldLocation.getZ();
}
public Player getBukkitPlayer() {
@ -27,13 +41,6 @@ public class CachedPlayer {
}
public Location getLocation() {
// Avoid creating a new object on each invocation
long currentTick = tickClock.getCurrentTick();
if (locationUpdateTick != currentTick) {
location = player.getLocation();
locationUpdateTick = currentTick;
}
return location;
}

View File

@ -38,7 +38,7 @@ public class TickingTask implements Runnable {
}
public void onPlayerJoin(Player player) {
onlinePlayers.add(new CachedPlayer(player, tickClock));
onlinePlayers.add(new CachedPlayer(player));
}
public void onPlayerQuit(Player player) {
@ -65,8 +65,16 @@ public class TickingTask implements Runnable {
// Remove outdated entries before using them from line trackers
placeholderTracker.clearOutdatedEntries();
List<CachedPlayer> movedPlayers = new ArrayList<>();
for (CachedPlayer onlinePlayer : onlinePlayers) {
boolean moved = onlinePlayer.onTick();
if (moved) {
movedPlayers.add(onlinePlayer);
}
}
try {
lineTrackerManager.update(onlinePlayers);
lineTrackerManager.update(onlinePlayers, movedPlayers);
} catch (Throwable t) {
// Catch all types of Throwable because we're using NMS code
if (tickClock.getCurrentTick() - lastErrorLogTick >= 20) {

View File

@ -6,11 +6,10 @@
package me.filoghost.holographicdisplays.core.tracking;
import me.filoghost.holographicdisplays.common.PositionCoordinates;
import me.filoghost.holographicdisplays.nms.common.NMSManager;
import me.filoghost.holographicdisplays.nms.common.entity.ClickableNMSPacketEntity;
import me.filoghost.holographicdisplays.core.base.BaseClickableHologramLine;
import me.filoghost.holographicdisplays.core.listener.LineClickListener;
import me.filoghost.holographicdisplays.core.tick.TickClock;
import me.filoghost.holographicdisplays.nms.common.NMSManager;
import me.filoghost.holographicdisplays.nms.common.entity.ClickableNMSPacketEntity;
import org.jetbrains.annotations.MustBeInvokedByOverriders;
public abstract class ClickableLineTracker<T extends Viewer> extends LineTracker<T> {
@ -22,8 +21,7 @@ public abstract class ClickableLineTracker<T extends Viewer> extends LineTracker
private boolean spawnClickableEntity;
private boolean spawnClickableEntityChanged;
public ClickableLineTracker(BaseClickableHologramLine line, NMSManager nmsManager, LineClickListener lineClickListener, TickClock tickClock) {
super(tickClock);
public ClickableLineTracker(BaseClickableHologramLine line, NMSManager nmsManager, LineClickListener lineClickListener) {
this.clickableEntity = nmsManager.newClickablePacketEntity();
this.positionOffsetY = (line.getHeight() - ClickableNMSPacketEntity.SLIME_HEIGHT) / 2;
this.lineClickListener = lineClickListener;
@ -102,7 +100,7 @@ public abstract class ClickableLineTracker<T extends Viewer> extends LineTracker
}
private PositionCoordinates getClickableEntityPosition() {
return position.addY(positionOffsetY);
return positionCoordinates.addY(positionOffsetY);
}
}

View File

@ -5,12 +5,11 @@
*/
package me.filoghost.holographicdisplays.core.tracking;
import me.filoghost.holographicdisplays.nms.common.NMSManager;
import me.filoghost.holographicdisplays.nms.common.entity.ItemNMSPacketEntity;
import me.filoghost.holographicdisplays.core.base.BaseItemHologramLine;
import me.filoghost.holographicdisplays.core.listener.LineClickListener;
import me.filoghost.holographicdisplays.core.tick.CachedPlayer;
import me.filoghost.holographicdisplays.core.tick.TickClock;
import me.filoghost.holographicdisplays.nms.common.NMSManager;
import me.filoghost.holographicdisplays.nms.common.entity.ItemNMSPacketEntity;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.MustBeInvokedByOverriders;
@ -31,9 +30,8 @@ public class ItemLineTracker extends ClickableLineTracker<Viewer> {
public ItemLineTracker(
BaseItemHologramLine line,
NMSManager nmsManager,
LineClickListener lineClickListener,
TickClock tickClock) {
super(line, nmsManager, lineClickListener, tickClock);
LineClickListener lineClickListener) {
super(line, nmsManager, lineClickListener);
this.line = line;
this.itemEntity = nmsManager.newItemPacketEntity();
}
@ -45,12 +43,12 @@ public class ItemLineTracker extends ClickableLineTracker<Viewer> {
@MustBeInvokedByOverriders
@Override
protected void update(List<CachedPlayer> onlinePlayers) {
super.update(onlinePlayers);
protected void update(List<CachedPlayer> onlinePlayers, List<CachedPlayer> movedPlayers) {
super.update(onlinePlayers, movedPlayers);
if (spawnItemEntity && hasViewers() && line.hasPickupCallback()) {
for (Viewer viewer : getViewers()) {
if (CollisionHelper.isInPickupRange(viewer.getLocation(), position)) {
if (CollisionHelper.isInPickupRange(viewer.getLocation(), positionCoordinates)) {
line.onPickup(viewer.getBukkitPlayer());
}
}
@ -99,7 +97,7 @@ public class ItemLineTracker extends ClickableLineTracker<Viewer> {
super.sendSpawnPackets(viewers);
if (spawnItemEntity) {
viewers.sendPackets(itemEntity.newSpawnPackets(position, itemStack));
viewers.sendPackets(itemEntity.newSpawnPackets(positionCoordinates, itemStack));
}
}
@ -120,7 +118,7 @@ public class ItemLineTracker extends ClickableLineTracker<Viewer> {
if (spawnItemEntityChanged) {
if (spawnItemEntity) {
viewers.sendPackets(itemEntity.newSpawnPackets(position, itemStack));
viewers.sendPackets(itemEntity.newSpawnPackets(positionCoordinates, itemStack));
} else {
viewers.sendPackets(itemEntity.newDestroyPackets());
}
@ -136,7 +134,7 @@ public class ItemLineTracker extends ClickableLineTracker<Viewer> {
super.sendPositionChangePackets(viewers);
if (spawnItemEntity) {
viewers.sendPackets(itemEntity.newTeleportPackets(position));
viewers.sendPackets(itemEntity.newTeleportPackets(positionCoordinates));
}
}

View File

@ -8,7 +8,6 @@ package me.filoghost.holographicdisplays.core.tracking;
import me.filoghost.holographicdisplays.common.PositionCoordinates;
import me.filoghost.holographicdisplays.core.base.BaseHologramLine;
import me.filoghost.holographicdisplays.core.tick.CachedPlayer;
import me.filoghost.holographicdisplays.core.tick.TickClock;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.MustBeInvokedByOverriders;
@ -21,22 +20,20 @@ import java.util.Objects;
public abstract class LineTracker<T extends Viewer> {
private static final int MODIFY_VIEWERS_INTERVAL_TICKS = 5;
private final TickClock tickClock;
private final Map<Player, T> viewers;
private final Viewers<T> iterableViewers;
protected PositionCoordinates position;
private String positionWorldName;
protected PositionCoordinates positionCoordinates;
private boolean positionChanged;
/**
* Flag to indicate that the line has changed in some way and there could be the need to send update packets.
*/
private boolean lineChanged;
private int lastVisibilitySettingsVersion;
protected LineTracker(TickClock tickClock) {
this.tickClock = tickClock;
protected LineTracker() {
this.viewers = new HashMap<>();
this.iterableViewers = new DelegateViewers<>(viewers.values());
}
@ -57,7 +54,7 @@ public abstract class LineTracker<T extends Viewer> {
}
@MustBeInvokedByOverriders
protected void update(List<CachedPlayer> onlinePlayers) {
protected void update(List<CachedPlayer> onlinePlayers, List<CachedPlayer> movedPlayers) {
boolean sendChangesPackets = false;
// First, detect the changes if the flag is on and set it off
@ -75,28 +72,43 @@ public abstract class LineTracker<T extends Viewer> {
}
// Then, send the changes (if any) to already tracked players
if (sendChangesPackets) {
if (hasViewers()) {
sendChangesPackets(iterableViewers);
}
clearDetectedChanges();
if (sendChangesPackets && hasViewers()) {
sendChangesPackets(iterableViewers);
}
// Finally, add/remove tracked players sending them the full spawn/destroy packets
modifyViewersAndSendPackets(onlinePlayers);
// Finally, add/remove viewers sending them the full spawn/destroy packets
modifyViewersAndSendPackets(onlinePlayers, movedPlayers);
if (sendChangesPackets) {
clearDetectedChanges();
}
}
protected abstract boolean updatePlaceholders();
private void modifyViewersAndSendPackets(List<CachedPlayer> onlinePlayers) {
private void modifyViewersAndSendPackets(List<CachedPlayer> onlinePlayers, List<CachedPlayer> movedPlayers) {
if (!getLine().isInLoadedChunk()) {
resetViewersAndSendDestroyPackets();
return;
}
// Add the identity hash code to avoid updating all the lines at the same time
if ((tickClock.getCurrentTick() + hashCode()) % MODIFY_VIEWERS_INTERVAL_TICKS != 0) {
return;
boolean checkAllPlayers = false;
int visibilitySettingsVersion = getLine().getVisibilitySettings().getVersion();
if (visibilitySettingsVersion != lastVisibilitySettingsVersion) {
lastVisibilitySettingsVersion = visibilitySettingsVersion;
checkAllPlayers = true;
}
if (positionChanged) {
checkAllPlayers = true;
}
List<CachedPlayer> playersToCheck;
if (checkAllPlayers) {
playersToCheck = onlinePlayers;
} else {
playersToCheck = movedPlayers;
}
// Lazy initialization
@ -104,9 +116,9 @@ public abstract class LineTracker<T extends Viewer> {
MutableViewers<T> removedPlayers = null;
// Micro-optimization, don't use for-each loop to avoid creating a new Iterator (method called frequently)
int size = onlinePlayers.size();
int size = playersToCheck.size();
for (int i = 0; i < size; i++) {
CachedPlayer player = onlinePlayers.get(i);
CachedPlayer player = playersToCheck.get(i);
Player bukkitPlayer = player.getBukkitPlayer();
if (shouldTrackPlayer(player)) {
if (!viewers.containsKey(bukkitPlayer)) {
@ -142,8 +154,8 @@ public abstract class LineTracker<T extends Viewer> {
return false;
}
double diffX = Math.abs(playerLocation.getX() - position.getX());
double diffZ = Math.abs(playerLocation.getZ() - position.getZ());
double diffX = Math.abs(playerLocation.getX() - positionCoordinates.getX());
double diffZ = Math.abs(playerLocation.getZ() - positionCoordinates.getZ());
return diffX <= getViewRange()
&& diffZ <= getViewRange()
@ -172,9 +184,15 @@ public abstract class LineTracker<T extends Viewer> {
@MustBeInvokedByOverriders
protected void detectChanges() {
PositionCoordinates position = getLine().getPosition();
if (!Objects.equals(this.position, position)) {
this.position = position;
PositionCoordinates positionCoordinates = getLine().getCoordinates();
if (!Objects.equals(this.positionCoordinates, positionCoordinates)) {
this.positionCoordinates = positionCoordinates;
this.positionChanged = true;
}
String positionWorldName = getLine().getWorldName();
if (!Objects.equals(this.positionWorldName, positionWorldName)) {
this.positionWorldName = positionWorldName;
this.positionChanged = true;
}
}

View File

@ -40,18 +40,18 @@ public class LineTrackerManager {
}
public TextLineTracker startTracking(BaseTextHologramLine line) {
TextLineTracker tracker = new TextLineTracker(line, nmsManager, lineClickListener, placeholderTracker, tickClock);
TextLineTracker tracker = new TextLineTracker(line, nmsManager, lineClickListener, placeholderTracker);
lineTrackers.add(tracker);
return tracker;
}
public ItemLineTracker startTracking(BaseItemHologramLine line) {
ItemLineTracker tracker = new ItemLineTracker(line, nmsManager, lineClickListener, tickClock);
ItemLineTracker tracker = new ItemLineTracker(line, nmsManager, lineClickListener);
lineTrackers.add(tracker);
return tracker;
}
public void update(List<CachedPlayer> onlinePlayers) {
public void update(List<CachedPlayer> onlinePlayers, List<CachedPlayer> movedPlayers) {
Iterator<LineTracker<?>> iterator = lineTrackers.iterator();
while (iterator.hasNext()) {
LineTracker<?> lineTracker = iterator.next();
@ -63,7 +63,7 @@ public class LineTrackerManager {
continue;
}
lineTracker.update(onlinePlayers);
lineTracker.update(onlinePlayers, movedPlayers);
}
}

View File

@ -5,14 +5,13 @@
*/
package me.filoghost.holographicdisplays.core.tracking;
import me.filoghost.holographicdisplays.nms.common.IndividualTextPacketGroup;
import me.filoghost.holographicdisplays.nms.common.NMSManager;
import me.filoghost.holographicdisplays.nms.common.entity.TextNMSPacketEntity;
import me.filoghost.holographicdisplays.core.base.BaseTextHologramLine;
import me.filoghost.holographicdisplays.core.listener.LineClickListener;
import me.filoghost.holographicdisplays.core.placeholder.tracking.ActivePlaceholderTracker;
import me.filoghost.holographicdisplays.core.tick.CachedPlayer;
import me.filoghost.holographicdisplays.core.tick.TickClock;
import me.filoghost.holographicdisplays.nms.common.IndividualTextPacketGroup;
import me.filoghost.holographicdisplays.nms.common.NMSManager;
import me.filoghost.holographicdisplays.nms.common.entity.TextNMSPacketEntity;
import org.jetbrains.annotations.MustBeInvokedByOverriders;
import java.util.Objects;
@ -29,9 +28,8 @@ public class TextLineTracker extends ClickableLineTracker<TextLineViewer> {
BaseTextHologramLine line,
NMSManager nmsManager,
LineClickListener lineClickListener,
ActivePlaceholderTracker placeholderTracker,
TickClock tickClock) {
super(line, nmsManager, lineClickListener, tickClock);
ActivePlaceholderTracker placeholderTracker) {
super(line, nmsManager, lineClickListener);
this.line = line;
this.textEntity = nmsManager.newTextPacketEntity();
this.displayText = new DisplayText(placeholderTracker);
@ -86,7 +84,7 @@ public class TextLineTracker extends ClickableLineTracker<TextLineViewer> {
protected void sendSpawnPackets(Viewers<TextLineViewer> viewers) {
super.sendSpawnPackets(viewers);
IndividualTextPacketGroup spawnPackets = textEntity.newSpawnPackets(position);
IndividualTextPacketGroup spawnPackets = textEntity.newSpawnPackets(positionCoordinates);
viewers.forEach(viewer -> viewer.sendTextPackets(spawnPackets));
}
@ -111,7 +109,7 @@ public class TextLineTracker extends ClickableLineTracker<TextLineViewer> {
@Override
protected void sendPositionChangePackets(Viewers<TextLineViewer> viewers) {
super.sendPositionChangePackets(viewers);
viewers.sendPackets(textEntity.newTeleportPackets(position));
viewers.sendPackets(textEntity.newTeleportPackets(positionCoordinates));
}
@Override