Skip to content

Instantly share code, notes, and snippets.

@Cryptite
Created October 10, 2019 00:16
Show Gist options
  • Save Cryptite/fd48b752ec83eaa6bf505c8b497b8b53 to your computer and use it in GitHub Desktop.
Save Cryptite/fd48b752ec83eaa6bf505c8b497b8b53 to your computer and use it in GitHub Desktop.
ChunkTaskHandler - A system for registering sync repeatable Bukkit Tasks on Chunks
public class ChunkTaskHandler implements Listener {
private static ChunkTaskHandler instance = new ChunkTaskHandler();
private final TheArtifact plugin;
private Map<Integer, Map<Object, WorldRunnable>> registeredChunks = new HashMap<>();
public boolean debug = true;
private class WorldRunnable {
private final Object key;
private final Runnable runnable;
private final int delay;
private final int frequency;
private final StringLocation location;
private int taskId;
WorldRunnable(Object key, StringLocation l, Runnable runnable, int delay, int frequency) {
this.key = key;
this.location = l;
this.runnable = runnable;
this.delay = delay;
this.frequency = frequency;
start();
}
void start() {
if (taskId != 0) {
cancel();
}
if (location.isChunkLoaded()) {
taskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, runnable, delay, frequency);
if (debug) {
TheArtifact.log.info("Chunk Runnable STARTED: " + key + " (" + RPGUtil.getLocationFancyName(location) + ")");
}
}
}
void cancel() {
Bukkit.getScheduler().cancelTask(taskId);
taskId = 0;
if (debug) {
TheArtifact.log.info("Chunk Runnable STOPPED: " + key + " (" + RPGUtil.getLocationFancyName(location) + ")");
}
}
@Override
public int hashCode() {
return Objects.hashCode(location);
}
@Override
public boolean equals(Object obj) {
return obj instanceof WorldRunnable && location.equals(((WorldRunnable) obj).location);
}
}
private ChunkTaskHandler() {
this.plugin = (TheArtifact) Bukkit.getPluginManager().getPlugin("TheArtifact");
Bukkit.getPluginManager().registerEvents(this, plugin);
}
public static ChunkTaskHandler getInstance() {
return instance;
}
@EventHandler(priority = EventPriority.MONITOR)
private void onChunkLoad(ChunkLoadEvent e) {
Map<Object, WorldRunnable> effects = registeredChunks.get(getChunkHash(e.getChunk()));
if (effects != null) {
for (WorldRunnable entry : effects.values()) {
entry.start();
}
}
}
@EventHandler(priority = EventPriority.MONITOR)
private void onChunkUnload(ChunkUnloadEvent e) {
Map<Object, WorldRunnable> effects = registeredChunks.get(getChunkHash(e.getChunk()));
if (effects != null) {
for (WorldRunnable entry : effects.values()) {
entry.cancel();
}
}
}
public void registerTask(Object key, Location location, Runnable runnable, int delay, int frequency) {
int chunkKey = getChunkHash(location.getChunk());
Map<Object, WorldRunnable> effects = registeredChunks.getOrDefault(chunkKey, new HashMap<>());
//If we had an effect already here, remove first
if (removeTask(key)) {
TheArtifact.log.warning("Task Key Clash - Already had a task called " + key + "!");
}
StringLocation l = new StringLocation(location);
WorldRunnable effect = new WorldRunnable(key, l, runnable, delay, frequency);
effects.put(key, effect);
registeredChunks.put(chunkKey, effects);
if (debug) {
TheArtifact.log.info("Chunk Task REGISTERED: " + key + " (" + totalTasks() + ") at " + RPGUtil.getLocationFancyName(location));
}
}
private int totalTasks() {
return (int) registeredChunks.values().stream()
.map(Map::values)
.count();
}
public boolean removeTask(Object key) {
for (Map.Entry<Integer, Map<Object, WorldRunnable>> entry : registeredChunks.entrySet()) {
WorldRunnable remove = entry.getValue().remove(key);
if (remove != null) {
remove.cancel();
return true;
}
}
return false;
}
private int getChunkHash(Chunk c) {
return Objects.hash(c.getWorld(), c.getX(), c.getZ());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment