s = Files.list(playerDataFolder)) {
- s.filter(p -> p.toString().endsWith(".dat")).forEach(this::loadOfflineMarker);
- } catch (IOException e) {
- plugin.getLogger().log(Level.SEVERE, "Failed to stream playerdata", e);
- }
- }
-
- private void loadOfflineMarker(@NotNull Path playerDataFile) {
- String fileName = playerDataFile.getFileName().toString();
- UUID uuid = UUID.fromString(fileName.replace(".dat", ""));
- OfflinePlayer op = Bukkit.getOfflinePlayer(uuid);
- if (op.isOnline()) return;
-
- long timeSinceLastPlayed = System.currentTimeMillis() - op.getLastPlayed();
- if (plugin.getCurrentConfig().expireTimeInHours > 0 && timeSinceLastPlayed > plugin.getCurrentConfig().expireTimeInHours * 60 * 60 * 1000) {
- plugin.getLogger().fine("Player " + op.getName() + " (" + uuid + ") was last seen " + timeSinceLastPlayed + "ms ago, which is too long ago, skipping");
- return;
- }
-
- try (GZIPInputStream in = new GZIPInputStream(Files.newInputStream(playerDataFile))) {
- NBTReader reader = new NBTReader(in);
- PlayerNBT playerNBT = nbt.read(reader, PlayerNBT.class);
- Location location = playerNBT.getLocation();
- GameMode gameMode = playerNBT.getGameMode();
-
- if (gameMode == null) {
- plugin.getLogger().warning("Couldn't read or convert GameMode from " + fileName);
- return;
- }
-
- if (location == null) {
- plugin.getLogger().warning("Couldn't read Location from " + fileName);
- return;
- }
-
- add(op, location, gameMode);
- } catch (IOException e) {
- plugin.getLogger().log(Level.WARNING, "Failed to read playerdata file " + fileName, e);
- }
- }
-}
diff --git a/src/main/java/com/technicjelle/bluemapofflineplayermarkers/common/Config.java b/src/main/java/com/technicjelle/bluemapofflineplayermarkers/common/Config.java
new file mode 100644
index 0000000..ac5cacd
--- /dev/null
+++ b/src/main/java/com/technicjelle/bluemapofflineplayermarkers/common/Config.java
@@ -0,0 +1,57 @@
+package com.technicjelle.bluemapofflineplayermarkers.common;
+
+import com.technicjelle.bluemapofflineplayermarkers.core.GameMode;
+import com.technicjelle.bluemapofflineplayermarkers.core.Singletons;
+
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+public interface Config {
+ String MARKER_SET_ID = "offline-players";
+
+ String getMarkerSetName();
+
+ boolean isToggleable();
+
+ boolean isDefaultHidden();
+
+ /**
+ * If you want to show only players who have joined in the last X hours, set this to a number greater than 0.
+ * If you want to show all players, set this to 0.
+ */
+ long getExpireTimeInHours();
+
+ List getHiddenGameModes();
+
+ default boolean isGameModeHidden(GameMode gameMode) {
+ return getHiddenGameModes().contains(gameMode);
+ }
+
+ /**
+ * @param playerUUID The player to check.
+ * @return true if the player should be hidden
+ */
+ default boolean checkPlayerLastPlayed(UUID playerUUID) {
+ if (getExpireTimeInHours() <= 0) return false; // don't hide players if the expiry time is 0 or less
+
+ Instant lastPlayed = Singletons.getServer().getPlayerLastPlayed(playerUUID);
+ Instant expireTime = Instant.now().minusSeconds(getExpireTimeInHours() * 60 * 60);
+ return lastPlayed.isBefore(expireTime);
+ }
+
+ static List parseGameModes(List hiddenGameModesStrings) throws IllegalArgumentException {
+ ArrayList gameModes = new ArrayList<>();
+ for (String hiddenGameModeString : hiddenGameModesStrings) {
+ try {
+ GameMode parsedGameMode = GameMode.getById(hiddenGameModeString);
+ if (parsedGameMode == null) throw new IllegalArgumentException("Invalid Game Mode: " + hiddenGameModeString);
+ gameModes.add(parsedGameMode);
+ } catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException("Invalid Game Mode: " + hiddenGameModeString);
+ }
+ }
+ return gameModes;
+ }
+}
diff --git a/src/main/java/com/technicjelle/bluemapofflineplayermarkers/common/PlayerData.java b/src/main/java/com/technicjelle/bluemapofflineplayermarkers/common/PlayerData.java
new file mode 100644
index 0000000..940b6c5
--- /dev/null
+++ b/src/main/java/com/technicjelle/bluemapofflineplayermarkers/common/PlayerData.java
@@ -0,0 +1,15 @@
+package com.technicjelle.bluemapofflineplayermarkers.common;
+
+import com.flowpowered.math.vector.Vector3d;
+import com.technicjelle.bluemapofflineplayermarkers.core.GameMode;
+
+import java.util.Optional;
+import java.util.UUID;
+
+public interface PlayerData {
+ GameMode getGameMode();
+
+ Vector3d getPosition();
+
+ Optional getWorldUUID();
+}
diff --git a/src/main/java/com/technicjelle/bluemapofflineplayermarkers/common/Server.java b/src/main/java/com/technicjelle/bluemapofflineplayermarkers/common/Server.java
new file mode 100644
index 0000000..46a761f
--- /dev/null
+++ b/src/main/java/com/technicjelle/bluemapofflineplayermarkers/common/Server.java
@@ -0,0 +1,91 @@
+package com.technicjelle.bluemapofflineplayermarkers.common;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonObject;
+import com.google.gson.reflect.TypeToken;
+import com.technicjelle.bluemapofflineplayermarkers.core.Singletons;
+
+import java.io.*;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.file.Path;
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
+
+public interface Server {
+ Gson _gson = new GsonBuilder()
+ .setLenient()
+// .setPrettyPrinting() //Disabled to discourage people from editing the file by hand
+ .enableComplexMapKeySerialization()
+ .create();
+
+ Map _cachedPlayerNames = new HashMap<>();
+ String _cacheFileName = "cachedPlayerNames.json";
+
+ default void startUp() {
+ //load cached player names
+ Path cacheFolder = Singletons.getServer().getConfigFolder();
+ File cacheFile = new File(cacheFolder.toFile(), _cacheFileName);
+ if (cacheFile.exists()) {
+ try (InputStreamReader reader = new FileReader(cacheFile)) {
+ Map map = _gson.fromJson(reader, new TypeToken