From 80303a68a52dd70c4a3b22fee4ec4e2119b80fa1 Mon Sep 17 00:00:00 2001 From: granny Date: Sat, 21 Oct 2023 23:36:29 -0700 Subject: [PATCH 01/53] make scheduler run on every tick --- .../src/main/java/net/pl3x/map/bukkit/Pl3xMapBukkit.java | 2 +- .../main/java/net/pl3x/map/core/markers/layer/Layer.java | 6 +++--- .../java/net/pl3x/map/core/markers/layer/SpawnLayer.java | 2 +- .../net/pl3x/map/core/markers/layer/WorldBorderLayer.java | 2 +- .../net/pl3x/map/core/renderer/task/UpdateMarkerData.java | 2 +- .../pl3x/map/core/renderer/task/UpdateSettingsData.java | 2 +- .../main/java/net/pl3x/map/core/scheduler/Scheduler.java | 8 ++++---- core/src/main/java/net/pl3x/map/core/scheduler/Task.java | 4 ++-- .../net/pl3x/map/fabric/client/manager/TileManager.java | 2 +- .../net/pl3x/map/fabric/server/Pl3xMapFabricServer.java | 6 +----- 10 files changed, 16 insertions(+), 20 deletions(-) diff --git a/bukkit/src/main/java/net/pl3x/map/bukkit/Pl3xMapBukkit.java b/bukkit/src/main/java/net/pl3x/map/bukkit/Pl3xMapBukkit.java index cd91e7dc0..9e2dfb968 100644 --- a/bukkit/src/main/java/net/pl3x/map/bukkit/Pl3xMapBukkit.java +++ b/bukkit/src/main/java/net/pl3x/map/bukkit/Pl3xMapBukkit.java @@ -81,7 +81,7 @@ public void onEnable() { } getServer().getScheduler().runTaskTimer(this, () -> - this.pl3xmap.getScheduler().tick(), 20, 20); + this.pl3xmap.getScheduler().tick(), 20, 1); } @Override diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java index b5f07c09b..ccc45d553 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java @@ -41,7 +41,7 @@ @SuppressWarnings("UnusedReturnValue") public abstract class Layer extends Keyed implements JsonSerializable { private Supplier<@NotNull String> labelSupplier; - private int updateInterval = 15; + private int updateInterval = 15 * 20; private boolean showControls = true; private boolean defaultHidden = false; private int priority = 99; @@ -93,7 +93,7 @@ public Layer(@NotNull String key, @NotNull Supplier<@NotNull String> labelSuppli } /** - * Get this layer's update interval (in seconds). + * Get this layer's update interval (in ticks). * * @return update interval */ @@ -102,7 +102,7 @@ public int getUpdateInterval() { } /** - * Set this layer's update interval (in seconds). + * Set this layer's update interval (in ticks). * * @param updateInterval new update interval * @return this layer diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java index 2114e589a..e1405a625 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java @@ -65,7 +65,7 @@ public SpawnLayer(@NotNull World world) { throw new RuntimeException(e); } - setUpdateInterval(SpawnLayerConfig.UPDATE_INTERVAL); + setUpdateInterval(SpawnLayerConfig.UPDATE_INTERVAL * 20); setShowControls(SpawnLayerConfig.SHOW_CONTROLS); setDefaultHidden(SpawnLayerConfig.DEFAULT_HIDDEN); setPriority(SpawnLayerConfig.PRIORITY); diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java index 33d8e97bd..6f256b7a6 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java @@ -52,7 +52,7 @@ public class WorldBorderLayer extends WorldLayer { */ public WorldBorderLayer(@NotNull World world) { this(KEY, world, () -> Lang.UI_LAYER_WORLDBORDER); - setUpdateInterval(WorldBorderLayerConfig.UPDATE_INTERVAL); + setUpdateInterval(WorldBorderLayerConfig.UPDATE_INTERVAL * 20); setShowControls(WorldBorderLayerConfig.SHOW_CONTROLS); setDefaultHidden(WorldBorderLayerConfig.DEFAULT_HIDDEN); setPriority(WorldBorderLayerConfig.PRIORITY); diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java index db7a38600..fea6d7d27 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java @@ -61,7 +61,7 @@ public class UpdateMarkerData extends Task { private boolean running; public UpdateMarkerData(@NotNull World world) { - super(1, true); + super(1 * 20, true); this.world = world; this.executor = Pl3xMap.ThreadFactory.createService("Pl3xMap-Markers"); } diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java index 799a9fd07..9b9411e38 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java @@ -52,7 +52,7 @@ public class UpdateSettingsData extends Task { .create(); public UpdateSettingsData() { - super(1, true); + super(1 * 20, true); } @Override diff --git a/core/src/main/java/net/pl3x/map/core/scheduler/Scheduler.java b/core/src/main/java/net/pl3x/map/core/scheduler/Scheduler.java index c3b8e9cf1..71eb0536e 100644 --- a/core/src/main/java/net/pl3x/map/core/scheduler/Scheduler.java +++ b/core/src/main/java/net/pl3x/map/core/scheduler/Scheduler.java @@ -34,7 +34,7 @@ public class Scheduler { private boolean ticking; /** - * Tick this scheduler once every second. + * Tick this scheduler once every tick. */ public void tick() { if (this.ticking) { @@ -88,7 +88,7 @@ public void addTask(@NotNull Task task) { /** * Add task to the scheduler. * - * @param delay Delay (in seconds) before task starts + * @param delay Delay (in ticks) before task starts * @param runnable Task to add */ public void addTask(int delay, @NotNull Runnable runnable) { @@ -98,8 +98,8 @@ public void addTask(int delay, @NotNull Runnable runnable) { /** * Add task to the scheduler. * - * @param delay Delay (in seconds) before task starts - * @param repeat Delay (in seconds) before task repeats + * @param delay Delay (in ticks) before task starts + * @param repeat Delay (in ticks) before task repeats * @param runnable Task to add */ public void addTask(int delay, boolean repeat, @NotNull Runnable runnable) { diff --git a/core/src/main/java/net/pl3x/map/core/scheduler/Task.java b/core/src/main/java/net/pl3x/map/core/scheduler/Task.java index b294e8464..b332496f4 100644 --- a/core/src/main/java/net/pl3x/map/core/scheduler/Task.java +++ b/core/src/main/java/net/pl3x/map/core/scheduler/Task.java @@ -33,7 +33,7 @@ public abstract class Task implements Runnable { /** * Creates a new schedulable task. * - * @param delay Delay (in seconds) before task starts + * @param delay Delay (in ticks) before task starts */ public Task(int delay) { this(delay, false); @@ -42,7 +42,7 @@ public Task(int delay) { /** * Creates a new schedulable task. * - * @param delay Delay (in seconds) before task starts + * @param delay Delay (in ticks) before task starts * @param repeat Whether this task should repeat */ public Task(int delay, boolean repeat) { diff --git a/fabric/src/main/java/net/pl3x/map/fabric/client/manager/TileManager.java b/fabric/src/main/java/net/pl3x/map/fabric/client/manager/TileManager.java index 80dcb1126..e4ac78751 100644 --- a/fabric/src/main/java/net/pl3x/map/fabric/client/manager/TileManager.java +++ b/fabric/src/main/java/net/pl3x/map/fabric/client/manager/TileManager.java @@ -64,7 +64,7 @@ public void initialize() { // update once next tick this.mod.getScheduler().addTask(0, this::update); // setup repeating task to update every 5 seconds - this.task = new Task(5, true) { + this.task = new Task(5 * 20, true) { @Override public void run() { update(); diff --git a/fabric/src/main/java/net/pl3x/map/fabric/server/Pl3xMapFabricServer.java b/fabric/src/main/java/net/pl3x/map/fabric/server/Pl3xMapFabricServer.java index 393a56ab6..dc67b2d1c 100644 --- a/fabric/src/main/java/net/pl3x/map/fabric/server/Pl3xMapFabricServer.java +++ b/fabric/src/main/java/net/pl3x/map/fabric/server/Pl3xMapFabricServer.java @@ -76,7 +76,6 @@ public class Pl3xMapFabricServer extends Pl3xMap implements DedicatedServerModIn private FabricServerAudiences adventure; private boolean firstTick = true; - private int tick; private FabricNetwork network; @@ -97,10 +96,7 @@ public void onInitializeServer() { Pl3xMap.api().getEventRegistry().callEvent(new ServerLoadedEvent()); this.firstTick = false; } - if (this.tick++ >= 20) { - this.tick = 0; - getScheduler().tick(); - } + getScheduler().tick(); }); ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { From f727f0c837d4840f0c4d6e817c26b4b8cf979596 Mon Sep 17 00:00:00 2001 From: granny Date: Sat, 21 Oct 2023 23:39:16 -0700 Subject: [PATCH 02/53] use delay/repeat values set in MarkerTask class --- core/src/main/java/net/pl3x/map/core/world/World.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/net/pl3x/map/core/world/World.java b/core/src/main/java/net/pl3x/map/core/world/World.java index 591af89a5..27f53e2f3 100644 --- a/core/src/main/java/net/pl3x/map/core/world/World.java +++ b/core/src/main/java/net/pl3x/map/core/world/World.java @@ -168,7 +168,7 @@ protected void init() { Pl3xMap.api().getRegionProcessor().addRegions(this, listRegions(false)); Logger.debug("Starting marker task"); - Pl3xMap.api().getScheduler().addTask(1, true, this.markerTask); + Pl3xMap.api().getScheduler().addTask(this.markerTask); // load up custom markers Logger.debug("Loading custom markers for " + getName()); From 9013c3b2a25fb7602080086d30efeb0e40a060ea Mon Sep 17 00:00:00 2001 From: granny Date: Sat, 21 Oct 2023 23:44:46 -0700 Subject: [PATCH 03/53] move parsePlayers method to PlayerRegistry --- .../pl3x/map/core/player/PlayerRegistry.java | 37 +++++++++++++++++++ .../renderer/task/UpdateSettingsData.java | 32 +--------------- 2 files changed, 38 insertions(+), 31 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/player/PlayerRegistry.java b/core/src/main/java/net/pl3x/map/core/player/PlayerRegistry.java index 820ec23a1..7a8b032ca 100644 --- a/core/src/main/java/net/pl3x/map/core/player/PlayerRegistry.java +++ b/core/src/main/java/net/pl3x/map/core/player/PlayerRegistry.java @@ -23,10 +23,17 @@ */ package net.pl3x.map.core.player; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Optional; import java.util.UUID; import java.util.function.Supplier; +import net.pl3x.map.core.Pl3xMap; +import net.pl3x.map.core.configuration.PlayersLayerConfig; import net.pl3x.map.core.registry.Registry; import net.pl3x.map.core.util.Preconditions; import org.jetbrains.annotations.NotNull; @@ -89,4 +96,34 @@ public class PlayerRegistry extends Registry<@NotNull Player> { Player player = get(uuid); return player == null ? Optional.empty() : Optional.of(player); } + + public @NotNull List<@NotNull Object> parsePlayers() { + if (!PlayersLayerConfig.ENABLED) { + return Collections.emptyList(); + } + List players = new ArrayList<>(); + Pl3xMap.api().getPlayerRegistry().forEach(player -> { + // do not expose hidden players in the json + if (player.isHidden() || player.isNPC()) { + return; + } + if (PlayersLayerConfig.HIDE_SPECTATORS && player.isSpectator()) { + return; + } + if (PlayersLayerConfig.HIDE_INVISIBLE && player.isInvisible()) { + return; + } + + Map playerEntry = new LinkedHashMap<>(); + + playerEntry.put("name", player.getDecoratedName()); + playerEntry.put("uuid", player.getUUID().toString()); + playerEntry.put("displayName", player.getDecoratedName()); + playerEntry.put("world", player.getWorld().getName()); + playerEntry.put("position", player.getPosition()); + + players.add(playerEntry); + }); + return players; + } } diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java index 9b9411e38..5a6128563 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java @@ -64,36 +64,6 @@ public void run() { } } - private @NotNull List<@NotNull Object> parsePlayers() { - if (!PlayersLayerConfig.ENABLED) { - return Collections.emptyList(); - } - List players = new ArrayList<>(); - Pl3xMap.api().getPlayerRegistry().forEach(player -> { - // do not expose hidden players in the json - if (player.isHidden() || player.isNPC()) { - return; - } - if (PlayersLayerConfig.HIDE_SPECTATORS && player.isSpectator()) { - return; - } - if (PlayersLayerConfig.HIDE_INVISIBLE && player.isInvisible()) { - return; - } - - Map playerEntry = new LinkedHashMap<>(); - - playerEntry.put("name", player.getDecoratedName()); - playerEntry.put("uuid", player.getUUID().toString()); - playerEntry.put("displayName", player.getDecoratedName()); - playerEntry.put("world", player.getWorld().getName()); - playerEntry.put("position", player.getPosition()); - - players.add(playerEntry); - }); - return players; - } - private @NotNull List<@NotNull Map<@NotNull String, @NotNull Object>> parseWorlds() { List> worldSettings = new ArrayList<>(); Pl3xMap.api().getWorldRegistry().entrySet().forEach(entry -> { @@ -175,7 +145,7 @@ private void parseSettings() { map.put("zoom", zoom); try { - map.put("players", parsePlayers()); + map.put("players", Pl3xMap.api().getPlayerRegistry().parsePlayers()); map.put("worldSettings", parseWorlds()); } catch (Throwable t) { t.printStackTrace(); From 9da766b9d366aa4894470ce273e5ff5e7fe5059c Mon Sep 17 00:00:00 2001 From: granny Date: Sat, 21 Oct 2023 23:48:32 -0700 Subject: [PATCH 04/53] working SSE prototype --- .../net/pl3x/map/core/httpd/HttpdServer.java | 37 +++++-- .../pl3x/map/core/registry/WorldRegistry.java | 1 + .../core/renderer/task/AbstractDataTask.java | 101 ++++++++++++++++++ .../core/renderer/task/UpdateMarkerData.java | 70 +----------- .../core/renderer/task/UpdateSSEEvents.java | 30 ++++++ .../java/net/pl3x/map/core/world/World.java | 11 ++ webmap/src/Pl3xMap.ts | 49 ++++++++- webmap/src/layergroup/MarkerLayer.ts | 78 +++++++------- webmap/src/player/PlayerManager.ts | 4 +- 9 files changed, 265 insertions(+), 116 deletions(-) create mode 100644 core/src/main/java/net/pl3x/map/core/renderer/task/AbstractDataTask.java create mode 100644 core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSSEEvents.java diff --git a/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java b/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java index e738da495..c1ed113f2 100644 --- a/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java +++ b/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java @@ -23,12 +23,15 @@ */ package net.pl3x.map.core.httpd; +import io.undertow.Handlers; import io.undertow.Undertow; import io.undertow.UndertowLogger; import io.undertow.UndertowOptions; import io.undertow.server.handlers.resource.PathResourceManager; import io.undertow.server.handlers.resource.ResourceHandler; import io.undertow.server.handlers.resource.ResourceManager; +import io.undertow.server.handlers.sse.ServerSentEventConnection; +import io.undertow.server.handlers.sse.ServerSentEventHandler; import io.undertow.util.ETag; import io.undertow.util.Headers; import java.io.IOException; @@ -43,6 +46,17 @@ public class HttpdServer { private Undertow server; + private static ServerSentEventHandler serverSentEventHandler = Handlers.serverSentEvents(); + + public static void sendSSE(String event, String data) { + for (ServerSentEventConnection connection : serverSentEventHandler.getConnections()) { + connection.send(data, event, null, null); + } + } + + public static void sendSSE(String data) { + sendSSE(null, data); + } public void startServer() { if (!Config.HTTPD_ENABLED) { @@ -81,16 +95,19 @@ public void startServer() { this.server = Undertow.builder() .setServerOption(UndertowOptions.ENABLE_HTTP2, true) .addHttpListener(Config.HTTPD_PORT, Config.HTTPD_BIND) - .setHandler(exchange -> { - if (exchange.getRelativePath().startsWith("/tiles")) { - exchange.getResponseHeaders().put(Headers.CACHE_CONTROL, "max-age=0, must-revalidate, no-cache"); - } - if (exchange.getRelativePath().endsWith(".gz")) { - exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "application/json"); - exchange.getResponseHeaders().put(Headers.CONTENT_ENCODING, "gzip"); - } - resourceHandler.handleRequest(exchange); - }) + .setHandler(Handlers.path() + .addPrefixPath("/", exchange -> { + if (exchange.getRelativePath().startsWith("/tiles")) { + exchange.getResponseHeaders().put(Headers.CACHE_CONTROL, "max-age=0, must-revalidate, no-cache"); + } + if (exchange.getRelativePath().endsWith(".gz")) { + exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "application/json"); + exchange.getResponseHeaders().put(Headers.CONTENT_ENCODING, "gzip"); + } + resourceHandler.handleRequest(exchange); + }) + .addExactPath("/sse", serverSentEventHandler) + ) .build(); this.server.start(); LogFilter.HIDE_UNDERTOW_LOGS = false; diff --git a/core/src/main/java/net/pl3x/map/core/registry/WorldRegistry.java b/core/src/main/java/net/pl3x/map/core/registry/WorldRegistry.java index a1c58694e..218756c95 100644 --- a/core/src/main/java/net/pl3x/map/core/registry/WorldRegistry.java +++ b/core/src/main/java/net/pl3x/map/core/registry/WorldRegistry.java @@ -46,6 +46,7 @@ public class WorldRegistry extends Registry<@NotNull World> { if (world != null) { Pl3xMap.api().getEventRegistry().callEvent(new WorldUnloadedEvent(world)); world.getMarkerTask().cancel(); + world.getSSETask().cancel(); //world.getRegionFileWatcher().stop(); world.cleanup(); } diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/AbstractDataTask.java b/core/src/main/java/net/pl3x/map/core/renderer/task/AbstractDataTask.java new file mode 100644 index 000000000..c81efe7f0 --- /dev/null +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/AbstractDataTask.java @@ -0,0 +1,101 @@ +/* + * MIT License + * + * Copyright (c) 2020-2023 William Blake Galbreath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.pl3x.map.core.renderer.task; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import net.pl3x.map.core.Pl3xMap; +import net.pl3x.map.core.markers.JsonObjectWrapper; +import net.pl3x.map.core.markers.marker.Marker; +import net.pl3x.map.core.scheduler.Task; +import net.pl3x.map.core.world.World; +import org.jetbrains.annotations.NotNull; + +public abstract class AbstractDataTask extends Task { + protected final Gson gson = new GsonBuilder() + //.setPrettyPrinting() + .disableHtmlEscaping() + .serializeNulls() + .setLenient() + .registerTypeHierarchyAdapter(Marker.class, new Adapter()) + .create(); + + protected final World world; + protected final Map<@NotNull String, @NotNull Long> lastUpdated = new HashMap<>(); + private final ExecutorService executor; + + private CompletableFuture future; + private boolean running; + + public AbstractDataTask(int delay, boolean repeat, World world, String serviceName) { + super(delay, repeat); + this.world = world; + this.executor = Pl3xMap.ThreadFactory.createService(serviceName); + } + + @Override + public void run() { + if (this.running) { + return; + } + this.running = true; + this.future = CompletableFuture.runAsync(() -> { + try { + parse(); + } catch (Throwable t) { + t.printStackTrace(); + } + this.running = false; + }, this.executor); + } + + @Override + public void cancel() { + super.cancel(); + if (this.future != null) { + this.future.cancel(true); + } + } + + public abstract void parse(); + + private static class Adapter implements JsonSerializer<@NotNull Marker> { + @Override + public @NotNull JsonElement serialize(@NotNull Marker marker, @NotNull Type type, @NotNull JsonSerializationContext context) { + JsonObjectWrapper wrapper = new JsonObjectWrapper(); + wrapper.addProperty("type", marker.getType()); + wrapper.addProperty("data", marker); + wrapper.addProperty("options", marker.getOptions()); + return wrapper.getJsonObject(); + } + } +} diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java index fea6d7d27..b7fbdce01 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java @@ -23,74 +23,21 @@ */ package net.pl3x.map.core.renderer.task; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonElement; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; -import java.lang.reflect.Type; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import net.pl3x.map.core.Pl3xMap; -import net.pl3x.map.core.markers.JsonObjectWrapper; import net.pl3x.map.core.markers.layer.Layer; import net.pl3x.map.core.markers.marker.Marker; -import net.pl3x.map.core.scheduler.Task; import net.pl3x.map.core.util.FileUtil; import net.pl3x.map.core.world.World; import org.jetbrains.annotations.NotNull; -public class UpdateMarkerData extends Task { - private final Gson gson = new GsonBuilder() - //.setPrettyPrinting() - .disableHtmlEscaping() - .serializeNulls() - .setLenient() - .registerTypeHierarchyAdapter(Marker.class, new Adapter()) - .create(); - - private final World world; - private final Map<@NotNull String, @NotNull Long> lastUpdated = new HashMap<>(); - private final ExecutorService executor; - - private CompletableFuture future; - private boolean running; - +public class UpdateMarkerData extends AbstractDataTask { public UpdateMarkerData(@NotNull World world) { - super(1 * 20, true); - this.world = world; - this.executor = Pl3xMap.ThreadFactory.createService("Pl3xMap-Markers"); - } - - @Override - public void run() { - if (this.running) { - return; - } - this.running = true; - this.future = CompletableFuture.runAsync(() -> { - try { - parseLayers(); - } catch (Throwable t) { - t.printStackTrace(); - } - this.running = false; - }, this.executor); + super(1 * 20, true, world, "Pl3xMap-Markers"); } @Override - public void cancel() { - super.cancel(); - if (this.future != null) { - this.future.cancel(true); - } - } - - private void parseLayers() { + public void parse() { List layers = new ArrayList<>(); this.world.getLayerRegistry().entrySet().forEach(entry -> { @@ -114,15 +61,4 @@ private void parseLayers() { FileUtil.writeJson(this.gson.toJson(layers), this.world.getTilesDirectory().resolve("markers.json")); } - - private static class Adapter implements JsonSerializer<@NotNull Marker> { - @Override - public @NotNull JsonElement serialize(@NotNull Marker marker, @NotNull Type type, @NotNull JsonSerializationContext context) { - JsonObjectWrapper wrapper = new JsonObjectWrapper(); - wrapper.addProperty("type", marker.getType()); - wrapper.addProperty("data", marker); - wrapper.addProperty("options", marker.getOptions()); - return wrapper.getJsonObject(); - } - } } diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSSEEvents.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSSEEvents.java new file mode 100644 index 000000000..835da3bf9 --- /dev/null +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSSEEvents.java @@ -0,0 +1,30 @@ +package net.pl3x.map.core.renderer.task; + +import java.util.ArrayList; +import java.util.List; +import net.pl3x.map.core.Pl3xMap; +import net.pl3x.map.core.configuration.Config; +import net.pl3x.map.core.httpd.HttpdServer; +import net.pl3x.map.core.markers.layer.Layer; +import net.pl3x.map.core.markers.marker.Marker; +import net.pl3x.map.core.world.World; + +public class UpdateSSEEvents extends AbstractDataTask { + public UpdateSSEEvents(World world) { + super(0, true, world, "Pl3xMap-SSE-Events"); + } + + @Override + public void parse() { + List layers = new ArrayList<>(); + + this.world.getLayerRegistry().entrySet().forEach(entry -> { + String key = entry.getKey(); + Layer layer = entry.getValue(); + List> list = new ArrayList<>(layer.getMarkers()); + HttpdServer.sendSSE("markers", String.format("{ \"world\": \"%s\", \"key\": \"%s\", \"markers\": %s}", this.world.getName(), key, this.gson.toJson(list))); + }); + + HttpdServer.sendSSE("players", this.gson.toJson(Pl3xMap.api().getPlayerRegistry().parsePlayers())); + } +} diff --git a/core/src/main/java/net/pl3x/map/core/world/World.java b/core/src/main/java/net/pl3x/map/core/world/World.java index 27f53e2f3..b5db5a9f0 100644 --- a/core/src/main/java/net/pl3x/map/core/world/World.java +++ b/core/src/main/java/net/pl3x/map/core/world/World.java @@ -41,6 +41,7 @@ import javax.imageio.ImageIO; import net.pl3x.map.core.Keyed; import net.pl3x.map.core.Pl3xMap; +import net.pl3x.map.core.configuration.Config; import net.pl3x.map.core.configuration.PlayersLayerConfig; import net.pl3x.map.core.configuration.SpawnLayerConfig; import net.pl3x.map.core.configuration.WorldBorderLayerConfig; @@ -59,6 +60,7 @@ import net.pl3x.map.core.registry.Registry; import net.pl3x.map.core.renderer.Renderer; import net.pl3x.map.core.renderer.task.UpdateMarkerData; +import net.pl3x.map.core.renderer.task.UpdateSSEEvents; import net.pl3x.map.core.util.FileUtil; import net.pl3x.map.core.util.Mathf; import org.jetbrains.annotations.NotNull; @@ -87,6 +89,7 @@ public abstract class World extends Keyed { private final RegionModifiedState regionModifiedState; //private final RegionFileWatcher regionFileWatcher; private final UpdateMarkerData markerTask; + private final UpdateSSEEvents sseTask; private final Map<@NotNull String, Renderer.@NotNull Builder> renderers = new LinkedHashMap<>(); public World(@NotNull String name, long seed, @NotNull Point spawn, @NotNull Type type, @NotNull Path regionDirectory) { @@ -122,6 +125,7 @@ public World(@NotNull String name, long seed, @NotNull Point spawn, @NotNull Typ this.regionModifiedState = new RegionModifiedState(this); //this.regionFileWatcher = new RegionFileWatcher(this); this.markerTask = new UpdateMarkerData(this); + this.sseTask = new UpdateSSEEvents(this); } protected void init() { @@ -170,6 +174,9 @@ protected void init() { Logger.debug("Starting marker task"); Pl3xMap.api().getScheduler().addTask(this.markerTask); + Logger.debug("Starting SSE events task"); + Pl3xMap.api().getScheduler().addTask(this.sseTask); + // load up custom markers Logger.debug("Loading custom markers for " + getName()); for (Path file : getCustomMarkerFiles()) { @@ -214,6 +221,10 @@ public void cleanup() { return this.markerTask; } + public @NotNull UpdateSSEEvents getSSETask() { + return this.sseTask; + } + public @NotNull Map<@NotNull String, Renderer.@NotNull Builder> getRenderers() { return Collections.unmodifiableMap(this.renderers); } diff --git a/webmap/src/Pl3xMap.ts b/webmap/src/Pl3xMap.ts index 0a69dd996..4234cc3d6 100644 --- a/webmap/src/Pl3xMap.ts +++ b/webmap/src/Pl3xMap.ts @@ -6,6 +6,7 @@ import {getJSON} from "./util/Util"; import SidebarControl from "./control/SidebarControl"; import Pl3xMapLeafletMap from "./map/Pl3xMapLeafletMap"; import "./scss/styles.scss"; +import {Player} from "./player/Player"; window.onload = function (): void { window.pl3xmap = new Pl3xMap(); @@ -23,6 +24,8 @@ export class Pl3xMap { private readonly _playerManager: PlayerManager; private readonly _worldManager: WorldManager; + private _eventSource: EventSource; + private _langPalette: Map = new Map(); private _settings?: Settings; @@ -33,6 +36,14 @@ export class Pl3xMap { this._map = new Pl3xMapLeafletMap(this); + this._eventSource = this.initSSE(); + + window.addEventListener('beforeunload', function () { + if (Pl3xMap.instance.eventSource != null) { + Pl3xMap.instance.eventSource.close(); + } + }); + this._controlManager = new ControlManager(this); this._playerManager = new PlayerManager(this); this._worldManager = new WorldManager(this); @@ -62,12 +73,44 @@ export class Pl3xMap { private update(): void { getJSON('tiles/settings.json').then((json): void => { this._settings = json as Settings; - this.playerManager.update(this._settings); + + if (Pl3xMap.instance.eventSource.readyState === EventSource.CLOSED) { + this.playerManager.update(this._settings.players); + } this._timer = setTimeout(() => this.update(), 1000); }); } + private initSSE(): EventSource { + const eventSource = new EventSource("sse"); + + eventSource.addEventListener("markers", (ev: Event) => { + const messageEvent = (ev as MessageEvent); + const json: any = JSON.parse(messageEvent.data); + const world = this._worldManager.getWorld(json.world); + const key: string = json.key; + const markers: any[] = json.markers; + + if (world === undefined) return; + + if (json.length === 0) return; + + world.markerLayers.forEach(layer => { + if (layer.key !== key) return; + layer.updateMarkers(markers, world); + }); + }); + + eventSource.addEventListener("players", (ev: Event) => { + const messageEvent = (ev as MessageEvent); + const json: Player[] = JSON.parse(messageEvent.data); + this.playerManager.update(json); + }); + + return eventSource; + } + get map(): Pl3xMapLeafletMap { return this._map; } @@ -84,6 +127,10 @@ export class Pl3xMap { return this._worldManager; } + get eventSource(): EventSource { + return this._eventSource; + } + get langPalette(): Map { return this._langPalette; } diff --git a/webmap/src/layergroup/MarkerLayer.ts b/webmap/src/layergroup/MarkerLayer.ts index 40b2adcef..3c78cc91f 100644 --- a/webmap/src/layergroup/MarkerLayer.ts +++ b/webmap/src/layergroup/MarkerLayer.ts @@ -115,45 +115,51 @@ export class MarkerLayer extends L.LayerGroup { } update(world: World): void { + if (Pl3xMap.instance.eventSource.readyState !== EventSource.CLOSED) { + return; + } + getJSON(`tiles/${world.name}/markers/${this._key}.json`) - .then((json): void => { - //this.clearLayers(); // do not just clear markers, remove the ones that are missing - const toRemove: Set = new Set(this._markers.keys()); - - for (const index in Object.keys(json)) { - const existing: Marker | undefined = this._markers.get(json[index].data.key); - if (existing) { - // update - const data = json[index]; - const options: MarkerOptions | undefined = isset(data.options) ? new MarkerOptions(data.options) : undefined; - existing.update(data.data, options); - // do not remove this marker - toRemove.delete(existing.key); - } else { - // new marker - const marker: Marker | undefined = this.parseMarker(json[index]); - if (marker) { - this._markers.set(marker.key, marker); - marker.marker.addTo(this); - // inform the events - fireCustomEvent('markeradded', marker); - } - } + .then((json): void => this.updateMarkers(json, world)); + } + + updateMarkers(json: any, world: World): void { + //this.clearLayers(); // do not just clear markers, remove the ones that are missing + const toRemove: Set = new Set(this._markers.keys()); + + for (const index in Object.keys(json)) { + const existing: Marker | undefined = this._markers.get(json[index].data.key); + if (existing) { + // update + const data = json[index]; + const options: MarkerOptions | undefined = isset(data.options) ? new MarkerOptions(data.options) : undefined; + existing.update(data.data, options); + // do not remove this marker + toRemove.delete(existing.key); + } else { + // new marker + const marker: Marker | undefined = this.parseMarker(json[index]); + if (marker) { + this._markers.set(marker.key, marker); + marker.marker.addTo(this); + // inform the events + fireCustomEvent('markeradded', marker); } + } + } + + toRemove.forEach((key: string): void => { + // remove players not in updated settings file + const marker: Marker | undefined = this._markers.get(key); + if (marker) { + this._markers.delete(key); + marker.marker.remove(); + this.removeLayer(marker.marker); + fireCustomEvent('markerremoved', marker); + } + }); - toRemove.forEach((key: string): void => { - // remove players not in updated settings file - const marker: Marker | undefined = this._markers.get(key); - if (marker) { - this._markers.delete(key); - marker.marker.remove(); - this.removeLayer(marker.marker); - fireCustomEvent('markerremoved', marker); - } - }); - - this._timer = setTimeout(() => this.update(world), this._updateInterval); - }); + this._timer = setTimeout(() => this.update(world), this._updateInterval); } unload(): void { diff --git a/webmap/src/player/PlayerManager.ts b/webmap/src/player/PlayerManager.ts index 7e2ddfd77..57ffb348b 100644 --- a/webmap/src/player/PlayerManager.ts +++ b/webmap/src/player/PlayerManager.ts @@ -17,10 +17,10 @@ export class PlayerManager { this._pl3xmap = pl3xmap; } - public update(settings: Settings): void { + public update(players: Player[]): void { const toRemove: Set = new Set(this._players.keys()); - settings.players.forEach((data: Player): void => { + players.forEach((data: Player): void => { const existing: Player | undefined = this._players.get(data.uuid); if (existing) { // update existing From f9f0246c576a4517be24797e2814c9b084bff904 Mon Sep 17 00:00:00 2001 From: granny Date: Sat, 21 Oct 2023 23:49:58 -0700 Subject: [PATCH 05/53] add temporary config option --- .../main/java/net/pl3x/map/core/configuration/Config.java | 5 +++++ .../net/pl3x/map/core/renderer/task/UpdateSSEEvents.java | 4 ++++ .../pl3x/map/core/renderer/task/UpdateSettingsData.java | 1 + core/src/main/java/net/pl3x/map/core/world/World.java | 6 ++++-- webmap/src/Pl3xMap.ts | 4 ++++ webmap/src/settings/Settings.ts | 8 +++++++- 6 files changed, 25 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/configuration/Config.java b/core/src/main/java/net/pl3x/map/core/configuration/Config.java index a0c4a2cae..a2e1e6e31 100644 --- a/core/src/main/java/net/pl3x/map/core/configuration/Config.java +++ b/core/src/main/java/net/pl3x/map/core/configuration/Config.java @@ -35,6 +35,11 @@ public final class Config extends AbstractConfig { Extra logger/console output. (can be spammy)""") public static boolean DEBUG_MODE = false; + @Key("settings.use-sse-events") + @Comment(""" + Enable the use of SSE events to make markers update in real time.""") + public static boolean SSE_EVENTS = true; + @Key("settings.language-file") @Comment(""" The language file to use from the locale folder.""") diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSSEEvents.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSSEEvents.java index 835da3bf9..3b85f259a 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSSEEvents.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSSEEvents.java @@ -16,6 +16,10 @@ public UpdateSSEEvents(World world) { @Override public void parse() { + if (!Config.SSE_EVENTS) { + return; + } + List layers = new ArrayList<>(); this.world.getLayerRegistry().entrySet().forEach(entry -> { diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java index 5a6128563..a138cc806 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java @@ -143,6 +143,7 @@ private void parseSettings() { map.put("maxPlayers", Pl3xMap.api().getMaxPlayers()); map.put("lang", lang); map.put("zoom", zoom); + map.put("useSSE", Config.SSE_EVENTS); try { map.put("players", Pl3xMap.api().getPlayerRegistry().parsePlayers()); diff --git a/core/src/main/java/net/pl3x/map/core/world/World.java b/core/src/main/java/net/pl3x/map/core/world/World.java index b5db5a9f0..0006399c5 100644 --- a/core/src/main/java/net/pl3x/map/core/world/World.java +++ b/core/src/main/java/net/pl3x/map/core/world/World.java @@ -174,8 +174,10 @@ protected void init() { Logger.debug("Starting marker task"); Pl3xMap.api().getScheduler().addTask(this.markerTask); - Logger.debug("Starting SSE events task"); - Pl3xMap.api().getScheduler().addTask(this.sseTask); + if (Config.SSE_EVENTS) { + Logger.debug("Starting SSE events task"); + Pl3xMap.api().getScheduler().addTask(this.sseTask); + } // load up custom markers Logger.debug("Loading custom markers for " + getName()); diff --git a/webmap/src/Pl3xMap.ts b/webmap/src/Pl3xMap.ts index 4234cc3d6..4efd265df 100644 --- a/webmap/src/Pl3xMap.ts +++ b/webmap/src/Pl3xMap.ts @@ -74,6 +74,10 @@ export class Pl3xMap { getJSON('tiles/settings.json').then((json): void => { this._settings = json as Settings; + if (!this._settings.useSSE) { + Pl3xMap.instance.eventSource.close(); + } + if (Pl3xMap.instance.eventSource.readyState === EventSource.CLOSED) { this.playerManager.update(this._settings.players); } diff --git a/webmap/src/settings/Settings.ts b/webmap/src/settings/Settings.ts index 7e1e009fa..52a1c1990 100644 --- a/webmap/src/settings/Settings.ts +++ b/webmap/src/settings/Settings.ts @@ -10,14 +10,16 @@ export class Settings { private readonly _maxPlayers: number; private readonly _lang: Lang; private readonly _zoom: Zoom; + private readonly _useSSE: boolean; private readonly _players: Player[]; private readonly _worldSettings: WorldSettings[]; - constructor(format: string, maxPlayers: number, lang: Lang, zoom: Zoom, players: Player[], worldSettings: WorldSettings[]) { + constructor(format: string, maxPlayers: number, lang: Lang, zoom: Zoom, useSSE: boolean, players: Player[], worldSettings: WorldSettings[]) { this._format = format; this._maxPlayers = maxPlayers; this._lang = lang; this._zoom = zoom; + this._useSSE = useSSE; this._players = players; this._worldSettings = worldSettings; } @@ -38,6 +40,10 @@ export class Settings { return this._zoom; } + get useSSE(): boolean { + return this._useSSE; + } + get players(): Player[] { return this._players; } From b158615882e3f1558b4ffcc64395371bdf9528dd Mon Sep 17 00:00:00 2001 From: granny Date: Sun, 22 Oct 2023 03:02:13 -0700 Subject: [PATCH 06/53] check PlayerManager for amount of players instead of settings.json --- webmap/src/sidebar/PlayersTab.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webmap/src/sidebar/PlayersTab.ts b/webmap/src/sidebar/PlayersTab.ts index 565be5f83..637508780 100644 --- a/webmap/src/sidebar/PlayersTab.ts +++ b/webmap/src/sidebar/PlayersTab.ts @@ -67,7 +67,7 @@ export default class PlayersTab extends BaseTab { private _update(): void { const settings: Settings | undefined = this._pl3xmap.settings; - const online: string = String(isset(settings?.players) ? Object.keys(settings!.players).length : '???'); + const online: string = String(this._pl3xmap.playerManager.players.size); const max: string = String(settings?.maxPlayers ?? '???'); const title: any = settings?.lang.players?.label From 1affd7a221edc69aebc2e300c56931962a288e6b Mon Sep 17 00:00:00 2001 From: granny Date: Sun, 22 Oct 2023 03:02:35 -0700 Subject: [PATCH 07/53] don't update url when following player --- webmap/src/control/LinkControl.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/webmap/src/control/LinkControl.ts b/webmap/src/control/LinkControl.ts index dbed4f04e..1f912c142 100644 --- a/webmap/src/control/LinkControl.ts +++ b/webmap/src/control/LinkControl.ts @@ -5,11 +5,16 @@ import {createSVGIcon, toPoint} from "../util/Util"; import Pl3xMapLeafletMap from "../map/Pl3xMapLeafletMap"; import '../svg/link.svg'; import {World} from "../world/World"; +import {Player} from "../player/Player"; export class LinkControl extends ControlBox { private readonly _dom: HTMLAnchorElement; + private _disabled: boolean; private onEvent = (): void => { + if (this._disabled) { + return; + } this.update(); } @@ -17,6 +22,10 @@ export class LinkControl extends ControlBox { super(pl3xmap, position); this._dom = L.DomUtil.create('a', 'leaflet-control leaflet-control-button leaflet-control-link'); this._dom.appendChild(createSVGIcon('link')); + this._disabled = false; + addEventListener('followplayer', (e: CustomEvent): void => { + this._disabled = !(e.detail == undefined); // e.detail returns "null" even though it's being set to "undefined" + }); } onAdd(map: Pl3xMapLeafletMap): HTMLAnchorElement { From b8801a52a0d299c74155902c4687eca80b11fb9a Mon Sep 17 00:00:00 2001 From: granny Date: Sun, 22 Oct 2023 03:04:03 -0700 Subject: [PATCH 08/53] initialize SSE after everything else loads --- webmap/src/Pl3xMap.ts | 17 ++++++++--------- webmap/src/layergroup/MarkerLayer.ts | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/webmap/src/Pl3xMap.ts b/webmap/src/Pl3xMap.ts index 4efd265df..90f921402 100644 --- a/webmap/src/Pl3xMap.ts +++ b/webmap/src/Pl3xMap.ts @@ -24,7 +24,7 @@ export class Pl3xMap { private readonly _playerManager: PlayerManager; private readonly _worldManager: WorldManager; - private _eventSource: EventSource; + private _eventSource?: EventSource; private _langPalette: Map = new Map(); private _settings?: Settings; @@ -35,11 +35,9 @@ export class Pl3xMap { Pl3xMap._instance = this; this._map = new Pl3xMapLeafletMap(this); - - this._eventSource = this.initSSE(); - + window.addEventListener('beforeunload', function () { - if (Pl3xMap.instance.eventSource != null) { + if (Pl3xMap.instance.eventSource != undefined) { Pl3xMap.instance.eventSource.close(); } }); @@ -61,6 +59,7 @@ export class Pl3xMap { }); this.controlManager.sidebarControl = new SidebarControl(this); const promise: Promise = this.worldManager.init(this._settings); + this._eventSource = this.initSSE(); this.update(); return promise; }); @@ -71,14 +70,14 @@ export class Pl3xMap { } private update(): void { - getJSON('tiles/settings.json').then((json): void => { + getJSON('tiles/settings.json').then( (json): void => { this._settings = json as Settings; if (!this._settings.useSSE) { - Pl3xMap.instance.eventSource.close(); + this.eventSource?.close(); } - if (Pl3xMap.instance.eventSource.readyState === EventSource.CLOSED) { + if (this.eventSource === undefined || this.eventSource.readyState === EventSource.CLOSED) { this.playerManager.update(this._settings.players); } @@ -131,7 +130,7 @@ export class Pl3xMap { return this._worldManager; } - get eventSource(): EventSource { + get eventSource(): EventSource | undefined { return this._eventSource; } diff --git a/webmap/src/layergroup/MarkerLayer.ts b/webmap/src/layergroup/MarkerLayer.ts index 3c78cc91f..aeaf6a53c 100644 --- a/webmap/src/layergroup/MarkerLayer.ts +++ b/webmap/src/layergroup/MarkerLayer.ts @@ -115,7 +115,7 @@ export class MarkerLayer extends L.LayerGroup { } update(world: World): void { - if (Pl3xMap.instance.eventSource.readyState !== EventSource.CLOSED) { + if (Pl3xMap.instance.eventSource !== undefined && Pl3xMap.instance.eventSource.readyState !== EventSource.CLOSED) { return; } From 77ff796c9f9e4d7311814b1092035477c4b2192e Mon Sep 17 00:00:00 2001 From: granny Date: Fri, 22 Dec 2023 06:32:16 -0800 Subject: [PATCH 09/53] close all SSE connections when stopping web server --- .../src/main/java/net/pl3x/map/core/httpd/HttpdServer.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java b/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java index c1ed113f2..14c2b97a2 100644 --- a/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java +++ b/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java @@ -58,6 +58,12 @@ public static void sendSSE(String data) { sendSSE(null, data); } + public static void closeSSEConnections() { + for (ServerSentEventConnection connection : serverSentEventHandler.getConnections()) { + connection.shutdown(); + } + } + public void startServer() { if (!Config.HTTPD_ENABLED) { Logger.info(Lang.HTTPD_DISABLED); @@ -134,6 +140,7 @@ public void stopServer() { } LogFilter.HIDE_UNDERTOW_LOGS = true; + this.closeSSEConnections(); this.server.stop(); LogFilter.HIDE_UNDERTOW_LOGS = false; From a9975c2576079d75e5f29f9fda3ac2ae438fcb2a Mon Sep 17 00:00:00 2001 From: granny Date: Fri, 22 Dec 2023 20:46:27 -0800 Subject: [PATCH 10/53] stop static abusing --- .../main/java/net/pl3x/map/core/httpd/HttpdServer.java | 8 ++++---- .../net/pl3x/map/core/renderer/task/UpdateSSEEvents.java | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java b/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java index 14c2b97a2..8a7e369e4 100644 --- a/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java +++ b/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java @@ -46,19 +46,19 @@ public class HttpdServer { private Undertow server; - private static ServerSentEventHandler serverSentEventHandler = Handlers.serverSentEvents(); + private ServerSentEventHandler serverSentEventHandler = Handlers.serverSentEvents(); - public static void sendSSE(String event, String data) { + public void sendSSE(String event, String data) { for (ServerSentEventConnection connection : serverSentEventHandler.getConnections()) { connection.send(data, event, null, null); } } - public static void sendSSE(String data) { + public void sendSSE(String data) { sendSSE(null, data); } - public static void closeSSEConnections() { + public void closeSSEConnections() { for (ServerSentEventConnection connection : serverSentEventHandler.getConnections()) { connection.shutdown(); } diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSSEEvents.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSSEEvents.java index 3b85f259a..926cd7f2b 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSSEEvents.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSSEEvents.java @@ -26,9 +26,9 @@ public void parse() { String key = entry.getKey(); Layer layer = entry.getValue(); List> list = new ArrayList<>(layer.getMarkers()); - HttpdServer.sendSSE("markers", String.format("{ \"world\": \"%s\", \"key\": \"%s\", \"markers\": %s}", this.world.getName(), key, this.gson.toJson(list))); + Pl3xMap.api().getHttpdServer().sendSSE("markers", String.format("{ \"world\": \"%s\", \"key\": \"%s\", \"markers\": %s}", this.world.getName(), key, this.gson.toJson(list))); }); - HttpdServer.sendSSE("players", this.gson.toJson(Pl3xMap.api().getPlayerRegistry().parsePlayers())); + Pl3xMap.api().getHttpdServer().sendSSE("players", this.gson.toJson(Pl3xMap.api().getPlayerRegistry().parsePlayers())); } } From 93042344bf7f6acd3233ffde32416be91f68116a Mon Sep 17 00:00:00 2001 From: granny Date: Fri, 22 Dec 2023 22:50:43 -0800 Subject: [PATCH 11/53] continue returning interval as seconds --- .../pl3x/map/core/markers/layer/Layer.java | 11 +++--- .../map/core/markers/layer/SpawnLayer.java | 3 +- .../core/markers/layer/WorldBorderLayer.java | 3 +- .../core/renderer/task/UpdateMarkerData.java | 3 +- .../renderer/task/UpdateSettingsData.java | 4 ++- .../pl3x/map/core/scheduler/Scheduler.java | 9 ++--- .../java/net/pl3x/map/core/util/TickUtil.java | 34 +++++++++++++++++++ .../java/net/pl3x/map/core/world/World.java | 1 - .../fabric/client/manager/TileManager.java | 3 +- 9 files changed, 56 insertions(+), 15 deletions(-) create mode 100644 core/src/main/java/net/pl3x/map/core/util/TickUtil.java diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java index ccc45d553..d201f5172 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java @@ -32,6 +32,7 @@ import net.pl3x.map.core.markers.JsonSerializable; import net.pl3x.map.core.markers.marker.Marker; import net.pl3x.map.core.util.Preconditions; +import net.pl3x.map.core.util.TickUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -41,7 +42,7 @@ @SuppressWarnings("UnusedReturnValue") public abstract class Layer extends Keyed implements JsonSerializable { private Supplier<@NotNull String> labelSupplier; - private int updateInterval = 15 * 20; + private int updateInterval = TickUtil.toTicks(15); private boolean showControls = true; private boolean defaultHidden = false; private int priority = 99; @@ -93,22 +94,22 @@ public Layer(@NotNull String key, @NotNull Supplier<@NotNull String> labelSuppli } /** - * Get this layer's update interval (in ticks). + * Get this layer's update interval (in seconds). * * @return update interval */ public int getUpdateInterval() { - return this.updateInterval; + return TickUtil.toSeconds(this.updateInterval); } /** - * Set this layer's update interval (in ticks). + * Set this layer's update interval (in seconds). * * @param updateInterval new update interval * @return this layer */ public @NotNull Layer setUpdateInterval(int updateInterval) { - this.updateInterval = updateInterval; + this.updateInterval = TickUtil.toTicks(updateInterval); return this; } diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java index e1405a625..b9203527b 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java @@ -36,6 +36,7 @@ import net.pl3x.map.core.markers.option.Options; import net.pl3x.map.core.markers.option.Tooltip; import net.pl3x.map.core.util.FileUtil; +import net.pl3x.map.core.util.TickUtil; import net.pl3x.map.core.world.World; import org.jetbrains.annotations.NotNull; @@ -65,7 +66,7 @@ public SpawnLayer(@NotNull World world) { throw new RuntimeException(e); } - setUpdateInterval(SpawnLayerConfig.UPDATE_INTERVAL * 20); + setUpdateInterval(TickUtil.toTicks(SpawnLayerConfig.UPDATE_INTERVAL)); setShowControls(SpawnLayerConfig.SHOW_CONTROLS); setDefaultHidden(SpawnLayerConfig.DEFAULT_HIDDEN); setPriority(SpawnLayerConfig.PRIORITY); diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java index 6f256b7a6..39cddf59a 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java @@ -34,6 +34,7 @@ import net.pl3x.map.core.markers.option.Options; import net.pl3x.map.core.markers.option.Tooltip; import net.pl3x.map.core.util.Colors; +import net.pl3x.map.core.util.TickUtil; import net.pl3x.map.core.world.World; import org.jetbrains.annotations.NotNull; @@ -52,7 +53,7 @@ public class WorldBorderLayer extends WorldLayer { */ public WorldBorderLayer(@NotNull World world) { this(KEY, world, () -> Lang.UI_LAYER_WORLDBORDER); - setUpdateInterval(WorldBorderLayerConfig.UPDATE_INTERVAL * 20); + setUpdateInterval(TickUtil.toTicks(WorldBorderLayerConfig.UPDATE_INTERVAL)); setShowControls(WorldBorderLayerConfig.SHOW_CONTROLS); setDefaultHidden(WorldBorderLayerConfig.DEFAULT_HIDDEN); setPriority(WorldBorderLayerConfig.PRIORITY); diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java index b7fbdce01..7cb6a1b55 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java @@ -28,12 +28,13 @@ import net.pl3x.map.core.markers.layer.Layer; import net.pl3x.map.core.markers.marker.Marker; import net.pl3x.map.core.util.FileUtil; +import net.pl3x.map.core.util.TickUtil; import net.pl3x.map.core.world.World; import org.jetbrains.annotations.NotNull; public class UpdateMarkerData extends AbstractDataTask { public UpdateMarkerData(@NotNull World world) { - super(1 * 20, true, world, "Pl3xMap-Markers"); + super(TickUtil.toTicks(1), true, world, "Pl3xMap-Markers"); } @Override diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java index a138cc806..767bc64ba 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java @@ -40,6 +40,7 @@ import net.pl3x.map.core.markers.Point; import net.pl3x.map.core.scheduler.Task; import net.pl3x.map.core.util.FileUtil; +import net.pl3x.map.core.util.TickUtil; import net.pl3x.map.core.world.World; import org.jetbrains.annotations.NotNull; @@ -52,7 +53,7 @@ public class UpdateSettingsData extends Task { .create(); public UpdateSettingsData() { - super(1 * 20, true); + super(TickUtil.toTicks(1), true); } @Override @@ -152,6 +153,7 @@ private void parseSettings() { t.printStackTrace(); } + Pl3xMap.api().getHttpdServer().sendSSE("settings", this.gson.toJson(map)); FileUtil.writeJson(this.gson.toJson(map), FileUtil.getTilesDir().resolve("settings.json")); } } diff --git a/core/src/main/java/net/pl3x/map/core/scheduler/Scheduler.java b/core/src/main/java/net/pl3x/map/core/scheduler/Scheduler.java index 71eb0536e..80d2578d8 100644 --- a/core/src/main/java/net/pl3x/map/core/scheduler/Scheduler.java +++ b/core/src/main/java/net/pl3x/map/core/scheduler/Scheduler.java @@ -26,6 +26,7 @@ import java.util.Iterator; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; +import net.pl3x.map.core.util.TickUtil; import org.jetbrains.annotations.NotNull; public class Scheduler { @@ -88,7 +89,7 @@ public void addTask(@NotNull Task task) { /** * Add task to the scheduler. * - * @param delay Delay (in ticks) before task starts + * @param delay Delay (in seconds) before task starts * @param runnable Task to add */ public void addTask(int delay, @NotNull Runnable runnable) { @@ -98,12 +99,12 @@ public void addTask(int delay, @NotNull Runnable runnable) { /** * Add task to the scheduler. * - * @param delay Delay (in ticks) before task starts - * @param repeat Delay (in ticks) before task repeats + * @param delay Delay (in seconds) before task starts + * @param repeat Delay (in seconds) before task repeats * @param runnable Task to add */ public void addTask(int delay, boolean repeat, @NotNull Runnable runnable) { - addTask(new Task(delay, repeat) { + addTask(new Task(TickUtil.toTicks(delay), repeat) { @Override public void run() { runnable.run(); diff --git a/core/src/main/java/net/pl3x/map/core/util/TickUtil.java b/core/src/main/java/net/pl3x/map/core/util/TickUtil.java new file mode 100644 index 000000000..8aedc8551 --- /dev/null +++ b/core/src/main/java/net/pl3x/map/core/util/TickUtil.java @@ -0,0 +1,34 @@ +/* + * MIT License + * + * Copyright (c) 2020-2023 William Blake Galbreath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.pl3x.map.core.util; + +public class TickUtil { + public static int toSeconds(int ticks) { + return (int) (0.05 * ticks); + } + + public static int toTicks(int seconds) { + return seconds * 20; + } +} diff --git a/core/src/main/java/net/pl3x/map/core/world/World.java b/core/src/main/java/net/pl3x/map/core/world/World.java index 0006399c5..e8818aa2f 100644 --- a/core/src/main/java/net/pl3x/map/core/world/World.java +++ b/core/src/main/java/net/pl3x/map/core/world/World.java @@ -60,7 +60,6 @@ import net.pl3x.map.core.registry.Registry; import net.pl3x.map.core.renderer.Renderer; import net.pl3x.map.core.renderer.task.UpdateMarkerData; -import net.pl3x.map.core.renderer.task.UpdateSSEEvents; import net.pl3x.map.core.util.FileUtil; import net.pl3x.map.core.util.Mathf; import org.jetbrains.annotations.NotNull; diff --git a/fabric/src/main/java/net/pl3x/map/fabric/client/manager/TileManager.java b/fabric/src/main/java/net/pl3x/map/fabric/client/manager/TileManager.java index e4ac78751..97a0e0048 100644 --- a/fabric/src/main/java/net/pl3x/map/fabric/client/manager/TileManager.java +++ b/fabric/src/main/java/net/pl3x/map/fabric/client/manager/TileManager.java @@ -37,6 +37,7 @@ import javax.imageio.ImageIO; import net.pl3x.map.core.scheduler.Task; import net.pl3x.map.core.util.Mathf; +import net.pl3x.map.core.util.TickUtil; import net.pl3x.map.fabric.client.Pl3xMapFabricClient; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; @@ -64,7 +65,7 @@ public void initialize() { // update once next tick this.mod.getScheduler().addTask(0, this::update); // setup repeating task to update every 5 seconds - this.task = new Task(5 * 20, true) { + this.task = new Task(TickUtil.toTicks(5), true) { @Override public void run() { update(); From 7394f2d664462611ec60d0097f23ce0aca65ac79 Mon Sep 17 00:00:00 2001 From: granny Date: Sat, 23 Dec 2023 00:23:15 -0800 Subject: [PATCH 12/53] merge sse task into marker task --- .../pl3x/map/core/configuration/Config.java | 5 - .../pl3x/map/core/markers/layer/Layer.java | 22 ++++ .../pl3x/map/core/registry/WorldRegistry.java | 1 - .../core/renderer/task/AbstractDataTask.java | 101 ------------------ .../core/renderer/task/UpdateMarkerData.java | 80 +++++++++++++- .../core/renderer/task/UpdateSSEEvents.java | 34 ------ .../renderer/task/UpdateSettingsData.java | 1 - .../java/net/pl3x/map/core/world/World.java | 11 -- webmap/src/Pl3xMap.ts | 11 +- webmap/src/settings/Settings.ts | 8 +- 10 files changed, 103 insertions(+), 171 deletions(-) delete mode 100644 core/src/main/java/net/pl3x/map/core/renderer/task/AbstractDataTask.java delete mode 100644 core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSSEEvents.java diff --git a/core/src/main/java/net/pl3x/map/core/configuration/Config.java b/core/src/main/java/net/pl3x/map/core/configuration/Config.java index a2e1e6e31..a0c4a2cae 100644 --- a/core/src/main/java/net/pl3x/map/core/configuration/Config.java +++ b/core/src/main/java/net/pl3x/map/core/configuration/Config.java @@ -35,11 +35,6 @@ public final class Config extends AbstractConfig { Extra logger/console output. (can be spammy)""") public static boolean DEBUG_MODE = false; - @Key("settings.use-sse-events") - @Comment(""" - Enable the use of SSE events to make markers update in real time.""") - public static boolean SSE_EVENTS = true; - @Key("settings.language-file") @Comment(""" The language file to use from the locale folder.""") diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java index d201f5172..2a4b95b9a 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java @@ -43,6 +43,7 @@ public abstract class Layer extends Keyed implements JsonSerializable { private Supplier<@NotNull String> labelSupplier; private int updateInterval = TickUtil.toTicks(15); + private int sseUpdateInterval = 0; private boolean showControls = true; private boolean defaultHidden = false; private int priority = 99; @@ -113,6 +114,27 @@ public int getUpdateInterval() { return this; } + + /** + * Get this layer's update interval (in ticks). + * + * @return update interval + */ + public int getSseUpdateInterval() { + return this.sseUpdateInterval; + } + + /** + * Set this layer's update interval (in ticks). + * + * @param sseUpdateInterval new update interval + * @return this layer + */ + public @NotNull Layer setSseUpdateInterval(int sseUpdateInterval) { + this.sseUpdateInterval = sseUpdateInterval; + return this; + } + /** * Get whether to show this layer in the control box. * diff --git a/core/src/main/java/net/pl3x/map/core/registry/WorldRegistry.java b/core/src/main/java/net/pl3x/map/core/registry/WorldRegistry.java index 218756c95..a1c58694e 100644 --- a/core/src/main/java/net/pl3x/map/core/registry/WorldRegistry.java +++ b/core/src/main/java/net/pl3x/map/core/registry/WorldRegistry.java @@ -46,7 +46,6 @@ public class WorldRegistry extends Registry<@NotNull World> { if (world != null) { Pl3xMap.api().getEventRegistry().callEvent(new WorldUnloadedEvent(world)); world.getMarkerTask().cancel(); - world.getSSETask().cancel(); //world.getRegionFileWatcher().stop(); world.cleanup(); } diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/AbstractDataTask.java b/core/src/main/java/net/pl3x/map/core/renderer/task/AbstractDataTask.java deleted file mode 100644 index c81efe7f0..000000000 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/AbstractDataTask.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2020-2023 William Blake Galbreath - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package net.pl3x.map.core.renderer.task; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonElement; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; -import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import net.pl3x.map.core.Pl3xMap; -import net.pl3x.map.core.markers.JsonObjectWrapper; -import net.pl3x.map.core.markers.marker.Marker; -import net.pl3x.map.core.scheduler.Task; -import net.pl3x.map.core.world.World; -import org.jetbrains.annotations.NotNull; - -public abstract class AbstractDataTask extends Task { - protected final Gson gson = new GsonBuilder() - //.setPrettyPrinting() - .disableHtmlEscaping() - .serializeNulls() - .setLenient() - .registerTypeHierarchyAdapter(Marker.class, new Adapter()) - .create(); - - protected final World world; - protected final Map<@NotNull String, @NotNull Long> lastUpdated = new HashMap<>(); - private final ExecutorService executor; - - private CompletableFuture future; - private boolean running; - - public AbstractDataTask(int delay, boolean repeat, World world, String serviceName) { - super(delay, repeat); - this.world = world; - this.executor = Pl3xMap.ThreadFactory.createService(serviceName); - } - - @Override - public void run() { - if (this.running) { - return; - } - this.running = true; - this.future = CompletableFuture.runAsync(() -> { - try { - parse(); - } catch (Throwable t) { - t.printStackTrace(); - } - this.running = false; - }, this.executor); - } - - @Override - public void cancel() { - super.cancel(); - if (this.future != null) { - this.future.cancel(true); - } - } - - public abstract void parse(); - - private static class Adapter implements JsonSerializer<@NotNull Marker> { - @Override - public @NotNull JsonElement serialize(@NotNull Marker marker, @NotNull Type type, @NotNull JsonSerializationContext context) { - JsonObjectWrapper wrapper = new JsonObjectWrapper(); - wrapper.addProperty("type", marker.getType()); - wrapper.addProperty("data", marker); - wrapper.addProperty("options", marker.getOptions()); - return wrapper.getJsonObject(); - } - } -} diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java index 7cb6a1b55..f647f6940 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java @@ -23,22 +23,76 @@ */ package net.pl3x.map.core.renderer.task; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import java.lang.reflect.Type; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import net.pl3x.map.core.Pl3xMap; +import net.pl3x.map.core.markers.JsonObjectWrapper; import net.pl3x.map.core.markers.layer.Layer; import net.pl3x.map.core.markers.marker.Marker; +import net.pl3x.map.core.scheduler.Task; import net.pl3x.map.core.util.FileUtil; import net.pl3x.map.core.util.TickUtil; import net.pl3x.map.core.world.World; import org.jetbrains.annotations.NotNull; -public class UpdateMarkerData extends AbstractDataTask { +public class UpdateMarkerData extends Task { + protected final Gson gson = new GsonBuilder() + //.setPrettyPrinting() + .disableHtmlEscaping() + .serializeNulls() + .setLenient() + .registerTypeHierarchyAdapter(Marker.class, new Adapter()) + .create(); + + protected final World world; + protected final Map<@NotNull String, @NotNull Long> lastUpdated = new HashMap<>(); + protected final Map<@NotNull String, @NotNull Long> lastUpdatedSSE = new HashMap<>(); + private final ExecutorService executor; + + private CompletableFuture future; + private boolean running; + public UpdateMarkerData(@NotNull World world) { - super(TickUtil.toTicks(1), true, world, "Pl3xMap-Markers"); + super(TickUtil.toTicks(1), true); + this.world = world; + this.executor = Pl3xMap.ThreadFactory.createService("Pl3xMap-Markers"); } @Override - public void parse() { + public void run() { + if (this.running) { + return; + } + this.running = true; + this.future = CompletableFuture.runAsync(() -> { + try { + parseLayers(); + } catch (Throwable t) { + t.printStackTrace(); + } + this.running = false; + }, this.executor); + } + + @Override + public void cancel() { + super.cancel(); + if (this.future != null) { + this.future.cancel(true); + } + } + + private void parseLayers() { List layers = new ArrayList<>(); this.world.getLayerRegistry().entrySet().forEach(entry -> { @@ -49,9 +103,16 @@ public void parse() { long now = System.currentTimeMillis() / 1000; long lastUpdate = this.lastUpdated.getOrDefault(key, 0L); + long lastUpdateSSE = this.lastUpdatedSSE.getOrDefault(key, 0L); + List> list = null; + if (now - lastUpdateSSE >= TickUtil.toSeconds(layer.getSseUpdateInterval())) { // TODO: this is bad + list = list == null ? new ArrayList<>(layer.getMarkers()) : list; + Pl3xMap.api().getHttpdServer().sendSSE("markers", String.format("{ \"world\": \"%s\", \"key\": \"%s\", \"markers\": %s}", this.world.getName(), key, this.gson.toJson(list))); + this.lastUpdatedSSE.put(key, now); + } if (now - lastUpdate > layer.getUpdateInterval()) { - List> list = new ArrayList<>(layer.getMarkers()); + list = list == null ? new ArrayList<>(layer.getMarkers()) : list; FileUtil.writeJson(this.gson.toJson(list), this.world.getMarkersDirectory().resolve(key.replace(":", "-") + ".json")); this.lastUpdated.put(key, now); } @@ -62,4 +123,15 @@ public void parse() { FileUtil.writeJson(this.gson.toJson(layers), this.world.getTilesDirectory().resolve("markers.json")); } + + private static class Adapter implements JsonSerializer<@NotNull Marker> { + @Override + public @NotNull JsonElement serialize(@NotNull Marker marker, @NotNull Type type, @NotNull JsonSerializationContext context) { + JsonObjectWrapper wrapper = new JsonObjectWrapper(); + wrapper.addProperty("type", marker.getType()); + wrapper.addProperty("data", marker); + wrapper.addProperty("options", marker.getOptions()); + return wrapper.getJsonObject(); + } + } } diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSSEEvents.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSSEEvents.java deleted file mode 100644 index 926cd7f2b..000000000 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSSEEvents.java +++ /dev/null @@ -1,34 +0,0 @@ -package net.pl3x.map.core.renderer.task; - -import java.util.ArrayList; -import java.util.List; -import net.pl3x.map.core.Pl3xMap; -import net.pl3x.map.core.configuration.Config; -import net.pl3x.map.core.httpd.HttpdServer; -import net.pl3x.map.core.markers.layer.Layer; -import net.pl3x.map.core.markers.marker.Marker; -import net.pl3x.map.core.world.World; - -public class UpdateSSEEvents extends AbstractDataTask { - public UpdateSSEEvents(World world) { - super(0, true, world, "Pl3xMap-SSE-Events"); - } - - @Override - public void parse() { - if (!Config.SSE_EVENTS) { - return; - } - - List layers = new ArrayList<>(); - - this.world.getLayerRegistry().entrySet().forEach(entry -> { - String key = entry.getKey(); - Layer layer = entry.getValue(); - List> list = new ArrayList<>(layer.getMarkers()); - Pl3xMap.api().getHttpdServer().sendSSE("markers", String.format("{ \"world\": \"%s\", \"key\": \"%s\", \"markers\": %s}", this.world.getName(), key, this.gson.toJson(list))); - }); - - Pl3xMap.api().getHttpdServer().sendSSE("players", this.gson.toJson(Pl3xMap.api().getPlayerRegistry().parsePlayers())); - } -} diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java index 767bc64ba..e48af48dd 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java @@ -144,7 +144,6 @@ private void parseSettings() { map.put("maxPlayers", Pl3xMap.api().getMaxPlayers()); map.put("lang", lang); map.put("zoom", zoom); - map.put("useSSE", Config.SSE_EVENTS); try { map.put("players", Pl3xMap.api().getPlayerRegistry().parsePlayers()); diff --git a/core/src/main/java/net/pl3x/map/core/world/World.java b/core/src/main/java/net/pl3x/map/core/world/World.java index e8818aa2f..f3eeace5c 100644 --- a/core/src/main/java/net/pl3x/map/core/world/World.java +++ b/core/src/main/java/net/pl3x/map/core/world/World.java @@ -88,7 +88,6 @@ public abstract class World extends Keyed { private final RegionModifiedState regionModifiedState; //private final RegionFileWatcher regionFileWatcher; private final UpdateMarkerData markerTask; - private final UpdateSSEEvents sseTask; private final Map<@NotNull String, Renderer.@NotNull Builder> renderers = new LinkedHashMap<>(); public World(@NotNull String name, long seed, @NotNull Point spawn, @NotNull Type type, @NotNull Path regionDirectory) { @@ -124,7 +123,6 @@ public World(@NotNull String name, long seed, @NotNull Point spawn, @NotNull Typ this.regionModifiedState = new RegionModifiedState(this); //this.regionFileWatcher = new RegionFileWatcher(this); this.markerTask = new UpdateMarkerData(this); - this.sseTask = new UpdateSSEEvents(this); } protected void init() { @@ -173,11 +171,6 @@ protected void init() { Logger.debug("Starting marker task"); Pl3xMap.api().getScheduler().addTask(this.markerTask); - if (Config.SSE_EVENTS) { - Logger.debug("Starting SSE events task"); - Pl3xMap.api().getScheduler().addTask(this.sseTask); - } - // load up custom markers Logger.debug("Loading custom markers for " + getName()); for (Path file : getCustomMarkerFiles()) { @@ -222,10 +215,6 @@ public void cleanup() { return this.markerTask; } - public @NotNull UpdateSSEEvents getSSETask() { - return this.sseTask; - } - public @NotNull Map<@NotNull String, Renderer.@NotNull Builder> getRenderers() { return Collections.unmodifiableMap(this.renderers); } diff --git a/webmap/src/Pl3xMap.ts b/webmap/src/Pl3xMap.ts index 90f921402..6d4146032 100644 --- a/webmap/src/Pl3xMap.ts +++ b/webmap/src/Pl3xMap.ts @@ -73,10 +73,6 @@ export class Pl3xMap { getJSON('tiles/settings.json').then( (json): void => { this._settings = json as Settings; - if (!this._settings.useSSE) { - this.eventSource?.close(); - } - if (this.eventSource === undefined || this.eventSource.readyState === EventSource.CLOSED) { this.playerManager.update(this._settings.players); } @@ -105,10 +101,11 @@ export class Pl3xMap { }); }); - eventSource.addEventListener("players", (ev: Event) => { + eventSource.addEventListener("settings", (ev: Event) => { const messageEvent = (ev as MessageEvent); - const json: Player[] = JSON.parse(messageEvent.data); - this.playerManager.update(json); + const json: any = JSON.parse(messageEvent.data); + this._settings = json as Settings; + this.playerManager.update(this._settings.players); }); return eventSource; diff --git a/webmap/src/settings/Settings.ts b/webmap/src/settings/Settings.ts index 52a1c1990..7e1e009fa 100644 --- a/webmap/src/settings/Settings.ts +++ b/webmap/src/settings/Settings.ts @@ -10,16 +10,14 @@ export class Settings { private readonly _maxPlayers: number; private readonly _lang: Lang; private readonly _zoom: Zoom; - private readonly _useSSE: boolean; private readonly _players: Player[]; private readonly _worldSettings: WorldSettings[]; - constructor(format: string, maxPlayers: number, lang: Lang, zoom: Zoom, useSSE: boolean, players: Player[], worldSettings: WorldSettings[]) { + constructor(format: string, maxPlayers: number, lang: Lang, zoom: Zoom, players: Player[], worldSettings: WorldSettings[]) { this._format = format; this._maxPlayers = maxPlayers; this._lang = lang; this._zoom = zoom; - this._useSSE = useSSE; this._players = players; this._worldSettings = worldSettings; } @@ -40,10 +38,6 @@ export class Settings { return this._zoom; } - get useSSE(): boolean { - return this._useSSE; - } - get players(): Player[] { return this._players; } From 57f1ee87d96c9313ee80ba51b266584541243a96 Mon Sep 17 00:00:00 2001 From: granny Date: Sat, 23 Dec 2023 01:21:42 -0800 Subject: [PATCH 13/53] updater marker and settings task every tick --- .../map/core/renderer/task/UpdateMarkerData.java | 9 +++++++-- .../map/core/renderer/task/UpdateSettingsData.java | 13 ++++++++----- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java index f647f6940..c007ea830 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java @@ -61,9 +61,10 @@ public class UpdateMarkerData extends Task { private CompletableFuture future; private boolean running; + private int tempTick; public UpdateMarkerData(@NotNull World world) { - super(TickUtil.toTicks(1), true); + super(1, true); this.world = world; this.executor = Pl3xMap.ThreadFactory.createService("Pl3xMap-Markers"); } @@ -76,6 +77,7 @@ public void run() { this.running = true; this.future = CompletableFuture.runAsync(() -> { try { + tempTick++; parseLayers(); } catch (Throwable t) { t.printStackTrace(); @@ -121,7 +123,10 @@ private void parseLayers() { } }); - FileUtil.writeJson(this.gson.toJson(layers), this.world.getTilesDirectory().resolve("markers.json")); + if (tempTick >= 20) { + FileUtil.writeJson(this.gson.toJson(layers), this.world.getTilesDirectory().resolve("markers.json")); + tempTick = 0; + } } private static class Adapter implements JsonSerializer<@NotNull Marker> { diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java index e48af48dd..b5df2cc9f 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java @@ -26,7 +26,6 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; @@ -34,17 +33,16 @@ import net.pl3x.map.core.Pl3xMap; import net.pl3x.map.core.configuration.Config; import net.pl3x.map.core.configuration.Lang; -import net.pl3x.map.core.configuration.PlayersLayerConfig; import net.pl3x.map.core.configuration.WorldConfig; import net.pl3x.map.core.image.io.IO; import net.pl3x.map.core.markers.Point; import net.pl3x.map.core.scheduler.Task; import net.pl3x.map.core.util.FileUtil; -import net.pl3x.map.core.util.TickUtil; import net.pl3x.map.core.world.World; import org.jetbrains.annotations.NotNull; public class UpdateSettingsData extends Task { + private int tempTick; private final Gson gson = new GsonBuilder() //.setPrettyPrinting() .disableHtmlEscaping() @@ -53,12 +51,13 @@ public class UpdateSettingsData extends Task { .create(); public UpdateSettingsData() { - super(TickUtil.toTicks(1), true); + super(1, true); } @Override public void run() { try { + tempTick++; parseSettings(); } catch (Throwable t) { t.printStackTrace(); @@ -153,6 +152,10 @@ private void parseSettings() { } Pl3xMap.api().getHttpdServer().sendSSE("settings", this.gson.toJson(map)); - FileUtil.writeJson(this.gson.toJson(map), FileUtil.getTilesDir().resolve("settings.json")); + + if (tempTick >= 20) { + FileUtil.writeJson(this.gson.toJson(map), FileUtil.getTilesDir().resolve("settings.json")); + tempTick = 0; + } } } From e4dd53225c8e2152152a5e04d2f92ec07b685a5b Mon Sep 17 00:00:00 2001 From: granny Date: Sat, 23 Dec 2023 03:13:31 -0800 Subject: [PATCH 14/53] stop requesting settings.json if using sse --- webmap/src/Pl3xMap.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/webmap/src/Pl3xMap.ts b/webmap/src/Pl3xMap.ts index 6d4146032..4f23c2635 100644 --- a/webmap/src/Pl3xMap.ts +++ b/webmap/src/Pl3xMap.ts @@ -70,12 +70,14 @@ export class Pl3xMap { } private update(): void { + if (this.eventSource !== undefined && this.eventSource.readyState !== EventSource.CLOSED) { + this._timer = setTimeout(() => this.update(), 1000); + return; + } getJSON('tiles/settings.json').then( (json): void => { this._settings = json as Settings; - if (this.eventSource === undefined || this.eventSource.readyState === EventSource.CLOSED) { - this.playerManager.update(this._settings.players); - } + this.playerManager.update(this._settings.players); this._timer = setTimeout(() => this.update(), 1000); }); From 6ec42fed1ee486cf9174c5aaf0baf6e54f8b5d02 Mon Sep 17 00:00:00 2001 From: granny Date: Sat, 23 Dec 2023 03:13:43 -0800 Subject: [PATCH 15/53] this check wasn't doing anything before --- webmap/src/Pl3xMap.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webmap/src/Pl3xMap.ts b/webmap/src/Pl3xMap.ts index 4f23c2635..fa6e53241 100644 --- a/webmap/src/Pl3xMap.ts +++ b/webmap/src/Pl3xMap.ts @@ -95,7 +95,7 @@ export class Pl3xMap { if (world === undefined) return; - if (json.length === 0) return; + if (messageEvent.data.length === 0) return; world.markerLayers.forEach(layer => { if (layer.key !== key) return; From 857e164a617a0e3c7b59f68455888e31549d129d Mon Sep 17 00:00:00 2001 From: granny Date: Sat, 23 Dec 2023 03:32:57 -0800 Subject: [PATCH 16/53] missed this --- .../net/pl3x/map/core/renderer/task/UpdateMarkerData.java | 8 ++++---- core/src/main/java/net/pl3x/map/core/world/World.java | 1 - webmap/src/player/PlayerManager.ts | 1 - 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java index c007ea830..74ca3d671 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java @@ -46,7 +46,7 @@ import org.jetbrains.annotations.NotNull; public class UpdateMarkerData extends Task { - protected final Gson gson = new GsonBuilder() + private final Gson gson = new GsonBuilder() //.setPrettyPrinting() .disableHtmlEscaping() .serializeNulls() @@ -54,9 +54,9 @@ public class UpdateMarkerData extends Task { .registerTypeHierarchyAdapter(Marker.class, new Adapter()) .create(); - protected final World world; - protected final Map<@NotNull String, @NotNull Long> lastUpdated = new HashMap<>(); - protected final Map<@NotNull String, @NotNull Long> lastUpdatedSSE = new HashMap<>(); + private final World world; + private final Map<@NotNull String, @NotNull Long> lastUpdated = new HashMap<>(); + private final Map<@NotNull String, @NotNull Long> lastUpdatedSSE = new HashMap<>(); private final ExecutorService executor; private CompletableFuture future; diff --git a/core/src/main/java/net/pl3x/map/core/world/World.java b/core/src/main/java/net/pl3x/map/core/world/World.java index f3eeace5c..27f53e2f3 100644 --- a/core/src/main/java/net/pl3x/map/core/world/World.java +++ b/core/src/main/java/net/pl3x/map/core/world/World.java @@ -41,7 +41,6 @@ import javax.imageio.ImageIO; import net.pl3x.map.core.Keyed; import net.pl3x.map.core.Pl3xMap; -import net.pl3x.map.core.configuration.Config; import net.pl3x.map.core.configuration.PlayersLayerConfig; import net.pl3x.map.core.configuration.SpawnLayerConfig; import net.pl3x.map.core.configuration.WorldBorderLayerConfig; diff --git a/webmap/src/player/PlayerManager.ts b/webmap/src/player/PlayerManager.ts index 57ffb348b..773d0c4f0 100644 --- a/webmap/src/player/PlayerManager.ts +++ b/webmap/src/player/PlayerManager.ts @@ -1,6 +1,5 @@ import {Pl3xMap} from "../Pl3xMap"; import {Player} from "./Player"; -import {Settings} from "../settings/Settings"; import {fireCustomEvent, toCenteredLatLng} from "../util/Util"; import {WorldManager} from "../world/WorldManager"; import Pl3xMapLeafletMap from "../map/Pl3xMapLeafletMap"; From a29c2d9a24f3cd2f56e67b3d9774cc36c50dfc49 Mon Sep 17 00:00:00 2001 From: granny Date: Sat, 23 Dec 2023 03:36:32 -0800 Subject: [PATCH 17/53] cleaner tick handling --- .../net/pl3x/map/core/renderer/task/UpdateMarkerData.java | 5 ++--- .../net/pl3x/map/core/renderer/task/UpdateSettingsData.java | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java index 74ca3d671..6da8f0bc6 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java @@ -77,7 +77,6 @@ public void run() { this.running = true; this.future = CompletableFuture.runAsync(() -> { try { - tempTick++; parseLayers(); } catch (Throwable t) { t.printStackTrace(); @@ -123,9 +122,9 @@ private void parseLayers() { } }); - if (tempTick >= 20) { - FileUtil.writeJson(this.gson.toJson(layers), this.world.getTilesDirectory().resolve("markers.json")); + if (tempTick++ >= 20) { tempTick = 0; + FileUtil.writeJson(this.gson.toJson(layers), this.world.getTilesDirectory().resolve("markers.json")); } } diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java index b5df2cc9f..d69fc84c2 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java @@ -57,7 +57,6 @@ public UpdateSettingsData() { @Override public void run() { try { - tempTick++; parseSettings(); } catch (Throwable t) { t.printStackTrace(); @@ -153,9 +152,9 @@ private void parseSettings() { Pl3xMap.api().getHttpdServer().sendSSE("settings", this.gson.toJson(map)); - if (tempTick >= 20) { - FileUtil.writeJson(this.gson.toJson(map), FileUtil.getTilesDir().resolve("settings.json")); + if (tempTick++ >= 20) { tempTick = 0; + FileUtil.writeJson(this.gson.toJson(map), FileUtil.getTilesDir().resolve("settings.json")); } } } From 83f8823825716c25614f04a2bc9ae23d6a34b751 Mon Sep 17 00:00:00 2001 From: granny Date: Fri, 26 Jan 2024 01:56:09 -0800 Subject: [PATCH 18/53] need to update loom for some reason --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 5c1fed569..c1a6ab8ce 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ bukkitVersion=1.20.4-R0.1-SNAPSHOT fabricApiVersion=0.91.3+1.20.4 fabricLoaderVersion=0.15.3 -fabricLoomVersion=1.4-SNAPSHOT +fabricLoomVersion=1.5-SNAPSHOT forgeVersion=1.20.2-48.0.6 forgeGradleVersion=[6.0,6.2) From f12a852e119c9d58ec415e1a9fa6ece1dac5abb6 Mon Sep 17 00:00:00 2001 From: granny Date: Fri, 26 Jan 2024 02:02:25 -0800 Subject: [PATCH 19/53] add get/set methods for update interval in ticks --- .../pl3x/map/core/markers/layer/Layer.java | 25 +++++++++++++++++-- .../java/net/pl3x/map/core/util/TickUtil.java | 4 +-- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java index 2a4b95b9a..866a22c67 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java @@ -100,7 +100,17 @@ public Layer(@NotNull String key, @NotNull Supplier<@NotNull String> labelSuppli * @return update interval */ public int getUpdateInterval() { - return TickUtil.toSeconds(this.updateInterval); + return this.getUpdateInterval(false); + } + + /** + * Get this layer's update interval (in seconds or in ticks). + * + * @param ticks set to true to get update interval as ticks instead of seconds + * @return update interval + */ + public int getUpdateInterval(boolean ticks) { + return ticks ? this.updateInterval : (int) TickUtil.toSeconds(this.updateInterval); } /** @@ -110,10 +120,21 @@ public int getUpdateInterval() { * @return this layer */ public @NotNull Layer setUpdateInterval(int updateInterval) { - this.updateInterval = TickUtil.toTicks(updateInterval); + this.setUpdateInterval(updateInterval, false); return this; } + /** + * Set this layer's update interval (in seconds or in ticks). + * + * @param updateInterval new update interval + * @param ticks set to true to treat the interval value as ticks instead of seconds + * @return this layer + */ + public @NotNull Layer setUpdateInterval(int updateInterval, boolean ticks) { + this.updateInterval = ticks ? updateInterval : TickUtil.toTicks(updateInterval); + return this; + } /** * Get this layer's update interval (in ticks). diff --git a/core/src/main/java/net/pl3x/map/core/util/TickUtil.java b/core/src/main/java/net/pl3x/map/core/util/TickUtil.java index 8aedc8551..309b6ef16 100644 --- a/core/src/main/java/net/pl3x/map/core/util/TickUtil.java +++ b/core/src/main/java/net/pl3x/map/core/util/TickUtil.java @@ -24,8 +24,8 @@ package net.pl3x.map.core.util; public class TickUtil { - public static int toSeconds(int ticks) { - return (int) (0.05 * ticks); + public static double toSeconds(int ticks) { + return ticks * (1.0 / 20); } public static int toTicks(int seconds) { From 4b342cc91bc5f1d39001d2e4e3849de44cef86bc Mon Sep 17 00:00:00 2001 From: granny Date: Fri, 26 Jan 2024 02:04:01 -0800 Subject: [PATCH 20/53] clean up layer update logic --- .../pl3x/map/core/markers/layer/Layer.java | 21 ------------------- .../core/renderer/task/UpdateMarkerData.java | 19 +++++++---------- .../java/net/pl3x/map/core/util/TickUtil.java | 4 ++++ 3 files changed, 11 insertions(+), 33 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java index 866a22c67..adce9292c 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java @@ -43,7 +43,6 @@ public abstract class Layer extends Keyed implements JsonSerializable { private Supplier<@NotNull String> labelSupplier; private int updateInterval = TickUtil.toTicks(15); - private int sseUpdateInterval = 0; private boolean showControls = true; private boolean defaultHidden = false; private int priority = 99; @@ -136,26 +135,6 @@ public int getUpdateInterval(boolean ticks) { return this; } - /** - * Get this layer's update interval (in ticks). - * - * @return update interval - */ - public int getSseUpdateInterval() { - return this.sseUpdateInterval; - } - - /** - * Set this layer's update interval (in ticks). - * - * @param sseUpdateInterval new update interval - * @return this layer - */ - public @NotNull Layer setSseUpdateInterval(int sseUpdateInterval) { - this.sseUpdateInterval = sseUpdateInterval; - return this; - } - /** * Get whether to show this layer in the control box. * diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java index 6da8f0bc6..b17b508dc 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java @@ -61,7 +61,7 @@ public class UpdateMarkerData extends Task { private CompletableFuture future; private boolean running; - private int tempTick; + private int fileTick; public UpdateMarkerData(@NotNull World world) { super(1, true); @@ -102,19 +102,14 @@ private void parseLayers() { try { layers.add(layer.toJson()); - long now = System.currentTimeMillis() / 1000; + long now = System.currentTimeMillis(); long lastUpdate = this.lastUpdated.getOrDefault(key, 0L); long lastUpdateSSE = this.lastUpdatedSSE.getOrDefault(key, 0L); - List> list = null; - if (now - lastUpdateSSE >= TickUtil.toSeconds(layer.getSseUpdateInterval())) { // TODO: this is bad - list = list == null ? new ArrayList<>(layer.getMarkers()) : list; - Pl3xMap.api().getHttpdServer().sendSSE("markers", String.format("{ \"world\": \"%s\", \"key\": \"%s\", \"markers\": %s}", this.world.getName(), key, this.gson.toJson(list))); - this.lastUpdatedSSE.put(key, now); - } - if (now - lastUpdate > layer.getUpdateInterval()) { - list = list == null ? new ArrayList<>(layer.getMarkers()) : list; + if (now - lastUpdate > Math.max(TickUtil.toMilliseconds(layer.getUpdateInterval()), 50)) { + List> list = new ArrayList<>(layer.getMarkers()); FileUtil.writeJson(this.gson.toJson(list), this.world.getMarkersDirectory().resolve(key.replace(":", "-") + ".json")); + Pl3xMap.api().getHttpdServer().sendSSE("markers", String.format("{ \"world\": \"%s\", \"key\": \"%s\", \"markers\": %s}", this.world.getName(), key, this.gson.toJson(list))); this.lastUpdated.put(key, now); } } catch (Throwable t) { @@ -122,8 +117,8 @@ private void parseLayers() { } }); - if (tempTick++ >= 20) { - tempTick = 0; + if (fileTick++ >= 20) { + fileTick = 0; FileUtil.writeJson(this.gson.toJson(layers), this.world.getTilesDirectory().resolve("markers.json")); } } diff --git a/core/src/main/java/net/pl3x/map/core/util/TickUtil.java b/core/src/main/java/net/pl3x/map/core/util/TickUtil.java index 309b6ef16..3a07edd3d 100644 --- a/core/src/main/java/net/pl3x/map/core/util/TickUtil.java +++ b/core/src/main/java/net/pl3x/map/core/util/TickUtil.java @@ -31,4 +31,8 @@ public static double toSeconds(int ticks) { public static int toTicks(int seconds) { return seconds * 20; } + + public static int toMilliseconds(int ticks) { + return ticks * 50; + } } From 85fe0dac64707d3f887301d22bb78e06a621708c Mon Sep 17 00:00:00 2001 From: granny Date: Fri, 26 Jan 2024 02:47:17 -0800 Subject: [PATCH 21/53] add update-interval-in-ticks option to layer configs --- .../configuration/PlayersLayerConfig.java | 20 ++++++++++++++++++- .../core/configuration/SpawnLayerConfig.java | 6 +++++- .../configuration/WorldBorderLayerConfig.java | 6 +++++- .../map/core/markers/layer/PlayersLayer.java | 2 +- .../map/core/markers/layer/SpawnLayer.java | 2 +- .../core/markers/layer/WorldBorderLayer.java | 2 +- 6 files changed, 32 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/configuration/PlayersLayerConfig.java b/core/src/main/java/net/pl3x/map/core/configuration/PlayersLayerConfig.java index 7ccbdd848..8900a42a8 100644 --- a/core/src/main/java/net/pl3x/map/core/configuration/PlayersLayerConfig.java +++ b/core/src/main/java/net/pl3x/map/core/configuration/PlayersLayerConfig.java @@ -24,6 +24,8 @@ package net.pl3x.map.core.configuration; import net.pl3x.map.core.Pl3xMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; @SuppressWarnings("CanBeFinal") public final class PlayersLayerConfig extends AbstractConfig { @@ -42,9 +44,13 @@ public final class PlayersLayerConfig extends AbstractConfig { Should spectators be hidden from the map.""") public static boolean HIDE_SPECTATORS = true; + @Key("settings.layer.update-interval-in-ticks") + @Comment(""" + Treat the update-interval option's value as ticks instead of seconds.""") + public static boolean UPDATE_INTERVAL_IN_TICKS = true; @Key("settings.layer.update-interval") @Comment(""" - How often (in seconds) to update the marker. + How often to update the marker. Setting to 0 is the same as setting it to 1.""") public static int UPDATE_INTERVAL = 0; @Key("settings.layer.show-controls") @@ -151,4 +157,16 @@ Whether the players layer should be hidden (toggled off) by default.""") public static void reload() { CONFIG.reload(Pl3xMap.api().getMainDir().resolve("layers/players.yml"), PlayersLayerConfig.class); } + + @Override + protected @Nullable Object getValue(@NotNull String path, @Nullable Object def) { + // assume that if the ticks option doesn't exist but the interval option does, + // then it's safe to set ticks option to false to keep backwards compatibility + if (path.contains("update-interval-in-ticks") + && getConfig().get(path) == null + && getConfig().get("settings.layer.update-interval") != null) { + return super.getValue(path, false); + } + return super.getValue(path, def); + } } diff --git a/core/src/main/java/net/pl3x/map/core/configuration/SpawnLayerConfig.java b/core/src/main/java/net/pl3x/map/core/configuration/SpawnLayerConfig.java index 86c6f7a44..66879272c 100644 --- a/core/src/main/java/net/pl3x/map/core/configuration/SpawnLayerConfig.java +++ b/core/src/main/java/net/pl3x/map/core/configuration/SpawnLayerConfig.java @@ -32,9 +32,13 @@ public final class SpawnLayerConfig extends AbstractConfig { Show spawn icon on the map.""") public static boolean ENABLED = true; + @Key("settings.layer.update-interval-in-ticks") + @Comment(""" + Treat the update-interval option as ticks instead of seconds.""") + public static boolean UPDATE_INTERVAL_IN_TICKS = false; @Key("settings.layer.update-interval") @Comment(""" - How often (in seconds) to update the marker. + How often to update the marker. Setting to 0 is the same as setting it to 1.""") public static int UPDATE_INTERVAL = 30; @Key("settings.layer.show-controls") diff --git a/core/src/main/java/net/pl3x/map/core/configuration/WorldBorderLayerConfig.java b/core/src/main/java/net/pl3x/map/core/configuration/WorldBorderLayerConfig.java index b7f5c78f0..8f0b89798 100644 --- a/core/src/main/java/net/pl3x/map/core/configuration/WorldBorderLayerConfig.java +++ b/core/src/main/java/net/pl3x/map/core/configuration/WorldBorderLayerConfig.java @@ -33,9 +33,13 @@ public final class WorldBorderLayerConfig extends AbstractConfig { Shows vanilla world border on the map.""") public static boolean ENABLED = true; + @Key("settings.layer.update-interval-in-ticks") + @Comment(""" + Treat the update-interval option as ticks instead of seconds.""") + public static boolean UPDATE_INTERVAL_IN_TICKS = false; @Key("settings.layer.update-interval") @Comment(""" - How often (in seconds) to update the marker. + How often to update the marker. Setting to 0 is the same as setting it to 1.""") public static int UPDATE_INTERVAL = 30; @Key("settings.layer.show-controls") diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/PlayersLayer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/PlayersLayer.java index bf01e7e30..6aef5b399 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/PlayersLayer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/PlayersLayer.java @@ -59,7 +59,7 @@ public class PlayersLayer extends WorldLayer { */ public PlayersLayer(@NotNull World world) { this(KEY, world, () -> Lang.UI_LAYER_PLAYERS); - setUpdateInterval(PlayersLayerConfig.UPDATE_INTERVAL); + setUpdateInterval(PlayersLayerConfig.UPDATE_INTERVAL, PlayersLayerConfig.UPDATE_INTERVAL_IN_TICKS); setShowControls(PlayersLayerConfig.SHOW_CONTROLS); setDefaultHidden(PlayersLayerConfig.DEFAULT_HIDDEN); setPriority(PlayersLayerConfig.PRIORITY); diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java index b9203527b..ea2416bec 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java @@ -66,7 +66,7 @@ public SpawnLayer(@NotNull World world) { throw new RuntimeException(e); } - setUpdateInterval(TickUtil.toTicks(SpawnLayerConfig.UPDATE_INTERVAL)); + setUpdateInterval(SpawnLayerConfig.UPDATE_INTERVAL, SpawnLayerConfig.UPDATE_INTERVAL_IN_TICKS); setShowControls(SpawnLayerConfig.SHOW_CONTROLS); setDefaultHidden(SpawnLayerConfig.DEFAULT_HIDDEN); setPriority(SpawnLayerConfig.PRIORITY); diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java index 39cddf59a..56ca355ea 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java @@ -53,7 +53,7 @@ public class WorldBorderLayer extends WorldLayer { */ public WorldBorderLayer(@NotNull World world) { this(KEY, world, () -> Lang.UI_LAYER_WORLDBORDER); - setUpdateInterval(TickUtil.toTicks(WorldBorderLayerConfig.UPDATE_INTERVAL)); + setUpdateInterval(WorldBorderLayerConfig.UPDATE_INTERVAL, WorldBorderLayerConfig.UPDATE_INTERVAL_IN_TICKS); setShowControls(WorldBorderLayerConfig.SHOW_CONTROLS); setDefaultHidden(WorldBorderLayerConfig.DEFAULT_HIDDEN); setPriority(WorldBorderLayerConfig.PRIORITY); From 8ea5bd2e314e6858853ab0237c6a9f37a15a306f Mon Sep 17 00:00:00 2001 From: granny Date: Fri, 26 Jan 2024 03:35:34 -0800 Subject: [PATCH 22/53] missed this --- .../main/java/net/pl3x/map/core/markers/layer/CustomLayer.java | 2 +- core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java | 2 +- .../java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/CustomLayer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/CustomLayer.java index b04f860ad..3496f1edd 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/CustomLayer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/CustomLayer.java @@ -67,7 +67,7 @@ public static void load(World world, Path path) { public static @NotNull CustomLayer fromJson(@NotNull World world, @NotNull JsonObject obj) { JsonElement el; CustomLayer layer = new CustomLayer(obj.get("key").getAsString(), world, () -> obj.get("label").getAsString()); - if ((el = obj.get("updateInterval")) != null && !(el instanceof JsonNull)) layer.setUpdateInterval(el.getAsInt()); + if ((el = obj.get("updateInterval")) != null && !(el instanceof JsonNull)) layer.setUpdateInterval(el.getAsInt(), true); if ((el = obj.get("showControls")) != null && !(el instanceof JsonNull)) layer.setShowControls(el.getAsBoolean()); if ((el = obj.get("defaultHidden")) != null && !(el instanceof JsonNull)) layer.setDefaultHidden(el.getAsBoolean()); if ((el = obj.get("priority")) != null && !(el instanceof JsonNull)) layer.setPriority(el.getAsInt()); diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java index adce9292c..1072bc500 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java @@ -280,7 +280,7 @@ public int getPriority() { JsonObjectWrapper wrapper = new JsonObjectWrapper(); wrapper.addProperty("key", getKey()); wrapper.addProperty("label", getLabel()); - wrapper.addProperty("updateInterval", getUpdateInterval()); + wrapper.addProperty("updateInterval", getUpdateInterval(true)); wrapper.addProperty("showControls", shouldShowControls()); wrapper.addProperty("defaultHidden", isDefaultHidden()); wrapper.addProperty("priority", getPriority()); diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java index b17b508dc..a9c572200 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java @@ -56,7 +56,6 @@ public class UpdateMarkerData extends Task { private final World world; private final Map<@NotNull String, @NotNull Long> lastUpdated = new HashMap<>(); - private final Map<@NotNull String, @NotNull Long> lastUpdatedSSE = new HashMap<>(); private final ExecutorService executor; private CompletableFuture future; @@ -104,7 +103,6 @@ private void parseLayers() { long now = System.currentTimeMillis(); long lastUpdate = this.lastUpdated.getOrDefault(key, 0L); - long lastUpdateSSE = this.lastUpdatedSSE.getOrDefault(key, 0L); if (now - lastUpdate > Math.max(TickUtil.toMilliseconds(layer.getUpdateInterval()), 50)) { List> list = new ArrayList<>(layer.getMarkers()); From 06f6f317d443fe65b5276fe80a41f0d08e29f4f4 Mon Sep 17 00:00:00 2001 From: granny Date: Fri, 26 Jan 2024 03:49:30 -0800 Subject: [PATCH 23/53] add methods for setting task delay as ticks in scheduler --- .../pl3x/map/core/scheduler/Scheduler.java | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/net/pl3x/map/core/scheduler/Scheduler.java b/core/src/main/java/net/pl3x/map/core/scheduler/Scheduler.java index 80d2578d8..308e84fc2 100644 --- a/core/src/main/java/net/pl3x/map/core/scheduler/Scheduler.java +++ b/core/src/main/java/net/pl3x/map/core/scheduler/Scheduler.java @@ -96,6 +96,17 @@ public void addTask(int delay, @NotNull Runnable runnable) { addTask(delay, false, runnable); } + /** + * Add task to the scheduler. + * + * @param delay Delay (in seconds or ticks) before task starts + * @param ticks Set to true to pass the delay as ticks instead of seconds + * @param runnable Task to add + */ + public void addTask(int delay, @NotNull Runnable runnable, boolean ticks) { + addTask(delay, false, runnable, ticks); + } + /** * Add task to the scheduler. * @@ -104,7 +115,19 @@ public void addTask(int delay, @NotNull Runnable runnable) { * @param runnable Task to add */ public void addTask(int delay, boolean repeat, @NotNull Runnable runnable) { - addTask(new Task(TickUtil.toTicks(delay), repeat) { + addTask(delay, repeat, runnable, false); + } + + /** + * Add task to the scheduler. + * + * @param delay Delay (in seconds or ticks) before task starts + * @param repeat Delay (in seconds or ticks) before task repeats + * @param runnable Task to add + * @param ticks Set to true to pass the delay as ticks instead of seconds + */ + public void addTask(int delay, boolean repeat, @NotNull Runnable runnable, boolean ticks) { + addTask(new Task(ticks ? delay : TickUtil.toTicks(delay), repeat) { @Override public void run() { runnable.run(); From 7da3fb6153f6e5c54073c119ae29b2023f88c879 Mon Sep 17 00:00:00 2001 From: granny Date: Fri, 26 Jan 2024 03:51:17 -0800 Subject: [PATCH 24/53] fix incorrect javadoc comments --- .../main/java/net/pl3x/map/core/scheduler/Scheduler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/scheduler/Scheduler.java b/core/src/main/java/net/pl3x/map/core/scheduler/Scheduler.java index 308e84fc2..d7b220c56 100644 --- a/core/src/main/java/net/pl3x/map/core/scheduler/Scheduler.java +++ b/core/src/main/java/net/pl3x/map/core/scheduler/Scheduler.java @@ -100,8 +100,8 @@ public void addTask(int delay, @NotNull Runnable runnable) { * Add task to the scheduler. * * @param delay Delay (in seconds or ticks) before task starts - * @param ticks Set to true to pass the delay as ticks instead of seconds * @param runnable Task to add + * @param ticks Set to true to pass the delay as ticks instead of seconds */ public void addTask(int delay, @NotNull Runnable runnable, boolean ticks) { addTask(delay, false, runnable, ticks); @@ -111,7 +111,7 @@ public void addTask(int delay, @NotNull Runnable runnable, boolean ticks) { * Add task to the scheduler. * * @param delay Delay (in seconds) before task starts - * @param repeat Delay (in seconds) before task repeats + * @param repeat Whether this task should repeat * @param runnable Task to add */ public void addTask(int delay, boolean repeat, @NotNull Runnable runnable) { @@ -122,7 +122,7 @@ public void addTask(int delay, boolean repeat, @NotNull Runnable runnable) { * Add task to the scheduler. * * @param delay Delay (in seconds or ticks) before task starts - * @param repeat Delay (in seconds or ticks) before task repeats + * @param repeat Whether this task should repeat * @param runnable Task to add * @param ticks Set to true to pass the delay as ticks instead of seconds */ From d9125052a581f7ae14d0bb52f42d925cbbc960cc Mon Sep 17 00:00:00 2001 From: granny Date: Fri, 26 Jan 2024 04:06:37 -0800 Subject: [PATCH 25/53] make the marker files update by at least a second --- .../pl3x/map/core/renderer/task/UpdateMarkerData.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java index a9c572200..0cd609e46 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java @@ -56,6 +56,7 @@ public class UpdateMarkerData extends Task { private final World world; private final Map<@NotNull String, @NotNull Long> lastUpdated = new HashMap<>(); + private final Map<@NotNull String, @NotNull Long> fileLastUpdated = new HashMap<>(); private final ExecutorService executor; private CompletableFuture future; @@ -103,13 +104,17 @@ private void parseLayers() { long now = System.currentTimeMillis(); long lastUpdate = this.lastUpdated.getOrDefault(key, 0L); + long fileLastUpdated = this.fileLastUpdated.getOrDefault(key, 0L); + List> list = new ArrayList<>(layer.getMarkers()); if (now - lastUpdate > Math.max(TickUtil.toMilliseconds(layer.getUpdateInterval()), 50)) { - List> list = new ArrayList<>(layer.getMarkers()); - FileUtil.writeJson(this.gson.toJson(list), this.world.getMarkersDirectory().resolve(key.replace(":", "-") + ".json")); Pl3xMap.api().getHttpdServer().sendSSE("markers", String.format("{ \"world\": \"%s\", \"key\": \"%s\", \"markers\": %s}", this.world.getName(), key, this.gson.toJson(list))); this.lastUpdated.put(key, now); } + if (now - fileLastUpdated > Math.max(TickUtil.toMilliseconds(layer.getUpdateInterval()), 1000)) { + FileUtil.writeJson(this.gson.toJson(list), this.world.getMarkersDirectory().resolve(key.replace(":", "-") + ".json")); + this.fileLastUpdated.put(key, now); + } } catch (Throwable t) { t.printStackTrace(); } From 9b92cc70f950109b7b26852efc8e4aa71f521f02 Mon Sep 17 00:00:00 2001 From: granny Date: Sun, 28 Jan 2024 19:06:30 -0800 Subject: [PATCH 26/53] use json files if SSE takes longer than one second --- webmap/src/Pl3xMap.ts | 9 ++++++++- webmap/src/layergroup/MarkerLayer.ts | 6 +++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/webmap/src/Pl3xMap.ts b/webmap/src/Pl3xMap.ts index fa6e53241..fd09b8654 100644 --- a/webmap/src/Pl3xMap.ts +++ b/webmap/src/Pl3xMap.ts @@ -29,6 +29,7 @@ export class Pl3xMap { private _langPalette: Map = new Map(); private _settings?: Settings; + private _timestamp: number = (new Date()).getTime(); private _timer: NodeJS.Timeout | undefined; constructor() { @@ -70,7 +71,7 @@ export class Pl3xMap { } private update(): void { - if (this.eventSource !== undefined && this.eventSource.readyState !== EventSource.CLOSED) { + if (this.eventSource !== undefined && this.eventSource.readyState !== EventSource.CLOSED && (new Date()).getTime() - this._timestamp < 1000) { this._timer = setTimeout(() => this.update(), 1000); return; } @@ -87,6 +88,7 @@ export class Pl3xMap { const eventSource = new EventSource("sse"); eventSource.addEventListener("markers", (ev: Event) => { + this._timestamp = (new Date()).getTime(); const messageEvent = (ev as MessageEvent); const json: any = JSON.parse(messageEvent.data); const world = this._worldManager.getWorld(json.world); @@ -104,6 +106,7 @@ export class Pl3xMap { }); eventSource.addEventListener("settings", (ev: Event) => { + this._timestamp = (new Date()).getTime(); const messageEvent = (ev as MessageEvent); const json: any = JSON.parse(messageEvent.data); this._settings = json as Settings; @@ -140,4 +143,8 @@ export class Pl3xMap { get settings(): Settings | undefined { return this._settings; } + + get timestamp(): number { + return this._timestamp; + } } diff --git a/webmap/src/layergroup/MarkerLayer.ts b/webmap/src/layergroup/MarkerLayer.ts index aeaf6a53c..37548dc05 100644 --- a/webmap/src/layergroup/MarkerLayer.ts +++ b/webmap/src/layergroup/MarkerLayer.ts @@ -48,6 +48,7 @@ export class MarkerLayer extends L.LayerGroup { private readonly _markers: Map = new Map(); private _timer: NodeJS.Timeout | undefined; + private _initialized = false; constructor(key: string, label: string, interval: number, showControls: boolean, defaultHidden: boolean, priority: number, zIndex: number, pane: string, css: string) { super(undefined, { @@ -115,7 +116,7 @@ export class MarkerLayer extends L.LayerGroup { } update(world: World): void { - if (Pl3xMap.instance.eventSource !== undefined && Pl3xMap.instance.eventSource.readyState !== EventSource.CLOSED) { + if (this._initialized && Pl3xMap.instance.eventSource !== undefined && Pl3xMap.instance.eventSource.readyState !== EventSource.CLOSED && (new Date()).getTime() - Pl3xMap.instance.timestamp < 1000) { return; } @@ -159,6 +160,9 @@ export class MarkerLayer extends L.LayerGroup { } }); + if (!this._initialized) { + this._initialized = true; + } this._timer = setTimeout(() => this.update(world), this._updateInterval); } From 3a29bf4ddc85425860851bc3365b1659afd00b71 Mon Sep 17 00:00:00 2001 From: granny Date: Sun, 28 Jan 2024 19:07:46 -0800 Subject: [PATCH 27/53] only send SSE events if the data has been modified --- .../core/renderer/task/UpdateMarkerData.java | 26 ++++++++++++------- .../renderer/task/UpdateSettingsData.java | 16 ++++++++---- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java index 0cd609e46..06fd84a6c 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java @@ -23,6 +23,8 @@ */ package net.pl3x.map.core.renderer.task; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; @@ -35,6 +37,7 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; import net.pl3x.map.core.Pl3xMap; import net.pl3x.map.core.markers.JsonObjectWrapper; import net.pl3x.map.core.markers.layer.Layer; @@ -56,7 +59,10 @@ public class UpdateMarkerData extends Task { private final World world; private final Map<@NotNull String, @NotNull Long> lastUpdated = new HashMap<>(); - private final Map<@NotNull String, @NotNull Long> fileLastUpdated = new HashMap<>(); + private final Cache<@NotNull String, String> markerCache = CacheBuilder.newBuilder() + .maximumSize(1000) + .expireAfterWrite(1, TimeUnit.MINUTES) + .build(); private final ExecutorService executor; private CompletableFuture future; @@ -103,17 +109,19 @@ private void parseLayers() { layers.add(layer.toJson()); long now = System.currentTimeMillis(); - long lastUpdate = this.lastUpdated.getOrDefault(key, 0L); - long fileLastUpdated = this.fileLastUpdated.getOrDefault(key, 0L); + long lastUpdated = this.lastUpdated.getOrDefault(key, 0L); List> list = new ArrayList<>(layer.getMarkers()); - if (now - lastUpdate > Math.max(TickUtil.toMilliseconds(layer.getUpdateInterval()), 50)) { - Pl3xMap.api().getHttpdServer().sendSSE("markers", String.format("{ \"world\": \"%s\", \"key\": \"%s\", \"markers\": %s}", this.world.getName(), key, this.gson.toJson(list))); - this.lastUpdated.put(key, now); + String json = this.gson.toJson(list); + String markerCacheIfPresent = markerCache.getIfPresent(key); + if (markerCacheIfPresent == null || !markerCacheIfPresent.equals(json)) { + Pl3xMap.api().getHttpdServer().sendSSE("markers", String.format("{ \"world\": \"%s\", \"key\": \"%s\", \"markers\": %s}", this.world.getName(), key, json)); + markerCache.put(key, json); } - if (now - fileLastUpdated > Math.max(TickUtil.toMilliseconds(layer.getUpdateInterval()), 1000)) { - FileUtil.writeJson(this.gson.toJson(list), this.world.getMarkersDirectory().resolve(key.replace(":", "-") + ".json")); - this.fileLastUpdated.put(key, now); + + if (now - lastUpdated > Math.max(TickUtil.toMilliseconds(layer.getUpdateInterval()), 1000)) { + FileUtil.writeJson(json, this.world.getMarkersDirectory().resolve(key.replace(":", "-") + ".json")); + this.lastUpdated.put(key, now); } } catch (Throwable t) { t.printStackTrace(); diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java index d69fc84c2..92ae42fc6 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java @@ -42,13 +42,14 @@ import org.jetbrains.annotations.NotNull; public class UpdateSettingsData extends Task { - private int tempTick; + private int fileTick; private final Gson gson = new GsonBuilder() //.setPrettyPrinting() .disableHtmlEscaping() .serializeNulls() .setLenient() .create(); + private String cachedJsonData = ""; public UpdateSettingsData() { super(1, true); @@ -150,11 +151,16 @@ private void parseSettings() { t.printStackTrace(); } - Pl3xMap.api().getHttpdServer().sendSSE("settings", this.gson.toJson(map)); + String json = this.gson.toJson(map); - if (tempTick++ >= 20) { - tempTick = 0; - FileUtil.writeJson(this.gson.toJson(map), FileUtil.getTilesDir().resolve("settings.json")); + if (!cachedJsonData.equals(json)) { + Pl3xMap.api().getHttpdServer().sendSSE("settings", json); + cachedJsonData = json; + } + + if (fileTick++ >= 20) { + fileTick = 0; + FileUtil.writeJson(json, FileUtil.getTilesDir().resolve("settings.json")); } } } From f8b8890cde805f12feebaf35362ecde5187cecfa Mon Sep 17 00:00:00 2001 From: granny Date: Fri, 2 Feb 2024 02:26:29 -0800 Subject: [PATCH 28/53] force update markers when loading worlds --- webmap/src/layergroup/MarkerLayer.ts | 8 ++------ webmap/src/world/World.ts | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/webmap/src/layergroup/MarkerLayer.ts b/webmap/src/layergroup/MarkerLayer.ts index 37548dc05..53ec600cd 100644 --- a/webmap/src/layergroup/MarkerLayer.ts +++ b/webmap/src/layergroup/MarkerLayer.ts @@ -48,7 +48,6 @@ export class MarkerLayer extends L.LayerGroup { private readonly _markers: Map = new Map(); private _timer: NodeJS.Timeout | undefined; - private _initialized = false; constructor(key: string, label: string, interval: number, showControls: boolean, defaultHidden: boolean, priority: number, zIndex: number, pane: string, css: string) { super(undefined, { @@ -115,8 +114,8 @@ export class MarkerLayer extends L.LayerGroup { return this._css; } - update(world: World): void { - if (this._initialized && Pl3xMap.instance.eventSource !== undefined && Pl3xMap.instance.eventSource.readyState !== EventSource.CLOSED && (new Date()).getTime() - Pl3xMap.instance.timestamp < 1000) { + update(world: World, updateOverride?: boolean): void { + if (!updateOverride && Pl3xMap.instance.eventSource !== undefined && Pl3xMap.instance.eventSource.readyState !== EventSource.CLOSED && (new Date()).getTime() - Pl3xMap.instance.timestamp < 1000) { return; } @@ -160,9 +159,6 @@ export class MarkerLayer extends L.LayerGroup { } }); - if (!this._initialized) { - this._initialized = true; - } this._timer = setTimeout(() => this.update(world), this._updateInterval); } diff --git a/webmap/src/world/World.ts b/webmap/src/world/World.ts index eccfc08de..ed7c51e02 100644 --- a/webmap/src/world/World.ts +++ b/webmap/src/world/World.ts @@ -94,7 +94,7 @@ export class World { (json as MarkerLayer[]).forEach((layer: MarkerLayer): void => { const markerLayer: MarkerLayer = new MarkerLayer(layer.key, layer.label, layer.updateInterval, layer.showControls, layer.defaultHidden, layer.priority, layer.zIndex, layer.pane, layer.css); this._markerLayers.push(markerLayer); - markerLayer.update(this); + markerLayer.update(this, true); }); }); } From f67b857fc5f59142885934db7e0c368d097b38ad Mon Sep 17 00:00:00 2001 From: granny Date: Fri, 2 Feb 2024 02:57:52 -0800 Subject: [PATCH 29/53] make marker cache key more unique --- .../net/pl3x/map/core/renderer/task/UpdateMarkerData.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java index 06fd84a6c..007fd41e7 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java @@ -39,6 +39,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import net.pl3x.map.core.Pl3xMap; +import net.pl3x.map.core.log.Logger; import net.pl3x.map.core.markers.JsonObjectWrapper; import net.pl3x.map.core.markers.layer.Layer; import net.pl3x.map.core.markers.marker.Marker; @@ -113,10 +114,10 @@ private void parseLayers() { List> list = new ArrayList<>(layer.getMarkers()); String json = this.gson.toJson(list); - String markerCacheIfPresent = markerCache.getIfPresent(key); + String markerCacheIfPresent = markerCache.getIfPresent(this.world.getKey() + "|" + key); if (markerCacheIfPresent == null || !markerCacheIfPresent.equals(json)) { Pl3xMap.api().getHttpdServer().sendSSE("markers", String.format("{ \"world\": \"%s\", \"key\": \"%s\", \"markers\": %s}", this.world.getName(), key, json)); - markerCache.put(key, json); + markerCache.put(this.world.getKey() + "|" + key, json); } if (now - lastUpdated > Math.max(TickUtil.toMilliseconds(layer.getUpdateInterval()), 1000)) { From de0a2e9387be2b49843c5cb09c5b672a8dc7ac05 Mon Sep 17 00:00:00 2001 From: granny Date: Fri, 16 Feb 2024 01:45:03 -0800 Subject: [PATCH 30/53] convert layer interval properly --- .../main/java/net/pl3x/map/core/markers/layer/CustomLayer.java | 2 +- core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/CustomLayer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/CustomLayer.java index 3496f1edd..b04f860ad 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/CustomLayer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/CustomLayer.java @@ -67,7 +67,7 @@ public static void load(World world, Path path) { public static @NotNull CustomLayer fromJson(@NotNull World world, @NotNull JsonObject obj) { JsonElement el; CustomLayer layer = new CustomLayer(obj.get("key").getAsString(), world, () -> obj.get("label").getAsString()); - if ((el = obj.get("updateInterval")) != null && !(el instanceof JsonNull)) layer.setUpdateInterval(el.getAsInt(), true); + if ((el = obj.get("updateInterval")) != null && !(el instanceof JsonNull)) layer.setUpdateInterval(el.getAsInt()); if ((el = obj.get("showControls")) != null && !(el instanceof JsonNull)) layer.setShowControls(el.getAsBoolean()); if ((el = obj.get("defaultHidden")) != null && !(el instanceof JsonNull)) layer.setDefaultHidden(el.getAsBoolean()); if ((el = obj.get("priority")) != null && !(el instanceof JsonNull)) layer.setPriority(el.getAsInt()); diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java index 1072bc500..adce9292c 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java @@ -280,7 +280,7 @@ public int getPriority() { JsonObjectWrapper wrapper = new JsonObjectWrapper(); wrapper.addProperty("key", getKey()); wrapper.addProperty("label", getLabel()); - wrapper.addProperty("updateInterval", getUpdateInterval(true)); + wrapper.addProperty("updateInterval", getUpdateInterval()); wrapper.addProperty("showControls", shouldShowControls()); wrapper.addProperty("defaultHidden", isDefaultHidden()); wrapper.addProperty("priority", getPriority()); From d11f85fcfd0abf8247e50b54b072cd690670ef32 Mon Sep 17 00:00:00 2001 From: granny Date: Thu, 29 Feb 2024 15:05:11 -0800 Subject: [PATCH 31/53] global and per-world sse endpoints --- .../net/pl3x/map/core/httpd/HttpdServer.java | 66 +++++++++++++++++-- .../core/renderer/task/UpdateMarkerData.java | 2 +- .../java/net/pl3x/map/core/world/World.java | 8 +++ webmap/src/Pl3xMap.ts | 20 +----- webmap/src/layergroup/MarkerLayer.ts | 21 +++++- webmap/src/world/World.ts | 27 ++++++++ 6 files changed, 115 insertions(+), 29 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java b/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java index 35f5fdf10..a2b36e9f5 100644 --- a/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java +++ b/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java @@ -27,6 +27,7 @@ import io.undertow.Undertow; import io.undertow.UndertowLogger; import io.undertow.UndertowOptions; +import io.undertow.server.HttpServerExchange; import io.undertow.server.handlers.resource.PathResourceManager; import io.undertow.server.handlers.resource.ResourceHandler; import io.undertow.server.handlers.resource.ResourceManager; @@ -34,31 +35,44 @@ import io.undertow.server.handlers.sse.ServerSentEventHandler; import io.undertow.util.ETag; import io.undertow.util.Headers; +import io.undertow.util.StatusCodes; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; +import java.util.stream.Collectors; +import net.pl3x.map.core.Pl3xMap; import net.pl3x.map.core.configuration.Config; import net.pl3x.map.core.configuration.Lang; import net.pl3x.map.core.log.LogFilter; import net.pl3x.map.core.log.Logger; +import net.pl3x.map.core.registry.WorldRegistry; import net.pl3x.map.core.util.FileUtil; +import net.pl3x.map.core.world.World; public class HttpdServer { private Undertow server; private ServerSentEventHandler serverSentEventHandler = Handlers.serverSentEvents(); - public void sendSSE(String event, String data) { + public void sendSSE(ServerSentEventHandler serverSentEventHandler, String event, String data) { for (ServerSentEventConnection connection : serverSentEventHandler.getConnections()) { connection.send(data, event, null, null); } } + public void sendSSE(ServerSentEventHandler serverSentEventHandler, String data) { + sendSSE(serverSentEventHandler, null, data); + } + + public void sendSSE(String event, String data) { + sendSSE(this.serverSentEventHandler, event, data); + } + public void sendSSE(String data) { - sendSSE(null, data); + sendSSE(this.serverSentEventHandler, null, data); } - public void closeSSEConnections() { + public void closeSSEConnections(ServerSentEventHandler serverSentEventHandler) { for (ServerSentEventConnection connection : serverSentEventHandler.getConnections()) { connection.shutdown(); } @@ -101,8 +115,38 @@ public void startServer() { this.server = Undertow.builder() .setServerOption(UndertowOptions.ENABLE_HTTP2, true) .addHttpListener(Config.HTTPD_PORT, Config.HTTPD_BIND) - .setHandler(Handlers.path() - .addPrefixPath("/", exchange -> { + .setHandler( + Handlers.path(exchange -> { + // TODO: clean up before merging into main + if (exchange.getRelativePath().startsWith("/sse")) { + String[] split = exchange.getRelativePath().split("/"); + if (split.length <= 2) { + serverSentEventHandler.handleRequest(exchange); + return; + } + String worldName = split[2]; + + WorldRegistry worldRegistry = Pl3xMap.api().getWorldRegistry(); + World world = worldRegistry.get(worldName); + if (world == null || split.length > 3) { + handleError(exchange, + "Could not find world named '%s'.\n Available worlds: %s" + .formatted( + split.length > 3 ? exchange.getRelativePath().split("/sse/")[1] : worldName, + worldRegistry.values().stream().map(World::getName).collect(Collectors.joining(", ")) + ) + ); + return; + } + + if (exchange.isInIoThread()) { + exchange.dispatch(world.getServerSentEventHandler()); + } else { + world.getServerSentEventHandler().handleRequest(exchange); + } + return; + } + if (exchange.getRelativePath().startsWith("/tiles")) { exchange.getResponseHeaders().put(Headers.CACHE_CONTROL, "max-age=0, must-revalidate, no-cache"); } @@ -112,7 +156,6 @@ public void startServer() { } resourceHandler.handleRequest(exchange); }) - .addExactPath("/sse", serverSentEventHandler) ) .build(); this.server.start(); @@ -128,6 +171,12 @@ public void startServer() { } } + private void handleError(HttpServerExchange exchange, String errorMessage) { + exchange.setStatusCode(StatusCodes.NOT_FOUND); + exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "application/json"); + exchange.getResponseSender().send("{\"error\": \"" + errorMessage + "\"}"); + } + public void stopServer() { if (!Config.HTTPD_ENABLED) { return; @@ -139,7 +188,10 @@ public void stopServer() { } LogFilter.HIDE_UNDERTOW_LOGS = true; - this.closeSSEConnections(); + this.closeSSEConnections(this.serverSentEventHandler); + Pl3xMap.api().getWorldRegistry().forEach(world -> { + this.closeSSEConnections(world.getServerSentEventHandler()); + }); this.server.stop(); LogFilter.HIDE_UNDERTOW_LOGS = false; diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java index 007fd41e7..eea6260b5 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java @@ -116,7 +116,7 @@ private void parseLayers() { String json = this.gson.toJson(list); String markerCacheIfPresent = markerCache.getIfPresent(this.world.getKey() + "|" + key); if (markerCacheIfPresent == null || !markerCacheIfPresent.equals(json)) { - Pl3xMap.api().getHttpdServer().sendSSE("markers", String.format("{ \"world\": \"%s\", \"key\": \"%s\", \"markers\": %s}", this.world.getName(), key, json)); + Pl3xMap.api().getHttpdServer().sendSSE(world.getServerSentEventHandler(), "markers", String.format("{\"key\": \"%s\", \"markers\": %s}", key, json)); markerCache.put(this.world.getKey() + "|" + key, json); } diff --git a/core/src/main/java/net/pl3x/map/core/world/World.java b/core/src/main/java/net/pl3x/map/core/world/World.java index c89b16d0f..be045801b 100644 --- a/core/src/main/java/net/pl3x/map/core/world/World.java +++ b/core/src/main/java/net/pl3x/map/core/world/World.java @@ -25,6 +25,8 @@ import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.LoadingCache; +import io.undertow.Handlers; +import io.undertow.server.handlers.sse.ServerSentEventHandler; import java.io.IOException; import java.nio.file.FileSystems; import java.nio.file.Files; @@ -78,6 +80,7 @@ public abstract class World extends Keyed { private final long seed; private final Point spawn; private final Type type; + private final ServerSentEventHandler serverSentEventHandler; private final BiomeManager biomeManager; private final BiomeRegistry biomeRegistry; @@ -95,6 +98,7 @@ public World(@NotNull String name, long seed, @NotNull Point spawn, @NotNull Typ this.seed = seed; this.spawn = spawn; this.type = type; + this.serverSentEventHandler = Handlers.serverSentEvents(); String safeNameForDirectories = name.replace(":", "-"); @@ -251,6 +255,10 @@ public int getSkylight() { return this.type; } + public ServerSentEventHandler getServerSentEventHandler() { + return serverSentEventHandler; + } + public @NotNull BiomeManager getBiomeManager() { return this.biomeManager; } diff --git a/webmap/src/Pl3xMap.ts b/webmap/src/Pl3xMap.ts index fd09b8654..76253c292 100644 --- a/webmap/src/Pl3xMap.ts +++ b/webmap/src/Pl3xMap.ts @@ -71,7 +71,7 @@ export class Pl3xMap { } private update(): void { - if (this.eventSource !== undefined && this.eventSource.readyState !== EventSource.CLOSED && (new Date()).getTime() - this._timestamp < 1000) { + if (this._eventSource?.readyState === EventSource.OPEN && (new Date()).getTime() - this._timestamp < 1000) { this._timer = setTimeout(() => this.update(), 1000); return; } @@ -87,24 +87,6 @@ export class Pl3xMap { private initSSE(): EventSource { const eventSource = new EventSource("sse"); - eventSource.addEventListener("markers", (ev: Event) => { - this._timestamp = (new Date()).getTime(); - const messageEvent = (ev as MessageEvent); - const json: any = JSON.parse(messageEvent.data); - const world = this._worldManager.getWorld(json.world); - const key: string = json.key; - const markers: any[] = json.markers; - - if (world === undefined) return; - - if (messageEvent.data.length === 0) return; - - world.markerLayers.forEach(layer => { - if (layer.key !== key) return; - layer.updateMarkers(markers, world); - }); - }); - eventSource.addEventListener("settings", (ev: Event) => { this._timestamp = (new Date()).getTime(); const messageEvent = (ev as MessageEvent); diff --git a/webmap/src/layergroup/MarkerLayer.ts b/webmap/src/layergroup/MarkerLayer.ts index 53ec600cd..58969f3b9 100644 --- a/webmap/src/layergroup/MarkerLayer.ts +++ b/webmap/src/layergroup/MarkerLayer.ts @@ -47,6 +47,7 @@ export class MarkerLayer extends L.LayerGroup { private readonly _markers: Map = new Map(); + private _timestamp: number = (new Date()).getTime(); private _timer: NodeJS.Timeout | undefined; constructor(key: string, label: string, interval: number, showControls: boolean, defaultHidden: boolean, priority: number, zIndex: number, pane: string, css: string) { @@ -114,9 +115,24 @@ export class MarkerLayer extends L.LayerGroup { return this._css; } + get timestamp(): number { + return this._timestamp; + } + + set timestamp(timestamp: number) { + this._timestamp = timestamp; + } + update(world: World, updateOverride?: boolean): void { - if (!updateOverride && Pl3xMap.instance.eventSource !== undefined && Pl3xMap.instance.eventSource.readyState !== EventSource.CLOSED && (new Date()).getTime() - Pl3xMap.instance.timestamp < 1000) { - return; + if (updateOverride === undefined) { + let time = (new Date()).getTime() - this._timestamp; + // console.log(world.eventSource?.readyState); + // console.log(`${this._key}: world.eventSource?.readyState === EventSource.OPEN is ${world.eventSource?.readyState === EventSource.OPEN}`); + // console.log(`${this._key}: time (${time}) < 1000 is ${time < 1000}`); + if (world.eventSource?.readyState === EventSource.OPEN && time < 1000) { + // console.log(this._key + ": source is open and timestamp is " + time + " which is less than 1000"); + return; + } } getJSON(`tiles/${world.name}/markers/${this._key}.json`) @@ -124,6 +140,7 @@ export class MarkerLayer extends L.LayerGroup { } updateMarkers(json: any, world: World): void { + // console.log(`updating ${this._key} with update interval of ${this._updateInterval}`); //this.clearLayers(); // do not just clear markers, remove the ones that are missing const toRemove: Set = new Set(this._markers.keys()); diff --git a/webmap/src/world/World.ts b/webmap/src/world/World.ts index fabb82780..cf6f727f3 100644 --- a/webmap/src/world/World.ts +++ b/webmap/src/world/World.ts @@ -25,6 +25,8 @@ export class World { private _loaded: boolean = false; + private _eventSource?: EventSource; + private _timer: NodeJS.Timeout | undefined; constructor(pl3xmap: Pl3xMap, worldManager: WorldManager, settings: WorldSettings) { @@ -32,6 +34,25 @@ export class World { this._settings = settings; } + private initSSE() { + this._eventSource = new EventSource("sse/" + this.settings.name); + + this._eventSource.addEventListener("markers", (ev: Event) => { + const messageEvent = (ev as MessageEvent); + const json: any = JSON.parse(messageEvent.data); + const key: string = json.key; + const markers: any[] = json.markers; + + if (messageEvent.data.length === 0) return; + + this._markerLayers.forEach(layer => { + if (layer.key !== key) return; + layer.timestamp = (new Date()).getTime(); + layer.updateMarkers(markers, this); + }); + }); + } + public load(): Promise { if (this._loaded) { return Promise.resolve(this); @@ -71,6 +92,7 @@ export class World { public unload(): void { clearTimeout(this._timer); // unload and clear markers + this._eventSource?.close(); this._markerLayers.forEach((layer: MarkerLayer) => layer.unload()) this._markerLayers = []; // unload renderer layer @@ -80,6 +102,7 @@ export class World { } public loadMarkers(): void { + this.initSSE(); getJSON(`tiles/${this.name}/markers.json`) .then((json): void => { (json as MarkerLayer[]).forEach((layer: MarkerLayer): void => { @@ -209,6 +232,10 @@ export class World { return this._biomePalette; } + get eventSource(): EventSource | undefined { + return this._eventSource; + } + get background(): string { switch (this.type) { case "nether": From 9dbf851903d854ee127897a546af6e8127f48e5c Mon Sep 17 00:00:00 2001 From: granny Date: Thu, 29 Feb 2024 15:09:12 -0800 Subject: [PATCH 32/53] add live update toggle to layers --- .../pl3x/map/core/markers/layer/Layer.java | 21 +++++++++++++++++++ .../map/core/markers/layer/PlayersLayer.java | 1 + .../map/core/markers/layer/SpawnLayer.java | 2 +- .../core/markers/layer/WorldBorderLayer.java | 2 +- .../core/renderer/task/UpdateMarkerData.java | 17 +++++++++------ 5 files changed, 35 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java index adce9292c..3925fe1c4 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java @@ -49,6 +49,7 @@ public abstract class Layer extends Keyed implements JsonSerializable { private Integer zIndex = 99; private String pane; private String css; + private boolean liveUpdate = false; /** * Create a layer. @@ -269,6 +270,26 @@ public int getPriority() { return this; } + /** + * Get if this layer gets pushed through sse. + * + * @return true if being sent through sse + */ + public @Nullable boolean isLiveUpdate() { + return this.liveUpdate; + } + + /** + * Set whether to push this layer through sse. + * + * @param liveUpdate true to push this layer through sse. + * @return this layer + */ + public @NotNull Layer setLiveUpdate(@Nullable boolean liveUpdate) { + this.liveUpdate = liveUpdate; + return this; + } + /** * Get the markers to display in this Layer. * diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/PlayersLayer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/PlayersLayer.java index 6aef5b399..bb90f1486 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/PlayersLayer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/PlayersLayer.java @@ -66,6 +66,7 @@ public PlayersLayer(@NotNull World world) { setZIndex(PlayersLayerConfig.Z_INDEX); setPane(PlayersLayerConfig.PANE); setCss(PlayersLayerConfig.CSS); + setLiveUpdate(true); } /** diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java index ea2416bec..ad01a685e 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java @@ -36,7 +36,6 @@ import net.pl3x.map.core.markers.option.Options; import net.pl3x.map.core.markers.option.Tooltip; import net.pl3x.map.core.util.FileUtil; -import net.pl3x.map.core.util.TickUtil; import net.pl3x.map.core.world.World; import org.jetbrains.annotations.NotNull; @@ -71,6 +70,7 @@ public SpawnLayer(@NotNull World world) { setDefaultHidden(SpawnLayerConfig.DEFAULT_HIDDEN); setPriority(SpawnLayerConfig.PRIORITY); setZIndex(SpawnLayerConfig.Z_INDEX); + setLiveUpdate(true); String tooltip = getLabel(); if (!tooltip.isBlank()) { diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java index 56ca355ea..0e5ef9d9a 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java @@ -34,7 +34,6 @@ import net.pl3x.map.core.markers.option.Options; import net.pl3x.map.core.markers.option.Tooltip; import net.pl3x.map.core.util.Colors; -import net.pl3x.map.core.util.TickUtil; import net.pl3x.map.core.world.World; import org.jetbrains.annotations.NotNull; @@ -58,6 +57,7 @@ public WorldBorderLayer(@NotNull World world) { setDefaultHidden(WorldBorderLayerConfig.DEFAULT_HIDDEN); setPriority(WorldBorderLayerConfig.PRIORITY); setZIndex(WorldBorderLayerConfig.Z_INDEX); + setLiveUpdate(true); setOptions(Options.builder() .strokeColor(Colors.fromHex(WorldBorderLayerConfig.STROKE_COLOR)) .strokeWeight(WorldBorderLayerConfig.STROKE_WEIGHT) diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java index eea6260b5..f9d061f87 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java @@ -112,15 +112,20 @@ private void parseLayers() { long now = System.currentTimeMillis(); long lastUpdated = this.lastUpdated.getOrDefault(key, 0L); - List> list = new ArrayList<>(layer.getMarkers()); - String json = this.gson.toJson(list); - String markerCacheIfPresent = markerCache.getIfPresent(this.world.getKey() + "|" + key); - if (markerCacheIfPresent == null || !markerCacheIfPresent.equals(json)) { - Pl3xMap.api().getHttpdServer().sendSSE(world.getServerSentEventHandler(), "markers", String.format("{\"key\": \"%s\", \"markers\": %s}", key, json)); - markerCache.put(this.world.getKey() + "|" + key, json); + List> list = null; + if (layer.isLiveUpdate()) { + list = new ArrayList<>(layer.getMarkers()); + String json = this.gson.toJson(list); + String markerCacheIfPresent = markerCache.getIfPresent(this.world.getKey() + "|" + key); + if (markerCacheIfPresent == null || !markerCacheIfPresent.equals(json)) { + Pl3xMap.api().getHttpdServer().sendSSE(world.getServerSentEventHandler(), "markers", String.format("{\"key\": \"%s\", \"markers\": %s}", key, json)); + markerCache.put(this.world.getKey() + "|" + key, json); + } } if (now - lastUpdated > Math.max(TickUtil.toMilliseconds(layer.getUpdateInterval()), 1000)) { + list = list == null ? new ArrayList<>(layer.getMarkers()) : list; + String json = this.gson.toJson(list); FileUtil.writeJson(json, this.world.getMarkersDirectory().resolve(key.replace(":", "-") + ".json")); this.lastUpdated.put(key, now); } From 39314f825028d6417ba1f639b0c728102d723b1f Mon Sep 17 00:00:00 2001 From: granny Date: Thu, 29 Feb 2024 15:20:34 -0800 Subject: [PATCH 33/53] filter disabled worlds from sse endpoint --- core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java b/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java index a2b36e9f5..3f1e4e45d 100644 --- a/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java +++ b/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java @@ -128,12 +128,14 @@ public void startServer() { WorldRegistry worldRegistry = Pl3xMap.api().getWorldRegistry(); World world = worldRegistry.get(worldName); - if (world == null || split.length > 3) { + if (world == null || world.isEnabled() || split.length > 3) { handleError(exchange, "Could not find world named '%s'.\n Available worlds: %s" .formatted( split.length > 3 ? exchange.getRelativePath().split("/sse/")[1] : worldName, - worldRegistry.values().stream().map(World::getName).collect(Collectors.joining(", ")) + worldRegistry.values().stream() + .filter(World::isEnabled) + .map(World::getName).collect(Collectors.joining(", ")) ) ); return; From be311b49d48fefd8568805d6a00710cabfb0f74f Mon Sep 17 00:00:00 2001 From: granny Date: Thu, 29 Feb 2024 15:38:08 -0800 Subject: [PATCH 34/53] remove newline from custom http error message --- core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java b/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java index 3f1e4e45d..965a15770 100644 --- a/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java +++ b/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java @@ -130,7 +130,7 @@ public void startServer() { World world = worldRegistry.get(worldName); if (world == null || world.isEnabled() || split.length > 3) { handleError(exchange, - "Could not find world named '%s'.\n Available worlds: %s" + "Could not find world named '%s'. Available worlds: %s" .formatted( split.length > 3 ? exchange.getRelativePath().split("/sse/")[1] : worldName, worldRegistry.values().stream() From f08aef011fb6fd2effcb801a372b767d5453a694 Mon Sep 17 00:00:00 2001 From: granny Date: Thu, 29 Feb 2024 16:26:20 -0800 Subject: [PATCH 35/53] add `settings.layer.live-update` to built-in layers --- .../net/pl3x/map/core/configuration/PlayersLayerConfig.java | 4 ++++ .../net/pl3x/map/core/configuration/SpawnLayerConfig.java | 4 ++++ .../pl3x/map/core/configuration/WorldBorderLayerConfig.java | 4 ++++ .../java/net/pl3x/map/core/markers/layer/PlayersLayer.java | 1 + .../main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java | 1 + .../net/pl3x/map/core/markers/layer/WorldBorderLayer.java | 1 + 6 files changed, 15 insertions(+) diff --git a/core/src/main/java/net/pl3x/map/core/configuration/PlayersLayerConfig.java b/core/src/main/java/net/pl3x/map/core/configuration/PlayersLayerConfig.java index 8900a42a8..d0586d2fa 100644 --- a/core/src/main/java/net/pl3x/map/core/configuration/PlayersLayerConfig.java +++ b/core/src/main/java/net/pl3x/map/core/configuration/PlayersLayerConfig.java @@ -53,6 +53,10 @@ public final class PlayersLayerConfig extends AbstractConfig { How often to update the marker. Setting to 0 is the same as setting it to 1.""") public static int UPDATE_INTERVAL = 0; + @Key("settings.layer.live-update") + @Comment(""" + Whether to push this layer through SSE or not.""") + public static boolean LIVE_UPDATE = true; @Key("settings.layer.show-controls") @Comment(""" Whether the players layer control shows up in the layers list or not.""") diff --git a/core/src/main/java/net/pl3x/map/core/configuration/SpawnLayerConfig.java b/core/src/main/java/net/pl3x/map/core/configuration/SpawnLayerConfig.java index 66879272c..572e77338 100644 --- a/core/src/main/java/net/pl3x/map/core/configuration/SpawnLayerConfig.java +++ b/core/src/main/java/net/pl3x/map/core/configuration/SpawnLayerConfig.java @@ -41,6 +41,10 @@ public final class SpawnLayerConfig extends AbstractConfig { How often to update the marker. Setting to 0 is the same as setting it to 1.""") public static int UPDATE_INTERVAL = 30; + @Key("settings.layer.live-update") + @Comment(""" + Whether to push this layer through SSE or not.""") + public static boolean LIVE_UPDATE = true; @Key("settings.layer.show-controls") @Comment(""" Whether the spawn layer control shows up in the layers list or not.""") diff --git a/core/src/main/java/net/pl3x/map/core/configuration/WorldBorderLayerConfig.java b/core/src/main/java/net/pl3x/map/core/configuration/WorldBorderLayerConfig.java index 8f0b89798..345908c5a 100644 --- a/core/src/main/java/net/pl3x/map/core/configuration/WorldBorderLayerConfig.java +++ b/core/src/main/java/net/pl3x/map/core/configuration/WorldBorderLayerConfig.java @@ -42,6 +42,10 @@ public final class WorldBorderLayerConfig extends AbstractConfig { How often to update the marker. Setting to 0 is the same as setting it to 1.""") public static int UPDATE_INTERVAL = 30; + @Key("settings.layer.live-update") + @Comment(""" + Whether to push this layer through SSE or not.""") + public static boolean LIVE_UPDATE = true; @Key("settings.layer.show-controls") @Comment(""" Whether the vanilla world border layer control shows up in the layers list or not.""") diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/PlayersLayer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/PlayersLayer.java index bb90f1486..5ad3fbdec 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/PlayersLayer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/PlayersLayer.java @@ -60,6 +60,7 @@ public class PlayersLayer extends WorldLayer { public PlayersLayer(@NotNull World world) { this(KEY, world, () -> Lang.UI_LAYER_PLAYERS); setUpdateInterval(PlayersLayerConfig.UPDATE_INTERVAL, PlayersLayerConfig.UPDATE_INTERVAL_IN_TICKS); + setLiveUpdate(PlayersLayerConfig.LIVE_UPDATE); setShowControls(PlayersLayerConfig.SHOW_CONTROLS); setDefaultHidden(PlayersLayerConfig.DEFAULT_HIDDEN); setPriority(PlayersLayerConfig.PRIORITY); diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java index ad01a685e..50846c3e8 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java @@ -66,6 +66,7 @@ public SpawnLayer(@NotNull World world) { } setUpdateInterval(SpawnLayerConfig.UPDATE_INTERVAL, SpawnLayerConfig.UPDATE_INTERVAL_IN_TICKS); + setLiveUpdate(SpawnLayerConfig.LIVE_UPDATE); setShowControls(SpawnLayerConfig.SHOW_CONTROLS); setDefaultHidden(SpawnLayerConfig.DEFAULT_HIDDEN); setPriority(SpawnLayerConfig.PRIORITY); diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java index 0e5ef9d9a..2b5d76e39 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java @@ -53,6 +53,7 @@ public class WorldBorderLayer extends WorldLayer { public WorldBorderLayer(@NotNull World world) { this(KEY, world, () -> Lang.UI_LAYER_WORLDBORDER); setUpdateInterval(WorldBorderLayerConfig.UPDATE_INTERVAL, WorldBorderLayerConfig.UPDATE_INTERVAL_IN_TICKS); + setLiveUpdate(WorldBorderLayerConfig.LIVE_UPDATE); setShowControls(WorldBorderLayerConfig.SHOW_CONTROLS); setDefaultHidden(WorldBorderLayerConfig.DEFAULT_HIDDEN); setPriority(WorldBorderLayerConfig.PRIORITY); From 2bcf638ac8a95c7be4e14d5ddf3e5c0751f02a07 Mon Sep 17 00:00:00 2001 From: granny Date: Thu, 29 Feb 2024 16:34:03 -0800 Subject: [PATCH 36/53] remove `settings.layer.update-interval-in-ticks` --- .../configuration/PlayersLayerConfig.java | 19 +------------------ .../core/configuration/SpawnLayerConfig.java | 7 +------ .../configuration/WorldBorderLayerConfig.java | 7 +------ .../map/core/markers/layer/PlayersLayer.java | 2 +- .../map/core/markers/layer/SpawnLayer.java | 2 +- .../core/markers/layer/WorldBorderLayer.java | 2 +- 6 files changed, 6 insertions(+), 33 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/configuration/PlayersLayerConfig.java b/core/src/main/java/net/pl3x/map/core/configuration/PlayersLayerConfig.java index d0586d2fa..0178a210f 100644 --- a/core/src/main/java/net/pl3x/map/core/configuration/PlayersLayerConfig.java +++ b/core/src/main/java/net/pl3x/map/core/configuration/PlayersLayerConfig.java @@ -44,14 +44,9 @@ public final class PlayersLayerConfig extends AbstractConfig { Should spectators be hidden from the map.""") public static boolean HIDE_SPECTATORS = true; - @Key("settings.layer.update-interval-in-ticks") - @Comment(""" - Treat the update-interval option's value as ticks instead of seconds.""") - public static boolean UPDATE_INTERVAL_IN_TICKS = true; @Key("settings.layer.update-interval") @Comment(""" - How often to update the marker. - Setting to 0 is the same as setting it to 1.""") + How often (in seconds) to update the marker.""") public static int UPDATE_INTERVAL = 0; @Key("settings.layer.live-update") @Comment(""" @@ -161,16 +156,4 @@ Whether the players layer should be hidden (toggled off) by default.""") public static void reload() { CONFIG.reload(Pl3xMap.api().getMainDir().resolve("layers/players.yml"), PlayersLayerConfig.class); } - - @Override - protected @Nullable Object getValue(@NotNull String path, @Nullable Object def) { - // assume that if the ticks option doesn't exist but the interval option does, - // then it's safe to set ticks option to false to keep backwards compatibility - if (path.contains("update-interval-in-ticks") - && getConfig().get(path) == null - && getConfig().get("settings.layer.update-interval") != null) { - return super.getValue(path, false); - } - return super.getValue(path, def); - } } diff --git a/core/src/main/java/net/pl3x/map/core/configuration/SpawnLayerConfig.java b/core/src/main/java/net/pl3x/map/core/configuration/SpawnLayerConfig.java index 572e77338..edc56b5b4 100644 --- a/core/src/main/java/net/pl3x/map/core/configuration/SpawnLayerConfig.java +++ b/core/src/main/java/net/pl3x/map/core/configuration/SpawnLayerConfig.java @@ -32,14 +32,9 @@ public final class SpawnLayerConfig extends AbstractConfig { Show spawn icon on the map.""") public static boolean ENABLED = true; - @Key("settings.layer.update-interval-in-ticks") - @Comment(""" - Treat the update-interval option as ticks instead of seconds.""") - public static boolean UPDATE_INTERVAL_IN_TICKS = false; @Key("settings.layer.update-interval") @Comment(""" - How often to update the marker. - Setting to 0 is the same as setting it to 1.""") + How often (in seconds) to update the marker.""") public static int UPDATE_INTERVAL = 30; @Key("settings.layer.live-update") @Comment(""" diff --git a/core/src/main/java/net/pl3x/map/core/configuration/WorldBorderLayerConfig.java b/core/src/main/java/net/pl3x/map/core/configuration/WorldBorderLayerConfig.java index 345908c5a..9fa92e96e 100644 --- a/core/src/main/java/net/pl3x/map/core/configuration/WorldBorderLayerConfig.java +++ b/core/src/main/java/net/pl3x/map/core/configuration/WorldBorderLayerConfig.java @@ -33,14 +33,9 @@ public final class WorldBorderLayerConfig extends AbstractConfig { Shows vanilla world border on the map.""") public static boolean ENABLED = true; - @Key("settings.layer.update-interval-in-ticks") - @Comment(""" - Treat the update-interval option as ticks instead of seconds.""") - public static boolean UPDATE_INTERVAL_IN_TICKS = false; @Key("settings.layer.update-interval") @Comment(""" - How often to update the marker. - Setting to 0 is the same as setting it to 1.""") + How often (in seconds) to update the marker.""") public static int UPDATE_INTERVAL = 30; @Key("settings.layer.live-update") @Comment(""" diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/PlayersLayer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/PlayersLayer.java index 5ad3fbdec..a67d67dc3 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/PlayersLayer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/PlayersLayer.java @@ -59,7 +59,7 @@ public class PlayersLayer extends WorldLayer { */ public PlayersLayer(@NotNull World world) { this(KEY, world, () -> Lang.UI_LAYER_PLAYERS); - setUpdateInterval(PlayersLayerConfig.UPDATE_INTERVAL, PlayersLayerConfig.UPDATE_INTERVAL_IN_TICKS); + setUpdateInterval(PlayersLayerConfig.UPDATE_INTERVAL); setLiveUpdate(PlayersLayerConfig.LIVE_UPDATE); setShowControls(PlayersLayerConfig.SHOW_CONTROLS); setDefaultHidden(PlayersLayerConfig.DEFAULT_HIDDEN); diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java index 50846c3e8..17ed529c2 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java @@ -65,7 +65,7 @@ public SpawnLayer(@NotNull World world) { throw new RuntimeException(e); } - setUpdateInterval(SpawnLayerConfig.UPDATE_INTERVAL, SpawnLayerConfig.UPDATE_INTERVAL_IN_TICKS); + setUpdateInterval(SpawnLayerConfig.UPDATE_INTERVAL); setLiveUpdate(SpawnLayerConfig.LIVE_UPDATE); setShowControls(SpawnLayerConfig.SHOW_CONTROLS); setDefaultHidden(SpawnLayerConfig.DEFAULT_HIDDEN); diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java index 2b5d76e39..a735a705f 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java @@ -52,7 +52,7 @@ public class WorldBorderLayer extends WorldLayer { */ public WorldBorderLayer(@NotNull World world) { this(KEY, world, () -> Lang.UI_LAYER_WORLDBORDER); - setUpdateInterval(WorldBorderLayerConfig.UPDATE_INTERVAL, WorldBorderLayerConfig.UPDATE_INTERVAL_IN_TICKS); + setUpdateInterval(WorldBorderLayerConfig.UPDATE_INTERVAL); setLiveUpdate(WorldBorderLayerConfig.LIVE_UPDATE); setShowControls(WorldBorderLayerConfig.SHOW_CONTROLS); setDefaultHidden(WorldBorderLayerConfig.DEFAULT_HIDDEN); From 31c145bd61ba33c3a0160fded57ee93b3563585e Mon Sep 17 00:00:00 2001 From: granny Date: Thu, 29 Feb 2024 22:30:49 -0800 Subject: [PATCH 37/53] [chore] remove duplicate calls --- .../main/java/net/pl3x/map/core/markers/layer/PlayersLayer.java | 1 - .../main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java | 1 - .../java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java | 1 - 3 files changed, 3 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/PlayersLayer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/PlayersLayer.java index a67d67dc3..c4ca32573 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/PlayersLayer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/PlayersLayer.java @@ -67,7 +67,6 @@ public PlayersLayer(@NotNull World world) { setZIndex(PlayersLayerConfig.Z_INDEX); setPane(PlayersLayerConfig.PANE); setCss(PlayersLayerConfig.CSS); - setLiveUpdate(true); } /** diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java index 17ed529c2..e27635a0c 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java @@ -71,7 +71,6 @@ public SpawnLayer(@NotNull World world) { setDefaultHidden(SpawnLayerConfig.DEFAULT_HIDDEN); setPriority(SpawnLayerConfig.PRIORITY); setZIndex(SpawnLayerConfig.Z_INDEX); - setLiveUpdate(true); String tooltip = getLabel(); if (!tooltip.isBlank()) { diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java index a735a705f..753d27818 100644 --- a/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java +++ b/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java @@ -58,7 +58,6 @@ public WorldBorderLayer(@NotNull World world) { setDefaultHidden(WorldBorderLayerConfig.DEFAULT_HIDDEN); setPriority(WorldBorderLayerConfig.PRIORITY); setZIndex(WorldBorderLayerConfig.Z_INDEX); - setLiveUpdate(true); setOptions(Options.builder() .strokeColor(Colors.fromHex(WorldBorderLayerConfig.STROKE_COLOR)) .strokeWeight(WorldBorderLayerConfig.STROKE_WEIGHT) From 3ef690e16d203ee6a5b7dd2c5f22e640fc187777 Mon Sep 17 00:00:00 2001 From: granny Date: Mon, 4 Mar 2024 01:43:15 -0800 Subject: [PATCH 38/53] separate the live updating into it's own task --- .../pl3x/map/core/registry/WorldRegistry.java | 1 + .../core/renderer/task/AbstractDataTask.java | 107 ++++++++++++++++++ .../core/renderer/task/UpdateLiveData.java | 92 +++++++++++++++ .../core/renderer/task/UpdateMarkerData.java | 83 +------------- .../java/net/pl3x/map/core/world/World.java | 10 ++ 5 files changed, 216 insertions(+), 77 deletions(-) create mode 100644 core/src/main/java/net/pl3x/map/core/renderer/task/AbstractDataTask.java create mode 100644 core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java diff --git a/core/src/main/java/net/pl3x/map/core/registry/WorldRegistry.java b/core/src/main/java/net/pl3x/map/core/registry/WorldRegistry.java index a1c58694e..732ea5e6c 100644 --- a/core/src/main/java/net/pl3x/map/core/registry/WorldRegistry.java +++ b/core/src/main/java/net/pl3x/map/core/registry/WorldRegistry.java @@ -46,6 +46,7 @@ public class WorldRegistry extends Registry<@NotNull World> { if (world != null) { Pl3xMap.api().getEventRegistry().callEvent(new WorldUnloadedEvent(world)); world.getMarkerTask().cancel(); + world.getLiveDataTask().cancel(); //world.getRegionFileWatcher().stop(); world.cleanup(); } diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/AbstractDataTask.java b/core/src/main/java/net/pl3x/map/core/renderer/task/AbstractDataTask.java new file mode 100644 index 000000000..5664d8ea7 --- /dev/null +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/AbstractDataTask.java @@ -0,0 +1,107 @@ +/* + * MIT License + * + * Copyright (c) 2020-2023 William Blake Galbreath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.pl3x.map.core.renderer.task; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import net.pl3x.map.core.Pl3xMap; +import net.pl3x.map.core.markers.JsonObjectWrapper; +import net.pl3x.map.core.markers.marker.Marker; +import net.pl3x.map.core.scheduler.Task; +import net.pl3x.map.core.world.World; +import org.jetbrains.annotations.NotNull; + +public abstract class AbstractDataTask extends Task { + protected final Gson gson = new GsonBuilder() + //.setPrettyPrinting() + .disableHtmlEscaping() + .serializeNulls() + .setLenient() + .registerTypeHierarchyAdapter(Marker.class, new Adapter()) + .create(); + + protected final World world; + protected final Map<@NotNull String, @NotNull Long> lastUpdated = new HashMap<>(); + protected final ExecutorService executor; + + protected CompletableFuture future; + protected boolean running; + + public AbstractDataTask(int delay, boolean repeat, World world, String serviceName, int threads) { + super(delay, repeat); + this.world = world; + this.executor = Pl3xMap.ThreadFactory.createService(serviceName, threads); + } + + public AbstractDataTask(int delay, boolean repeat, World world, String serviceName) { + super(delay, repeat); + this.world = world; + this.executor = Pl3xMap.ThreadFactory.createService(serviceName); + } + + @Override + public void run() { + if (this.running) { + return; + } + this.running = true; + this.future = CompletableFuture.runAsync(() -> { + try { + parse(); + } catch (Throwable t) { + t.printStackTrace(); + } + this.running = false; + }, this.executor); + } + + @Override + public void cancel() { + super.cancel(); + if (this.future != null) { + this.future.cancel(true); + } + } + + public abstract void parse(); + + protected static class Adapter implements JsonSerializer<@NotNull Marker> { + @Override + public @NotNull JsonElement serialize(@NotNull Marker marker, @NotNull Type type, @NotNull JsonSerializationContext context) { + JsonObjectWrapper wrapper = new JsonObjectWrapper(); + wrapper.addProperty("type", marker.getType()); + wrapper.addProperty("data", marker); + wrapper.addProperty("options", marker.getOptions()); + return wrapper.getJsonObject(); + } + } +} \ No newline at end of file diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java new file mode 100644 index 000000000..32868d8bb --- /dev/null +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java @@ -0,0 +1,92 @@ +/* + * MIT License + * + * Copyright (c) 2020-2023 William Blake Galbreath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.pl3x.map.core.renderer.task; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import net.pl3x.map.core.Pl3xMap; +import net.pl3x.map.core.log.Logger; +import net.pl3x.map.core.markers.layer.Layer; +import net.pl3x.map.core.markers.marker.Marker; +import net.pl3x.map.core.world.World; +import org.jetbrains.annotations.NotNull; + +public class UpdateLiveData extends AbstractDataTask { + private final Cache<@NotNull String, String> markerCache = CacheBuilder.newBuilder() + .maximumSize(1000) + .expireAfterWrite(1, TimeUnit.MINUTES) + .build(); + private Map> liveUpdateFutures; + + public UpdateLiveData(@NotNull World world) { + super(1, true, world, "Pl3xMap-LiveData", 2); + this.liveUpdateFutures = new HashMap<>(); + } + + @Override + public void cancel() { + super.cancel(); + this.liveUpdateFutures.forEach((key, future) -> future.cancel(true)); + this.liveUpdateFutures.clear(); + } + + @Override + public void parse() { + this.world.getLayerRegistry().entrySet().forEach(entry -> { + String key = entry.getKey(); + Layer layer = entry.getValue(); + + if (!layer.isLiveUpdate()) { + return; + } + + CompletableFuture future = liveUpdateFutures.get(key); + if (future != null && !future.isDone()) { + return; + } + + this.liveUpdateFutures.put(key, CompletableFuture.runAsync(() -> { + try { + String json = this.gson.toJson(new ArrayList>(layer.getMarkers())); + String markerCacheIfPresent = markerCache.getIfPresent(key); + if (markerCacheIfPresent == null || !markerCacheIfPresent.equals(json)) { + Logger.debug("[%s/%s] sending through sse".formatted(this.world.getName(), key)); + Pl3xMap.api().getHttpdServer().sendSSE(world.getServerSentEventHandler(), "markers", String.format("{\"key\": \"%s\", \"markers\": %s}", key, json)); + markerCache.put(key, json); + } + } catch (Throwable t) { + Logger.debug("[%s/%s] failed".formatted(this.world.getName(), key)); + t.printStackTrace(); + } finally { + this.liveUpdateFutures.remove(key); + } + }, this.executor)); + }); + } +} diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java index f9d061f87..849e23c00 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java @@ -49,58 +49,13 @@ import net.pl3x.map.core.world.World; import org.jetbrains.annotations.NotNull; -public class UpdateMarkerData extends Task { - private final Gson gson = new GsonBuilder() - //.setPrettyPrinting() - .disableHtmlEscaping() - .serializeNulls() - .setLenient() - .registerTypeHierarchyAdapter(Marker.class, new Adapter()) - .create(); - - private final World world; - private final Map<@NotNull String, @NotNull Long> lastUpdated = new HashMap<>(); - private final Cache<@NotNull String, String> markerCache = CacheBuilder.newBuilder() - .maximumSize(1000) - .expireAfterWrite(1, TimeUnit.MINUTES) - .build(); - private final ExecutorService executor; - - private CompletableFuture future; - private boolean running; - private int fileTick; - +public class UpdateMarkerData extends AbstractDataTask { public UpdateMarkerData(@NotNull World world) { - super(1, true); - this.world = world; - this.executor = Pl3xMap.ThreadFactory.createService("Pl3xMap-Markers"); - } - - @Override - public void run() { - if (this.running) { - return; - } - this.running = true; - this.future = CompletableFuture.runAsync(() -> { - try { - parseLayers(); - } catch (Throwable t) { - t.printStackTrace(); - } - this.running = false; - }, this.executor); + super(TickUtil.toTicks(1), true, world, "Pl3xMap-Markers"); } @Override - public void cancel() { - super.cancel(); - if (this.future != null) { - this.future.cancel(true); - } - } - - private void parseLayers() { + public void parse() { List layers = new ArrayList<>(); this.world.getLayerRegistry().entrySet().forEach(entry -> { @@ -112,21 +67,9 @@ private void parseLayers() { long now = System.currentTimeMillis(); long lastUpdated = this.lastUpdated.getOrDefault(key, 0L); - List> list = null; - if (layer.isLiveUpdate()) { - list = new ArrayList<>(layer.getMarkers()); - String json = this.gson.toJson(list); - String markerCacheIfPresent = markerCache.getIfPresent(this.world.getKey() + "|" + key); - if (markerCacheIfPresent == null || !markerCacheIfPresent.equals(json)) { - Pl3xMap.api().getHttpdServer().sendSSE(world.getServerSentEventHandler(), "markers", String.format("{\"key\": \"%s\", \"markers\": %s}", key, json)); - markerCache.put(this.world.getKey() + "|" + key, json); - } - } - if (now - lastUpdated > Math.max(TickUtil.toMilliseconds(layer.getUpdateInterval()), 1000)) { - list = list == null ? new ArrayList<>(layer.getMarkers()) : list; - String json = this.gson.toJson(list); - FileUtil.writeJson(json, this.world.getMarkersDirectory().resolve(key.replace(":", "-") + ".json")); + List> list = new ArrayList<>(layer.getMarkers()); + FileUtil.writeJson(this.gson.toJson(list), this.world.getMarkersDirectory().resolve(key.replace(":", "-") + ".json")); this.lastUpdated.put(key, now); } } catch (Throwable t) { @@ -134,20 +77,6 @@ private void parseLayers() { } }); - if (fileTick++ >= 20) { - fileTick = 0; - FileUtil.writeJson(this.gson.toJson(layers), this.world.getTilesDirectory().resolve("markers.json")); - } - } - - private static class Adapter implements JsonSerializer<@NotNull Marker> { - @Override - public @NotNull JsonElement serialize(@NotNull Marker marker, @NotNull Type type, @NotNull JsonSerializationContext context) { - JsonObjectWrapper wrapper = new JsonObjectWrapper(); - wrapper.addProperty("type", marker.getType()); - wrapper.addProperty("data", marker); - wrapper.addProperty("options", marker.getOptions()); - return wrapper.getJsonObject(); - } + FileUtil.writeJson(this.gson.toJson(layers), this.world.getTilesDirectory().resolve("markers.json")); } } diff --git a/core/src/main/java/net/pl3x/map/core/world/World.java b/core/src/main/java/net/pl3x/map/core/world/World.java index be045801b..aa1cfc4f0 100644 --- a/core/src/main/java/net/pl3x/map/core/world/World.java +++ b/core/src/main/java/net/pl3x/map/core/world/World.java @@ -60,6 +60,7 @@ import net.pl3x.map.core.registry.BiomeRegistry; import net.pl3x.map.core.registry.Registry; import net.pl3x.map.core.renderer.Renderer; +import net.pl3x.map.core.renderer.task.UpdateLiveData; import net.pl3x.map.core.renderer.task.UpdateMarkerData; import net.pl3x.map.core.util.FileUtil; import net.pl3x.map.core.util.Mathf; @@ -90,6 +91,7 @@ public abstract class World extends Keyed { private final RegionModifiedState regionModifiedState; //private final RegionFileWatcher regionFileWatcher; private final UpdateMarkerData markerTask; + private final UpdateLiveData liveDataTask; private final Map<@NotNull String, Renderer.@NotNull Builder> renderers = new LinkedHashMap<>(); public World(@NotNull String name, long seed, @NotNull Point spawn, @NotNull Type type, @NotNull Path regionDirectory) { @@ -126,6 +128,7 @@ public World(@NotNull String name, long seed, @NotNull Point spawn, @NotNull Typ this.regionModifiedState = new RegionModifiedState(this); //this.regionFileWatcher = new RegionFileWatcher(this); this.markerTask = new UpdateMarkerData(this); + this.liveDataTask = new UpdateLiveData(this); } protected void init() { @@ -173,6 +176,9 @@ protected void init() { Logger.debug("Starting marker task"); Pl3xMap.api().getScheduler().addTask(this.markerTask); + Logger.debug("Starting live data task"); + Pl3xMap.api().getScheduler().addTask(this.liveDataTask); + // load up custom markers Logger.debug("Loading custom markers for " + getName()); for (Path file : getCustomMarkerFiles()) { @@ -217,6 +223,10 @@ public void cleanup() { return this.markerTask; } + public @NotNull UpdateLiveData getLiveDataTask() { + return this.liveDataTask; + } + public @NotNull Map<@NotNull String, Renderer.@NotNull Builder> getRenderers() { return Collections.unmodifiableMap(this.renderers); } From b7ede6ea06a0122bd442809c7c5f8bc0513b7cd7 Mon Sep 17 00:00:00 2001 From: granny Date: Mon, 4 Mar 2024 03:48:37 -0800 Subject: [PATCH 39/53] flip enabled world check in sse endpoint --- core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java b/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java index 965a15770..a5b6f377d 100644 --- a/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java +++ b/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java @@ -128,7 +128,7 @@ public void startServer() { WorldRegistry worldRegistry = Pl3xMap.api().getWorldRegistry(); World world = worldRegistry.get(worldName); - if (world == null || world.isEnabled() || split.length > 3) { + if (world == null || !world.isEnabled() || split.length > 3) { handleError(exchange, "Could not find world named '%s'. Available worlds: %s" .formatted( From 6f22b534057bff095c7071e1032aa7310ef14cbd Mon Sep 17 00:00:00 2001 From: granny Date: Mon, 4 Mar 2024 03:58:58 -0800 Subject: [PATCH 40/53] comment out a debug log --- .../java/net/pl3x/map/core/renderer/task/UpdateLiveData.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java index 32868d8bb..e544344ce 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java @@ -76,7 +76,7 @@ public void parse() { String json = this.gson.toJson(new ArrayList>(layer.getMarkers())); String markerCacheIfPresent = markerCache.getIfPresent(key); if (markerCacheIfPresent == null || !markerCacheIfPresent.equals(json)) { - Logger.debug("[%s/%s] sending through sse".formatted(this.world.getName(), key)); + //Logger.debug("[%s/%s] sending through sse".formatted(this.world.getName(), key)); Pl3xMap.api().getHttpdServer().sendSSE(world.getServerSentEventHandler(), "markers", String.format("{\"key\": \"%s\", \"markers\": %s}", key, json)); markerCache.put(key, json); } From c37a45bec8ab0b7bc7f09e94ce1413c7ddeb3a9f Mon Sep 17 00:00:00 2001 From: granny Date: Mon, 4 Mar 2024 04:00:03 -0800 Subject: [PATCH 41/53] [chore] remove unused imports --- .../core/renderer/task/UpdateMarkerData.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java index 849e23c00..cd9905a2b 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateMarkerData.java @@ -23,27 +23,10 @@ */ package net.pl3x.map.core.renderer.task; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonElement; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; -import java.lang.reflect.Type; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.TimeUnit; -import net.pl3x.map.core.Pl3xMap; -import net.pl3x.map.core.log.Logger; -import net.pl3x.map.core.markers.JsonObjectWrapper; import net.pl3x.map.core.markers.layer.Layer; import net.pl3x.map.core.markers.marker.Marker; -import net.pl3x.map.core.scheduler.Task; import net.pl3x.map.core.util.FileUtil; import net.pl3x.map.core.util.TickUtil; import net.pl3x.map.core.world.World; From dbc44e6247d54b568e96e72cf788b8db06cc6a59 Mon Sep 17 00:00:00 2001 From: granny Date: Tue, 5 Mar 2024 05:02:14 -0800 Subject: [PATCH 42/53] cache marker hashcodes instead of stringified json object --- .../map/core/renderer/task/UpdateLiveData.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java index e544344ce..7d7e7fb80 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java @@ -26,7 +26,9 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @@ -38,7 +40,7 @@ import org.jetbrains.annotations.NotNull; public class UpdateLiveData extends AbstractDataTask { - private final Cache<@NotNull String, String> markerCache = CacheBuilder.newBuilder() + private final Cache<@NotNull String, Integer> markerCache = CacheBuilder.newBuilder() .maximumSize(1000) .expireAfterWrite(1, TimeUnit.MINUTES) .build(); @@ -73,12 +75,13 @@ public void parse() { this.liveUpdateFutures.put(key, CompletableFuture.runAsync(() -> { try { - String json = this.gson.toJson(new ArrayList>(layer.getMarkers())); - String markerCacheIfPresent = markerCache.getIfPresent(key); - if (markerCacheIfPresent == null || !markerCacheIfPresent.equals(json)) { + List> list = new ArrayList<>(layer.getMarkers()); + Integer markerCacheIfPresent = markerCache.getIfPresent(key); + int markerHashCode = list.hashCode(); + if (markerCacheIfPresent == null || !markerCacheIfPresent.equals(markerHashCode)) { //Logger.debug("[%s/%s] sending through sse".formatted(this.world.getName(), key)); - Pl3xMap.api().getHttpdServer().sendSSE(world.getServerSentEventHandler(), "markers", String.format("{\"key\": \"%s\", \"markers\": %s}", key, json)); - markerCache.put(key, json); + Pl3xMap.api().getHttpdServer().sendSSE(world.getServerSentEventHandler(), "markers", String.format("{\"key\": \"%s\", \"markers\": %s}", key, this.gson.toJson(list))); + markerCache.put(key, markerHashCode); } } catch (Throwable t) { Logger.debug("[%s/%s] failed".formatted(this.world.getName(), key)); From 905170ee7d4a9dea24d589bded11c6d9ef3b8256 Mon Sep 17 00:00:00 2001 From: granny Date: Tue, 5 Mar 2024 06:13:33 -0800 Subject: [PATCH 43/53] clean up sse route logic --- .../net/pl3x/map/core/httpd/HttpdServer.java | 53 +++++++++---------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java b/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java index a5b6f377d..c41f85669 100644 --- a/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java +++ b/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java @@ -40,6 +40,8 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; +import java.util.Deque; +import java.util.Map; import java.util.stream.Collectors; import net.pl3x.map.core.Pl3xMap; import net.pl3x.map.core.configuration.Config; @@ -116,28 +118,33 @@ public void startServer() { .setServerOption(UndertowOptions.ENABLE_HTTP2, true) .addHttpListener(Config.HTTPD_PORT, Config.HTTPD_BIND) .setHandler( - Handlers.path(exchange -> { - // TODO: clean up before merging into main - if (exchange.getRelativePath().startsWith("/sse")) { - String[] split = exchange.getRelativePath().split("/"); - if (split.length <= 2) { + Handlers.path(exchange -> { + if (exchange.getRelativePath().startsWith("/tiles")) { + exchange.getResponseHeaders().put(Headers.CACHE_CONTROL, "max-age=0, must-revalidate, no-cache"); + } + if (exchange.getRelativePath().endsWith(".gz")) { + exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "application/json"); + exchange.getResponseHeaders().put(Headers.CONTENT_ENCODING, "gzip"); + } + resourceHandler.handleRequest(exchange); + }) + .addPrefixPath("/sse", + Handlers.pathTemplate() + .add("{world}", exchange -> { + String worldName = exchange.getQueryParameters().get("world").peek(); + if (worldName == null || worldName.isEmpty()) { serverSentEventHandler.handleRequest(exchange); return; } - String worldName = split[2]; WorldRegistry worldRegistry = Pl3xMap.api().getWorldRegistry(); World world = worldRegistry.get(worldName); - if (world == null || !world.isEnabled() || split.length > 3) { - handleError(exchange, - "Could not find world named '%s'. Available worlds: %s" - .formatted( - split.length > 3 ? exchange.getRelativePath().split("/sse/")[1] : worldName, - worldRegistry.values().stream() - .filter(World::isEnabled) - .map(World::getName).collect(Collectors.joining(", ")) - ) - ); + if (world == null || !world.isEnabled()) { + String listOfValidWorlds = worldRegistry.values().stream() + .filter(World::isEnabled) + .map(World::getName).collect(Collectors.joining(", ")); + handleError(exchange, "Could not find world named '%s'. Available worlds: %s" + .formatted(worldName, listOfValidWorlds)); return; } @@ -146,18 +153,8 @@ public void startServer() { } else { world.getServerSentEventHandler().handleRequest(exchange); } - return; - } - - if (exchange.getRelativePath().startsWith("/tiles")) { - exchange.getResponseHeaders().put(Headers.CACHE_CONTROL, "max-age=0, must-revalidate, no-cache"); - } - if (exchange.getRelativePath().endsWith(".gz")) { - exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "application/json"); - exchange.getResponseHeaders().put(Headers.CONTENT_ENCODING, "gzip"); - } - resourceHandler.handleRequest(exchange); - }) + }) + ) ) .build(); this.server.start(); From 37004dea6bdc2b7e6807ac5d0d828f68625e5350 Mon Sep 17 00:00:00 2001 From: granny Date: Tue, 5 Mar 2024 06:21:51 -0800 Subject: [PATCH 44/53] [chore] remove unused imports & add newline at eof --- core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java | 2 -- .../java/net/pl3x/map/core/renderer/task/AbstractDataTask.java | 2 +- .../java/net/pl3x/map/core/renderer/task/UpdateLiveData.java | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java b/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java index c41f85669..31cef67ca 100644 --- a/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java +++ b/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java @@ -40,8 +40,6 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; -import java.util.Deque; -import java.util.Map; import java.util.stream.Collectors; import net.pl3x.map.core.Pl3xMap; import net.pl3x.map.core.configuration.Config; diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/AbstractDataTask.java b/core/src/main/java/net/pl3x/map/core/renderer/task/AbstractDataTask.java index 5664d8ea7..9a3d02e97 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/AbstractDataTask.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/AbstractDataTask.java @@ -104,4 +104,4 @@ protected static class Adapter implements JsonSerializer<@NotNull Marker> { return wrapper.getJsonObject(); } } -} \ No newline at end of file +} diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java index 7d7e7fb80..d731f2469 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java @@ -26,7 +26,6 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; From 42a15d6db05700432524822644030513adce97be Mon Sep 17 00:00:00 2001 From: granny Date: Sat, 9 Mar 2024 02:23:27 -0800 Subject: [PATCH 45/53] specify buffering header for nginx users --- core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java b/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java index 31cef67ca..dbd8d1532 100644 --- a/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java +++ b/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java @@ -35,6 +35,7 @@ import io.undertow.server.handlers.sse.ServerSentEventHandler; import io.undertow.util.ETag; import io.undertow.util.Headers; +import io.undertow.util.HttpString; import io.undertow.util.StatusCodes; import java.io.IOException; import java.nio.file.Files; @@ -51,6 +52,7 @@ import net.pl3x.map.core.world.World; public class HttpdServer { + private HttpString X_ACCEL_BUFFERING = new HttpString("X-Accel-Buffering"); private Undertow server; private ServerSentEventHandler serverSentEventHandler = Handlers.serverSentEvents(); @@ -131,6 +133,7 @@ public void startServer() { .add("{world}", exchange -> { String worldName = exchange.getQueryParameters().get("world").peek(); if (worldName == null || worldName.isEmpty()) { + exchange.getResponseHeaders().put(X_ACCEL_BUFFERING, "no"); serverSentEventHandler.handleRequest(exchange); return; } @@ -149,6 +152,7 @@ public void startServer() { if (exchange.isInIoThread()) { exchange.dispatch(world.getServerSentEventHandler()); } else { + exchange.getResponseHeaders().put(X_ACCEL_BUFFERING, "no"); world.getServerSentEventHandler().handleRequest(exchange); } }) From fbfdad626e9a8931211b71b7995ee3d4a3210445 Mon Sep 17 00:00:00 2001 From: granny Date: Thu, 14 Mar 2024 20:20:48 -0700 Subject: [PATCH 46/53] make codefactor happy --- webmap/src/layergroup/MarkerLayer.ts | 2 +- webmap/src/sidebar/PlayersTab.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/webmap/src/layergroup/MarkerLayer.ts b/webmap/src/layergroup/MarkerLayer.ts index 58969f3b9..f5f82cc0c 100644 --- a/webmap/src/layergroup/MarkerLayer.ts +++ b/webmap/src/layergroup/MarkerLayer.ts @@ -125,7 +125,7 @@ export class MarkerLayer extends L.LayerGroup { update(world: World, updateOverride?: boolean): void { if (updateOverride === undefined) { - let time = (new Date()).getTime() - this._timestamp; + const time = (new Date()).getTime() - this._timestamp; // console.log(world.eventSource?.readyState); // console.log(`${this._key}: world.eventSource?.readyState === EventSource.OPEN is ${world.eventSource?.readyState === EventSource.OPEN}`); // console.log(`${this._key}: time (${time}) < 1000 is ${time < 1000}`); diff --git a/webmap/src/sidebar/PlayersTab.ts b/webmap/src/sidebar/PlayersTab.ts index 637508780..edb79fc3c 100644 --- a/webmap/src/sidebar/PlayersTab.ts +++ b/webmap/src/sidebar/PlayersTab.ts @@ -1,7 +1,7 @@ import * as L from "leaflet"; import {Pl3xMap} from "../Pl3xMap"; import {Player} from "../player/Player"; -import {createSVGIcon, handleKeyboardEvent, isset} from "../util/Util"; +import {createSVGIcon, handleKeyboardEvent} from "../util/Util"; import BaseTab from "./BaseTab"; import '../svg/players.svg'; import {Lang} from "../settings/Lang"; From e7407d72b75a56cd8487fd4f09c36fb1435b725b Mon Sep 17 00:00:00 2001 From: granny Date: Thu, 14 Mar 2024 20:22:16 -0700 Subject: [PATCH 47/53] add temporary debug logs --- .../java/net/pl3x/map/core/renderer/task/UpdateLiveData.java | 2 +- webmap/src/world/World.ts | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java index d731f2469..e03b11bc4 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java @@ -78,7 +78,7 @@ public void parse() { Integer markerCacheIfPresent = markerCache.getIfPresent(key); int markerHashCode = list.hashCode(); if (markerCacheIfPresent == null || !markerCacheIfPresent.equals(markerHashCode)) { - //Logger.debug("[%s/%s] sending through sse".formatted(this.world.getName(), key)); + Logger.debug("[%s/%s] sending through sse %d".formatted(this.world.getName(), key, (System.currentTimeMillis()))); Pl3xMap.api().getHttpdServer().sendSSE(world.getServerSentEventHandler(), "markers", String.format("{\"key\": \"%s\", \"markers\": %s}", key, this.gson.toJson(list))); markerCache.put(key, markerHashCode); } diff --git a/webmap/src/world/World.ts b/webmap/src/world/World.ts index cf6f727f3..1a19dd3d3 100644 --- a/webmap/src/world/World.ts +++ b/webmap/src/world/World.ts @@ -36,12 +36,14 @@ export class World { private initSSE() { this._eventSource = new EventSource("sse/" + this.settings.name); + console.debug("initializing " + this.settings.name + " sse"); this._eventSource.addEventListener("markers", (ev: Event) => { const messageEvent = (ev as MessageEvent); const json: any = JSON.parse(messageEvent.data); const key: string = json.key; const markers: any[] = json.markers; + console.debug(json); if (messageEvent.data.length === 0) return; @@ -93,6 +95,7 @@ export class World { clearTimeout(this._timer); // unload and clear markers this._eventSource?.close(); + console.debug("closing " + this.settings.name + " sse"); this._markerLayers.forEach((layer: MarkerLayer) => layer.unload()) this._markerLayers = []; // unload renderer layer From 3e82eb56d57c23e699f4da6945ad03281b58d3c1 Mon Sep 17 00:00:00 2001 From: granny Date: Thu, 14 Mar 2024 21:20:47 -0700 Subject: [PATCH 48/53] remove unused imports --- .../net/pl3x/map/core/configuration/PlayersLayerConfig.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/configuration/PlayersLayerConfig.java b/core/src/main/java/net/pl3x/map/core/configuration/PlayersLayerConfig.java index 0178a210f..81380d5d9 100644 --- a/core/src/main/java/net/pl3x/map/core/configuration/PlayersLayerConfig.java +++ b/core/src/main/java/net/pl3x/map/core/configuration/PlayersLayerConfig.java @@ -24,8 +24,6 @@ package net.pl3x.map.core.configuration; import net.pl3x.map.core.Pl3xMap; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; @SuppressWarnings("CanBeFinal") public final class PlayersLayerConfig extends AbstractConfig { From d183c66d343128173dba7a8e9310b79b56b16633 Mon Sep 17 00:00:00 2001 From: Andrzej Bansleben <64475360+jedrek0429@users.noreply.github.com> Date: Fri, 5 Apr 2024 20:02:35 +0200 Subject: [PATCH 49/53] Make thread count configurable (#36) --- .../main/java/net/pl3x/map/core/configuration/Config.java | 6 ++++++ .../net/pl3x/map/core/renderer/task/UpdateLiveData.java | 4 ++-- core/src/main/java/net/pl3x/map/core/world/World.java | 3 ++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/configuration/Config.java b/core/src/main/java/net/pl3x/map/core/configuration/Config.java index a0c4a2cae..88ee80025 100644 --- a/core/src/main/java/net/pl3x/map/core/configuration/Config.java +++ b/core/src/main/java/net/pl3x/map/core/configuration/Config.java @@ -118,6 +118,12 @@ How many scroll pixels (as reported by L.DomEvent.getWheelDelta) mean for security reasons. But you do you, boo boo.""") public static boolean HTTPD_FOLLOW_SYMLINKS = false; + @Key("settings.performance.live-update-threads") + @Comment(""" + The number of process-threads to use for real-time marker updates on the map. + Value of -1 will use 50% of the available cpu-threads. (recommended)""") + public static int LIVE_UPDATE_THREADS = -1; + @Key("settings.performance.render-threads") @Comment(""" The number of process-threads to use for loading and scanning chunks. diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java index e03b11bc4..794fcc22c 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java @@ -45,8 +45,8 @@ public class UpdateLiveData extends AbstractDataTask { .build(); private Map> liveUpdateFutures; - public UpdateLiveData(@NotNull World world) { - super(1, true, world, "Pl3xMap-LiveData", 2); + public UpdateLiveData(@NotNull World world, int threads) { + super(1, true, world, "Pl3xMap-LiveData", threads); this.liveUpdateFutures = new HashMap<>(); } diff --git a/core/src/main/java/net/pl3x/map/core/world/World.java b/core/src/main/java/net/pl3x/map/core/world/World.java index aa1cfc4f0..7fc4e7145 100644 --- a/core/src/main/java/net/pl3x/map/core/world/World.java +++ b/core/src/main/java/net/pl3x/map/core/world/World.java @@ -43,6 +43,7 @@ import javax.imageio.ImageIO; import net.pl3x.map.core.Keyed; import net.pl3x.map.core.Pl3xMap; +import net.pl3x.map.core.configuration.Config; import net.pl3x.map.core.configuration.PlayersLayerConfig; import net.pl3x.map.core.configuration.SpawnLayerConfig; import net.pl3x.map.core.configuration.WorldBorderLayerConfig; @@ -128,7 +129,7 @@ public World(@NotNull String name, long seed, @NotNull Point spawn, @NotNull Typ this.regionModifiedState = new RegionModifiedState(this); //this.regionFileWatcher = new RegionFileWatcher(this); this.markerTask = new UpdateMarkerData(this); - this.liveDataTask = new UpdateLiveData(this); + this.liveDataTask = new UpdateLiveData(this, Config.LIVE_UPDATE_THREADS); } protected void init() { From 20d1ad919168727504bfa8bc63fc5e9436c3feaa Mon Sep 17 00:00:00 2001 From: granny Date: Fri, 12 Apr 2024 02:26:11 -0700 Subject: [PATCH 50/53] cache hashcode instead of string --- .../net/pl3x/map/core/renderer/task/UpdateSettingsData.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java index 47b0d3e1e..d1d544693 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java @@ -50,7 +50,7 @@ public class UpdateSettingsData extends Task { .serializeNulls() .setLenient() .create(); - private String cachedJsonData = ""; + private int jsonHashCache = -1; public UpdateSettingsData() { super(1, true); @@ -163,9 +163,9 @@ private void parseSettings() { String json = this.gson.toJson(map); - if (!cachedJsonData.equals(json)) { + if (jsonHashCache != json.hashCode()) { Pl3xMap.api().getHttpdServer().sendSSE("settings", json); - cachedJsonData = json; + jsonHashCache = json.hashCode(); } if (fileTick++ >= 20) { From ade62c7c4613e9a19bd288345557362afb1f220c Mon Sep 17 00:00:00 2001 From: granny Date: Fri, 12 Apr 2024 05:09:23 -0700 Subject: [PATCH 51/53] wrap ServerSentEventHandler class --- .../net/pl3x/map/core/httpd/HttpdServer.java | 39 ++--- .../pl3x/map/core/httpd/LiveDataHandler.java | 150 ++++++++++++++++++ .../core/renderer/task/UpdateLiveData.java | 2 +- .../renderer/task/UpdateSettingsData.java | 2 +- .../java/net/pl3x/map/core/world/World.java | 13 +- 5 files changed, 168 insertions(+), 38 deletions(-) create mode 100644 core/src/main/java/net/pl3x/map/core/httpd/LiveDataHandler.java diff --git a/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java b/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java index e621e0f5c..1423a3409 100644 --- a/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java +++ b/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java @@ -31,8 +31,6 @@ import io.undertow.server.handlers.resource.PathResourceManager; import io.undertow.server.handlers.resource.ResourceHandler; import io.undertow.server.handlers.resource.ResourceManager; -import io.undertow.server.handlers.sse.ServerSentEventConnection; -import io.undertow.server.handlers.sse.ServerSentEventHandler; import io.undertow.util.ETag; import io.undertow.util.Headers; import io.undertow.util.HttpString; @@ -54,30 +52,10 @@ public class HttpdServer { private HttpString X_ACCEL_BUFFERING = new HttpString("X-Accel-Buffering"); private Undertow server; - private ServerSentEventHandler serverSentEventHandler = Handlers.serverSentEvents(); + private LiveDataHandler liveDataHandler = new LiveDataHandler(); - public void sendSSE(ServerSentEventHandler serverSentEventHandler, String event, String data) { - for (ServerSentEventConnection connection : serverSentEventHandler.getConnections()) { - connection.send(data, event, null, null); - } - } - - public void sendSSE(ServerSentEventHandler serverSentEventHandler, String data) { - sendSSE(serverSentEventHandler, null, data); - } - - public void sendSSE(String event, String data) { - sendSSE(this.serverSentEventHandler, event, data); - } - - public void sendSSE(String data) { - sendSSE(this.serverSentEventHandler, null, data); - } - - public void closeSSEConnections(ServerSentEventHandler serverSentEventHandler) { - for (ServerSentEventConnection connection : serverSentEventHandler.getConnections()) { - connection.shutdown(); - } + public LiveDataHandler getLiveDataHandler() { + return liveDataHandler; } public void startServer() { @@ -134,7 +112,7 @@ public void startServer() { String worldName = exchange.getQueryParameters().get("world").peek(); if (worldName == null || worldName.isEmpty()) { exchange.getResponseHeaders().put(X_ACCEL_BUFFERING, "no"); - serverSentEventHandler.handleRequest(exchange); + liveDataHandler.handle(exchange); return; } @@ -146,14 +124,15 @@ public void startServer() { .map(World::getName).collect(Collectors.joining(", ")); handleError(exchange, "Could not find world named '%s'. Available worlds: %s" .formatted(worldName, listOfValidWorlds)); + exchange.endExchange(); return; } if (exchange.isInIoThread()) { - exchange.dispatch(world.getServerSentEventHandler()); + exchange.dispatch(world.getServerSentEventHandler().get()); } else { exchange.getResponseHeaders().put(X_ACCEL_BUFFERING, "no"); - world.getServerSentEventHandler().handleRequest(exchange); + world.getServerSentEventHandler().handle(exchange); } }) ) @@ -189,9 +168,9 @@ public void stopServer() { } LogFilter.HIDE_UNDERTOW_LOGS = true; - this.closeSSEConnections(this.serverSentEventHandler); + this.liveDataHandler.closeConnections(); Pl3xMap.api().getWorldRegistry().forEach(world -> { - this.closeSSEConnections(world.getServerSentEventHandler()); + world.getServerSentEventHandler().closeConnections(); }); this.server.stop(); LogFilter.HIDE_UNDERTOW_LOGS = false; diff --git a/core/src/main/java/net/pl3x/map/core/httpd/LiveDataHandler.java b/core/src/main/java/net/pl3x/map/core/httpd/LiveDataHandler.java new file mode 100644 index 000000000..8e873a68a --- /dev/null +++ b/core/src/main/java/net/pl3x/map/core/httpd/LiveDataHandler.java @@ -0,0 +1,150 @@ +/* + * MIT License + * + * Copyright (c) 2020-2023 William Blake Galbreath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.pl3x.map.core.httpd; + +import io.undertow.Handlers; +import io.undertow.server.HttpServerExchange; +import io.undertow.server.handlers.sse.ServerSentEventConnection; +import io.undertow.server.handlers.sse.ServerSentEventHandler; +import java.io.IOException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class LiveDataHandler { + private ServerSentEventHandler serverSentEventHandler; + + public LiveDataHandler() { + this.serverSentEventHandler = Handlers.serverSentEvents(); + } + + /** + * + * @param event The message event + * @param data The message data + * @param success The callback that is called when a message is sucessfully sent. + * @param failure The callback that is called when a message send fails. + */ + public void send(String event, String data, SuccessCallback success, FailureCallback failure) { + if (serverSentEventHandler == null) { + return; + } + + Callback callback = new Callback(success, failure); + for (ServerSentEventConnection connection : this.serverSentEventHandler.getConnections()) { + connection.send(data, event, null, callback); + } + } + + /** + * + * @param event The message event + * @param data The message data + * @param success The callback that is called when a message is sucessfully sent. + */ + public void send(String event, String data, SuccessCallback success) { + this.send(event, data, success, null); + } + + /** + * + * @param event The message event + * @param data The message data + */ + public void send(String event, String data) { + this.send(event, data, null, null); + } + + /** + * + * @param data The message data + */ + public void send(String data) { + this.send(null, data); + } + + public void closeConnections() { + for (ServerSentEventConnection connection : serverSentEventHandler.getConnections()) { + connection.shutdown(); + } + } + + public void handle(HttpServerExchange exchange) throws Exception { + this.serverSentEventHandler.handleRequest(exchange); + } + + public ServerSentEventHandler get() { + return this.serverSentEventHandler; + } + + /** + * Notification that is called when a message is sucessfully sent + */ + public interface SuccessCallback { + /** + * @param connection The connection + * @param data The message data + * @param event The message event + * @param id The message id + */ + void apply(@NotNull ServerSentEventConnection connection, @Nullable String data, @Nullable String event, @Nullable String id); + } + + /** + * Notification that is called when a message send fails. + */ + public interface FailureCallback { + /** + * @param connection The connection + * @param data The message data + * @param event The message event + * @param id The message id + * @param exception The exception + */ + void apply(@NotNull ServerSentEventConnection connection, @Nullable String data, @Nullable String event, @Nullable String id, @NotNull IOException exception); + } + + private class Callback implements ServerSentEventConnection.EventCallback { + private SuccessCallback success; + private FailureCallback failure; + + public Callback(SuccessCallback success, FailureCallback failure) { + this.success = success; + this.failure = failure; + } + + @Override + public void done(ServerSentEventConnection connection, String data, String event, String id) { + if (success != null) { + success.apply(connection, data, event, id); + } + } + + @Override + public void failed(ServerSentEventConnection connection, String data, String event, String id, IOException e) { + if (failure != null) { + failure.apply(connection, data, event, id, e); + } + } + } +} diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java index 794fcc22c..b50f15aa3 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateLiveData.java @@ -79,7 +79,7 @@ public void parse() { int markerHashCode = list.hashCode(); if (markerCacheIfPresent == null || !markerCacheIfPresent.equals(markerHashCode)) { Logger.debug("[%s/%s] sending through sse %d".formatted(this.world.getName(), key, (System.currentTimeMillis()))); - Pl3xMap.api().getHttpdServer().sendSSE(world.getServerSentEventHandler(), "markers", String.format("{\"key\": \"%s\", \"markers\": %s}", key, this.gson.toJson(list))); + world.getServerSentEventHandler().send("markers", String.format("{\"key\": \"%s\", \"markers\": %s}", key, this.gson.toJson(list))); markerCache.put(key, markerHashCode); } } catch (Throwable t) { diff --git a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java index d1d544693..76e4a42a7 100644 --- a/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java +++ b/core/src/main/java/net/pl3x/map/core/renderer/task/UpdateSettingsData.java @@ -164,7 +164,7 @@ private void parseSettings() { String json = this.gson.toJson(map); if (jsonHashCache != json.hashCode()) { - Pl3xMap.api().getHttpdServer().sendSSE("settings", json); + Pl3xMap.api().getHttpdServer().getLiveDataHandler().send("settings", json); jsonHashCache = json.hashCode(); } diff --git a/core/src/main/java/net/pl3x/map/core/world/World.java b/core/src/main/java/net/pl3x/map/core/world/World.java index 7fc4e7145..d20f71943 100644 --- a/core/src/main/java/net/pl3x/map/core/world/World.java +++ b/core/src/main/java/net/pl3x/map/core/world/World.java @@ -25,8 +25,6 @@ import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.LoadingCache; -import io.undertow.Handlers; -import io.undertow.server.handlers.sse.ServerSentEventHandler; import java.io.IOException; import java.nio.file.FileSystems; import java.nio.file.Files; @@ -48,6 +46,7 @@ import net.pl3x.map.core.configuration.SpawnLayerConfig; import net.pl3x.map.core.configuration.WorldBorderLayerConfig; import net.pl3x.map.core.configuration.WorldConfig; +import net.pl3x.map.core.httpd.LiveDataHandler; import net.pl3x.map.core.image.IconImage; import net.pl3x.map.core.log.Logger; import net.pl3x.map.core.markers.Point; @@ -82,7 +81,8 @@ public abstract class World extends Keyed { private final long seed; private final Point spawn; private final Type type; - private final ServerSentEventHandler serverSentEventHandler; + + private final LiveDataHandler liveDataHandler; private final BiomeManager biomeManager; private final BiomeRegistry biomeRegistry; @@ -101,7 +101,8 @@ public World(@NotNull String name, long seed, @NotNull Point spawn, @NotNull Typ this.seed = seed; this.spawn = spawn; this.type = type; - this.serverSentEventHandler = Handlers.serverSentEvents(); + + this.liveDataHandler = new LiveDataHandler(); String safeNameForDirectories = name.replace(":", "-"); @@ -266,8 +267,8 @@ public int getSkylight() { return this.type; } - public ServerSentEventHandler getServerSentEventHandler() { - return serverSentEventHandler; + public LiveDataHandler getServerSentEventHandler() { + return liveDataHandler; } public @NotNull BiomeManager getBiomeManager() { From 5e3ffccb0eb7038fd597d42c1b675043e81b0209 Mon Sep 17 00:00:00 2001 From: granny Date: Fri, 12 Apr 2024 05:53:31 -0700 Subject: [PATCH 52/53] label SAM interfaces with annotations --- core/src/main/java/net/pl3x/map/core/httpd/LiveDataHandler.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/main/java/net/pl3x/map/core/httpd/LiveDataHandler.java b/core/src/main/java/net/pl3x/map/core/httpd/LiveDataHandler.java index 8e873a68a..9130ad52b 100644 --- a/core/src/main/java/net/pl3x/map/core/httpd/LiveDataHandler.java +++ b/core/src/main/java/net/pl3x/map/core/httpd/LiveDataHandler.java @@ -100,6 +100,7 @@ public ServerSentEventHandler get() { /** * Notification that is called when a message is sucessfully sent */ + @FunctionalInterface public interface SuccessCallback { /** * @param connection The connection @@ -113,6 +114,7 @@ public interface SuccessCallback { /** * Notification that is called when a message send fails. */ + @FunctionalInterface public interface FailureCallback { /** * @param connection The connection From 06c8a68623d34ff3ec5d6f5499ba26a2c3be21b3 Mon Sep 17 00:00:00 2001 From: granny Date: Fri, 12 Apr 2024 05:57:57 -0700 Subject: [PATCH 53/53] throw away unused SpiFix class --- .../main/java/net/pl3x/map/core/Pl3xMap.java | 9 - .../java/net/pl3x/map/core/util/SpiFix.java | 269 ------------------ 2 files changed, 278 deletions(-) delete mode 100644 core/src/main/java/net/pl3x/map/core/util/SpiFix.java diff --git a/core/src/main/java/net/pl3x/map/core/Pl3xMap.java b/core/src/main/java/net/pl3x/map/core/Pl3xMap.java index c1ceaa889..3ddfc69d6 100644 --- a/core/src/main/java/net/pl3x/map/core/Pl3xMap.java +++ b/core/src/main/java/net/pl3x/map/core/Pl3xMap.java @@ -99,15 +99,6 @@ public abstract class Pl3xMap { public Pl3xMap(boolean isBukkit) { this.isBukkit = isBukkit; - /*try { - // Due to these bugs(?) in spi - // * relocated libraries cant find their services (xnio fails) - // * imageio fails to find twelvemonkeys spis at all - // I am forced to load them all myself instead of relying on the META-INF - SpiFix.forceRegisterSpis(); - } catch (Throwable ignore) { - }*/ - try { Field api = Provider.class.getDeclaredField("api"); api.setAccessible(true); diff --git a/core/src/main/java/net/pl3x/map/core/util/SpiFix.java b/core/src/main/java/net/pl3x/map/core/util/SpiFix.java deleted file mode 100644 index 4c33fcc42..000000000 --- a/core/src/main/java/net/pl3x/map/core/util/SpiFix.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2020-2023 William Blake Galbreath - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package net.pl3x.map.core.util; - -import io.undertow.attribute.AuthenticationTypeExchangeAttribute; -import io.undertow.attribute.BytesSentAttribute; -import io.undertow.attribute.CookieAttribute; -import io.undertow.attribute.DateTimeAttribute; -import io.undertow.attribute.HostAndPortAttribute; -import io.undertow.attribute.IdentUsernameAttribute; -import io.undertow.attribute.LocalIPAttribute; -import io.undertow.attribute.LocalPortAttribute; -import io.undertow.attribute.LocalServerNameAttribute; -import io.undertow.attribute.NullAttribute; -import io.undertow.attribute.PathParameterAttribute; -import io.undertow.attribute.PredicateContextAttribute; -import io.undertow.attribute.QueryParameterAttribute; -import io.undertow.attribute.QueryStringAttribute; -import io.undertow.attribute.RelativePathAttribute; -import io.undertow.attribute.RemoteHostAttribute; -import io.undertow.attribute.RemoteIPAttribute; -import io.undertow.attribute.RemoteObfuscatedIPAttribute; -import io.undertow.attribute.RemoteUserAttribute; -import io.undertow.attribute.RequestCookieAttribute; -import io.undertow.attribute.RequestHeaderAttribute; -import io.undertow.attribute.RequestLineAttribute; -import io.undertow.attribute.RequestMethodAttribute; -import io.undertow.attribute.RequestPathAttribute; -import io.undertow.attribute.RequestProtocolAttribute; -import io.undertow.attribute.RequestSchemeAttribute; -import io.undertow.attribute.RequestURLAttribute; -import io.undertow.attribute.ResolvedPathAttribute; -import io.undertow.attribute.ResponseCodeAttribute; -import io.undertow.attribute.ResponseCookieAttribute; -import io.undertow.attribute.ResponseHeaderAttribute; -import io.undertow.attribute.ResponseReasonPhraseAttribute; -import io.undertow.attribute.ResponseTimeAttribute; -import io.undertow.attribute.SecureExchangeAttribute; -import io.undertow.attribute.SslCipherAttribute; -import io.undertow.attribute.SslClientCertAttribute; -import io.undertow.attribute.SslSessionIdAttribute; -import io.undertow.attribute.StoredResponse; -import io.undertow.attribute.ThreadNameAttribute; -import io.undertow.attribute.TransportProtocolAttribute; -import io.undertow.client.ajp.AjpClientProvider; -import io.undertow.client.http.HttpClientProvider; -import io.undertow.client.http2.Http2ClearClientProvider; -import io.undertow.client.http2.Http2ClientProvider; -import io.undertow.client.http2.Http2PriorKnowledgeClientProvider; -import io.undertow.predicate.AuthenticationRequiredPredicate; -import io.undertow.predicate.ContainsPredicate; -import io.undertow.predicate.EqualsPredicate; -import io.undertow.predicate.ExistsPredicate; -import io.undertow.predicate.IdempotentPredicate; -import io.undertow.predicate.MaxContentSizePredicate; -import io.undertow.predicate.MethodPredicate; -import io.undertow.predicate.MinContentSizePredicate; -import io.undertow.predicate.PathMatchPredicate; -import io.undertow.predicate.PathPrefixPredicate; -import io.undertow.predicate.PathSuffixPredicate; -import io.undertow.predicate.PathTemplatePredicate; -import io.undertow.predicate.PredicatesHandler; -import io.undertow.predicate.RegularExpressionPredicate; -import io.undertow.predicate.RequestLargerThanPredicate; -import io.undertow.predicate.RequestSmallerThanPredicate; -import io.undertow.predicate.SecurePredicate; -import io.undertow.protocols.alpn.DefaultAlpnEngineManager; -import io.undertow.protocols.alpn.JettyAlpnProvider; -import io.undertow.protocols.alpn.ModularJdkAlpnProvider; -import io.undertow.protocols.alpn.OpenSSLAlpnProvider; -import io.undertow.protocols.ssl.SNIAlpnEngineManager; -import io.undertow.server.JvmRouteHandler; -import io.undertow.server.handlers.AccessControlListHandler; -import io.undertow.server.handlers.ActiveRequestTrackerHandler; -import io.undertow.server.handlers.AllowedMethodsHandler; -import io.undertow.server.handlers.BlockingHandler; -import io.undertow.server.handlers.ByteRangeHandler; -import io.undertow.server.handlers.CanonicalPathHandler; -import io.undertow.server.handlers.DisableCacheHandler; -import io.undertow.server.handlers.DisallowedMethodsHandler; -import io.undertow.server.handlers.ForwardedHandler; -import io.undertow.server.handlers.HttpContinueAcceptingHandler; -import io.undertow.server.handlers.HttpTraceHandler; -import io.undertow.server.handlers.IPAddressAccessControlHandler; -import io.undertow.server.handlers.JDBCLogHandler; -import io.undertow.server.handlers.LearningPushHandler; -import io.undertow.server.handlers.LocalNameResolvingHandler; -import io.undertow.server.handlers.PathSeparatorHandler; -import io.undertow.server.handlers.PeerNameResolvingHandler; -import io.undertow.server.handlers.ProxyPeerAddressHandler; -import io.undertow.server.handlers.RedirectHandler; -import io.undertow.server.handlers.RequestBufferingHandler; -import io.undertow.server.handlers.RequestDumpingHandler; -import io.undertow.server.handlers.RequestLimitingHandler; -import io.undertow.server.handlers.ResponseRateLimitingHandler; -import io.undertow.server.handlers.SSLHeaderHandler; -import io.undertow.server.handlers.SameSiteCookieHandler; -import io.undertow.server.handlers.SecureCookieHandler; -import io.undertow.server.handlers.SetAttributeHandler; -import io.undertow.server.handlers.SetErrorHandler; -import io.undertow.server.handlers.SetHeaderHandler; -import io.undertow.server.handlers.StoredResponseHandler; -import io.undertow.server.handlers.StuckThreadDetectionHandler; -import io.undertow.server.handlers.URLDecodingHandler; -import io.undertow.server.handlers.accesslog.AccessLogHandler; -import io.undertow.server.handlers.builder.ResponseCodeHandlerBuilder; -import io.undertow.server.handlers.builder.RewriteHandlerBuilder; -import io.undertow.server.handlers.encoding.EncodingHandler; -import io.undertow.server.handlers.encoding.RequestEncodingHandler; -import io.undertow.server.handlers.error.FileErrorPageHandler; -import io.undertow.server.handlers.form.EagerFormParsingHandler; -import io.undertow.server.handlers.proxy.ProxyHandlerBuilder; -import io.undertow.server.handlers.resource.ResourceHandler; -import javax.imageio.spi.IIORegistry; - - -@SuppressWarnings("deprecation") -public class SpiFix { - public static void forceRegisterSpis() { - IIORegistry registry = IIORegistry.getDefaultInstance(); - - // io.undertow.attribute.ExchangeAttributeBuilder - registry.registerServiceProvider(new RelativePathAttribute.Builder()); - registry.registerServiceProvider(new RemoteIPAttribute.Builder()); - registry.registerServiceProvider(new LocalIPAttribute.Builder()); - registry.registerServiceProvider(new RequestProtocolAttribute.Builder()); - registry.registerServiceProvider(new LocalPortAttribute.Builder()); - registry.registerServiceProvider(new IdentUsernameAttribute.Builder()); - registry.registerServiceProvider(new RequestMethodAttribute.Builder()); - registry.registerServiceProvider(new QueryStringAttribute.Builder()); - registry.registerServiceProvider(new RequestLineAttribute.Builder()); - registry.registerServiceProvider(new BytesSentAttribute.Builder()); - registry.registerServiceProvider(new DateTimeAttribute.Builder()); - registry.registerServiceProvider(new RemoteUserAttribute.Builder()); - registry.registerServiceProvider(new RequestURLAttribute.Builder()); - registry.registerServiceProvider(new ThreadNameAttribute.Builder()); - registry.registerServiceProvider(new LocalServerNameAttribute.Builder()); - registry.registerServiceProvider(new RequestHeaderAttribute.Builder()); - registry.registerServiceProvider(new ResponseHeaderAttribute.Builder()); - registry.registerServiceProvider(new CookieAttribute.Builder()); - registry.registerServiceProvider(new RequestCookieAttribute.Builder()); - registry.registerServiceProvider(new ResponseCookieAttribute.Builder()); - registry.registerServiceProvider(new ResponseCodeAttribute.Builder()); - registry.registerServiceProvider(new PredicateContextAttribute.Builder()); - registry.registerServiceProvider(new QueryParameterAttribute.Builder()); - registry.registerServiceProvider(new SslClientCertAttribute.Builder()); - registry.registerServiceProvider(new SslCipherAttribute.Builder()); - registry.registerServiceProvider(new SslSessionIdAttribute.Builder()); - registry.registerServiceProvider(new ResponseTimeAttribute.Builder()); - registry.registerServiceProvider(new PathParameterAttribute.Builder()); - registry.registerServiceProvider(new TransportProtocolAttribute.Builder()); - registry.registerServiceProvider(new RequestSchemeAttribute.Builder()); - registry.registerServiceProvider(new HostAndPortAttribute.Builder()); - registry.registerServiceProvider(new AuthenticationTypeExchangeAttribute.Builder()); - registry.registerServiceProvider(new SecureExchangeAttribute.Builder()); - registry.registerServiceProvider(new RemoteHostAttribute.Builder()); - registry.registerServiceProvider(new RequestPathAttribute.Builder()); - registry.registerServiceProvider(new ResolvedPathAttribute.Builder()); - registry.registerServiceProvider(new NullAttribute.Builder()); - registry.registerServiceProvider(new StoredResponse.Builder()); - registry.registerServiceProvider(new ResponseReasonPhraseAttribute.Builder()); - registry.registerServiceProvider(new RemoteObfuscatedIPAttribute.Builder()); - - // io.undertow.client.ClientProvider - registry.registerServiceProvider(new HttpClientProvider()); - registry.registerServiceProvider(new AjpClientProvider()); - registry.registerServiceProvider(new Http2ClientProvider()); - registry.registerServiceProvider(new Http2ClearClientProvider()); - registry.registerServiceProvider(new Http2PriorKnowledgeClientProvider()); - - // io.undertow.predicate.PredicateBuilder - registry.registerServiceProvider(new PathMatchPredicate.Builder()); - registry.registerServiceProvider(new PathPrefixPredicate.Builder()); - registry.registerServiceProvider(new ContainsPredicate.Builder()); - registry.registerServiceProvider(new ExistsPredicate.Builder()); - registry.registerServiceProvider(new RegularExpressionPredicate.Builder()); - registry.registerServiceProvider(new PathSuffixPredicate.Builder()); - registry.registerServiceProvider(new EqualsPredicate.Builder()); - registry.registerServiceProvider(new PathTemplatePredicate.Builder()); - registry.registerServiceProvider(new MethodPredicate.Builder()); - registry.registerServiceProvider(new AuthenticationRequiredPredicate.Builder()); - registry.registerServiceProvider(new MaxContentSizePredicate.Builder()); - registry.registerServiceProvider(new MinContentSizePredicate.Builder()); - registry.registerServiceProvider(new SecurePredicate.Builder()); - registry.registerServiceProvider(new IdempotentPredicate.Builder()); - registry.registerServiceProvider(new RequestLargerThanPredicate.Builder()); - registry.registerServiceProvider(new RequestSmallerThanPredicate.Builder()); - - // io.undertow.protocols.alpn.ALPNEngineManager - registry.registerServiceProvider(new SNIAlpnEngineManager()); - registry.registerServiceProvider(new DefaultAlpnEngineManager()); - - // io.undertow.protocols.alpn.ALPNProvider - registry.registerServiceProvider(new JettyAlpnProvider()); - registry.registerServiceProvider(new ModularJdkAlpnProvider()); - registry.registerServiceProvider(new OpenSSLAlpnProvider()); - - // io.undertow.server.handlers.builder.HandlerBuilder - registry.registerServiceProvider(new RewriteHandlerBuilder()); - registry.registerServiceProvider(new SetAttributeHandler.Builder()); - registry.registerServiceProvider(new SetAttributeHandler.ClearBuilder()); - registry.registerServiceProvider(new ResponseCodeHandlerBuilder()); - registry.registerServiceProvider(new DisableCacheHandler.Builder()); - registry.registerServiceProvider(new ProxyPeerAddressHandler.Builder()); - registry.registerServiceProvider(new ProxyHandlerBuilder()); - registry.registerServiceProvider(new RedirectHandler.Builder()); - registry.registerServiceProvider(new AccessLogHandler.Builder()); - registry.registerServiceProvider(new ActiveRequestTrackerHandler.Builder()); - registry.registerServiceProvider(new AllowedMethodsHandler.Builder()); - registry.registerServiceProvider(new BlockingHandler.Builder()); - registry.registerServiceProvider(new CanonicalPathHandler.Builder()); - registry.registerServiceProvider(new DisallowedMethodsHandler.Builder()); - registry.registerServiceProvider(new FileErrorPageHandler.Builder()); - registry.registerServiceProvider(new HttpTraceHandler.Builder()); - registry.registerServiceProvider(new JvmRouteHandler.Builder()); - registry.registerServiceProvider(new PeerNameResolvingHandler.Builder()); - registry.registerServiceProvider(new RequestDumpingHandler.Builder()); - registry.registerServiceProvider(new RequestLimitingHandler.Builder()); - registry.registerServiceProvider(new ResourceHandler.Builder()); - registry.registerServiceProvider(new SSLHeaderHandler.Builder()); - registry.registerServiceProvider(new ResponseRateLimitingHandler.Builder()); - registry.registerServiceProvider(new URLDecodingHandler.Builder()); - registry.registerServiceProvider(new PathSeparatorHandler.Builder()); - registry.registerServiceProvider(new IPAddressAccessControlHandler.Builder()); - registry.registerServiceProvider(new ByteRangeHandler.Builder()); - registry.registerServiceProvider(new EncodingHandler.Builder()); - registry.registerServiceProvider(new RequestEncodingHandler.Builder()); - registry.registerServiceProvider(new LearningPushHandler.Builder()); - registry.registerServiceProvider(new SetHeaderHandler.Builder()); - registry.registerServiceProvider(new PredicatesHandler.DoneHandlerBuilder()); - registry.registerServiceProvider(new PredicatesHandler.RestartHandlerBuilder()); - registry.registerServiceProvider(new RequestBufferingHandler.Builder()); - registry.registerServiceProvider(new StuckThreadDetectionHandler.Builder()); - registry.registerServiceProvider(new AccessControlListHandler.Builder()); - registry.registerServiceProvider(new JDBCLogHandler.Builder()); - registry.registerServiceProvider(new LocalNameResolvingHandler.Builder()); - registry.registerServiceProvider(new StoredResponseHandler.Builder()); - registry.registerServiceProvider(new SecureCookieHandler.Builder()); - registry.registerServiceProvider(new ForwardedHandler.Builder()); - registry.registerServiceProvider(new HttpContinueAcceptingHandler.Builder()); - registry.registerServiceProvider(new EagerFormParsingHandler.Builder()); - registry.registerServiceProvider(new SameSiteCookieHandler.Builder()); - registry.registerServiceProvider(new SetErrorHandler.Builder()); - - // org.xnio.XnioProvider - //registry.registerServiceProvider(new NioXnioProvider()); - } -}