plugins/Sklep/config.ymlNowy plik, 7 linii
12przedmioty:3 vip-30:4 - "lp user {gracz} parent addtemp vip 30d"5 - "tellraw {gracz} {\"text\":\"Dziękujemy za VIP-a!\",\"color\":\"gold\"}"6 diamenty-64:7 - "give {gracz} minecraft:diamond 64"
SklepCommand.javaNowy plik, 40 linii
1public final class SklepCommand implements BasicCommand {2 3 private final JavaPlugin plugin;4 private final HttpClient http = HttpClient.newHttpClient();5 private final String api;6 private final String token;7 8 public SklepCommand(JavaPlugin plugin, String api, String token) {9 this.plugin = plugin;10 this.api = api;11 this.token = token;12 }13 14 @Override15 public void execute(CommandSourceStack source, String[] args) {16 if (!(source.getExecutor() instanceof Player player) || args.length != 1) {17 source.getSender().sendRichMessage("<gray>Użycie: /sklep <przedmiot>");18 return;19 }20 JsonObject body = new JsonObject();21 body.addProperty("gracz_uuid", player.getUniqueId().toString());22 body.addProperty("gracz_nick", player.getName());23 body.addProperty("przedmiot", args[0]);24 HttpRequest request = HttpRequest.newBuilder(URI.create(api + "/zamowienia"))25 .header("Authorization", "Bearer " + token)26 .header("Content-Type", "application/json")27 .POST(HttpRequest.BodyPublishers.ofString(body.toString()))28 .build();29 http.sendAsync(request, HttpResponse.BodyHandlers.ofString()).thenAccept(response ->30 Bukkit.getScheduler().runTask(plugin, () -> {31 if (response.statusCode() != 201) {32 player.sendRichMessage("<red>Nie udało się otworzyć zamówienia. Spróbuj za chwilę.");33 return;34 }35 String link = JsonParser.parseString(response.body()).getAsJsonObject().get("link").getAsString();36 player.sendMessage(Component.text("Kliknij, żeby zapłacić (link działa 60 minut)", NamedTextColor.GREEN)37 .clickEvent(ClickEvent.openUrl(link)));38 }));39 }40}
platnosc.sqlNowy plik, 4 linie
12UPDATE zamowienia3 SET oplacone_at = now(), stan_dostawy = 'w_kolejce'4 WHERE id = $1 AND oplacone_at IS NULL;
rcon.pyNowy plik, 42 linie
1import socket2import struct3 4 5class Rcon:6 """Klient RCON Minecrafta: pakiety little-endian, typ 3 to logowanie, typ 2 to komenda."""7 8 def __init__(self, host: str, port: int, password: str) -> None:9 self.sock = socket.create_connection((host, port), timeout=5)10 self.next_id = 011 request_id = self._send(3, password)12 reply_id, _ = self._read()13 if reply_id == -1 or reply_id != request_id:14 raise PermissionError("RCON: złe hasło")15 16 def _send(self, kind: int, payload: str) -> int:17 self.next_id += 118 body = struct.pack("<ii", self.next_id, kind) + payload.encode("utf-8") + b"\x00\x00"19 self.sock.sendall(struct.pack("<i", len(body)) + body)20 return self.next_id21 22 def _read(self) -> tuple[int, str]:23 (length,) = struct.unpack("<i", self._exact(4))24 data = self._exact(length)25 request_id, _kind = struct.unpack("<ii", data[:8])26 return request_id, data[8:-2].decode("utf-8", "replace")27 28 def _exact(self, size: int) -> bytes:29 chunks = b""30 while len(chunks) < size:31 chunk = self.sock.recv(size - len(chunks))32 if not chunk:33 raise ConnectionError("RCON: połączenie zamknięte")34 chunks += chunk35 return chunks36 37 def command(self, command: str) -> str:38 request_id = self._send(2, command)39 reply_id, text = self._read()40 if reply_id != request_id:41 raise RuntimeError("RCON: odpowiedź na inne żądanie")42 return text
dostawy.sqlNowy plik, 21 linii
12WITH due AS (3 SELECT id FROM zamowienia4 WHERE serwer_id = $15 AND (stan_dostawy = 'w_kolejce'6 OR (stan_dostawy = 'wydzierzawione' AND dzierzawa_do < now()))7 ORDER BY oplacone_at8 LIMIT 509 FOR UPDATE SKIP LOCKED10)11UPDATE zamowienia z12 SET stan_dostawy = 'wydzierzawione', dzierzawa_token = $2,13 dzierzawa_do = now() + interval '10 minutes', proby = z.proby + 114 FROM due WHERE z.id = due.id15RETURNING z.id, z.gracz_uuid, z.klucz, z.proby;16 1718UPDATE zamowienia19 SET stan_dostawy = 'dostarczone', dostarczone_at = now()20 WHERE id = $1 AND serwer_id = $2 AND dzierzawa_token = $321 AND stan_dostawy = 'wydzierzawione';
Dostawy.javaNowy plik, 61 linii
1public final class Dostawy {2 3 private final JavaPlugin plugin;4 private final HttpClient http = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10)).build();5 private final String api; 6 private final String token; 7 8 public Dostawy(JavaPlugin plugin, String api, String token) {9 this.plugin = plugin;10 this.api = api;11 this.token = token;12 }13 14 public void start() {15 Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, this::pobierz, 20L, 20L * 15);16 }17 18 private void pobierz() {19 JsonObject lease = post("/dostawy/dzierzawa", "{}");20 if (lease == null) return;21 String leaseToken = lease.get("lease_token").getAsString();22 for (JsonElement element : lease.getAsJsonArray("dostawy")) {23 JsonObject dostawa = element.getAsJsonObject();24 UUID gracz = UUID.fromString(dostawa.get("gracz_uuid").getAsString());25 String klucz = dostawa.get("klucz").getAsString();26 String id = dostawa.get("id").getAsString();27 Bukkit.getScheduler().runTask(plugin, () -> nadaj(leaseToken, id, gracz, klucz));28 }29 }30 31 32 private void nadaj(String leaseToken, String id, UUID uuid, String klucz) {33 Player player = Bukkit.getPlayer(uuid);34 if (player == null) return; 35 List<String> komendy = plugin.getConfig().getStringList("przedmioty." + klucz);36 boolean wszystkie = !komendy.isEmpty();37 for (String komenda : komendy) {38 wszystkie &= Bukkit.dispatchCommand(Bukkit.getConsoleSender(), komenda.replace("{gracz}", player.getName()));39 }40 String uwaga = wszystkie ? "nadano" : "nieznany klucz albo komenda";41 Bukkit.getScheduler().runTaskAsynchronously(plugin, () ->42 post("/dostawy/" + id + "/potwierdz", "{\"lease_token\":\"" + leaseToken + "\",\"uwaga\":\"" + uwaga + "\"}"));43 }44 45 private JsonObject post(String path, String body) {46 try {47 HttpRequest request = HttpRequest.newBuilder(URI.create(api + path))48 .timeout(Duration.ofSeconds(15))49 .header("Authorization", "Bearer " + token)50 .header("Content-Type", "application/json")51 .POST(HttpRequest.BodyPublishers.ofString(body))52 .build();53 HttpResponse<String> response = http.send(request, HttpResponse.BodyHandlers.ofString());54 if (response.statusCode() != 200) return null;55 return JsonParser.parseString(response.body()).getAsJsonObject();56 } catch (Exception e) {57 plugin.getLogger().fine("Sklep niedostępny, spróbuję za 15 s: " + e.getMessage());58 return null;59 }60 }61}