Bleeding: Split off Relog check from nopwnage.

This commit is contained in:
asofold 2012-10-01 09:56:49 +02:00
parent 0574530c45
commit b34aec55b4
9 changed files with 164 additions and 112 deletions

View File

@ -79,6 +79,8 @@ public class ChatConfig extends AsyncCheckConfig {
public final boolean colorCheck;
public final ActionList colorActions;
private final boolean commandsCheck;
public final boolean globalChatCheck;
public final boolean globalChatGlobalCheck;
public final boolean globalChatPlayerCheck;
@ -91,6 +93,8 @@ public class ChatConfig extends AsyncCheckConfig {
public boolean globalChatEngineMaximum;
public final boolean globalChatDebug;
public final ActionList globalChatActions;
private final boolean loginsCheck;
public final boolean noPwnageCheck;
public final boolean noPwnageDebug;
@ -113,13 +117,6 @@ public class ChatConfig extends AsyncCheckConfig {
public final long noPwnageMoveTimeout;
public final int noPwnageMoveWeight;
public final boolean noPwnageReloginCheck;
public final String noPwnageReloginKickMessage;
public final long noPwnageReloginTimeout;
public final String noPwnageReloginWarningMessage;
public final int noPwnageReloginWarningNumber;
public final long noPwnageReloginWarningTimeout;
public final boolean noPwnageRepeatCheck;
public final long noPwnageRepeatTimeout;
public final int noPwnageRepeatWeight;
@ -141,6 +138,15 @@ public class ChatConfig extends AsyncCheckConfig {
public final boolean protectPlugins;
public final boolean relogCheck;
public final String relogKickMessage;
public final long relogTimeout;
public final String relogWarningMessage;
public final int relogWarningNumber;
public final long relogWarningTimeout;
public ActionList relogActions;
/**
* Instantiates a new chat configuration.
*
@ -166,6 +172,8 @@ public class ChatConfig extends AsyncCheckConfig {
colorCheck = config.getBoolean(ConfPaths.CHAT_COLOR_CHECK);
colorActions = config.getActionList(ConfPaths.CHAT_COLOR_ACTIONS, Permissions.CHAT_COLOR);
commandsCheck = config.getBoolean(ConfPaths.CHAT_COMMANDS_CHECK);
globalChatCheck = config.getBoolean(ConfPaths.CHAT_GLOBALCHAT_CHECK);
globalChatGlobalCheck = config.getBoolean(ConfPaths.CHAT_GLOBALCHAT_GL_CHECK, true);
globalChatPlayerCheck = config.getBoolean(ConfPaths.CHAT_GLOBALCHAT_PP_CHECK, true);
@ -178,6 +186,8 @@ public class ChatConfig extends AsyncCheckConfig {
globalChatEngineMaximum = config.getBoolean(ConfPaths.CHAT_GLOBALCHAT_ENGINE_MAXIMUM, true);
globalChatDebug = config.getBoolean(ConfPaths.CHAT_GLOBALCHAT_DEBUG, false);
globalChatActions = config.getActionList(ConfPaths.CHAT_GLOBALCHAT_ACTIONS, Permissions.CHAT_GLOBALCHAT);
loginsCheck = config.getBoolean(ConfPaths.CHAT_LOGINS_CHECK);
noPwnageCheck = config.getBoolean(ConfPaths.CHAT_NOPWNAGE_CHECK);
noPwnageDebug = config.getBoolean(ConfPaths.CHAT_NOPWNAGE_DEBUG, false);
@ -201,13 +211,6 @@ public class ChatConfig extends AsyncCheckConfig {
noPwnageMoveTimeout = config.getLong(ConfPaths.CHAT_NOPWNAGE_MOVE_TIMEOUT);
noPwnageMoveWeight = config.getInt(ConfPaths.CHAT_NOPWNAGE_MOVE_WEIGHT);
noPwnageReloginCheck = config.getBoolean(ConfPaths.CHAT_NOPWNAGE_RELOGIN_CHECK);
noPwnageReloginKickMessage = config.getString(ConfPaths.CHAT_NOPWNAGE_RELOGIN_KICKMESSAGE);
noPwnageReloginTimeout = config.getLong(ConfPaths.CHAT_NOPWNAGE_RELOGIN_TIMEOUT);
noPwnageReloginWarningMessage = config.getString(ConfPaths.CHAT_NOPWNAGE_RELOGIN_WARNING_MESSAGE);
noPwnageReloginWarningNumber = config.getInt(ConfPaths.CHAT_NOPWNAGE_RELOGIN_WARNING_NUMBER);
noPwnageReloginWarningTimeout = config.getLong(ConfPaths.CHAT_NOPWNAGE_RELOGIN_WARNING_TIMEOUT);
noPwnageRepeatCheck = config.getBoolean(ConfPaths.CHAT_NOPWNAGE_REPEAT_CHECK);
noPwnageRepeatTimeout = config.getLong(ConfPaths.CHAT_NOPWNAGE_REPEAT_TIMEOUT);
noPwnageRepeatWeight = config.getInt(ConfPaths.CHAT_NOPWNAGE_REPEAT_WEIGHT);
@ -224,6 +227,14 @@ public class ChatConfig extends AsyncCheckConfig {
noPwnageWarnPlayerMessage = config.getString(ConfPaths.CHAT_NOPWNAGE_WARN_PLAYER_MESSAGE);
noPwnageActions = config.getActionList(ConfPaths.CHAT_NOPWNAGE_ACTIONS, Permissions.CHAT_NOPWNAGE);
relogCheck = config.getBoolean(ConfPaths.CHAT_RELOG_CHECK);
relogKickMessage = config.getString(ConfPaths.CHAT_RELOG_KICKMESSAGE);
relogTimeout = config.getLong(ConfPaths.CHAT_RELOG_TIMEOUT);
relogWarningMessage = config.getString(ConfPaths.CHAT_RELOG_WARNING_MESSAGE);
relogWarningNumber = config.getInt(ConfPaths.CHAT_RELOG_WARNING_NUMBER);
relogWarningTimeout = config.getLong(ConfPaths.CHAT_RELOG_WARNING_TIMEOUT);
relogActions = config.getActionList(ConfPaths.CHAT_RELOG_ACTIONS, Permissions.CHAT_RELOG);
opInConsoleOnly = config.getBoolean(ConfPaths.MISCELLANEOUS_OPINCONSOLEONLY);
@ -242,6 +253,14 @@ public class ChatConfig extends AsyncCheckConfig {
return globalChatCheck;
case CHAT_NOPWNAGE:
return noPwnageCheck;
case CHAT_COMMANDS:
return commandsCheck;
case CHAT_CAPTCHA:
return captchaCheck;
case CHAT_RELOG:
return relogCheck;
case CHAT_LOGINS:
return loginsCheck;
default:
return true;
}

View File

@ -71,6 +71,7 @@ public class ChatData extends AsyncCheckData {
public double colorVL;
public double globalChatVL;
public double noPwnageVL;
public double relogVL;
// Captcha data.
public int captchTries;
@ -80,30 +81,30 @@ public class ChatData extends AsyncCheckData {
// Data of the globalchat check.
public final ActionFrequency globalChatFrequency = new ActionFrequency(10, 3000);
// Data of the no pwnage check.
public long noPwnageJoinTime;
// Data of the no pwnage check.
public String noPwnageLastMessage;
public long noPwnageLastMessageTime;
public long noPwnageLastWarningTime;
public long noPwnageLeaveTime;
public int noPwnageReloginWarnings;
public long noPwnageReloginWarningTime;
public final ActionFrequency noPwnageSpeed = new ActionFrequency(5, 1000);
public int relogWarnings;
public long relogWarningTime;
/**
* Clear the data of the no pwnage check.
*/
public synchronized void clearNoPwnageData() {
captchTries = noPwnageReloginWarnings = 0;
captchTries = relogWarnings = 0;
captchaVL = 0D;
// colorVL <- is spared to avoid problems with spam + captcha success.
noPwnageVL = 0;
noPwnageSpeed.clear(System.currentTimeMillis());
noPwnageJoinTime = noPwnageLastMessageTime = noPwnageLastWarningTime = noPwnageLeaveTime = noPwnageReloginWarningTime = 0L;
noPwnageLastMessageTime = noPwnageLastWarningTime = relogWarningTime = 0L;
captchaGenerated = noPwnageLastMessage = "";
}

View File

@ -53,6 +53,8 @@ public class ChatListener implements Listener, INotifyReload {
private final SimpleCharPrefixTree chatCommands = new SimpleCharPrefixTree();
private final Relog relog = new Relog();
public ChatListener(){
ConfigFile config = ConfigManager.getConfigFile();
initFilters(config);
@ -202,8 +204,8 @@ public class ChatListener implements Listener, INotifyReload {
captcha.resetCaptcha(player);
// Execute the no pwnage check.
if (noPwnage.isEnabled(player) && noPwnage.checkLogin(player))
event.disallow(Result.KICK_OTHER, cc.noPwnageReloginKickMessage);
if (relog.isEnabled(player) && relog.checkLogin(player))
event.disallow(Result.KICK_OTHER, cc.relogKickMessage);
}
@EventHandler(

View File

@ -70,27 +70,6 @@ public class NoPwnage extends AsyncCheck{
}
}
/**
* Checks a player (join).
*
* Only called from the main thread.
*
* @param player
* the player
* @return true, if successful
*/
public boolean checkLogin(final Player player) {
if (!isEnabled(player))
return false;
final ChatConfig cc = ChatConfig.getConfig(player);
final ChatData data = ChatData.getData(player);
// Keep related to ChatData/NoPwnage/Color used lock.
synchronized (data) {
return unsafeLoginCheck(player, cc, data);
}
}
/**
* Only to be called form synchronized code.
@ -119,6 +98,8 @@ public class NoPwnage extends AsyncCheck{
// Cancel the event.
return true;
}
CombinedData cData = CombinedData.getData(player);
int suspicion = 0;
// NoPwnage will remember the last message that caused someone to get banned. If a player repeats that
@ -129,7 +110,7 @@ public class NoPwnage extends AsyncCheck{
// NoPwnage will check if a player sends his first message within "timeout" milliseconds after his login. If
// he does, increase suspicion by "weight".
if (cc.noPwnageFirstCheck && now - data.noPwnageJoinTime < cc.noPwnageFirstTimeout)
if (cc.noPwnageFirstCheck && now - cData.lastJoinTime < cc.noPwnageFirstTimeout)
suspicion += cc.noPwnageFirstWeight;
// NoPwnage will check if a player repeats a message that has been sent by another player just before,
@ -159,7 +140,7 @@ public class NoPwnage extends AsyncCheck{
// NoPwnage will check if a player moved within the "timeout" timeframe. If he did not move, the suspicion will
// be increased by "weight" value.
if (!isCommand && cc.noPwnageMoveCheck && now - CombinedData.getData(player).lastMoveTime > cc.noPwnageMoveTimeout)
if (!isCommand && cc.noPwnageMoveCheck && now - cData.lastMoveTime > cc.noPwnageMoveTimeout)
suspicion += cc.noPwnageMoveWeight;
// Should a player that reaches the "warnLevel" get a text message telling him that he is under suspicion of
@ -211,42 +192,7 @@ public class NoPwnage extends AsyncCheck{
/**
* Check (Join), only call from synchronized code.
*
* @param player
* the player
* @param cc
* the cc
* @param data
* the data
* @return true, if successful
*/
private boolean unsafeLoginCheck(final Player player, final ChatConfig cc, final ChatData data) {
boolean cancel = false;
final long now = System.currentTimeMillis();
// NoPwnage will remember the time when a player leaves the server. If he returns within "time" milliseconds, he
// will get warned. If he has been warned "warnings" times already, the "commands" will be executed for him.
// Warnings get removed if the time of the last warning was more than "timeout" milliseconds ago.
if (cc.noPwnageReloginCheck && now - data.noPwnageLeaveTime < cc.noPwnageReloginTimeout) {
if (now - data.noPwnageReloginWarningTime > cc.noPwnageReloginWarningTimeout)
data.noPwnageReloginWarnings = 0;
if (data.noPwnageReloginWarnings < cc.noPwnageReloginWarningNumber) {
player.sendMessage(CheckUtils.replaceColors(cc.noPwnageReloginWarningMessage));
data.noPwnageReloginWarningTime = now;
data.noPwnageReloginWarnings++;
} else if (now - data.noPwnageReloginWarningTime < cc.noPwnageReloginWarningTimeout)
// Find out if we need to ban the player or not.
cancel = executeActions(player, (double) data.noPwnageVL, 0D, cc.noPwnageActions, true);
}
// Store his joining time.
data.noPwnageJoinTime = now;
return cancel;
}
@Override
protected Map<ParameterName, String> getParameterMap(final ViolationData violationData) {

View File

@ -1,12 +1,78 @@
package fr.neatmonster.nocheatplus.checks.chat;
import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.checks.Check;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.combined.CombinedData;
import fr.neatmonster.nocheatplus.utilities.CheckUtils;
public class Relog extends Check {
public Relog() {
super(CheckType.CHAT_RELOG);
}
/**
* Checks a player (join).
*
* Only called from the main thread.
*
* @param player
* the player
* @return true, if successful
*/
public boolean checkLogin(final Player player) {
if (!isEnabled(player))
return false;
final ChatConfig cc = ChatConfig.getConfig(player);
final ChatData data = ChatData.getData(player);
// Keep related to ChatData/NoPwnage/Color used lock.
synchronized (data) {
return unsafeLoginCheck(player, cc, data);
}
}
/**
* Check (Join), only call from synchronized code.
*
* @param player
* the player
* @param cc
* the cc
* @param data
* the data
* @return true, if successful
*/
private boolean unsafeLoginCheck(final Player player, final ChatConfig cc, final ChatData data) {
boolean cancel = false;
final long now = System.currentTimeMillis();
final CombinedData cData = CombinedData.getData(player);
// NoPwnage will remember the time when a player leaves the server. If he returns within "time" milliseconds, he
// will get warned. If he has been warned "warnings" times already, the "commands" will be executed for him.
// Warnings get removed if the time of the last warning was more than "timeout" milliseconds ago.
if (now - cData.lastLogoutTime < cc.relogTimeout) {
if (now - data.relogWarningTime > cc.relogWarningTimeout)
data.relogWarnings = 0;
if (data.relogWarnings < cc.relogWarningNumber) {
player.sendMessage(CheckUtils.replaceColors(cc.relogWarningMessage));
data.relogWarningTime = now;
data.relogWarnings++;
} else{
// Find out if we need to ban the player or not.
data.relogVL += 1D;
cancel = executeActions(player, (double) data.relogVL, 1D, cc.relogActions, true);
}
}
// TODO: decrease relog vl ?
return cancel;
}
}

View File

@ -51,7 +51,6 @@ public class CombinedData extends ACheckData {
}
public double improbableVL = 0;
public double speedVL = 0;
public float lastYaw;
public long lastYawTime;
@ -63,6 +62,10 @@ public class CombinedData extends ACheckData {
public String lastWorld = "";
public long lastJoinTime;
public long lastLogoutTime;
public long lastMoveTime;
public CombinedData(final Player player){

View File

@ -193,6 +193,9 @@ public abstract class ConfPaths {
public static final String CHAT_COLOR_CHECK = CHAT_COLOR + "active";
public static final String CHAT_COLOR_ACTIONS = CHAT_COLOR + "actions";
private static final String CHAT_COMMANDS = CHAT + "commands.";
public static final String CHAT_COMMANDS_CHECK = CHAT_COMMANDS + "active";
// globalchat
private static final String CHAT_GLOBALCHAT = CHAT + "globalchat.";
public static final String CHAT_GLOBALCHAT_CHECK = CHAT_GLOBALCHAT + "active";
@ -230,8 +233,11 @@ public abstract class ConfPaths {
public static final String CHAT_GLOBALCHAT_PP_SIMILARITY = CHAT_GLOBALCHAT_PP + "similarity.";
public static final String CHAT_GLOBALCHAT_PP_SIMILARITY_CHECK = CHAT_GLOBALCHAT_PP_SIMILARITY + "active";
// globalchat actions
public static final String CHAT_GLOBALCHAT_ACTIONS = CHAT_GLOBALCHAT + "actions";
public static final String CHAT_GLOBALCHAT_ACTIONS = CHAT_GLOBALCHAT + "actions";
private static final String CHAT_LOGINS = CHAT + "logins.";
public static final String CHAT_LOGINS_CHECK = CHAT_LOGINS + "active";
// nopwnage
private static final String CHAT_NOPWNAGE = CHAT + "nopwnage.";
public static final String CHAT_NOPWNAGE_CHECK = CHAT_NOPWNAGE + "active";
@ -260,16 +266,6 @@ public abstract class ConfPaths {
public static final String CHAT_NOPWNAGE_MOVE_TIMEOUT = CHAT_NOPWNAGE_MOVE + "timeout";
public static final String CHAT_NOPWNAGE_MOVE_WEIGHT = CHAT_NOPWNAGE_MOVE + "weight";
private static final String CHAT_NOPWNAGE_RELOGIN = CHAT_NOPWNAGE + "relogin.";
public static final String CHAT_NOPWNAGE_RELOGIN_CHECK = CHAT_NOPWNAGE_RELOGIN + "active";
public static final String CHAT_NOPWNAGE_RELOGIN_KICKMESSAGE = CHAT_NOPWNAGE_RELOGIN + "kickmessage";
public static final String CHAT_NOPWNAGE_RELOGIN_TIMEOUT = CHAT_NOPWNAGE_RELOGIN + "timeout";
private static final String CHAT_NOPWNAGE_RELOGIN_WARNING = CHAT_NOPWNAGE_RELOGIN + "warning.";
public static final String CHAT_NOPWNAGE_RELOGIN_WARNING_MESSAGE = CHAT_NOPWNAGE_RELOGIN_WARNING + "message";
public static final String CHAT_NOPWNAGE_RELOGIN_WARNING_NUMBER = CHAT_NOPWNAGE_RELOGIN_WARNING + "number";
public static final String CHAT_NOPWNAGE_RELOGIN_WARNING_TIMEOUT = CHAT_NOPWNAGE_RELOGIN_WARNING + "timeout";
private static final String CHAT_NOPWNAGE_REPEAT = CHAT_NOPWNAGE + "repeat.";
public static final String CHAT_NOPWNAGE_REPEAT_CHECK = CHAT_NOPWNAGE_REPEAT + "active";
public static final String CHAT_NOPWNAGE_REPEAT_TIMEOUT = CHAT_NOPWNAGE_REPEAT + "timeout";
@ -296,6 +292,16 @@ public abstract class ConfPaths {
public static final String CHAT_NOPWNAGE_WARN_PLAYER_MESSAGE = CHAT_NOPWNAGE_WARN_PLAYER + "message";
public static final String CHAT_NOPWNAGE_ACTIONS = CHAT_NOPWNAGE + "actions";
private static final String CHAT_RELOG = CHAT + "relog.";
public static final String CHAT_RELOG_CHECK = CHAT_RELOG + "active";
public static final String CHAT_RELOG_KICKMESSAGE = CHAT_RELOG + "kickmessage";
public static final String CHAT_RELOG_TIMEOUT = CHAT_RELOG + "timeout";
private static final String CHAT_RELOG_WARNING = CHAT_RELOG + "warning.";
public static final String CHAT_RELOG_WARNING_MESSAGE = CHAT_RELOG_WARNING + "message";
public static final String CHAT_RELOG_WARNING_NUMBER = CHAT_RELOG_WARNING + "number";
public static final String CHAT_RELOG_WARNING_TIMEOUT = CHAT_RELOG_WARNING + "timeout";
public static final String CHAT_RELOG_ACTIONS = CHAT_RELOG + "actions";
/*
* Combined !

View File

@ -200,15 +200,6 @@ public class DefaultConfig extends ConfigFile {
set(ConfPaths.CHAT_NOPWNAGE_MOVE_TIMEOUT, 30000L);
set(ConfPaths.CHAT_NOPWNAGE_MOVE_WEIGHT, 200);
set(ConfPaths.CHAT_NOPWNAGE_RELOGIN_CHECK, true);
set(ConfPaths.CHAT_NOPWNAGE_RELOGIN_TIMEOUT, 1500L);
set(ConfPaths.CHAT_NOPWNAGE_RELOGIN_WARNING_MESSAGE,
"&cYou relogged really fast! If you keep doing that, you're going to be banned.");
set(ConfPaths.CHAT_NOPWNAGE_RELOGIN_WARNING_NUMBER, 1);
set(ConfPaths.CHAT_NOPWNAGE_RELOGIN_KICKMESSAGE, "You've relogged too fast, joining cancelled!");
set(ConfPaths.CHAT_NOPWNAGE_RELOGIN_WARNING_TIMEOUT, 60000L);
set(ConfPaths.CHAT_NOPWNAGE_REPEAT_CHECK, true);
set(ConfPaths.CHAT_NOPWNAGE_REPEAT_TIMEOUT, 5000L);
set(ConfPaths.CHAT_NOPWNAGE_REPEAT_WEIGHT, 150);
@ -229,6 +220,14 @@ public class DefaultConfig extends ConfigFile {
set(ConfPaths.CHAT_NOPWNAGE_ACTIONS, "cancel log:nopwnage:0:5:cf cmd:kicknopwnage vl>150 cancel log:nopwnage:0:5:cf cmd:tempkick5");
// Reload
set(ConfPaths.CHAT_RELOG_CHECK, true);
set(ConfPaths.CHAT_RELOG_TIMEOUT, 1500L);
set(ConfPaths.CHAT_RELOG_WARNING_MESSAGE, "&cYou relogged really fast! If you keep doing that, you're going to be banned.");
set(ConfPaths.CHAT_RELOG_WARNING_NUMBER, 1);
set(ConfPaths.CHAT_RELOG_KICKMESSAGE, "You've relogged too fast, joining cancelled!");
set(ConfPaths.CHAT_RELOG_WARNING_TIMEOUT, 60000L);
set(ConfPaths.CHAT_RELOG_ACTIONS, "log:relog:0:10 cancel vl>20 log:relog:0:10 cancel tempkick5");
/*
* Combined !
@ -414,6 +413,7 @@ public class DefaultConfig extends ConfigFile {
set(ConfPaths.STRINGS + ".nopwnage", start + "acted like spamming (IP: [ip])" + end);
set(ConfPaths.STRINGS + ".noswing", start + "didn't swing arm" + end);
set(ConfPaths.STRINGS + ".passable", start + "moved into a block ([blockid])" + end);
set(ConfPaths.STRINGS + ".relog", start + "relogs too fast" + end);
set(ConfPaths.STRINGS + ".tellglchat", tell + "&cNCP: &eChat can by annoying at times...");
set(ConfPaths.STRINGS + ".tempkick1", "ncp tempkick [player] 1 Wait a minute!");
set(ConfPaths.STRINGS + ".tempkick5", "ncp tempkick [player] 5 You have five minutes to think about it!");

View File

@ -9,6 +9,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
@ -19,6 +20,7 @@ import org.bukkit.event.player.PlayerQuitEvent;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.ViolationHistory;
import fr.neatmonster.nocheatplus.checks.access.CheckDataFactory;
import fr.neatmonster.nocheatplus.checks.combined.CombinedData;
import fr.neatmonster.nocheatplus.command.INotifyReload;
import fr.neatmonster.nocheatplus.config.ConfPaths;
import fr.neatmonster.nocheatplus.config.ConfigFile;
@ -83,19 +85,26 @@ public class DataManager implements Listener, INotifyReload, INeedConfig{
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerJoin(final PlayerJoinEvent event){
lastLogout.remove(event.getPlayer().getName());
final Player player = event.getPlayer();
lastLogout.remove(player.getName());
CombinedData.getData(player).lastJoinTime = System.currentTimeMillis();
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerQuit(final PlayerQuitEvent event){
lastLogout.put(event.getPlayer().getName(), System.currentTimeMillis());
onLeave(event.getPlayer());
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerKick(final PlayerKickEvent event){
lastLogout.put(event.getPlayer().getName(), System.currentTimeMillis());
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerKick(final PlayerKickEvent event){
onLeave(event.getPlayer());
}
private final void onLeave(final Player player) {
final long now = System.currentTimeMillis();
lastLogout.put(player.getName(), now);
CombinedData.getData(player).lastLogoutTime = now;
}
@Override
public void onReload() {