NoCheatPlus/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/chat/Commands.java

111 lines
4.3 KiB
Java

/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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.players.IPlayerData;
import fr.neatmonster.nocheatplus.utilities.ColorUtil;
import fr.neatmonster.nocheatplus.utilities.TickTask;
/**
* Check only for commands
* @author mc_dev
*
*/
public class Commands extends Check {
public Commands() {
super(CheckType.CHAT_COMMANDS);
}
public boolean check(final Player player, final String message,
final ChatConfig cc, final IPlayerData pData,
final ICaptcha captcha) {
final long now = System.currentTimeMillis();
final int tick = TickTask.getTick();
final ChatData data = pData.getGenericInstance(ChatData.class);
final boolean captchaEnabled = !cc.captchaSkipCommands
&& pData.isCheckActive(CheckType.CHAT_CAPTCHA, player);
if (captchaEnabled){
synchronized (data) {
if (captcha.shouldCheckCaptcha(player, cc, data, pData)){
captcha.checkCaptcha(player, message, cc, data, true);
return true;
}
}
}
// Rest of the check is done without sync, because the data is only used by this check.
// Weight might later be read from some prefix tree (also known / unknown).
final float weight = 1f;
data.commandsWeights.add(now, weight);
if (tick < data.commandsShortTermTick){
// TickTask got reset.
data.commandsShortTermTick = tick;
data.commandsShortTermWeight = 1.0;
}
else if (tick - data.commandsShortTermTick < cc.commandsShortTermTicks){
if (!pData.getCurrentWorldData().shouldAdjustToLag(type)
|| TickTask.getLag(50L * (tick - data.commandsShortTermTick), true) < 1.3f){
// Add up.
data.commandsShortTermWeight += weight;
}
else{
// Reset, too much lag.
data.commandsShortTermTick = tick;
data.commandsShortTermWeight = 1.0;
}
}
else{
// Reset.
data.commandsShortTermTick = tick;
data.commandsShortTermWeight = 1.0;
}
final float nw = data.commandsWeights.score(1f);
final double violation = Math.max(nw - cc.commandsLevel, data.commandsShortTermWeight - cc.commandsShortTermLevel);
if (violation > 0.0){
data.commandsVL += violation;
// TODO: Evaluate if sync(data) is necessary or better for executeActions.
if (captchaEnabled){
synchronized (data) {
captcha.sendNewCaptcha(player, cc, data);
}
return true;
}
else if (executeActions(player, data.commandsVL, violation, cc.commandsActions).willCancel())
return true;
}
else if (cc.chatWarningCheck && now - data.chatWarningTime > cc.chatWarningTimeout && (100f * nw / cc.commandsLevel > cc.chatWarningLevel || 100f * data.commandsShortTermWeight / cc.commandsShortTermLevel > cc.chatWarningLevel)){
player.sendMessage(ColorUtil.replaceColors(cc.chatWarningMessage));
data.chatWarningTime = now;
}
else{
// TODO: This might need invalidation with time.
data.commandsVL *= 0.99;
}
return false;
}
}