/* * L2Servers.top — in-game vote reward command (example for L2J Mobius). * https://l2servers.top/developers/ * * The player votes on https://l2servers.top/vote// and then types .vote in game. * The server asks the L2Servers.top API whether this character (or the player's IP) voted * in the last 12 hours and gives the reward once per vote. * * Install: * 1. Save as dist/game/data/scripts/handlers/voicedcommandhandlers/L2ServersVote.java * 2. Register in handlers/MasterHandler.java (VOICED_COMMAND_HANDLERS list): L2ServersVote.class, * 3. Set SERVER_ID and API_KEY below (L2Servers.top → your server card → Votes). * 4. Rebuild / restart. Requires Java 11+. * * Other packs (aCis, L2Scripts, Lucera): the logic is the same — adapt the handler interface, * the "give item" call and the per-account storage. */ package handlers.voicedcommandhandlers; import java.net.URI; import java.net.URLEncoder; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.gameserver.handler.IVoicedCommandHandler; import org.l2jmobius.gameserver.model.actor.Player; public class L2ServersVote implements IVoicedCommandHandler { // ---- CONFIG ---- private static final int SERVER_ID = 0; // Server ID from L2Servers.top private static final String API_KEY = "PASTE_YOUR_API_KEY_HERE"; private static final int[][] REWARD = { { 57, 1_000_000 } }; // { itemId, count } // ---------------- private static final String API = "https://l2servers.top/api/vote-check"; private static final String VAR = "L2S_VOTE_CLAIMED"; // last claimed voted_at (per account) private static final Pattern VOTED_AT = Pattern.compile("\"voted_at\"\\s*:\\s*\"([^\"]+)\""); private static final HttpClient HTTP = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(5)).build(); private static final String[] COMMANDS = { "vote" }; @Override public boolean useVoicedCommand(String command, Player player, String params) { player.sendMessage("Checking your vote on L2Servers.top..."); final String name = player.getName(); final String ip = (player.getClient() != null) ? player.getClient().getIp() : ""; // HTTP must not block the game thread. ThreadPool.execute(() -> { String votedAt = check("username", name); if (votedAt == null && !ip.isEmpty()) { votedAt = check("ip", ip); } if (votedAt == null) { player.sendMessage("No vote found in the last 12 hours. Vote here: https://l2servers.top/top/"); return; } synchronized (player) { if (votedAt.equals(player.getAccountVariables().getString(VAR, ""))) { player.sendMessage("You already received the reward for this vote. Vote again in 12 hours!"); return; } player.getAccountVariables().set(VAR, votedAt); player.getAccountVariables().storeMe(); for (int[] item : REWARD) { // Older Mobius versions: player.addItem("L2ServersVote", item[0], item[1], player, true); player.addItem(org.l2jmobius.gameserver.model.item.enums.ItemProcessType.REWARD, item[0], item[1], player, true); } player.sendMessage("Thank you for voting on L2Servers.top!"); } }); return true; } /** * @return voted_at (ISO date) if a vote exists in the last 12 hours, otherwise null. */ private static String check(String field, String value) { try { final String url = API + "?server=" + SERVER_ID + "&key=" + URLEncoder.encode(API_KEY, StandardCharsets.UTF_8) + "&" + field + "=" + URLEncoder.encode(value, StandardCharsets.UTF_8); final HttpResponse res = HTTP.send(HttpRequest.newBuilder(URI.create(url)).timeout(Duration.ofSeconds(8)).GET().build(), HttpResponse.BodyHandlers.ofString()); if ((res.statusCode() != 200) || !res.body().contains("\"voted\":true")) { return null; } final Matcher m = VOTED_AT.matcher(res.body()); return m.find() ? m.group(1) : null; } catch (Exception e) { return null; } } @Override public String[] getVoicedCommandList() { return COMMANDS; } }