Allow updating holograms in bulk

This improves performance when using *HolographicDisplays* drastically on many holograms.

Plugins like *EpicAnchors* might need to manage and update a lot of holograms frequently, causing SongodaCore to fetch all the holograms from the external API (My test setup reduced the time needed to update from ~30ms to ~1ms)
This commit is contained in:
Christian Koop 2021-04-21 14:36:04 +02:00 committed by Brianna
parent 040eb14982
commit dde2fd36c6
5 changed files with 71 additions and 25 deletions

View File

@ -5,6 +5,7 @@ import org.bukkit.Location;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* A convenience class for static access to a Holograms HookManager * A convenience class for static access to a Holograms HookManager
@ -76,4 +77,9 @@ public class HologramManager {
if (manager.isEnabled()) if (manager.isEnabled())
manager.getCurrentHook().updateHologram(location, lines); manager.getCurrentHook().updateHologram(location, lines);
} }
public static void bulkUpdateHolograms(Map<Location, List<String>> holograms) {
if (manager.isEnabled())
manager.getCurrentHook().bulkUpdateHolograms(holograms);
}
} }

View File

@ -12,6 +12,7 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -30,7 +31,6 @@ public class CMIHolograms extends Holograms {
} catch (NoSuchFieldException | NoSuchMethodException e) { } catch (NoSuchFieldException | NoSuchMethodException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
public CMIHolograms(Plugin plugin) { public CMIHolograms(Plugin plugin) {
@ -116,6 +116,13 @@ public class CMIHolograms extends Holograms {
createAt(location, lines); createAt(location, lines);
} }
@Override
public void bulkUpdateHolograms(Map<Location, List<String>> hologramData) {
for (Map.Entry<Location, List<String>> entry : hologramData.entrySet()) {
updateHologram(entry.getKey(), entry.getValue());
}
}
private String locStr(Location loc) { private String locStr(Location loc) {
return String.format("%s-%d-%d-%d", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); return String.format("%s-%d-%d-%d", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
} }
@ -133,5 +140,4 @@ public class CMIHolograms extends Holograms {
ourHolograms.add(id); ourHolograms.add(id);
} }
} }
} }

View File

@ -6,6 +6,7 @@ import org.bukkit.plugin.Plugin;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
public abstract class Holograms implements Hook { public abstract class Holograms implements Hook {
@ -55,5 +56,7 @@ public abstract class Holograms implements Hook {
public abstract void updateHologram(Location location, List<String> lines); public abstract void updateHologram(Location location, List<String> lines);
public abstract void bulkUpdateHolograms(Map<Location, List<String>> hologramData);
public abstract void removeAllHolograms(); public abstract void removeAllHolograms();
} }

View File

@ -10,11 +10,12 @@ import org.bukkit.plugin.Plugin;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map;
public class HologramsHolograms extends Holograms { public class HologramsHolograms extends Holograms {
HologramPlugin hologramPlugin; HologramPlugin hologramPlugin;
HashSet<String> ourHolograms = new HashSet(); HashSet<String> ourHolograms = new HashSet<>();
public HologramsHolograms(Plugin plugin) { public HologramsHolograms(Plugin plugin) {
super(plugin); super(plugin);
@ -69,16 +70,20 @@ public class HologramsHolograms extends Holograms {
public void updateHologram(Location location, List<String> lines) { public void updateHologram(Location location, List<String> lines) {
location = fixLocation(location); location = fixLocation(location);
Hologram hologram = hologramPlugin.getHologramManager().getHologram(locStr(location)); Hologram hologram = hologramPlugin.getHologramManager().getHologram(locStr(location));
if (hologram != null) { if (hologram != null) {
hologram.spawn(); hologram.spawn();
// only update if there is a change to the text // only update if there is a change to the text
boolean isChanged = lines.size() != hologram.getLines().size(); boolean isChanged = lines.size() != hologram.getLines().size();
if (!isChanged) { if (!isChanged) {
// double-check the lines // double-check the lines
for (int i = 0; !isChanged && i < lines.size(); ++i) { for (int i = 0; !isChanged && i < lines.size(); ++i) {
isChanged = !hologram.getLine(i).getRaw().equals(lines.get(i)); isChanged = !hologram.getLine(i).getRaw().equals(lines.get(i));
} }
} }
if (isChanged) { if (isChanged) {
for (HologramLine line : hologram.getLines().toArray(new HologramLine[0])) { for (HologramLine line : hologram.getLines().toArray(new HologramLine[0])) {
hologram.removeLine(line); hologram.removeLine(line);
@ -87,17 +92,25 @@ public class HologramsHolograms extends Holograms {
hologram.addLine(new TextLine(hologram, line)); hologram.addLine(new TextLine(hologram, line));
} }
} }
return; return;
} }
createAt(location, lines); createAt(location, lines);
} }
@Override
public void bulkUpdateHolograms(Map<Location, List<String>> hologramData) {
for (Map.Entry<Location, List<String>> entry : hologramData.entrySet()) {
updateHologram(entry.getKey(), entry.getValue());
}
}
private String locStr(Location loc) { private String locStr(Location loc) {
return String.format("%s-%d-%d-%d", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); return String.format("%s-%d-%d-%d", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
} }
private void createAt(Location location, List<String> lines) { private void createAt(Location location, List<String> lines) {
final String id = locStr(location); final String id = locStr(location);
Hologram hologram = new Hologram(id, location); Hologram hologram = new Hologram(id, location);
for (String line : lines) { for (String line : lines) {
@ -109,5 +122,4 @@ public class HologramsHolograms extends Holograms {
if (!ourHolograms.contains(id)) if (!ourHolograms.contains(id))
ourHolograms.add(id); ourHolograms.add(id);
} }
} }

View File

@ -5,7 +5,10 @@ import com.gmail.filoghost.holographicdisplays.api.HologramsAPI;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import java.util.Collection;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
public class HolographicDisplaysHolograms extends Holograms { public class HolographicDisplaysHolograms extends Holograms {
@ -46,28 +49,45 @@ public class HolographicDisplaysHolograms extends Holograms {
@Override @Override
public void updateHologram(Location location, List<String> lines) { public void updateHologram(Location location, List<String> lines) {
location = fixLocation(location); bulkUpdateHolograms(Collections.singletonMap(location, lines));
for (Hologram hologram : HologramsAPI.getHolograms(plugin)) { }
if (hologram.getX() != location.getX()
|| hologram.getY() != location.getY() @Override
|| hologram.getZ() != location.getZ()) continue; public void bulkUpdateHolograms(Map<Location, List<String>> hologramData) {
// only update if there is a change to the text Collection<Hologram> holograms = HologramsAPI.getHolograms(plugin);
boolean isChanged = lines.size() != hologram.size();
if (!isChanged) { for (Map.Entry<Location, List<String>> entry : hologramData.entrySet()) {
// double-check the lines Location location = fixLocation(entry.getKey());
for (int i = 0; !isChanged && i < lines.size(); ++i) { List<String> lines = entry.getValue();
isChanged = !hologram.getLine(i).toString().equals("CraftTextLine [text=" + lines.get(i) + "]");
for (Hologram hologram : holograms) {
if (hologram.getX() != location.getX()
|| hologram.getY() != location.getY()
|| hologram.getZ() != location.getZ()) continue;
// only update if there is a change to the text
boolean isChanged = lines.size() != hologram.size();
if (!isChanged) {
// double-check the lines
for (int i = 0; !isChanged && i < lines.size(); ++i) {
isChanged = !hologram.getLine(i).toString().equals("CraftTextLine [text=" + lines.get(i) + "]");
}
} }
}
if (isChanged) { if (isChanged) {
hologram.clearLines(); hologram.clearLines();
for (String line : lines) {
hologram.appendTextLine(line); for (String line : lines) {
hologram.appendTextLine(line);
}
} }
return;
} }
return;
createAt(location, lines);
} }
createAt(location, lines);
} }
private void createAt(Location location, List<String> lines) { private void createAt(Location location, List<String> lines) {
@ -79,7 +99,6 @@ public class HolographicDisplaysHolograms extends Holograms {
@Override @Override
public void removeAllHolograms() { public void removeAllHolograms() {
HologramsAPI.getHolograms(plugin).stream().forEach(x -> x.delete()); HologramsAPI.getHolograms(plugin).forEach(Hologram::delete);
} }
} }