Bot Prevention

Iniciado por Swarlog, Jun 25, 2025, 09:08 PM

Tema anterior - Siguiente tema

Swarlog


Index: /trunk/aCis_gameserver/config/server.properties
===================================================================
--- /trunk/aCis_gameserver/config/server.properties    (revision 427)
+++ /trunk/aCis_gameserver/config/server.properties    (revision 428)
@@ -286,5 +286,5 @@
-# =================================================================
-#                                Misc
-# =================================================================
-
-# Basic protection against L2Walker.
-L2WalkerProtection = False
-
+# =================================================================
+#                                Misc
+# =================================================================
+
+# Bots prevention system.
+EnableBotsPrevention = False
+# How many monsters have to be killed to run validation task?
+KillsCounter = 60
+# Specify range of randomly taken values summed with main counter.
+KillsCounterRandomization = 50
+# How long validation window awaits an answer? (in seconds)
+ValidationTime = 60
+# Punishments:
+#    0 = move character to the closest village.
+#     1 = kick characters from the server.
+#    2 = put character to jail.
+#    3 = ban character from the server.
+Punishment = 0
+# How long character were suppose to stay in jail? (in minutes)
+PunishmentTime = 60
+
+# Basic protection against L2Walker.
+L2WalkerProtection = False
+
Index: trunk/aCis_gameserver/java/net/sf/l2j/Config.java
===================================================================
--- trunk/aCis_gameserver/java/net/sf/l2j/Config.java    (révision 427)
+++ trunk/aCis_gameserver/java/net/sf/l2j/Config.java    (révision 428)
@@ -653,5 +653,5 @@
-    /** Misc */
+    /** Misc */
+    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;
@@ -1264 +1264 @@
-            L2WALKER_PROTECTION = server.getProperty("L2WalkerProtection", false);
+            BOTS_PREVENTION = server.getProperty("EnableBotsPrevention", false);
+            KILLS_COUNTER = server.getProperty("KillsCounter", 60);
+            KILLS_COUNTER_RANDOMIZATION = server.getProperty("KillsCounterRandomization", 50);
+            VALIDATION_TIME = server.getProperty("ValidationTime", 60);
+            PUNISHMENT = server.getProperty("Punishment", 0);
+            PUNISHMENT_TIME = server.getProperty("PunishmentTime", 60);
+            L2WALKER_PROTECTION = server.getProperty("L2WalkerProtection", false);
+
Index: trunk/aCis_gameserver/java/net/sf/l2j/gameserver/instancemanager/BotsPreventionManager.java
===================================================================
--- trunk/aCis_gameserver/java/net/sf/l2j/gameserver/instancemanager/BotsPreventionManager.java    (revision 0)
+++ trunk/aCis_gameserver/java/net/sf/l2j/gameserver/instancemanager/BotsPreventionManager.java    (revision 1)
@@ -0 +0 @@
+package net.sf.l2j.gameserver.instancemanager;
+
+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 net.sf.l2j.Config;
+import net.sf.l2j.L2DatabaseFactory;
+import net.sf.l2j.commons.lang.StringUtil;
+import net.sf.l2j.gameserver.ThreadPoolManager;
+import net.sf.l2j.gameserver.datatables.MapRegionTable;
+import net.sf.l2j.gameserver.model.actor.L2Character;
+import net.sf.l2j.gameserver.model.actor.instance.L2MonsterInstance;
+import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
+import net.sf.l2j.gameserver.network.serverpackets.NpcHtmlMessage;
+import net.sf.l2j.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>Bots prevention</title>");
+        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 such window appears it means server suspect,<br1>that you may 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>Bots prevention</title>");
+        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 colours within generated pattern:</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>click-on pattern of your choice beneath:</font>");
+       
+        // generate random colours.
+        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>Bots prevention</title>");
+        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 such window appears, it means character haven't<br1>passed through prevention system.");
+        StringUtil.append(tb, "<br><br><font color=\"b09979\">in such case character get moved to 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 = ThreadPoolManager.getInstance().scheduleGeneral(new ReportCheckTask(player), VALIDATION_TIME);
+        ThreadPoolManager.getInstance().scheduleGeneral(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())
+                {
+                    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, colours doesn't match.");
+    }
+   
+    private static void changeaccesslevel(L2PcInstance targetPlayer, int lvl)
+    {
+        if (targetPlayer.isOnline())
+        {
+            targetPlayer.setAccessLevel(lvl);
+            targetPlayer.logout();
+        }
+        else
+        {
+            try (Connection con = L2DatabaseFactory.getInstance().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())
+        {
+            activeChar.setPunishLevel(L2PcInstance.PunishLevel.JAIL, Config.PUNISHMENT_TIME);
+        }
+        else
+        {
+            try (Connection con = L2DatabaseFactory.getInstance().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, colours match!");
+                _validation.remove(player.getObjectId());
+                _beginvalidation.get(player.getObjectId()).cancel(true);
+                _beginvalidation.remove(player.getObjectId());
+            }
+        }
+    }
+   
+    protected class countdown implements Runnable
+    {
+        private final L2PcInstance _player;
+        private int _time;
+       
+        public countdown(L2PcInstance player, int time)
+        {
+            _time = time;
+            _player = player;
+        }
+       
+        @Override
+        public void run()
+        {
+            if (_player.isOnline())
+            {
+                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 colors.");
+                        break;
+                    case 30:
+                    case 10:
+                    case 5:
+                    case 4:
+                    case 3:
+                    case 2:
+                    case 1:
+                        _player.sendMessage(_time + " second(s) to match colors!");
+                        break;
+                }
+                if (_time > 1 && _validation.containsKey(_player.getObjectId()))
+                {
+                    ThreadPoolManager.getInstance().scheduleGeneral(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();
+    }
+}
Index: trunk/aCis_gameserver/java/net/sf/l2j/gameserver/model/actor/L2Character.java
===================================================================
--- trunk/aCis_gameserver/java/net/sf/l2j/gameserver/model/actor/L2Character.java    (revision 427)
+++ trunk/aCis_gameserver/java/net/sf/l2j/gameserver/model/actor/L2Character.java    (revision 428)
@@ -41 +42 @@
-import net.sf.l2j.gameserver.handler.SkillHandler;
+import net.sf.l2j.gameserver.handler.SkillHandler;
+import net.sf.l2j.gameserver.instancemanager.BotsPreventionManager;
@@ -1613 +1613 @@
-        calculateRewards(killer);
+        calculateRewards(killer);
+        if (Config.BOTS_PREVENTION)
+        {
+            BotsPreventionManager.getInstance().updatecounter(killer,this);
+        }
+
Index: trunk/aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/RequestBypassToServer.java
===================================================================
--- trunk/aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/RequestBypassToServer.java    (revision 427)
+++ trunk/aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/RequestBypassToServer.java    (revision 428)
@@ -24 +24 @@
-import net.sf.l2j.gameserver.handler.IAdminCommandHandler;
+import net.sf.l2j.gameserver.handler.IAdminCommandHandler;
+import net.sf.l2j.gameserver.instancemanager.BotsPreventionManager;
@@ -166 +166 @@
-            else if (_command.startsWith("arenachange")) // change
-            {
-                final boolean isManager = activeChar.getCurrentFolkNPC() instanceof L2OlympiadManagerInstance;
-                if (!isManager)
-                {
-                    // Without npc, command can be used only in observer mode on arena
-                    if (!activeChar.inObserverMode() || activeChar.isInOlympiadMode() || activeChar.getOlympiadGameId() < 0)
-                        return;
-                }
-               
-                if (OlympiadManager.getInstance().isRegisteredInComp(activeChar))
-                {
-                    activeChar.sendPacket(SystemMessageId.WHILE_YOU_ARE_ON_THE_WAITING_LIST_YOU_ARE_NOT_ALLOWED_TO_WATCH_THE_GAME);
-                    return;
-                }
-               
-                final int arenaId = Integer.parseInt(_command.substring(12).trim());
-                activeChar.enterOlympiadObserverMode(arenaId);
-            }
+            else if (_command.startsWith("arenachange")) // change
+            {
+                final boolean isManager = activeChar.getCurrentFolkNPC() instanceof L2OlympiadManagerInstance;
+                if (!isManager)
+                {
+                    // Without npc, command can be used only in observer mode on arena
+                    if (!activeChar.inObserverMode() || activeChar.isInOlympiadMode() || activeChar.getOlympiadGameId() < 0)
+                        return;
+                }
+               
+                if (OlympiadManager.getInstance().isRegisteredInComp(activeChar))
+                {
+                    activeChar.sendPacket(SystemMessageId.WHILE_YOU_ARE_ON_THE_WAITING_LIST_YOU_ARE_NOT_ALLOWED_TO_WATCH_THE_GAME);
+                    return;
+                }
+               
+                final int arenaId = Integer.parseInt(_command.substring(12).trim());
+                activeChar.enterOlympiadObserverMode(arenaId);
+            }
+            else if (_command.startsWith("report"))
+            {
+                BotsPreventionManager.getInstance().AnalyseBypass(_command,activeChar);
+            }
+
Index: trunk/aCis_gameserver/java/net/sf/l2j/gameserver/network/serverpackets/PledgeCrest.java
===================================================================
--- trunk/aCis_gameserver/java/net/sf/l2j/gameserver/network/serverpackets/PledgeCrest.java    (revision 427)
+++ trunk/aCis_gameserver/java/net/sf/l2j/gameserver/network/serverpackets/PledgeCrest.java    (revision 428)
@@ -29 +29 @@
-    }
-   
-    @Override
-    protected final void writeImpl()
+    }
+   
+    public PledgeCrest(int crestId, byte[] data)
+    {
+        _crestId = crestId;
+        _data = data;
+    }
+   
+    @Override
+    protected final void writeImpl()
+



CitarACIS: Adaptación:

### Eclipse Workspace Patch 1.0
#P L2jaCis 360

Index: aCis_gameserver/config/l2jcustom/protect.properties
===================================================================
--- aCis_gameserver/config/l2jcustom/protect.properties    (revision 0)
+++ aCis_gameserver/config/l2jcustom/protect.properties    (working copy)
@@ -0,0 +1,23 @@
+# =================================================================
+#                                Bots Prevention
+# =================================================================
+
+# Bots prevention system.
+EnableBotsPrevention = False
+# How many monsters have to be killed to run validation task?
+KillsCounter = 60
+# Specify range of randomly taken values summed with main counter.
+KillsCounterRandomization = 50
+# How long validation window awaits an answer? (in seconds)
+ValidationTime = 60
+# Punishments:
+#    0 = move character to the closest village.
+#     1 = kick characters from the server.
+#    2 = put character to jail.
+#    3 = ban character from the server.
+Punishment = 0
+# How long character were suppose to stay in jail? (in minutes)
+PunishmentTime = 60
+
+# Basic protection against L2Walker.
+L2WalkerProtection = False
Index: aCis_gameserver/config/server.properties
===================================================================
--- aCis_gameserver/config/server.properties    (revision 2)
+++ aCis_gameserver/config/server.properties    (working copy)
@@ -295,9 +295,6 @@
 #                                Misc
 # =================================================================
 
-# Basic protection against L2Walker.
-L2WalkerProtection = False
-
 # Zone setting.
 #   0 = Peace All the Time
 #   1 = PVP During Siege for siege participants
Index: aCis_gameserver/java/net/sf/l2j/Config.java
===================================================================
--- aCis_gameserver/java/net/sf/l2j/Config.java    (revision 2)
+++ aCis_gameserver/java/net/sf/l2j/Config.java    (working copy)
@@ -51,6 +51,7 @@
     public static final String PLAYERS_FILE = "./config/players.properties";
     public static final String SERVER_FILE = "./config/server.properties";
     public static final String SIEGE_FILE = "./config/siege.properties";
+    public static final String PROTECT_FILE = "./config/l2jcustom/protect.properties";
    
     // --------------------------------------------------
     // Clans settings
@@ -641,11 +642,19 @@
     public static int THREADS_PER_INSTANT_THREAD_POOL;
    
     /** Misc */
-    public static boolean L2WALKER_PROTECTION;
     public static boolean SERVER_NEWS;
     public static int ZONE_TOWN;
     public static boolean DISABLE_TUTORIAL;
    
+    /** Bots Prevention */
+    public static boolean L2WALKER_PROTECTION;
+    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;
+   
     // --------------------------------------------------
     // Those "hidden" settings haven't configs to avoid admins to fuck their server
     // You still can experiment changing values here. But don't say I didn't warn you.
@@ -1359,6 +1368,23 @@
     }
    
     /**
+     * Loads protect settings.<br>
+     * Bot Prevention.
+     */
+    private static final void loadProtect()
+    {
+        final ExProperties protect = initProperties(PROTECT_FILE);
+        BOTS_PREVENTION = protect.getProperty("EnableBotsPrevention", false);
+        KILLS_COUNTER = protect.getProperty("KillsCounter", 60);
+        KILLS_COUNTER_RANDOMIZATION = protect.getProperty("KillsCounterRandomization", 50);
+        VALIDATION_TIME = protect.getProperty("ValidationTime", 60);
+        PUNISHMENT = protect.getProperty("Punishment", 0);
+        PUNISHMENT_TIME = protect.getProperty("PunishmentTime", 60);
+        L2WALKER_PROTECTION = protect.getProperty("L2WalkerProtection", false);
+       
+    }
+   
+    /**
      * Loads loginserver settings.<br>
      * IP addresses, database, account, misc.
      */
@@ -1427,6 +1453,9 @@
        
         // server settings
         loadServer();
+       
+        // Protect settings
+        loadProtect();
     }
    
     public static final void loadLoginServer()
Index: aCis_gameserver/java/net/sf/l2j/gameserver/instancemanager/BotsPreventionManager.java
===================================================================
--- aCis_gameserver/java/net/sf/l2j/gameserver/instancemanager/BotsPreventionManager.java    (revision 0)
+++ aCis_gameserver/java/net/sf/l2j/gameserver/instancemanager/BotsPreventionManager.java    (working copy)
@@ -0,0 +1,466 @@
+package net.sf.l2j.gameserver.instancemanager;
+
+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 net.sf.l2j.commons.concurrent.ThreadPool;
+
+import net.sf.l2j.Config;
+import net.sf.l2j.L2DatabaseFactory;
+
+import net.sf.l2j.commons.lang.StringUtil;
+
+import net.sf.l2j.gameserver.datatables.MapRegionTable.TeleportWhereType;
+import net.sf.l2j.gameserver.model.actor.L2Character;
+import net.sf.l2j.gameserver.model.actor.instance.L2MonsterInstance;
+import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
+import net.sf.l2j.gameserver.network.serverpackets.NpcHtmlMessage;
+import net.sf.l2j.gameserver.network.serverpackets.PledgeCrest;
+
+/**
+ * @Adaptacao Revengeance
+ */
+
+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>Bots prevention</title>");
+        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 such window appears it means server suspect,<br1>that you may 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>Bots prevention</title>");
+        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 colours within generated pattern:</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>click-on pattern of your choice beneath:</font>");
+       
+        // generate random colours.
+        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>Bots prevention</title>");
+        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 such window appears, it means character haven't<br1>passed through prevention system.");
+        StringUtil.append(tb, "<br><br><font color=\"b09979\">in such case character get moved to 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(TeleportWhereType.TOWN);
+                punishmentnwindow(player);
+                break;
+            case 1:
+                if (player.isOnline())
+                {
+                    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, colours doesn't match.");
+    }
+   
+    private static void changeaccesslevel(L2PcInstance targetPlayer, int lvl)
+    {
+        if (targetPlayer.isOnline())
+        {
+            targetPlayer.setAccessLevel(lvl);
+            targetPlayer.logout();
+        }
+        else
+        {
+            try (Connection con = L2DatabaseFactory.getInstance().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())
+        {
+            activeChar.setPunishLevel(L2PcInstance.PunishLevel.JAIL, Config.PUNISHMENT_TIME);
+        }
+        else
+        {
+            try (Connection con = L2DatabaseFactory.getInstance().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, colours match!");
+                _validation.remove(player.getObjectId());
+                _beginvalidation.get(player.getObjectId()).cancel(true);
+                _beginvalidation.remove(player.getObjectId());
+            }
+        }
+    }
+   
+    protected class countdown implements Runnable
+    {
+        private final L2PcInstance _player;
+        private int _time;
+       
+        public countdown(L2PcInstance player, int time)
+        {
+            _time = time;
+            _player = player;
+        }
+       
+        @Override
+        public void run()
+        {
+            if (_player.isOnline())
+            {
+                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 colors.");
+                        break;
+                    case 30:
+                    case 10:
+                    case 5:
+                    case 4:
+                    case 3:
+                    case 2:
+                    case 1:
+                        _player.sendMessage(_time + " second(s) to match colors!");
+                        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();
+    }
+}
Index: aCis_gameserver/java/net/sf/l2j/gameserver/model/actor/L2Character.java
===================================================================
--- aCis_gameserver/java/net/sf/l2j/gameserver/model/actor/L2Character.java    (revision 2)
+++ aCis_gameserver/java/net/sf/l2j/gameserver/model/actor/L2Character.java    (working copy)
@@ -36,6 +36,7 @@
 import net.sf.l2j.gameserver.geoengine.GeoEngine;
 import net.sf.l2j.gameserver.handler.ISkillHandler;
 import net.sf.l2j.gameserver.handler.SkillHandler;
+import net.sf.l2j.gameserver.instancemanager.BotsPreventionManager;
 import net.sf.l2j.gameserver.instancemanager.DimensionalRiftManager;
 import net.sf.l2j.gameserver.model.ChanceSkillList;
 import net.sf.l2j.gameserver.model.CharEffectList;
@@ -1527,6 +1528,11 @@
         stopAllEffectsExceptThoseThatLastThroughDeath();
        
         calculateRewards(killer);
+        if (Config.BOTS_PREVENTION)
+        {
+            BotsPreventionManager.getInstance().updatecounter(killer,this);
+        }
+
        
         // Send the Server->Client packet StatusUpdate with current HP and MP to all other L2PcInstance to inform
         broadcastStatusUpdate();
Index: aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/RequestBypassToServer.java
===================================================================
--- aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/RequestBypassToServer.java    (revision 2)
+++ aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/RequestBypassToServer.java    (working copy)
@@ -22,6 +22,7 @@
 import net.sf.l2j.gameserver.datatables.AdminCommandAccessRights;
 import net.sf.l2j.gameserver.handler.AdminCommandHandler;
 import net.sf.l2j.gameserver.handler.IAdminCommandHandler;
+import net.sf.l2j.gameserver.instancemanager.BotsPreventionManager;
 import net.sf.l2j.gameserver.model.L2Object;
 import net.sf.l2j.gameserver.model.L2World;
 import net.sf.l2j.gameserver.model.actor.L2Npc;
@@ -181,6 +182,11 @@
                 final int arenaId = Integer.parseInt(_command.substring(12).trim());
                 activeChar.enterOlympiadObserverMode(arenaId);
             }
+            else if (_command.startsWith("report"))
+            {
+                BotsPreventionManager.getInstance().AnalyseBypass(_command,activeChar);
+            }
+
         }
         catch (Exception e)
         {
Index: aCis_gameserver/java/net/sf/l2j/gameserver/network/serverpackets/PledgeCrest.java
===================================================================
--- aCis_gameserver/java/net/sf/l2j/gameserver/network/serverpackets/PledgeCrest.java    (revision 2)
+++ aCis_gameserver/java/net/sf/l2j/gameserver/network/serverpackets/PledgeCrest.java    (working copy)
@@ -28,6 +28,12 @@
         _data = CrestCache.getInstance().getCrest(CrestType.PLEDGE, _crestId);
     }
    
+    public PledgeCrest(int crestId, byte[] data)
+    {
+        _crestId = crestId;
+        _data = data;
+    }
+   
     @Override
     protected final void writeImpl()
     {



HTML:

<html><title>Bots prevention</title><body><center><br><br><img src="L2UI_CH3.herotower_deco" width="256" height="32"><br><br><font color="a2a0a2">in order to prove you are a human being<br1>you've to</font> <font color="b09979">match colours within generated pattern:</font><br><br><img src="Crest.crest_1_9903795" width="32" height="32"></td></tr><br><br><font color=b09979>click-on pattern of your choice beneath:</font><table><tr><td><button action="bypass -h report_0" width=32 height=32 back="Crest.crest_1_1978" fore="Crest.crest_1_1978"></td><td><button action="bypass -h report_1" width=32 height=32 back="Crest.crest_1_1970" fore="Crest.crest_1_1970"></td><td><button action="bypass -h report_2" width=32 height=32 back="Crest.crest_1_1975" fore="Crest.crest_1_1975"></td><td><button action="bypass -h report_3" width=32 height=32 back="Crest.crest_1_1971" fore="Crest.crest_1_1971"></td></tr></table></center></body></html>


Imágenes del anti bot --> https://mega.nz/#!O4owmagL!H2OLT3WpgPTrCC-rKFLfQwgrTWjUo3CGDg7Hao-mjAE