Captcha para L2JaCis 367
Spoiler
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 # Zone setting. # 0 = Peace All the Time # 1 = PVP During Siege for siege participants # 2 = PVP All the Time ZoneTown = 0 # Show "data/html/servnews.htm" when a character logins from lvl 5. ServerNews = 5 # Disable tutorial on new player game entrance. Default: False. DisableTutorial = 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 */ + 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); 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.awt.image.BufferedImage; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Future; + +import net.sf.l2j.commons.concurrent.ThreadPool; +import net.sf.l2j.commons.lang.StringUtil; + +import net.sf.l2j.Config; +import net.sf.l2j.L2DatabaseFactory; +import net.sf.l2j.gameserver.datatables.MapRegionTable; +import net.sf.l2j.gameserver.features.Captcha; +import net.sf.l2j.gameserver.features.DDSConverter; +import net.sf.l2j.gameserver.features.ImageData; +import net.sf.l2j.gameserver.model.actor.Character; +import net.sf.l2j.gameserver.model.actor.instance.Monster; +import net.sf.l2j.gameserver.model.actor.instance.Player; +import net.sf.l2j.gameserver.network.serverpackets.NpcHtmlMessage; +import net.sf.l2j.gameserver.network.serverpackets.PledgeCrest; + +public class BotsPreventionManager +{ + public class PlayerData + { + public PlayerData() + { + firstWindow = true; + } + + public boolean firstWindow; + public BufferedImage image; + public String captchaText = ""; + public int captchaID = 0; + } + + protected Random _randomize; + protected static Map<Integer, ImageData> _imageMap; + protected static Map<Integer, Integer> _monsterscounter; + protected static Map<Integer, Future<?>> _beginvalidation; + protected static Map<Integer, PlayerData> _validation; + protected int WINDOW_DELAY = 3; // delay used to generate new window if previous have been closed. + protected int VALIDATION_TIME = Config.VALIDATION_TIME * 1000; + private int USEDID = 0; + + public static final BotsPreventionManager getInstance() + { + return SingletonHolder._instance; + } + + BotsPreventionManager() + { + _randomize = new Random(); + _monsterscounter = new HashMap<>(); + _beginvalidation = new HashMap<>(); + _validation = new HashMap<>(); + _beginvalidation = new HashMap<>(); + _imageMap = new ConcurrentHashMap<>(); + _imageMap = Captcha.getInstance().createImageList(); + } + + public void updatecounter(Character player, Character monster) + { + if ((player instanceof Player) && (monster instanceof Monster)) + { + Player killer = (Player) 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); + } + } + } + + public void prevalidationwindow(Player 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(Player 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\">enter the code from picture:</font>"); + + // generated main pattern. + StringUtil.append(tb, "<br><br><img src=\"Crest.crest_" + Config.SERVER_ID + "_" + (container.captchaID) + "\" width=256 height=64></td></tr>"); + StringUtil.append(tb, "<br>"); + StringUtil.append(tb, "<br><br><edit var=\"answer\" width=110>"); + StringUtil.append(tb, "<br><button value=\"Confirm\" action=\"bypass -h report_ $answer\" width=\"75\" height=\"21\" back=\"L2UI_CH3.Btn1_normal\" fore=\"L2UI_CH3.Btn1_normal\"><br/>"); + StringUtil.append(tb, "</center></body>"); + StringUtil.append(tb, "</html>"); + + html.setHtml(tb.toString()); + player.sendPacket(html); + } + + public void punishmentnwindow(Player 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(Player player) + { + PlayerData container = new PlayerData(); + // Captcha.getInstance().generateCaptcha(container, player); + container.image = _imageMap.get(getInstance().USEDID).image; + container.captchaID = _imageMap.get(getInstance().USEDID).captchaID; + container.captchaText = _imageMap.get(getInstance().USEDID).captchaText; + PledgeCrest packet = new PledgeCrest(container.captchaID, DDSConverter.convertToDDS(container.image).array()); + player.sendPacket(packet); + getInstance().USEDID++; + + if (getInstance().USEDID == 998) + { + getInstance().USEDID = 0; + ThreadPool.schedule(() -> { + _imageMap = Captcha.getInstance().createImageList(); + }, 100); + } + _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 banpunishment(Player 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.TeleportType.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, code doesn't match."); + } + + private static void changeaccesslevel(Player 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(Player activeChar, int delay) + { + if (activeChar.isOnline()) + { + activeChar.setPunishLevel(Player.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, Player.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, Player 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; + } + + PlayerData playerData = _validation.get(player.getObjectId()); + if (!params.trim().equalsIgnoreCase(playerData.captchaText)) + { + banpunishment(player); + } + else + { + player.sendMessage("Congratulations, code match!"); + _validation.remove(player.getObjectId()); + _beginvalidation.get(player.getObjectId()).cancel(true); + _beginvalidation.remove(player.getObjectId()); + } + + } + + protected class countdown implements Runnable + { + private final Player _player; + private int _time; + + public countdown(Player 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 enter the code."); + break; + case 30: + case 10: + case 5: + case 4: + case 3: + case 2: + case 1: + _player.sendMessage(_time + " second(s) to enter the code!"); + 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(Player player) + { + if (_validation.get(player.getObjectId()) != null) + { + _validation.remove(player.getObjectId()); + } + } + + public Boolean IsAlredyInReportMode(Player player) + { + if (_validation.get(player.getObjectId()) != null) + { + return true; + } + return false; + } + + private class ReportCheckTask implements Runnable + { + private final Player _player; + + public ReportCheckTask(Player 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/Character.java =================================================================== --- trunk/aCis_gameserver/java/net/sf/l2j/gameserver/model/actor/Character.java (revision 427) +++ trunk/aCis_gameserver/java/net/sf/l2j/gameserver/model/actor/Character.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); + 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 OlympiadManagerNpc; + if (!isManager) + { + // Without npc, command can be used only in observer mode on arena + if (!activeChar.isInObserverMode() || 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() + Index: trunk/aCis_gameserver/java/net/sf/l2j/gameserver/features/DDSConverter.java =================================================================== --- trunk/aCis_gameserver/java/net/sf/l2j/gameserver/features/DDSConverter.java (revision 427) +++ trunk/aCis_gameserver/java/net/sf/l2j/gameserver/features/DDSConverter.java (revision 428) +package net.sf.l2j.gameserver.features; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.logging.Logger; + +import javax.imageio.ImageIO; + +public class DDSConverter +{ + protected static final Logger LOG = Logger.getLogger(DDSConverter.class.getName()); + + protected static class Color + { + + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + if ((obj == null) || (getClass() != obj.getClass())) + { + return false; + } + Color color = (Color) obj; + if (b != color.b) + { + return false; + } + if (g != color.g) + { + return false; + } + return r == color.r; + } + + @Override + public int hashCode() + { + int i = r; + i = (29 * i) + g; + i = (29 * i) + b; + return i; + } + + protected int r; + protected int g; + protected int b; + + public Color() + { + r = g = b = 0; + } + + public Color(int i, int j, int k) + { + r = i; + g = j; + b = k; + } + } + + public static ByteBuffer convertToDDS(BufferedImage bufferedimage) + { + if (bufferedimage == null) + { + return null; + } + if (bufferedimage.getColorModel().hasAlpha()) + { + return convertToDxt3(bufferedimage); + } + return convertToDxt1NoTransparency(bufferedimage); + } + + public static ByteBuffer convertToDDS(File file) + { + if (file == null) + { + String s = "nullValue.FileIsNull"; + LOG.severe(s + " " + new IllegalArgumentException(s)); + new IllegalArgumentException(s); + return null; + } + if (!file.exists() || !file.canRead()) + { + String s1 = "DDSConverter.NoFileOrNoPermission"; + LOG.severe(s1 + " " + new IllegalArgumentException(s1)); + new IllegalArgumentException(s1); + return null; + } + BufferedImage bufferedimage = null; + try + { + bufferedimage = ImageIO.read(file); + } + catch (IOException e) + { + e.printStackTrace(); + //LOG.error("Error while reading Image that needs to be DDSConverted", e); + } + if (bufferedimage == null) + { + return null; + } + if (bufferedimage.getColorModel().hasAlpha()) + { + return convertToDxt3(bufferedimage); + } + return convertToDxt1NoTransparency(bufferedimage); + } + + public static ByteBuffer convertToDxt1NoTransparency(BufferedImage bufferedimage) + { + if (bufferedimage == null) + { + return null; + } + int ai[] = new int[16]; + int i = 128 + ((bufferedimage.getWidth() * bufferedimage.getHeight()) / 2); + ByteBuffer bytebuffer = ByteBuffer.allocate(i); + bytebuffer.order(ByteOrder.LITTLE_ENDIAN); + buildHeaderDxt1(bytebuffer, bufferedimage.getWidth(), bufferedimage.getHeight()); + int j = bufferedimage.getWidth() / 4; + int k = bufferedimage.getHeight() / 4; + for (int l = 0; l < k; l++) + { + for (int i1 = 0; i1 < j; i1++) + { + BufferedImage bufferedimage1 = bufferedimage.getSubimage(i1 * 4, l * 4, 4, 4); + bufferedimage1.getRGB(0, 0, 4, 4, ai, 0, 4); + Color acolor[] = getColors888(ai); + for (int j1 = 0; j1 < ai.length; j1++) + { + ai[j1] = getPixel565(acolor[j1]); + acolor[j1] = getColor565(ai[j1]); + } + + int ai1[] = determineExtremeColors(acolor); + if (ai[ai1[0]] < ai[ai1[1]]) + { + int k1 = ai1[0]; + ai1[0] = ai1[1]; + ai1[1] = k1; + } + bytebuffer.putShort((short) ai[ai1[0]]); + bytebuffer.putShort((short) ai[ai1[1]]); + long l1 = computeBitMask(acolor, ai1); + bytebuffer.putInt((int) l1); + } + + } + + return bytebuffer; + } + + public static ByteBuffer convertToDxt3(BufferedImage bufferedimage) + { + if (bufferedimage == null) + { + return null; + } + if (!bufferedimage.getColorModel().hasAlpha()) + { + return convertToDxt1NoTransparency(bufferedimage); + } + int ai[] = new int[16]; + int i = 128 + (bufferedimage.getWidth() * bufferedimage.getHeight()); + ByteBuffer bytebuffer = ByteBuffer.allocate(i); + bytebuffer.order(ByteOrder.LITTLE_ENDIAN); + buildHeaderDxt3(bytebuffer, bufferedimage.getWidth(), bufferedimage.getHeight()); + int j = bufferedimage.getWidth() / 4; + int k = bufferedimage.getHeight() / 4; + for (int l = 0; l < k; l++) + { + for (int i1 = 0; i1 < j; i1++) + { + BufferedImage bufferedimage1 = bufferedimage.getSubimage(i1 * 4, l * 4, 4, 4); + bufferedimage1.getRGB(0, 0, 4, 4, ai, 0, 4); + Color acolor[] = getColors888(ai); + for (int j1 = 0; j1 < ai.length; j1 += 2) + { + bytebuffer.put((byte) ((ai[j1] >>> 28) | (ai[j1 + 1] >>> 24))); + } + + for (int k1 = 0; k1 < ai.length; k1++) + { + ai[k1] = getPixel565(acolor[k1]); + acolor[k1] = getColor565(ai[k1]); + } + + int ai1[] = determineExtremeColors(acolor); + if (ai[ai1[0]] < ai[ai1[1]]) + { + int l1 = ai1[0]; + ai1[0] = ai1[1]; + ai1[1] = l1; + } + bytebuffer.putShort((short) ai[ai1[0]]); + bytebuffer.putShort((short) ai[ai1[1]]); + long l2 = computeBitMask(acolor, ai1); + bytebuffer.putInt((int) l2); + } + + } + + return bytebuffer; + } + + protected static void buildHeaderDxt1(ByteBuffer bytebuffer, int i, int j) + { + bytebuffer.rewind(); + bytebuffer.put((byte) 68); + bytebuffer.put((byte) 68); + bytebuffer.put((byte) 83); + bytebuffer.put((byte) 32); + bytebuffer.putInt(124); + int k = 0xa1007; + bytebuffer.putInt(k); + bytebuffer.putInt(j); + bytebuffer.putInt(i); + bytebuffer.putInt((i * j) / 2); + bytebuffer.putInt(0); + bytebuffer.putInt(0); + bytebuffer.position(bytebuffer.position() + 44); + bytebuffer.putInt(32); + bytebuffer.putInt(4); + bytebuffer.put((byte) 68); + bytebuffer.put((byte) 88); + bytebuffer.put((byte) 84); + bytebuffer.put((byte) 49); + bytebuffer.putInt(0); + bytebuffer.putInt(0); + bytebuffer.putInt(0); + bytebuffer.putInt(0); + bytebuffer.putInt(0); + bytebuffer.putInt(4096); + bytebuffer.putInt(0); + bytebuffer.position(bytebuffer.position() + 12); + } + + protected static void buildHeaderDxt3(ByteBuffer bytebuffer, int i, int j) + { + bytebuffer.rewind(); + bytebuffer.put((byte) 68); + bytebuffer.put((byte) 68); + bytebuffer.put((byte) 83); + bytebuffer.put((byte) 32); + bytebuffer.putInt(124); + int k = 0xa1007; + bytebuffer.putInt(k); + bytebuffer.putInt(j); + bytebuffer.putInt(i); + bytebuffer.putInt(i * j); + bytebuffer.putInt(0); + bytebuffer.putInt(0); + bytebuffer.position(bytebuffer.position() + 44); + bytebuffer.putInt(32); + bytebuffer.putInt(4); + bytebuffer.put((byte) 68); + bytebuffer.put((byte) 88); + bytebuffer.put((byte) 84); + bytebuffer.put((byte) 51); + bytebuffer.putInt(0); + bytebuffer.putInt(0); + bytebuffer.putInt(0); + bytebuffer.putInt(0); + bytebuffer.putInt(0); + bytebuffer.putInt(4096); + bytebuffer.putInt(0); + bytebuffer.position(bytebuffer.position() + 12); + } + + protected static int[] determineExtremeColors(Color acolor[]) + { + int i = 0x80000000; + int ai[] = new int[2]; + for (int j = 0; j < (acolor.length - 1); j++) + { + for (int k = j + 1; k < acolor.length; k++) + { + int l = distance(acolor[j], acolor[k]); + if (l > i) + { + i = l; + ai[0] = j; + ai[1] = k; + } + } + + } + + return ai; + } + + protected static long computeBitMask(Color acolor[], int ai[]) + { + Color acolor1[] = + { + null, + null, + new Color(), + new Color() + }; + acolor1[0] = acolor[ai[0]]; + acolor1[1] = acolor[ai[1]]; + if (acolor1[0].equals(acolor1[1])) + { + return 0L; + } + acolor1[2].r = ((2 * acolor1[0].r) + acolor1[1].r + 1) / 3; + acolor1[2].g = ((2 * acolor1[0].g) + acolor1[1].g + 1) / 3; + acolor1[2].b = ((2 * acolor1[0].b) + acolor1[1].b + 1) / 3; + acolor1[3].r = (acolor1[0].r + (2 * acolor1[1].r) + 1) / 3; + acolor1[3].g = (acolor1[0].g + (2 * acolor1[1].g) + 1) / 3; + acolor1[3].b = (acolor1[0].b + (2 * acolor1[1].b) + 1) / 3; + long l = 0L; + for (int i = 0; i < acolor.length; i++) + { + int j = 0x7fffffff; + int k = 0; + for (int i1 = 0; i1 < acolor1.length; i1++) + { + int j1 = distance(acolor[i], acolor1[i1]); + if (j1 < j) + { + j = j1; + k = i1; + } + } + + l |= k << (i * 2); + } + + return l; + } + + protected static int getPixel565(Color color) + { + int i = color.r >> 3; + int j = color.g >> 2; + int k = color.b >> 3; + return (i << 11) | (j << 5) | k; + } + + protected static Color getColor565(int i) + { + Color color = new Color(); + color.r = (int) (i & 63488L) >> 11; + color.g = (int) (i & 2016L) >> 5; + color.b = (int) (i & 31L); + return color; + } + + protected static Color[] getColors888(int ai[]) + { + Color acolor[] = new Color[ai.length]; + for (int i = 0; i < ai.length; i++) + { + acolor[i] = new Color(); + acolor[i].r = (int) (ai[i] & 0xff0000L) >> 16; + acolor[i].g = (int) (ai[i] & 65280L) >> 8; + acolor[i].b = (int) (ai[i] & 255L); + } + + return acolor; + } + + protected static int distance(Color color, Color color1) + { + return ((color1.r - color.r) * (color1.r - color.r)) + ((color1.g - color.g) * (color1.g - color.g)) + ((color1.b - color.b) * (color1.b - color.b)); + } +} Index: trunk/aCis_gameserver/java/net/sf/l2j/gameserver/features/ImageData.java =================================================================== --- trunk/aCis_gameserver/java/net/sf/l2j/gameserver/features/ImageData.java (revision 427) +++ trunk/aCis_gameserver/java/net/sf/l2j/gameserver/features/ImageData.java (revision 428) +/* + * 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.gameserver.features; + +import java.awt.image.BufferedImage; + +public class ImageData +{ + public ImageData() + { + } + + public BufferedImage image; + public String captchaText = ""; + public int captchaID = 0; +} Index: trunk/aCis_gameserver/java/net/sf/l2j/gameserver/features/Captcha.java =================================================================== --- trunk/aCis_gameserver/java/net/sf/l2j/gameserver/features/Captcha.java (revision 427) +++ trunk/aCis_gameserver/java/net/sf/l2j/gameserver/features/Captcha.java (revision 428) +package net.sf.l2j.gameserver.features; + +import java.awt.Color; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import net.sf.l2j.commons.random.Rnd; +import net.sf.l2j.gameserver.instancemanager.BotsPreventionManager.PlayerData; +import net.sf.l2j.gameserver.model.actor.instance.Player; + +/** + * Class that handles Generating and Sending Captcha Image to the Player + */ +public class Captcha +{ + private static final char[] CAPTCHA_TEXT_POSSIBILITIES = + { + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + 'G', + 'H', + 'K', + 'L', + 'M', + 'P', + 'R', + 'S', + 'T', + 'U', + 'W', + 'X', + 'Y', + 'Z' + }; + private static final int CAPTCHA_WORD_LENGTH = 5; + + private static final int CAPTCHA_MIN_ID = 19000; + private static final int CAPTCHA_MAX_ID = 25000; + + Captcha() + { + } + + public static Captcha getInstance() + { + return SingletonHolder._instance; + } + + private static class SingletonHolder + { + protected static final Captcha _instance = new Captcha(); + } + + public void generateCaptcha(PlayerData container, Player target) + { + int captchaId = generateRandomCaptchaId(); + char[] captchaText = generateCaptchaText(); + + container.image = generateCaptcha(captchaText); + // PledgeCrest packet = new PledgeCrest(captchaId, DDSConverter.convertToDDS(image).array()); + // target.sendPacket(packet); + + container.captchaID = captchaId; + container.captchaText = String.valueOf(captchaText); + } + char[] captchaText; + int captchaId; + + public synchronized Map<Integer, ImageData> createImageList() + { + Map<Integer, ImageData> _imageMap = new ConcurrentHashMap<>(); + for (int i = 0; i < 1000; i++) + { + do + { + captchaId = generateRandomCaptchaId(); + captchaText = generateCaptchaText(); + } + while (!_imageMap.isEmpty() && _imageMap.values().stream().anyMatch(txt -> txt.captchaText.equals(String.valueOf(captchaText))) || _imageMap.values().stream().anyMatch(s -> s.captchaID == captchaId)); + ImageData dt = new ImageData(); + dt.captchaID = captchaId; + dt.captchaText = String.valueOf(captchaText); + dt.image = generateCaptcha(captchaText); + _imageMap.put(i, dt); + } + return _imageMap; + } + + private static char[] generateCaptchaText() + { + char[] text = new char[CAPTCHA_WORD_LENGTH]; + for (int i = 0; i < CAPTCHA_WORD_LENGTH; i++) + text[i] = CAPTCHA_TEXT_POSSIBILITIES[Rnd.get(CAPTCHA_TEXT_POSSIBILITIES.length)]; + return text; + } + + private static int generateRandomCaptchaId() + { + return Rnd.get(CAPTCHA_MIN_ID, CAPTCHA_MAX_ID); + } + + public static BufferedImage generateCaptcha(char[] text) + { + Color textColor = new Color(38, 213, 30); + Color circleColor = new Color(73, 100, 151); + Font textFont = new Font("comic sans ms", Font.BOLD, 24); + int charsToPrint = 5; + int width = 256; + int height = 64; + int circlesToDraw = 8; + float horizMargin = 20.0f; + double rotationRange = 0.7; // this is radians + BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + + Graphics2D g = (Graphics2D) bufferedImage.getGraphics(); + + // Draw an oval + g.setColor(new Color(30, 31, 31)); + g.fillRect(0, 0, width, height); + + g.setColor(circleColor); + for (int i = 0; i < circlesToDraw; i++) + { + int circleRadius = (int) (Math.random() * height / 2.0); + int circleX = (int) (Math.random() * width - circleRadius); + int circleY = (int) (Math.random() * height - circleRadius); + g.drawOval(circleX, circleY, circleRadius * 2, circleRadius * 2); + } + + g.setColor(textColor); + g.setFont(textFont); + + FontMetrics fontMetrics = g.getFontMetrics(); + int maxAdvance = fontMetrics.getMaxAdvance(); + int fontHeight = fontMetrics.getHeight(); + + float spaceForLetters = -horizMargin * 2.0F + width; + float spacePerChar = spaceForLetters / (charsToPrint - 1.0f); + + for (int i = 0; i < charsToPrint; i++) + { + char characterToShow = text[i]; + + // this is a separate canvas used for the character so that + // we can rotate it independently + int charWidth = fontMetrics.charWidth(characterToShow); + int charDim = Math.max(maxAdvance, fontHeight); + int halfCharDim = charDim / 2; + + BufferedImage charImage = new BufferedImage(charDim, charDim, BufferedImage.TYPE_INT_ARGB); + Graphics2D charGraphics = charImage.createGraphics(); + charGraphics.translate(halfCharDim, halfCharDim); + double angle = (Math.random() - 0.5) * rotationRange; + charGraphics.transform(AffineTransform.getRotateInstance(angle)); + charGraphics.translate(-halfCharDim, -halfCharDim); + charGraphics.setColor(textColor); + charGraphics.setFont(textFont); + + int charX = (int) (0.5 * charDim - 0.5 * charWidth); + charGraphics.drawString(String.valueOf(characterToShow), charX, (charDim - fontMetrics.getAscent()) / 2 + fontMetrics.getAscent()); + + float x = horizMargin + spacePerChar * i - charDim / 2.0f; + int y = (height - charDim) / 2; + g.drawImage(charImage, (int) x, y, charDim, charDim, null, null); + + charGraphics.dispose(); + } + + g.dispose(); + + return bufferedImage; + } +}
Pastebin: https://pastebin.com/R1YEwSPW
Backup: https://pastebin.com/1Utdrbca
// Não testei // Créditos : AnotherPerson // Não dou suporte ao mesmo