diff --git a/.gitignore b/.gitignore
index 4788b4b..87d4436 100755
--- a/.gitignore
+++ b/.gitignore
@@ -110,4 +110,4 @@ buildNumber.properties
.flattened-pom.xml
# Common working directory
-run/
+run/
\ No newline at end of file
diff --git a/README.md b/README.md
index ccc13b6..b4f8d40 100644
--- a/README.md
+++ b/README.md
@@ -1,45 +1,58 @@
# FroggyMonitorReward
Плагин для награды игроков за голоса и отзывы на FroggyMonitor
-Плагин запускает сайт,
-на который будут приходить запросы от
-FroggyMonitor на поощрение игрока,
-плагин их читает и выполняет действие из конфига
-
[Скачать](https://github.com/MeexReay/FroggyMonitorReward/releases/latest)
## Конфиг
```yml
-site_host: localhost # IP адрес для сайта
-site_port: 8080 # Порт для сайта
-site_backlog: 0 # Максимальное кол-во подключений одновременно
+bind_host: 0.0.0.0 # Локальный IP адрес сервера (обычно такой же как и в server.properties)
+bind_port: 8080 # Свободный порт для сайта (потребуется открыть его на хостинге)
+
+external_host: example.com # Внешний IP адрес / домен сервера
secret_token: "ваш_секретный_токен" # Секретный токен с FroggyMonitor
-comment_page: "/api/comment" # Страница для награды за отзыв
-vote_page: "/api/vote" # Страница для награды за голос
-
-# Что указать в FroggyMonitor?
-# В URL для поощрения за отзыв:
-# http://{ip_сервера}:{site_port}{comment_page}
-# -> http://example.com:8080/api/comment
-# В URL для поощрения за голос:
-# http://{ip_сервера}:{site_port}{vote_page}
-# -> http://example.com:8080/api/vote
-# Также возможно понадобится открыть порт на хосте
-
vote: # Награда за голос
- vault: 10 # Выдать валюту (необяз.)
- item: "diamond 10" # Выдать предмет (необяз.) (забрать предмет нельзя)
- message: "Спасибо за голос!" # Отправить сообщение (необяз.)
- commands: # Исполнить команды (необяз.)
+ vault: 10 # Выдать валюту
+ item: "diamond 10" # Выдать предмет (забрать предмет нельзя)
+ message: "Спасибо за голос!" # Отправить сообщение
+ commands: # Исполнить команды
- "/title {player_name} subtitle на FroggyMonitor"
- "/title {player_name} title Спасибо за отзыв!"
+ # Каждый параметр наград не обязателен
-add_comment: # Награда за добавление отзыва
+add_comment: # Награда за удаление отзыва
vault: 10
message: "Спасибо за отзыв!"
del_comment: # Награда за удаление отзыва
vault: -10 # Снять валюту
+
+enable_logs: true # Включить логи плагина (true/false); true - вкл; false - выкл
+
+message_formatting: "ampersand" # Изменить тип форматирования сообщений
+ # Типы форматирования:
+ # ampersand: &cСообщение
+ # section: §cСообщение
+ # minimessage: Сообщение
+ # json: {"text": "Сообщение", "color": "red"}
```
+
+## Как это работает
+
+```mermaid
+sequenceDiagram
+ participant FroggyMonitor
+ participant Сервер
+ participant Сайт
+ participant Плагин
+ participant Vault
+ Сервер-->>Плагин: Запуск плагина
+ Плагин-->>Сайт: Запуск сайта
+ FroggyMonitor->>Сайт: Игрок проголосовал за сервер
+ Сайт->>Плагин: Голос игрока
+ Плагин->>Vault: Выдать валюту
+ Плагин->>Сервер: Выдать предмет
+ Плагин->>Сервер: Отправить сообщение
+ Плагин->>Сервер: Выполнить команды
+```
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 77f0beb..31af942 100755
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
ru.froggymonitor
rewardplugin
- 1.2
+ 1.3
jar
FroggyMonitorReward
@@ -100,5 +100,25 @@
2.11.5
provided
+
+ net.kyori
+ adventure-text-serializer-legacy
+ 4.16.0
+
+
+ net.kyori
+ adventure-text-serializer-gson
+ 4.16.0
+
+
+ net.kyori
+ adventure-text-minimessage
+ 4.16.0
+
+
+ net.kyori
+ adventure-api
+ 4.16.0
+
diff --git a/src/main/java/ru.froggymonitor/rewardplugin/Main.java b/src/main/java/ru.froggymonitor/rewardplugin/Main.java
index 8fb43f9..dd67752 100755
--- a/src/main/java/ru.froggymonitor/rewardplugin/Main.java
+++ b/src/main/java/ru.froggymonitor/rewardplugin/Main.java
@@ -2,26 +2,22 @@ package ru.froggymonitor.rewardplugin;
import net.milkbowl.vault.economy.Economy;
import org.bukkit.Bukkit;
-import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
-import org.bukkit.configuration.MemorySection;
-import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
-import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.player.PlayerJoinEvent;
-import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.io.IOException;
-import java.nio.file.Path;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.nio.file.Files;
import java.util.*;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
public final class Main extends JavaPlugin implements Listener {
public static Main me;
@@ -45,13 +41,22 @@ public final class Main extends JavaPlugin implements Listener {
public String secret_token;
- public String comment_page;
- public String vote_page;
+ public String external_host;
+
+ public boolean enable_logs;
+ public MessageFormatting message_formatting;
public Reward vote_reward;
public Reward add_comment_reward;
public Reward del_comment_reward;
+ public String vote_page;
+ public String comment_page;
+
+ public Map cache;
+
+ public File cache_file;
+
@Override
public void onEnable() {
if (!setupEconomy()) {
@@ -70,19 +75,31 @@ public final class Main extends JavaPlugin implements Listener {
conf = new UnrealConfig(this, "config.yml");
+ vote_page = "/api/vote";
+ comment_page = "/api/comment";
+
secret_token = (String) conf.get("secret_token");
+ external_host = (String) conf.get("external_host");
- comment_page = (String) conf.get("comment_page");
- vote_page = (String) conf.get("vote_page");
+ enable_logs = (Boolean) conf.get("enable_logs");
+ message_formatting = MessageFormatting.getFormatting((String) conf.get("message_formatting"));
- vote_reward = new Reward((Map) conf.get("vote"));
- add_comment_reward = new Reward((Map) conf.get("add_comment"));
- del_comment_reward = new Reward((Map) conf.get("del_comment"));
+ vote_reward = new Reward("vote", (Map) conf.get("vote"));
+ add_comment_reward = new Reward("add_comment", (Map) conf.get("add_comment"));
+ del_comment_reward = new Reward("del_comment", (Map) conf.get("del_comment"));
+
+ httpClient = HttpClient.newHttpClient();
+
+ sendRewardUrls();
+
+ cache_file = new File(getDataFolder().getPath(), "cache");
+
+ loadCache();
site = new SitePart(
- (String) conf.get("site_host"),
- ((Number) conf.get("site_port")).intValue(),
- ((Number) conf.get("site_backlog")).intValue());
+ (String) conf.get("bind_host"),
+ ((Number) conf.get("bind_port")).intValue(),
+ 0);
site.start();
@@ -92,6 +109,59 @@ public final class Main extends JavaPlugin implements Listener {
@Override
public void onDisable() {
site.stop();
+ saveCache();
+ }
+
+ @EventHandler
+ public void onJoin(PlayerJoinEvent e) {
+ Player p = e.getPlayer();
+ String n = p.getName();
+
+ if (cache.containsKey(n)) {
+ switch (cache.get(n)) {
+ case ("vote") -> vote_reward.later(p);
+ case ("add_comment") -> add_comment_reward.later(p);
+ case ("del_comment") -> del_comment_reward.later(p);
+ }
+
+ Main.me.cache.remove(n);
+ }
+ }
+
+ public void saveCache() {
+ if (cache.isEmpty()) {
+ cache_file.delete();
+ } else {
+ try {
+ if (!cache_file.exists())
+ cache_file.createNewFile();
+
+ StringBuilder text = new StringBuilder();
+ for (Map.Entry e : cache.entrySet())
+ text.append(e.getKey()).append("=").append(e.getValue()).append("\n");
+
+ Files.writeString(cache_file.toPath(), text.toString());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ public void loadCache() {
+ cache = new HashMap<>();
+
+ if (cache_file.exists()) {
+ try {
+ String text = Files.readString(cache_file.toPath());
+
+ for (String s : text.split("\n")) {
+ String[] ss = s.split("=");
+ cache.put(ss[0], ss[1]);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
}
public static OfflinePlayer getOfflinePlayer(String name) {
@@ -102,4 +172,25 @@ public final class Main extends JavaPlugin implements Listener {
}
return null;
}
+
+ public HttpClient httpClient;
+
+ public void sendRewardUrls() {
+ String start_url = "http://"+external_host+":"+site.port;
+
+ String body = "{\"secret_token\": \""+secret_token+"\", "+
+ "\"vote_url\": \""+start_url+vote_page+"\", "+
+ "\"comment_url\": \""+start_url+comment_page+"\"}";
+
+ try {
+ httpClient.send(HttpRequest.newBuilder()
+ .POST(HttpRequest.BodyPublishers.ofString(body))
+ .uri(URI.create("https://froggymonitor.ru/api/set_reward_urls"))
+ .build(), HttpResponse.BodyHandlers.ofString());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
}
diff --git a/src/main/java/ru.froggymonitor/rewardplugin/MessageFormatting.java b/src/main/java/ru.froggymonitor/rewardplugin/MessageFormatting.java
new file mode 100644
index 0000000..1bfd5a5
--- /dev/null
+++ b/src/main/java/ru.froggymonitor/rewardplugin/MessageFormatting.java
@@ -0,0 +1,43 @@
+package ru.froggymonitor.rewardplugin;
+
+import net.kyori.adventure.text.TextComponent;
+import net.kyori.adventure.text.minimessage.MiniMessage;
+import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
+import net.kyori.adventure.text.serializer.json.JSONComponentSerializer;
+import net.md_5.bungee.api.chat.BaseComponent;
+import net.md_5.bungee.chat.ComponentSerializer;
+
+public enum MessageFormatting {
+ AMPERSAND("ampersand", (str) -> LegacyComponentSerializer.legacyAmpersand().deserialize(str)),
+ SECTION("section", (str) -> LegacyComponentSerializer.legacySection().deserialize(str)),
+ MINIMESSAGE("minimessage", (str) -> (TextComponent) MiniMessage.miniMessage().deserialize(str)),
+ JSON("json", (str) -> (TextComponent) JSONComponentSerializer.json().deserialize(str));
+
+ public interface MessageFormat {
+ TextComponent format(String input);
+ }
+
+ private MessageFormat format_func;
+ private String name;
+ MessageFormatting(String name, MessageFormat format) {
+ this.name = name;
+ this.format_func = format;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public BaseComponent[] format(String str) {
+ return ComponentSerializer.parse(JSONComponentSerializer.json().serialize(format_func.format(str)));
+ }
+
+ public static MessageFormatting getFormatting(String name) {
+ for (MessageFormatting f : values()) {
+ if (f.getName().startsWith(name.toLowerCase())) {
+ return f;
+ }
+ }
+ return SECTION;
+ }
+}
diff --git a/src/main/java/ru.froggymonitor/rewardplugin/Reward.java b/src/main/java/ru.froggymonitor/rewardplugin/Reward.java
index a9af00d..ef44d6b 100644
--- a/src/main/java/ru.froggymonitor/rewardplugin/Reward.java
+++ b/src/main/java/ru.froggymonitor/rewardplugin/Reward.java
@@ -14,10 +14,12 @@ import java.util.Map;
import static org.bukkit.Bukkit.getServer;
public class Reward {
+ public String name;
public Map data;
- public Reward(Map data) {
+ public Reward(String name, Map data) {
this.data = data;
+ this.name = name;
}
public void execute(String nickname) {
@@ -30,8 +32,9 @@ public class Reward {
player.getInventory().addItem(item);
}
if (data.containsKey("message")) {
- player.sendMessage(PlaceholderAPI.setPlaceholders(player, (String) data.get("message")));
+ player.spigot().sendMessage(Main.me.message_formatting.format(PlaceholderAPI.setPlaceholders(player, (String) data.get("message"))));
}
+ Main.me.cache.put(nickname, name);
}
OfflinePlayer offlinePlayer = player != null ? player : Main.getOfflinePlayer(nickname);
@@ -49,4 +52,15 @@ public class Reward {
}
}
}
+
+ public void later(Player player) {
+ if (data.containsKey("item")) {
+ String[] ss = ((String)data.get("item")).split(" ");
+ ItemStack item = new ItemStack(Material.valueOf(ss[0].toUpperCase()), ss.length == 1 ? 1 : Integer.parseInt(ss[1]));
+ player.getInventory().addItem(item);
+ }
+ if (data.containsKey("message")) {
+ player.spigot().sendMessage(Main.me.message_formatting.format(PlaceholderAPI.setPlaceholders(player, (String) data.get("message"))));
+ }
+ }
}
diff --git a/src/main/java/ru.froggymonitor/rewardplugin/SitePart.java b/src/main/java/ru.froggymonitor/rewardplugin/SitePart.java
index 4f32615..4ddbd6d 100755
--- a/src/main/java/ru.froggymonitor/rewardplugin/SitePart.java
+++ b/src/main/java/ru.froggymonitor/rewardplugin/SitePart.java
@@ -3,21 +3,23 @@ package ru.froggymonitor.rewardplugin;
import com.google.common.base.Charsets;
import com.google.common.hash.Hashing;
import com.sun.net.httpserver.HttpExchange;
-import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
-import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-import java.util.List;
import java.util.Map;
public class SitePart extends FormDataHandler {
public HttpServer server;
+ public String host;
+ public int port;
+
public SitePart(String host, int port, int backlog) {
+ this.host = host;
+ this.port = port;
+
try {
server = HttpServer.create(new InetSocketAddress(host,port),backlog);
server.createContext("/",this);
@@ -29,6 +31,8 @@ public class SitePart extends FormDataHandler {
public void start() {
server.start();
+
+ if (Main.me.enable_logs) Main.me.getLogger().info("Site started at "+host+":"+port);
}
public void stop() {
@@ -47,8 +51,6 @@ public class SitePart extends FormDataHandler {
String method = e.getRequestMethod();
String path = e.getRequestURI().getPath();
-// System.out.println(response+" "+status_code+" "+path+" "+method);
-
if (method.equals("GET")) {
if (path.equals(Main.me.vote_page)) {
if (params.containsKey("nickname") &&
@@ -62,6 +64,8 @@ public class SitePart extends FormDataHandler {
Main.me.vote_reward.execute(nickname);
response = "ok";
status_code = 200;
+
+ if (Main.me.enable_logs) Main.me.getLogger().info("Reward \"vote\" gave to player "+nickname);
}
}
} else if (path.equals(Main.me.comment_page)) {
@@ -82,11 +86,15 @@ public class SitePart extends FormDataHandler {
response = "ok";
status_code = 200;
+
+ if (Main.me.enable_logs) Main.me.getLogger().info("Reward \"add_comment\" gave to player "+nickname);
} else if (type.equals("delete")) {
Main.me.del_comment_reward.execute(nickname);
response = "ok";
status_code = 200;
+
+ if (Main.me.enable_logs) Main.me.getLogger().info("Reward \"del_comment\" gave to player "+nickname);
}
}
}
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index d076c4f..8b2b054 100755
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -1,28 +1,31 @@
-site_host: localhost # IP адрес для сайта
-site_port: 8080 # Порт для сайта
-site_backlog: 0 # Максимальное кол-во подключений одновременно
+bind_host: 0.0.0.0 # Локальный IP адрес сервера (обычно такой же как и в server.properties)
+bind_port: 8080 # Свободный порт для сайта (потребуется открыть его на хостинге)
+
+external_host: example.com # Внешний IP адрес / домен сервера
secret_token: "ваш_секретный_токен" # Секретный токен с FroggyMonitor
-comment_page: "/api/comment" # Страница для награды за отзыв
-vote_page: "/api/vote" # Страница для награды за голос
-
-# Что указать в FroggyMonitor?
-# В URL для поощрения за отзыв: http://{ip_сервера}:{site_port}{comment_page} -> http://example.com:8080/api/comment
-# В URL для поощрения за голос: http://{ip_сервера}:{site_port}{vote_page} -> http://example.com:8080/api/vote
-# Также возможно понадобится открыть порт на хосте
-
vote: # Награда за голос
- vault: 10 # Выдать валюту (необяз.)
- item: "diamond 10" # Выдать предмет (необяз.) (забрать предмет нельзя)
- message: "Спасибо за голос!" # Отправить сообщение (необяз.)
- commands: # Исполнить команды (необяз.)
+ vault: 10 # Выдать валюту
+ item: "diamond 10" # Выдать предмет (забрать предмет нельзя)
+ message: "Спасибо за голос!" # Отправить сообщение
+ commands: # Исполнить команды
- "/title {player_name} subtitle на FroggyMonitor"
- "/title {player_name} title Спасибо за отзыв!"
+ # Каждый параметр наград не обязателен
add_comment: # Награда за удаление отзыва
vault: 10
message: "Спасибо за отзыв!"
del_comment: # Награда за удаление отзыва
- vault: -10 # Снять валюту
\ No newline at end of file
+ vault: -10 # Снять валюту
+
+enable_logs: true # Включить логи плагина (true/false); true - вкл; false - выкл
+
+message_formatting: "ampersand" # Изменить тип форматирования сообщений
+ # Типы форматирования:
+ # ampersand: &cСообщение
+ # section: §cСообщение
+ # minimessage: Сообщение
+ # json: {"text": "Сообщение", "color": "red"}