Skip to content

Instantly share code, notes, and snippets.

@aikar
Created June 14, 2015 15:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aikar/06c42a2d7f72c18d5819 to your computer and use it in GitHub Desktop.
Save aikar/06c42a2d7f72c18d5819 to your computer and use it in GitHub Desktop.
package com.empireminecraft.systems.residence;
import com.empireminecraft.systems.residence.protection.ClaimedResidence;
@FunctionalInterface
public interface ResidenceTimer {
void onTick(ClaimedResidence res, String[] args, ResidenceTimerWrapper wrapper);
}
package com.empireminecraft.systems.residence;
import com.empireminecraft.systems.residence.protection.ClaimedResidence;
import com.empireminecraft.util.BukkitUtil;
import com.empireminecraft.util.RegexPatterns;
import com.empireminecraft.util.Util;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
public final class ResidenceTimerManager {
private static final Map<String, ResidenceTimer> timerMethods = Maps.newHashMap();
private static final Multimap<Integer, ResidenceTimerWrapper> timers = ArrayListMultimap.create();
private static int timerCounter = 0;
private ResidenceTimerManager() {}
public static void initialize() {
BukkitUtil.runTaskTimer(() -> {
final int bucketId = Bukkit.spigot().getTick() % 20;
final Collection<ResidenceTimerWrapper> timerBucket = timers.get(bucketId);
if (timerBucket != null && !timerBucket.isEmpty()) {
timerBucket.forEach(ResidenceTimerWrapper::tick);
}
}, 1);
registerTimers();
}
private static void registerTimers() {
registerTimerMethod("cmd", (res, args, w) -> {
String cmd = Util.join(args);
cmd = Util.replaceStrings(cmd,
"%resname%", res.getName(),
"%resaddr%", res.getAddress().toString(),
"%resowner%", res.getOwner()
);
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), cmd);
});
registerTimerMethod("teleport", (res, args, w) -> {
// Args: <sourceLocName1,sourceLocName2> <targetLocName> [radius=3] [all/items]
if (args.length < 2) {
Util.log("[timer:teleport] not enough args: " + res.getName());
return;
}
String target = args[1];
final Location targetLoc = res.getNamedLocations().get(target);
if (targetLoc == null) {
Util.log("[timer:teleport] Could not find targetLoc: " + res.getName()+":"+target);
return;
}
int radius = args.length > 2 ? Util.parseInt(args[2], 3) : 3;
boolean all = (args.length > 3 && "all".equals(args[3]));
boolean items = (args.length > 3 && "items".equals(args[3]));
final String[] sources = RegexPatterns.COMMA.split(args[0]);
for (String source : sources) {
final Location center = res.getNamedLocations().get(source);
if (center == null) {
Util.log("[timer:teleport] Could not find sourceLoc: " + res.getName()+":"+source);
continue;
}
if (!center.isChunkLoaded()) {
continue;
}
center.getWorld()
.getNearbyEntities(center, radius, radius, radius)
.stream().filter(entity -> all
|| (items && entity instanceof Item)
|| (!items && entity instanceof Player))
.forEach(entity -> entity.teleport(targetLoc));
}
});
}
public static boolean isValidTimer(String name) {
name = RegexPatterns.COLON.split(name.toLowerCase())[0];
return timerMethods.containsKey(name);
}
public static void registerTimerMethod(String name, ResidenceTimer timer) {
name = name.toLowerCase();
timerMethods.put(name, timer);
}
public static void registerResidenceTimer(ClaimedResidence res, String name, int interval, String[] args) {
int base = interval % 20;
removeResidenceTimer(res, name);
name = name.toLowerCase();
String timerName = RegexPatterns.COLON.split(name)[0];
ResidenceTimer timer = timerMethods.get(timerName);
if (timer == null) {
Util.logSevere("Attempted to register invalid timer: " + name);
return;
}
// Offset will make it so every timer at say interval 10
// doesn't all run on the same tick
int offset = timerCounter++ % 20;
ResidenceTimerWrapper wrapper = new ResidenceTimerWrapper(timer, res, name, args, interval);
for (int i = 0; i < 20; i++) {
// If Interval = 25, base = 5, only schedule on bucket 5. If <= 20, schedule for
// Every valid bucket the event runs in. For > 20, it'll run more often than
// Needed, but the ::tick method will enforce tick interval rate.
if ((interval <= 20 && i % base == 0) || (interval > 20 && i == base)) {
final int bucketKey = (i + offset) % 20;
timers.put(bucketKey, wrapper);
}
}
}
public static boolean removeResidenceTimer(ClaimedResidence residence, String name) {
boolean found = false;
final Iterator<ResidenceTimerWrapper> iterator = timers.values().iterator();
while (iterator.hasNext()) {
final ResidenceTimerWrapper w = iterator.next();
if (w.getRes() == residence && w.getName().equals(name.toLowerCase())) {
iterator.remove();
found = true;
}
}
return found;
}
public static void loadResidence(ClaimedResidence res) {
res.getPersistentMeta().entrySet().forEach(e -> {
if (e.getKey().startsWith("timer_")) {
String timerName = e.getKey().substring(6);
final String[] split = RegexPatterns.COLON.split(e.getValue(), 2);
Integer interval = Util.parseInt(split[0]);
if (interval == null) {
return;
}
String[] args = split.length > 1 ? RegexPatterns.SPACE.split(split[1]) : new String[0];
registerResidenceTimer(res, timerName, interval, args);
}
});
}
}
package com.empireminecraft.systems.residence;
import com.empireminecraft.config.meta.PersistentMetaKey;
import com.empireminecraft.systems.residence.protection.ClaimedResidence;
import lombok.Data;
import lombok.NonNull;
import org.bukkit.Bukkit;
@Data
public class ResidenceTimerWrapper {
private final ResidenceTimer timer;
private final ClaimedResidence res;
private final String name;
private final String[] args;
private final int timerRate;
private int lastTick = Bukkit.spigot().getTick();
ResidenceTimerWrapper(@NonNull ResidenceTimer timer, @NonNull ClaimedResidence res,
@NonNull String name, String[] args, int timerRate) {
this.timer = timer;
this.res = res;
this.name = name;
this.args = args;
this.timerRate = timerRate;
}
public void tick() {
int tick = Bukkit.spigot().getTick();
if (tick - lastTick >= timerRate) {
lastTick += timerRate;
if (!res.hasPlayers() && res.hasPersistentMeta(PersistentMetaKey.RES_TIMER_REQUIRE_PLAYER+name)) {
return;
}
timer.onTick(res, args, this);
}
}
public void delay(int ticks) {
lastTick += ticks;
}
public void cancel() {
ResidenceTimerManager.removeResidenceTimer(res, name);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment