Ok my bad there, here are the codes.
BotsPreventionManager.java:
package com.l2jmobius.gameserver.model.actor.instance;
import java.io.File;
import java.io.RandomAccessFile;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.Future;
import com.l2jmobius.Config;
import com.l2jmobius.commons.concurrent.ThreadPool;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.commons.util.StringUtil;
import com.l2jmobius.gameserver.datatables.csv.MapRegionTable;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage;
import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
import com.l2jmobius.gameserver.network.serverpackets.PledgeCrest;
public class BotsPreventionManager
{
private class PlayerData
{
public PlayerData()
{
firstWindow = true;
}
public int mainpattern;
public List<Integer> options = new ArrayList<>();
public boolean firstWindow;
public int patternid;
}
protected Random _randomize;
protected static Map<Integer, Integer> _monsterscounter;
protected static Map<Integer, Future<?>> _beginvalidation;
protected static Map<Integer, PlayerData> _validation;
protected static Map<Integer, byte[]> _images;
protected int WINDOW_DELAY = 3; // delay used to generate new window if previous have been closed.
protected int VALIDATION_TIME = Config.VALIDATION_TIME * 1000;
public static final BotsPreventionManager getInstance()
{
return SingletonHolder._instance;
}
BotsPreventionManager()
{
_randomize = new Random();
_monsterscounter = new HashMap<>();
_beginvalidation = new HashMap<>();
_validation = new HashMap<>();
_images = new HashMap<>();
_beginvalidation = new HashMap<>();
getimages();
}
public void updatecounter(L2Character player, L2Character monster)
{
if ((player instanceof L2PcInstance) && (monster instanceof L2MonsterInstance))
{
L2PcInstance killer = (L2PcInstance) player;
if (_validation.get(killer.getObjectId()) != null)
{
return;
}
int count = 1;
if (_monsterscounter.get(killer.getObjectId()) != null)
{
count = _monsterscounter.get(killer.getObjectId()) + 1;
}
int next = _randomize.nextInt(Config.KILLS_COUNTER_RANDOMIZATION);
if ((Config.KILLS_COUNTER + next) < count)
{
validationtasks(killer);
_monsterscounter.remove(killer.getObjectId());
}
else
{
_monsterscounter.put(killer.getObjectId(), count);
}
}
}
private static void getimages()
{
String CRESTS_DIR = "data/html/mods/prevention";
final File directory = new File(CRESTS_DIR);
directory.mkdirs();
int i = 0;
for (File file : directory.listFiles())
{
if (!file.getName().endsWith(".dds"))
{
continue;
}
byte[] data;
try (RandomAccessFile f = new RandomAccessFile(file, "r"))
{
data = new byte[(int) f.length()];
f.readFully(data);
}
catch (Exception e)
{
continue;
}
_images.put(i, data);
i++;
}
}
public void prevalidationwindow(L2PcInstance player)
{
NpcHtmlMessage html = new NpcHtmlMessage(1);
StringBuilder tb = new StringBuilder();
StringUtil.append(tb, "<html>");
StringUtil.append(tb, "<title>~L2Infinity~: Boting prevention</title>");
StringUtil.append(tb, "<body><center><br1><img src=\"L2UI.SquareGray\" width=\"300\" height=\"1\">");
StringUtil.append(tb, "<body><center><br><br><img src=\"L2UI_CH3.herotower_deco\" width=\"256\" height=\"32\">");
StringUtil.append(tb, "<br><br><font color=\"a2a0a2\">When this window appears it means the server <br1>suspects that you might be using cheating software.</font>");
StringUtil.append(tb, "<br><br><font color=\"b09979\">If given answer results are incorrect or no action is made<br1>server is going to punish character instantly.</font>");
StringUtil.append(tb, "<br><br><button value=\"CONTINUE\" action=\"bypass report_continue\" width=\"75\" height=\"21\" back=\"L2UI_CH3.Btn1_normal\" fore=\"L2UI_CH3.Btn1_normal\">");
StringUtil.append(tb, "</center></body>");
StringUtil.append(tb, "</html>");
html.setHtml(tb.toString());
player.sendPacket(html);
}
private static void validationwindow(L2PcInstance player)
{
PlayerData container = _validation.get(player.getObjectId());
NpcHtmlMessage html = new NpcHtmlMessage(1);
StringBuilder tb = new StringBuilder();
StringUtil.append(tb, "<html>");
StringUtil.append(tb, "<title>~L2Infinity~: Boting prevention</title>");
StringUtil.append(tb, "<body><center><br1><img src=\"L2UI.SquareGray\" width=\"300\" height=\"1\">");
StringUtil.append(tb, "<body><center><br><br><img src=\"L2UI_CH3.herotower_deco\" width=\"256\" height=\"32\">");
StringUtil.append(tb, "<br><br><font color=\"a2a0a2\">In order to prove you are a human being<br1>you've to</font> <font color=\"b09979\">match the symbol with the generated patterns:</font>");
// generated main pattern.
StringUtil.append(tb, "<br><br><img src=\"Crest.crest_" + Config.SERVER_ID + "_" + (_validation.get(player.getObjectId()).patternid) + "\" width=\"32\" height=\"32\"></td></tr>");
StringUtil.append(tb, "<br><br><font color=b09979>Select the correct symbol:</font>");
// generate random symbol.
StringUtil.append(tb, "<table><tr>");
for (int i = 0; i < container.options.size(); i++)
{
StringUtil.append(tb, "<td><button action=\"bypass -h report_" + i + "\" width=32 height=32 back=\"Crest.crest_" + Config.SERVER_ID + "_" + (container.options.get(i) + 1500) + "\" fore=\"Crest.crest_" + Config.SERVER_ID + "_" + (container.options.get(i) + 1500) + "\"></td>");
}
StringUtil.append(tb, "</tr></table>");
StringUtil.append(tb, "</center></body>");
StringUtil.append(tb, "</html>");
html.setHtml(tb.toString());
player.sendPacket(html);
}
public void punishmentnwindow(L2PcInstance player)
{
NpcHtmlMessage html = new NpcHtmlMessage(1);
StringBuilder tb = new StringBuilder();
StringUtil.append(tb, "<html>");
StringUtil.append(tb, "<title>~L2Infinity~: Boting prevention</title>");
StringUtil.append(tb, "<body><center><br1><img src=\"L2UI.SquareGray\" width=\"300\" height=\"1\">");
StringUtil.append(tb, "<body><center><br><br><img src=\"L2UI_CH3.herotower_deco\" width=\"256\" height=\"32\">");
StringUtil.append(tb, "<br><br><font color=\"a2a0a2\">If this window appears, it means you haven't<br1>passed the prevention system.");
StringUtil.append(tb, "<br><br><font color=\"b09979\">In this case you get moved to the nearest town.</font>");
StringUtil.append(tb, "</center></body>");
StringUtil.append(tb, "</html>");
html.setHtml(tb.toString());
player.sendPacket(html);
}
public void validationtasks(L2PcInstance player)
{
PlayerData container = new PlayerData();
randomizeimages(container, player);
for (int i = 0; i < container.options.size(); i++)
{
PledgeCrest packet = new PledgeCrest((container.options.get(i) + 1500), _images.get(container.options.get(i)));
player.sendPacket(packet);
}
PledgeCrest packet = new PledgeCrest(container.patternid, _images.get(container.options.get(container.mainpattern)));
player.sendPacket(packet);
_validation.put(player.getObjectId(), container);
Future<?> newTask = ThreadPool.schedule(new ReportCheckTask(player), VALIDATION_TIME);
ThreadPool.schedule(new countdown(player, VALIDATION_TIME / 1000), 0);
_beginvalidation.put(player.getObjectId(), newTask);
}
protected void randomizeimages(PlayerData container, L2PcInstance player)
{
int buttonscount = 4;
int imagescount = _images.size();
for (int i = 0; i < buttonscount; i++)
{
int next = _randomize.nextInt(imagescount);
while (container.options.indexOf(next) > -1)
{
next = _randomize.nextInt(imagescount);
}
container.options.add(next);
}
int mainIndex = _randomize.nextInt(buttonscount);
container.mainpattern = mainIndex;
Calendar token = Calendar.getInstance();
String uniquetoken = Integer.toString(token.get(Calendar.DAY_OF_MONTH)) + Integer.toString(token.get(Calendar.HOUR_OF_DAY)) + Integer.toString(token.get(Calendar.MINUTE)) + Integer.toString(token.get(Calendar.SECOND)) + Integer.toString(token.get(Calendar.MILLISECOND) / 100);
container.patternid = Integer.parseInt(uniquetoken);
}
protected void banpunishment(L2PcInstance player)
{
_validation.remove(player.getObjectId());
_beginvalidation.get(player.getObjectId()).cancel(true);
_beginvalidation.remove(player.getObjectId());
switch (Config.PUNISHMENT)
{
// 0 = move character to the closest village.
// 1 = kick characters from the server.
// 2 = put character to jail.
// 3 = ban character from the server.
case 0:
player.stopMove(null);
player.teleToLocation(MapRegionTable.TeleportWhereType.Town);
punishmentnwindow(player);
break;
case 1:
if (player.isOnline() == 1)
{
player.logout(true);
}
break;
case 2:
jailpunishment(player, Config.PUNISHMENT_TIME * 60);
break;
case 3:
// player.setAccessLevel(-100);
changeaccesslevel(player, -100);
break;
}
// player.sendMessage("Unfortunately, symbols didn't match.");
ExShowScreenMessage welcomemessage = new ExShowScreenMessage("Unfortunately, symbols didn't match.", 3000); // 10000 = 10 seconds
player.sendPacket(welcomemessage);
}
private static void changeaccesslevel(L2PcInstance targetPlayer, int lvl)
{
if (targetPlayer.isOnline() == 1)
{
targetPlayer.setAccessLevel(lvl);
targetPlayer.logout();
}
else
{
try (Connection con = DatabaseFactory.getConnection())
{
PreparedStatement statement = con.prepareStatement("UPDATE characters SET accesslevel=? WHERE obj_id=?");
statement.setInt(1, lvl);
statement.setInt(2, targetPlayer.getObjectId());
statement.execute();
statement.close();
}
catch (SQLException se)
{
if (Config.DEBUG)
{
se.printStackTrace();
}
}
}
}
private static void jailpunishment(L2PcInstance activeChar, int delay)
{
if (activeChar.isOnline() == 1)
{
activeChar.setPunishLevel(L2PcInstance.PunishLevel.JAIL, Config.PUNISHMENT_TIME);
}
else
{
try (Connection con = DatabaseFactory.getConnection())
{
PreparedStatement statement = con.prepareStatement("UPDATE characters SET x=?, y=?, z=?, punish_level=?, punish_timer=? WHERE obj_id=?");
statement.setInt(1, -114356);
statement.setInt(2, -249645);
statement.setInt(3, -2984);
statement.setInt(4, L2PcInstance.PunishLevel.JAIL.value());
statement.setLong(5, (delay > 0 ? delay * Config.PUNISHMENT_TIME * 100 : 0));
statement.setInt(6, activeChar.getObjectId());
statement.execute();
statement.close();
}
catch (SQLException se)
{
activeChar.sendMessage("SQLException while jailing player");
if (Config.DEBUG)
{
se.printStackTrace();
}
}
}
}
public void AnalyseBypass(String command, L2PcInstance player)
{
if (!_validation.containsKey(player.getObjectId()))
{
return;
}
String params = command.substring(command.indexOf("_") + 1);
if (params.startsWith("continue"))
{
validationwindow(player);
_validation.get(player.getObjectId()).firstWindow = false;
return;
}
int choosenoption = -1;
if (tryParseInt(params))
{
choosenoption = Integer.parseInt(params);
}
if (choosenoption > -1)
{
PlayerData playerData = _validation.get(player.getObjectId());
if (choosenoption != playerData.mainpattern)
{
banpunishment(player);
}
else
{
// player.sendMessage("Congratulations, the symbol is a match!");
ExShowScreenMessage welcomemessage = new ExShowScreenMessage("Congratulations, the symbol is a match!", 3000); // 10000 = 10 seconds
player.sendPacket(welcomemessage);
_validation.remove(player.getObjectId());
_beginvalidation.get(player.getObjectId()).cancel(true);
_beginvalidation.remove(player.getObjectId());
}
}
}
protected class countdown implements Runnable
{
private final L2PcInstance _player;
private final int _time;
public countdown(L2PcInstance player, int time)
{
_time = time;
_player = player;
}
@Override
public void run()
{
if (_player.isOnline() == 1)
{
if (_validation.containsKey(_player.getObjectId()) && _validation.get(_player.getObjectId()).firstWindow)
{
if ((_time % WINDOW_DELAY) == 0)
{
prevalidationwindow(_player);
}
}
switch (_time)
{
case 300:
case 240:
case 180:
case 120:
case 60:
// _player.sendMessage((_time / 60) + " minute(s) to match the symbols.");
ExShowScreenMessage welcomemessage = new ExShowScreenMessage((_time / 60) + " minute(s) to match the symbols.", 3000); // 10000 = 10 seconds
_player.sendPacket(welcomemessage);
break;
case 30:
case 10:
case 5:
case 4:
case 3:
case 2:
case 1:
// _player.sendMessage(_time + " second(s) to match the symbols!");
ExShowScreenMessage welcomemessage2 = new ExShowScreenMessage(_time + " second(s) to match the symbols!", 3000); // 10000 = 10 seconds
_player.sendPacket(welcomemessage2);
break;
}
if ((_time > 1) && _validation.containsKey(_player.getObjectId()))
{
ThreadPool.schedule(new countdown(_player, _time - 1), 1000);
}
}
}
}
protected boolean tryParseInt(String value)
{
try
{
Integer.parseInt(value);
return true;
}
catch (NumberFormatException e)
{
return false;
}
}
public void CaptchaSuccessfull(L2PcInstance player)
{
if (_validation.get(player.getObjectId()) != null)
{
_validation.remove(player.getObjectId());
}
}
public Boolean IsAlredyInReportMode(L2PcInstance player)
{
if (_validation.get(player.getObjectId()) != null)
{
return true;
}
return false;
}
private class ReportCheckTask implements Runnable
{
private final L2PcInstance _player;
public ReportCheckTask(L2PcInstance player)
{
_player = player;
}
@Override
public void run()
{
if (_validation.get(_player.getObjectId()) != null)
{
banpunishment(_player);
}
}
}
private static class SingletonHolder
{
protected static final BotsPreventionManager _instance = new BotsPreventionManager();
}
}
PledgeCrest.Java:
/*
* This file is part of the L2J Mobius project.
*
* 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 com.l2jmobius.gameserver.network.serverpackets;
import com.l2jmobius.gameserver.cache.CrestCache;
/**
* sample 0000: 84 6d 06 00 00 36 05 00 00 42 4d 36 05 00 00 00 .m...6...BM6.... 0010: 00 00 00 36 04 00 00 28 00 00 00 10 00 00 00 10 ...6...(........ 0020: 00 00 00 01 00 08 00 00 00 00 00 00 01 00 00 c4 ................ 0030: ... 0530: 10 91 00 00 00 60 9b d1 01 e4 6e ee 52 97 dd .....`....n.R..
* format dd x...x
* @version $Revision: 1.3.2.1.2.4 $ $Date: 2005/03/27 15:29:57 $
*/
public final class PledgeCrest extends L2GameServerPacket
{
private final int _crestId;
private final byte[] _data;
public PledgeCrest(int crestId)
{
_crestId = crestId;
_data = CrestCache.getInstance().getPledgeCrest(_crestId);
}
public PledgeCrest(int crestId, byte[] data)
{
_crestId = crestId;
_data = data;
}
@Override
protected final void writeImpl()
{
writeC(0x6c);
writeD(_crestId);
if (_data != null)
{
writeD(_data.length);
writeB(_data);
}
else
{
writeD(0);
}
}
}
From Config.java:
public static boolean BOTS_PREVENTION;
public static int KILLS_COUNTER;
public static int KILLS_COUNTER_RANDOMIZATION;
public static int VALIDATION_TIME;
public static int PUNISHMENT;
public static int PUNISHMENT_TIME;
BOTS_PREVENTION = Boolean.parseBoolean(POtherSetting.getProperty("EnableBotsPrevention", "false"));
KILLS_COUNTER = Integer.parseInt(POtherSetting.getProperty("KillsCounter", "60"));
KILLS_COUNTER_RANDOMIZATION = Integer.parseInt(POtherSetting.getProperty("KillsCounterRandomization", "50"));
VALIDATION_TIME = Integer.parseInt(POtherSetting.getProperty("ValidationTime", "60"));
PUNISHMENT = Integer.parseInt(POtherSetting.getProperty("Punishment", "0"));
PUNISHMENT_TIME = Integer.parseInt(POtherSetting.getProperty("PunishmentTime", "60"));
And from L2Character:
// if killer is the same then the most damager/hated
L2Character mostHated = null;
if (this instanceof L2Attackable)
{
mostHated = ((L2Attackable) this)._mostHated;
}
if ((mostHated != null) && isInsideRadius(mostHated, 200, false, false))
{
calculateRewards(mostHated);
}
else
{
calculateRewards(killer);
if (Config.BOTS_PREVENTION)
{
BotsPreventionManager.getInstance().updatecounter(killer, this);
}
}
The system activates only if i use ranged attacks. If i use melee attacks, it wont activate.