From 26ba16efd0bf6f82659900c8459a7c4dc1ce3e3e Mon Sep 17 00:00:00 2001 From: Matt Date: Sun, 29 Dec 2024 07:14:31 -0500 Subject: [PATCH 1/3] optimize - tptickets. --- .../api/base/commands/GivenCommands.java | 8 ++ .../base/timers/AbstractPlayerTeleporter.java | 124 ++++++++++++++++ .../base/runnables/PlayerTeleporter.java | 90 ++++-------- .../configs/given/GivenConfigs.java | 8 +- .../singularity/database/CoreDBOperator.java | 3 + .../base/runnables/PlayerTeleporter.java | 133 +++++++----------- .../base/runnables/PlayerTeleporter.java | 106 +++++--------- 7 files changed, 262 insertions(+), 210 deletions(-) create mode 100644 api/src/main/java/net/streamline/api/base/timers/AbstractPlayerTeleporter.java diff --git a/api/src/main/java/net/streamline/api/base/commands/GivenCommands.java b/api/src/main/java/net/streamline/api/base/commands/GivenCommands.java index 3f3338d1..779ed795 100644 --- a/api/src/main/java/net/streamline/api/base/commands/GivenCommands.java +++ b/api/src/main/java/net/streamline/api/base/commands/GivenCommands.java @@ -11,21 +11,29 @@ public class GivenCommands { @Getter @Setter private static PlaytimeCommand playtimeCommand; @Getter @Setter + private static PTagCommand pTagCommand; + @Getter @Setter private static ReloadCommand reloadCommand; @Getter @Setter + private static SetServerCommand setServerCommand; + @Getter @Setter private static SyncCommand syncCommand; public static void init() { setModulesCommand(new ModulesCommand()); setParseCommand(new ParseCommand()); setPlaytimeCommand(new PlaytimeCommand()); + setPTagCommand(new PTagCommand()); setReloadCommand(new ReloadCommand()); + setSetServerCommand(new SetServerCommand()); setSyncCommand(new SyncCommand()); getModulesCommand().register(); getParseCommand().register(); getPlaytimeCommand().register(); + getPTagCommand().register(); getReloadCommand().register(); + getSetServerCommand().register(); getSyncCommand().register(); } } diff --git a/api/src/main/java/net/streamline/api/base/timers/AbstractPlayerTeleporter.java b/api/src/main/java/net/streamline/api/base/timers/AbstractPlayerTeleporter.java new file mode 100644 index 00000000..ec66324e --- /dev/null +++ b/api/src/main/java/net/streamline/api/base/timers/AbstractPlayerTeleporter.java @@ -0,0 +1,124 @@ +package net.streamline.api.base.timers; + +import lombok.Getter; +import lombok.Setter; +import singularity.data.teleportation.TPTicket; +import singularity.utils.MessageUtils; + +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; + +public abstract class AbstractPlayerTeleporter extends Thread { + public static final long TICKING_FREQUENCY = 50L; // Milliseconds + + @Getter @Setter + private static AbstractPlayerTeleporter instance; + + @Getter @Setter + private static AtomicReference stage = new AtomicReference<>(TeleportStage.READY); + + @Getter @Setter + private static AtomicLong lastRun = new AtomicLong(0); + + public enum TeleportStage { + COLLECTION, + TELEPORTATION, + READY; + } + + /** + * Start the teleporter instance. + */ + public static synchronized void startInstance() { + if (instance == null) { + throw new IllegalStateException("Teleporter instance is not set."); + } + if (!instance.isAlive()) { + instance.start(); + } + } + + /** + * Stop the teleporter instance safely. + */ + public static synchronized void stopInstance() { + if (instance != null && instance.isAlive()) { + instance.interrupt(); + try { + instance.join(); // Wait for the thread to finish + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); // Restore interrupt status + } finally { + instance = null; + } + } + } + + /** + * Check if the teleporter can tick again based on the last run time. + */ + public static boolean isAbleToRunAgain() { + long currentTime = System.currentTimeMillis(); + long lastRunTime = lastRun.get(); + + if (lastRunTime == 0 || (lastRunTime + TICKING_FREQUENCY < currentTime)) { + lastRun.set(currentTime); + return true; + } + return false; + } + + /** + * Abstract constructor with a custom thread name. + */ + public AbstractPlayerTeleporter() { + super("SL - Player Teleporter"); + } + + /** + * Main run loop for the teleporter thread. + */ + @Override + public void run() { + while (! isInterrupted()) { + try { + tick(); + } catch (Throwable e) { + MessageUtils.logWarning("Error during teleporter tick: ", e); + } + try { + Thread.sleep(TICKING_FREQUENCY); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); // Preserve interrupt status + break; // Exit the loop + } + } + } + + /** + * Perform a single tick action if the teleporter is ready. + */ + public void contemplateTick() { + if (isAbleToRunAgain()) { + tick(); + } + } + + /** + * Abstract tick method to be implemented by subclasses. + */ + public abstract void tick(); + + /** + * Clear the ticket and log the action. + * + * @param ticket The teleportation ticket to clear. + * @param instance The instance ID for logging. + */ + private static void clearTicket(TPTicket ticket, int instance) { + if (ticket != null) { + ticket.clear(); + MessageUtils.logInfo("Cleared teleportation ticket for player " + ticket.getIdentifier() + ". [" + instance + "]"); + } + } +} diff --git a/bungee/src/main/java/net/streamline/base/runnables/PlayerTeleporter.java b/bungee/src/main/java/net/streamline/base/runnables/PlayerTeleporter.java index 0d3a68d1..45c4d12d 100644 --- a/bungee/src/main/java/net/streamline/base/runnables/PlayerTeleporter.java +++ b/bungee/src/main/java/net/streamline/base/runnables/PlayerTeleporter.java @@ -1,96 +1,61 @@ package net.streamline.base.runnables; -import lombok.Getter; -import lombok.Setter; import net.md_5.bungee.api.ServerConnectRequest; import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.event.ServerConnectEvent; +import net.streamline.api.base.timers.AbstractPlayerTeleporter; import net.streamline.base.Streamline; import singularity.configs.given.GivenConfigs; import singularity.data.teleportation.TPTicket; +import singularity.utils.MessageUtils; import java.util.Date; import java.util.UUID; import java.util.concurrent.ConcurrentSkipListSet; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; -public class PlayerTeleporter extends Thread { - public static final long TICKING_FREQUENCY = 50L; - - @Getter @Setter - private static PlayerTeleporter instance; +public class PlayerTeleporter extends AbstractPlayerTeleporter { + private static final ExecutorService executor = Executors.newFixedThreadPool(4); // Adjust as needed public static void init() { - instance = new PlayerTeleporter(); - instance.start(); - } - - public static void stopInstance() { - try { - if (instance != null) { - instance.interrupt(); - instance = null; - } - } catch (Exception e) { - // ignore - } - } - - @Getter @Setter - private static AtomicReference stage = new AtomicReference<>(TeleportStage.READY); - @Getter @Setter - private static AtomicLong lastRun = new AtomicLong(0); - - public enum TeleportStage { - COLLECTION, - TELEPORTATION, - READY, - ; - } - - public static boolean isAbleToRunAgain() { - return lastRun.get() + TICKING_FREQUENCY < System.currentTimeMillis(); - } - - public static void setLastRun() { - lastRun.set(System.currentTimeMillis()); - } - - public PlayerTeleporter() { - super("SL - Player Teleporter"); + setInstance(new PlayerTeleporter()); + startInstance(); } @Override - public void run() { - if (! isAbleToRunAgain()) return; + public void tick() { + getStage().set(TeleportStage.COLLECTION); + ConcurrentSkipListSet tickets = GivenConfigs.getMainDatabase().pullAllTPTickets().join(); - setLastRun(); + getStage().set(TeleportStage.TELEPORTATION); + tickets.forEach(ticket -> executor.submit(() -> processTicket(ticket))); - stage.set(TeleportStage.COLLECTION); - ConcurrentSkipListSet tickets = GivenConfigs.getMainDatabase().pullAllTPTickets().join(); + getStage().set(TeleportStage.READY); + } - stage.set(TeleportStage.TELEPORTATION); - tickets.forEach(ticket -> { - if (ticket.getCreateDate().before(new Date(System.currentTimeMillis() - 7 * 1000))) { - ticket.clear(); + private void processTicket(TPTicket ticket) { + try { + if (ticket.getCreateDate().before(new Date(System.currentTimeMillis() - (7 * 1000)))) { + clearTicket(ticket, 1); return; } ProxiedPlayer player = Streamline.getInstance().getProxy().getPlayer(UUID.fromString(ticket.getIdentifier())); if (player == null) { - ticket.clear(); + clearTicket(ticket, 2); return; } teleportPlayerAsync(player, ticket.getTargetServer().getIdentifier()); - }); - - stage.set(TeleportStage.READY); + clearTicket(ticket, 3); + } catch (Exception e) { + MessageUtils.logWarning("Error processing ticket: " + ticket.getIdentifier(), e); + } } - private static void teleportPlayerAsync(ProxiedPlayer player, String server) { + private void teleportPlayerAsync(ProxiedPlayer player, String server) { ServerInfo targetServer = Streamline.getInstance().getProxy().getServerInfo(server); if (targetServer != null) { ServerConnectRequest request = ServerConnectRequest.builder() @@ -100,4 +65,9 @@ private static void teleportPlayerAsync(ProxiedPlayer player, String server) { player.connect(request); } } + + private static void clearTicket(TPTicket ticket, int instance) { + ticket.clear(); + MessageUtils.logInfo("Cleared teleportation ticket for player " + ticket.getIdentifier() + ". [" + instance + "]"); + } } diff --git a/singularity-api/src/main/java/singularity/configs/given/GivenConfigs.java b/singularity-api/src/main/java/singularity/configs/given/GivenConfigs.java index b8be242d..96d7dfab 100644 --- a/singularity-api/src/main/java/singularity/configs/given/GivenConfigs.java +++ b/singularity-api/src/main/java/singularity/configs/given/GivenConfigs.java @@ -69,12 +69,16 @@ public static void reloadData() { } } + public static void ensureServer() { + getServer().push(); + } + public static SavedServer getServer() { return getServerConfig().getServer(); } - public static void ensureServer() { - getServer().push(); + public static String getServerName() { + return getServerConfig().getName(); } public static void setServer(SavedServer server) { diff --git a/singularity-api/src/main/java/singularity/database/CoreDBOperator.java b/singularity-api/src/main/java/singularity/database/CoreDBOperator.java index 5c4994d3..e788db18 100644 --- a/singularity-api/src/main/java/singularity/database/CoreDBOperator.java +++ b/singularity-api/src/main/java/singularity/database/CoreDBOperator.java @@ -26,6 +26,7 @@ import singularity.database.servers.SavedServer; import singularity.database.servers.UpdateInfo; import singularity.interfaces.ISingularityExtension; +import singularity.utils.MessageUtils; import singularity.utils.UserUtils; public class CoreDBOperator extends DBOperator { @@ -768,6 +769,8 @@ public CompletableFuture> pullAllTPTickets() { } }); + if (! tickets.isEmpty()) MessageUtils.logDebug("Collected " + tickets.size() + " teleportation tickets."); + return tickets; }); } diff --git a/spigot/src/main/java/net/streamline/base/runnables/PlayerTeleporter.java b/spigot/src/main/java/net/streamline/base/runnables/PlayerTeleporter.java index 8de44e21..bb201976 100644 --- a/spigot/src/main/java/net/streamline/base/runnables/PlayerTeleporter.java +++ b/spigot/src/main/java/net/streamline/base/runnables/PlayerTeleporter.java @@ -1,9 +1,7 @@ package net.streamline.base.runnables; import host.plas.bou.scheduling.TaskManager; -import lombok.Getter; -import lombok.Setter; -import net.streamline.base.Streamline; +import net.streamline.api.base.timers.AbstractPlayerTeleporter; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; @@ -18,109 +16,82 @@ import java.util.Date; import java.util.UUID; import java.util.concurrent.ConcurrentSkipListSet; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; -public class PlayerTeleporter extends Thread { - public static final long TICKING_FREQUENCY = 50L; - - @Getter @Setter - private static PlayerTeleporter instance; +public class PlayerTeleporter extends AbstractPlayerTeleporter { + private static final ExecutorService executor = Executors.newFixedThreadPool(4); // Adjust as needed public static void init() { - instance = new PlayerTeleporter(); - instance.start(); - } - - public static void stopInstance() { - try { - if (instance != null) { - instance.interrupt(); - instance = null; - } - } catch (Exception e) { - // ignore - } - } - - @Getter @Setter - private static AtomicReference stage = new AtomicReference<>(TeleportStage.READY); - @Getter @Setter - private static AtomicLong lastRun = new AtomicLong(0); - - public enum TeleportStage { - COLLECTION, - TELEPORTATION, - READY, - ; - } - - public static boolean isAbleToRunAgain() { - return lastRun.get() + TICKING_FREQUENCY < System.currentTimeMillis(); - } - - public static void setLastRun() { - lastRun.set(System.currentTimeMillis()); - } - - public PlayerTeleporter() { - super("SL - Player Teleporter"); + setInstance(new PlayerTeleporter()); + startInstance(); } @Override - public void run() { - if (! isAbleToRunAgain()) return; + public void tick() { + getStage().set(TeleportStage.COLLECTION); + ConcurrentSkipListSet tickets = GivenConfigs.getMainDatabase().pullAllTPTickets().join(); - setLastRun(); + getStage().set(TeleportStage.TELEPORTATION); + tickets.forEach(ticket -> executor.submit(() -> processTicket(ticket))); - stage.set(TeleportStage.COLLECTION); - ConcurrentSkipListSet tickets = GivenConfigs.getMainDatabase().pullAllTPTickets().join(); + getStage().set(TeleportStage.READY); + } - stage.set(TeleportStage.TELEPORTATION); - tickets.forEach(ticket -> { - if (ticket.getCreateDate().before(new Date(System.currentTimeMillis() - 7 * 1000))) { - ticket.clear(); + private void processTicket(TPTicket ticket) { + try { + if (ticket.getCreateDate().before(new Date(System.currentTimeMillis() - (7 * 1000)))) { + clearTicket(ticket, 1); return; } - if (ticket.getTargetServer().getIdentifier().equals(GivenConfigs.getServer().getIdentifier())) { - Player player = Streamline.getInstance().getProxy().getPlayer(UUID.fromString(ticket.getIdentifier())); + if (ticket.getTargetServer().getIdentifier().equals(GivenConfigs.getServerName())) { + Player player = Bukkit.getPlayer(UUID.fromString(ticket.getIdentifier())); if (player == null) { - ticket.clear(); + clearTicket(ticket, 2); return; } teleportPlayer(player, ticket); - ticket.clear(); + clearTicket(ticket, 3); } - }); - - stage.set(TeleportStage.READY); + } catch (Exception e) { + MessageUtils.logWarning("Error processing ticket: " + ticket.getIdentifier(), e); + } } - private static void teleportPlayer(Player player, TPTicket ticket) { + private void teleportPlayer(Player player, TPTicket ticket) { PlayerWorld world = ticket.getTargetWorld(); WorldPosition position = ticket.getTargetLocation(); PlayerRotation rotation = ticket.getTargetRotation(); TaskManager.runTask(() -> { - World targetWorld = Bukkit.getWorld(world.getIdentifier()); - if (targetWorld == null) { - MessageUtils.logWarning("World " + world.getIdentifier() + " not found for teleportation."); - return; - } - - Location location = rotation != null - ? new Location(targetWorld, position.getX(), position.getY(), position.getZ(), rotation.getYaw(), rotation.getPitch()) - : new Location(targetWorld, position.getX(), position.getY(), position.getZ()); - - TaskManager.teleport(player, location); + try { + World targetWorld = Bukkit.getWorld(world.getIdentifier()); + if (targetWorld == null) { + MessageUtils.logWarning("World " + world.getIdentifier() + " not found for teleportation."); + return; + } - MessageUtils.logInfo(String.format( - "Teleported %s to %s at %.2f, %.2f, %.2f with yaw %.2f and pitch %.2f.", - player.getName(), world.getIdentifier(), position.getX(), position.getY(), position.getZ(), - rotation != null ? rotation.getYaw() : 0, rotation != null ? rotation.getPitch() : 0 - )); + Location location = new Location( + targetWorld, + position.getX(), + position.getY(), + position.getZ(), + rotation != null ? rotation.getYaw() : 0, + rotation != null ? rotation.getPitch() : 0 + ); + + player.teleport(location); + MessageUtils.logInfo("Teleported " + player.getName() + " to " + location); + } catch (Exception e) { + MessageUtils.logWarning("Failed to teleport player " + player.getName(), e); + } }); } -} \ No newline at end of file + + private static void clearTicket(TPTicket ticket, int instance) { + ticket.clear(); + MessageUtils.logInfo("Cleared teleportation ticket for player " + ticket.getIdentifier() + ". [" + instance + "]"); + } +} diff --git a/velocity/src/main/java/net/streamline/base/runnables/PlayerTeleporter.java b/velocity/src/main/java/net/streamline/base/runnables/PlayerTeleporter.java index afdca470..177014a3 100644 --- a/velocity/src/main/java/net/streamline/base/runnables/PlayerTeleporter.java +++ b/velocity/src/main/java/net/streamline/base/runnables/PlayerTeleporter.java @@ -1,97 +1,69 @@ package net.streamline.base.runnables; -import com.velocitypowered.api.proxy.ConnectionRequestBuilder; import com.velocitypowered.api.proxy.Player; -import lombok.Getter; -import lombok.Setter; +import com.velocitypowered.api.proxy.server.RegisteredServer; +import net.streamline.api.base.timers.AbstractPlayerTeleporter; import net.streamline.base.StreamlineVelocity; import singularity.configs.given.GivenConfigs; import singularity.data.teleportation.TPTicket; +import singularity.utils.MessageUtils; import java.util.Date; +import java.util.Optional; import java.util.UUID; import java.util.concurrent.ConcurrentSkipListSet; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; -public class PlayerTeleporter extends Thread { - public static final long TICKING_FREQUENCY = 50L; - - @Getter @Setter - private static PlayerTeleporter instance; +public class PlayerTeleporter extends AbstractPlayerTeleporter { + private static final ExecutorService executor = Executors.newFixedThreadPool(4); // Adjust as needed public static void init() { - instance = new PlayerTeleporter(); - instance.start(); - } - - public static void stopInstance() { - try { - if (instance != null) { - instance.interrupt(); - instance = null; - } - } catch (Exception e) { - // ignore - } - } - - @Getter @Setter - private static AtomicReference stage = new AtomicReference<>(TeleportStage.READY); - @Getter @Setter - private static AtomicLong lastRun = new AtomicLong(0); - - public enum TeleportStage { - COLLECTION, - TELEPORTATION, - READY, - ; - } - - public static boolean isAbleToRunAgain() { - return lastRun.get() + TICKING_FREQUENCY < System.currentTimeMillis(); - } - - public static void setLastRun() { - lastRun.set(System.currentTimeMillis()); - } - - public PlayerTeleporter() { - super("SL - Player Teleporter"); + setInstance(new PlayerTeleporter()); + startInstance(); } @Override - public void run() { - if (! isAbleToRunAgain()) return; + public void tick() { + getStage().set(TeleportStage.COLLECTION); + ConcurrentSkipListSet tickets = GivenConfigs.getMainDatabase().pullAllTPTickets().join(); - setLastRun(); + getStage().set(TeleportStage.TELEPORTATION); + tickets.forEach(ticket -> executor.submit(() -> processTicket(ticket))); - stage.set(TeleportStage.COLLECTION); - ConcurrentSkipListSet tickets = GivenConfigs.getMainDatabase().pullAllTPTickets().join(); + getStage().set(TeleportStage.READY); + } - stage.set(TeleportStage.TELEPORTATION); - tickets.forEach(ticket -> { - if (ticket.getCreateDate().before(new Date(System.currentTimeMillis() - 7 * 1000))) { - ticket.clear(); + private void processTicket(TPTicket ticket) { + try { + if (ticket.getCreateDate().before(new Date(System.currentTimeMillis() - (7 * 1000)))) { + clearTicket(ticket, 1); return; } - Player player = StreamlineVelocity.getInstance().getProxy().getPlayer(UUID.fromString(ticket.getIdentifier())).orElse(null); - if (player == null) { - ticket.clear(); + Optional player = StreamlineVelocity.getInstance().getProxy().getPlayer(UUID.fromString(ticket.getIdentifier())); + if (player.isEmpty()) { + clearTicket(ticket, 2); return; } - teleportPlayerAsync(player, ticket.getTargetServer().getIdentifier()); - }); + teleportPlayerAsync(player.get(), ticket.getTargetServer().getIdentifier()); + clearTicket(ticket, 3); + } catch (Exception e) { + MessageUtils.logWarning("Error processing ticket: " + ticket.getIdentifier(), e); + } + } - stage.set(TeleportStage.READY); + private void teleportPlayerAsync(Player player, String server) { + Optional targetServer = StreamlineVelocity.getInstance().getProxy().getServer(server); + if (targetServer.isPresent()) { + player.createConnectionRequest(targetServer.get()).connect(); + MessageUtils.logInfo("Teleported player " + player.getUsername() + " to server " + server + "."); + } } - private static void teleportPlayerAsync(Player player, String server) { - StreamlineVelocity.getInstance().getProxy().getServer(server).ifPresent(serverInfo -> { - ConnectionRequestBuilder builder = player.createConnectionRequest(serverInfo); - builder.connect().join(); - }); + private static void clearTicket(TPTicket ticket, int instance) { + ticket.clear(); + MessageUtils.logInfo("Cleared teleportation ticket for player " + ticket.getIdentifier() + ". [" + instance + "]"); } } From 32325a09436beb251705e48dcfc52efc06008230 Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 11 Jan 2025 19:53:28 -0500 Subject: [PATCH 2/3] optimize - tptickets. --- .../base/timers/AbstractPlayerTeleporter.java | 25 +++++- .../base/runnables/PlayerTeleporter.java | 12 ++- gradle.properties | 2 +- .../java/singularity/database/DBOperator.java | 87 ++++++++----------- .../java/singularity/utils/UserUtils.java | 5 +- .../base/runnables/PlayerTeleporter.java | 10 ++- .../base/runnables/PlayerTeleporter.java | 12 ++- 7 files changed, 89 insertions(+), 64 deletions(-) diff --git a/api/src/main/java/net/streamline/api/base/timers/AbstractPlayerTeleporter.java b/api/src/main/java/net/streamline/api/base/timers/AbstractPlayerTeleporter.java index ec66324e..42709c84 100644 --- a/api/src/main/java/net/streamline/api/base/timers/AbstractPlayerTeleporter.java +++ b/api/src/main/java/net/streamline/api/base/timers/AbstractPlayerTeleporter.java @@ -2,9 +2,13 @@ import lombok.Getter; import lombok.Setter; +import singularity.configs.given.GivenConfigs; import singularity.data.teleportation.TPTicket; import singularity.utils.MessageUtils; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentSkipListMap; +import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; @@ -33,7 +37,7 @@ public static synchronized void startInstance() { if (instance == null) { throw new IllegalStateException("Teleporter instance is not set."); } - if (!instance.isAlive()) { + if (! instance.isAlive()) { instance.start(); } } @@ -95,6 +99,25 @@ public void run() { } } + @Getter @Setter + private static AtomicReference>> atomicTicketsPending = new AtomicReference<>(null); + + public CompletableFuture> getTicketsPending() { + if (getAtomicTicketsPending().get() == null) { + getAtomicTicketsPending().set(GivenConfigs.getMainDatabase().pullAllTPTickets()); + } + + return getAtomicTicketsPending().get(); + } + + public void unpendTickets() { + getAtomicTicketsPending().set(null); + } + + public boolean areTicketsPending() { + return getAtomicTicketsPending().get() != null; + } + /** * Perform a single tick action if the teleporter is ready. */ diff --git a/bungee/src/main/java/net/streamline/base/runnables/PlayerTeleporter.java b/bungee/src/main/java/net/streamline/base/runnables/PlayerTeleporter.java index 45c4d12d..3996e16a 100644 --- a/bungee/src/main/java/net/streamline/base/runnables/PlayerTeleporter.java +++ b/bungee/src/main/java/net/streamline/base/runnables/PlayerTeleporter.java @@ -17,7 +17,7 @@ import java.util.concurrent.Executors; public class PlayerTeleporter extends AbstractPlayerTeleporter { - private static final ExecutorService executor = Executors.newFixedThreadPool(4); // Adjust as needed +// private static final ExecutorService executor = Executors.newFixedThreadPool(4); // Adjust as needed public static void init() { setInstance(new PlayerTeleporter()); @@ -26,12 +26,16 @@ public static void init() { @Override public void tick() { + if (areTicketsPending()) return; + getStage().set(TeleportStage.COLLECTION); - ConcurrentSkipListSet tickets = GivenConfigs.getMainDatabase().pullAllTPTickets().join(); + ConcurrentSkipListSet tickets = getTicketsPending().join(); getStage().set(TeleportStage.TELEPORTATION); - tickets.forEach(ticket -> executor.submit(() -> processTicket(ticket))); +// tickets.forEach(ticket -> executor.submit(() -> processTicket(ticket))); + tickets.forEach(this::processTicket); + unpendTickets(); getStage().set(TeleportStage.READY); } @@ -49,7 +53,7 @@ private void processTicket(TPTicket ticket) { } teleportPlayerAsync(player, ticket.getTargetServer().getIdentifier()); - clearTicket(ticket, 3); +// clearTicket(ticket, 3); // Handled by the Spigot side } catch (Exception e) { MessageUtils.logWarning("Error processing ticket: " + ticket.getIdentifier(), e); } diff --git a/gradle.properties b/gradle.properties index 43028bd5..b86d848c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ org.gradle.vfs.watch = false # Other properties name = StreamlineCore group = com.github.Streamline-Essentials.StreamlineCore -version = 2.5.0.0 +version = 2.5.1.0 base-version = c8388399 diff --git a/singularity-api/src/main/java/singularity/database/DBOperator.java b/singularity-api/src/main/java/singularity/database/DBOperator.java index 13403d23..a52446ba 100644 --- a/singularity-api/src/main/java/singularity/database/DBOperator.java +++ b/singularity-api/src/main/java/singularity/database/DBOperator.java @@ -42,6 +42,8 @@ public HikariDataSource buildDataSource() { break; case SQLITE: + initializeSQLiteDatabase(); + config.setJdbcUrl(connectorSet.getUri() + getDatabaseFolder().getPath() + File.separator + connectorSet.getSqliteFileName()); break; @@ -55,8 +57,7 @@ public HikariDataSource buildDataSource() { config.setDriverClassName(connectorSet.getType().getDriver()); config.setConnectionTestQuery("SELECT 1"); - dataSource = new HikariDataSource(config); - return dataSource; + return new HikariDataSource(config); } public Connection getConnection() { @@ -64,16 +65,9 @@ public Connection getConnection() { if (dataSource == null) { dataSource = buildDataSource(); } - - if (rawConnection != null && ! rawConnection.isClosed()) { - return rawConnection; - } - - rawConnection = dataSource.getConnection(); - - return rawConnection; + return dataSource.getConnection(); } catch (Exception e) { - e.printStackTrace(); + MessageUtils.logWarning("Failed to get connection", e); return null; } } @@ -83,21 +77,29 @@ public DatabaseType getType() { } public ExecutionResult executeSingle(String statement, Consumer statementBuilder) { - AtomicReference result = new AtomicReference<>(ExecutionResult.ERROR); - - try { - Connection connection = getConnection(); - PreparedStatement stmt = connection.prepareStatement(statement); + try (Connection connection = getConnection(); + PreparedStatement stmt = connection.prepareStatement(statement)) { statementBuilder.accept(stmt); - if (stmt.execute()) result.set(ExecutionResult.YES); - else result.set(ExecutionResult.NO); + return stmt.execute() ? ExecutionResult.YES : ExecutionResult.NO; } catch (Exception e) { - MessageUtils.logInfo("Failed to execute statement: " + statement, e); + MessageUtils.logWarning("Failed to execute statement: " + statement, e); + return ExecutionResult.ERROR; } + } - return result.get(); + public void executeQuery(String statement, Consumer statementBuilder, DBAction action) { + try (Connection connection = getConnection(); + PreparedStatement stmt = connection.prepareStatement(statement)) { + + statementBuilder.accept(stmt); + try (ResultSet set = stmt.executeQuery()) { + action.accept(set); + } + } catch (Exception e) { + MessageUtils.logWarning("Failed to execute query: " + statement, e); + } } public List execute(String statement, Consumer statementBuilder) { @@ -115,42 +117,14 @@ public List execute(String statement, Consumer statementBuilder, DBAction action) { - try { - Connection connection = getConnection(); - PreparedStatement stmt = connection.prepareStatement(statement); - - statementBuilder.accept(stmt); - - ResultSet set = stmt.executeQuery(); - - action.accept(set); - } catch (Exception e) { - MessageUtils.logInfo("Failed to execute query: " + statement, e); - } - } - - public void createSqliteFileIfNotExists() { - if (connectorSet.getType() != DatabaseType.SQLITE) return; - - File file = new File(getDatabaseFolder(), connectorSet.getSqliteFileName()); - if (! file.exists()) { - try { - file.createNewFile(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - public void ensureFile() { if (this.getConnectorSet().getType() != DatabaseType.SQLITE) return; String s1 = this.getConnectorSet().getSqliteFileName(); if (s1 == null) return; - if (s1.isBlank() || s1.isEmpty()) return; + if (s1.isBlank()) return; - createSqliteFileIfNotExists(); + initializeSQLiteDatabase(); } public abstract void ensureTables(); @@ -172,4 +146,17 @@ public static File getDatabaseFolder() { return folder; } + + private void initializeSQLiteDatabase() { + if (connectorSet.getType() == DatabaseType.SQLITE) { + File file = new File(getDatabaseFolder(), connectorSet.getSqliteFileName()); + if (! file.exists()) { + try { + file.createNewFile(); + } catch (Exception e) { + MessageUtils.logWarning("Failed to create SQLite database file", e); + } + } + } + } } diff --git a/singularity-api/src/main/java/singularity/utils/UserUtils.java b/singularity-api/src/main/java/singularity/utils/UserUtils.java index 2c158972..c5b64fdb 100644 --- a/singularity-api/src/main/java/singularity/utils/UserUtils.java +++ b/singularity-api/src/main/java/singularity/utils/UserUtils.java @@ -339,7 +339,10 @@ public static void teleport(CosmicSender sender, CosmicPlayer target) { } public static void teleport(CosmicSender sender, CosmicLocation location) { - if (sender.isConsole()) return; + if (sender.isConsole()) { + MessageUtils.logWarning("Console attempted to teleport to " + location.asString()); + return; + } TPTicket ticket = new TPTicket(sender.getIdentifier(), location); ticket.post(); diff --git a/spigot/src/main/java/net/streamline/base/runnables/PlayerTeleporter.java b/spigot/src/main/java/net/streamline/base/runnables/PlayerTeleporter.java index bb201976..72d1be1d 100644 --- a/spigot/src/main/java/net/streamline/base/runnables/PlayerTeleporter.java +++ b/spigot/src/main/java/net/streamline/base/runnables/PlayerTeleporter.java @@ -20,7 +20,7 @@ import java.util.concurrent.Executors; public class PlayerTeleporter extends AbstractPlayerTeleporter { - private static final ExecutorService executor = Executors.newFixedThreadPool(4); // Adjust as needed +// private static final ExecutorService executor = Executors.newFixedThreadPool(4); // Adjust as needed public static void init() { setInstance(new PlayerTeleporter()); @@ -29,12 +29,16 @@ public static void init() { @Override public void tick() { + if (areTicketsPending()) return; + getStage().set(TeleportStage.COLLECTION); - ConcurrentSkipListSet tickets = GivenConfigs.getMainDatabase().pullAllTPTickets().join(); + ConcurrentSkipListSet tickets = getTicketsPending().join(); getStage().set(TeleportStage.TELEPORTATION); - tickets.forEach(ticket -> executor.submit(() -> processTicket(ticket))); +// tickets.forEach(ticket -> executor.submit(() -> processTicket(ticket))); + tickets.forEach(this::processTicket); + unpendTickets(); getStage().set(TeleportStage.READY); } diff --git a/velocity/src/main/java/net/streamline/base/runnables/PlayerTeleporter.java b/velocity/src/main/java/net/streamline/base/runnables/PlayerTeleporter.java index 177014a3..e709a291 100644 --- a/velocity/src/main/java/net/streamline/base/runnables/PlayerTeleporter.java +++ b/velocity/src/main/java/net/streamline/base/runnables/PlayerTeleporter.java @@ -16,7 +16,7 @@ import java.util.concurrent.Executors; public class PlayerTeleporter extends AbstractPlayerTeleporter { - private static final ExecutorService executor = Executors.newFixedThreadPool(4); // Adjust as needed +// private static final ExecutorService executor = Executors.newFixedThreadPool(4); // Adjust as needed public static void init() { setInstance(new PlayerTeleporter()); @@ -25,12 +25,16 @@ public static void init() { @Override public void tick() { + if (areTicketsPending()) return; + getStage().set(TeleportStage.COLLECTION); - ConcurrentSkipListSet tickets = GivenConfigs.getMainDatabase().pullAllTPTickets().join(); + ConcurrentSkipListSet tickets = getTicketsPending().join(); getStage().set(TeleportStage.TELEPORTATION); - tickets.forEach(ticket -> executor.submit(() -> processTicket(ticket))); +// tickets.forEach(ticket -> executor.submit(() -> processTicket(ticket))); + tickets.forEach(this::processTicket); + unpendTickets(); getStage().set(TeleportStage.READY); } @@ -48,7 +52,7 @@ private void processTicket(TPTicket ticket) { } teleportPlayerAsync(player.get(), ticket.getTargetServer().getIdentifier()); - clearTicket(ticket, 3); +// clearTicket(ticket, 3); // Handled by the Spigot side } catch (Exception e) { MessageUtils.logWarning("Error processing ticket: " + ticket.getIdentifier(), e); } From f8095fad0fc88903e775e25505fa062e1a247ae4 Mon Sep 17 00:00:00 2001 From: Matt Date: Sun, 16 Mar 2025 23:38:09 -0400 Subject: [PATCH 3/3] update: base framework --- build.gradle | 13 +++- dependencies.gradle | 6 +- gradle.properties | 4 +- spigot/src/main/resources/plugin.yml | 5 ++ velocity/build.gradle | 9 ++- .../streamline/base/StreamlineVelocity.java | 75 ++++++++++++++++++- .../net/streamline/platform/BasePlugin.java | 18 +++-- 7 files changed, 109 insertions(+), 21 deletions(-) diff --git a/build.gradle b/build.gradle index 6c032642..d7eca954 100644 --- a/build.gradle +++ b/build.gradle @@ -47,7 +47,10 @@ subprojects { maven { url "https://oss.sonatype.org/content/repositories/snapshots" } maven { url "https://oss.sonatype.org/content/repositories/central" } // Paper / Velocity - maven { url "https://repo.papermc.io/repository/maven-public" } + maven { + name = 'papermc' + url = 'https://repo.papermc.io/repository/maven-public/' + } // Fabric maven { url "https://maven.fabricmc.net" } maven { url "https://libraries.minecraft.net" } @@ -69,6 +72,11 @@ subprojects { maven { url "https://repo.extendedclip.com/content/repositories/placeholderapi" } } + java { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + processResources { // Debugging: Print values doFirst { @@ -80,9 +88,6 @@ subprojects { inputs.property("main", project.ext.pluginMain.toString()) outputs.dir(file("build/generated-src")) - java.sourceCompatibility = JavaVersion.VERSION_11 - java.targetCompatibility = JavaVersion.VERSION_11 - filesMatching("**/plugin.yml") { expand ( "name": rootProject.name.toString(), diff --git a/dependencies.gradle b/dependencies.gradle index 881190c8..4eb9e16f 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -1,19 +1,19 @@ ext { IMPL = [ "com.github.ben-manes.caffeine:caffeine:3.1.8", - "com.github.server-utilities:TheBase:${rootProject.properties['base-version']}", + "com.github.Server-Utilities:TheBase:master-SNAPSHOT", "org.pf4j:pf4j:3.10.0", "commons-codec:commons-codec:1.5", ] SHADOW = [ "com.github.ben-manes.caffeine:caffeine:3.1.8", - "com.github.server-utilities:TheBase:${rootProject.properties['base-version']}", + "com.github.Server-Utilities:TheBase:master-SNAPSHOT", "org.pf4j:pf4j:3.10.0", "commons-codec:commons-codec:1.5", ] ANNO = [ "com.github.ben-manes.caffeine:caffeine:3.1.8", - "com.github.server-utilities:TheBase:${rootProject.properties['base-version']}", + "com.github.Server-Utilities:TheBase:master-SNAPSHOT", "org.pf4j:pf4j:3.10.0" ] COMP_ONLY = [ diff --git a/gradle.properties b/gradle.properties index b86d848c..440f44f2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,8 +9,8 @@ org.gradle.vfs.watch = false # Other properties name = StreamlineCore group = com.github.Streamline-Essentials.StreamlineCore -version = 2.5.1.0 +version = 2.5.3.0 -base-version = c8388399 +base-version = 6f2e7e2d plugin.main = default \ No newline at end of file diff --git a/spigot/src/main/resources/plugin.yml b/spigot/src/main/resources/plugin.yml index bc822a82..f7a1cd63 100644 --- a/spigot/src/main/resources/plugin.yml +++ b/spigot/src/main/resources/plugin.yml @@ -1,9 +1,13 @@ name: '${name}' version: '${version}' main: 'net.streamline.base.Streamline' + +api-version: 1.21 + authors: [ Drak ] website: https://github.com/Streamline-Essentials description: True potential is here. A Proxy and Spigot plugin that opens up endless cross-platform possibilities. + depend: - LuckPerms - BukkitOfUtils @@ -15,6 +19,7 @@ soft-depend: - CMI - EssentialsX - Essentials + folia-supported: true commands: diff --git a/velocity/build.gradle b/velocity/build.gradle index 5417fd63..b8de120a 100644 --- a/velocity/build.gradle +++ b/velocity/build.gradle @@ -1,6 +1,6 @@ dependencies { - compileOnly 'com.velocitypowered:velocity-api:3.2.0-SNAPSHOT' - annotationProcessor 'com.velocitypowered:velocity-api:3.2.0-SNAPSHOT' + compileOnly 'com.velocitypowered:velocity-api:3.4.0-SNAPSHOT' + annotationProcessor 'com.velocitypowered:velocity-api:3.4.0-SNAPSHOT' // implementation 'net.kyori:adventure-text-serializer-gson:4.15.0' @@ -24,3 +24,8 @@ compileJava { delombok { dependsOn(":StreamlineCore-API:jar") } + +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} \ No newline at end of file diff --git a/velocity/src/main/java/net/streamline/base/StreamlineVelocity.java b/velocity/src/main/java/net/streamline/base/StreamlineVelocity.java index 8f84f041..7fedc5fe 100644 --- a/velocity/src/main/java/net/streamline/base/StreamlineVelocity.java +++ b/velocity/src/main/java/net/streamline/base/StreamlineVelocity.java @@ -1,5 +1,6 @@ package net.streamline.base; +import com.google.inject.Inject; import com.velocitypowered.api.plugin.Dependency; import com.velocitypowered.api.plugin.Plugin; import com.velocitypowered.api.plugin.annotation.DataDirectory; @@ -9,7 +10,7 @@ import org.slf4j.Logger; import singularity.modules.ModuleManager; -import javax.inject.Inject; +import java.io.File; import java.nio.file.Path; @Plugin( @@ -23,8 +24,76 @@ ) public class StreamlineVelocity extends BasePlugin { @Inject - public StreamlineVelocity(ProxyServer s, Logger l, @DataDirectory Path dd, Metrics.Factory mf) { - super(s, l, dd, mf); + public StreamlineVelocity(ProxyServer server, + Logger logger, + Metrics.Factory metricsFactory) { + super(server, logger, getStreamlineFolder(), metricsFactory); + } + + public static File getStreamlineFolder() { + return new File(getPluginsDirectory(), "StreamlineCore"); + } + + public static File getPluginsDirectory() { + File file = getSystemFile(); + + File[] files = file.listFiles(); + if (files == null) { + return null; + } + + File pluginDirectory = null; + for (File f : files) { + if (f.getName().equals("plugins")) { + pluginDirectory = f; + break; + } + } + if (pluginDirectory == null) { + file = file.getParentFile(); + + files = file.listFiles(); + if (files == null) { + return null; + } + + for (File f : files) { + if (f.getName().equals("plugins")) { + pluginDirectory = f; + break; + } + } + } + + return pluginDirectory; + } + + public static Path getSystemPath() { + return Path.of(System.getProperty("user.dir")); + } + + public static File getSystemFile() { + return getSystemPath().toFile(); + } + + public static String getStreamlineName() { + String name = "${name}"; // Gets injected by Gradle + + if (name.startsWith("$")) { + name = "StreamlineCore"; + } + + return name; + } + + public static String getStreamlineVersion() { + String version = "${version}"; // Gets injected by Gradle + + if (version.startsWith("$")) { + version = "2.5.2.0"; + } + + return version; } @Override diff --git a/velocity/src/main/java/net/streamline/platform/BasePlugin.java b/velocity/src/main/java/net/streamline/platform/BasePlugin.java index cbf74228..1e3eb990 100644 --- a/velocity/src/main/java/net/streamline/platform/BasePlugin.java +++ b/velocity/src/main/java/net/streamline/platform/BasePlugin.java @@ -13,6 +13,7 @@ import lombok.Setter; import net.streamline.api.SLAPI; import net.streamline.api.base.module.BaseModule; +import net.streamline.base.StreamlineVelocity; import net.streamline.base.runnables.PlayerChecker; import net.streamline.base.runnables.PlayerTeleporter; import net.streamline.metrics.Metrics; @@ -79,6 +80,8 @@ public abstract class BasePlugin implements ISingularityExtension { @Getter private final Logger logger; @Getter + private final Path dataDirectory; + @Getter private final File dataFolder; @Getter private final Metrics.Factory metricsFactory; @@ -86,13 +89,14 @@ public abstract class BasePlugin implements ISingularityExtension { @Getter @Setter private static PlayerChecker playerChecker; - public BasePlugin(ProxyServer s, Logger l, Path dd, Metrics.Factory mf) { - this.proxy = s; - this.logger = l; - this.dataFolder = dd.toFile(); - this.metricsFactory = mf; + public BasePlugin(ProxyServer server, Logger logger, File dataFolder, Metrics.Factory metricsFactory) { + this.proxy = server; + this.logger = logger; + this.dataDirectory = dataFolder.toPath(); + this.dataFolder = dataFolder; + this.metricsFactory = metricsFactory; - Path parentPath = dd.getParent(); + Path parentPath = this.dataDirectory.getParent(); if (parentPath != null) { File parentFile = new File(parentPath.toString()); File[] files = parentFile.listFiles((f) -> { @@ -107,7 +111,7 @@ public BasePlugin(ProxyServer s, Logger l, Path dd, Metrics.Factory mf) { if (files != null) { Arrays.stream(files).forEach(file -> { - file.renameTo(new File(parentPath.toString(), this.name)); + file.renameTo(new File(parentPath.toString(), StreamlineVelocity.getStreamlineName())); }); } }