This commit is contained in:
Paul Reilly 2023-06-02 17:07:14 -05:00
parent a632eb778c
commit 9481f88afd
20 changed files with 792 additions and 205 deletions

View File

@ -27,11 +27,11 @@ public class Datura extends JavaPlugin
CommonsBase.getInstance() CommonsBase.getInstance()
.getRegistrations() .getRegistrations()
.getServiceRegistry() .getServiceRegistry()
.register(this, locker); .registerService(this, locker);
CommonsBase.getInstance() CommonsBase.getInstance()
.getRegistrations() .getRegistrations()
.getServiceRegistry() .getServiceRegistry()
.register(this, cager); .registerService(this, cager);
Bukkit.getPluginManager() Bukkit.getPluginManager()
.registerEvents(halter, this); .registerEvents(halter, this);

View File

@ -1,16 +1,25 @@
package me.totalfreedom.fossil; package me.totalfreedom.fossil;
import me.totalfreedom.base.CommonsBase; 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; import org.bukkit.plugin.java.JavaPlugin;
public class Fossil extends JavaPlugin public class Fossil extends JavaPlugin
{ {
private final Trailer trailer = new Trailer();
private final Registration registration = CommonsBase.getInstance()
.getRegistrations();
@Override @Override
public void onEnable() public void onEnable()
{ {
CommonsBase.getInstance() registration.getModuleRegistry()
.getRegistrations() .addModule(this);
.getModuleRegistry()
.addModule(this); registration.getServiceRegistry()
.registerService(
SubscriptionProvider.syncService(this, trailer));
} }
} }

View File

@ -8,9 +8,9 @@ import org.jetbrains.annotations.Nullable;
public final class TrailItem extends ShopItem public final class TrailItem extends ShopItem
{ {
public TrailItem(final Material material) public TrailItem()
{ {
super(material); super(Material.LINGERING_POTION);
} }
@Override @Override

View File

@ -1,41 +1,37 @@
package me.totalfreedom.fossil.trail; package me.totalfreedom.fossil.trail;
import me.totalfreedom.particle.Trail; import me.totalfreedom.particle.Trail;
import me.totalfreedom.particle.TrailType;
import me.totalfreedom.service.Service; import me.totalfreedom.service.Service;
import org.bukkit.entity.Player;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.UUID;
public class Trailer extends Service public class Trailer extends Service
{ {
private final List<Trail> trailList = new ArrayList<>(); private final List<Trail> 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"); super("trailer_service");
} }
public void addTrail(final Trail trail) { public void addTrail(final Trail trail)
this.trailList.add(trail); {
this.activeTrails.add(trail);
} }
public void removeTrail(final Trail trail) { public void removeTrail(final Trail trail)
this.trailList.remove(trail); {
this.activeTrails.remove(trail);
} }
@Override @Override
public void tick() public void tick()
{ {
for (final Trail trail : trailList) { for (final Trail trail : activeTrails)
if (trail.getAssociatedPlayer().isOnline()) { {
final Player player = (Player) trail.getAssociatedPlayer(); trail.spawnParticle();
}
} }
} }
} }

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -35,7 +35,7 @@ public final class RainbowTrail extends SimpleTrail
final Color color = currentColor.next(); final Color color = currentColor.next();
final Player player = (Player) getAssociatedPlayer(); final Player player = (Player) getAssociatedPlayer();
final Particle particle = getTrailType().getType(); 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() final Location location = player.getLocation()
.clone() .clone()
.subtract(0, 1, 0); .subtract(0, 1, 0);

View File

@ -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);
}
}

View File

@ -8,5 +8,4 @@ public final class TrailProvider
return new BasicTrail(player); return new BasicTrail(player);
} }
} }

View File

@ -2,6 +2,8 @@ package me.totalfreedom.base;
import me.totalfreedom.event.EventBus; import me.totalfreedom.event.EventBus;
import me.totalfreedom.service.FreedomExecutor; import me.totalfreedom.service.FreedomExecutor;
import me.totalfreedom.service.SubscriptionProvider;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
public class CommonsBase extends JavaPlugin public class CommonsBase extends JavaPlugin
@ -18,21 +20,23 @@ public class CommonsBase extends JavaPlugin
@Override @Override
public void onDisable() public void onDisable()
{ {
Bukkit.getScheduler().runTaskLater(this, () -> getRegistrations()
.getServiceRegistry()
.stopAllServices(), 1L);
getRegistrations().getServiceRegistry() getRegistrations().getServiceRegistry()
.stopAll(); .unregisterService(EventBus.class);
getRegistrations().getServiceRegistry()
.unregister(EventBus.class, eventBus);
} }
@Override @Override
public void onEnable() public void onEnable()
{ {
getRegistrations().getServiceRegistry() getRegistrations().getServiceRegistry()
.register(this, eventBus); .registerService(SubscriptionProvider.asyncService(this, eventBus));
getExecutor().getSync() getExecutor().getSync()
.execute(() -> getRegistrations() .execute(() -> getRegistrations()
.getServiceRegistry() .getServiceRegistry()
.startAll()); .startAllServices());
} }
public FreedomExecutor getExecutor() public FreedomExecutor getExecutor()

View File

@ -4,14 +4,14 @@ import me.totalfreedom.data.ConfigRegistry;
import me.totalfreedom.data.EventRegistry; import me.totalfreedom.data.EventRegistry;
import me.totalfreedom.data.GroupRegistry; import me.totalfreedom.data.GroupRegistry;
import me.totalfreedom.data.ModuleRegistry; import me.totalfreedom.data.ModuleRegistry;
import me.totalfreedom.data.ServiceRegistry; import me.totalfreedom.data.ServiceTaskRegistry;
import me.totalfreedom.data.UserRegistry; import me.totalfreedom.data.UserRegistry;
public class Registration public class Registration
{ {
private final EventRegistry eventRegistry; private final EventRegistry eventRegistry;
private final UserRegistry userRegistry; private final UserRegistry userRegistry;
private final ServiceRegistry serviceRegistry; private final ServiceTaskRegistry serviceTaskRegistry;
private final ModuleRegistry moduleRegistry; private final ModuleRegistry moduleRegistry;
private final GroupRegistry groupRegistry; private final GroupRegistry groupRegistry;
private final ConfigRegistry configRegistry; private final ConfigRegistry configRegistry;
@ -20,7 +20,7 @@ public class Registration
{ {
this.eventRegistry = new EventRegistry(); this.eventRegistry = new EventRegistry();
this.userRegistry = new UserRegistry(); this.userRegistry = new UserRegistry();
this.serviceRegistry = new ServiceRegistry(); this.serviceTaskRegistry = new ServiceTaskRegistry();
this.moduleRegistry = new ModuleRegistry(); this.moduleRegistry = new ModuleRegistry();
this.groupRegistry = new GroupRegistry(); this.groupRegistry = new GroupRegistry();
this.configRegistry = new ConfigRegistry(); this.configRegistry = new ConfigRegistry();
@ -41,9 +41,9 @@ public class Registration
return userRegistry; return userRegistry;
} }
public ServiceRegistry getServiceRegistry() public ServiceTaskRegistry getServiceRegistry()
{ {
return serviceRegistry; return serviceTaskRegistry;
} }
public GroupRegistry getGroupRegistry() public GroupRegistry getGroupRegistry()

View File

@ -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<Service> 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<T>, though we may lose
// the identity of the code signature in the process.
// In this case, that is fine.
public <T extends Service> 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<T>) service.getClass(),
service,
plugin,
ServicePriority.Normal);
}
public <T extends Service> RegisteredServiceProvider<T> getService(final Class<T> clazz)
{
return Bukkit.getServicesManager()
.getRegistration(clazz);
}
public void unregister(final Class<? extends Service> clazz, final Service service)
{
this.services.remove(service);
Bukkit.getServicesManager()
.unregister(clazz, service);
}
}

View File

@ -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.
* <br>
* This class is <b>not</b> thread-safe, and should only be accessed from the main server thread.
* <br>
* <br>
* <b>Services</b> are tickable tasks which execute every single game tick. They are registered using
* {@link #registerService(ServiceSubscription)} and can be started using {@link #startService(Class)}.
* <br>
* <br>
* <b>Tasks</b> 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)}.
* <br>
* <br>
* <b>ServiceSubscriptions</b> and <b>TaskSubscriptions</b> 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<ServiceSubscription<?>> services;
/**
* A list of all tasks registered with the registry.
*/
private final List<TaskSubscription<?>> 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.
* <br>
* This method should be <i>avoided</i>, due to the fact that <b><i>modules may have registered their services
* after this method
* has already been called.</i></b> In this case, it is preferred to start
* each service using {@link #startService(Class)}.
* <br>
* However, <i><b>Patchwork calls this method when the server is starting up</b></i>, 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 <b>AND</b> starting them <b>POST WORLD</b>, 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.
* <br>
* This method should be <i>avoided</i>, due to the fact that <b><i>modules may have registered their tasks after
* this method
* has already been called.</i></b> In this case, it is preferred to start
* each task
* using {@link #startTask(Class)}.
* <br>
* However, <i><b>Patchwork calls this method when the server is starting up</b></i>, 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 <b>AND</b> starting them <b>POST WORLD</b>, 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.
* <br>
* This method should be <i>avoided</i>, due to the fact that <b><i>modules should be handling their own
* registrations</i></b>.
* It is preferred to use {@link #stopService(Class)} for each service you would like to stop.
* <br>
* However, <b><i>Patchwork calls this method when the server is shutting down</i></b>, or when Patchwork is being
* disabled, as Patchwork is the central resource manager for registered tasks and services.
* Unless you are <b>modifying service states while the server is running</b>, 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.
* <br>
* This method should be <i>avoided</i>, due to the fact that <b><i>modules should be handling their own
* registrations</i></b>.
* It is preferred to use {@link #stopTask(Class)} for each task you would like to stop.
* <br>
* However, <b><i>Patchwork calls this method when the server is shutting down</i></b>, or when Patchwork is being
* disabled, as Patchwork is the central resource manager for registered tasks and services.
* Unless you are <b>modifying task states while the server is running</b>, 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.
* <br>
* <i>Services must be registered using <b>ServiceSubscriptions</b></i>, which can be easily obtained through the
* {@link SubscriptionProvider} utility class.
*
* @param service The service you are trying to register.
* @param <T> A generic type for type inference of the service being registered.
*/
public <T extends Service> void registerService(final ServiceSubscription<T> service)
{
this.services.add(service);
}
/**
* Registers a task with the registry.
* <br>
* <i>Tasks must be registered using <b>TaskSubscriptions</b></i>, which can be easily obtained through the
* {@link SubscriptionProvider} utility class.
*
* @param task The task you are trying to register.
* @param <T> A generic type for type inference of the task being registered.
*/
public <T extends Task> void registerTask(final TaskSubscription<T> task)
{
this.tasks.add(task);
}
/**
* Starts a service using the specified {@link Service} class.
* <br>
* <i>The service should already be registered with the registry as a <b>ServiceSubscription</b></i>.
*
* @param clazz The class of the service you are trying to start.
* @see ServiceSubscription
* @see #registerService(ServiceSubscription)
*/
public void startService(final Class<? extends Service> clazz)
{
this.getService(clazz)
.start();
}
/**
* Gets a {@link ServiceSubscription} from the registry using the specified class.
* <br>
* <b>The class should be the <u>service class you are trying to locate</u>, not the class for the subscription
* itself</b>.
* <br>
* <i>The service should have been registered previously as a <b>ServiceSubscription</b></i>.
*
* @param clazz The class of the service you are trying to locate.
* @param <T> 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 <T extends Service> ServiceSubscription<T> getService(final Class<T> clazz)
{
for (final ServiceSubscription<?> service : this.services)
{
if (service.getService()
.getClass()
.equals(clazz))
{
return (ServiceSubscription<T>) service;
}
}
return null;
}
/**
* Stops a service using the specified {@link Service} class.
* <br>
* <i>The service should already be registered with the registry as a <b>ServiceSubscription</b></i>.
*
* @param clazz The class of the service you are trying to stop.
* @see #registerService(ServiceSubscription)
* @see ServiceSubscription
*/
public void stopService(final Class<? extends Service> clazz)
{
this.getService(clazz)
.stop();
}
/**
* Starts a task using the specified {@link Task} class.
* <br>
* <i>The task should already be registered with the registry as a <b>TaskSubscription</b></i>.
*
* @param clazz The class of the task you are trying to start.
* @see #registerTask(TaskSubscription)
* @see TaskSubscription
*/
public void startTask(final Class<? extends Task> clazz)
{
this.getTask(clazz)
.start();
}
/**
* Gets a {@link TaskSubscription} from the registry using the specified class.
* <br>
* <b>The class should be the <u>task class you are trying to locate</u>, not the class for the subscription
* itself</b>.
* <br>
* <i>The task should have been registered previously as a <b>TaskSubscription</b></i>.
*
* @param clazz The class of the task you are trying to locate.
* @param <T> 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 <T extends Task> TaskSubscription<T> getTask(final Class<T> clazz)
{
for (final TaskSubscription<?> task : this.tasks)
{
if (task.getTask()
.getClass()
.equals(clazz))
{
return (TaskSubscription<T>) task;
}
}
return null;
}
/**
* Stops a task using the specified {@link Task} class.
* <br>
* <i>The task should already be registered with the registry as a <b>TaskSubscription</b></i>.
*
* @param clazz The class of the task you are trying to stop.
* @see #registerTask(TaskSubscription)
* @see TaskSubscription
*/
public void stopTask(final Class<? extends Task> clazz)
{
this.getTask(clazz)
.stop();
}
/**
* Unregisters a service from the registry.
* <br>
* <i>The service should have been registered previously as a <b>ServiceSubscription</b></i>.
*
* @param service The service you are trying to unregister.
* @see #registerService(ServiceSubscription)
* @see ServiceSubscription
*/
public void unregisterService(final Class<? extends Service> clazz)
{
this.services.remove(getService(clazz));
}
/**
* Unregisters a task from the registry.
* <br>
* <i>The task should have been registered previously as a <b>TaskSubscription</b></i>.
*
* @param clazz The task you are trying to unregister.
* @see #registerTask(TaskSubscription)
* @see TaskSubscription
*/
public void unregisterTask(final Class<? extends Task> clazz)
{
this.tasks.remove(getTask(clazz));
}
}

View File

@ -2,7 +2,7 @@ package me.totalfreedom.service;
import me.totalfreedom.base.CommonsBase; import me.totalfreedom.base.CommonsBase;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.jetbrains.annotations.NotNull; import org.bukkit.plugin.java.JavaPlugin;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@ -19,29 +19,40 @@ public class FreedomExecutor
.runTaskAsynchronously(CommonsBase.getInstance(), r); .runTaskAsynchronously(CommonsBase.getInstance(), r);
} }
public Executor scheduled(final long delay, final long period) public Executor singleExecutor(final JavaPlugin plugin)
{ {
return r -> Bukkit.getScheduler() return r -> Bukkit.getScheduler()
.runTaskTimer( .runTask(plugin, r);
CommonsBase.getInstance(),
r,
delay,
period);
} }
public Executor scheduledAsync(final long delay, final long period) public Executor delayedExecutor(final JavaPlugin plugin, final long delay)
{ {
return r -> Bukkit.getScheduler() return r -> Bukkit.getScheduler()
.runTaskTimerAsynchronously( .runTaskLater(plugin, r, delay);
CommonsBase.getInstance(),
r,
delay,
period);
} }
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() public Executor getSync()
@ -49,11 +60,6 @@ public class FreedomExecutor
return syncExecutor; return syncExecutor;
} }
public void runAsync(@NotNull final Task task)
{
getAsync().execute(task);
}
public Executor getAsync() public Executor getAsync()
{ {
return asyncExecutor; return asyncExecutor;

View File

@ -1,47 +1,18 @@
package me.totalfreedom.service; package me.totalfreedom.service;
import me.totalfreedom.base.CommonsBase;
public abstract class Service public abstract class Service
{ {
private final String name; private final String name;
private boolean isActive = false;
protected Service(final String name) protected Service(final String name)
{ {
this.name = name; this.name = name;
}
public void start()
{
isActive = true;
CommonsBase.getInstance()
.getExecutor()
.getSync()
.execute(() ->
{
while (isActive)
{
tick();
}
});
} }
public abstract void tick(); public abstract void tick();
public void stop()
{
isActive = false;
}
public String getName() public String getName()
{ {
return name; return name;
} }
public boolean isActive()
{
return isActive;
}
} }

View File

@ -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<T extends Service>
{
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;
}
}

View File

@ -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 <S extends Service> ServiceSubscription<S> syncService(@NotNull final JavaPlugin plugin,
@NotNull final S service)
{
return new ServiceSubscription<>(plugin, service, false);
}
@NotNull
@Contract(value = "_, _ -> new", pure = false)
public static final <S extends Service> ServiceSubscription<S> asyncService(@NotNull final JavaPlugin plugin,
@NotNull final S service)
{
return new ServiceSubscription<>(plugin, service, true);
}
@NotNull
@Contract(value = "_, _ -> new", pure = false)
public static final <T extends Task> TaskSubscription<T> runSyncTask(@NotNull final JavaPlugin plugin,
@NotNull final T task)
{
return new TaskSubscription<>(plugin, task, false);
}
@NotNull
@Contract(value = "_, _ -> new", pure = false)
public static final <T extends Task> TaskSubscription<T> runAsyncTask(@NotNull final JavaPlugin plugin,
@NotNull final T task)
{
return new TaskSubscription<>(plugin, task, true);
}
}

View File

@ -2,10 +2,6 @@ package me.totalfreedom.service;
public interface Task extends Runnable public interface Task extends Runnable
{ {
void start();
void stop();
boolean isRunning(); boolean isRunning();
String getName(); String getName();

View File

@ -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<T extends Task>
{
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<Integer, Executor> integerExecutorPair = async
? getAsync(plugin, delay, period)
: getSync(plugin, delay, period);
this.executor = integerExecutorPair.value();
this.taskId = integerExecutorPair.key();
}
private Pair<Integer, Executor> 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<Integer, Executor> 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;
}
}

View File

@ -8,8 +8,13 @@ import org.bukkit.Color;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.Set; import java.util.Set;
public class InterpolationUtils public final class InterpolationUtils
{ {
private InterpolationUtils()
{
throw new AssertionError();
}
public static Set<Color> rainbow(final int length) public static Set<Color> rainbow(final int length)
{ {
final LinkedHashSet<Color> base = new LinkedHashSet<>(); final LinkedHashSet<Color> base = new LinkedHashSet<>();
@ -60,7 +65,54 @@ public class InterpolationUtils
return res; return res;
} }
public static Set<Color> rgbGradient(final int length, final Color from, final Color to, public static Set<TextColor> rainbowComponent(final int length)
{
final LinkedHashSet<TextColor> base = new LinkedHashSet<>();
final Set<TextColor> redToOrange = componentRGBGradient(length, NamedTextColor.RED,
NamedTextColor.GOLD, InterpolationUtils::linear);
final Set<TextColor> orangeToYellow = componentRGBGradient(length, NamedTextColor.GOLD,
NamedTextColor.YELLOW, InterpolationUtils::linear);
final Set<TextColor> yellowToGreen = componentRGBGradient(length, NamedTextColor.YELLOW,
NamedTextColor.GREEN, InterpolationUtils::linear);
final Set<TextColor> greenToBlue = componentRGBGradient(length, NamedTextColor.GREEN,
NamedTextColor.BLUE, InterpolationUtils::linear);
final Set<TextColor> blueToPurple = componentRGBGradient(length, NamedTextColor.BLUE,
NamedTextColor.LIGHT_PURPLE,
InterpolationUtils::linear);
final Set<TextColor> 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<TextColor> 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<TextColor> 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<Color> standardGradient(final int length, final Color from, final Color to)
{
return rgbGradient(length, from, to, InterpolationUtils::linear);
}
private static Set<Color> rgbGradient(final int length, final Color from, final Color to,
final Interpolator interpolator) final Interpolator interpolator)
{ {
final double[] r = interpolator.interpolate(from.getRed(), to.getRed(), length); final double[] r = interpolator.interpolate(from.getRed(), to.getRed(), length);
@ -77,44 +129,8 @@ public class InterpolationUtils
return gradient; return gradient;
} }
public static Set<TextColor> rainbowComponent(final int length) public static Set<TextColor> standardComponentGradient(final int length, final TextColor from, final TextColor to)
{ {
final LinkedHashSet<TextColor> base = new LinkedHashSet<>(); return componentRGBGradient(length, from, to, InterpolationUtils::linear);
final Set<TextColor> redToOrange = componentRGBGradient(length, NamedTextColor.RED,
NamedTextColor.GOLD, InterpolationUtils::linear);
final Set<TextColor> orangeToYellow = componentRGBGradient(length, NamedTextColor.GOLD,
NamedTextColor.YELLOW, InterpolationUtils::linear);
final Set<TextColor> yellowToGreen = componentRGBGradient(length, NamedTextColor.YELLOW,
NamedTextColor.GREEN, InterpolationUtils::linear);
final Set<TextColor> greenToBlue = componentRGBGradient(length, NamedTextColor.GREEN,
NamedTextColor.BLUE, InterpolationUtils::linear);
final Set<TextColor> blueToPurple = componentRGBGradient(length, NamedTextColor.BLUE,
NamedTextColor.LIGHT_PURPLE, InterpolationUtils::linear);
final Set<TextColor> 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<TextColor> 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<TextColor> 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;
} }
} }