Hello everyone! I'm using latest free aCis files. I added Capraso's bots prevention to the server (
But when I'm trying to test it I'm getting this: "WARNING 33 net.sf.l2j.commons.concurrent.ThreadPool Exception in a Runnable execution:java.lang.IllegalArgumentException: bound must be positive" . Bots prevention doesn't work and it also causes to stay some mosters alive with 0 hp (they are not respawning). Any ideas to fix this? Below I'm pasting some *.java
My BotsPreventionManager.java
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.commons.concurrent.ThreadPool;
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;protectedstaticMap<Integer,PlayerData> _validation;protectedstaticMap<Integer,byte[]> _images;protectedint WINDOW_DELAY =3;//delay used to generate new window if previous have been closed.protectedint VALIDATION_TIME =Config.VALIDATION_TIME *1000;publicstaticfinalBotsPreventionManager getInstance(){returnSingletonHolder._instance;}BotsPreventionManager(){
_randomize =newRandom();
_monsterscounter =newHashMap<>();
_beginvalidation =newHashMap<>();
_validation =newHashMap<>();
_images =newHashMap<>();
_beginvalidation =newHashMap<>();
getimages();}publicvoid 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;}intnext= _randomize.nextInt(Config.KILLS_COUNTER_RANDOMIZATION);if(Config.KILLS_COUNTER +next< count){
validationtasks(killer);
_monsterscounter.remove(killer.getObjectId());}else{
_monsterscounter.put(killer.getObjectId(), count);}}}privatestaticvoid getimages(){String CRESTS_DIR ="data/html/mods/prevention";finalFile directory =newFile(CRESTS_DIR);
directory.mkdirs();int i =0;for(File file : directory.listFiles()){if(!file.getName().endsWith(".dds"))continue;byte[] data;try(RandomAccessFile f =newRandomAccessFile(file,"r")){
data =newbyte[(int) f.length()];
f.readFully(data);}catch(Exception e){continue;}
_images.put(i, data);
i++;}}publicvoid prevalidationwindow(L2PcInstance player){NpcHtmlMessage html =newNpcHtmlMessage(1);StringBuilder tb =newStringBuilder();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);}privatestaticvoid validationwindow(L2PcInstance player){PlayerData container = _validation.get(player.getObjectId());NpcHtmlMessage html =newNpcHtmlMessage(1);StringBuilder tb =newStringBuilder();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);}publicvoid punishmentnwindow(L2PcInstance player){NpcHtmlMessage html =newNpcHtmlMessage(1);StringBuilder tb =newStringBuilder();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);}publicvoid validationtasks(L2PcInstance player){PlayerData container =newPlayerData();
randomizeimages(container, player);for(int i =0; i < container.options.size(); i++){PledgeCrest packet =newPledgeCrest((container.options.get(i)+1500), _images.get(container.options.get(i)));
player.sendPacket(packet);}PledgeCrest packet =newPledgeCrest(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())
{
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();
}
}
My ThreadPool.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 net.sf.l2j.commons.concurrent;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import net.sf.l2j.Config;
/**
* This class handles thread pooling system. It relies on two ThreadPoolExecutor arrays, which poolers number is generated using config.
* <p>
* Those arrays hold following pools :
* </p>
* <ul>
* <li>Scheduled pool keeps a track about incoming, future events.</li>
* <li>Instant pool handles short-life events.</li>
* </ul>
*/
public final class ThreadPool
{
protected static final Logger LOG = Logger.getLogger(ThreadPool.class.getName());
private static final long MAX_DELAY = TimeUnit.NANOSECONDS.toMillis(Long.MAX_VALUE - System.nanoTime()) / 2;
private static int _threadPoolRandomizer;
protected static ScheduledThreadPoolExecutor[] _scheduledPools;
protected static ThreadPoolExecutor[] _instantPools;
/**
* Init the different pools, based on Config. It is launched only once, on Gameserver instance.
*/
public static void init()
{
// Feed scheduled pool.
int poolCount = Config.SCHEDULED_THREAD_POOL_COUNT;
if (poolCount == -1)
poolCount = Runtime.getRuntime().availableProcessors();
_scheduledPools = new ScheduledThreadPoolExecutor[poolCount];
for (int i = 0; i < poolCount; i++)
_scheduledPools[i] = new ScheduledThreadPoolExecutor(Config.THREADS_PER_SCHEDULED_THREAD_POOL);
// Feed instant pool.
poolCount = Config.INSTANT_THREAD_POOL_COUNT;
if (poolCount == -1)
poolCount = Runtime.getRuntime().availableProcessors();
_instantPools = new ThreadPoolExecutor[poolCount];
for (int i = 0; i < poolCount; i++)
_instantPools[i] = new ThreadPoolExecutor(Config.THREADS_PER_INSTANT_THREAD_POOL, Config.THREADS_PER_INSTANT_THREAD_POOL, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(100000));
// Prestart core threads.
for (ScheduledThreadPoolExecutor threadPool : _scheduledPools)
threadPool.prestartAllCoreThreads();
for (ThreadPoolExecutor threadPool : _instantPools)
threadPool.prestartAllCoreThreads();
// Launch purge task.
scheduleAtFixedRate(new Runnable()
{
@Override
public void run()
{
for (ScheduledThreadPoolExecutor threadPool : _scheduledPools)
threadPool.purge();
for (ThreadPoolExecutor threadPool : _instantPools)
threadPool.purge();
}
}, 600000, 600000);
LOG.info("ThreadPool: Initialized " + getPoolSize(_scheduledPools) + "/" + getMaximumPoolSize(_scheduledPools) + " scheduled, " + getPoolSize(_instantPools) + "/" + getMaximumPoolSize(_instantPools) + " instant thread(s).");
}
/**
* Schedules a one-shot action that becomes enabled after a delay. The pool is chosen based on pools activity.
* @param r : the task to execute.
* @param delay : the time from now to delay execution.
* @return a ScheduledFuture representing pending completion of the task and whose get() method will return null upon completion.
*/
public static ScheduledFuture<?> schedule(Runnable r,long delay){try{return getPool(_scheduledPools).schedule(newTaskWrapper(r), validate(delay),TimeUnit.MILLISECONDS);}catch(Exception e){returnnull;}}/**
* Schedules a periodic action that becomes enabled after a delay. The pool is chosen based on pools activity.
* @param r : the task to execute.
* @param delay : the time from now to delay execution.
* @param period : the period between successive executions.
* @return a ScheduledFuture representing pending completion of the task and whose get() method will throw an exception upon cancellation.
*/publicstaticScheduledFuture<?> scheduleAtFixedRate(Runnable r, long delay, long period)
{
try
{
return getPool(_scheduledPools).scheduleAtFixedRate(new TaskWrapper(r), validate(delay), validate(period), TimeUnit.MILLISECONDS);
}
catch (Exception e)
{
return null;
}
}
/**
* Executes the given task sometime in the future.
* @param r : the task to execute.
*/
public static void execute(Runnable r)
{
try
{
getPool(_instantPools).execute(new TaskWrapper(r));
}
catch (Exception e)
{
}
}
/**
* Retrieve stats of current running thread pools.
*/
public static void getStats()
{
for (int i = 0; i < _scheduledPools.length; i++)
{
final ScheduledThreadPoolExecutor threadPool = _scheduledPools[i];
LOG.info("=================================================");
LOG.info("Scheduled pool #" + i + ":");
LOG.info("\tgetActiveCount: ...... " + threadPool.getActiveCount());
LOG.info("\tgetCorePoolSize: ..... " + threadPool.getCorePoolSize());
LOG.info("\tgetPoolSize: ......... " + threadPool.getPoolSize());
LOG.info("\tgetLargestPoolSize: .. " + threadPool.getLargestPoolSize());
LOG.info("\tgetMaximumPoolSize: .. " + threadPool.getMaximumPoolSize());
LOG.info("\tgetCompletedTaskCount: " + threadPool.getCompletedTaskCount());
LOG.info("\tgetQueuedTaskCount: .. " + threadPool.getQueue().size());
LOG.info("\tgetTaskCount: ........ " + threadPool.getTaskCount());
}
for (int i = 0; i < _instantPools.length; i++)
{
final ThreadPoolExecutor threadPool = _instantPools[i];
LOG.info("=================================================");
LOG.info("Instant pool #" + i + ":");
LOG.info("\tgetActiveCount: ...... " + threadPool.getActiveCount());
LOG.info("\tgetCorePoolSize: ..... " + threadPool.getCorePoolSize());
LOG.info("\tgetPoolSize: ......... " + threadPool.getPoolSize());
LOG.info("\tgetLargestPoolSize: .. " + threadPool.getLargestPoolSize());
LOG.info("\tgetMaximumPoolSize: .. " + threadPool.getMaximumPoolSize());
LOG.info("\tgetCompletedTaskCount: " + threadPool.getCompletedTaskCount());
LOG.info("\tgetQueuedTaskCount: .. " + threadPool.getQueue().size());
LOG.info("\tgetTaskCount: ........ " + threadPool.getTaskCount());
}
}
/**
* Shutdown thread pooling system correctly. Send different informations.
*/
public static void shutdown()
{
try
{
System.out.println("ThreadPool: Shutting down.");
for (ScheduledThreadPoolExecutor threadPool : _scheduledPools)
threadPool.shutdownNow();
for (ThreadPoolExecutor threadPool : _instantPools)
threadPool.shutdownNow();
}
catch (Throwable t)
{
t.printStackTrace();
}
}
/**
* @param <T> : The pool type.
* @param threadPools : The pool array to check.
* @return the less fed pool.
*/
private static <T> T getPool(T[] threadPools)
{
return threadPools[_threadPoolRandomizer++ % threadPools.length];
}
/**
* @param delay : The delay to validate.
* @return a secured value, from 0 to MAX_DELAY.
*/
private static long validate(long delay)
{
return Math.max(0, Math.min(MAX_DELAY, delay));
}
/**
* @param threadPools : The pool array to check.
* @return the overall actual pools size.
*/
private static long getPoolSize(ThreadPoolExecutor[] threadPools)
{
long result = 0;
for (ThreadPoolExecutor threadPool : threadPools)
result += threadPool.getPoolSize();
return result;
}
/**
* @param threadPools : The pool array to check.
* @return the overall maximum pools size.
*/
private static long getMaximumPoolSize(ThreadPoolExecutor[] threadPools)
{
long result = 0;
for (ThreadPoolExecutor threadPool : threadPools)
result += threadPool.getMaximumPoolSize();
return result;
}
public static final class TaskWrapper implements Runnable
{
private final Runnable _runnable;
public TaskWrapper(Runnable runnable)
{
_runnable = runnable;
}
@Override
public void run()
{
try
{
_runnable.run();
}
catch (RuntimeException e)
{
LOG.warning("Exception in a Runnable execution:" + e);
}
}
}
}
@Hitcher I agree 100%! Are you running a live server using MyExt64 or just experimenting? I'm currently creating my IDA db's so i can start adding more stuff into the extender.
I don't understand why you are so offended and aggressive, who allowed you to disrespect me or call me in any way? Did I insulted you? You act like a angry kid, grow up boy.
@Maxtor@Celestino
The administrators of this forum can access everything I've sent...
Your move won't work on me. Hahahaha!
Getting into the parameters and editing the HTMLs of websites and claiming it's real used to be really cool among true friends.
@jtos So, is this also true? 🤣😂🤣😂🤣😂🤣
Your joke still hasn't been better than mine. Hahahah!
Question
devil12pl
Hello everyone! I'm using latest free aCis files. I added Capraso's bots prevention to the server (
But when I'm trying to test it I'm getting this: "WARNING 33 net.sf.l2j.commons.concurrent.ThreadPool Exception in a Runnable execution:java.lang.IllegalArgumentException: bound must be positive" . Bots prevention doesn't work and it also causes to stay some mosters alive with 0 hp (they are not respawning). Any ideas to fix this? Below I'm pasting some *.java
My BotsPreventionManager.java
My ThreadPool.java
3 answers to this question
Recommended Posts