diff --git a/SkyblockCore-BungeeCord/src/main/java/me/illusion/skyblockcore/bungee/SkyblockBungeePlugin.java b/SkyblockCore-BungeeCord/src/main/java/me/illusion/skyblockcore/bungee/SkyblockBungeePlugin.java index 677aa12..f6d2c32 100644 --- a/SkyblockCore-BungeeCord/src/main/java/me/illusion/skyblockcore/bungee/SkyblockBungeePlugin.java +++ b/SkyblockCore-BungeeCord/src/main/java/me/illusion/skyblockcore/bungee/SkyblockBungeePlugin.java @@ -13,6 +13,9 @@ import me.illusion.skyblockcore.common.database.registry.SkyblockDatabaseRegistry; import me.illusion.skyblockcore.common.event.manager.SkyblockEventManager; import me.illusion.skyblockcore.common.event.manager.SkyblockEventManagerImpl; +import me.illusion.skyblockcore.common.platform.SkyblockPlatformProvider; +import me.illusion.skyblockcore.common.registry.Registries; +import me.illusion.skyblockcore.common.scheduler.SkyblockScheduler; import me.illusion.skyblockcore.common.utilities.file.IOUtils; import me.illusion.skyblockcore.proxy.SkyblockProxyPlatform; import me.illusion.skyblockcore.proxy.command.PlaySkyblockCommand; @@ -23,6 +26,7 @@ import me.illusion.skyblockcore.proxy.matchmaking.data.SkyblockServerMatchmaker; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.plugin.Plugin; +import net.md_5.bungee.api.plugin.PluginManager; /** * Bungee implementation of {@link SkyblockProxyPlatform}. @@ -34,6 +38,7 @@ public class SkyblockBungeePlugin extends Plugin implements SkyblockProxyPlatfor private SkyblockDatabaseRegistry databaseRegistry; private SkyblockEventManager eventManager; + private SkyblockScheduler scheduler; private SkyblockServerMatchmaker matchmaker; private SkyblockServerComparatorRegistry matchmakerComparatorRegistry; @@ -43,8 +48,11 @@ public class SkyblockBungeePlugin extends Plugin implements SkyblockProxyPlatfor private SkyblockCommandManager commandManager; private SkyblockMessagesFile messagesFile; + private Registries registries; + @Override public void onEnable() { + registries = new Registries(); configurationProvider = new BungeeConfigurationProvider(this); commandManager = new BungeeSkyblockCommandManager(this); @@ -62,6 +70,11 @@ public void onEnable() { ProxyServer.getInstance().getScheduler().schedule(this, this::loadDatabase, 1, TimeUnit.SECONDS); } + @Override + public void onLoad() { + SkyblockPlatformProvider.setPlatform(this); + } + private void finishEnable() { matchmaker = new BungeeSkyblockMatchmaker(this); } @@ -103,7 +116,9 @@ public void onDisable() { @Override public void disableExceptionally() { - ProxyServer.getInstance().getPluginManager().unregisterListeners(this); - ProxyServer.getInstance().getPluginManager().unregisterCommands(this); + PluginManager pluginManager = ProxyServer.getInstance().getPluginManager(); + + pluginManager.unregisterListeners(this); + pluginManager.unregisterCommands(this); } } diff --git a/SkyblockCore-BungeeCord/src/main/java/me/illusion/skyblockcore/bungee/command/BungeeSkyblockCommandManager.java b/SkyblockCore-BungeeCord/src/main/java/me/illusion/skyblockcore/bungee/command/BungeeSkyblockCommandManager.java index d2d276a..559eeb2 100644 --- a/SkyblockCore-BungeeCord/src/main/java/me/illusion/skyblockcore/bungee/command/BungeeSkyblockCommandManager.java +++ b/SkyblockCore-BungeeCord/src/main/java/me/illusion/skyblockcore/bungee/command/BungeeSkyblockCommandManager.java @@ -31,7 +31,7 @@ public void registerRoot(String name) { @Override public void syncCommands() { - + // BungeeCord does not need to sync commands } private class BungeeCommand extends Command implements TabExecutor { diff --git a/SkyblockCore-Common/build.gradle b/SkyblockCore-Common/build.gradle index 3237acc..f126917 100644 --- a/SkyblockCore-Common/build.gradle +++ b/SkyblockCore-Common/build.gradle @@ -23,6 +23,7 @@ dependencies { implementation 'redis.clients:jedis:5.0.1' compileOnly 'org.mongodb:mongodb-driver-sync:4.10.2' + compileOnly "com.influxdb:influxdb-client-java:6.10.0" } def targetJavaVersion = 17 diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/command/manager/AbstractSkyblockCommandManager.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/command/manager/AbstractSkyblockCommandManager.java index cf0c98f..d29e88c 100644 --- a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/command/manager/AbstractSkyblockCommandManager.java +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/command/manager/AbstractSkyblockCommandManager.java @@ -58,6 +58,11 @@ protected void handle(SkyblockAudience audience, St return; } + if (!result.isSuccess()) { + messages.sendMessage(audience, "invalid-argument"); + return; + } + CommandContext context = result.getContext(); SkyblockCommand command = (SkyblockCommand) argumentNode.getCommand(); diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/command/structure/CommandTree.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/command/structure/CommandTree.java index d67583c..350ea08 100644 --- a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/command/structure/CommandTree.java +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/command/structure/CommandTree.java @@ -53,7 +53,7 @@ public TargetResult getTargetNode(String fullInput) { } if (node.getChildren().isEmpty() && fullInput.equalsIgnoreCase(node.getName())) { - return new TargetResult(node, new MutatingCommandContext(fullInput)); + return new TargetResult(node, new MutatingCommandContext(fullInput), true); } CommandNode target = node; @@ -67,7 +67,7 @@ public TargetResult getTargetNode(String fullInput) { boolean isLast = index == split.length - 1; if (children == null) { - return null; + return new TargetResult(target, context, false); } CommandNode child = null; @@ -86,17 +86,13 @@ public TargetResult getTargetNode(String fullInput) { } if (child == null) { - return null; + return new TargetResult(target, context, false); } target = child; } - if (!valid) { - return null; - } - - return new TargetResult(target, context); + return new TargetResult(target, context, valid); } /** @@ -235,10 +231,13 @@ public static class TargetResult { private final CommandNode node; private final CommandContext context; + private final boolean success; + - public TargetResult(CommandNode node, CommandContext context) { + public TargetResult(CommandNode node, CommandContext context, boolean success) { this.node = node; this.context = context; + this.success = success; } } diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/data/IslandData.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/data/IslandData.java index c15597b..daee1fa 100644 --- a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/data/IslandData.java +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/data/IslandData.java @@ -17,6 +17,4 @@ public class IslandData implements Serializable { private final UUID islandId; private final UUID ownerId; // Profile ID, not player - // TODO: Add more data here - } diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/database/metrics/influx/InfluxMetricsDatabase.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/database/metrics/influx/InfluxMetricsDatabase.java new file mode 100644 index 0000000..bd43c7d --- /dev/null +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/database/metrics/influx/InfluxMetricsDatabase.java @@ -0,0 +1,126 @@ +package me.illusion.skyblockcore.common.database.metrics.influx; + +import com.influxdb.client.InfluxDBClient; +import com.influxdb.client.InfluxDBClientFactory; +import com.influxdb.client.WriteApi; +import com.influxdb.client.WriteOptions; +import com.influxdb.client.domain.WritePrecision; +import com.influxdb.client.write.Point; +import com.influxdb.client.write.events.WriteSuccessEvent; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import me.illusion.skyblockcore.common.config.section.ConfigurationSection; +import me.illusion.skyblockcore.common.database.AbstractSkyblockDatabase; +import me.illusion.skyblockcore.common.metrics.SkyblockMetric; +import me.illusion.skyblockcore.common.metrics.SkyblockMetricBroker; +import me.illusion.skyblockcore.common.metrics.data.InternalSkyblockMetric; +import me.illusion.skyblockcore.common.metrics.data.MetricTimestamp; +import me.illusion.skyblockcore.common.metrics.provider.SkyblockMetricProvider; +import me.illusion.skyblockcore.common.platform.SkyblockPlatform; +import me.illusion.skyblockcore.common.scheduler.ThreadContext; +import me.illusion.skyblockcore.common.utilities.time.Time; +import me.illusion.skyblockcore.common.utilities.time.TimeParser; + +public class InfluxMetricsDatabase extends AbstractSkyblockDatabase implements SkyblockMetricBroker { + + private final Map providers = new ConcurrentHashMap<>(); + + private CompletableFuture currentWrite = new CompletableFuture<>(); + + private InfluxDBClient client; + private WriteApi writeApi; + + @Override + public String getName() { + return "influx"; + } + + @Override + public CompletableFuture enable(SkyblockPlatform platform, ConfigurationSection properties) { + setProperties(properties); + + return associate(() -> { + String host = properties.getString("host"); + int port = properties.getInt("port"); + String bucket = properties.getString("bucket"); + String token = properties.getString("token"); + String org = properties.getString("org"); + + client = InfluxDBClientFactory.create(host + ":" + port, token.toCharArray(), org, bucket); + + if (!client.ping()) { + return false; + } + + Time updateTime = TimeParser.parse(properties.getString("update-interval", "5 seconds")); + + platform.getScheduler().scheduleRepeating(ThreadContext.SYNC, () -> run(ThreadContext.SYNC), updateTime, updateTime); + platform.getScheduler().scheduleRepeating(ThreadContext.ASYNC, () -> run(ThreadContext.ASYNC), updateTime, updateTime); + + Time batchTime = TimeParser.parse(properties.getString("batch-time", "1 second")); + + writeApi = client.makeWriteApi( + WriteOptions.builder() + .flushInterval(batchTime.as(TimeUnit.MILLISECONDS)) + .build() + ); + + writeApi.listenEvents(WriteSuccessEvent.class, event -> { + currentWrite.complete(null); + currentWrite = new CompletableFuture<>(); + }); + + return true; + }); + } + + @Override + public CompletableFuture wipe() { + // no-op + // TODO: Use Offsets and stuff + return CompletableFuture.completedFuture(null); + } + + @Override + public SkyblockMetric createMetric(String name) { + MetricTimestamp timestamp = MetricTimestamp.currentMillis(); + + return new InternalSkyblockMetric(this, name, timestamp); + } + + @Override + public void registerProvider(SkyblockMetricProvider provider) { + providers.put(provider.getName(), provider); + } + + @Override + public CompletableFuture submit(SkyblockMetric metric) { + InternalSkyblockMetric internalMetric = (InternalSkyblockMetric) metric; + MetricTimestamp timestamp = internalMetric.getTimestamp(); + + long ns = timestamp.getTimeUnit().convert(timestamp.getTime(), TimeUnit.NANOSECONDS); + + Point point = Point.measurement(internalMetric.getName()) + .addFields(internalMetric.getData()) + .time(ns, WritePrecision.NS); + + writeApi.writePoint(point); + + return currentWrite; + } + + public void run(ThreadContext context) { + for (SkyblockMetricProvider provider : providers.values()) { + + if (provider.getThreadContext() != context) { + continue; + } + + SkyblockMetric metric = createMetric(provider.getName()); + provider.fillData(metric); + submit(metric); + } + } +} diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/database/persistence/sql/AbstractRemoteSQLPersistenceDatabase.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/database/persistence/sql/AbstractRemoteSQLPersistenceDatabase.java index 2165a80..be06178 100644 --- a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/database/persistence/sql/AbstractRemoteSQLPersistenceDatabase.java +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/database/persistence/sql/AbstractRemoteSQLPersistenceDatabase.java @@ -12,7 +12,7 @@ public abstract class AbstractRemoteSQLPersistenceDatabase extends AbstractSQLPe protected String username; protected String password; - public AbstractRemoteSQLPersistenceDatabase() { + protected AbstractRemoteSQLPersistenceDatabase() { addTag(SkyblockDatabaseTag.REMOTE); } diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/database/persistence/sql/AbstractSQLPersistenceDatabase.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/database/persistence/sql/AbstractSQLPersistenceDatabase.java index 617c6f8..39be252 100644 --- a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/database/persistence/sql/AbstractSQLPersistenceDatabase.java +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/database/persistence/sql/AbstractSQLPersistenceDatabase.java @@ -41,47 +41,31 @@ public CompletableFuture enable(ConfigurationSection properties) { }); } - protected ResultSet runQuery(String query, List list) { + protected T runQuery(String query, List list, ResultSetFunction function) { try (PreparedStatement statement = getConnection().prepareStatement(query)) { for (int index = 0; index < list.size(); index++) { list.get(index).applyTo(statement, index + 1); } - return statement.executeQuery(); - } catch (Exception ex) { - ex.printStackTrace(); - } - - return null; - } - - protected CompletableFuture runQueryAsync(String query, List list, ResultSetFunction function) { - return associate(() -> { - ResultSet set = runQuery(query, list); - - if (set == null) { - return null; - } + ResultSet set = statement.executeQuery(); // This will be auto-closed by the try-with-resources try { return function.apply(set); - } catch (Exception e) { + } catch (SQLException e) { throw new RuntimeException(e); - } finally { - try { - set.close(); - } catch (SQLException e) { - e.printStackTrace(); - } } - }); + } catch (SQLException ex) { + ex.printStackTrace(); + } + + return null; } protected void runUpdate(String query, Consumer consumer) { try (PreparedStatement statement = getConnection().prepareStatement(query)) { consumer.accept(statement); statement.executeUpdate(); - } catch (Exception ex) { + } catch (SQLException ex) { ex.printStackTrace(); } } @@ -103,15 +87,12 @@ protected void runUpdate(String query) { }); } + protected CompletableFuture runQueryAsync(String query, List list, ResultSetFunction function) { + return associate(() -> runQuery(query, list, function)); + } + protected CompletableFuture runUpdateAsync(String query, Consumer consumer) { - return associate(() -> { - try (PreparedStatement statement = getConnection().prepareStatement(query)) { - consumer.accept(statement); - statement.executeUpdate(); - } catch (Exception ex) { - ex.printStackTrace(); - } - }); + return associate(() -> runUpdate(query, consumer)); } protected CompletableFuture runUpdateAsync(String query, StatementObject... objects) { diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/database/registry/SkyblockDatabaseRegistry.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/database/registry/SkyblockDatabaseRegistry.java index 5f12042..43e25ef 100644 --- a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/database/registry/SkyblockDatabaseRegistry.java +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/database/registry/SkyblockDatabaseRegistry.java @@ -12,6 +12,7 @@ import me.illusion.skyblockcore.common.config.section.WritableConfigurationSection; import me.illusion.skyblockcore.common.database.SkyblockDatabase; import me.illusion.skyblockcore.common.database.cache.SkyblockCache; +import me.illusion.skyblockcore.common.database.metrics.influx.InfluxMetricsDatabase; import me.illusion.skyblockcore.common.platform.SkyblockPlatform; import me.illusion.skyblockcore.common.storage.SkyblockStorage; import me.illusion.skyblockcore.common.storage.cache.redis.MemorySkyblockIslandCache; @@ -55,6 +56,10 @@ private void registerDefaults() { new RedisSkyblockIslandCache(), new MemorySkyblockIslandCache() )); + + register("metrics", SkyblockDatabaseProvider.of( + new InfluxMetricsDatabase() + )); } // --- CORE LOGIC --- @@ -125,11 +130,10 @@ public CompletableFuture loadPossible(ConfigurationSection section) { continue; } - if(keys.contains(registeredDatabase.getName())) { + if (keys.contains(registeredDatabase.getName())) { registeredDatabase.setAttemptedLoad(true); } - temp.add(tryLoad(registeredDatabase)); } diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/database/sql/functional/ResultSetConsumer.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/database/sql/functional/ResultSetConsumer.java deleted file mode 100644 index c719560..0000000 --- a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/database/sql/functional/ResultSetConsumer.java +++ /dev/null @@ -1,9 +0,0 @@ -package me.illusion.skyblockcore.common.database.sql.functional; - -import java.sql.ResultSet; - -@FunctionalInterface -public interface ResultSetConsumer { - - void accept(ResultSet resultSet) throws Exception; -} diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/database/sql/functional/ResultSetFunction.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/database/sql/functional/ResultSetFunction.java index a268c25..0d6948c 100644 --- a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/database/sql/functional/ResultSetFunction.java +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/database/sql/functional/ResultSetFunction.java @@ -1,10 +1,11 @@ package me.illusion.skyblockcore.common.database.sql.functional; import java.sql.ResultSet; +import java.sql.SQLException; @FunctionalInterface public interface ResultSetFunction { - T apply(ResultSet resultSet) throws Exception; + T apply(ResultSet resultSet) throws SQLException; } diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/event/manager/SkyblockEventManagerImpl.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/event/manager/SkyblockEventManagerImpl.java index fa4b0af..b57cd3f 100644 --- a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/event/manager/SkyblockEventManagerImpl.java +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/event/manager/SkyblockEventManagerImpl.java @@ -15,14 +15,11 @@ public class SkyblockEventManagerImpl implements SkyblockEventManager { @Override public void subscribe(Class eventClass, SkyblockEventListener listener) { - System.out.println("Subscribing to event " + eventClass.getSimpleName()); handlers.add(new SkyblockEventHandler<>(eventClass, listener)); } @Override public void callEvent(T event) { - System.out.println("Calling event " + event.getClass().getSimpleName()); - for (SkyblockEventHandler handler : handlers) { Class eventClass = handler.getEventClass(); diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/metrics/SkyblockMetric.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/metrics/SkyblockMetric.java new file mode 100644 index 0000000..d1108b3 --- /dev/null +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/metrics/SkyblockMetric.java @@ -0,0 +1,11 @@ +package me.illusion.skyblockcore.common.metrics; + +import java.util.concurrent.CompletableFuture; + +public interface SkyblockMetric { + + void addData(String key, Object value); + + CompletableFuture submit(); + +} diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/metrics/SkyblockMetricBroker.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/metrics/SkyblockMetricBroker.java new file mode 100644 index 0000000..ace8570 --- /dev/null +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/metrics/SkyblockMetricBroker.java @@ -0,0 +1,14 @@ +package me.illusion.skyblockcore.common.metrics; + +import java.util.concurrent.CompletableFuture; +import me.illusion.skyblockcore.common.metrics.provider.SkyblockMetricProvider; + +public interface SkyblockMetricBroker { + + SkyblockMetric createMetric(String name); + + void registerProvider(SkyblockMetricProvider provider); + + CompletableFuture submit(SkyblockMetric metric); + +} diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/metrics/data/InternalSkyblockMetric.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/metrics/data/InternalSkyblockMetric.java new file mode 100644 index 0000000..c5cbf39 --- /dev/null +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/metrics/data/InternalSkyblockMetric.java @@ -0,0 +1,45 @@ +package me.illusion.skyblockcore.common.metrics.data; + +import com.google.common.collect.ImmutableMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import me.illusion.skyblockcore.common.metrics.SkyblockMetric; +import me.illusion.skyblockcore.common.metrics.SkyblockMetricBroker; + +public class InternalSkyblockMetric implements SkyblockMetric { + + private final String name; + private final MetricTimestamp timestamp; + private final Map data = new ConcurrentHashMap<>(); + + private final SkyblockMetricBroker broker; + + public InternalSkyblockMetric(SkyblockMetricBroker broker, String name, MetricTimestamp timestamp) { + this.broker = broker; + this.name = name; + this.timestamp = timestamp; + } + + @Override + public void addData(String key, Object value) { + data.put(key, value); + } + + @Override + public CompletableFuture submit() { + return broker.submit(this); + } + + public Map getData() { + return ImmutableMap.copyOf(data); + } + + public String getName() { + return name; + } + + public MetricTimestamp getTimestamp() { + return timestamp; + } +} diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/metrics/data/MetricTimestamp.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/metrics/data/MetricTimestamp.java new file mode 100644 index 0000000..d980a37 --- /dev/null +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/metrics/data/MetricTimestamp.java @@ -0,0 +1,30 @@ +package me.illusion.skyblockcore.common.metrics.data; + +import java.util.concurrent.TimeUnit; + +public class MetricTimestamp { + + private final long time; + private final TimeUnit timeUnit; + + public MetricTimestamp(long time, TimeUnit timeUnit) { + this.time = time; + this.timeUnit = timeUnit; + } + + public static MetricTimestamp currentMillis() { + return new MetricTimestamp(System.currentTimeMillis(), TimeUnit.MILLISECONDS); + } + + public static MetricTimestamp currentNano() { + return new MetricTimestamp(System.nanoTime(), TimeUnit.NANOSECONDS); + } + + public long getTime() { + return time; + } + + public TimeUnit getTimeUnit() { + return timeUnit; + } +} diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/metrics/provider/SkyblockMetricProvider.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/metrics/provider/SkyblockMetricProvider.java new file mode 100644 index 0000000..a30afeb --- /dev/null +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/metrics/provider/SkyblockMetricProvider.java @@ -0,0 +1,14 @@ +package me.illusion.skyblockcore.common.metrics.provider; + +import me.illusion.skyblockcore.common.metrics.SkyblockMetric; +import me.illusion.skyblockcore.common.scheduler.ThreadContext; + +public interface SkyblockMetricProvider { + + String getName(); + + ThreadContext getThreadContext(); + + void fillData(SkyblockMetric metric); + +} diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/platform/SkyblockPlatform.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/platform/SkyblockPlatform.java index bfe408c..642389d 100644 --- a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/platform/SkyblockPlatform.java +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/platform/SkyblockPlatform.java @@ -7,6 +7,8 @@ import me.illusion.skyblockcore.common.config.SkyblockMessagesFile; import me.illusion.skyblockcore.common.database.registry.SkyblockDatabaseRegistry; import me.illusion.skyblockcore.common.event.manager.SkyblockEventManager; +import me.illusion.skyblockcore.common.registry.Registries; +import me.illusion.skyblockcore.common.scheduler.SkyblockScheduler; /** * The SkyblockPlatform interface is a template that includes all the common methods across all platforms, such as Spigot, Bungee, Velocity etc. This interface @@ -56,6 +58,20 @@ public interface SkyblockPlatform { */ SkyblockMessagesFile getMessagesFile(); + /** + * Gets the registries for the platform + * @return the registries for the platform + */ + Registries getRegistries(); + + /** + * Gets the scheduler for the platform + * + * @return the scheduler for the platform + */ + SkyblockScheduler getScheduler(); + + /** * Disables the platform due to an initialization error (e.g. incorrect configuration) */ diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/platform/SkyblockPlatformProvider.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/platform/SkyblockPlatformProvider.java new file mode 100644 index 0000000..0522273 --- /dev/null +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/platform/SkyblockPlatformProvider.java @@ -0,0 +1,22 @@ +package me.illusion.skyblockcore.common.platform; + +public final class SkyblockPlatformProvider { + + private static SkyblockPlatform platform; + + private SkyblockPlatformProvider() { + } + + public static SkyblockPlatform getPlatform() { + return platform; + } + + public static void setPlatform(SkyblockPlatform platform) { + if (SkyblockPlatformProvider.platform != null) { + throw new IllegalStateException("Platform already set!"); + } + + SkyblockPlatformProvider.platform = platform; + } + +} diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/registry/Keyed.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/registry/Keyed.java new file mode 100644 index 0000000..fb18066 --- /dev/null +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/registry/Keyed.java @@ -0,0 +1,6 @@ +package me.illusion.skyblockcore.common.registry; + +public interface Keyed { + + SkyblockNamespacedKey getKey(); +} diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/registry/Registries.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/registry/Registries.java new file mode 100644 index 0000000..de34c2c --- /dev/null +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/registry/Registries.java @@ -0,0 +1,46 @@ +package me.illusion.skyblockcore.common.registry; + +import java.util.Collection; +import java.util.concurrent.ConcurrentHashMap; + +public class Registries { + + private final Collection> internalCollection = ConcurrentHashMap.newKeySet(); + + public Registry createRegistry(Class type) { + Registry registry = new SimpleRegistry<>(type); + internalCollection.add(registry); + return registry; + } + + public void registerRegistry(Registry registry) { + internalCollection.add(registry); + } + + public void lockAll() { + for (Registry registry : internalCollection) { + registry.lock(); + } + } + + public Registry getRegistry(Class clazz) { + for (Registry registry : internalCollection) { + if (registry.getObjectType() == clazz) { + return (Registry) registry; + } + } + + return null; + } + + public > T getSpecificRegistry(Class clazz) { + for (Registry registry : internalCollection) { + if (clazz.isAssignableFrom(registry.getClass())) { + return (T) registry; + } + } + + return null; + } + +} diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/registry/Registry.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/registry/Registry.java new file mode 100644 index 0000000..304b866 --- /dev/null +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/registry/Registry.java @@ -0,0 +1,32 @@ +package me.illusion.skyblockcore.common.registry; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public abstract class Registry { + + protected final Map internalMap = new ConcurrentHashMap<>(); + protected boolean locked = false; + + public void register(T value) { + if (locked) { + throw new IllegalStateException("Registry is locked"); + } + + if (internalMap.containsKey(value.getKey())) { + throw new IllegalArgumentException("Duplicate key " + value.getKey().toString()); + } + + internalMap.put(value.getKey(), value); + } + + public T get(SkyblockNamespacedKey key) { + return internalMap.get(key); + } + + public void lock() { + locked = true; + } + + public abstract Class getObjectType(); +} diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/registry/SimpleRegistry.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/registry/SimpleRegistry.java new file mode 100644 index 0000000..1ab060e --- /dev/null +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/registry/SimpleRegistry.java @@ -0,0 +1,16 @@ +package me.illusion.skyblockcore.common.registry; + +public class SimpleRegistry extends Registry { + + private final Class clazz; + + public SimpleRegistry(Class clazz) { + this.clazz = clazz; + } + + + @Override + public Class getObjectType() { + return clazz; + } +} diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/registry/SkyblockNamespacedKey.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/registry/SkyblockNamespacedKey.java new file mode 100644 index 0000000..464b819 --- /dev/null +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/registry/SkyblockNamespacedKey.java @@ -0,0 +1,71 @@ +package me.illusion.skyblockcore.common.registry; + +import java.util.Locale; +import java.util.regex.Pattern; + +public class SkyblockNamespacedKey { + + private static final Pattern PATTERN = Pattern.compile("^[a-z0-9._-]+$"); + private static final String MINECRAFT_NAMESPACE = "minecraft"; + private static final String SKYBLOCK_NAMESPACE = "skyblock"; + + private final String namespace; + private final String key; + + public SkyblockNamespacedKey(String namespace, String key) { + this.namespace = namespace.toLowerCase(Locale.ROOT); + this.key = key.toLowerCase(Locale.ROOT); + + validatePattern(); + } + + public static SkyblockNamespacedKey minecraft(String key) { + return new SkyblockNamespacedKey(MINECRAFT_NAMESPACE, key); + } + + public static SkyblockNamespacedKey skyblock(String key) { + return new SkyblockNamespacedKey(SKYBLOCK_NAMESPACE, key); + } + + public String getNamespace() { + return namespace; + } + + public String getKey() { + return key; + } + + @Override + public String toString() { + return namespace + ":" + key; + } + + private void validatePattern() { + if (!PATTERN.matcher(namespace).matches()) { + throw new IllegalArgumentException("Namespace '" + namespace + "' does not match pattern " + PATTERN.pattern()); + } + + if (!PATTERN.matcher(key).matches()) { + throw new IllegalArgumentException("Key '" + key + "' does not match pattern " + PATTERN.pattern()); + } + } + + public SkyblockNamespacedKey fromInput(String input) { + String[] split = input.split(":"); + + String namespace; + String key; + + if (split.length == 1) { + namespace = MINECRAFT_NAMESPACE; + key = split[0]; + } else if (split.length == 2) { + namespace = split[0]; + key = split[1]; + } else { + throw new IllegalArgumentException("Input '" + input + "' does not follow the pattern namespace:key"); + } + + return new SkyblockNamespacedKey(namespace, key); + } +} diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/scheduler/ScheduledTask.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/scheduler/ScheduledTask.java new file mode 100644 index 0000000..1b0f7dd --- /dev/null +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/scheduler/ScheduledTask.java @@ -0,0 +1,12 @@ +package me.illusion.skyblockcore.common.scheduler; + +import java.util.UUID; + +public interface ScheduledTask { + + boolean isCancelled(); + + void cancel(); + + UUID getTaskId(); +} diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/scheduler/ScheduledTaskImpl.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/scheduler/ScheduledTaskImpl.java new file mode 100644 index 0000000..5e2ca6d --- /dev/null +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/scheduler/ScheduledTaskImpl.java @@ -0,0 +1,29 @@ +package me.illusion.skyblockcore.common.scheduler; + +import java.util.UUID; + +public class ScheduledTaskImpl implements ScheduledTask { + + private final UUID taskId; + private final SkyblockScheduler scheduler; + + public ScheduledTaskImpl(UUID taskId, SkyblockScheduler scheduler) { + this.taskId = taskId; + this.scheduler = scheduler; + } + + @Override + public boolean isCancelled() { + return scheduler.isCancelled(taskId); + } + + @Override + public void cancel() { + scheduler.cancel(taskId); + } + + @Override + public UUID getTaskId() { + return taskId; + } +} diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/scheduler/SkyblockScheduler.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/scheduler/SkyblockScheduler.java new file mode 100644 index 0000000..eb085ab --- /dev/null +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/scheduler/SkyblockScheduler.java @@ -0,0 +1,26 @@ +package me.illusion.skyblockcore.common.scheduler; + +import java.util.UUID; +import java.util.function.Consumer; +import me.illusion.skyblockcore.common.utilities.time.Time; + +public interface SkyblockScheduler { + + boolean isCancelled(UUID taskId); + + void cancel(UUID taskId); + + + default UUID scheduleOnce(ThreadContext context, Runnable task, Time delay) { + return scheduleOnce(context, t -> task.run(), delay); + } + + UUID scheduleOnce(ThreadContext context, Consumer task, Time delay); + + default UUID scheduleRepeating(ThreadContext context, Runnable task, Time delay, Time period) { + return scheduleRepeating(context, t -> task.run(), delay, period); + } + + UUID scheduleRepeating(ThreadContext context, Consumer task, Time delay, Time period); + +} diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/scheduler/ThreadContext.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/scheduler/ThreadContext.java new file mode 100644 index 0000000..0100b20 --- /dev/null +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/scheduler/ThreadContext.java @@ -0,0 +1,6 @@ +package me.illusion.skyblockcore.common.scheduler; + +public enum ThreadContext { + SYNC, + ASYNC +} diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/storage/cache/redis/RedisSkyblockIslandCache.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/storage/cache/redis/RedisSkyblockIslandCache.java index 5213668..fe18bd8 100644 --- a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/storage/cache/redis/RedisSkyblockIslandCache.java +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/storage/cache/redis/RedisSkyblockIslandCache.java @@ -11,24 +11,22 @@ public class RedisSkyblockIslandCache extends AbstractRedisCacheDatabase implements SkyblockIslandCache { + private static final String ISLANDS_KEY = "islands"; + @Override public CompletableFuture wipe() { - return update(jedis -> { - jedis.hdel("islands", jedis.hkeys("islands").toArray(new String[0])); - }); + return update(jedis -> jedis.hdel(ISLANDS_KEY, jedis.hkeys(ISLANDS_KEY).toArray(new String[0]))); } @Override public CompletableFuture unloadServer() { - return update(jedis -> { - jedis.hdel("islands", jedis.hkeys("islands").toArray(new String[0])); - }); + return update(jedis -> jedis.hdel(ISLANDS_KEY, jedis.hkeys(ISLANDS_KEY).toArray(new String[0]))); } @Override public CompletableFuture>> getAllIslands() { return query(jedis -> { - Map islands = jedis.hgetAll("islands"); + Map islands = jedis.hgetAll(ISLANDS_KEY); Map> map = new HashMap<>(); for (Map.Entry entry : islands.entrySet()) { @@ -44,33 +42,27 @@ public CompletableFuture>> getAllIslands() { @Override public CompletableFuture getIslandServer(UUID islandId) { - return query(jedis -> { - return jedis.hget("islands", islandId.toString()); - }); + return query(jedis -> jedis.hget(ISLANDS_KEY, islandId.toString())); } @Override public CompletableFuture setServer(UUID islandId, String serverId) { - return update(jedis -> { - jedis.hset("islands", islandId.toString(), serverId); - }); + return update(jedis -> jedis.hset(ISLANDS_KEY, islandId.toString(), serverId)); } @Override public CompletableFuture removeIsland(UUID islandId) { - return update(jedis -> { - jedis.hdel("islands", islandId.toString()); - }); + return update(jedis -> jedis.hdel(ISLANDS_KEY, islandId.toString())); } @Override public CompletableFuture removeServer(String serverId) { return update(jedis -> { - Map islands = jedis.hgetAll("islands"); + Map islands = jedis.hgetAll(ISLANDS_KEY); for (Map.Entry entry : islands.entrySet()) { if (entry.getValue().equals(serverId)) { - jedis.hdel("islands", entry.getKey()); + jedis.hdel(ISLANDS_KEY, entry.getKey()); } } }); diff --git a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/utilities/time/Time.java b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/utilities/time/Time.java index 21c9798..f8b212b 100644 --- a/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/utilities/time/Time.java +++ b/SkyblockCore-Common/src/main/java/me/illusion/skyblockcore/common/utilities/time/Time.java @@ -21,8 +21,8 @@ public Time(int duration, TimeUnit unit) { * @param unit The unit to convert to * @return The converted time */ - public long as(TimeUnit unit) { - return unit.convert(duration, this.unit); + public int as(TimeUnit unit) { + return (int) unit.convert(duration, this.unit); } /** diff --git a/SkyblockCore-Proxy/src/main/java/me/illusion/skyblockcore/proxy/command/PlaySkyblockCommand.java b/SkyblockCore-Proxy/src/main/java/me/illusion/skyblockcore/proxy/command/PlaySkyblockCommand.java index 5a99a63..4b0fdb2 100644 --- a/SkyblockCore-Proxy/src/main/java/me/illusion/skyblockcore/proxy/command/PlaySkyblockCommand.java +++ b/SkyblockCore-Proxy/src/main/java/me/illusion/skyblockcore/proxy/command/PlaySkyblockCommand.java @@ -5,6 +5,7 @@ import me.illusion.skyblockcore.common.command.audience.SkyblockAudience; import me.illusion.skyblockcore.common.command.manager.SkyblockCommandManager; import me.illusion.skyblockcore.common.config.SkyblockMessagesFile; +import me.illusion.skyblockcore.common.database.registry.SkyblockDatabaseRegistry; import me.illusion.skyblockcore.common.storage.island.SkyblockIslandStorage; import me.illusion.skyblockcore.common.storage.profiles.SkyblockProfileStorage; import me.illusion.skyblockcore.proxy.SkyblockProxyPlatform; @@ -44,8 +45,10 @@ public PlaySkyblockCommand(SkyblockProxyPlatform platform) { } private CompletableFuture fetchIslandId(UUID playerId) { - SkyblockProfileStorage profileStorage = platform.getDatabaseRegistry().getStorage(SkyblockProfileStorage.class); - SkyblockIslandStorage islandStorage = platform.getDatabaseRegistry().getStorage(SkyblockIslandStorage.class); + SkyblockDatabaseRegistry databaseRegistry = platform.getDatabaseRegistry(); + + SkyblockProfileStorage profileStorage = databaseRegistry.getStorage(SkyblockProfileStorage.class); + SkyblockIslandStorage islandStorage = databaseRegistry.getStorage(SkyblockIslandStorage.class); return profileStorage.getProfileId(playerId).thenCompose(uuid -> { if (uuid == null) { diff --git a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/island/AbstractIslandManager.java b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/island/AbstractIslandManager.java index a4709a9..f39df2a 100644 --- a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/island/AbstractIslandManager.java +++ b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/island/AbstractIslandManager.java @@ -43,7 +43,7 @@ public CompletableFuture loadPlayerIsland(UUID profileId, String SkyblockIsland cached = getProfileIsland(profileId); if (cached != null) { // Idiots - System.out.println("Loaded cached island"); + platform.getLogger().info("Loaded cached island"); return CompletableFuture.completedFuture(cached); } @@ -171,4 +171,9 @@ public SkyblockIsland getIslandAt(SkyblockLocation location) { return null; } + + @Override + public int getLoadedIslandCount() { + return loadedIslands.size(); + } } diff --git a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/island/SkyblockIslandManager.java b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/island/SkyblockIslandManager.java index 76d7932..34bbaba 100644 --- a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/island/SkyblockIslandManager.java +++ b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/island/SkyblockIslandManager.java @@ -131,4 +131,11 @@ default SkyblockIsland getPlayerIsland(SkyblockPlayer player) { * @return The island at the location. */ SkyblockIsland getIslandAt(SkyblockLocation location); + + /** + * Gets the amount of loaded islands, useful for metrics. + * + * @return The amount of loaded islands. + */ + int getLoadedIslandCount(); } diff --git a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/MinecraftItem.java b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/MinecraftItem.java new file mode 100644 index 0000000..d675099 --- /dev/null +++ b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/MinecraftItem.java @@ -0,0 +1,19 @@ +package me.illusion.skyblockcore.server.item; + +import me.illusion.skyblockcore.common.registry.Keyed; +import me.illusion.skyblockcore.common.registry.SkyblockNamespacedKey; +import me.illusion.skyblockcore.server.item.stack.meta.ItemMeta; + +public interface MinecraftItem extends Keyed { + + MinecraftMaterial getMaterial(); + + int getMaxStackSize(); + + ItemMeta createItemMeta(); + + @Override + default SkyblockNamespacedKey getKey() { + return getMaterial().getKey(); + } +} diff --git a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/MinecraftMaterial.java b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/MinecraftMaterial.java new file mode 100644 index 0000000..26e9145 --- /dev/null +++ b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/MinecraftMaterial.java @@ -0,0 +1,33 @@ +package me.illusion.skyblockcore.server.item; + +import me.illusion.skyblockcore.common.platform.SkyblockPlatform; +import me.illusion.skyblockcore.common.platform.SkyblockPlatformProvider; +import me.illusion.skyblockcore.common.registry.Keyed; +import me.illusion.skyblockcore.common.registry.Registry; +import me.illusion.skyblockcore.common.registry.SkyblockNamespacedKey; + +public abstract class MinecraftMaterial implements Keyed { + + private final SkyblockNamespacedKey key; + + protected MinecraftMaterial(SkyblockNamespacedKey key) { + this.key = key; + } + + public static MinecraftMaterial of(SkyblockNamespacedKey key) { + SkyblockPlatform platform = SkyblockPlatformProvider.getPlatform(); + Registry registry = platform.getRegistries().getRegistry(MinecraftMaterial.class); + return registry.get(key); + } + + public static MinecraftMaterial of(String key) { + return MinecraftMaterial.of(SkyblockNamespacedKey.minecraft(key)); + } + + public abstract MinecraftItem attemptCreateItem(); + + @Override + public SkyblockNamespacedKey getKey() { + return key; + } +} diff --git a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/MinecraftItemStack.java b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/MinecraftItemStack.java new file mode 100644 index 0000000..d365df8 --- /dev/null +++ b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/MinecraftItemStack.java @@ -0,0 +1,73 @@ +package me.illusion.skyblockcore.server.item.stack; + +import java.util.function.UnaryOperator; +import me.illusion.skyblockcore.server.item.MinecraftItem; +import me.illusion.skyblockcore.server.item.stack.meta.ItemMeta; + +public class MinecraftItemStack { + + private final MinecraftItem item; + private ItemMeta meta; + + private int amount; + + private MinecraftItemStack(MinecraftItem item, int amount) { + this.item = item; + this.amount = amount; + + this.meta = item.createItemMeta(); + } + + public MinecraftItemStack(MinecraftItem item) { + this(item, 1); + } + + public static MinecraftItemStack create(MinecraftItem item, int amount) { + return new MinecraftItemStack(item, amount); + } + + public static MinecraftItemStack create(MinecraftItem item) { + return new MinecraftItemStack(item); + } + + public ItemMeta getMeta() { + return meta; + } + + public void modifyMeta(UnaryOperator operator) { + meta = operator.apply(meta); + } + + public int getAmount() { + return amount; + } + + public void setAmount(int amount) { + this.amount = amount; + } + + public boolean isSimilar(MinecraftItemStack other) { + return item == other.item && meta.equals(other.meta); + } + + @Override + public int hashCode() { + int result = item.hashCode(); + result = 31 * result + meta.hashCode(); + result = 31 * result + amount; + return result; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof MinecraftItemStack other)) { + return false; + } + + if (other == this) { + return true; + } + + return isSimilar(other) && amount == other.amount; + } +} diff --git a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/ItemMeta.java b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/ItemMeta.java new file mode 100644 index 0000000..9a4329f --- /dev/null +++ b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/ItemMeta.java @@ -0,0 +1,72 @@ +package me.illusion.skyblockcore.server.item.stack.meta; + +import java.util.Collection; +import java.util.List; +import java.util.Set; +import me.illusion.skyblockcore.server.item.stack.meta.data.ItemFlag; +import me.illusion.skyblockcore.server.item.stack.meta.value.BuiltinMetaValues; +import me.illusion.skyblockcore.server.item.stack.meta.value.MetaValue; + +public interface ItemMeta { + + ItemMeta setValue(MetaValue value, T object); + + T getValue(MetaValue value); + + T as(Class clazz); + + Collection> getSetValues(); + + default String getDisplayName() { + return getValue(BuiltinMetaValues.DISPLAY_NAME); + } + + default ItemMeta setDisplayName(String displayName) { + return setValue(BuiltinMetaValues.DISPLAY_NAME, displayName); + } + + default List getLore() { + return getValue(BuiltinMetaValues.LORE); + } + + default ItemMeta setLore(List lore) { + return setValue(BuiltinMetaValues.LORE, lore); + } + + default ItemMeta setLore(String... lore) { + return setValue(BuiltinMetaValues.LORE, List.of(lore)); + } + + default Integer getCustomModelData() { + return getValue(BuiltinMetaValues.MODEL_DATA); + } + + default ItemMeta setCustomModelData(Integer customModelData) { + return setValue(BuiltinMetaValues.MODEL_DATA, customModelData); + } + + default boolean hasCustomModelData() { + return getCustomModelData() != null; + } + + default boolean hasFlag(ItemFlag flag) { + return getValue(BuiltinMetaValues.ITEM_FLAGS).contains(flag); + } + + default ItemMeta addFlag(ItemFlag flag) { + Set flags = getValue(BuiltinMetaValues.ITEM_FLAGS); + flags.add(flag); + return setValue(BuiltinMetaValues.ITEM_FLAGS, flags); + } + + default ItemMeta removeFlag(ItemFlag flag) { + Set flags = getFlags(); + flags.remove(flag); + return setValue(BuiltinMetaValues.ITEM_FLAGS, flags); + } + + default Set getFlags() { + return getValue(BuiltinMetaValues.ITEM_FLAGS); + } + +} diff --git a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/LeatherArmorMeta.java b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/LeatherArmorMeta.java new file mode 100644 index 0000000..fdd9786 --- /dev/null +++ b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/LeatherArmorMeta.java @@ -0,0 +1,16 @@ +package me.illusion.skyblockcore.server.item.stack.meta; + +import java.awt.Color; +import me.illusion.skyblockcore.server.item.stack.meta.value.BuiltinMetaValues; + +public interface LeatherArmorMeta extends ItemMeta { + + default Color getColor() { + return getValue(BuiltinMetaValues.LEATHER_COLOR); + } + + default ItemMeta setColor(Color color) { + return setValue(BuiltinMetaValues.LEATHER_COLOR, color); + } + +} diff --git a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/data/ItemFlag.java b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/data/ItemFlag.java new file mode 100644 index 0000000..94312f1 --- /dev/null +++ b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/data/ItemFlag.java @@ -0,0 +1,8 @@ +package me.illusion.skyblockcore.server.item.stack.meta.data; + +public enum ItemFlag { + + HIDE_ENCHANTS, + HIDE_ATTRIBUTES, + HIDE_UNBREAKABLE, +} diff --git a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/impl/ItemMetaFactory.java b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/impl/ItemMetaFactory.java new file mode 100644 index 0000000..46fb45d --- /dev/null +++ b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/impl/ItemMetaFactory.java @@ -0,0 +1,41 @@ +package me.illusion.skyblockcore.server.item.stack.meta.impl; + +import java.util.Map; +import me.illusion.skyblockcore.server.item.stack.meta.ItemMeta; +import me.illusion.skyblockcore.server.item.stack.meta.LeatherArmorMeta; +import me.illusion.skyblockcore.server.item.stack.meta.impl.data.ItemMetaDataContainer; +import me.illusion.skyblockcore.server.item.stack.meta.impl.data.ItemMetaViewProvider; + +public final class ItemMetaFactory { + + // Janky way, might redo this later + private static final Map, ItemMetaViewProvider> PROVIDERS = Map.of( + ItemMeta.class, ItemMetaView::new, + LeatherArmorMeta.class, LeatherArmorMetaView::new + ); + + private ItemMetaFactory() { + + } + + public static T create(Class metaClass) { + ItemMetaDataContainer container = ItemMetaDataContainer.empty(); + ItemMetaViewProvider provider = PROVIDERS.get(metaClass); + + if (provider == null) { + throw new IllegalArgumentException("No provider for " + metaClass.getName()); + } + + return (T) provider.apply(container); + } + + public static T create(Class metaClass, ItemMetaDataContainer container) { + ItemMetaViewProvider provider = PROVIDERS.get(metaClass); + + if (provider == null) { + throw new IllegalArgumentException("No provider for " + metaClass.getName()); + } + + return (T) provider.apply(container); + } +} diff --git a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/impl/ItemMetaView.java b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/impl/ItemMetaView.java new file mode 100644 index 0000000..12d81cb --- /dev/null +++ b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/impl/ItemMetaView.java @@ -0,0 +1,50 @@ +package me.illusion.skyblockcore.server.item.stack.meta.impl; + +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import me.illusion.skyblockcore.server.item.stack.meta.ItemMeta; +import me.illusion.skyblockcore.server.item.stack.meta.data.ItemFlag; +import me.illusion.skyblockcore.server.item.stack.meta.impl.data.ItemMetaDataContainer; +import me.illusion.skyblockcore.server.item.stack.meta.value.BuiltinMetaValues; +import me.illusion.skyblockcore.server.item.stack.meta.value.MetaValue; + +public class ItemMetaView implements ItemMeta { + + private final ItemMetaDataContainer container; + + public ItemMetaView(ItemMetaDataContainer container) { + this.container = container; + } + + @Override + public ItemMeta setValue(MetaValue value, T object) { + return new ItemMetaView(container.set(value, object)); + } + + @Override + public T getValue(MetaValue value) { + return container.get(value); + } + + @Override + public T as(Class clazz) { + return ItemMetaFactory.create(clazz, container); + } + + @Override + public Collection> getSetValues() { + return Set.copyOf(container.getValues().keySet()); + } + + @Override + public Set getFlags() { + return new HashSet<>(getValue(BuiltinMetaValues.ITEM_FLAGS)); + } + + @Override + public List getLore() { + return getValue(BuiltinMetaValues.LORE); + } +} diff --git a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/impl/LeatherArmorMetaView.java b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/impl/LeatherArmorMetaView.java new file mode 100644 index 0000000..8ed0a2d --- /dev/null +++ b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/impl/LeatherArmorMetaView.java @@ -0,0 +1,11 @@ +package me.illusion.skyblockcore.server.item.stack.meta.impl; + +import me.illusion.skyblockcore.server.item.stack.meta.LeatherArmorMeta; +import me.illusion.skyblockcore.server.item.stack.meta.impl.data.ItemMetaDataContainer; + +public class LeatherArmorMetaView extends ItemMetaView implements LeatherArmorMeta { + + public LeatherArmorMetaView(ItemMetaDataContainer container) { + super(container); + } +} diff --git a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/impl/data/ItemMetaDataContainer.java b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/impl/data/ItemMetaDataContainer.java new file mode 100644 index 0000000..5810e5f --- /dev/null +++ b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/impl/data/ItemMetaDataContainer.java @@ -0,0 +1,46 @@ +package me.illusion.skyblockcore.server.item.stack.meta.impl.data; + +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; +import me.illusion.skyblockcore.server.item.stack.meta.value.MetaValue; + +public class ItemMetaDataContainer { + + private final Map, Object> values; + + private ItemMetaDataContainer(Map, Object> values) { + this.values = Map.copyOf(values); + } + + public static ItemMetaDataContainer empty() { + return new ItemMetaDataContainer(Collections.emptyMap()); + } + + public static ItemMetaDataContainer of(Map, Object> values) { + return new ItemMetaDataContainer(values); + } + + public T get(MetaValue metaValue) { + return (T) values.getOrDefault(metaValue, metaValue.getDefaultValue()); + } + + public ItemMetaDataContainer set(MetaValue metaValue, T value) { + return modify(map -> map.put(metaValue, value)); + } + + public ItemMetaDataContainer remove(MetaValue metaValue) { + return modify(map -> map.remove(metaValue)); + } + + private ItemMetaDataContainer modify(Consumer, Object>> consumer) { + Map, Object> newValues = new ConcurrentHashMap<>(values); + consumer.accept(newValues); + return new ItemMetaDataContainer(newValues); + } + + public Map, Object> getValues() { + return values; + } +} diff --git a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/impl/data/ItemMetaViewProvider.java b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/impl/data/ItemMetaViewProvider.java new file mode 100644 index 0000000..8dcb7ac --- /dev/null +++ b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/impl/data/ItemMetaViewProvider.java @@ -0,0 +1,8 @@ +package me.illusion.skyblockcore.server.item.stack.meta.impl.data; + +import java.util.function.Function; +import me.illusion.skyblockcore.server.item.stack.meta.impl.ItemMetaView; + +public interface ItemMetaViewProvider extends Function { + +} diff --git a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/value/BuiltinMetaValues.java b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/value/BuiltinMetaValues.java new file mode 100644 index 0000000..aad4500 --- /dev/null +++ b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/value/BuiltinMetaValues.java @@ -0,0 +1,23 @@ +package me.illusion.skyblockcore.server.item.stack.meta.value; + +import java.awt.Color; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import me.illusion.skyblockcore.server.item.stack.meta.data.ItemFlag; + +public final class BuiltinMetaValues { + + public static final MetaValue DISPLAY_NAME = MetaValue.create(); + public static final MetaValue LOCALIZED_NAME = MetaValue.create(); + public static final MetaValue> LORE = MetaValue.create(ArrayList::new); + public static final MetaValue UNBREAKABLE = MetaValue.create(false); + public static final MetaValue> ITEM_FLAGS = MetaValue.create(HashSet::new); + public static final MetaValue MODEL_DATA = MetaValue.create(); + public static final MetaValue LEATHER_COLOR = MetaValue.create(); + + private BuiltinMetaValues() { + } + +} diff --git a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/value/MetaValue.java b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/value/MetaValue.java new file mode 100644 index 0000000..25d591f --- /dev/null +++ b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/value/MetaValue.java @@ -0,0 +1,21 @@ +package me.illusion.skyblockcore.server.item.stack.meta.value; + +import java.util.function.Supplier; + +public interface MetaValue { + + static MetaValue create(T defaultValue) { + return SimpleMetaValue.create(defaultValue); + } + + static MetaValue create(Supplier defaultValue) { + return SimpleMetaValue.create(defaultValue); + } + + static MetaValue create() { + return SimpleMetaValue.create(null); + } + + T getDefaultValue(); + +} diff --git a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/value/SimpleMetaValue.java b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/value/SimpleMetaValue.java new file mode 100644 index 0000000..053a641 --- /dev/null +++ b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/item/stack/meta/value/SimpleMetaValue.java @@ -0,0 +1,33 @@ +package me.illusion.skyblockcore.server.item.stack.meta.value; + +import java.util.function.Supplier; + +public class SimpleMetaValue implements MetaValue { + + private final Supplier defaultValue; + + public SimpleMetaValue(T defaultValue) { + this.defaultValue = () -> defaultValue; + } + + public SimpleMetaValue(Supplier defaultValue) { + if (defaultValue == null) { + defaultValue = () -> null; + } + + this.defaultValue = defaultValue; + } + + public static SimpleMetaValue create(T defaultValue) { + return new SimpleMetaValue<>(defaultValue); + } + + public static SimpleMetaValue create(Supplier defaultValue) { + return new SimpleMetaValue<>(defaultValue); + } + + @Override + public T getDefaultValue() { + return defaultValue.get(); + } +} diff --git a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/metric/impl/IslandCountMetricProvider.java b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/metric/impl/IslandCountMetricProvider.java new file mode 100644 index 0000000..5b2fb66 --- /dev/null +++ b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/metric/impl/IslandCountMetricProvider.java @@ -0,0 +1,30 @@ +package me.illusion.skyblockcore.server.metric.impl; + +import me.illusion.skyblockcore.common.metrics.SkyblockMetric; +import me.illusion.skyblockcore.common.metrics.provider.SkyblockMetricProvider; +import me.illusion.skyblockcore.common.scheduler.ThreadContext; +import me.illusion.skyblockcore.server.SkyblockServerPlatform; + +public class IslandCountMetricProvider implements SkyblockMetricProvider { + + private final SkyblockServerPlatform platform; + + public IslandCountMetricProvider(SkyblockServerPlatform platform) { + this.platform = platform; + } + + @Override + public String getName() { + return "island_count"; + } + + @Override + public ThreadContext getThreadContext() { + return ThreadContext.ASYNC; + } + + @Override + public void fillData(SkyblockMetric metric) { + metric.addData("amount", platform.getIslandManager().getLoadedIslandCount()); + } +} diff --git a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/metric/impl/PlayerCountMetricProvider.java b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/metric/impl/PlayerCountMetricProvider.java new file mode 100644 index 0000000..241d5ef --- /dev/null +++ b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/metric/impl/PlayerCountMetricProvider.java @@ -0,0 +1,30 @@ +package me.illusion.skyblockcore.server.metric.impl; + +import me.illusion.skyblockcore.common.metrics.SkyblockMetric; +import me.illusion.skyblockcore.common.metrics.provider.SkyblockMetricProvider; +import me.illusion.skyblockcore.common.scheduler.ThreadContext; +import me.illusion.skyblockcore.server.SkyblockServerPlatform; + +public class PlayerCountMetricProvider implements SkyblockMetricProvider { + + private final SkyblockServerPlatform platform; + + public PlayerCountMetricProvider(SkyblockServerPlatform platform) { + this.platform = platform; + } + + @Override + public String getName() { + return "player_count"; + } + + @Override + public ThreadContext getThreadContext() { + return ThreadContext.ASYNC; + } + + @Override + public void fillData(SkyblockMetric metric) { + metric.addData("amount", platform.getPlayerManager().getPlayers().size()); + } +} diff --git a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/network/complex/communication/CommunicationsHandler.java b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/network/complex/communication/CommunicationsHandler.java index a1c59fe..d9d80dd 100644 --- a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/network/complex/communication/CommunicationsHandler.java +++ b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/network/complex/communication/CommunicationsHandler.java @@ -4,7 +4,6 @@ import java.util.concurrent.CompletableFuture; import me.illusion.skyblockcore.common.communication.packet.PacketManager; import me.illusion.skyblockcore.common.storage.cache.SkyblockIslandCache; -import me.illusion.skyblockcore.common.storage.island.SkyblockIslandStorage; import me.illusion.skyblockcore.server.island.SkyblockIsland; import me.illusion.skyblockcore.server.network.complex.ComplexSkyblockNetwork; import me.illusion.skyblockcore.server.network.complex.communication.packet.request.PacketRequestIslandTeleport; @@ -19,13 +18,12 @@ public class CommunicationsHandler { // Potential problem: If an island is reque private final PacketManager packetManager; private final String serverId; private final SkyblockIslandCache cacheDatabase; - private final SkyblockIslandStorage database; private final ComplexSkyblockNetwork network; public CommunicationsHandler(ComplexSkyblockNetwork network) { this.network = network; - this.database = network.getDatabase(); + this.cacheDatabase = network.getCacheDatabase(); this.serverId = network.getConfiguration().getServerId(); diff --git a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/player/AbstractSkyblockPlayerManager.java b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/player/AbstractSkyblockPlayerManager.java index e3cbdb8..e4f3b89 100644 --- a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/player/AbstractSkyblockPlayerManager.java +++ b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/player/AbstractSkyblockPlayerManager.java @@ -1,5 +1,7 @@ package me.illusion.skyblockcore.server.player; +import java.util.Collection; +import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -33,7 +35,6 @@ protected AbstractSkyblockPlayerManager(SkyblockPlatform platform) { // Player management stuff protected void handleJoin(UUID playerId) { - System.out.println("Handling join for " + playerId); cacheProfileId(playerId).thenAccept(profileId -> { SkyblockPlayer player = createPlayer(playerId); playerIdMap.put(profileId, player); @@ -82,8 +83,6 @@ public SkyblockPlayer getPlayerFromProfile(UUID profileId) { private CompletableFuture cacheProfileId(UUID playerId) { return fetchProfileId(playerId).thenCompose(profileId -> { - System.out.println("Profile ID for " + playerId + " is " + profileId); - if (profileId == null) { profileId = createProfileId(playerId); setIdInternally(playerId, profileId); @@ -118,6 +117,11 @@ public CompletableFuture saveProfileId(UUID playerId, UUID profileId) { return database.setProfileId(playerId, profileId).thenRun(() -> setIdInternally(playerId, profileId)); } + @Override + public Collection getPlayers() { + return List.copyOf(playerIdMap.values()); + } + private UUID createProfileId(UUID playerId) { return profileMappingFunction.apply(playerId); } diff --git a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/player/SkyblockPlayerManager.java b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/player/SkyblockPlayerManager.java index dead82c..1381590 100644 --- a/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/player/SkyblockPlayerManager.java +++ b/SkyblockCore-Server/src/main/java/me/illusion/skyblockcore/server/player/SkyblockPlayerManager.java @@ -1,5 +1,6 @@ package me.illusion.skyblockcore.server.player; +import java.util.Collection; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -50,4 +51,11 @@ public interface SkyblockPlayerManager { */ UUID getCachedProfileId(UUID playerId); + /** + * Gets a snapshot of all the loaded players. + * + * @return A collection of all the loaded players. + */ + Collection getPlayers(); + } diff --git a/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/SkyblockSpigotPlugin.java b/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/SkyblockSpigotPlugin.java index 061d003..1723bcb 100644 --- a/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/SkyblockSpigotPlugin.java +++ b/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/SkyblockSpigotPlugin.java @@ -2,7 +2,6 @@ import java.io.File; import java.util.logging.Level; - import lombok.Getter; import me.illusion.cosmos.CosmosPlugin; import me.illusion.skyblockcore.common.command.audience.SkyblockAudience; @@ -14,6 +13,9 @@ import me.illusion.skyblockcore.common.event.manager.SkyblockEventManager; import me.illusion.skyblockcore.common.event.manager.SkyblockEventManagerImpl; import me.illusion.skyblockcore.common.platform.SkyblockPlatform; +import me.illusion.skyblockcore.common.platform.SkyblockPlatformProvider; +import me.illusion.skyblockcore.common.registry.Registries; +import me.illusion.skyblockcore.common.scheduler.SkyblockScheduler; import me.illusion.skyblockcore.common.utilities.file.IOUtils; import me.illusion.skyblockcore.server.SkyblockServerPlatform; import me.illusion.skyblockcore.server.island.SkyblockIslandManager; @@ -30,6 +32,8 @@ import me.illusion.skyblockcore.spigot.grid.SkyblockGridRegistry; import me.illusion.skyblockcore.spigot.island.IslandManagerImpl; import me.illusion.skyblockcore.spigot.player.SkyblockBukkitPlayerManager; +import me.illusion.skyblockcore.spigot.registries.BukkitMaterialRegistry; +import me.illusion.skyblockcore.spigot.scheduler.SkyblockBukkitScheduler; import org.bukkit.Bukkit; import org.bukkit.plugin.ServicePriority; import org.bukkit.plugin.java.JavaPlugin; @@ -50,16 +54,19 @@ public class SkyblockSpigotPlugin extends JavaPlugin implements SkyblockServerPl private ConfigurationProvider configurationProvider; + private Registries registries; private SkyblockDatabaseRegistry databaseRegistry; private SkyblockIslandManager islandManager; private SkyblockNetworkRegistry networkRegistry; private SkyblockEventManager eventManager; private SkyblockPlayerManager playerManager; + private SkyblockScheduler scheduler; private SkyblockCommandManager commandManager; @Override public void onLoad() { Bukkit.getServicesManager().register(SkyblockPlatform.class, this, this, ServicePriority.Normal); + SkyblockPlatformProvider.setPlatform(this); } @Override @@ -67,6 +74,12 @@ public void onEnable() { log("Loading configuration provider"); configurationProvider = new BukkitConfigurationProvider(this); + log("Loading scheduler"); + scheduler = new SkyblockBukkitScheduler(this); + + log("Loading minecraft registries.."); + loadRegistries(); + log("Loading network registry"); networkRegistry = new SkyblockNetworkRegistryImpl(this); @@ -173,6 +186,16 @@ private void initCosmos() { cosmosPlugin.getSessionHolderRegistry().registerHolder("skyblock", cosmosSetup.getSessionHolder()); } + private void loadRegistries() { + registries = new Registries(); + + registries.registerRegistry(new BukkitMaterialRegistry()); + } + + public BukkitMaterialRegistry getMaterialRegistry() { + return registries.getSpecificRegistry(BukkitMaterialRegistry.class); + } + @Override public void disableExceptionally() { Bukkit.getPluginManager().disablePlugin(this); diff --git a/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/command/SkyblockBukkitCommandManager.java b/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/command/SkyblockBukkitCommandManager.java index df5e8da..2c1fef5 100644 --- a/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/command/SkyblockBukkitCommandManager.java +++ b/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/command/SkyblockBukkitCommandManager.java @@ -43,7 +43,7 @@ public class SkyblockBukkitCommandManager extends AbstractSkyblockCommandManager Class pluginCommandClass = PluginCommand.class; PLUGIN_COMMAND_CONSTRUCTOR = pluginCommandClass.getDeclaredConstructor(String.class, Plugin.class); - PLUGIN_COMMAND_CONSTRUCTOR.setAccessible(true); + PLUGIN_COMMAND_CONSTRUCTOR.setAccessible(true); // Need to use the constructor as the class has a protected constructor and is final SYNC_COMMANDS_METHOD = serverClass.getDeclaredMethod("syncCommands"); SYNC_COMMANDS_METHOD.setAccessible(true); diff --git a/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/island/IslandManagerImpl.java b/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/island/IslandManagerImpl.java index e522c9e..c79ddb4 100644 --- a/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/island/IslandManagerImpl.java +++ b/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/island/IslandManagerImpl.java @@ -82,8 +82,6 @@ public CompletableFuture createIsland(String template, UUID prof }); } - System.out.println("Creating island for " + profileId); - UUID islandId = UUID.randomUUID(); IslandData data = new IslandData(islandId, profileId); diff --git a/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/registries/BukkitMaterialRegistry.java b/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/registries/BukkitMaterialRegistry.java new file mode 100644 index 0000000..72c8206 --- /dev/null +++ b/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/registries/BukkitMaterialRegistry.java @@ -0,0 +1,61 @@ +package me.illusion.skyblockcore.spigot.registries; + +import me.illusion.skyblockcore.common.registry.SimpleRegistry; +import me.illusion.skyblockcore.server.item.MinecraftItem; +import me.illusion.skyblockcore.server.item.MinecraftMaterial; +import me.illusion.skyblockcore.server.item.stack.meta.ItemMeta; +import me.illusion.skyblockcore.spigot.registries.meta.BukkitMetaAdapter; +import me.illusion.skyblockcore.spigot.utilities.adapter.SkyblockBukkitAdapter; +import org.bukkit.Bukkit; +import org.bukkit.Material; + +public class BukkitMaterialRegistry extends SimpleRegistry { + + public BukkitMaterialRegistry() { + super(MinecraftItem.class); + + for (Material material : Material.values()) { + register(new MaterialItem(material)); + } + } + + public MinecraftItem getItem(Material material) { + return get(SkyblockBukkitAdapter.adapt(material.getKey())); + } + + private static class MaterialItem extends MinecraftMaterial implements MinecraftItem { + + private final Material material; + + protected MaterialItem(Material material) { + super(SkyblockBukkitAdapter.adapt(material.getKey())); + this.material = material; + } + + @Override + public MinecraftItem attemptCreateItem() { + return material.isItem() ? this : null; + } + + @Override + public MinecraftMaterial getMaterial() { + return this; + } + + @Override + public int getMaxStackSize() { + return material.getMaxStackSize(); + } + + @Override + public ItemMeta createItemMeta() { + org.bukkit.inventory.meta.ItemMeta bukkitMeta = Bukkit.getItemFactory().getItemMeta(material); + + if (bukkitMeta == null) { + return null; + } + + return BukkitMetaAdapter.adapt(bukkitMeta); + } + } +} diff --git a/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/registries/meta/BukkitMetaAdapter.java b/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/registries/meta/BukkitMetaAdapter.java new file mode 100644 index 0000000..54db232 --- /dev/null +++ b/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/registries/meta/BukkitMetaAdapter.java @@ -0,0 +1,41 @@ +package me.illusion.skyblockcore.spigot.registries.meta; + +import java.util.List; +import me.illusion.skyblockcore.server.item.stack.meta.ItemMeta; +import me.illusion.skyblockcore.server.item.stack.meta.impl.ItemMetaFactory; +import me.illusion.skyblockcore.spigot.registries.meta.converter.DefaultItemMetaAdapter; +import me.illusion.skyblockcore.spigot.registries.meta.converter.LeatherItemMetaAdapter; +import me.illusion.skyblockcore.spigot.registries.meta.converter.MetaAdapter; + +public final class BukkitMetaAdapter { + + private static final List> META_ADAPTERS = List.of( + new DefaultItemMetaAdapter(), + new LeatherItemMetaAdapter() + ); + + private BukkitMetaAdapter() { + + } + + public static ItemMeta adapt(org.bukkit.inventory.meta.ItemMeta bukkitMeta) { + ItemMeta platformMeta = ItemMetaFactory.create(ItemMeta.class); + + for (MetaAdapter adapter : META_ADAPTERS) { + MetaAdapter metaAdapter = (MetaAdapter) adapter; + + Class bukkitMetaClass = metaAdapter.getBukkitMetaClass(); + Class

platformMetaClass = metaAdapter.getPlatformMetaClass(); + + if (!bukkitMetaClass.isAssignableFrom(bukkitMeta.getClass())) { + continue; + } + + P platformMetaInstance = platformMeta.as(platformMetaClass); + metaAdapter.convertToPlatform(bukkitMetaClass.cast(bukkitMeta), platformMetaInstance); + } + + return platformMeta; + } + +} diff --git a/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/registries/meta/converter/DefaultItemMetaAdapter.java b/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/registries/meta/converter/DefaultItemMetaAdapter.java new file mode 100644 index 0000000..22f7b3c --- /dev/null +++ b/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/registries/meta/converter/DefaultItemMetaAdapter.java @@ -0,0 +1,57 @@ +package me.illusion.skyblockcore.spigot.registries.meta.converter; + +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.meta.ItemMeta; + +public class DefaultItemMetaAdapter implements MetaAdapter { + + @Override + public Class getBukkitMetaClass() { + return ItemMeta.class; + } + + @Override + public Class getPlatformMetaClass() { + return me.illusion.skyblockcore.server.item.stack.meta.ItemMeta.class; + } + + @Override + public void convertToPlatform(ItemMeta bukkitMeta, me.illusion.skyblockcore.server.item.stack.meta.ItemMeta platformMeta) { + platformMeta.setLore(bukkitMeta.getLore()); + platformMeta.setDisplayName(bukkitMeta.getDisplayName()); + platformMeta.setCustomModelData(bukkitMeta.getCustomModelData()); + + for (ItemFlag bukkitFlag : bukkitMeta.getItemFlags()) { + platformMeta.addFlag(adaptFlag(bukkitFlag)); + } + } + + @Override + public void convertToBukkit(me.illusion.skyblockcore.server.item.stack.meta.ItemMeta platformMeta, ItemMeta bukkitMeta) { + bukkitMeta.setLore(platformMeta.getLore()); + bukkitMeta.setDisplayName(platformMeta.getDisplayName()); + bukkitMeta.setCustomModelData(platformMeta.getCustomModelData()); + + for (me.illusion.skyblockcore.server.item.stack.meta.data.ItemFlag platformFlag : platformMeta.getFlags()) { + bukkitMeta.addItemFlags(adaptFlag(platformFlag)); + } + } + + private me.illusion.skyblockcore.server.item.stack.meta.data.ItemFlag adaptFlag(ItemFlag bukkitFlag) { + return switch (bukkitFlag) { + case HIDE_ENCHANTS -> me.illusion.skyblockcore.server.item.stack.meta.data.ItemFlag.HIDE_ENCHANTS; + case HIDE_ATTRIBUTES -> me.illusion.skyblockcore.server.item.stack.meta.data.ItemFlag.HIDE_ATTRIBUTES; + case HIDE_UNBREAKABLE -> me.illusion.skyblockcore.server.item.stack.meta.data.ItemFlag.HIDE_UNBREAKABLE; + default -> throw new IllegalArgumentException("No adapter found for " + bukkitFlag.name()); + }; + } + + private ItemFlag adaptFlag(me.illusion.skyblockcore.server.item.stack.meta.data.ItemFlag platformFlag) { + return switch (platformFlag) { + case HIDE_ENCHANTS -> ItemFlag.HIDE_ENCHANTS; + case HIDE_ATTRIBUTES -> ItemFlag.HIDE_ATTRIBUTES; + case HIDE_UNBREAKABLE -> ItemFlag.HIDE_UNBREAKABLE; + default -> throw new IllegalArgumentException("No adapter found for " + platformFlag.name()); + }; + } +} diff --git a/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/registries/meta/converter/LeatherItemMetaAdapter.java b/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/registries/meta/converter/LeatherItemMetaAdapter.java new file mode 100644 index 0000000..68106aa --- /dev/null +++ b/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/registries/meta/converter/LeatherItemMetaAdapter.java @@ -0,0 +1,33 @@ +package me.illusion.skyblockcore.spigot.registries.meta.converter; + +import org.bukkit.Color; +import org.bukkit.inventory.meta.LeatherArmorMeta; + +public class LeatherItemMetaAdapter implements MetaAdapter { + + @Override + public Class getBukkitMetaClass() { + return LeatherArmorMeta.class; + } + + @Override + public Class getPlatformMetaClass() { + return me.illusion.skyblockcore.server.item.stack.meta.LeatherArmorMeta.class; + } + + @Override + public void convertToPlatform(LeatherArmorMeta bukkitMeta, me.illusion.skyblockcore.server.item.stack.meta.LeatherArmorMeta platformMeta) { + Color bukkitColor = bukkitMeta.getColor(); + java.awt.Color platformColor = new java.awt.Color(bukkitColor.getRed(), bukkitColor.getGreen(), bukkitColor.getBlue()); + + platformMeta.setColor(platformColor); + } + + @Override + public void convertToBukkit(me.illusion.skyblockcore.server.item.stack.meta.LeatherArmorMeta platformMeta, LeatherArmorMeta bukkitMeta) { + java.awt.Color platformColor = platformMeta.getColor(); + Color bukkitColor = Color.fromRGB(platformColor.getRed(), platformColor.getGreen(), platformColor.getBlue()); + + bukkitMeta.setColor(bukkitColor); + } +} diff --git a/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/registries/meta/converter/MetaAdapter.java b/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/registries/meta/converter/MetaAdapter.java new file mode 100644 index 0000000..f529fdc --- /dev/null +++ b/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/registries/meta/converter/MetaAdapter.java @@ -0,0 +1,13 @@ +package me.illusion.skyblockcore.spigot.registries.meta.converter; + +public interface MetaAdapter { + + Class getBukkitMetaClass(); + + Class

getPlatformMetaClass(); + + void convertToPlatform(B bukkitMeta, P platformMeta); + + void convertToBukkit(P platformMeta, B bukkitMeta); + +} diff --git a/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/scheduler/SkyblockBukkitScheduler.java b/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/scheduler/SkyblockBukkitScheduler.java new file mode 100644 index 0000000..f8444b6 --- /dev/null +++ b/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/scheduler/SkyblockBukkitScheduler.java @@ -0,0 +1,93 @@ +package me.illusion.skyblockcore.spigot.scheduler; + +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; +import me.illusion.skyblockcore.common.scheduler.ScheduledTask; +import me.illusion.skyblockcore.common.scheduler.ScheduledTaskImpl; +import me.illusion.skyblockcore.common.scheduler.SkyblockScheduler; +import me.illusion.skyblockcore.common.scheduler.ThreadContext; +import me.illusion.skyblockcore.common.utilities.time.Time; +import org.bukkit.Bukkit; +import org.bukkit.plugin.java.JavaPlugin; + +public class SkyblockBukkitScheduler implements SkyblockScheduler { + + private final Map taskIds = new ConcurrentHashMap<>(); + private final Map tasks = new ConcurrentHashMap<>(); + + private final JavaPlugin plugin; + + public SkyblockBukkitScheduler(JavaPlugin plugin) { + this.plugin = plugin; + } + + @Override + public boolean isCancelled(UUID taskId) { + int bukkitTaskId = taskIds.getOrDefault(taskId, -1); + + if (bukkitTaskId == -1) { + return true; + } + + return Bukkit.getScheduler().isQueued(bukkitTaskId) || Bukkit.getScheduler().isCurrentlyRunning(bukkitTaskId); + } + + @Override + public void cancel(UUID taskId) { + int bukkitTaskId = taskIds.remove(taskId); + + if (bukkitTaskId == -1) { + return; + } + + Bukkit.getScheduler().cancelTask(bukkitTaskId); + tasks.remove(taskId); + } + + @Override + public UUID scheduleOnce(ThreadContext context, Consumer task, Time delay) { + UUID taskId = UUID.randomUUID(); + ScheduledTask scheduledTask = new ScheduledTaskImpl(taskId, this); + + Runnable runnable = () -> { + task.accept(scheduledTask); + tasks.remove(taskId); + taskIds.remove(taskId); + }; + + int bukkitId; + + if (context == ThreadContext.ASYNC) { + bukkitId = Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, runnable, delay.asTicks()).getTaskId(); + } else { + bukkitId = Bukkit.getScheduler().runTaskLater(plugin, runnable, delay.asTicks()).getTaskId(); + } + + taskIds.put(taskId, bukkitId); + tasks.put(taskId, scheduledTask); + + return taskId; + } + + @Override + public UUID scheduleRepeating(ThreadContext context, Consumer task, Time delay, Time period) { + UUID taskId = UUID.randomUUID(); + ScheduledTask scheduledTask = new ScheduledTaskImpl(taskId, this); + + int bukkitId; + + if (context == ThreadContext.ASYNC) { + bukkitId = Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, () -> task.accept(scheduledTask), delay.asTicks(), period.asTicks()) + .getTaskId(); + } else { + bukkitId = Bukkit.getScheduler().runTaskTimer(plugin, () -> task.accept(scheduledTask), delay.asTicks(), period.asTicks()).getTaskId(); + } + + taskIds.put(taskId, bukkitId); + tasks.put(taskId, scheduledTask); + + return taskId; + } +} diff --git a/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/utilities/adapter/SkyblockBukkitAdapter.java b/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/utilities/adapter/SkyblockBukkitAdapter.java index ee52572..500f606 100644 --- a/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/utilities/adapter/SkyblockBukkitAdapter.java +++ b/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/utilities/adapter/SkyblockBukkitAdapter.java @@ -3,10 +3,12 @@ import java.util.concurrent.TimeUnit; import me.illusion.cosmos.utilities.geometry.Cuboid; import me.illusion.cosmos.utilities.time.Time; +import me.illusion.skyblockcore.common.registry.SkyblockNamespacedKey; import me.illusion.skyblockcore.server.util.SkyblockCuboid; import me.illusion.skyblockcore.server.util.SkyblockLocation; import org.bukkit.Bukkit; import org.bukkit.Location; +import org.bukkit.NamespacedKey; import org.bukkit.util.Vector; /** @@ -87,4 +89,11 @@ public static Cuboid toCosmosCuboid(SkyblockCuboid cuboid) { return new Cuboid(toBukkitLocation(cuboid.getMin()), toBukkitLocation(cuboid.getMax())); } + public static SkyblockNamespacedKey adapt(NamespacedKey key) { + return new SkyblockNamespacedKey(key.getNamespace(), key.getKey()); + } + + public static NamespacedKey adapt(SkyblockNamespacedKey key) { + return new NamespacedKey(key.getNamespace(), key.getKey()); + } } diff --git a/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/utilities/config/BukkitConfigurationAdapter.java b/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/utilities/config/BukkitConfigurationAdapter.java index 042ebdb..2c3a555 100644 --- a/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/utilities/config/BukkitConfigurationAdapter.java +++ b/SkyblockCore-Spigot/src/main/java/me/illusion/skyblockcore/spigot/utilities/config/BukkitConfigurationAdapter.java @@ -57,7 +57,3 @@ public static void writeTo(me.illusion.skyblockcore.common.config.section.Config } } - -/* -{mongo=ReadOnlyConfigurationSection{internalMap={host=localhost, port=27017, database=island, username=root, password=12345}, name='mongo'}, island-cache=ReadOnlyConfigurationSection{internalMap={type=memory}, name='island-cache'}, sqlite=ReadOnlyConfigurationSection{internalMap={name=island-storage/database}, name='sqlite'}, island=ReadOnlyConfigurationSection{internalMap={type=sqlite}, name='island'}, profile=ReadOnlyConfigurationSection{internalMap={type=sqlite}, name='profile'}, remote-sql=ReadOnlyConfigurationSection{internalMap={host=localhost, port=3306, database=island, username=root, password=12345}, name='remote-sql'}, redis=ReadOnlyConfigurationSection{internalMap={host=localhost, port=6379, password=12345}, name='redis'}} - */ \ No newline at end of file