Advertisement
Caparso

Bots prevention system, version 2.0!

Feb 10th, 2023 (edited)
1,685
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 41.07 KB | Gaming | 0 0
  1. diff --git a/aCis_gameserver/config/server.properties b/aCis_gameserver/config/server.properties
  2. index 33735f6..3321659 100644
  3. --- a/aCis_gameserver/config/server.properties
  4. +++ b/aCis_gameserver/config/server.properties
  5. @@ -284,4 +284,48 @@
  6.  ZoneTown = 0
  7.  
  8.  # Show "data/html/servnews.htm" when a character logins.
  9. -ShowServerNews = False
  10. \ No newline at end of file
  11. +ShowServerNews = False
  12. +
  13. +# =================================================================
  14. +#                      Bots prevention system
  15. +# =================================================================
  16. +
  17. +# Enable bots prevention system?
  18. +EnableBotsPrevention = True
  19. +
  20. +# How many monsters have to be killed to run validation task?
  21. +KillsCounter = 250
  22. +
  23. +# Specify range of randomly taken values summed with main counter.
  24. +KillsCounterRandomization = 100
  25. +
  26. +# How long validation window awaits an answer? (in seconds)
  27. +ValidationTime = 30
  28. +
  29. +# Punishments:
  30. +#  0 = move character to the closest village.
  31. +#  1 = kick characters from the server.
  32. +#  2 = put character to jail.
  33. +#  3 = ban character from the server.
  34. +Punishment = 0
  35. +
  36. +# How long character were suppose to stay in jail? (in minutes)
  37. +PunishmentTime = 60
  38. +
  39. +# Extra checks against supporting professions.
  40. +# System counts party kills and triggers a verification process for selected classes.
  41. +Bishops = True
  42. +Elders = True
  43. +Prophets = True
  44. +Bladedancers = True
  45. +Swordsingers = True
  46. +Warcryers = True
  47. +Overlords = True
  48. +
  49. +# Allow second attempt, so player can try one more time in case of incorrect verification.
  50. +AllowIncorrectChoice = True
  51. +
  52. +# Awards character with a selected type of item for passing the validation process correctly.
  53. +Rewards = True
  54. +Item = 1539
  55. +Amount = 5
  56. \ No newline at end of file
  57. diff --git a/aCis_gameserver/java/net/sf/l2j/Config.java b/aCis_gameserver/java/net/sf/l2j/Config.java
  58. index 65daaa6..079a0d9 100644
  59. --- a/aCis_gameserver/java/net/sf/l2j/Config.java
  60. +++ b/aCis_gameserver/java/net/sf/l2j/Config.java
  61. @@ -588,6 +588,25 @@
  62.     public static int INSTANT_THREAD_POOL_COUNT;
  63.     public static int THREADS_PER_INSTANT_THREAD_POOL;
  64.    
  65. +   /** Bot Prevention System */
  66. +   public static boolean BPS_BOTS_PREVENTION;
  67. +   public static boolean BPS_ALLOW_INCORRECT_CHOICE;
  68. +   public static int BPS_KILLS_COUNTER;
  69. +   public static int BPS_KILLS_COUNTER_RANDOMIZATION;
  70. +   public static int BPS_VALIDATION_TIME;
  71. +   public static int BPS_PUNISHMENT;
  72. +   public static int BPS_PUNISHMENT_TIME;
  73. +   public static boolean BPS_CHECK_BISHOPS;
  74. +   public static boolean BPS_CHECK_ELDERS;
  75. +   public static boolean BPS_CHECK_PROPHETS;
  76. +   public static boolean BPS_CHECK_BLADEDANCERS;
  77. +   public static boolean BPS_CHECK_SWORDSINGERS;
  78. +   public static boolean BPS_CHECK_WARCRYERS;
  79. +   public static boolean BPS_CHECK_OVERLORDS;
  80. +   public static boolean BPS_ENABLE_REWARD;
  81. +   public static int BPS_REWARD_ID;
  82. +   public static int BPS_REWARD_AMOUNT;
  83. +  
  84.     /** Misc */
  85.     public static boolean L2WALKER_PROTECTION;
  86.     public static boolean SERVER_NEWS;
  87. @@ -1229,6 +1248,25 @@
  88.         INSTANT_THREAD_POOL_COUNT = server.getProperty("InstantThreadPoolCount", -1);
  89.         THREADS_PER_INSTANT_THREAD_POOL = server.getProperty("ThreadsPerInstantThreadPool", 2);
  90.        
  91. +       BPS_BOTS_PREVENTION = server.getProperty("EnableBotsPrevention", false);
  92. +       BPS_ALLOW_INCORRECT_CHOICE = server.getProperty("AllowIncorrectChoice", false);
  93. +       BPS_KILLS_COUNTER = server.getProperty("KillsCounter", 60);
  94. +       BPS_KILLS_COUNTER_RANDOMIZATION = server.getProperty("KillsCounterRandomization", 50);
  95. +       BPS_VALIDATION_TIME = server.getProperty("ValidationTime", 60);
  96. +       BPS_PUNISHMENT = server.getProperty("Punishment", 0);
  97. +       BPS_PUNISHMENT_TIME = server.getProperty("PunishmentTime", 60);
  98. +      
  99. +       BPS_CHECK_BISHOPS = server.getProperty("Bishops", false);
  100. +       BPS_CHECK_ELDERS = server.getProperty("Elders", false);
  101. +       BPS_CHECK_PROPHETS = server.getProperty("Prophets", false);
  102. +       BPS_CHECK_BLADEDANCERS = server.getProperty("Bladedancers", false);
  103. +       BPS_CHECK_SWORDSINGERS = server.getProperty("Swordsingers", false);
  104. +       BPS_CHECK_WARCRYERS = server.getProperty("Warcryers", false);
  105. +       BPS_CHECK_OVERLORDS = server.getProperty("Overlords", false);
  106. +       BPS_ENABLE_REWARD = server.getProperty("Rewards", false);
  107. +       BPS_REWARD_ID = server.getProperty("Item", 0);
  108. +       BPS_REWARD_AMOUNT = server.getProperty("Amount", 0);
  109. +      
  110.         L2WALKER_PROTECTION = server.getProperty("L2WalkerProtection", false);
  111.         ZONE_TOWN = server.getProperty("ZoneTown", 0);
  112.         SERVER_NEWS = server.getProperty("ShowServerNews", false);
  113. diff --git a/aCis_gameserver/java/net/sf/l2j/gameserver/Shutdown.java b/aCis_gameserver/java/net/sf/l2j/gameserver/Shutdown.java
  114. index 7b58886..95c4b19 100644
  115. --- a/aCis_gameserver/java/net/sf/l2j/gameserver/Shutdown.java
  116. +++ b/aCis_gameserver/java/net/sf/l2j/gameserver/Shutdown.java
  117. @@ -20,6 +20,7 @@
  118.  import net.sf.l2j.gameserver.data.manager.ZoneManager;
  119.  import net.sf.l2j.gameserver.model.World;
  120.  import net.sf.l2j.gameserver.model.actor.Player;
  121. +import net.sf.l2j.gameserver.model.botprevention.BotsPreventionManager;
  122.  import net.sf.l2j.gameserver.model.olympiad.Olympiad;
  123.  import net.sf.l2j.gameserver.network.GameClient;
  124.  import net.sf.l2j.gameserver.network.SystemMessageId;
  125. @@ -113,6 +114,9 @@
  126.             // Save zones (grandbosses status)
  127.             ZoneManager.getInstance().save();
  128.            
  129. +           // Stop Bot Prevention Validations
  130. +           BotsPreventionManager.getInstance().cleanUp();
  131. +          
  132.             // Save raidbosses status
  133.             RaidBossManager.getInstance().cleanUp(true);
  134.             LOGGER.info("Raid Bosses data has been saved.");
  135. diff --git a/aCis_gameserver/java/net/sf/l2j/gameserver/model/actor/Creature.java b/aCis_gameserver/java/net/sf/l2j/gameserver/model/actor/Creature.java
  136. index 9009a45..4a4b34d 100644
  137. --- a/aCis_gameserver/java/net/sf/l2j/gameserver/model/actor/Creature.java
  138. +++ b/aCis_gameserver/java/net/sf/l2j/gameserver/model/actor/Creature.java
  139. @@ -39,6 +39,7 @@
  140.  import net.sf.l2j.gameserver.model.actor.status.CreatureStatus;
  141.  import net.sf.l2j.gameserver.model.actor.template.CreatureTemplate;
  142.  import net.sf.l2j.gameserver.model.actor.template.NpcTemplate;
  143. +import net.sf.l2j.gameserver.model.botprevention.BotsPreventionManager;
  144.  import net.sf.l2j.gameserver.model.group.Party;
  145.  import net.sf.l2j.gameserver.model.item.instance.ItemInstance;
  146.  import net.sf.l2j.gameserver.model.item.kind.Item;
  147. @@ -486,6 +487,10 @@
  148.         stopAllEffectsExceptThoseThatLastThroughDeath();
  149.        
  150.         calculateRewards(killer);
  151. +       if (Config.BPS_BOTS_PREVENTION)
  152. +       {
  153. +           BotsPreventionManager.getInstance().onCreatureKill(killer, this);
  154. +       }
  155.        
  156.         // Send the Server->Client packet StatusUpdate with current HP and MP to all other Player to inform
  157.         getStatus().broadcastStatusUpdate();
  158. diff --git a/aCis_gameserver/java/net/sf/l2j/gameserver/model/actor/Player.java b/aCis_gameserver/java/net/sf/l2j/gameserver/model/actor/Player.java
  159. index 023516a..c0b74d9 100644
  160. --- a/aCis_gameserver/java/net/sf/l2j/gameserver/model/actor/Player.java
  161. +++ b/aCis_gameserver/java/net/sf/l2j/gameserver/model/actor/Player.java
  162. @@ -119,6 +119,7 @@
  163.  import net.sf.l2j.gameserver.model.actor.status.PlayerStatus;
  164.  import net.sf.l2j.gameserver.model.actor.template.PetTemplate;
  165.  import net.sf.l2j.gameserver.model.actor.template.PlayerTemplate;
  166. +import net.sf.l2j.gameserver.model.botprevention.BotsPreventionManager;
  167.  import net.sf.l2j.gameserver.model.craft.ManufactureList;
  168.  import net.sf.l2j.gameserver.model.entity.Castle;
  169.  import net.sf.l2j.gameserver.model.entity.Duel.DuelState;
  170. @@ -256,6 +257,7 @@
  171.     private static final String UPDATE_CHAR_RECOM_LEFT = "UPDATE characters SET rec_left=? WHERE obj_Id=?";
  172.    
  173.     private static final String UPDATE_NOBLESS = "UPDATE characters SET nobless=? WHERE obj_Id=?";
  174. +   private static final String UPDATE_LOCATION = "UPDATE characters SET x=?,y=?,z=? WHERE obj_id=?";
  175.    
  176.     public static final int REQUEST_TIMEOUT = 15;
  177.    
  178. @@ -5755,6 +5757,25 @@
  179.         }
  180.     }
  181.    
  182. +   public void teleportToOffline(TeleportType type)
  183. +   {
  184. +       var loc = MapRegionData.getInstance().getLocationToTeleport(this, type);
  185. +      
  186. +       try (Connection con = ConnectionPool.getConnection();
  187. +           PreparedStatement ps = con.prepareStatement(UPDATE_LOCATION))
  188. +       {
  189. +           ps.setInt(1, loc.getX());
  190. +           ps.setInt(2, loc.getY());
  191. +           ps.setInt(3, loc.getZ());
  192. +           ps.setInt(4, getObjectId());
  193. +           ps.executeUpdate();
  194. +       }
  195. +       catch (final Exception e)
  196. +       {
  197. +           LOGGER.error("Couldn't update location for {}.", e, getName());
  198. +       }
  199. +   }
  200. +  
  201.     public void setLvlJoinedAcademy(int lvl)
  202.     {
  203.         _lvlJoinedAcademy = lvl;
  204. @@ -6527,6 +6548,9 @@
  205.             // Remove the Player from the world
  206.             decayMe();
  207.            
  208. +           //handle logout
  209. +           BotsPreventionManager.getInstance().onLogout(this);
  210. +          
  211.             // If a party is in progress, leave it
  212.             if (_party != null)
  213.                 _party.removePartyMember(this, MessageType.DISCONNECTED);
  214. diff --git a/aCis_gameserver/java/net/sf/l2j/gameserver/model/botprevention/BotsPreventionManager.java b/aCis_gameserver/java/net/sf/l2j/gameserver/model/botprevention/BotsPreventionManager.java
  215. new file mode 100644
  216. index 0000000..9d5879f
  217. --- /dev/null
  218. +++ b/aCis_gameserver/java/net/sf/l2j/gameserver/model/botprevention/BotsPreventionManager.java
  219. @@ -0,0 +1,836 @@
  220. +package net.sf.l2j.gameserver.model.botprevention;
  221. +
  222. +import java.io.File;
  223. +import java.io.RandomAccessFile;
  224. +import java.sql.Connection;
  225. +import java.sql.PreparedStatement;
  226. +import java.util.ArrayList;
  227. +import java.util.Arrays;
  228. +import java.util.Calendar;
  229. +import java.util.Comparator;
  230. +import java.util.HashMap;
  231. +import java.util.List;
  232. +import java.util.Map;
  233. +import java.util.stream.Collectors;
  234. +import net.sf.l2j.commons.logging.CLogger;
  235. +import net.sf.l2j.commons.pool.ConnectionPool;
  236. +import net.sf.l2j.commons.pool.ThreadPool;
  237. +import net.sf.l2j.commons.random.Rnd;
  238. +import net.sf.l2j.Config;
  239. +import net.sf.l2j.gameserver.data.cache.CrestCache;
  240. +import net.sf.l2j.gameserver.data.cache.CrestCache.CrestType;
  241. +import net.sf.l2j.gameserver.data.xml.MapRegionData;
  242. +import net.sf.l2j.gameserver.enums.PunishmentType;
  243. +import net.sf.l2j.gameserver.enums.actors.ClassId;
  244. +import net.sf.l2j.gameserver.model.actor.Creature;
  245. +import net.sf.l2j.gameserver.model.actor.Player;
  246. +import net.sf.l2j.gameserver.model.actor.instance.Monster;
  247. +import net.sf.l2j.gameserver.model.actor.instance.Pet;
  248. +import net.sf.l2j.gameserver.model.actor.instance.Servitor;
  249. +import net.sf.l2j.gameserver.network.serverpackets.ExShowScreenMessage;
  250. +import net.sf.l2j.gameserver.network.serverpackets.NpcHtmlMessage;
  251. +import net.sf.l2j.gameserver.network.serverpackets.PledgeCrest;
  252. +import net.sf.l2j.gameserver.network.serverpackets.TutorialCloseHtml;
  253. +import net.sf.l2j.gameserver.network.serverpackets.TutorialShowHtml;
  254. +import net.sf.l2j.gameserver.network.serverpackets.TutorialShowQuestionMark;
  255. +import net.sf.l2j.gameserver.network.serverpackets.ExShowScreenMessage.SMPOS;
  256. +
  257. +public class BotsPreventionManager
  258. +{
  259. +   final static CLogger LOGGER = new CLogger(BotsPreventionManager.class.getName());
  260. +  
  261. +   private enum ValidationState
  262. +   {
  263. +       NONE, VALIDATION
  264. +   }
  265. +  
  266. +   protected static final int PUNISH_TELEPORT = 1000;
  267. +   protected static final int PUNISH_KICK = 1001;
  268. +   protected static final int PUNISH_JAIL = 1002;
  269. +   protected static final int PUNISH_BAN = 1003;
  270. +      
  271. +   private class PlayerValidationData
  272. +    {
  273. +       public PlayerValidationData(boolean allowIncorrectChoice)
  274. +       {
  275. +           _state = ValidationState.NONE;
  276. +           _allowIncorrectChoice = allowIncorrectChoice;
  277. +       }
  278. +      
  279. +       public ValidationState _state;
  280. +       public boolean _allowIncorrectChoice;
  281. +       public int mainpattern;
  282. +       public ArrayList<Integer> options = new ArrayList<>();
  283. +       public int patternid;
  284. +      
  285. +       public boolean showLastChanceWindow()
  286. +       {
  287. +           if (!Config.BPS_ALLOW_INCORRECT_CHOICE)
  288. +               return false;
  289. +          
  290. +           return !_allowIncorrectChoice;
  291. +       }
  292. +   }
  293. +  
  294. +    protected static Map<Integer, Double> _monstersCounter;
  295. +    protected static Map<Integer, ValidationCountdown> _validationTasks;
  296. +    protected static Map<Integer, PlayerValidationData> _validationData;
  297. +    protected static Map<Integer, byte[]> _images;
  298. +    protected static List<Integer> _supportClasses;
  299. +    protected static List<Integer> _showMessageOnLogin;
  300. +    protected static byte[] _emptyImage;
  301. +    protected static int _emptyImageId;
  302. +    protected int VALIDATION_TIME = Config.BPS_VALIDATION_TIME * 1000;
  303. +    protected static List<Integer> _generatedPatternsIDs;
  304. +    protected static int IMAGES_STARTING_ID = 1500;
  305. +    
  306. +    public static final BotsPreventionManager getInstance()
  307. +    {
  308. +        return SingletonHolder._instance;
  309. +    }
  310. +  
  311. +    BotsPreventionManager()
  312. +    {
  313. +       _monstersCounter = new HashMap<>();
  314. +        _validationTasks = new HashMap<>();
  315. +        _validationData = new HashMap<>();
  316. +        _supportClasses = new ArrayList<>();
  317. +        _images = new HashMap<>();
  318. +        _showMessageOnLogin = new ArrayList<>();
  319. +        _generatedPatternsIDs = new ArrayList<>();
  320. +        
  321. +        loadSupportClasses();
  322. +        loadImages();
  323. +    }
  324. +
  325. +    private static void loadSupportClasses()
  326. +    {
  327. +       if (Config.BPS_CHECK_BISHOPS)
  328. +       {
  329. +           _supportClasses.add(ClassId.BISHOP.getId());
  330. +           _supportClasses.add(ClassId.CARDINAL.getId());
  331. +       }
  332. +       if (Config.BPS_CHECK_ELDERS)
  333. +       {
  334. +           _supportClasses.add(ClassId.ELVEN_ELDER.getId());
  335. +           _supportClasses.add(ClassId.EVAS_SAINT.getId());
  336. +       }
  337. +       if (Config.BPS_CHECK_PROPHETS)
  338. +       {
  339. +           _supportClasses.add(ClassId.PROPHET.getId());
  340. +           _supportClasses.add(ClassId.HIEROPHANT.getId());
  341. +       }
  342. +       if (Config.BPS_CHECK_BLADEDANCERS)
  343. +       {
  344. +           _supportClasses.add(ClassId.BLADEDANCER.getId());
  345. +           _supportClasses.add(ClassId.SPECTRAL_DANCER.getId());
  346. +       }
  347. +       if (Config.BPS_CHECK_SWORDSINGERS)
  348. +       {
  349. +           _supportClasses.add(ClassId.SWORD_SINGER.getId());
  350. +           _supportClasses.add(ClassId.SWORD_MUSE.getId());
  351. +       }
  352. +       if (Config.BPS_CHECK_WARCRYERS)
  353. +       {
  354. +           _supportClasses.add(ClassId.WARCRYER.getId());
  355. +           _supportClasses.add(ClassId.DOOMCRYER.getId());
  356. +       }
  357. +       if (Config.BPS_CHECK_OVERLORDS)
  358. +       {
  359. +           _supportClasses.add(ClassId.OVERLORD.getId());
  360. +           _supportClasses.add(ClassId.DOMINATOR.getId());
  361. +       }
  362. +    }
  363. +    
  364. +    public boolean onQuestionMark(Player player, int number)
  365. +    {
  366. +       if (number != PUNISH_TELEPORT && number != PUNISH_JAIL && number != PUNISH_KICK  && number != PUNISH_BAN)
  367. +           return false;
  368. +
  369. +       punishmentWindow(player, number);
  370. +       return true;
  371. +    }
  372. +
  373. +    public void onLogin(Player player)
  374. +    {
  375. +       sendImagesOnEnter(player);
  376. +       //create player validation data if not exist
  377. +       if (!_validationData.containsKey(player.getObjectId()))
  378. +       {
  379. +           _validationData.put(player.getObjectId(), new PlayerValidationData(Config.BPS_ALLOW_INCORRECT_CHOICE));
  380. +       }
  381. +       //create also validation task
  382. +       if (!_validationTasks.containsKey(player.getObjectId()))
  383. +       {
  384. +           _validationTasks.put(player.getObjectId(), new ValidationCountdown(VALIDATION_TIME));
  385. +       }
  386. +       handleOnLogin(player);
  387. +    }
  388. +    
  389. +    private static void handleOnLogin(Player player)
  390. +    {
  391. +       //check if player validation is in progress
  392. +       if (_validationData.get(player.getObjectId())._state != ValidationState.NONE)
  393. +       {
  394. +           _validationTasks.get(player.getObjectId()).setPlayer(player);
  395. +           _validationTasks.get(player.getObjectId()).showHtmlWindow();
  396. +       }
  397. +      
  398. +       //handle message on login
  399. +       if (_showMessageOnLogin.contains(player.getObjectId()))
  400. +       {
  401. +           var punishType = Config.BPS_PUNISHMENT + 1000;
  402. +           showQuestionMark(player, punishType);
  403. +       }
  404. +    }
  405. +    
  406. +    private static void showQuestionMark(Player player, int param)
  407. +    {
  408. +       player.sendPacket(new TutorialShowQuestionMark(param));
  409. +    }
  410. +    
  411. +    private static void sendImagesOnEnter(Player player)
  412. +    {
  413. +      
  414. +       //Crest ID is generated by Client while uploading, and each time Crest is changed new ID is generated: Example ID: 268481020
  415. +       //When player is logging in, send images with static names
  416. +       //Send all choice options to client
  417. +       for (var imageId : _images.keySet())
  418. +       {
  419. +            PledgeCrest packet = new PledgeCrest(imageId, _images.get(imageId));
  420. +            player.sendPacket(packet);
  421. +       }
  422. +      
  423. +        //Send empty image to client
  424. +        PledgeCrest emptyImage = new PledgeCrest(_emptyImageId, _emptyImage);
  425. +        player.sendPacket(emptyImage);
  426. +    }
  427. +    
  428. +    public void onLogout(Player player)
  429. +    {
  430. +      
  431. +    }
  432. +        
  433. +    //on server shutdown
  434. +    public void cleanUp()
  435. +    {
  436. +       //stop all tasks
  437. +       for (var playerId : _validationTasks.keySet())
  438. +       {
  439. +           var validationTask = _validationTasks.get(playerId);
  440. +           if (validationTask != null)
  441. +           {
  442. +               validationTask.stopTask();
  443. +           }
  444. +       }
  445. +    }
  446. +    
  447. +    public void onCreatureKill(Creature killer, Creature victim)
  448. +    {
  449. +       //check only if monster is killed
  450. +       if (!(victim instanceof Monster))
  451. +       {
  452. +           return;
  453. +       }
  454. +      
  455. +       Player killingPlayer = null;
  456. +       if (killer instanceof Player)
  457. +       {
  458. +           killingPlayer = (Player) killer;
  459. +       }
  460. +       else if (killer instanceof Servitor)
  461. +       {
  462. +           killingPlayer = ((Servitor) killer).getOwner();
  463. +       }
  464. +       else if (killer instanceof Pet)
  465. +       {
  466. +           killingPlayer = ((Pet) killer).getOwner();
  467. +       }
  468. +      
  469. +       //something wrong
  470. +       if (killingPlayer == null)
  471. +       {
  472. +           return;
  473. +       }
  474. +      
  475. +       checkSupportsKills(killingPlayer);
  476. +       checkKillerKills(killingPlayer);
  477. +    }
  478. +    
  479. +    private void checkKillerKills(Player player)
  480. +    {
  481. +        if (!isValidationInProgress(player))
  482. +        {
  483. +           updateKillsCounter(player, 1.0);
  484. +        }
  485. +    }
  486. +    
  487. +    private void checkSupportsKills(Player player)
  488. +    {
  489. +       //no support classes declared, so we do not need analyse party
  490. +       if (_supportClasses.isEmpty())
  491. +       {
  492. +           return;
  493. +       }
  494. +      
  495. +       if (player.getParty() == null)
  496. +       {
  497. +           return;
  498. +       }
  499. +      
  500. +       var supports = new ArrayList<Player>();
  501. +       var damageDealersCount = 1.0; // 1 = because killer is considered as damage dealer
  502. +      
  503. +       for (Player member : player.getParty().getMembers())
  504. +       {
  505. +           //if support killed a monster count him as damage dealer
  506. +           if (member == null || member.getObjectId() == player.getObjectId() || member.isDead())
  507. +               continue;
  508. +          
  509. +           //if party member is too far - skip checking
  510. +           if (player.distance2D(member) > 2000)
  511. +           {
  512. +               continue;
  513. +           }
  514. +          
  515. +           if (_supportClasses.contains(member.getActiveClass()))
  516. +           {
  517. +               supports.add(member);
  518. +           }
  519. +           else
  520. +           {
  521. +               damageDealersCount ++;
  522. +           }
  523. +       }
  524. +      
  525. +       if (!supports.isEmpty())
  526. +       {
  527. +           for (Player sup : supports)
  528. +           {
  529. +               //validation is already in progress...
  530. +                if (!isValidationInProgress(sup))
  531. +                {
  532. +                   updateKillsCounter(sup, 1.0 / damageDealersCount);
  533. +                }
  534. +           }
  535. +       }
  536. +    }
  537. +    
  538. +    private void updateKillsCounter(Player player, double count)
  539. +    {
  540. +       var currentCount = 0.0;
  541. +        if (_monstersCounter.containsKey(player.getObjectId()))
  542. +        {
  543. +           currentCount = _monstersCounter.get(player.getObjectId());
  544. +        }
  545. +        currentCount += count;
  546. +        
  547. +        int next = Config.BPS_KILLS_COUNTER_RANDOMIZATION <= 0 ? 0 : Rnd.get(Config.BPS_KILLS_COUNTER_RANDOMIZATION);
  548. +        if (Config.BPS_KILLS_COUNTER + next < currentCount)
  549. +        {
  550. +            startValidationTask(player);
  551. +            _monstersCounter.put(player.getObjectId(), 0.0);
  552. +            player.broadcastTitleInfo();
  553. +        }
  554. +        else
  555. +        {
  556. +           _monstersCounter.put(player.getObjectId(), currentCount);
  557. +           player.broadcastTitleInfo();
  558. +        }
  559. +    }
  560. +  
  561. +    private static void loadImages()
  562. +    {
  563. +        String CRESTS_DIR = "data/html/mods/prevention/patterns";
  564. +      
  565. +        final File directory = new File(CRESTS_DIR);
  566. +        directory.mkdirs();
  567. +      
  568. +        int imageId = IMAGES_STARTING_ID;
  569. +        
  570. +        File[] files = directory.listFiles();
  571. +        Arrays.sort(files, Comparator.comparing(File::getName));
  572. +        
  573. +        for (File file : files)
  574. +        {
  575. +           var fileName = file.getName();
  576. +            if (!(fileName.startsWith("pattern_") && fileName.endsWith(".dds")))
  577. +                continue;
  578. +          
  579. +            byte[] data;
  580. +          
  581. +            try (RandomAccessFile f = new RandomAccessFile(file, "r"))
  582. +            {
  583. +                data = new byte[(int) f.length()];
  584. +                f.readFully(data);
  585. +            }
  586. +            catch (Exception e)
  587. +            {
  588. +                continue;
  589. +            }
  590. +            _images.put(imageId, data);
  591. +            imageId ++;
  592. +        }
  593. +        
  594. +        //---- empty image ----
  595. +        
  596. +        final File emptyImage = new File(CRESTS_DIR + "/empty.dds");
  597. +        
  598. +        try (RandomAccessFile f = new RandomAccessFile(emptyImage, "r"))
  599. +        {
  600. +           _emptyImage = new byte[(int) f.length()];
  601. +            f.readFully(_emptyImage);
  602. +            _emptyImageId = imageId; //set empty image ID as last of all images loaded
  603. +        }
  604. +        catch (Exception e)
  605. +        {
  606. +        }
  607. +        
  608. +    }
  609. +  
  610. +    private static void preValidationWindow(Player player)
  611. +    {
  612. +       var container = _validationData.get(player.getObjectId());
  613. +      
  614. +       String filename = "data/html/mods/prevention/prevention.htm";
  615. +       final NpcHtmlMessage html = new NpcHtmlMessage(0);
  616. +       html.setFile(filename);
  617. +       html.replace("%pattern%","<img src=Crest.crest_" + Config.SERVER_ID + "_" + (_validationData.get(player.getObjectId()).patternid) + " width=38 height=38>");
  618. +      
  619. +      
  620. +        StringBuilder tb = new StringBuilder();
  621. +
  622. +        for (int i = 0; i < container.options.size(); i++)
  623. +        {
  624. +           tb.append("<td align=center><button width=38 height=38 back=Crest.crest_" + Config.SERVER_ID + "_" + _emptyImageId + " fore=Crest.crest_" + Config.SERVER_ID + "_" + _emptyImageId + "></td>");
  625. +        }
  626. +        
  627. +        html.replace("%choices%", tb.toString());
  628. +
  629. +        player.sendPacket(new TutorialShowHtml(html.getHtml()));
  630. +    }
  631. +    
  632. +    private static void validationWindow(Player player)
  633. +    {
  634. +       var container = _validationData.get(player.getObjectId());
  635. +       var isLastChance = container.showLastChanceWindow();
  636. +      
  637. +       String filename = "data/html/mods/prevention/" + (isLastChance ? "prevention_event_mistake.htm" : "prevention_event.htm");
  638. +       final NpcHtmlMessage html = new NpcHtmlMessage(0);
  639. +       html.setFile(filename);
  640. +       html.replace("%pattern%","<img src=Crest.crest_" + Config.SERVER_ID + "_" + (_validationData.get(player.getObjectId()).patternid) + " width=38 height=38>");
  641. +
  642. +        
  643. +        StringBuilder tb = new StringBuilder();
  644. +
  645. +        for (int i = 0; i < container.options.size(); i++)
  646. +        {
  647. +           tb.append("<td align=center><button action=\"link report_" + i + "\" width=38 height=38 back=Crest.crest_" + Config.SERVER_ID + "_" + container.options.get(i) + " fore=Crest.crest_" + Config.SERVER_ID + "_" + container.options.get(i) + "></td>");
  648. +        }
  649. +        
  650. +        html.replace("%choices%", tb.toString());
  651. +        
  652. +        player.sendPacket(new TutorialShowHtml(html.getHtml()));
  653. +    }
  654. +  
  655. +    private static boolean isValidationInProgress(Player player)
  656. +    {
  657. +       return _validationData.containsKey(player.getObjectId()) && _validationData.get(player.getObjectId())._state != ValidationState.NONE;
  658. +    }
  659. +    
  660. +    private static void punishmentWindow(Player player, int punishType)
  661. +    {
  662. +       //message has been displayed, remove
  663. +       if (_showMessageOnLogin.contains(player.getObjectId()))
  664. +       {
  665. +           _showMessageOnLogin.remove(_showMessageOnLogin.indexOf(player.getObjectId()));
  666. +       }
  667. +      
  668. +       String punishMessage = "character has been punished";
  669. +       if (punishType == PUNISH_TELEPORT)
  670. +           punishMessage = "character has been moved to nearest town!";
  671. +       else if (punishType == PUNISH_KICK)
  672. +           punishMessage = "character has been disconnected from the server!";
  673. +       else if (punishType == PUNISH_JAIL)
  674. +           punishMessage = "character has been imprisoned!";
  675. +       else if (punishType == PUNISH_BAN)
  676. +           punishMessage = "character has been banned!";      
  677. +      
  678. +      
  679. +       String filename = "data/html/mods/prevention/prevention_punishment.htm";
  680. +       final NpcHtmlMessage html = new NpcHtmlMessage(0);
  681. +       html.setFile(filename);
  682. +      
  683. +       html.replace("%punish_message%", punishMessage);
  684. +       player.sendPacket(html);
  685. +    }
  686. +  
  687. +    public void startValidationTask(Player player)
  688. +    {
  689. +       var validationData = _validationData.get(player.getObjectId());
  690. +       validationData._state = ValidationState.VALIDATION;
  691. +        randomizeimages(validationData, player);
  692. +
  693. +        //Send pattern with unique file name to client
  694. +        PledgeCrest patternImage = new PledgeCrest(validationData.patternid, _images.get(validationData.options.get(validationData.mainpattern)));
  695. +        player.sendPacket(patternImage);
  696. +      
  697. +        var validationTask = _validationTasks.get(player.getObjectId());
  698. +        validationTask.startTask(player, VALIDATION_TIME / 1000);
  699. +        ThreadPool.schedule(validationTask, 1);
  700. +    }
  701. +  
  702. +    protected void randomizeimages(PlayerValidationData container, Player player)
  703. +    {
  704. +        int buttonscount = 4;
  705. +        var imagesIds = _images.keySet().stream().collect(Collectors.toList());
  706. +        int imagescount = imagesIds.size();
  707. +        
  708. +        container.options.clear();
  709. +      
  710. +        for (int i = 0; i < buttonscount; i++)
  711. +        {
  712. +           var randomIndex = Rnd.get(imagescount);
  713. +           while (container.options.indexOf(imagesIds.get(randomIndex)) > -1)
  714. +            {
  715. +               randomIndex = Rnd.get(imagescount);
  716. +            }
  717. +           container.options.add(imagesIds.get(randomIndex));
  718. +        }
  719. +              
  720. +        int mainIndex = Rnd.get(buttonscount);
  721. +        container.mainpattern = mainIndex;
  722. +      
  723. +        Calendar token =  Calendar.getInstance();
  724. +       String uniquetoken = getDatePart(token,Calendar.DAY_OF_MONTH) + getDatePart(token,Calendar.HOUR_OF_DAY)+ getDatePart(token,Calendar.MINUTE)+ getDatePart(token,Calendar.SECOND) + getDatePart(token,Calendar.MILLISECOND);
  725. +       var intUniqueToken = Integer.parseInt(uniquetoken);
  726. +
  727. +       //when token already exists, just increase by one (when in same miliseconds two players are validated)
  728. +       //also check if ID is not used by any clan crest
  729. +        while(true)
  730. +        {
  731. +           if (_generatedPatternsIDs.contains(intUniqueToken) || CrestCache.getInstance().getCrest(CrestType.PLEDGE, intUniqueToken) != null)
  732. +           {
  733. +               intUniqueToken++;
  734. +           }
  735. +           else
  736. +           {
  737. +               break;
  738. +           }
  739. +        }
  740. +        
  741. +        synchronized(_generatedPatternsIDs)
  742. +        {
  743. +           _generatedPatternsIDs.add(intUniqueToken);
  744. +        }
  745. +        
  746. +        container.patternid = intUniqueToken;  
  747. +    }
  748. +  
  749. +    private static String getDatePart(Calendar token, int part)
  750. +    {
  751. +       var partNum = token.get(part);
  752. +       if (part == Calendar.MILLISECOND)
  753. +       {
  754. +           return Integer.toString(partNum / 100);
  755. +       }
  756. +      
  757. +       if (partNum< 10)
  758. +       {
  759. +           return "0" + partNum;
  760. +       }
  761. +       return Integer.toString(partNum);
  762. +    }
  763. +    
  764. +    protected void punishPlayer(Player player)
  765. +    {
  766. +
  767. +       _showMessageOnLogin.add(player.getObjectId());
  768. +      
  769. +       var punishType = Config.BPS_PUNISHMENT + 1000;
  770. +        switch (punishType)
  771. +        {
  772. +        // 0 = move character to the closest village.
  773. +        // 1 = kick characters from the server.
  774. +        // 2 = put character to jail.
  775. +        // 3 = ban character from the server.
  776. +            case PUNISH_TELEPORT:
  777. +                teleportPunishment(player, Config.BPS_PUNISHMENT_TIME * 60);
  778. +                break;
  779. +            case PUNISH_KICK:
  780. +                if (player.isOnline())
  781. +                {
  782. +                   showQuestionMark(player, PUNISH_KICK);
  783. +                    player.logout(true);
  784. +                }
  785. +                break;
  786. +            case PUNISH_JAIL:
  787. +                jailPunishment(player, Config.BPS_PUNISHMENT_TIME * 60);
  788. +                break;
  789. +            case PUNISH_BAN:
  790. +                changeaccesslevel(player, -100);
  791. +                break;
  792. +        }
  793. +
  794. +    }
  795. +  
  796. +    private static void changeaccesslevel(Player player, int lvl)
  797. +    {
  798. +        if (player.isOnline())
  799. +        {
  800. +           showQuestionMark(player, PUNISH_BAN);
  801. +            player.setAccessLevel(lvl);
  802. +            player.logout(false);
  803. +        }
  804. +        else
  805. +        {
  806. +           try (Connection con = ConnectionPool.getConnection();
  807. +               PreparedStatement ps = con.prepareStatement("UPDATE characters SET accesslevel=? WHERE obj_id=?"))
  808. +           {
  809. +               ps.setInt(1, lvl);
  810. +               ps.setInt(2, player.getObjectId());
  811. +               ps.execute();
  812. +           }
  813. +           catch (Exception e)
  814. +           {
  815. +               LOGGER.error("Couldn't change player's accesslevel.", e);
  816. +           }
  817. +        }
  818. +    }
  819. +    
  820. +    private static void teleportPunishment(Player player, int delay)
  821. +    {
  822. +        if (player.isOnline())
  823. +        {
  824. +           player.abortAll(true);
  825. +            player.teleportTo(MapRegionData.TeleportType.TOWN);
  826. +            showQuestionMark(player, PUNISH_TELEPORT);
  827. +        }
  828. +        else
  829. +        {
  830. +           player.teleportToOffline(MapRegionData.TeleportType.TOWN);
  831. +           _showMessageOnLogin.add(player.getObjectId());
  832. +        }
  833. +    }
  834. +    
  835. +    
  836. +    private static void jailPunishment(Player player, int delay)
  837. +    {
  838. +        if (player.isOnline())
  839. +        {
  840. +           showQuestionMark(player, PUNISH_JAIL);
  841. +           player.getPunishment().setType(PunishmentType.JAIL, Config.BPS_PUNISHMENT_TIME);
  842. +        }
  843. +        else
  844. +        {
  845. +           try (Connection con = ConnectionPool.getConnection();
  846. +               PreparedStatement ps = con.prepareStatement("UPDATE characters SET x=-114356, y=-249645, z=-2984, punish_level=?, punish_timer=? WHERE obj_id=?"))
  847. +           {
  848. +               ps.setInt(1, PunishmentType.JAIL.ordinal());
  849. +               ps.setLong(2, ((delay > 0) ? delay * 60000L : 0));
  850. +               ps.setInt(3, player.getObjectId());
  851. +               ps.execute();
  852. +           }
  853. +           catch (Exception e)
  854. +           {
  855. +               LOGGER.error("Couldn't jail offline Player.", e);
  856. +           }
  857. +          
  858. +           _showMessageOnLogin.add(player.getObjectId());
  859. +        }
  860. +    }
  861. +  
  862. +    public void onBypass(String command, Player player)
  863. +    {
  864. +        if (!isValidationInProgress(player))
  865. +            return;
  866. +      
  867. +        String params = command.substring(command.indexOf("_") + 1);
  868. +      
  869. +        int chosenOption = -1;
  870. +        if (tryParseInt(params))
  871. +        {
  872. +           chosenOption = Integer.parseInt(params);
  873. +        }
  874. +      
  875. +        if (chosenOption > -1)
  876. +        {
  877. +           PlayerValidationData playerData = _validationData.get(player.getObjectId());
  878. +            if (chosenOption != playerData.mainpattern)
  879. +            {
  880. +               //check attempts
  881. +               if (playerData._allowIncorrectChoice)
  882. +               {
  883. +                   playerData._allowIncorrectChoice = false;
  884. +                   validationWindow(player);
  885. +               }
  886. +               else
  887. +               {
  888. +                   showOnScreenMessage(player,"Unfortunately, patterns don't match.");
  889. +                   _validationTasks.get(player.getObjectId()).stopTask();
  890. +                   player.sendPacket(TutorialCloseHtml.STATIC_PACKET);
  891. +                   punishPlayer(player);
  892. +                   resetValidationData(player);
  893. +               }
  894. +            }
  895. +            else
  896. +            {
  897. +                showOnScreenMessage(player,"Congratulations, patterns match!");
  898. +                _validationTasks.get(player.getObjectId()).stopTask();
  899. +                player.sendPacket(TutorialCloseHtml.STATIC_PACKET);
  900. +                resetValidationData(player);
  901. +                rewardPlayer(player);
  902. +            }
  903. +        }
  904. +    }
  905. +    
  906. +    private static void rewardPlayer(Player player)
  907. +    {
  908. +       if (Config.BPS_ENABLE_REWARD)
  909. +       {
  910. +           player.addItem("BotPreventionSystem", Config.BPS_REWARD_ID, Config.BPS_REWARD_AMOUNT, player, true);
  911. +       }
  912. +    }
  913. +    
  914. +    private static void resetValidationData(Player player)
  915. +    {
  916. +       if (player == null)
  917. +           return;
  918. +      
  919. +       _validationData.get(player.getObjectId())._allowIncorrectChoice = Config.BPS_ALLOW_INCORRECT_CHOICE;
  920. +       _validationData.get(player.getObjectId())._state = ValidationState.NONE;
  921. +    }
  922. +    
  923. +    private static void showOnScreenMessage(Player player, String message)
  924. +    {
  925. +       player.sendPacket(new ExShowScreenMessage(message, 2000, SMPOS.TOP_CENTER, false));
  926. +    }
  927. +    
  928. +   protected class ValidationCountdown implements Runnable
  929. +   {
  930. +        private Player _player = null;
  931. +        private int _time;
  932. +        private int _countTime;
  933. +        private boolean _stopTask = false;
  934. +      
  935. +        public ValidationCountdown(int time)
  936. +        {
  937. +            _time = time;
  938. +            _countTime = time + 3;
  939. +        }
  940. +      
  941. +        public void stopTask()
  942. +        {
  943. +           _stopTask = true;
  944. +           _countTime = -1;
  945. +        }
  946. +        
  947. +        public void startTask(Player player, int time)
  948. +        {
  949. +           _stopTask = false;
  950. +           _player = player;
  951. +            _time = time;
  952. +            _countTime = time + 3;
  953. +        }
  954. +        
  955. +        public void setPlayer(Player player)
  956. +        {
  957. +           _player = player;
  958. +        }
  959. +
  960. +        public void showHtmlWindow()
  961. +        {
  962. +           //for first 3 seconds to avoid accidental click by player, display static window
  963. +           if (_time < _countTime)
  964. +           {
  965. +               preValidationWindow(_player);
  966. +           }
  967. +           else
  968. +           {
  969. +               validationWindow(_player);
  970. +           }
  971. +        }
  972. +        
  973. +       @Override
  974. +       public void run()
  975. +       {
  976. +           if (_stopTask)
  977. +           {
  978. +               return;
  979. +           }
  980. +          
  981. +           if (_player != null)
  982. +            {
  983. +               //if player is online
  984. +               if (_player.isOnline())
  985. +               {
  986. +                    if (_time + 3 == _countTime)
  987. +                   {
  988. +                       preValidationWindow(_player);
  989. +                   }
  990. +                   else if (_time  == _countTime)
  991. +                   {
  992. +                       _player.sendPacket(TutorialCloseHtml.STATIC_PACKET);
  993. +                       validationWindow(_player);
  994. +                   }
  995. +
  996. +                   //Display Time Counter
  997. +                   if (_countTime > 0 )
  998. +                   {
  999. +                       if (_countTime <= _time)
  1000. +                       {
  1001. +                           var seconds = _countTime % 60;
  1002. +                           var minutes = (_countTime - seconds) / 60;
  1003. +                          
  1004. +                           var strMinutes = "";
  1005. +                           if (minutes > 0)
  1006. +                           {
  1007. +                               strMinutes = minutes + " minute(s) ";
  1008. +                           }
  1009. +                          
  1010. +                           //_player.sendPacket(new ExShowScreenMessage(1, -1, SMPOS.TOP_CENTER, false, 1, 0, 0, true, 2000, false, "You have " + strMinutes + seconds + " second(s) to match patterns."));
  1011. +                           _player.sendPacket(new ExShowScreenMessage("You have " + strMinutes + seconds + " second(s) to match patterns.", 2000, SMPOS.TOP_CENTER, false));
  1012. +                       }
  1013. +                   }
  1014. +               }
  1015. +              
  1016. +               if (_countTime <= 0)
  1017. +               {
  1018. +                   showOnScreenMessage(_player, "No action occurred in time.");
  1019. +                   _player.sendPacket(TutorialCloseHtml.STATIC_PACKET);
  1020. +                   punishPlayer(_player);
  1021. +                   resetValidationData(_player);
  1022. +               }
  1023. +               //reschedule and decrease time even if player is offline (will be punished while offline)
  1024. +               if (_countTime > 0)
  1025. +               {
  1026. +                    //reschedule
  1027. +                   var validationTask = _validationTasks.get(_player.getObjectId());
  1028. +                    ThreadPool.schedule(validationTask, 1000);
  1029. +               }
  1030. +                _countTime--;
  1031. +            }
  1032. +       }
  1033. +   }
  1034. +  
  1035. +    protected boolean tryParseInt(String value)
  1036. +    {
  1037. +        try
  1038. +        {
  1039. +            Integer.parseInt(value);
  1040. +            return true;
  1041. +        }
  1042. +      
  1043. +        catch (NumberFormatException e)
  1044. +        {
  1045. +            return false;
  1046. +        }
  1047. +    }
  1048. +  
  1049. +    private static class SingletonHolder
  1050. +    {
  1051. +        protected static final BotsPreventionManager _instance = new BotsPreventionManager();
  1052. +    }
  1053. +}
  1054. \ No newline at end of file
  1055. diff --git a/aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/EnterWorld.java b/aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/EnterWorld.java
  1056. index e0fdf75..1c93e62 100644
  1057. --- a/aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/EnterWorld.java
  1058. +++ b/aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/EnterWorld.java
  1059. @@ -21,6 +21,7 @@
  1060.  import net.sf.l2j.gameserver.enums.actors.ClassRace;
  1061.  import net.sf.l2j.gameserver.model.World;
  1062.  import net.sf.l2j.gameserver.model.actor.Player;
  1063. +import net.sf.l2j.gameserver.model.botprevention.BotsPreventionManager;
  1064.  import net.sf.l2j.gameserver.model.clanhall.ClanHall;
  1065.  import net.sf.l2j.gameserver.model.clanhall.SiegableHall;
  1066.  import net.sf.l2j.gameserver.model.entity.Castle;
  1067. @@ -211,6 +212,11 @@
  1068.             }
  1069.         }
  1070.        
  1071. +       if (Config.BPS_BOTS_PREVENTION)
  1072. +       {
  1073. +           BotsPreventionManager.getInstance().onLogin(player);
  1074. +       }
  1075. +      
  1076.         // Announcements, welcome & Seven signs period messages.
  1077.         player.sendPacket(SystemMessageId.WELCOME_TO_LINEAGE);
  1078.         player.sendPacket(SevenSignsManager.getInstance().getCurrentPeriod().getMessageId());
  1079. diff --git a/aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/RequestTutorialLinkHtml.java b/aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/RequestTutorialLinkHtml.java
  1080. index a60ea86..7127573 100644
  1081. --- a/aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/RequestTutorialLinkHtml.java
  1082. +++ b/aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/RequestTutorialLinkHtml.java
  1083. @@ -1,6 +1,7 @@
  1084.  package net.sf.l2j.gameserver.network.clientpackets;
  1085.  
  1086.  import net.sf.l2j.gameserver.model.actor.Player;
  1087. +import net.sf.l2j.gameserver.model.botprevention.BotsPreventionManager;
  1088.  import net.sf.l2j.gameserver.scripting.QuestState;
  1089.  
  1090.  public class RequestTutorialLinkHtml extends L2GameClientPacket
  1091. @@ -20,6 +21,13 @@
  1092.         if (player == null)
  1093.             return;
  1094.        
  1095. +       if (_bypass != null && _bypass.startsWith("report_"))
  1096. +       {
  1097. +           BotsPreventionManager.getInstance().onBypass(_bypass, player);
  1098. +           return;
  1099. +       }
  1100. +      
  1101. +      
  1102.         final QuestState qs = player.getQuestList().getQuestState("Tutorial");
  1103.         if (qs != null)
  1104.             qs.getQuest().notifyEvent(_bypass, null, player);
  1105. diff --git a/aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/RequestTutorialQuestionMark.java b/aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/RequestTutorialQuestionMark.java
  1106. index 3694d0a..70f16ff 100644
  1107. --- a/aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/RequestTutorialQuestionMark.java
  1108. +++ b/aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/RequestTutorialQuestionMark.java
  1109. @@ -1,6 +1,7 @@
  1110.  package net.sf.l2j.gameserver.network.clientpackets;
  1111.  
  1112.  import net.sf.l2j.gameserver.model.actor.Player;
  1113. +import net.sf.l2j.gameserver.model.botprevention.BotsPreventionManager;
  1114.  import net.sf.l2j.gameserver.scripting.QuestState;
  1115.  
  1116.  public class RequestTutorialQuestionMark extends L2GameClientPacket
  1117. @@ -20,6 +21,9 @@
  1118.         if (player == null)
  1119.             return;
  1120.        
  1121. +       if (BotsPreventionManager.getInstance().onQuestionMark(player, _number))
  1122. +           return;
  1123. +      
  1124.         final QuestState qs = player.getQuestList().getQuestState("Tutorial");
  1125.         if (qs != null)
  1126.             qs.getQuest().notifyEvent("QM" + _number + "", null, player);
  1127. diff --git a/aCis_gameserver/java/net/sf/l2j/gameserver/network/serverpackets/NpcHtmlMessage.java b/aCis_gameserver/java/net/sf/l2j/gameserver/network/serverpackets/NpcHtmlMessage.java
  1128. index e483774..0a96462 100644
  1129. --- a/aCis_gameserver/java/net/sf/l2j/gameserver/network/serverpackets/NpcHtmlMessage.java
  1130. +++ b/aCis_gameserver/java/net/sf/l2j/gameserver/network/serverpackets/NpcHtmlMessage.java
  1131. @@ -88,6 +88,10 @@
  1132.         _html = text;
  1133.     }
  1134.    
  1135. +   public String getHtml() {
  1136. +       return _html;
  1137. +   }
  1138. +  
  1139.     public void setFile(String filename)
  1140.     {
  1141.         // Avoid to generate file directory if config is off.
  1142. diff --git a/aCis_gameserver/java/net/sf/l2j/gameserver/network/serverpackets/PledgeCrest.java b/aCis_gameserver/java/net/sf/l2j/gameserver/network/serverpackets/PledgeCrest.java
  1143. index 628912d..47139c5 100644
  1144. --- a/aCis_gameserver/java/net/sf/l2j/gameserver/network/serverpackets/PledgeCrest.java
  1145. +++ b/aCis_gameserver/java/net/sf/l2j/gameserver/network/serverpackets/PledgeCrest.java
  1146. @@ -14,6 +14,12 @@
  1147.         _data = CrestCache.getInstance().getCrest(CrestType.PLEDGE, _crestId);
  1148.     }
  1149.    
  1150. +   public PledgeCrest(int crestId, byte[] data)
  1151. +   {
  1152. +       _crestId = crestId;
  1153. +       _data = data;
  1154. +   }
  1155. +  
  1156.     @Override
  1157.     protected final void writeImpl()
  1158.     {
  1159.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement