diff --git a/Datura/src/main/java/me/totalfreedom/datura/Datura.java b/Datura/src/main/java/me/totalfreedom/datura/Datura.java index 918935a..e41c339 100644 --- a/Datura/src/main/java/me/totalfreedom/datura/Datura.java +++ b/Datura/src/main/java/me/totalfreedom/datura/Datura.java @@ -27,11 +27,11 @@ public class Datura extends JavaPlugin CommonsBase.getInstance() .getRegistrations() .getServiceRegistry() - .register(this, locker); + .registerService(this, locker); CommonsBase.getInstance() .getRegistrations() .getServiceRegistry() - .register(this, cager); + .registerService(this, cager); Bukkit.getPluginManager() .registerEvents(halter, this); diff --git a/Fossil/src/main/java/me/totalfreedom/fossil/Fossil.java b/Fossil/src/main/java/me/totalfreedom/fossil/Fossil.java index 3309ef4..a638249 100644 --- a/Fossil/src/main/java/me/totalfreedom/fossil/Fossil.java +++ b/Fossil/src/main/java/me/totalfreedom/fossil/Fossil.java @@ -1,16 +1,25 @@ package me.totalfreedom.fossil; import me.totalfreedom.base.CommonsBase; +import me.totalfreedom.base.Registration; +import me.totalfreedom.fossil.trail.Trailer; +import me.totalfreedom.service.SubscriptionProvider; import org.bukkit.plugin.java.JavaPlugin; public class Fossil extends JavaPlugin { + private final Trailer trailer = new Trailer(); + private final Registration registration = CommonsBase.getInstance() + .getRegistrations(); + @Override public void onEnable() { - CommonsBase.getInstance() - .getRegistrations() - .getModuleRegistry() - .addModule(this); + registration.getModuleRegistry() + .addModule(this); + + registration.getServiceRegistry() + .registerService( + SubscriptionProvider.syncService(this, trailer)); } } diff --git a/Fossil/src/main/java/me/totalfreedom/fossil/items/TrailItem.java b/Fossil/src/main/java/me/totalfreedom/fossil/items/TrailItem.java index a9e6a7d..ea95de6 100644 --- a/Fossil/src/main/java/me/totalfreedom/fossil/items/TrailItem.java +++ b/Fossil/src/main/java/me/totalfreedom/fossil/items/TrailItem.java @@ -8,9 +8,9 @@ import org.jetbrains.annotations.Nullable; public final class TrailItem extends ShopItem { - public TrailItem(final Material material) + public TrailItem() { - super(material); + super(Material.LINGERING_POTION); } @Override diff --git a/Fossil/src/main/java/me/totalfreedom/fossil/trail/Trailer.java b/Fossil/src/main/java/me/totalfreedom/fossil/trail/Trailer.java index ae51c0b..b530595 100644 --- a/Fossil/src/main/java/me/totalfreedom/fossil/trail/Trailer.java +++ b/Fossil/src/main/java/me/totalfreedom/fossil/trail/Trailer.java @@ -1,41 +1,37 @@ package me.totalfreedom.fossil.trail; import me.totalfreedom.particle.Trail; -import me.totalfreedom.particle.TrailType; import me.totalfreedom.service.Service; -import org.bukkit.entity.Player; import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; import java.util.List; -import java.util.Map; -import java.util.UUID; public class Trailer extends Service { - private final List trailList = new ArrayList<>(); + private final List activeTrails = new ArrayList<>(); - public Trailer() { + // Cannot be async due to interaction with the world, and API interactions MUST be synchronized. + public Trailer() + { super("trailer_service"); } - public void addTrail(final Trail trail) { - this.trailList.add(trail); + public void addTrail(final Trail trail) + { + this.activeTrails.add(trail); } - public void removeTrail(final Trail trail) { - this.trailList.remove(trail); + public void removeTrail(final Trail trail) + { + this.activeTrails.remove(trail); } @Override public void tick() { - for (final Trail trail : trailList) { - if (trail.getAssociatedPlayer().isOnline()) { - final Player player = (Player) trail.getAssociatedPlayer(); - - } + for (final Trail trail : activeTrails) + { + trail.spawnParticle(); } } } diff --git a/Fossil/src/main/java/me/totalfreedom/fossil/trail/types/FlameTrail.java b/Fossil/src/main/java/me/totalfreedom/fossil/trail/types/FlameTrail.java new file mode 100644 index 0000000..fad995d --- /dev/null +++ b/Fossil/src/main/java/me/totalfreedom/fossil/trail/types/FlameTrail.java @@ -0,0 +1,29 @@ +package me.totalfreedom.fossil.trail.types; + +import me.totalfreedom.particle.TrailType; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; + +public final class FlameTrail extends SimpleTrail +{ + public FlameTrail(final Player player) + { + super(player, TrailType.FLAME); + } + + @Override + public void spawnParticle() + { + if (!getAssociatedPlayer().isOnline() || !isActive()) return; + + final Player player = (Player) getAssociatedPlayer(); + final Location location = player.getLocation() + .clone() + .subtract(0, 1, 0); + final Vector direction = location.getDirection(); + location.getWorld() + .spawnParticle(getTrailType().getType(), location, 0, direction.getX(), direction.getY(), + direction.getZ(), 0.1); + } +} diff --git a/Fossil/src/main/java/me/totalfreedom/fossil/trail/types/HeartTrail.java b/Fossil/src/main/java/me/totalfreedom/fossil/trail/types/HeartTrail.java new file mode 100644 index 0000000..b8a83cc --- /dev/null +++ b/Fossil/src/main/java/me/totalfreedom/fossil/trail/types/HeartTrail.java @@ -0,0 +1,25 @@ +package me.totalfreedom.fossil.trail.types; + +import me.totalfreedom.particle.TrailType; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +public final class HeartTrail extends SimpleTrail +{ + public HeartTrail(final Player player) + { + super(player, TrailType.HEART); + } + + @Override + public void spawnParticle() + { + if (!getAssociatedPlayer().isOnline() || !isActive()) return; + + final Player player = (Player) getAssociatedPlayer(); + final Location location = player.getLocation() + .clone() + .subtract(0, 1, 0); + location.getWorld().spawnParticle(getTrailType().getType(), location, 1, 0.0, 0.5, 0.0); + } +} diff --git a/Fossil/src/main/java/me/totalfreedom/fossil/trail/types/RainbowTrail.java b/Fossil/src/main/java/me/totalfreedom/fossil/trail/types/RainbowTrail.java index 36b9108..b020349 100644 --- a/Fossil/src/main/java/me/totalfreedom/fossil/trail/types/RainbowTrail.java +++ b/Fossil/src/main/java/me/totalfreedom/fossil/trail/types/RainbowTrail.java @@ -35,7 +35,7 @@ public final class RainbowTrail extends SimpleTrail final Color color = currentColor.next(); final Player player = (Player) getAssociatedPlayer(); final Particle particle = getTrailType().getType(); - final Particle.DustOptions options = new Particle.DustOptions(color, 3); + final Particle.DustOptions options = new Particle.DustOptions(color, 3F); final Location location = player.getLocation() .clone() .subtract(0, 1, 0); diff --git a/Fossil/src/main/java/me/totalfreedom/fossil/trail/types/StrobeTrail.java b/Fossil/src/main/java/me/totalfreedom/fossil/trail/types/StrobeTrail.java new file mode 100644 index 0000000..54b167d --- /dev/null +++ b/Fossil/src/main/java/me/totalfreedom/fossil/trail/types/StrobeTrail.java @@ -0,0 +1,30 @@ +package me.totalfreedom.fossil.trail.types; + +import me.totalfreedom.particle.TrailType; +import org.bukkit.Color; +import org.bukkit.Location; +import org.bukkit.Particle; +import org.bukkit.entity.Player; + +public final class StrobeTrail extends SimpleTrail +{ + private final Particle.DustTransition dustTransition; + + public StrobeTrail(final Player player, final Color from, final Color to) + { + super(player, TrailType.STROBE); + this.dustTransition = new Particle.DustTransition(from, to, 3F); + } + + @Override + public void spawnParticle() + { + if (!getAssociatedPlayer().isOnline() || !isActive()) return; + + final Player player = (Player) getAssociatedPlayer(); + final Location location = player.getLocation() + .clone() + .subtract(0, 1, 0); + location.getWorld().spawnParticle(getTrailType().getType(), location, 1, 0.0, 0.5, 0.0, dustTransition); + } +} diff --git a/Fossil/src/main/java/me/totalfreedom/fossil/trail/types/TrailProvider.java b/Fossil/src/main/java/me/totalfreedom/fossil/trail/types/TrailProvider.java index 427bb09..2e7d8d5 100644 --- a/Fossil/src/main/java/me/totalfreedom/fossil/trail/types/TrailProvider.java +++ b/Fossil/src/main/java/me/totalfreedom/fossil/trail/types/TrailProvider.java @@ -8,5 +8,4 @@ public final class TrailProvider return new BasicTrail(player); } - } diff --git a/Patchwork/src/main/java/me/totalfreedom/base/CommonsBase.java b/Patchwork/src/main/java/me/totalfreedom/base/CommonsBase.java index 2d1cb5a..1bc35bf 100644 --- a/Patchwork/src/main/java/me/totalfreedom/base/CommonsBase.java +++ b/Patchwork/src/main/java/me/totalfreedom/base/CommonsBase.java @@ -2,6 +2,8 @@ package me.totalfreedom.base; import me.totalfreedom.event.EventBus; import me.totalfreedom.service.FreedomExecutor; +import me.totalfreedom.service.SubscriptionProvider; +import org.bukkit.Bukkit; import org.bukkit.plugin.java.JavaPlugin; public class CommonsBase extends JavaPlugin @@ -18,21 +20,23 @@ public class CommonsBase extends JavaPlugin @Override public void onDisable() { + Bukkit.getScheduler().runTaskLater(this, () -> getRegistrations() + .getServiceRegistry() + .stopAllServices(), 1L); + getRegistrations().getServiceRegistry() - .stopAll(); - getRegistrations().getServiceRegistry() - .unregister(EventBus.class, eventBus); + .unregisterService(EventBus.class); } @Override public void onEnable() { getRegistrations().getServiceRegistry() - .register(this, eventBus); + .registerService(SubscriptionProvider.asyncService(this, eventBus)); getExecutor().getSync() .execute(() -> getRegistrations() .getServiceRegistry() - .startAll()); + .startAllServices()); } public FreedomExecutor getExecutor() diff --git a/Patchwork/src/main/java/me/totalfreedom/base/Registration.java b/Patchwork/src/main/java/me/totalfreedom/base/Registration.java index 7d8b8cb..e23609a 100644 --- a/Patchwork/src/main/java/me/totalfreedom/base/Registration.java +++ b/Patchwork/src/main/java/me/totalfreedom/base/Registration.java @@ -4,14 +4,14 @@ import me.totalfreedom.data.ConfigRegistry; import me.totalfreedom.data.EventRegistry; import me.totalfreedom.data.GroupRegistry; import me.totalfreedom.data.ModuleRegistry; -import me.totalfreedom.data.ServiceRegistry; +import me.totalfreedom.data.ServiceTaskRegistry; import me.totalfreedom.data.UserRegistry; public class Registration { private final EventRegistry eventRegistry; private final UserRegistry userRegistry; - private final ServiceRegistry serviceRegistry; + private final ServiceTaskRegistry serviceTaskRegistry; private final ModuleRegistry moduleRegistry; private final GroupRegistry groupRegistry; private final ConfigRegistry configRegistry; @@ -20,7 +20,7 @@ public class Registration { this.eventRegistry = new EventRegistry(); this.userRegistry = new UserRegistry(); - this.serviceRegistry = new ServiceRegistry(); + this.serviceTaskRegistry = new ServiceTaskRegistry(); this.moduleRegistry = new ModuleRegistry(); this.groupRegistry = new GroupRegistry(); this.configRegistry = new ConfigRegistry(); @@ -41,9 +41,9 @@ public class Registration return userRegistry; } - public ServiceRegistry getServiceRegistry() + public ServiceTaskRegistry getServiceRegistry() { - return serviceRegistry; + return serviceTaskRegistry; } public GroupRegistry getGroupRegistry() diff --git a/Patchwork/src/main/java/me/totalfreedom/data/ServiceRegistry.java b/Patchwork/src/main/java/me/totalfreedom/data/ServiceRegistry.java deleted file mode 100644 index 589db1d..0000000 --- a/Patchwork/src/main/java/me/totalfreedom/data/ServiceRegistry.java +++ /dev/null @@ -1,75 +0,0 @@ -package me.totalfreedom.data; - -import me.totalfreedom.service.Service; -import org.bukkit.Bukkit; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.RegisteredServiceProvider; -import org.bukkit.plugin.ServicePriority; - -import java.util.ArrayList; -import java.util.List; - -public class ServiceRegistry -{ - private final List services; - - public ServiceRegistry() - { - this.services = new ArrayList<>(); - } - - public void startAll() - { - for (final Service service : this.services) - { - service.start(); - } - } - - public void stopAll() - { - for (final Service service : this.services) - { - service.stop(); - } - } - - @SuppressWarnings("unchecked") - // Suppressing is fine here; we know that the service is of type T extends Service, - // and calling getClass() on this object would effectively be Class, though we may lose - // the identity of the code signature in the process. - // In this case, that is fine. - public void register(final Plugin plugin, final T service) - { - this.services.add(service); - if (!service.getClass() - .isInstance(service)) - { - throw new UnknownError(""" - A critical issue has been encountered: - The service %s is not an instance of itself. - This is a critical issue and should be reported immediately. - """.formatted(service.getClass() - .getName())); - } - Bukkit.getServicesManager() - .register( - (Class) service.getClass(), - service, - plugin, - ServicePriority.Normal); - } - - public RegisteredServiceProvider getService(final Class clazz) - { - return Bukkit.getServicesManager() - .getRegistration(clazz); - } - - public void unregister(final Class clazz, final Service service) - { - this.services.remove(service); - Bukkit.getServicesManager() - .unregister(clazz, service); - } -} diff --git a/Patchwork/src/main/java/me/totalfreedom/data/ServiceTaskRegistry.java b/Patchwork/src/main/java/me/totalfreedom/data/ServiceTaskRegistry.java new file mode 100644 index 0000000..4a1b191 --- /dev/null +++ b/Patchwork/src/main/java/me/totalfreedom/data/ServiceTaskRegistry.java @@ -0,0 +1,316 @@ +package me.totalfreedom.data; + +import me.totalfreedom.service.Service; +import me.totalfreedom.service.ServiceSubscription; +import me.totalfreedom.service.SubscriptionProvider; +import me.totalfreedom.service.Task; +import me.totalfreedom.service.TaskSubscription; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * A registry for all services and tasks registered with Patchwork. + *
+ * This class is not thread-safe, and should only be accessed from the main server thread. + *
+ *
+ * Services are tickable tasks which execute every single game tick. They are registered using + * {@link #registerService(ServiceSubscription)} and can be started using {@link #startService(Class)}. + *
+ *
+ * Tasks are runnable tasks which execute at the provided times in the {@link Task} and + * {@link TaskSubscription} classes. These define whether the Task is repeating, delayed, or just a one-time task. + * Tasks are registered using {@link #registerTask(TaskSubscription)} and can be started using + * {@link #startTask(Class)}. + *
+ *
+ * ServiceSubscriptions and TaskSubscriptions can both be easily obtained using the + * {@link SubscriptionProvider} utility class. + * + * @see Service + * @see Task + * @see ServiceSubscription + * @see TaskSubscription + * @see SubscriptionProvider + */ +public class ServiceTaskRegistry +{ + /** + * A list of all services registered with the registry. + */ + private final List> services; + /** + * A list of all tasks registered with the registry. + */ + private final List> tasks; + + /** + * Creates a new instance of the registry and initializes the service and task lists to new empty + * {@link ArrayList}s. + */ + public ServiceTaskRegistry() + { + this.services = new ArrayList<>(); + this.tasks = new ArrayList<>(); + } + + /** + * Starts all services registered with the registry. + *
+ * This method should be avoided, due to the fact that modules may have registered their services + * after this method + * has already been called. In this case, it is preferred to start + * each service using {@link #startService(Class)}. + *
+ * However, Patchwork calls this method when the server is starting up, as Patchwork is the central + * resource + * manager for registered tasks and services. Patchwork will call this method on the first server tick, so unless + * you are registering services AND starting them POST WORLD, you do not need to worry about starting + * your services. + */ + public void startAllServices() + { + for (final ServiceSubscription service : this.services) + { + service.start(); + } + } + + /** + * Starts all tasks registered with the registry. + *
+ * This method should be avoided, due to the fact that modules may have registered their tasks after + * this method + * has already been called. In this case, it is preferred to start + * each task + * using {@link #startTask(Class)}. + *
+ * However, Patchwork calls this method when the server is starting up, as Patchwork is the central + * resource + * manager for registered tasks and services. Patchwork will call this method on the first server tick, so unless + * you are registering tasks AND starting them POST WORLD, you do not need to worry about starting + * your tasks. + */ + public void startAllTasks() + { + for (final TaskSubscription task : this.tasks) + { + task.start(); + } + } + + /** + * Stops all services registered with the registry. + *
+ * This method should be avoided, due to the fact that modules should be handling their own + * registrations. + * It is preferred to use {@link #stopService(Class)} for each service you would like to stop. + *
+ * However, Patchwork calls this method when the server is shutting down, or when Patchwork is being + * disabled, as Patchwork is the central resource manager for registered tasks and services. + * Unless you are modifying service states while the server is running, you do not need to worry about + * disabling or unregistering your services. + */ + public void stopAllServices() + { + for (final ServiceSubscription service : this.services) + { + service.stop(); + } + } + + /** + * Stops all tasks registered with the registry. + *
+ * This method should be avoided, due to the fact that modules should be handling their own + * registrations. + * It is preferred to use {@link #stopTask(Class)} for each task you would like to stop. + *
+ * However, Patchwork calls this method when the server is shutting down, or when Patchwork is being + * disabled, as Patchwork is the central resource manager for registered tasks and services. + * Unless you are modifying task states while the server is running, you do not need to worry about + * disabling or unregistering your tasks. + */ + public void stopAllTasks() + { + for (final TaskSubscription task : this.tasks) + { + task.stop(); + } + } + + /** + * Registers a service with the registry. + *
+ * Services must be registered using ServiceSubscriptions, which can be easily obtained through the + * {@link SubscriptionProvider} utility class. + * + * @param service The service you are trying to register. + * @param A generic type for type inference of the service being registered. + */ + public void registerService(final ServiceSubscription service) + { + this.services.add(service); + } + + /** + * Registers a task with the registry. + *
+ * Tasks must be registered using TaskSubscriptions, which can be easily obtained through the + * {@link SubscriptionProvider} utility class. + * + * @param task The task you are trying to register. + * @param A generic type for type inference of the task being registered. + */ + public void registerTask(final TaskSubscription task) + { + this.tasks.add(task); + } + + /** + * Starts a service using the specified {@link Service} class. + *
+ * The service should already be registered with the registry as a ServiceSubscription. + * + * @param clazz The class of the service you are trying to start. + * @see ServiceSubscription + * @see #registerService(ServiceSubscription) + */ + public void startService(final Class clazz) + { + this.getService(clazz) + .start(); + } + + /** + * Gets a {@link ServiceSubscription} from the registry using the specified class. + *
+ * The class should be the service class you are trying to locate, not the class for the subscription + * itself. + *
+ * The service should have been registered previously as a ServiceSubscription. + * + * @param clazz The class of the service you are trying to locate. + * @param A generic type for type inference of the service requested. + * @return The {@link ServiceSubscription} for the specified class, or null if it could not be found. + * @see #registerService(ServiceSubscription) + * @see ServiceSubscription + */ + @Nullable + public ServiceSubscription getService(final Class clazz) + { + for (final ServiceSubscription service : this.services) + { + if (service.getService() + .getClass() + .equals(clazz)) + { + return (ServiceSubscription) service; + } + } + return null; + } + + /** + * Stops a service using the specified {@link Service} class. + *
+ * The service should already be registered with the registry as a ServiceSubscription. + * + * @param clazz The class of the service you are trying to stop. + * @see #registerService(ServiceSubscription) + * @see ServiceSubscription + */ + public void stopService(final Class clazz) + { + this.getService(clazz) + .stop(); + } + + /** + * Starts a task using the specified {@link Task} class. + *
+ * The task should already be registered with the registry as a TaskSubscription. + * + * @param clazz The class of the task you are trying to start. + * @see #registerTask(TaskSubscription) + * @see TaskSubscription + */ + public void startTask(final Class clazz) + { + this.getTask(clazz) + .start(); + } + + /** + * Gets a {@link TaskSubscription} from the registry using the specified class. + *
+ * The class should be the task class you are trying to locate, not the class for the subscription + * itself. + *
+ * The task should have been registered previously as a TaskSubscription. + * + * @param clazz The class of the task you are trying to locate. + * @param A generic type for type inference of the task requested. + * @return The {@link TaskSubscription} for the specified class, or null if it could not be found. + * @see #registerTask(TaskSubscription) + * @see TaskSubscription + */ + public TaskSubscription getTask(final Class clazz) + { + for (final TaskSubscription task : this.tasks) + { + if (task.getTask() + .getClass() + .equals(clazz)) + { + return (TaskSubscription) task; + } + } + return null; + } + + /** + * Stops a task using the specified {@link Task} class. + *
+ * The task should already be registered with the registry as a TaskSubscription. + * + * @param clazz The class of the task you are trying to stop. + * @see #registerTask(TaskSubscription) + * @see TaskSubscription + */ + public void stopTask(final Class clazz) + { + this.getTask(clazz) + .stop(); + } + + /** + * Unregisters a service from the registry. + *
+ * The service should have been registered previously as a ServiceSubscription. + * + * @param service The service you are trying to unregister. + * @see #registerService(ServiceSubscription) + * @see ServiceSubscription + */ + public void unregisterService(final Class clazz) + { + this.services.remove(getService(clazz)); + } + + /** + * Unregisters a task from the registry. + *
+ * The task should have been registered previously as a TaskSubscription. + * + * @param clazz The task you are trying to unregister. + * @see #registerTask(TaskSubscription) + * @see TaskSubscription + */ + public void unregisterTask(final Class clazz) + { + this.tasks.remove(getTask(clazz)); + } +} diff --git a/Patchwork/src/main/java/me/totalfreedom/service/FreedomExecutor.java b/Patchwork/src/main/java/me/totalfreedom/service/FreedomExecutor.java index 6c6542d..dcaff95 100644 --- a/Patchwork/src/main/java/me/totalfreedom/service/FreedomExecutor.java +++ b/Patchwork/src/main/java/me/totalfreedom/service/FreedomExecutor.java @@ -2,7 +2,7 @@ package me.totalfreedom.service; import me.totalfreedom.base.CommonsBase; import org.bukkit.Bukkit; -import org.jetbrains.annotations.NotNull; +import org.bukkit.plugin.java.JavaPlugin; import java.util.concurrent.Executor; @@ -19,29 +19,40 @@ public class FreedomExecutor .runTaskAsynchronously(CommonsBase.getInstance(), r); } - public Executor scheduled(final long delay, final long period) + public Executor singleExecutor(final JavaPlugin plugin) { return r -> Bukkit.getScheduler() - .runTaskTimer( - CommonsBase.getInstance(), - r, - delay, - period); + .runTask(plugin, r); } - public Executor scheduledAsync(final long delay, final long period) + public Executor delayedExecutor(final JavaPlugin plugin, final long delay) { return r -> Bukkit.getScheduler() - .runTaskTimerAsynchronously( - CommonsBase.getInstance(), - r, - delay, - period); + .runTaskLater(plugin, r, delay); } - public void runSync(@NotNull final Task task) + public Executor periodicExecutor(final JavaPlugin plugin, final long delay, final long period) { - getSync().execute(task); + return r -> Bukkit.getScheduler() + .runTaskTimer(plugin, r, delay, period); + } + + public Executor asynchronousSingleExecutor(final JavaPlugin plugin) + { + return r -> Bukkit.getScheduler() + .runTaskAsynchronously(plugin, r); + } + + public Executor asynchronousDelayedExecutor(final JavaPlugin plugin, final long delay) + { + return r -> Bukkit.getScheduler() + .runTaskLaterAsynchronously(plugin, r, delay); + } + + public Executor asynchronousPeriodicExecutor(final JavaPlugin plugin, final long delay, final long period) + { + return r -> Bukkit.getScheduler() + .runTaskTimerAsynchronously(plugin, r, delay, period); } public Executor getSync() @@ -49,11 +60,6 @@ public class FreedomExecutor return syncExecutor; } - public void runAsync(@NotNull final Task task) - { - getAsync().execute(task); - } - public Executor getAsync() { return asyncExecutor; diff --git a/Patchwork/src/main/java/me/totalfreedom/service/Service.java b/Patchwork/src/main/java/me/totalfreedom/service/Service.java index df33c00..592eb9c 100644 --- a/Patchwork/src/main/java/me/totalfreedom/service/Service.java +++ b/Patchwork/src/main/java/me/totalfreedom/service/Service.java @@ -1,47 +1,18 @@ package me.totalfreedom.service; -import me.totalfreedom.base.CommonsBase; - public abstract class Service { private final String name; - private boolean isActive = false; protected Service(final String name) { this.name = name; - - } - - public void start() - { - isActive = true; - CommonsBase.getInstance() - .getExecutor() - .getSync() - .execute(() -> - { - while (isActive) - { - tick(); - } - }); } public abstract void tick(); - public void stop() - { - isActive = false; - } - public String getName() { return name; } - - public boolean isActive() - { - return isActive; - } } diff --git a/Patchwork/src/main/java/me/totalfreedom/service/ServiceSubscription.java b/Patchwork/src/main/java/me/totalfreedom/service/ServiceSubscription.java new file mode 100644 index 0000000..8cc99cf --- /dev/null +++ b/Patchwork/src/main/java/me/totalfreedom/service/ServiceSubscription.java @@ -0,0 +1,77 @@ +package me.totalfreedom.service; + +import org.bukkit.Bukkit; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitTask; + +import java.util.concurrent.Executor; + +public final class ServiceSubscription +{ + private final T service; + private final boolean async; + private final Executor executor; + private final int serviceId; + + private boolean isActive = false; + + ServiceSubscription(final JavaPlugin plugin, final T service, final boolean async) + { + this.service = service; + this.async = async; + + final int[] tempId = new int[1]; + + if (async) + { + this.executor = r -> + { + final BukkitTask task = Bukkit.getScheduler() + .runTaskTimerAsynchronously(plugin, r, 0, 1); + tempId[0] = task.getTaskId(); + }; + } else + { + this.executor = r -> + { + final BukkitTask task = Bukkit.getScheduler() + .runTaskTimer(plugin, r, 0, 1); + tempId[0] = task.getTaskId(); + }; + } + + this.serviceId = tempId[0]; + } + + public void start() + { + this.isActive = true; + this.executor.execute(service::tick); + } + + public void stop() + { + this.isActive = false; + Bukkit.getScheduler().cancelTask(this.getServiceId()); + } + + public T getService() + { + return service; + } + + public int getServiceId() + { + return serviceId; + } + + public boolean isAsync() + { + return async; + } + + public boolean isActive() + { + return isActive; + } +} diff --git a/Patchwork/src/main/java/me/totalfreedom/service/SubscriptionProvider.java b/Patchwork/src/main/java/me/totalfreedom/service/SubscriptionProvider.java new file mode 100644 index 0000000..a1478c0 --- /dev/null +++ b/Patchwork/src/main/java/me/totalfreedom/service/SubscriptionProvider.java @@ -0,0 +1,45 @@ +package me.totalfreedom.service; + +import org.bukkit.plugin.java.JavaPlugin; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +public final class SubscriptionProvider +{ + private SubscriptionProvider() + { + throw new AssertionError(); + } + + @NotNull + @Contract(value = "_, _ -> new", pure = false) + public static final ServiceSubscription syncService(@NotNull final JavaPlugin plugin, + @NotNull final S service) + { + return new ServiceSubscription<>(plugin, service, false); + } + + @NotNull + @Contract(value = "_, _ -> new", pure = false) + public static final ServiceSubscription asyncService(@NotNull final JavaPlugin plugin, + @NotNull final S service) + { + return new ServiceSubscription<>(plugin, service, true); + } + + @NotNull + @Contract(value = "_, _ -> new", pure = false) + public static final TaskSubscription runSyncTask(@NotNull final JavaPlugin plugin, + @NotNull final T task) + { + return new TaskSubscription<>(plugin, task, false); + } + + @NotNull + @Contract(value = "_, _ -> new", pure = false) + public static final TaskSubscription runAsyncTask(@NotNull final JavaPlugin plugin, + @NotNull final T task) + { + return new TaskSubscription<>(plugin, task, true); + } +} diff --git a/Patchwork/src/main/java/me/totalfreedom/service/Task.java b/Patchwork/src/main/java/me/totalfreedom/service/Task.java index 941ae6f..b072b26 100644 --- a/Patchwork/src/main/java/me/totalfreedom/service/Task.java +++ b/Patchwork/src/main/java/me/totalfreedom/service/Task.java @@ -2,10 +2,6 @@ package me.totalfreedom.service; public interface Task extends Runnable { - void start(); - - void stop(); - boolean isRunning(); String getName(); diff --git a/Patchwork/src/main/java/me/totalfreedom/service/TaskSubscription.java b/Patchwork/src/main/java/me/totalfreedom/service/TaskSubscription.java new file mode 100644 index 0000000..e8e4b8e --- /dev/null +++ b/Patchwork/src/main/java/me/totalfreedom/service/TaskSubscription.java @@ -0,0 +1,143 @@ +package me.totalfreedom.service; + +import me.totalfreedom.utils.Pair; +import org.bukkit.Bukkit; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitTask; + +import java.util.concurrent.Executor; + +public final class TaskSubscription +{ + private final T task; + private final int taskId; + private final boolean async; + private final Executor executor; + + private boolean isActive = false; + + TaskSubscription(final JavaPlugin plugin, final T task, final boolean async) + { + this.task = task; + this.async = async; + + final long delay = (task.isDelayed() + ? task.getDelay() + : 0); + final long period = (task.isRepeating() + ? task.getInterval() + : 0); + + final Pair integerExecutorPair = async + ? getAsync(plugin, delay, period) + : getSync(plugin, delay, period); + + this.executor = integerExecutorPair.value(); + this.taskId = integerExecutorPair.key(); + } + + private Pair getAsync(final JavaPlugin plugin, final long delay, final long period) + { + final Executor executor1; + final int[] tempId = new int[1]; + if (period != 0) + { + executor1 = r -> + { + final BukkitTask task1 = Bukkit.getScheduler() + .runTaskTimerAsynchronously(plugin, r, delay, period); + tempId[0] = task1.getTaskId(); + }; + } else if (delay != 0) + { + executor1 = r -> + { + final BukkitTask task1 = Bukkit.getScheduler() + .runTaskLaterAsynchronously(plugin, r, delay); + tempId[0] = task1.getTaskId(); + }; + } else + { + executor1 = r -> + { + final BukkitTask task1 = Bukkit.getScheduler() + .runTaskAsynchronously(plugin, r); + tempId[0] = task1.getTaskId(); + }; + } + + return new Pair<>(tempId[0], executor1); + } + + private Pair getSync(final JavaPlugin plugin, final long delay, final long period) + { + final Executor executor1; + final int[] tempId = new int[1]; + + if (period != 0) + { + executor1 = r -> + { + final BukkitTask task1 = Bukkit.getScheduler() + .runTaskTimer(plugin, r, delay, period); + tempId[0] = task1.getTaskId(); + }; + } else if (delay != 0) + { + executor1 = r -> + { + final BukkitTask task1 = Bukkit.getScheduler() + .runTaskLater(plugin, r, delay); + tempId[0] = task1.getTaskId(); + }; + } else + { + executor1 = r -> + { + final BukkitTask task1 = Bukkit.getScheduler() + .runTask(plugin, r); + tempId[0] = task1.getTaskId(); + }; + } + + return new Pair<>(tempId[0], executor1); + } + + public void start() + { + this.isActive = true; + executor.execute(task); + } + + public void stop() + { + this.isActive = false; + Bukkit.getScheduler() + .cancelTask(this.getTaskId()); + } + + public int getTaskId() + { + return taskId; + } + + public T getTask() + { + return task; + } + + public boolean isAsync() + { + return async; + } + + public Executor getExecutor() + { + return executor; + } + + public boolean isActive() + { + return isActive; + } +} diff --git a/Patchwork/src/main/java/me/totalfreedom/utils/InterpolationUtils.java b/Patchwork/src/main/java/me/totalfreedom/utils/InterpolationUtils.java index 587f05d..9f839ed 100644 --- a/Patchwork/src/main/java/me/totalfreedom/utils/InterpolationUtils.java +++ b/Patchwork/src/main/java/me/totalfreedom/utils/InterpolationUtils.java @@ -8,8 +8,13 @@ import org.bukkit.Color; import java.util.LinkedHashSet; import java.util.Set; -public class InterpolationUtils +public final class InterpolationUtils { + private InterpolationUtils() + { + throw new AssertionError(); + } + public static Set rainbow(final int length) { final LinkedHashSet base = new LinkedHashSet<>(); @@ -60,7 +65,54 @@ public class InterpolationUtils return res; } - public static Set rgbGradient(final int length, final Color from, final Color to, + public static Set rainbowComponent(final int length) + { + final LinkedHashSet base = new LinkedHashSet<>(); + final Set redToOrange = componentRGBGradient(length, NamedTextColor.RED, + NamedTextColor.GOLD, InterpolationUtils::linear); + final Set orangeToYellow = componentRGBGradient(length, NamedTextColor.GOLD, + NamedTextColor.YELLOW, InterpolationUtils::linear); + final Set yellowToGreen = componentRGBGradient(length, NamedTextColor.YELLOW, + NamedTextColor.GREEN, InterpolationUtils::linear); + final Set greenToBlue = componentRGBGradient(length, NamedTextColor.GREEN, + NamedTextColor.BLUE, InterpolationUtils::linear); + final Set blueToPurple = componentRGBGradient(length, NamedTextColor.BLUE, + NamedTextColor.LIGHT_PURPLE, + InterpolationUtils::linear); + final Set purpleToRed = componentRGBGradient(length, TextColor.color(75, 0, 130), + TextColor.color(255, 0, 0), InterpolationUtils::linear); + base.addAll(redToOrange); + base.addAll(orangeToYellow); + base.addAll(yellowToGreen); + base.addAll(greenToBlue); + base.addAll(blueToPurple); + base.addAll(purpleToRed); + return base; + } + + private static Set componentRGBGradient(final int length, final TextColor from, final TextColor to, + final Interpolator interpolator) + { + final double[] r = interpolator.interpolate(from.red(), to.red(), length); + final double[] g = interpolator.interpolate(from.green(), to.green(), length); + final double[] b = interpolator.interpolate(from.blue(), to.blue(), length); + + final LinkedHashSet gradient = new LinkedHashSet<>(); + + for (int i = 0; i < length; i++) + { + final TextColor color = TextColor.color((int) r[i], (int) g[i], (int) b[i]); + gradient.add(color); + } + return gradient; + } + + public static Set standardGradient(final int length, final Color from, final Color to) + { + return rgbGradient(length, from, to, InterpolationUtils::linear); + } + + private static Set rgbGradient(final int length, final Color from, final Color to, final Interpolator interpolator) { final double[] r = interpolator.interpolate(from.getRed(), to.getRed(), length); @@ -77,44 +129,8 @@ public class InterpolationUtils return gradient; } - public static Set rainbowComponent(final int length) + public static Set standardComponentGradient(final int length, final TextColor from, final TextColor to) { - final LinkedHashSet base = new LinkedHashSet<>(); - final Set redToOrange = componentRGBGradient(length, NamedTextColor.RED, - NamedTextColor.GOLD, InterpolationUtils::linear); - final Set orangeToYellow = componentRGBGradient(length, NamedTextColor.GOLD, - NamedTextColor.YELLOW, InterpolationUtils::linear); - final Set yellowToGreen = componentRGBGradient(length, NamedTextColor.YELLOW, - NamedTextColor.GREEN, InterpolationUtils::linear); - final Set greenToBlue = componentRGBGradient(length, NamedTextColor.GREEN, - NamedTextColor.BLUE, InterpolationUtils::linear); - final Set blueToPurple = componentRGBGradient(length, NamedTextColor.BLUE, - NamedTextColor.LIGHT_PURPLE, InterpolationUtils::linear); - final Set purpleToRed = componentRGBGradient(length, TextColor.color(75, 0, 130), - TextColor.color(255, 0, 0), InterpolationUtils::linear); - base.addAll(redToOrange); - base.addAll(orangeToYellow); - base.addAll(yellowToGreen); - base.addAll(greenToBlue); - base.addAll(blueToPurple); - base.addAll(purpleToRed); - return base; - } - - public static Set componentRGBGradient(final int length, final TextColor from, final TextColor to, - final Interpolator interpolator) - { - final double[] r = interpolator.interpolate(from.red(), to.red(), length); - final double[] g = interpolator.interpolate(from.green(), to.green(), length); - final double[] b = interpolator.interpolate(from.blue(), to.blue(), length); - - final LinkedHashSet gradient = new LinkedHashSet<>(); - - for (int i = 0; i < length; i++) - { - final TextColor color = TextColor.color((int) r[i], (int) g[i], (int) b[i]); - gradient.add(color); - } - return gradient; + return componentRGBGradient(length, from, to, InterpolationUtils::linear); } }