Reputation: 1110
I am working on a Java/Spigot plugin for minecraft where every 15 minutes I'd like to send the player a message. It needs to be every 15 minutes since they joined not every 15 minutes all together, so every player would be on a different timer.
What I have tried
@SuppressWarnings("deprecation")
public static void setup()
{
Bukkit.getScheduler().scheduleAsyncRepeatingTask(MyPlugin.getPlugin(), new BukkitRunnable()
{
public void run() {
for (final String string : online.keySet()) {
Utils.sendMessage(string, "It's been 15 minutes")
}
}
}, 1L, 1200L);
}
but that is doing every 15 minutes since the server started. I can't find a way to do it for every player that won't lag the server if there are 50+ players online.
Edit:
Second attempt
private static boolean taskStarted = false;
private static HashMap<UUID, Long> map = new HashMap<UUID, Long>();
@EventHandler
public void onJoin(PlayerJoinEvent event) {
map.put(event.getPlayer().getUniqueId(), Calendar.getInstance().getTime().getTime());
}
@EventHandler
public void onQuit(PlayerQuitEvent event) {
map.remove(event.getPlayer().getUniqueId());
}
@SuppressWarnings("deprecation")
public static void startPowerTask() {
if(taskStarted)
return;
taskStarted = true;
Bukkit.getScheduler().scheduleSyncRepeatingTask(ServerCore.getPlugin(), new BukkitRunnable() {
@Override
public void run() {
for(UUID uuid : map.keySet()) {
long time = map.get(uuid);
if(time == ???)
Utils.sendMessage(uuid, "It's been 15 minutes");
}
}
}, 20, 20);
}
I don't know how to check if it's been 15 minutes
Upvotes: 0
Views: 3547
Reputation:
Scheduling a task per player is not a good idea, also why are you using an async task? These are especially costly to setup and may led to unintentional behaviour unless you know what you're doing. Always aim at using a sync task instead if possible.
For the least lag I'm using a single scheduler, called the global scheduler.
Listen for the PlayerJoinEvent, we need to know each player and when they joined. I'm using a hashmap to store the player UUID as well as a long representing their join date.
private HashMap<UUID, Long> map = new HashMap<UUID, Long>();
@EventHandler
public void onJoin(PlayerJoinEvent event) {
map.put(event.getPlayer().getUniqueID(), Calendar.getInstance().getTime().getTime());
}
You can store the player name or even the player object instead, but UUIDs are most robust as they are consistent.
Now we need to check if the hashmap is empty or not, this can be done right after setting values to the map:
This makes it only run when necessary, reducing lag.
In the scheduler we want to loop through all players in the map and compare their join date with the current date, if above 15 minutes, do something and set the player join date as the current date. This scheduler should preferably run as rarely as possible, but to achieve most accurate results, aim at around a second (20 ticks)
Upvotes: 4
Reputation: 2970
I am not personally familiar with Bukkit, however, the documentation provides a getLastPlayed() method which should return the date when the user last was seen on the server. I believe you could use this date to calculate the delay
in the BukkitScheduler
, like this:
@SuppressWarnings("deprecation")
public static void setup()
{
// calculate delay amount
static long delay = somePlayer.getLastPlayed();
// figure out remaining time post calculation
delay = (System.currentTimeMillis() - delay) % 1200;
// proceed with your code as before
Bukkit.getScheduler().scheduleAsyncRepeatingTask(MyPlugin.getPlugin(), new BukkitRunnable()
{
public void run() {
for (final String string : online.keySet()) {
Utils.sendMessage(string, "It's been 15 minutes")
}
}
}, delay, 1200L);
}
Note that I'm assuming 1200 ticks gives you the amount of time you want, but if not you can change that value after delay
as well as in the modular arithmetic accordingly.
Upvotes: 1