Automatic inactivity cleanup
This commit is contained in:
parent
482151aa9a
commit
a89dace930
@ -18,6 +18,7 @@ permissions:
|
||||
massivecore.store.stats: {description: show mstore statistics, default: false}
|
||||
massivecore.store.listcolls: {description: list collections in a database, default: false}
|
||||
massivecore.store.copydb: {description: copy database content, default: false}
|
||||
massivecore.store.playerclean: {description: clean inactive players, default: false}
|
||||
massivecore.usys: {description: use the usys command, default: false}
|
||||
massivecore.usys.multiverse: {description: manage multiverses, default: false}
|
||||
massivecore.usys.multiverse.list: {description: list multiverses, default: false}
|
||||
@ -62,6 +63,7 @@ permissions:
|
||||
massivecore.store.stats: true
|
||||
massivecore.store.listcolls: true
|
||||
massivecore.store.copydb: true
|
||||
massivecore.store.playerclean: true
|
||||
massivecore.usys: true
|
||||
massivecore.usys.multiverse: true
|
||||
massivecore.usys.multiverse.list: true
|
||||
@ -101,6 +103,7 @@ permissions:
|
||||
massivecore.kit.rank3:
|
||||
default: false
|
||||
children:
|
||||
massivecore.store.playerclean: true
|
||||
massivecore.kit.rank2: true
|
||||
massivecore.kit.rank2:
|
||||
default: false
|
||||
|
@ -127,6 +127,27 @@ public class MassiveCoreMConf extends Entity<MassiveCoreMConf>
|
||||
@EditorType(TypeBooleanOn.class)
|
||||
public boolean warnOnLocalAlter = false;
|
||||
|
||||
// -------------------------------------------- //
|
||||
// PLAYERCLEAN
|
||||
// -------------------------------------------- //
|
||||
|
||||
// How often should the task run?
|
||||
// When set to 0 this feature is disabled. Meaning no cleaning will be done.
|
||||
// Default: 1 day (Per default once a day.)
|
||||
public long playercleanPeriodMillis = TimeUnit.MILLIS_PER_DAY;
|
||||
|
||||
// This is used to decide at what time of the day the task will run.
|
||||
// For Example: If the taskPeriodMillis is 24 hours:
|
||||
// Set it to 0 for UTC midnight.
|
||||
// Set it to 3600000 for UTC midnight + 1 hour.
|
||||
public long playercleanOffsetMillis = 0;
|
||||
|
||||
// When did the task last run?
|
||||
// This need not be modified by the server owner.
|
||||
// It will be set for you automatically.
|
||||
// 0 means it never ran before.
|
||||
public long playercleanLastMillis = 0;
|
||||
|
||||
// -------------------------------------------- //
|
||||
// MONGODB
|
||||
// -------------------------------------------- //
|
||||
|
@ -18,6 +18,7 @@ public enum MassiveCorePerm implements Identified
|
||||
STORE_STATS,
|
||||
STORE_LISTCOLLS,
|
||||
STORE_COPYDB,
|
||||
STORE_PLAYERCLEAN,
|
||||
USYS,
|
||||
USYS_MULTIVERSE,
|
||||
USYS_MULTIVERSE_LIST,
|
||||
|
@ -20,5 +20,6 @@ public class CmdMassiveCoreStore extends MassiveCoreCommand
|
||||
public CmdMassiveCoreStoreStats cmdMassiveCoreStoreStats = new CmdMassiveCoreStoreStats();
|
||||
public CmdMassiveCoreStoreListcolls cmdMassiveCoreStoreListcolls = new CmdMassiveCoreStoreListcolls();
|
||||
public CmdMassiveCoreStoreCopydb cmdMassiveCoreStoreCopydb = new CmdMassiveCoreStoreCopydb();
|
||||
public CmdMassiveCoreStorePlayerclean cmdMassiveCoreStorePlayerclean = new CmdMassiveCoreStorePlayerclean();
|
||||
|
||||
}
|
||||
|
43
src/com/massivecraft/massivecore/cmd/CmdMassiveCoreStorePlayerclean.java
Executable file
43
src/com/massivecraft/massivecore/cmd/CmdMassiveCoreStorePlayerclean.java
Executable file
@ -0,0 +1,43 @@
|
||||
package com.massivecraft.massivecore.cmd;
|
||||
|
||||
import com.massivecraft.massivecore.MassiveException;
|
||||
import com.massivecraft.massivecore.command.type.container.TypeSet;
|
||||
import com.massivecraft.massivecore.command.type.store.TypeSenderColl;
|
||||
import com.massivecraft.massivecore.store.SenderColl;
|
||||
import com.massivecraft.massivecore.store.inactive.InactiveUtil;
|
||||
import com.massivecraft.massivecore.util.IdUtil;
|
||||
import com.massivecraft.massivecore.util.MUtil;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class CmdMassiveCoreStorePlayerclean extends MassiveCoreCommand
|
||||
{
|
||||
// -------------------------------------------- //
|
||||
// CONSTRUCT
|
||||
// -------------------------------------------- //
|
||||
|
||||
public CmdMassiveCoreStorePlayerclean()
|
||||
{
|
||||
// Parameters
|
||||
this.addParameter(TypeSet.get(TypeSenderColl.get()), "player coll", true).setDesc("the coll to clean inactive players from");
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// OVERRIDE
|
||||
// -------------------------------------------- //
|
||||
|
||||
@Override
|
||||
public void perform() throws MassiveException
|
||||
{
|
||||
Set<SenderColl<?>> colls = this.readArg();
|
||||
|
||||
Set<CommandSender> receivers = MUtil.set(sender, IdUtil.getConsole());
|
||||
|
||||
for (SenderColl<?> coll : colls)
|
||||
{
|
||||
InactiveUtil.considerRemoveInactive(coll, receivers);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.massivecraft.massivecore.command.type.store;
|
||||
|
||||
import com.massivecraft.massivecore.command.type.TypeAbstractChoice;
|
||||
import com.massivecraft.massivecore.store.Coll;
|
||||
import com.massivecraft.massivecore.store.SenderColl;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class TypeSenderColl extends TypeAbstractChoice<SenderColl<?>>
|
||||
{
|
||||
// -------------------------------------------- //
|
||||
// INSTANCE & CONSTRUCT
|
||||
// -------------------------------------------- //
|
||||
|
||||
private static TypeSenderColl i = new TypeSenderColl();
|
||||
public static TypeSenderColl get() { return i; }
|
||||
public TypeSenderColl() { super(Coll.class); }
|
||||
|
||||
// -------------------------------------------- //
|
||||
// OVERRIDE
|
||||
// -------------------------------------------- //
|
||||
|
||||
@Override
|
||||
public Collection<SenderColl<?>> getAll()
|
||||
{
|
||||
return SenderColl.getSenderInstances();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
package com.massivecraft.massivecore.engine;
|
||||
|
||||
import com.massivecraft.massivecore.Engine;
|
||||
import com.massivecraft.massivecore.MassiveCore;
|
||||
import com.massivecraft.massivecore.MassiveCoreMConf;
|
||||
import com.massivecraft.massivecore.event.EventMassiveCorePlayercleanToleranceMillis;
|
||||
import com.massivecraft.massivecore.store.SenderColl;
|
||||
import com.massivecraft.massivecore.store.inactive.InactiveUtil;
|
||||
import com.massivecraft.massivecore.util.IdUtil;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class EngineMassiveCorePlayerclean extends Engine
|
||||
{
|
||||
// -------------------------------------------- //
|
||||
// INSTANCE & CONSTRUCT
|
||||
// -------------------------------------------- //
|
||||
|
||||
private static EngineMassiveCorePlayerclean i = new EngineMassiveCorePlayerclean();
|
||||
public static EngineMassiveCorePlayerclean get() { return i; }
|
||||
public EngineMassiveCorePlayerclean()
|
||||
{
|
||||
// Just check once a minute
|
||||
this.setPeriod(60L * 20L);
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// OVERRIDE: RUNNABLE
|
||||
// -------------------------------------------- //
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
final long now = System.currentTimeMillis();
|
||||
|
||||
// If this is the right server ...
|
||||
if ( ! MassiveCore.isTaskServer()) return;
|
||||
|
||||
// ... and the current invocation ...
|
||||
final long currentInvocation = getInvocationFromMillis(now);
|
||||
|
||||
// ... and the last invocation ...
|
||||
final long lastInvocation = getInvocationFromMillis(MassiveCoreMConf.get().playercleanLastMillis);
|
||||
|
||||
// ... are different ...
|
||||
if (currentInvocation == lastInvocation) return;
|
||||
|
||||
// ... then it's time to invoke.
|
||||
invoke(now);
|
||||
}
|
||||
|
||||
public void invoke(long now)
|
||||
{
|
||||
// Update lastMillis
|
||||
MassiveCoreMConf.get().playercleanLastMillis = now;
|
||||
MassiveCoreMConf.get().changed();
|
||||
|
||||
List<CommandSender> recipients = Collections.<CommandSender>singletonList(IdUtil.getConsole());
|
||||
for (SenderColl<?> coll : SenderColl.getSenderInstances())
|
||||
{
|
||||
if (!coll.isPlayercleanTaskEnabled()) continue;
|
||||
InactiveUtil.considerRemoveInactive(now, coll, recipients);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// TASK MILLIS AND INVOCATION
|
||||
// -------------------------------------------- //
|
||||
// The invocation is the amount of periods from UNIX time to now.
|
||||
// It will increment by one when a period has passed.
|
||||
|
||||
// Remember to check isDisabled first!
|
||||
// Here we accept millis from inside the period by rounding down.
|
||||
private static long getInvocationFromMillis(long millis)
|
||||
{
|
||||
return (millis - MassiveCoreMConf.get().playercleanOffsetMillis) / MassiveCoreMConf.get().playercleanPeriodMillis;
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// DEFAULT
|
||||
// -------------------------------------------- //
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void defaultMillis(EventMassiveCorePlayercleanToleranceMillis event)
|
||||
{
|
||||
event.getToleranceCauseMillis().put("Default", event.getColl().getPlayercleanToleranceMillis());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package com.massivecraft.massivecore.event;
|
||||
|
||||
import com.massivecraft.massivecore.store.SenderColl;
|
||||
import com.massivecraft.massivecore.store.SenderEntity;
|
||||
import com.massivecraft.massivecore.store.inactive.Inactive;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class EventMassiveCorePlayercleanToleranceMillis extends EventMassiveCore
|
||||
{
|
||||
// -------------------------------------------- //
|
||||
// REQUIRED EVENT CODE
|
||||
// -------------------------------------------- //
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
@Override public HandlerList getHandlers() { return handlers; }
|
||||
public static HandlerList getHandlerList() { return handlers; }
|
||||
|
||||
// -------------------------------------------- //
|
||||
// FIELD
|
||||
// -------------------------------------------- //
|
||||
|
||||
private final long now;
|
||||
public long getNow() { return now; }
|
||||
|
||||
private final SenderEntity<?> entity;
|
||||
public SenderEntity<?> getEntity() { return this.entity; }
|
||||
|
||||
public SenderColl<?> getColl() { return entity.getColl(); }
|
||||
|
||||
private final Map<String, Long> toleranceCauseMillis = new LinkedHashMap<>();
|
||||
public Map<String, Long> getToleranceCauseMillis() { return this.toleranceCauseMillis; }
|
||||
|
||||
// -------------------------------------------- //
|
||||
// CONSTRUCT
|
||||
// -------------------------------------------- //
|
||||
|
||||
public EventMassiveCorePlayercleanToleranceMillis(SenderEntity entity)
|
||||
{
|
||||
this(System.currentTimeMillis(), entity);
|
||||
}
|
||||
|
||||
public EventMassiveCorePlayercleanToleranceMillis(long now, SenderEntity entity)
|
||||
{
|
||||
this.now = now;
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// CONVENIENCE
|
||||
// -------------------------------------------- //
|
||||
|
||||
public long getToleranceMillis()
|
||||
{
|
||||
long ret = 0;
|
||||
|
||||
for (Long value : toleranceCauseMillis.values())
|
||||
{
|
||||
ret += value;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public boolean shouldBeRemoved()
|
||||
{
|
||||
long toleranceMillis = getToleranceMillis();
|
||||
|
||||
long now = this.getNow();
|
||||
long lastActivityMillis = ((Inactive)this.getEntity()).getLastActivityMillis();
|
||||
|
||||
long removeTime = lastActivityMillis + toleranceMillis;
|
||||
|
||||
return now >= removeTime;
|
||||
}
|
||||
|
||||
}
|
@ -16,6 +16,13 @@ import java.util.List;
|
||||
|
||||
public class SenderColl<E extends SenderEntity<E>> extends Coll<E> implements SenderIdSource
|
||||
{
|
||||
// This should be false under most circumstances.
|
||||
// In some cases such as Factions we want it though.
|
||||
// Especially so we don't change the years old way Factions does it.
|
||||
private boolean playercleanTaskEnabled = false;
|
||||
public boolean isPlayercleanTaskEnabled() { return this.playercleanTaskEnabled; }
|
||||
public void setPlayercleanTaskEnabled(boolean playercleanTaskEnabled) { this.playercleanTaskEnabled = playercleanTaskEnabled; }
|
||||
|
||||
// -------------------------------------------- //
|
||||
// CONSTRUCT
|
||||
// -------------------------------------------- //
|
||||
@ -194,5 +201,15 @@ public class SenderColl<E extends SenderEntity<E>> extends Coll<E> implements Se
|
||||
senderColl.setSenderReference(senderId, sender);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// ACTIVITY MILLIS
|
||||
// -------------------------------------------- //
|
||||
|
||||
// Must be overriden if they want to use it.
|
||||
public long getPlayercleanToleranceMillis()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,6 @@
|
||||
package com.massivecraft.massivecore.store.inactive;
|
||||
|
||||
public interface Inactive
|
||||
{
|
||||
long getLastActivityMillis();
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package com.massivecraft.massivecore.store.inactive;
|
||||
|
||||
import com.massivecraft.massivecore.event.EventMassiveCorePlayercleanToleranceMillis;
|
||||
import com.massivecraft.massivecore.mixin.MixinMessage;
|
||||
import com.massivecraft.massivecore.store.SenderColl;
|
||||
import com.massivecraft.massivecore.store.SenderEntity;
|
||||
import com.massivecraft.massivecore.util.Txt;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class InactiveUtil
|
||||
{
|
||||
public static void considerRemoveInactive(final SenderColl<? extends SenderEntity<?>> coll, final Iterable<CommandSender> recipients)
|
||||
{
|
||||
considerRemoveInactive(System.currentTimeMillis(), coll, recipients);
|
||||
}
|
||||
|
||||
public static void considerRemoveInactive(long now, final SenderColl<? extends SenderEntity<?>> coll, final Iterable<CommandSender> recipients)
|
||||
{
|
||||
final long playercleanToleranceMillis = coll.getPlayercleanToleranceMillis();
|
||||
if (playercleanToleranceMillis <= 0)
|
||||
{
|
||||
for (CommandSender recipient : recipients)
|
||||
{
|
||||
MixinMessage.get().msgOne(recipient, "<h>%s<b> does not support player cleaning.", coll.getName());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
final long start = System.currentTimeMillis();
|
||||
int count = 0;
|
||||
|
||||
final Collection<? extends SenderEntity<?>> senderEntitiesOffline = coll.getAllOffline();
|
||||
|
||||
// For each offline player ...
|
||||
for (SenderEntity entity : senderEntitiesOffline)
|
||||
{
|
||||
// ... see if they should be removed.
|
||||
boolean result = considerRemoveInactive(now, entity, recipients);
|
||||
if (result) count++;
|
||||
}
|
||||
|
||||
long time = System.currentTimeMillis() - start;
|
||||
for (CommandSender recipient : recipients)
|
||||
{
|
||||
MixinMessage.get().msgOne(recipient, "<i>Removed <h>%d <i>players from <h>%s <i>took <v>%dms<i>.", count, coll.getName(), time);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean considerRemoveInactive(long now, SenderEntity<?> entity, Iterable<CommandSender> recipients)
|
||||
{
|
||||
if ( ! (entity instanceof Inactive)) return false;
|
||||
if (entity.detached()) return false;
|
||||
|
||||
// Consider
|
||||
if (!shouldBeRemoved(now, entity)) return false;
|
||||
|
||||
String message = Txt.parse("<i>Player <h>%s<i> with id %s was removed due to inactivity.", entity.getName(), entity.getId());
|
||||
|
||||
for (CommandSender recipient : recipients)
|
||||
{
|
||||
MixinMessage.get().messageOne(recipient, message);
|
||||
}
|
||||
|
||||
// Apply
|
||||
entity.detach();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean shouldBeRemoved(long now, SenderEntity entity)
|
||||
{
|
||||
EventMassiveCorePlayercleanToleranceMillis event = new EventMassiveCorePlayercleanToleranceMillis(now, entity);
|
||||
event.run();
|
||||
return event.shouldBeRemoved();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user