some update (informativno)

This commit is contained in:
MeexReay 2024-03-24 00:34:35 +03:00
parent 436d61c68b
commit 854e66073e
8 changed files with 262 additions and 70 deletions

2
.gitignore vendored
View File

@ -110,4 +110,4 @@ buildNumber.properties
.flattened-pom.xml .flattened-pom.xml
# Common working directory # Common working directory
run/ run/

View File

@ -1,45 +1,58 @@
# FroggyMonitorReward # FroggyMonitorReward
Плагин для награды игроков за голоса и отзывы на FroggyMonitor Плагин для награды игроков за голоса и отзывы на FroggyMonitor
Плагин запускает сайт,
на который будут приходить запросы от
FroggyMonitor на поощрение игрока,
плагин их читает и выполняет действие из конфига
[Скачать](https://github.com/MeexReay/FroggyMonitorReward/releases/latest) [Скачать](https://github.com/MeexReay/FroggyMonitorReward/releases/latest)
## Конфиг ## Конфиг
```yml ```yml
site_host: localhost # IP адрес для сайта bind_host: 0.0.0.0 # Локальный IP адрес сервера (обычно такой же как и в server.properties)
site_port: 8080 # Порт для сайта bind_port: 8080 # Свободный порт для сайта (потребуется открыть его на хостинге)
site_backlog: 0 # Максимальное кол-во подключений одновременно
external_host: example.com # Внешний IP адрес / домен сервера
secret_token: "ваш_секретный_токен" # Секретный токен с FroggyMonitor 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: # Награда за голос vote: # Награда за голос
vault: 10 # Выдать валюту (необяз.) vault: 10 # Выдать валюту
item: "diamond 10" # Выдать предмет (необяз.) (забрать предмет нельзя) item: "diamond 10" # Выдать предмет (забрать предмет нельзя)
message: "Спасибо за голос!" # Отправить сообщение (необяз.) message: "Спасибо за голос!" # Отправить сообщение
commands: # Исполнить команды (необяз.) commands: # Исполнить команды
- "/title {player_name} subtitle на FroggyMonitor" - "/title {player_name} subtitle на FroggyMonitor"
- "/title {player_name} title Спасибо за отзыв!" - "/title {player_name} title Спасибо за отзыв!"
# Каждый параметр наград не обязателен
add_comment: # Награда за добавление отзыва add_comment: # Награда за удаление отзыва
vault: 10 vault: 10
message: "Спасибо за отзыв!" message: "Спасибо за отзыв!"
del_comment: # Награда за удаление отзыва del_comment: # Награда за удаление отзыва
vault: -10 # Снять валюту vault: -10 # Снять валюту
enable_logs: true # Включить логи плагина (true/false); true - вкл; false - выкл
message_formatting: "ampersand" # Изменить тип форматирования сообщений
# Типы форматирования:
# ampersand: &cСообщение
# section: §cСообщение
# minimessage: <red>Сообщение</red>
# json: {"text": "Сообщение", "color": "red"}
``` ```
## Как это работает
```mermaid
sequenceDiagram
participant FroggyMonitor
participant Сервер
participant Сайт
participant Плагин
participant Vault
Сервер-->>Плагин: Запуск плагина
Плагин-->>Сайт: Запуск сайта
FroggyMonitor->>Сайт: Игрок проголосовал за сервер
Сайт->>Плагин: Голос игрока
Плагин->>Vault: Выдать валюту
Плагин->>Сервер: Выдать предмет
Плагин->>Сервер: Отправить сообщение
Плагин->>Сервер: Выполнить команды
```

22
pom.xml
View File

@ -6,7 +6,7 @@
<groupId>ru.froggymonitor</groupId> <groupId>ru.froggymonitor</groupId>
<artifactId>rewardplugin</artifactId> <artifactId>rewardplugin</artifactId>
<version>1.2</version> <version>1.3</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>FroggyMonitorReward</name> <name>FroggyMonitorReward</name>
@ -100,5 +100,25 @@
<version>2.11.5</version> <version>2.11.5</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-text-serializer-legacy</artifactId>
<version>4.16.0</version>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-text-serializer-gson</artifactId>
<version>4.16.0</version>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-text-minimessage</artifactId>
<version>4.16.0</version>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-api</artifactId>
<version>4.16.0</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -2,26 +2,22 @@ package ru.froggymonitor.rewardplugin;
import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.economy.Economy;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.configuration.MemorySection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.player.PlayerJoinEvent; 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.RegisteredServiceProvider;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import java.io.File; import java.io.File;
import java.io.IOException; 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.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public final class Main extends JavaPlugin implements Listener { public final class Main extends JavaPlugin implements Listener {
public static Main me; public static Main me;
@ -45,13 +41,22 @@ public final class Main extends JavaPlugin implements Listener {
public String secret_token; public String secret_token;
public String comment_page; public String external_host;
public String vote_page;
public boolean enable_logs;
public MessageFormatting message_formatting;
public Reward vote_reward; public Reward vote_reward;
public Reward add_comment_reward; public Reward add_comment_reward;
public Reward del_comment_reward; public Reward del_comment_reward;
public String vote_page;
public String comment_page;
public Map<String, String> cache;
public File cache_file;
@Override @Override
public void onEnable() { public void onEnable() {
if (!setupEconomy()) { if (!setupEconomy()) {
@ -70,19 +75,31 @@ public final class Main extends JavaPlugin implements Listener {
conf = new UnrealConfig(this, "config.yml"); conf = new UnrealConfig(this, "config.yml");
vote_page = "/api/vote";
comment_page = "/api/comment";
secret_token = (String) conf.get("secret_token"); secret_token = (String) conf.get("secret_token");
external_host = (String) conf.get("external_host");
comment_page = (String) conf.get("comment_page"); enable_logs = (Boolean) conf.get("enable_logs");
vote_page = (String) conf.get("vote_page"); message_formatting = MessageFormatting.getFormatting((String) conf.get("message_formatting"));
vote_reward = new Reward((Map<String, Object>) conf.get("vote")); vote_reward = new Reward("vote", (Map<String, Object>) conf.get("vote"));
add_comment_reward = new Reward((Map<String, Object>) conf.get("add_comment")); add_comment_reward = new Reward("add_comment", (Map<String, Object>) conf.get("add_comment"));
del_comment_reward = new Reward((Map<String, Object>) conf.get("del_comment")); del_comment_reward = new Reward("del_comment", (Map<String, Object>) conf.get("del_comment"));
httpClient = HttpClient.newHttpClient();
sendRewardUrls();
cache_file = new File(getDataFolder().getPath(), "cache");
loadCache();
site = new SitePart( site = new SitePart(
(String) conf.get("site_host"), (String) conf.get("bind_host"),
((Number) conf.get("site_port")).intValue(), ((Number) conf.get("bind_port")).intValue(),
((Number) conf.get("site_backlog")).intValue()); 0);
site.start(); site.start();
@ -92,6 +109,59 @@ public final class Main extends JavaPlugin implements Listener {
@Override @Override
public void onDisable() { public void onDisable() {
site.stop(); 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<String, String> 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) { public static OfflinePlayer getOfflinePlayer(String name) {
@ -102,4 +172,25 @@ public final class Main extends JavaPlugin implements Listener {
} }
return null; 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);
}
}
} }

View File

@ -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;
}
}

View File

@ -14,10 +14,12 @@ import java.util.Map;
import static org.bukkit.Bukkit.getServer; import static org.bukkit.Bukkit.getServer;
public class Reward { public class Reward {
public String name;
public Map<String,Object> data; public Map<String,Object> data;
public Reward(Map<String,Object> data) { public Reward(String name, Map<String,Object> data) {
this.data = data; this.data = data;
this.name = name;
} }
public void execute(String nickname) { public void execute(String nickname) {
@ -30,8 +32,9 @@ public class Reward {
player.getInventory().addItem(item); player.getInventory().addItem(item);
} }
if (data.containsKey("message")) { 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); 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"))));
}
}
} }

View File

@ -3,21 +3,23 @@ package ru.froggymonitor.rewardplugin;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.hash.Hashing; import com.google.common.hash.Hashing;
import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer; import com.sun.net.httpserver.HttpServer;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
public class SitePart extends FormDataHandler { public class SitePart extends FormDataHandler {
public HttpServer server; public HttpServer server;
public String host;
public int port;
public SitePart(String host, int port, int backlog) { public SitePart(String host, int port, int backlog) {
this.host = host;
this.port = port;
try { try {
server = HttpServer.create(new InetSocketAddress(host,port),backlog); server = HttpServer.create(new InetSocketAddress(host,port),backlog);
server.createContext("/",this); server.createContext("/",this);
@ -29,6 +31,8 @@ public class SitePart extends FormDataHandler {
public void start() { public void start() {
server.start(); server.start();
if (Main.me.enable_logs) Main.me.getLogger().info("Site started at "+host+":"+port);
} }
public void stop() { public void stop() {
@ -47,8 +51,6 @@ public class SitePart extends FormDataHandler {
String method = e.getRequestMethod(); String method = e.getRequestMethod();
String path = e.getRequestURI().getPath(); String path = e.getRequestURI().getPath();
// System.out.println(response+" "+status_code+" "+path+" "+method);
if (method.equals("GET")) { if (method.equals("GET")) {
if (path.equals(Main.me.vote_page)) { if (path.equals(Main.me.vote_page)) {
if (params.containsKey("nickname") && if (params.containsKey("nickname") &&
@ -62,6 +64,8 @@ public class SitePart extends FormDataHandler {
Main.me.vote_reward.execute(nickname); Main.me.vote_reward.execute(nickname);
response = "ok"; response = "ok";
status_code = 200; 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)) { } else if (path.equals(Main.me.comment_page)) {
@ -82,11 +86,15 @@ public class SitePart extends FormDataHandler {
response = "ok"; response = "ok";
status_code = 200; status_code = 200;
if (Main.me.enable_logs) Main.me.getLogger().info("Reward \"add_comment\" gave to player "+nickname);
} else if (type.equals("delete")) { } else if (type.equals("delete")) {
Main.me.del_comment_reward.execute(nickname); Main.me.del_comment_reward.execute(nickname);
response = "ok"; response = "ok";
status_code = 200; status_code = 200;
if (Main.me.enable_logs) Main.me.getLogger().info("Reward \"del_comment\" gave to player "+nickname);
} }
} }
} }

View File

@ -1,28 +1,31 @@
site_host: localhost # IP адрес для сайта bind_host: 0.0.0.0 # Локальный IP адрес сервера (обычно такой же как и в server.properties)
site_port: 8080 # Порт для сайта bind_port: 8080 # Свободный порт для сайта (потребуется открыть его на хостинге)
site_backlog: 0 # Максимальное кол-во подключений одновременно
external_host: example.com # Внешний IP адрес / домен сервера
secret_token: аш_секретный_токен" # Секретный токен с FroggyMonitor 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: # Награда за голос vote: # Награда за голос
vault: 10 # Выдать валюту (необяз.) vault: 10 # Выдать валюту
item: "diamond 10" # Выдать предмет (необяз.) (забрать предмет нельзя) item: "diamond 10" # Выдать предмет (забрать предмет нельзя)
message: "Спасибо за голос!" # Отправить сообщение (необяз.) message: "Спасибо за голос!" # Отправить сообщение
commands: # Исполнить команды (необяз.) commands: # Исполнить команды
- "/title {player_name} subtitle на FroggyMonitor" - "/title {player_name} subtitle на FroggyMonitor"
- "/title {player_name} title Спасибо за отзыв!" - "/title {player_name} title Спасибо за отзыв!"
# Каждый параметр наград не обязателен
add_comment: # Награда за удаление отзыва add_comment: # Награда за удаление отзыва
vault: 10 vault: 10
message: "Спасибо за отзыв!" message: "Спасибо за отзыв!"
del_comment: # Награда за удаление отзыва del_comment: # Награда за удаление отзыва
vault: -10 # Снять валюту vault: -10 # Снять валюту
enable_logs: true # Включить логи плагина (true/false); true - вкл; false - выкл
message_formatting: "ampersand" # Изменить тип форматирования сообщений
# Типы форматирования:
# ampersand: &cСообщение
# section: §cСообщение
# minimessage: <red>Сообщение</red>
# json: {"text": "Сообщение", "color": "red"}