AutoLeaveTask is now throttled to only spend a certain amount of time per server tick on removing inactive players, to prevent it from potentially choking very large servers. This amount of time can be specified by the new setting "autoLeaveRoutineMaxMillisecondsPerTick" (default 5ms, ~10% of a tick).
Also some very minor improvements to the config command.
This commit is contained in:
parent
63837691ce
commit
cec9422a13
@ -75,6 +75,7 @@ public class Conf
|
|||||||
|
|
||||||
public static double autoLeaveAfterDaysOfInactivity = 10.0;
|
public static double autoLeaveAfterDaysOfInactivity = 10.0;
|
||||||
public static double autoLeaveRoutineRunsEveryXMinutes = 5.0;
|
public static double autoLeaveRoutineRunsEveryXMinutes = 5.0;
|
||||||
|
public static int autoLeaveRoutineMaxMillisecondsPerTick = 5; // 1 server tick is roughly 50ms, so default max 10% of a tick
|
||||||
public static boolean removePlayerDataWhenBanned = true;
|
public static boolean removePlayerDataWhenBanned = true;
|
||||||
|
|
||||||
public static boolean worldGuardChecking = false;
|
public static boolean worldGuardChecking = false;
|
||||||
|
@ -108,6 +108,22 @@ public class CmdConfig extends FCommand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// long
|
||||||
|
else if (target.getType() == long.class)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
long longVal = Long.parseLong(value);
|
||||||
|
target.setLong(null, longVal);
|
||||||
|
success = "\""+fieldName+"\" option set to "+longVal+".";
|
||||||
|
}
|
||||||
|
catch(NumberFormatException ex)
|
||||||
|
{
|
||||||
|
sendMessage("Cannot set \""+fieldName+"\": long integer (whole number) value required.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// double
|
// double
|
||||||
else if (target.getType() == double.class)
|
else if (target.getType() == double.class)
|
||||||
{
|
{
|
||||||
@ -268,11 +284,13 @@ public class CmdConfig extends FCommand
|
|||||||
|
|
||||||
if (!success.isEmpty())
|
if (!success.isEmpty())
|
||||||
{
|
{
|
||||||
sendMessage(success);
|
|
||||||
if (sender instanceof Player)
|
if (sender instanceof Player)
|
||||||
{
|
{
|
||||||
|
sendMessage(success);
|
||||||
P.p.log(success + " Command was run by "+fme.getName()+".");
|
P.p.log(success + " Command was run by "+fme.getName()+".");
|
||||||
}
|
}
|
||||||
|
else // using P.p.log() instead of sendMessage if run from server console so that "[Factions v#.#.#]" is prepended in server log
|
||||||
|
P.p.log(success);
|
||||||
}
|
}
|
||||||
// save change to disk
|
// save change to disk
|
||||||
Conf.save();
|
Conf.save();
|
||||||
|
94
src/com/massivecraft/factions/util/AutoLeaveProcessTask.java
Normal file
94
src/com/massivecraft/factions/util/AutoLeaveProcessTask.java
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
package com.massivecraft.factions.util;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.ListIterator;
|
||||||
|
|
||||||
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
|
||||||
|
import com.massivecraft.factions.Conf;
|
||||||
|
import com.massivecraft.factions.Faction;
|
||||||
|
import com.massivecraft.factions.FPlayer;
|
||||||
|
import com.massivecraft.factions.FPlayers;
|
||||||
|
import com.massivecraft.factions.P;
|
||||||
|
import com.massivecraft.factions.struct.Role;
|
||||||
|
|
||||||
|
public class AutoLeaveProcessTask extends BukkitRunnable
|
||||||
|
{
|
||||||
|
private transient boolean readyToGo = false;
|
||||||
|
private transient boolean finished = false;
|
||||||
|
private transient ArrayList<FPlayer> fplayers;
|
||||||
|
private transient ListIterator<FPlayer> iterator;
|
||||||
|
private transient double toleranceMillis;
|
||||||
|
|
||||||
|
public AutoLeaveProcessTask()
|
||||||
|
{
|
||||||
|
fplayers = new ArrayList<FPlayer>(FPlayers.i.get());
|
||||||
|
this.iterator = fplayers.listIterator();
|
||||||
|
this.toleranceMillis = Conf.autoLeaveAfterDaysOfInactivity * 24 * 60 * 60 * 1000;
|
||||||
|
this.readyToGo = true;
|
||||||
|
this.finished = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
if (Conf.autoLeaveAfterDaysOfInactivity <= 0.0 || Conf.autoLeaveRoutineMaxMillisecondsPerTick <= 0.0)
|
||||||
|
{
|
||||||
|
this.stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! readyToGo) return;
|
||||||
|
// this is set so it only does one iteration at a time, no matter how frequently the timer fires
|
||||||
|
readyToGo = false;
|
||||||
|
// and this is tracked to keep one iteration from dragging on too long and possibly choking the system if there are a very large number of players to go through
|
||||||
|
long loopStartTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
while(iterator.hasNext())
|
||||||
|
{
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
|
||||||
|
// if this iteration has been running for maximum time, stop to take a breather until next tick
|
||||||
|
if (now > loopStartTime + Conf.autoLeaveRoutineMaxMillisecondsPerTick)
|
||||||
|
{
|
||||||
|
readyToGo = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FPlayer fplayer = iterator.next();
|
||||||
|
if (fplayer.isOffline() && now - fplayer.getLastLoginTime() > toleranceMillis)
|
||||||
|
{
|
||||||
|
if (Conf.logFactionLeave || Conf.logFactionKick)
|
||||||
|
P.p.log("Player "+fplayer.getName()+" was auto-removed due to inactivity.");
|
||||||
|
|
||||||
|
// if player is faction admin, sort out the faction since he's going away
|
||||||
|
if (fplayer.getRole() == Role.ADMIN)
|
||||||
|
{
|
||||||
|
Faction faction = fplayer.getFaction();
|
||||||
|
if (faction != null)
|
||||||
|
fplayer.getFaction().promoteNewLeader();
|
||||||
|
}
|
||||||
|
|
||||||
|
fplayer.leave(false);
|
||||||
|
iterator.remove(); // go ahead and remove this list's link to the FPlayer object
|
||||||
|
fplayer.detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// looks like we've finished
|
||||||
|
this.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// we're done, shut down
|
||||||
|
public void stop()
|
||||||
|
{
|
||||||
|
readyToGo = false;
|
||||||
|
finished = true;
|
||||||
|
|
||||||
|
this.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFinished()
|
||||||
|
{
|
||||||
|
return finished;
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,11 @@
|
|||||||
package com.massivecraft.factions.util;
|
package com.massivecraft.factions.util;
|
||||||
|
|
||||||
import com.massivecraft.factions.Conf;
|
import com.massivecraft.factions.Conf;
|
||||||
import com.massivecraft.factions.FPlayers;
|
|
||||||
import com.massivecraft.factions.P;
|
import com.massivecraft.factions.P;
|
||||||
|
|
||||||
public class AutoLeaveTask implements Runnable
|
public class AutoLeaveTask implements Runnable
|
||||||
{
|
{
|
||||||
|
private static AutoLeaveProcessTask task;
|
||||||
double rate;
|
double rate;
|
||||||
|
|
||||||
public AutoLeaveTask()
|
public AutoLeaveTask()
|
||||||
@ -13,11 +13,15 @@ public class AutoLeaveTask implements Runnable
|
|||||||
this.rate = Conf.autoLeaveRoutineRunsEveryXMinutes;
|
this.rate = Conf.autoLeaveRoutineRunsEveryXMinutes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run()
|
public synchronized void run()
|
||||||
{
|
{
|
||||||
FPlayers.i.autoLeaveOnInactivityRoutine();
|
if (task != null && ! task.isFinished())
|
||||||
|
return;
|
||||||
|
|
||||||
// maybe setting has been changed? if so, restart task at new rate
|
task = new AutoLeaveProcessTask();
|
||||||
|
task.runTaskTimer(P.p, 1, 1);
|
||||||
|
|
||||||
|
// maybe setting has been changed? if so, restart this task at new rate
|
||||||
if (this.rate != Conf.autoLeaveRoutineRunsEveryXMinutes)
|
if (this.rate != Conf.autoLeaveRoutineRunsEveryXMinutes)
|
||||||
P.p.startAutoLeaveTask(true);
|
P.p.startAutoLeaveTask(true);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user