From da06bc595252c4ea0f528b74d068f8c97c34c7e7 Mon Sep 17 00:00:00 2001
From: link1107 <66795347+link1107@users.noreply.github.com>
Date: Sat, 22 Jan 2022 20:02:36 +0100
Subject: [PATCH] Initial commit
---
.gitignore | 113 ++++
pom.xml | 92 +++
.../DonationAlerts/DonationAlerts.java | 103 ++++
.../igorlink/command/AbstractCommand.java | 30 +
.../igorlink/command/DonateSubCommand.java | 43 ++
.../command/DonationExecutorCommand.java | 68 +++
.../igorlink/command/FilterSubCommand.java | 26 +
.../igorlink/command/ReloadSubCommand.java | 16 +
.../donationexecutor/DonationExecutor.java | 64 ++
.../donationexecutor/EventListener.java | 44 ++
.../igorlink/donationexecutor/Executor.java | 315 ++++++++++
.../executionsstaff/Donation.java | 53 ++
.../executionsstaff/GiantMobManager.java | 577 ++++++++++++++++++
.../ListOfStreamerPlayers.java | 79 +++
.../executionsstaff/StreamerPlayer.java | 109 ++++
.../java/igorlink/service/MainConfig.java | 118 ++++
src/main/java/igorlink/service/Utils.java | 248 ++++++++
src/main/resources/config.yml | 96 +++
src/main/resources/plugin.yml | 15 +
19 files changed, 2209 insertions(+)
create mode 100644 .gitignore
create mode 100644 pom.xml
create mode 100644 src/main/java/igorlink/DonationAlerts/DonationAlerts.java
create mode 100644 src/main/java/igorlink/command/AbstractCommand.java
create mode 100644 src/main/java/igorlink/command/DonateSubCommand.java
create mode 100644 src/main/java/igorlink/command/DonationExecutorCommand.java
create mode 100644 src/main/java/igorlink/command/FilterSubCommand.java
create mode 100644 src/main/java/igorlink/command/ReloadSubCommand.java
create mode 100644 src/main/java/igorlink/donationexecutor/DonationExecutor.java
create mode 100644 src/main/java/igorlink/donationexecutor/EventListener.java
create mode 100644 src/main/java/igorlink/donationexecutor/Executor.java
create mode 100644 src/main/java/igorlink/donationexecutor/executionsstaff/Donation.java
create mode 100644 src/main/java/igorlink/donationexecutor/executionsstaff/GiantMobManager.java
create mode 100644 src/main/java/igorlink/donationexecutor/executionsstaff/ListOfStreamerPlayers.java
create mode 100644 src/main/java/igorlink/donationexecutor/executionsstaff/StreamerPlayer.java
create mode 100644 src/main/java/igorlink/service/MainConfig.java
create mode 100644 src/main/java/igorlink/service/Utils.java
create mode 100644 src/main/resources/config.yml
create mode 100644 src/main/resources/plugin.yml
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4788b4b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,113 @@
+# User-specific stuff
+.idea/
+
+*.iml
+*.ipr
+*.iws
+
+# IntelliJ
+out/
+
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+*~
+
+# temporary files which can be created if a process still has a handle open of a deleted file
+.fuse_hidden*
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
+
+# .nfs files are created when an open file is removed but is still being accessed
+.nfs*
+
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+# Windows thumbnail cache files
+Thumbs.db
+Thumbs.db:encryptable
+ehthumbs.db
+ehthumbs_vista.db
+
+# Dump file
+*.stackdump
+
+# Folder config file
+[Dd]esktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+target/
+
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+.mvn/wrapper/maven-wrapper.jar
+.flattened-pom.xml
+
+# Common working directory
+run/
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..7e5181b
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,92 @@
+
+
+ 4.0.0
+
+ IgorLink
+ DonationExecutor
+ 1.0-SNAPSHOT
+ jar
+
+ DonationExecutor
+
+ Executes donations
+
+ 1.8
+ UTF-8
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+
+ ${java.version}
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.2.4
+
+
+ package
+
+ shade
+
+
+ false
+
+
+
+
+
+
+
+ src/main/resources
+ true
+
+
+
+
+
+
+ mvnrepo-repo
+ https://papermc.io/repo/repository/maven-public/
+
+
+ sonatype
+ https://oss.sonatype.org/content/groups/public/
+
+
+
+
+
+ io.papermc.paper
+ paper-api
+ 1.18.1-R0.1-SNAPSHOT
+ provided
+
+
+ io.socket
+ engine.io-client
+ 0.8.3
+
+
+ io.socket
+ socket.io-client
+ 0.8.3
+
+
+ org.json
+ json
+ 20190722
+
+
+
+
+
diff --git a/src/main/java/igorlink/DonationAlerts/DonationAlerts.java b/src/main/java/igorlink/DonationAlerts/DonationAlerts.java
new file mode 100644
index 0000000..c4ca073
--- /dev/null
+++ b/src/main/java/igorlink/DonationAlerts/DonationAlerts.java
@@ -0,0 +1,103 @@
+package igorlink.DonationAlerts;
+
+import igorlink.donationexecutor.DonationExecutor;
+import igorlink.donationexecutor.executionsstaff.Donation;
+import org.bukkit.Bukkit;
+import org.bukkit.scheduler.BukkitRunnable;
+import io.socket.emitter.Emitter.Listener;
+import io.socket.client.IO;
+import io.socket.client.Socket;
+import org.json.JSONException;
+import org.json.JSONObject;
+import java.net.URI;
+import java.net.URISyntaxException;
+import static igorlink.service.Utils.logToConsole;
+
+
+public class DonationAlerts {
+ private Listener connectListener;
+ private Listener disconectListener;
+ private Listener donationListener;
+ private Listener errorListener;
+
+ private URI url;
+ private Socket socket;
+
+
+ public DonationAlerts(String server) throws URISyntaxException {
+
+ url = new URI(server);
+ socket = IO.socket(url);
+
+ connectListener = new Listener() {
+ @Override
+ public void call(Object... arg0) {
+ logToConsole("Произведено успешное подключение!");
+ }
+ };
+
+ disconectListener = new Listener() {
+ @Override
+ public void call(Object... arg0) {
+ logToConsole("Соединение разорвано!");
+ }
+ };
+
+ donationListener = new Listener() {
+ @Override
+ public void call(Object... arg0) {
+
+ JSONObject json = new JSONObject((String) arg0[0]);
+ json.toString();
+ new BukkitRunnable() {
+ @Override
+ public void run() {
+
+ if ( (json.isNull("username")) || (json.isNull("amount_formatted"))) {
+ return;
+ }
+
+ if ((json.getString("amount_formatted")).length() <= 1) {
+ return;
+ }
+
+ DonationExecutor.getInstance().listOfStreamerPlayers
+ .addToDonationsQueue(new Donation(Bukkit.getConsoleSender(),
+ json.getString("username"),
+ json.getString("amount_formatted"),
+ json.getString("message")));
+
+ }
+ }.runTask(Bukkit.getPluginManager().getPlugin("DonationExecutor"));
+
+ }
+ };
+
+ errorListener = new Listener() {
+ @Override
+ public void call(Object... arg0) {
+ logToConsole("Произошла ошибка подключения к Donation Alerts!");
+ }
+ };
+
+ socket.on(Socket.EVENT_CONNECT, connectListener)
+ .on(Socket.EVENT_DISCONNECT, disconectListener)
+ .on(Socket.EVENT_ERROR, errorListener)
+ .on("donation", donationListener);
+ }
+
+ public void Connect (String token) throws JSONException {
+ socket.connect();
+ socket.emit("add-user", new JSONObject()
+ .put("token", token)
+ .put("type", "minor"));
+ }
+
+ public void Disconnect() throws JSONException {
+ socket.disconnect();
+ }
+
+ public boolean getConnected() {
+ return socket.connected();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/igorlink/command/AbstractCommand.java b/src/main/java/igorlink/command/AbstractCommand.java
new file mode 100644
index 0000000..d62bf86
--- /dev/null
+++ b/src/main/java/igorlink/command/AbstractCommand.java
@@ -0,0 +1,30 @@
+package igorlink.command;
+
+import igorlink.donationexecutor.DonationExecutor;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.PluginCommand;
+import org.jetbrains.annotations.NotNull;
+
+public abstract class AbstractCommand implements CommandExecutor {
+
+ public AbstractCommand(String command) {
+ PluginCommand pluginCommand = DonationExecutor.getInstance().getCommand(command);
+ if (pluginCommand != null) {
+ pluginCommand.setExecutor(this);
+ }
+ }
+
+ public abstract Boolean execute(CommandSender sender, String label, String[] args);
+
+
+ @Override
+ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
+ if (execute(sender, label, args)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/src/main/java/igorlink/command/DonateSubCommand.java b/src/main/java/igorlink/command/DonateSubCommand.java
new file mode 100644
index 0000000..3e4c1b3
--- /dev/null
+++ b/src/main/java/igorlink/command/DonateSubCommand.java
@@ -0,0 +1,43 @@
+package igorlink.command;
+
+import igorlink.donationexecutor.DonationExecutor;
+import igorlink.donationexecutor.executionsstaff.Donation;
+import org.bukkit.command.CommandSender;
+
+public class DonateSubCommand {
+ public static void onDonateCommand(CommandSender sender, String[] args) {
+ int i;
+
+ //Getting donation's amount
+ String donationAmount = new String();
+ String donationUsername = new String();
+ String donationMessage = new String();
+
+ //Getting donation's amount
+ donationAmount = args[0];
+
+ //Получаем имя донатера
+ for (i = 1; i <= args.length - 1; i++) {
+ if (args[i].equals("##")) {
+ break;
+ }
+ else {
+ if (i==1) {
+ donationUsername = donationUsername + args[i];
+ }
+ else {
+ donationUsername = ' ' + donationUsername + args[i];
+ }
+ }
+ }
+
+ //Все, что после символов ## - это сообщение
+ for (i = i+1; i <= args.length - 1; i++)
+ {
+ donationMessage = donationMessage + args[i] + ' ';
+ }
+
+ //Отправляем донат на исполнение
+ DonationExecutor.getInstance().listOfStreamerPlayers.addToDonationsQueue(new Donation(sender, donationUsername, donationAmount+".00", donationMessage));
+ }
+}
diff --git a/src/main/java/igorlink/command/DonationExecutorCommand.java b/src/main/java/igorlink/command/DonationExecutorCommand.java
new file mode 100644
index 0000000..fae90d7
--- /dev/null
+++ b/src/main/java/igorlink/command/DonationExecutorCommand.java
@@ -0,0 +1,68 @@
+package igorlink.command;
+
+import org.bukkit.command.CommandSender;
+import static igorlink.service.Utils.logToConsole;
+
+
+public class DonationExecutorCommand extends AbstractCommand {
+
+ public DonationExecutorCommand() {
+ super("donationexecutor");
+ }
+
+ @Override
+ public Boolean execute(CommandSender sender, String label, String[] args) {
+ String[] newArgs;
+
+ if (args.length == 0) {
+ return false;
+ }
+
+ try {
+
+ //Если команда - это reload, где не должно быть доп аргументов, то вызываем функцию релоуда конфига
+ if (args[0].equals("reload")) {
+ if (args.length == 1) {
+ ReloadSubCommand.onReloadCommand(sender);
+ return true;
+ }
+ } else if (args[0].equals("donate")) {
+ //Инициализируем список аргментов для новой сабфункции
+ //Если команда - donate, где нужен минимум 1 доп аргумент, создаем новый массив аргументов со смещением 1, и вызываем функцию обработки доната
+ if (args.length >= 2) {
+ //Инициализируем список новых аргументов для субкоманды
+ newArgs = new String[args.length - 1];
+ //Создаем новый список аргументов, копируя старый со смещением 1
+ System.arraycopy(args, 1, newArgs, 0, args.length - 1);
+ //Вызываем обработку доната
+ DonateSubCommand.onDonateCommand(sender, newArgs);
+ //Возвращаем true, к все прошло успешно
+ return true;
+ }
+ } else if (args[0].equals("filter")) {
+ if ((args.length == 2) && (args[1].equals("on")) || (args[1].equals("off"))) {
+ //Инициализируем список новых аргументов для субкоманды
+ newArgs = new String[args.length - 1];
+ //Создаем новый список аргументов, копируя старый со смещением 1
+ System.arraycopy(args, 1, newArgs, 0, args.length - 1);
+ //Вызываем обработку доната
+ FilterSubCommand.onFilterCommand(sender, newArgs);
+ //Возвращаем true, к все прошло успешно
+ return true;
+ }
+ }
+
+ } catch (Exception e) {
+
+ //Если получили exception, сообщаем о нем и выдаем сообщение об ошибке в консоль
+ e.printStackTrace();
+ logToConsole("Произошла неизвестная ошибка при выполнении команды!");
+ return false;
+
+ }
+
+ //Если ничего не выполнилось - в команде была ошибка
+ return false;
+ }
+
+}
diff --git a/src/main/java/igorlink/command/FilterSubCommand.java b/src/main/java/igorlink/command/FilterSubCommand.java
new file mode 100644
index 0000000..b6c8402
--- /dev/null
+++ b/src/main/java/igorlink/command/FilterSubCommand.java
@@ -0,0 +1,26 @@
+package igorlink.command;
+
+import igorlink.service.MainConfig;
+import igorlink.service.Utils;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+
+public class FilterSubCommand {
+ public static void onFilterCommand(CommandSender sender, String[] args) {
+ if (args[0].toLowerCase().equals("on")) {
+ MainConfig.turnFilterOn();
+ Utils.logToConsole("Фильтр никнеймов донатеров §bВКЛЮЧЕН");
+ if (sender instanceof Player) {
+ Utils.sendSysMsgToPlayer((Player) sender, "Фильтр никнеймов донатеров §bВКЛЮЧЕН");
+ }
+ } else {
+ MainConfig.turnFilterOff();
+ Utils.logToConsole("Фильтр никнеймов донатеров §bВЫКЛЮЧЕН");
+ if (sender instanceof Player) {
+ Utils.sendSysMsgToPlayer((Player) sender,"Фильтр никнеймов донатеров §bВЫКЛЮЧЕН");
+ }
+ }
+
+ }
+}
diff --git a/src/main/java/igorlink/command/ReloadSubCommand.java b/src/main/java/igorlink/command/ReloadSubCommand.java
new file mode 100644
index 0000000..5c59c0c
--- /dev/null
+++ b/src/main/java/igorlink/command/ReloadSubCommand.java
@@ -0,0 +1,16 @@
+package igorlink.command;
+
+import igorlink.service.MainConfig;
+import igorlink.service.Utils;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+public class ReloadSubCommand {
+ public static void onReloadCommand(CommandSender sender){
+ MainConfig.loadMainConfig(true);
+ Utils.logToConsole("Настройки успешно обновлены!");
+ if (sender instanceof Player) {
+ Utils.sendSysMsgToPlayer(((Player) sender).getPlayer(), "Настройки успешно обновлены!");
+ }
+ }
+}
diff --git a/src/main/java/igorlink/donationexecutor/DonationExecutor.java b/src/main/java/igorlink/donationexecutor/DonationExecutor.java
new file mode 100644
index 0000000..ddca55b
--- /dev/null
+++ b/src/main/java/igorlink/donationexecutor/DonationExecutor.java
@@ -0,0 +1,64 @@
+package igorlink.donationexecutor;
+
+import igorlink.command.DonationExecutorCommand;
+import igorlink.donationexecutor.executionsstaff.GiantMobManager;
+import igorlink.donationexecutor.executionsstaff.ListOfStreamerPlayers;
+import igorlink.service.MainConfig;
+import org.bukkit.Bukkit;
+import org.bukkit.plugin.java.JavaPlugin;
+import igorlink.DonationAlerts.*;
+import java.net.URISyntaxException;
+import static igorlink.service.Utils.*;
+
+
+public final class DonationExecutor extends JavaPlugin {
+
+ public static final String DASERVER = "https://socket.donationalerts.ru:443";
+ private static DonationExecutor instance;
+ public static DonationAlerts da;
+ public static GiantMobManager giantMobManager;
+ public static Boolean isRunning = true;
+ public ListOfStreamerPlayers listOfStreamerPlayers;
+
+
+ @Override
+ public void onEnable() {
+ instance = this;
+ listOfStreamerPlayers = new ListOfStreamerPlayers();
+ MainConfig.loadMainConfig();
+ giantMobManager = new GiantMobManager(this);
+
+ if (CheckNameAndToken()) {
+ try {
+ da = new DonationAlerts(DASERVER);
+ da.Connect(MainConfig.token);
+ } catch (URISyntaxException e) {
+ e.printStackTrace();
+ }
+ new DonationExecutorCommand();
+ }
+
+
+ Bukkit.getPluginManager().registerEvents(new EventListener(),this);
+
+ }
+
+ @Override
+ public void onDisable() {
+ try {
+ isRunning = false;
+ da.Disconnect();
+ Thread.sleep(1000);
+ da = null;
+ } catch (Exception e) {
+ logToConsole("Какая-то ебаная ошибка, похуй на нее вообще");
+ }
+ }
+
+
+ public static DonationExecutor getInstance() {
+ return instance;
+ }
+
+
+}
diff --git a/src/main/java/igorlink/donationexecutor/EventListener.java b/src/main/java/igorlink/donationexecutor/EventListener.java
new file mode 100644
index 0000000..cf0748c
--- /dev/null
+++ b/src/main/java/igorlink/donationexecutor/EventListener.java
@@ -0,0 +1,44 @@
+package igorlink.donationexecutor;
+
+import igorlink.service.Utils;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.*;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.scheduler.BukkitTask;
+import java.util.HashMap;
+import java.util.Map;
+import static igorlink.service.Utils.*;
+
+public class EventListener implements Listener {
+
+ private Map projectiles = new HashMap();
+
+ //Отмена горения НКВДшников
+ @EventHandler
+ public void onComburst(EntityCombustEvent e){
+ if ((e.getEntity().getName().equals("§cСотрудник НКВД")) || (e.getEntity().getName().equals("§cИосиф Сталин"))) {
+ e.setCancelled(true);
+ }
+ }
+
+ //Закачка ресурспака и оповещение о том, что плагин не активен, если он не активен
+ @EventHandler
+ public void onJoin(PlayerJoinEvent e) {
+ e.getPlayer().setResourcePack("https://download.mc-packs.net/pack/4923efe27212858f64c3ba65ff4bd35a42dadfb0.zip", Utils.decodeUsingBigInteger("4923efe27212858f64c3ba65ff4bd35a42dadfb0"));
+ if (!isPluginActive) {
+ sendSysMsgToPlayer(e.getPlayer(), " плагин не активен. Укажите токен и свой никнейм в файле конфигурации плагина и перезапустите сервер.");
+ }
+ }
+
+
+ //Отмена дропа у НКВДшников
+ @EventHandler
+ public void onEntityDeath(EntityDeathEvent e){
+ if (e.getEntity().getName().equals("§cСотрудник НКВД")) {
+ e.getDrops().clear();
+ }
+ }
+
+}
+
diff --git a/src/main/java/igorlink/donationexecutor/Executor.java b/src/main/java/igorlink/donationexecutor/Executor.java
new file mode 100644
index 0000000..4ff2e9c
--- /dev/null
+++ b/src/main/java/igorlink/donationexecutor/Executor.java
@@ -0,0 +1,315 @@
+package igorlink.donationexecutor;
+import igorlink.service.MainConfig;
+import net.md_5.bungee.api.ChatMessageType;
+import net.md_5.bungee.api.chat.TextComponent;
+import org.bukkit.*;
+import org.bukkit.attribute.Attribute;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.*;
+import org.bukkit.inventory.EquipmentSlot;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.scheduler.BukkitRunnable;
+import org.bukkit.util.Vector;
+
+import java.util.*;
+
+import static igorlink.service.Utils.*;
+import static java.lang.Math.*;
+import static org.bukkit.Bukkit.getPlayer;
+
+public class Executor {
+ public static String nameOfStreamerPlayer;
+ public static String nameOfSecondStreamerPlayer;
+ public static List executionsList = new ArrayList<>(Arrays.asList("ShitToInventory", "Lesch", "DropActiveItem",
+ "PowerKick", "ClearLastDeathDrop", "SpawnCreeper", "GiveDiamonds", "GiveStackOfDiamonds", "GiveBread",
+ "CallNKVD", "CallStalin", "RandomChange", "TamedBecomesEnemies", "HalfHeart", "BigBoom"));
+
+
+ public static void DoExecute(CommandSender sender, String streamerName, String donationUsername, String fullDonationAmount, String donationMessage, String executionName) {
+
+ //Если имя донатера не указано - устанавливаем в качестве имени "Кто-то"
+ String _donationUsername;
+ if (donationUsername.equals("")) {
+ _donationUsername = "Кто-то";
+ } else {
+ _donationUsername = donationUsername;
+ }
+
+ Boolean canContinue = true;
+ //Определяем игрока (если он оффлайн - не выполняем донат и пишем об этом в консоль), а также определяем мир, местоположение и направление игрока
+ Player streamerPlayer = getPlayer(streamerName);
+ if (streamerPlayer == null) {
+ canContinue = false;
+ } else if (streamerPlayer.isDead()) {
+ canContinue = false;
+ }
+
+ if (!canContinue) {
+ logToConsole("Донат от §b" + donationUsername + " §f в размере §b" + fullDonationAmount + "§f выполнен из-за того, что целевой стример был недоступен.");
+ return;
+ }
+
+ Location streamerPlayerLocation = streamerPlayer.getLocation();
+ World world = streamerPlayer.getWorld();
+ Vector direction = streamerPlayerLocation.getDirection();
+
+ //streamerPlayer.sendActionBar(donationMessage);
+
+ switch (executionName) {
+ case "ShitToInventory":
+ shitToInventory(streamerPlayer, donationUsername);
+ break;
+ case "Lesch":
+ lesch(streamerPlayer, donationUsername);
+ break;
+ case "DropActiveItem":
+ dropActiveItem(streamerPlayer, donationUsername);
+ break;
+ case "PowerKick":
+ powerKick(streamerPlayer, donationUsername);
+ break;
+ case "ClearLastDeathDrop":
+ clearLastDeathDrop(streamerPlayer, donationUsername);
+ break;
+ case "SpawnCreeper":
+ spawnCreeper(streamerPlayer, donationUsername);
+ break;
+ case "GiveDiamonds":
+ giveDiamonds(streamerPlayer, donationUsername);
+ break;
+ case "GiveStackOfDiamonds":
+ giveStackOfDiamonds(streamerPlayer, donationUsername);
+ break;
+ case "GiveBread":
+ giveBread(streamerPlayer, donationUsername);
+ break;
+ case "CallNKVD":
+ callNKVD(streamerPlayer, donationUsername);
+ break;
+ case "CallStalin":
+ callStalin(streamerPlayer, donationUsername);
+ break;
+ case "RandomChange":
+ randomChange(streamerPlayer, donationUsername);
+ break;
+ case "TamedBecomesEnemies":
+ tamedBecomesEnemies(streamerPlayer, donationUsername);
+ break;
+ case "HalfHeart":
+ halfHeart(streamerPlayer, donationUsername);
+ break;
+ case "BigBoom":
+ bigBoom(streamerPlayer, donationUsername);
+ break;
+ }
+
+ }
+
+
+
+
+ public static void shitToInventory (Player player, String donationUsername) {
+ announce(donationUsername, "насрал тебе в инвентарь", "насрал в инвентарь", player, true);
+ Material itemType = Material.DIRT;
+ ItemStack itemStack = new ItemStack(itemType, 64);
+ ItemMeta meta = itemStack.getItemMeta();
+ meta.setDisplayName("§cГОВНО ОТ §f" + donationUsername.toUpperCase());
+ meta.setLore(Arrays.asList("§7Это говно ужасно вонюче и занимает много места"));
+ itemStack.setItemMeta(meta);
+
+ for (int i = 0; i < MainConfig.dirtAmount; i++) {
+ player.getInventory().addItem(itemStack);
+ }
+ }
+
+ public static void dropActiveItem (Player player, String donationUsername) {
+ if (player.getEquipment().getItemInMainHand().getType() == Material.AIR) {
+ announce(donationUsername, "безуспешно пытался выбить у тебя предмет из рук", "безуспешно пытался выбить предмет из рук", player, true);
+ } else {
+ announce(donationUsername, "выбил у тебя предмет из рук", "выбил предмет из рук", player, true);
+ ((HumanEntity) player).dropItem(true);
+ player.updateInventory();
+ }
+ }
+
+ public static void lesch (Player player, String donationUsername) {
+ announce(donationUsername, "дал тебе леща", "дал леща", player, true);
+ Vector direction = player.getLocation().getDirection();
+ direction.setY(0);
+ direction.normalize();
+ direction.setY(0.3);
+ player.setVelocity(direction.multiply(0.8));
+ if (player.getHealth()>2.0D) {
+ player.setHealth(player.getHealth()-2);
+ } else {
+ player.setHealth(0);
+ }
+ ((org.bukkit.entity.Player) player).playSound(player.getLocation(), Sound.ENTITY_PLAYER_HURT, 1, 1);
+ }
+
+ public static void powerKick (Player player, String donationUsername) {
+ announce(donationUsername, "дал тебе смачного пинка под зад", "дал смачного пинка под зад", player, true);
+ Vector direction = player.getLocation().getDirection();
+ direction.setY(0);
+ direction.normalize();
+ direction.setY(0.5);
+ player.setVelocity(direction.multiply(1.66));
+ if (player.getHealth()>3.0D) {
+ player.setHealth(player.getHealth()-3);
+ } else {
+ player.setHealth(0);
+ }
+ ((org.bukkit.entity.Player) player).playSound(player.getLocation(), Sound.ENTITY_PLAYER_HURT, 1, 1);
+ }
+
+ public static void clearLastDeathDrop (Player player, String donationUsername) {
+ //Remove Last Death Dropped Items
+ if (DonationExecutor.getInstance().listOfStreamerPlayers.getStreamerPlayer(player.getName()).removeDeathDrop()) {
+ announce(donationUsername, "уничтожил твой посмертный дроп...", "уничтожил посмертный дроп", player, true);
+ } else {
+ announce(donationUsername, "безуспешно пытался уничтожить твой посмертный дроп...", "безуспешно пытался уничтожить посмертный дроп", player, true);
+ }
+ }
+
+ public static void spawnCreeper (Player player, String donationUsername) {
+ //Spawn Creepers
+ Vector direction = player.getLocation().getDirection();
+ announce(donationUsername, "прислал тебе в подарок крипера...", "прислал крипера в подарок", player, true);
+ direction.setY(0);
+ direction.normalize();
+ player.getWorld().spawnEntity(player.getLocation().clone().subtract(direction.multiply(1)), EntityType.CREEPER);
+
+ }
+
+ public static void giveDiamonds (Player player, String donationUsername) {
+ //Give some diamonds to the player
+ announce(donationUsername, "насыпал тебе алмазов!", "насыпал алмазов", player, true);
+ Material itemType = Material.DIAMOND;
+ ItemStack itemStack = new ItemStack(itemType, MainConfig.diamondsAmount);
+ ItemMeta meta = itemStack.getItemMeta();
+ meta.setDisplayName("§bАлмаз");
+ meta.setLore(Arrays.asList("§7Эти алмазы подарил §f" + donationUsername));
+ itemStack.setItemMeta(meta);
+ Item diamonds = player.getWorld().dropItemNaturally(player.getLocation(), itemStack);
+ }
+
+ public static void giveStackOfDiamonds (Player player, String donationUsername) {
+ announce(donationUsername, "насыпал тебе алмазов!", "насыпал алмазов", player, true);
+ Material itemType = Material.DIAMOND;
+ ItemStack itemStack = new ItemStack(itemType, 64);
+ ItemMeta meta = itemStack.getItemMeta();
+ meta.setDisplayName("§bАлмаз");
+ meta.setLore(Arrays.asList("§7Эти алмазы подарил §f" + donationUsername));
+ itemStack.setItemMeta(meta);
+ Item diamonds = player.getWorld().dropItemNaturally(player.getLocation(), itemStack);
+ }
+
+ public static void giveBread (Player player, String donationUsername) {
+ announce(donationUsername, "дал тебе хлеба!", "дал хлеба", player, true);
+ Material itemType = Material.BREAD;
+ ItemStack itemStack = new ItemStack(itemType, 4);
+ ItemMeta meta = itemStack.getItemMeta();
+ meta.setDisplayName("§bХлеб");
+ meta.setLore(Arrays.asList("§7Этот хлеб подарил §f" + donationUsername));
+ itemStack.setItemMeta(meta);
+ Item bread = player.getWorld().dropItemNaturally(player.getLocation(), itemStack);
+ }
+
+ public static void callNKVD (Player player, String donationUsername) {
+ Vector direction = player.getLocation().getDirection();
+ LivingEntity nkvdMob;
+ announce(donationUsername, "хочет отправить тебя в ГУЛАГ!", "хочет отправить в ГУЛАГ", player, true);
+ direction.setY(0);
+ direction.normalize();
+ for (int i = 1; i <= 3; i++) {
+ Location newloc = player.getLocation().clone();
+ Vector newdir = direction.clone();
+ newdir = newdir.rotateAroundY(1.5708 * i).multiply(2);
+ newloc.add(newdir);
+ nkvdMob = (LivingEntity) player.getWorld().spawnEntity(newloc, EntityType.ZOMBIE);
+ nkvdMob.setCustomName("§cСотрудник НКВД");
+ nkvdMob.getEquipment().setItem(EquipmentSlot.HAND, new ItemStack(Material.IRON_SWORD));
+ nkvdMob.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.3);
+ }
+
+ }
+
+ public static void callStalin (Player player, String donationUsername) {
+ announce(donationUsername, "призвал Сталина разобраться с тобой!", "призвал Сталина разобраться с", player, true);
+ DonationExecutor.giantMobManager.addMob(player.getLocation(), "§cИосиф Сталин");
+ }
+
+ public static void randomChange (Player player, String donationUsername) {
+ announce(donationUsername, "подменил тебе кое-что на камни...", "призвал Сталина разобраться с", player, true);
+ int[] randoms = new int[5];
+ for (int i = 0; i <= 4; i++) {
+
+ int temp = 0;
+ Boolean isUnique = false;
+ while (!isUnique) {
+ temp = (int) (round(random() * 35));
+ isUnique = true;
+ int n;
+ for (n = 0; n < i; n++) {
+ if (randoms[n] == temp) {
+ isUnique = false;
+ break;
+ }
+ }
+ }
+ randoms[i] = temp;
+
+ }
+
+ String replacedItems = new String("");
+ int replacedCounter = 0;
+ for (int i = 0; i <= 4; i++) {
+ if (!(player.getInventory().getItem(randoms[i]) == null)) {
+ replacedCounter++;
+ if (replacedCounter > 1) {
+ replacedItems = replacedItems + "§f, ";
+ }
+ replacedItems = replacedItems + "§b" + player.getInventory().getItem(randoms[i]).getAmount() + " §f" + player.getInventory().getItem(randoms[i]).getI18NDisplayName().toString();
+ }
+ player.getInventory().setItem(randoms[i], new ItemStack(Material.STONE, 1));
+ }
+
+ if (replacedCounter == 0) {
+ sendSysMsgToPlayer(player,"§cТебе повезло: все камни попали в пустые слоты!");
+ } else {
+ sendSysMsgToPlayer(player,"§cБыли заменены следующие предметусы: §f" + replacedItems);
+ }
+ }
+
+ public static void halfHeart (Player player, String donationUsername) {
+ player.setHealth(1);
+ announce(donationUsername, "оставил тебе лишь полсердечка...", "оставил лишь полсердечка", player, true);
+ }
+
+ public static void tamedBecomesEnemies (Player player, String donationUsername) {
+ announce(donationUsername, "настроил твоих питомцев против тебя!", "настроил прирученных питомцев против", player, true);
+ for (Entity e : player.getWorld().getEntitiesByClasses(Wolf.class, Cat.class)) {
+ if (((Tameable) e).isTamed() && ((Tameable) e).getOwner().getName().equals(player.getName())) {
+ if (e instanceof Cat) {
+ ((Tameable) e).setOwner(null);
+ ((Cat) e).setSitting(false);
+ ((Cat) e).setTarget(player);
+ player.sendMessage("+");
+ } else {
+ ((Wolf) e).setSitting(false);
+ ((Tameable) e).setOwner(null);
+ ((Wolf) e).setTarget(player);
+ }
+ }
+ }
+ }
+
+ public static void bigBoom (Player player, String donationUsername) {
+ announce(donationUsername, "сейчас тебя РАЗНЕСЕТ В КЛОЧЬЯ!!!", "сейчас РАЗНЕСЕТ В КЛОЧЬЯ", player, true);
+ player.getWorld().createExplosion(player.getLocation(), MainConfig.bigBoomRadius, true);
+
+ }
+
+
+}
diff --git a/src/main/java/igorlink/donationexecutor/executionsstaff/Donation.java b/src/main/java/igorlink/donationexecutor/executionsstaff/Donation.java
new file mode 100644
index 0000000..6a33bda
--- /dev/null
+++ b/src/main/java/igorlink/donationexecutor/executionsstaff/Donation.java
@@ -0,0 +1,53 @@
+package igorlink.donationexecutor.executionsstaff;
+
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+
+public class Donation {
+ private CommandSender sender;
+ private String username;
+ private String amount;
+ private String message;
+ private String executionName = null;
+
+ public Donation(String _username, String _amount, String _message) {
+ new Donation(Bukkit.getConsoleSender(), _username, _amount, _message);
+ }
+
+ public Donation(CommandSender _sender, String _username, String _amount, String _message) {
+ sender = _sender;
+ if (_username.equals("")) {
+ username = "Аноним";
+ } else {
+ username = _username;
+ }
+ amount = _amount;
+ message = _message;
+ }
+
+ public CommandSender getSender() {
+ return sender;
+ }
+
+ public String getName() {
+ return username;
+ }
+
+ public String getAmount() {
+ return amount;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public String getexecutionName() {
+ return executionName;
+ }
+
+ public void setexecutionName(String _executionName) {
+ executionName = _executionName;
+ }
+
+
+}
diff --git a/src/main/java/igorlink/donationexecutor/executionsstaff/GiantMobManager.java b/src/main/java/igorlink/donationexecutor/executionsstaff/GiantMobManager.java
new file mode 100644
index 0000000..082ee21
--- /dev/null
+++ b/src/main/java/igorlink/donationexecutor/executionsstaff/GiantMobManager.java
@@ -0,0 +1,577 @@
+package igorlink.donationexecutor.executionsstaff;
+import com.destroystokyo.paper.event.entity.EntityAddToWorldEvent;
+import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent;
+import igorlink.donationexecutor.DonationExecutor;
+import io.papermc.paper.event.entity.EntityMoveEvent;
+import org.bukkit.*;
+import org.bukkit.entity.*;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.entity.EntityDamageEvent;
+import org.bukkit.event.entity.ProjectileHitEvent;
+import org.bukkit.inventory.EquipmentSlot;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.scheduler.BukkitRunnable;
+import org.bukkit.util.RayTraceResult;
+import org.bukkit.util.Vector;
+import org.jetbrains.annotations.NotNull;
+import java.util.*;
+
+import static igorlink.service.Utils.*;
+import static java.lang.Math.sqrt;
+import static org.bukkit.Bukkit.getPlayer;
+
+import org.bukkit.event.Listener;
+
+public class GiantMobManager {
+ private HashMap listOfMobLists = new HashMap();
+ private HashMap listOfGiantMob = new HashMap();
+
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ //Конструктор класса. Регистрируем в нем слушателя событий GiantEventListener
+
+ public GiantMobManager(Plugin thisPlugin) {
+ Bukkit.getPluginManager().registerEvents(new GiantMobEventListener(this), thisPlugin);
+ for (Player p : Bukkit.getOnlinePlayers()) {
+ for (Entity ent : p.getWorld().getEntities()) {
+ if (ent instanceof Giant) {
+ this.addMob((LivingEntity) ent);
+ }
+ }
+ }
+ }
+
+
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ //Добавление и удаление моба
+ //Добавляем нового моба, которого нужно заспавнить
+ public void addMob(@NotNull Location playerLocation, @NotNull String mobName) {
+ addMobToList(new GiantMob(playerLocation, mobName));
+ }
+
+ //Добавляем нового моба, который уже был заспавнен
+ public void addMob(@NotNull LivingEntity giantMob) {
+ addMobToList(new GiantMob(giantMob));
+ }
+
+ //Удаляем моба
+ public void removeMob(@NotNull LivingEntity giantMob) {
+ removeMobFromList(giantMob);
+ }
+
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ //Добавление и удаления из списка мобов
+
+ //Добавляем моба в оответствующий его типу список
+ private void addMobToList(@NotNull GiantMob newGiantMob) {
+ if (listOfMobLists.containsKey(newGiantMob.getName())) {
+ listOfMobLists.get(newGiantMob.getName()).put(newGiantMob.getUUID(), newGiantMob);
+ } else {
+ listOfMobLists.put(newGiantMob.getName(), new HashMap());
+ listOfMobLists.get(newGiantMob.getName()).put(newGiantMob.getUUID(), newGiantMob);
+ }
+
+ }
+
+ //Удаляем моба из соответствующего ему списка
+ private void removeMobFromList(@NotNull LivingEntity giantMob) {
+ listOfMobLists.get(giantMob.getName()).remove(giantMob.getUniqueId());
+ }
+
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ //Класс гигантского моба
+ private class GiantMob {
+ private int timesThisGiantMobIsOnOnePlace = 0;
+ private String thisGiantMobPlayerCurrentTargetName = null;
+ private int stepsAfterHiding = 0;
+ private LivingEntity giantMobLivingEntity = null;
+ private UUID thisGiantMobUUID = null;
+
+ final private int howManySnowballsMobLaunches = 4;
+ final private Boolean SnowballsFollowingTarget = false;
+ final private int giantMobTrackingRange = 40;
+ final private static int timeBeforeThisGiantMobForgetHisTarget = 5;
+ final private static int ticksBetweenSnowballsShots = 7;
+
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ //Конструктор гигантского моба
+
+ //Создаем моба, заспавнив его и указав Имя-тип
+ public GiantMob(@NotNull Location playerLocation, String mobName) {
+
+ //Определяем направление игрока и спавним моба перед ним, повернутым к игроку лицом
+ Vector playerDirection = playerLocation.getDirection();
+ playerDirection.setY(0);
+ playerDirection.normalize();
+ this.giantMobLivingEntity = (LivingEntity) playerLocation.getWorld().spawnEntity(playerLocation.clone().add(playerDirection.clone().multiply(5)).setDirection(playerDirection.multiply(-1)), EntityType.GIANT);
+ if (!(mobName == null)) {
+ this.giantMobLivingEntity.setCustomName(mobName);
+ }
+ this.giantMobLivingEntity.setGravity(true);
+ this.giantMobLivingEntity.setRemoveWhenFarAway(false);
+ this.thisGiantMobUUID = giantMobLivingEntity.getUniqueId();
+ this.giantMobLivingEntity.getEquipment().setItem(EquipmentSlot.HAND, new ItemStack(Material.IRON_SWORD));
+
+ //Заставляем бегать и стрелять
+ this.makeGiantMobAttackWithFireballs();
+ this.forceGiantMobToMove();
+ this.makeGiantMobAttackWithSnowballs();
+ }
+
+ //Добавляем существующего
+ public GiantMob(@NotNull LivingEntity _stalinMob) {
+ this.giantMobLivingEntity = _stalinMob;
+
+ //Заставляем бегать и стрелять
+ this.turnOnGiantMobAi();
+ }
+
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ //Геттеры
+
+ //Отдает имя моба
+ public String getName() {
+ return this.giantMobLivingEntity.getName();
+ }
+
+ //Отдает UUID моба
+ public UUID getUUID() {
+ return this.thisGiantMobUUID;
+ }
+
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ //Поиск ближайшей цели
+ private LivingEntity findGiantMobTarget() {
+ //получаем список ближайших врагов dв радиусе sralinShootingRadius
+ Double sralinShootingRadius = (double) giantMobTrackingRange;
+ List listOfNearbyEntities = giantMobLivingEntity.getNearbyEntities(sralinShootingRadius, sralinShootingRadius, sralinShootingRadius);
+ List listOfNearbyPlayers = new ArrayList<>();
+ List listOfNearbyLivingEntities = new ArrayList<>();
+
+ //Пробегаемся и ищем игроков
+ for (Entity e : listOfNearbyEntities) {
+ RayTraceResult rtRes1 = null;
+ RayTraceResult rtRes2 = null;
+ RayTraceResult rtRes3 = null;
+ RayTraceResult rtRes4 = null;
+ RayTraceResult rtRes5 = null;
+ RayTraceResult rtRes6 = null;
+ RayTraceResult rtRes7 = null;
+ RayTraceResult rtRes8 = null;
+
+ if (e instanceof LivingEntity) {
+ //Позиции псевдоглаз вокруг головы с каждой стороны
+ Location rtGiantMobPseudoEyesPos1 = giantMobLivingEntity.getLocation().clone().add(2, 11, 0);
+ Location rtGiantMobPseudoEyesPos2 = giantMobLivingEntity.getLocation().clone().add(-2, 11, 0);
+ Location rtGiantMobPseudoEyesPos3 = giantMobLivingEntity.getLocation().clone().add(0, 11, 2);
+ Location rtGiantMobPseudoEyesPos4 = giantMobLivingEntity.getLocation().clone().add(0, 11, -2);
+
+ //Пускаем лучи из каждой точки псевдоглаз до верха и низа каждой сущности
+ rtRes1 = giantMobLivingEntity.getWorld().rayTraceBlocks(rtGiantMobPseudoEyesPos1, genVec(rtGiantMobPseudoEyesPos1, ((LivingEntity) e).getEyeLocation()), rtGiantMobPseudoEyesPos1.distance(((LivingEntity) e).getEyeLocation()), FluidCollisionMode.NEVER, true);
+ rtRes2 = giantMobLivingEntity.getWorld().rayTraceBlocks(rtGiantMobPseudoEyesPos2, genVec(rtGiantMobPseudoEyesPos2, ((LivingEntity) e).getEyeLocation()), rtGiantMobPseudoEyesPos2.distance(((LivingEntity) e).getEyeLocation()), FluidCollisionMode.NEVER, true);
+ rtRes3 = giantMobLivingEntity.getWorld().rayTraceBlocks(rtGiantMobPseudoEyesPos3, genVec(rtGiantMobPseudoEyesPos3, ((LivingEntity) e).getEyeLocation()), rtGiantMobPseudoEyesPos3.distance(((LivingEntity) e).getEyeLocation()), FluidCollisionMode.NEVER, true);
+ rtRes4 = giantMobLivingEntity.getWorld().rayTraceBlocks(rtGiantMobPseudoEyesPos4, genVec(rtGiantMobPseudoEyesPos4, ((LivingEntity) e).getEyeLocation()), rtGiantMobPseudoEyesPos4.distance(((LivingEntity) e).getEyeLocation()), FluidCollisionMode.NEVER, true);
+ rtRes5 = giantMobLivingEntity.getWorld().rayTraceBlocks(rtGiantMobPseudoEyesPos1, genVec(rtGiantMobPseudoEyesPos1, ((LivingEntity) e).getLocation()), rtGiantMobPseudoEyesPos1.distance(((LivingEntity) e).getLocation()), FluidCollisionMode.NEVER, true);
+ rtRes6 = giantMobLivingEntity.getWorld().rayTraceBlocks(rtGiantMobPseudoEyesPos2, genVec(rtGiantMobPseudoEyesPos2, ((LivingEntity) e).getLocation()), rtGiantMobPseudoEyesPos2.distance(((LivingEntity) e).getLocation()), FluidCollisionMode.NEVER, true);
+ rtRes7 = giantMobLivingEntity.getWorld().rayTraceBlocks(rtGiantMobPseudoEyesPos3, genVec(rtGiantMobPseudoEyesPos3, ((LivingEntity) e).getLocation()), rtGiantMobPseudoEyesPos3.distance(((LivingEntity) e).getLocation()), FluidCollisionMode.NEVER, true);
+ rtRes8 = giantMobLivingEntity.getWorld().rayTraceBlocks(rtGiantMobPseudoEyesPos4, genVec(rtGiantMobPseudoEyesPos4, ((LivingEntity) e).getLocation()), rtGiantMobPseudoEyesPos4.distance(((LivingEntity) e).getLocation()), FluidCollisionMode.NEVER, true);
+
+ //Если Сталин может из любой позиции поврота голвоы увидеть верх или низ цели, то эта цель вносится в список кандидатов
+ if ((rtRes1 == null) || (rtRes2 == null) || (rtRes3 == null) || (rtRes4 == null) || (rtRes5 == null) || (rtRes6 == null) || (rtRes7 == null) || (rtRes8 == null)) {
+ if ((e instanceof Player) && (!(((Player) e).getGameMode() == GameMode.SPECTATOR)) && (!(((Player) e).getGameMode() == GameMode.CREATIVE))) {
+ listOfNearbyPlayers.add((LivingEntity) e);
+ } else if (!(e instanceof Player)) {
+ listOfNearbyLivingEntities.add((LivingEntity) e);
+ }
+ }
+ }
+
+ }
+
+ //Создаем переменную будущей цели
+ LivingEntity target = null;
+ Double minDistance = null;
+
+ if (!(listOfNearbyPlayers.isEmpty())) {
+
+ //Если есть игроки - ищем среди них ближайшего
+ for (LivingEntity e : listOfNearbyPlayers) {
+ if (target == null) {
+ target = e;
+ minDistance = giantMobLivingEntity.getLocation().distance(e.getLocation());
+ } else if (minDistance > giantMobLivingEntity.getLocation().distance(e.getLocation())) {
+ target = e;
+ minDistance = giantMobLivingEntity.getLocation().distance(e.getLocation());
+ }
+ }
+
+ //Если новая цель - сбрасываем счетчик забвения после скрытия из области видимости моба, и назначаем цель текущей целью моба
+ if (!(target.getName().equals(thisGiantMobPlayerCurrentTargetName))) {
+ stepsAfterHiding = 0;
+ thisGiantMobPlayerCurrentTargetName = target.getName();
+ }
+
+ } else if (!(listOfNearbyLivingEntities.isEmpty())) {
+ //Если игроков рядом не было, проверяем все живые сущности
+ for (LivingEntity e : listOfNearbyLivingEntities) {
+ if (target == null) {
+ target = e;
+ minDistance = this.giantMobLivingEntity.getLocation().distance(e.getLocation());
+ } else if (minDistance > this.giantMobLivingEntity.getLocation().distance(e.getLocation())) {
+ target = e;
+ minDistance = this.giantMobLivingEntity.getLocation().distance(e.getLocation());
+ }
+ }
+
+ }
+
+ if ( (!(target instanceof Player)) && (!(thisGiantMobPlayerCurrentTargetName == null)) ) {
+ //Если прошлая цель-игрок существует, и он не мертв и находится в том же мире, что и наш моб
+ if ( (!(getPlayer(thisGiantMobPlayerCurrentTargetName).isDead())) && (getPlayer(thisGiantMobPlayerCurrentTargetName).getWorld() == giantMobLivingEntity.getWorld()) ) {
+
+ //Если не подошло время забыть о нем и он не стал спектэйтором, фокусим моба на него
+ if ((stepsAfterHiding <= timeBeforeThisGiantMobForgetHisTarget * 2) && (!(getPlayer(thisGiantMobPlayerCurrentTargetName).getGameMode()==GameMode.SPECTATOR)) && (!(getPlayer(thisGiantMobPlayerCurrentTargetName).getGameMode()==GameMode.CREATIVE))){
+ target = getPlayer(thisGiantMobPlayerCurrentTargetName);
+ stepsAfterHiding++;
+ } else {
+ //если подошло время забыть про него - забываем
+ stepsAfterHiding = 0;
+ thisGiantMobPlayerCurrentTargetName = null;
+ }
+
+ }
+ }
+
+ //Возвращаем ближайшее ентити (игрок в приоритете)
+ return target;
+ }
+
+ private void turnOnGiantMobAi() {
+ this.forceGiantMobToMove();
+ this.makeGiantMobAttackWithFireballs();
+ this.makeGiantMobAttackWithSnowballs();
+ }
+
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ //Заставляем нашего моба двигаться
+ private void forceGiantMobToMove() {
+ final GiantMob thisGiantMob = this;
+ new BukkitRunnable() {
+ @Override
+ public void run() {
+ LivingEntity thisGiantMobLivingEntity = thisGiantMob.giantMobLivingEntity;
+
+ if ( (thisGiantMobLivingEntity.isDead()) || (!(DonationExecutor.isRunning)) ) {
+ //Если Сталин уже помер, отрубаем задание
+ this.cancel();
+ return;
+ } else {
+ //Если не помер, находим ближайшую цель (игроки в приоритете)
+ LivingEntity target;
+ target = thisGiantMob.findGiantMobTarget();
+
+ //Если цели нет...
+ if (target == null) {
+ //Если моб не в воде, то прижимаем его к Земле, чтобы не улетел в небо на прыжке
+ if (!(thisGiantMobLivingEntity.getEyeLocation().clone().add(0,2,0).getBlock().getType()==Material.WATER)) {
+ thisGiantMobLivingEntity.setVelocity(thisGiantMobLivingEntity.getLocation().getDirection().clone().normalize().setY(-4.5));
+ } else {
+ //сли над мобом вода - всплываем
+ thisGiantMobLivingEntity.setVelocity(thisGiantMobLivingEntity.getLocation().getDirection().clone().normalize().setY(3));
+ }
+ return;
+ }
+
+ //Поворачиваем в плоскости XZ
+ float newYaw = (float) Math.toDegrees(
+ Math.atan2(
+ target.getLocation().getZ() - thisGiantMobLivingEntity.getLocation().getZ(),
+ target.getLocation().getX() - thisGiantMobLivingEntity.getLocation().getX()))
+ - 90;
+
+ //Поворачиваем по вертикальной оси Y (не работает из-за зачатков AI, которые сами крутят моба)
+ double xDiff = target.getEyeLocation().getX() - thisGiantMobLivingEntity.getEyeLocation().getX();
+ double yDiff = target.getEyeLocation().getY() - thisGiantMobLivingEntity.getEyeLocation().getY();
+ double zDiff = target.getEyeLocation().getZ() - thisGiantMobLivingEntity.getEyeLocation().getZ();
+
+ double distanceXZ = sqrt(xDiff * xDiff + zDiff * zDiff);
+ double distanceY = sqrt(distanceXZ * distanceXZ + yDiff * yDiff);
+
+ double yaw = Math.toDegrees(Math.acos(xDiff / distanceXZ));
+ double pitch = Math.toDegrees(Math.acos(yDiff / distanceY)) - 90.0D;
+ if (zDiff < 0.0D) {
+ yaw += Math.abs(180.0D - yaw) * 2.0D;
+ }
+
+ thisGiantMobLivingEntity.setRotation(newYaw, (float) pitch);
+
+
+ //Готовимся к совершению движения
+ Location thisGiantMobLoc = thisGiantMobLivingEntity.getLocation().clone();
+ Location thisGiantMobLocXZ = thisGiantMobLivingEntity.getLocation().clone();
+ thisGiantMobLocXZ.setY(0);
+ double thisGiantMobLocY = thisGiantMobLoc.clone().getY();
+
+ Location targetLoc = target.getLocation().clone();
+ Location targetLocXZ = target.getLocation().clone();
+ targetLocXZ.setY(0);
+ double targetY = targetLoc.clone().getY();
+
+
+ //Совершаем движение, если мы далеко от цели, либо если мы сильно под ней
+ if ((thisGiantMobLocXZ.distance(targetLocXZ) > 1) || (((targetY - thisGiantMobLocY) > 20) && (thisGiantMobLocY < targetY))) {
+ double oldX = thisGiantMobLoc.getX();
+ double oldZ = thisGiantMobLoc.getZ();
+ //sendSysMsgToPlayer(Bukkit.getPlayer("Evropejets"), "ДВИЖЕНИЕ! До цели " + (int) (Math.round(thisGiantMobLoc.distance(target.getLocation()))) + "\nЦЕЛЬ: " + target.getName());
+ //Стандартное движение к цели, если она за радиусом досягаемости
+ if (!(thisGiantMobLivingEntity.getEyeLocation().clone().add(0,1,0).getBlock().getType()==Material.WATER)) {
+ thisGiantMobLivingEntity.setRemainingAir(thisGiantMobLivingEntity.getMaximumAir());
+ thisGiantMobLivingEntity.setVelocity(thisGiantMobLoc.getDirection().clone().normalize().setY(-4.5));
+ } else {
+ thisGiantMobLivingEntity.setVelocity(thisGiantMobLoc.getDirection().clone().normalize().setY(1.4));
+ return;
+ }
+
+ new BukkitRunnable() {
+ @Override
+ public void run() {
+
+ if ( (thisGiantMobLivingEntity.isDead()) || (!(DonationExecutor.isRunning)) ) {
+ this.cancel();
+ return;
+ }
+
+ //Если моб не сдвинулся за счет стандартного движения (разница между новыми и старыми кордами<2), и при этом он находится ниже цели по Y, но дальше по XZ, чем на 2.5 блока от нее (то есть ему есть куда стремиться до цели)...
+ if ((Math.abs(thisGiantMobLivingEntity.getLocation().getX() - oldX) < 1) && (Math.abs(thisGiantMobLivingEntity.getLocation().getZ() - oldZ) < 1) && ((thisGiantMobLocY < targetY) || (thisGiantMobLocXZ.distance(targetLocXZ) > 2.5))) {
+ thisGiantMob.timesThisGiantMobIsOnOnePlace++;
+ if (thisGiantMob.timesThisGiantMobIsOnOnePlace > 2) {
+ if (timesThisGiantMobIsOnOnePlace == 3) {
+ thisGiantMobLivingEntity.setVelocity(thisGiantMobLoc.getDirection().clone().normalize().multiply(1).setY(4));
+ } else if (timesThisGiantMobIsOnOnePlace == 6) {
+ thisGiantMobLivingEntity.setVelocity(thisGiantMobLoc.getDirection().clone().normalize().rotateAroundY(0.9).multiply(2).setY(5));
+ } else if (timesThisGiantMobIsOnOnePlace == 9) {
+ thisGiantMobLivingEntity.setVelocity(thisGiantMobLoc.getDirection().clone().normalize().rotateAroundY(-0.9).multiply(2).setY(5));
+ } else if (timesThisGiantMobIsOnOnePlace == 10) {
+ thisGiantMobLivingEntity.setVelocity(thisGiantMobLoc.getDirection().clone().normalize().rotateAroundY(-0.9).multiply(2).setY(5));
+ } else if (timesThisGiantMobIsOnOnePlace == 13) {
+ thisGiantMobLivingEntity.setVelocity(thisGiantMobLoc.getDirection().clone().normalize().rotateAroundY(0.9).multiply(2).setY(5));
+ thisGiantMob.timesThisGiantMobIsOnOnePlace = 0;
+ }
+
+ } else {
+ //обычный прыжок
+ thisGiantMobLivingEntity.setVelocity(thisGiantMobLoc.getDirection().clone().normalize().multiply(1).setY(1));
+ // sendSysMsgToPlayer(Bukkit.getPlayer("Evropejets"), "HIGH");
+ }
+
+ } else {
+ //если он сдвинулся, обнуляем счетчик нахождения на одном месте по XZ
+ thisGiantMob.timesThisGiantMobIsOnOnePlace = 0;
+ }
+
+ }
+ }.runTaskLater(DonationExecutor.getInstance(), 7);
+ }
+ }
+ }
+ }.runTaskTimer(DonationExecutor.getInstance(), 0, 10);
+ }
+
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ //Заставляем моба стрелять файерболами
+ private void makeGiantMobAttackWithFireballs() {
+ final GiantMob thisGiantMob = this;
+ new BukkitRunnable() {
+ @Override
+ public void run() {
+
+
+ LivingEntity thisGiantMobLivingEntity = thisGiantMob.giantMobLivingEntity;
+
+ //Если моб уже не существует, отменяем стрельбу
+ if ((thisGiantMobLivingEntity.isDead()) || (!(DonationExecutor.isRunning)) ) {
+ this.cancel();
+ return;
+ }
+
+ //Находим ближайшее ентити (игроки в приоритете), чтобы сделать из него цель для моба
+ LivingEntity target;
+ target = thisGiantMob.findGiantMobTarget();
+ if (target == null) {
+ return;
+ }
+
+ //Спавним файер болл на 2 блока ниже глаз (район между рук)
+ Fireball stalinBall;
+ stalinBall = (Fireball) thisGiantMobLivingEntity.getWorld().spawnEntity(thisGiantMobLivingEntity.getEyeLocation().clone()
+ .add(genVec(thisGiantMobLivingEntity.getEyeLocation().clone(), target.getLocation()).clone().multiply(3.5)).clone()
+ .add(0, -2, 0),
+ EntityType.FIREBALL);
+ stalinBall.setDirection(genVec(stalinBall.getLocation(), target.getLocation()).clone().multiply(2));
+
+ }
+
+ }.runTaskTimer(DonationExecutor.getInstance(), 0, 45);
+ }
+
+ private void makeGiantMobAttackWithSnowballs() {
+ final GiantMob thisGiantMob = this;
+ new BukkitRunnable() {
+ @Override
+ public void run() {
+ LivingEntity thisGiantMobLivingEntity = thisGiantMob.giantMobLivingEntity;
+
+ //Если моб уже не существует, отменяем стрельбу
+ if ( (thisGiantMobLivingEntity.isDead()) || (!(DonationExecutor.isRunning)) ) {
+ this.cancel();
+ return;
+ }
+
+ //Находим ближайшее ентити (игроки в приоритете), чтобы сделать из него цель для моба
+ LivingEntity target;
+ target = thisGiantMob.findGiantMobTarget();
+ if (target == null) {
+ return;
+ }
+
+ //Запускаем снежки в количестве howManySnowballsMobLaunches
+ for (int i = 0; i <= howManySnowballsMobLaunches; i++) {
+ final int finali = i;
+ final LivingEntity finalTarget = target;
+ new BukkitRunnable() {
+ @Override
+ public void run() {
+ if ( (thisGiantMob.giantMobLivingEntity.isDead()) || (!(DonationExecutor.isRunning)) ) {
+ this.cancel();
+ return;
+ }
+ Snowball snowball;
+ Location handHeightPoint;
+ handHeightPoint = thisGiantMobLivingEntity.getLocation().clone().add(0, 7, 0);
+ snowball = (Snowball) thisGiantMobLivingEntity.getWorld().spawnEntity(handHeightPoint.clone()
+ .add(handHeightPoint.getDirection().rotateAroundY(0.7).multiply(3.5)),
+ EntityType.SNOWBALL);
+ ItemStack itemStack = new ItemStack(Material.SNOWBALL, 1);
+ ItemMeta meta = snowball.getItem().getItemMeta();
+ meta.setLore(Arrays.asList("Stalinball"));
+ itemStack.setItemMeta(meta);
+ snowball.setItem(itemStack);
+ snowball.setVelocity(genVec(snowball.getLocation(), finalTarget.getEyeLocation()).multiply(2.2));
+ snowball.getWorld().playSound(snowball.getLocation(), Sound.ENTITY_DRAGON_FIREBALL_EXPLODE, 3, 2);
+
+ //Каждый тик направляем снежок в игрока
+ if (SnowballsFollowingTarget) {
+ new BukkitRunnable() {
+ @Override
+ public void run() {
+ if ( (snowball.isDead()) || finalTarget.isDead() || (!(finalTarget.getWorld() == snowball.getWorld())) || (!(DonationExecutor.isRunning)) ) {
+ this.cancel();
+ return;
+ } else {
+ snowball.setVelocity(genVec(snowball.getLocation(), finalTarget.getEyeLocation()));
+ }
+ }
+ }.runTaskTimer(DonationExecutor.getInstance(), finali * ticksBetweenSnowballsShots, 1);
+ }
+
+ }
+ }.runTaskLater(DonationExecutor.getInstance(), i * ticksBetweenSnowballsShots);
+ }
+
+
+ }
+ }.runTaskTimer(DonationExecutor.getInstance(), 0, 150);
+ }
+ }
+
+
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ //Проверка всех добавлений и удалений из мира, чтобы ловить и упаковывать подходящих гигантов или удалять их из списка
+ private class GiantMobEventListener implements Listener{
+
+ GiantMobManager thisInstanceOfGiantMobManager;
+ private GiantMobEventListener(GiantMobManager _thisInstanceOfGiantMobManager) {
+ thisInstanceOfGiantMobManager = _thisInstanceOfGiantMobManager;
+ }
+
+ @EventHandler
+ private void onGiantMobAddTOWorld(EntityAddToWorldEvent e) {
+ if (e.getEntity() instanceof Giant) {
+ thisInstanceOfGiantMobManager.addMob((LivingEntity) e.getEntity());
+ }
+ }
+
+ @EventHandler
+ private void onGiantMobRemoveFromWorld(EntityRemoveFromWorldEvent e) {
+ if (thisInstanceOfGiantMobManager.listOfMobLists.containsKey(e.getEntity().getName())) {
+ thisInstanceOfGiantMobManager.removeMob((LivingEntity) e.getEntity());
+ }
+ }
+
+ @EventHandler
+ public void onGiantMobDamage(EntityDamageEvent e){
+ //Нашему мобу отменяем дамаг от падения
+ if ( (e.getEntity() instanceof Giant) && ((e.getCause() == EntityDamageEvent.DamageCause.FALL) || (e.getCause() == EntityDamageEvent.DamageCause.BLOCK_EXPLOSION) || (e.getCause() == EntityDamageEvent.DamageCause.FIRE) || (e.getCause() == EntityDamageEvent.DamageCause.FIRE_TICK))) {
+ e.setCancelled(true);
+ // sendSysMsgToPlayer(getPlayer(Executor.nameOfStreamerPlayer), "Cancelled DMG from: " + e.getCause().toString());
+ } else if (e.getEntity() instanceof Giant) {
+ // sendSysMsgToPlayer(getPlayer(Executor.nameOfStreamerPlayer), "Passed DMG from: " + e.getCause().toString());
+ }
+ }
+
+ @EventHandler
+ public void onProjectileHit(ProjectileHitEvent e) {
+ if (e.getEntity() instanceof Snowball) {
+
+ if ((e.getHitEntity()) instanceof LivingEntity) {
+
+ if (((LivingEntity) e.getHitEntity()).getHealth()>1) {
+ ((LivingEntity) e.getHitEntity()).setHealth(((LivingEntity) e.getHitEntity()).getHealth()-1);
+ } else {
+ ((LivingEntity) e.getHitEntity()).setHealth(0);
+ }
+ }
+
+
+ } else if (e.getEntity() instanceof Fireball) {
+
+ if (!(e.getHitEntity() instanceof Giant)) {
+ e.getEntity().getWorld().createExplosion(e.getEntity().getLocation(), 2.0F, true);
+ e.getEntity().remove();
+ e.setCancelled(true);
+ }
+ }
+ }
+
+
+ @EventHandler
+ public void onComeTooClose(EntityMoveEvent e){
+ //дать пинка, если слишком близок к Сталину
+ if (e.getEntity() instanceof Giant) {
+ for (Entity ent : e.getEntity().getNearbyEntities(1.9, 4, 1.9)) {
+ if (ent instanceof LivingEntity) {
+ Vector launchDirection = e.getEntity().getLocation().getDirection().clone().setY(0).normalize().multiply(0.8);
+ launchDirection.setY(0.4);
+ ent.setVelocity(launchDirection);
+ }
+ }
+ }
+ }
+
+ }
+
+
+}
diff --git a/src/main/java/igorlink/donationexecutor/executionsstaff/ListOfStreamerPlayers.java b/src/main/java/igorlink/donationexecutor/executionsstaff/ListOfStreamerPlayers.java
new file mode 100644
index 0000000..f6d44aa
--- /dev/null
+++ b/src/main/java/igorlink/donationexecutor/executionsstaff/ListOfStreamerPlayers.java
@@ -0,0 +1,79 @@
+package igorlink.donationexecutor.executionsstaff;
+
+import igorlink.donationexecutor.DonationExecutor;
+import igorlink.donationexecutor.Executor;
+import igorlink.service.Utils;
+import org.bukkit.Bukkit;
+import org.bukkit.scheduler.BukkitRunnable;
+import org.jetbrains.annotations.NotNull;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ListOfStreamerPlayers {
+ private List listOfStreamerPlayers = new ArrayList();
+
+ //Таймер будет выполнять донаты из очередей игроков каждые 2 сек, если они живы и онлайн - выполняем донат и убираем его из очереди
+ public ListOfStreamerPlayers() {
+ new BukkitRunnable() {
+ @Override
+ public void run() {
+ if (!DonationExecutor.isRunning) {
+ this.cancel();
+ return;
+ }
+
+ for (StreamerPlayer sp : listOfStreamerPlayers) {
+ if ( !(Bukkit.getPlayer(sp.getName()) == null) ) {
+ if (!(Bukkit.getPlayer(sp.getName()).isDead())) {
+ Donation donation = sp.takeDonationFromQueue();
+ if (donation==null) {
+ continue;
+ }
+ Utils.logToConsole("Отправлен на выполнение донат §b" + donation.getexecutionName() + "§f для стримера §b" + sp.getName() + "§f от донатера §b" + donation.getName());
+ Executor.DoExecute(donation.getSender(), sp.getName(), donation.getName(), donation.getAmount(), donation.getMessage(), donation.getexecutionName());
+ }
+ }
+
+ }
+ }
+ }.runTaskTimer(DonationExecutor.getInstance(), 0, 40);
+ }
+
+ public int getNumberOfStreamers() {
+ return listOfStreamerPlayers.size();
+ }
+
+ //Добавляем стримера в список
+ public void addStreamerPlayer(@NotNull String streamerPlayerName) {
+ listOfStreamerPlayers.add(new StreamerPlayer(streamerPlayerName));
+ }
+
+ public StreamerPlayer getStreamerPlayer(@NotNull String name) {
+ for (StreamerPlayer p : listOfStreamerPlayers) {
+ if (p.getName().equals(name)) {
+ return p;
+ }
+ }
+ return null;
+ }
+
+ //Очищаем список стримеров
+ public void clear() {
+ listOfStreamerPlayers.clear();
+ }
+
+ //Добавление доната в очередь
+ public void addToDonationsQueue(Donation donation) {
+ String execution;
+ for (StreamerPlayer sp : listOfStreamerPlayers) {
+ execution = sp.checkExecution(Utils.cutOffKopeykis(donation.getAmount()));
+ if (!(execution == null)) {
+ donation.setexecutionName(execution);
+ sp.putDonationToQueue(donation);
+ Utils.logToConsole("Донат от §b" + donation.getName() + "§f в размере §b" + donation.getAmount() + " руб.§f был обработан и отправлен в очередь на выполнение.");
+ return;
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/igorlink/donationexecutor/executionsstaff/StreamerPlayer.java b/src/main/java/igorlink/donationexecutor/executionsstaff/StreamerPlayer.java
new file mode 100644
index 0000000..2d89de3
--- /dev/null
+++ b/src/main/java/igorlink/donationexecutor/executionsstaff/StreamerPlayer.java
@@ -0,0 +1,109 @@
+package igorlink.donationexecutor.executionsstaff;
+
+import igorlink.donationexecutor.DonationExecutor;
+import igorlink.donationexecutor.Executor;
+import igorlink.service.MainConfig;
+import igorlink.service.Utils;
+import org.bukkit.Bukkit;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.entity.Item;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.PlayerDeathEvent;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.*;
+
+public class StreamerPlayer {
+ private String streamerPlayerName;
+ private List- listOfDeathDropItems = new ArrayList
- ();
+ private Queue listOfQueuedDonations = new LinkedList();
+ private HashMap listOfAmounts = new HashMap();
+
+
+ //Инициализация нового объекта стримера-игрока
+ public StreamerPlayer(@NotNull String _streamerPlayerName) {
+ FileConfiguration config = MainConfig.getConfig();
+ streamerPlayerName = _streamerPlayerName;
+ Bukkit.getPluginManager().registerEvents(new PlayerDeathListener(this), DonationExecutor.getInstance());
+
+
+ //Заполняем список сумм для донатов
+ String amount;
+ for (String execName : Executor.executionsList) {
+ amount = config.getString("DonationAmounts." + streamerPlayerName + "." + execName);
+ if (!(amount==null)) {
+ listOfAmounts.put(amount, execName);
+ } else {
+ Utils.logToConsole("Сумма доната, необходимая для " + execName + " для стримера " + streamerPlayerName + " не найдена. Проверьте правильность заполнения файла конфигурации DonationExecutor.yml в папке с именем плагина.");
+ }
+ }
+ }
+
+ public String checkExecution(@NotNull String amount) {
+ return listOfAmounts.get(amount);
+ }
+
+ public String getName(){
+ return streamerPlayerName;
+ }
+
+ //Работа со списком выпавших при смерти вещей
+ public void setDeathDrop(List
- listOfItems) {
+ listOfDeathDropItems.clear();
+ listOfDeathDropItems.addAll(listOfItems);
+ }
+
+
+ //Работа с очередью донатов
+ //Поставить донат в очередь на выполнение донатов для этого игрока
+ public void putDonationToQueue(@NotNull Donation donation) {
+ listOfQueuedDonations.add(donation);
+ }
+
+ //Взять донат из очереди и убрать его из нее
+ public Donation takeDonationFromQueue() {
+ return listOfQueuedDonations.poll();
+ }
+
+
+ //Удалить дроп игрока после смерти
+ public Boolean removeDeathDrop() {
+ Boolean wasAnythingDeleted = false;
+ for (Item i : listOfDeathDropItems) {
+ if (i.isDead()) {
+ continue;
+ }
+ i.remove();
+ wasAnythingDeleted = true;
+ }
+ return wasAnythingDeleted;
+ }
+
+ //Замена дездропа при смерти игрока (через Listener)
+ private class PlayerDeathListener implements Listener{
+ StreamerPlayer thisStreamerPlayer;
+
+ //Передача родительского объекта в слушателя
+ private PlayerDeathListener(StreamerPlayer _thisStreamerPlayer) {
+ thisStreamerPlayer = _thisStreamerPlayer;
+ }
+
+ //Если данный игрок умер - запоминаем его посмертный дроп
+ @EventHandler
+ private void onPlayerDeath(PlayerDeathEvent event) {
+ List
- deathDrop = new ArrayList<>();
+ if (event.getPlayer().getName().equals(thisStreamerPlayer.getName())) {
+ for (ItemStack i : event.getDrops()) {
+ deathDrop.add(event.getPlayer().getWorld().dropItemNaturally(event.getPlayer().getLocation(), i));
+ }
+ }
+ event.getDrops().clear();
+ thisStreamerPlayer.setDeathDrop(deathDrop);
+ }
+ }
+
+
+
+}
diff --git a/src/main/java/igorlink/service/MainConfig.java b/src/main/java/igorlink/service/MainConfig.java
new file mode 100644
index 0000000..cc81967
--- /dev/null
+++ b/src/main/java/igorlink/service/MainConfig.java
@@ -0,0 +1,118 @@
+package igorlink.service;
+
+import igorlink.donationexecutor.DonationExecutor;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.jetbrains.annotations.NotNull;
+import java.util.ArrayList;
+import static igorlink.service.Utils.*;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+public class MainConfig {
+ private static HashMap> donationAmountsHashMap = new HashMap>();
+ private static FileConfiguration config = DonationExecutor.getInstance().getConfig();
+ public static int dirtAmount = 0;
+ public static int diamondsAmount = 0;
+ public static int breadAmount = 0;
+ public static int bigBoomRadius = 0;
+ public static String token;
+ public static List listOfBlackListedSubstrings = new ArrayList<>();
+ public static List listOfWhiteListedSubstrings = new ArrayList<>();
+ private static Boolean twitchFilter;
+
+ public MainConfig() {
+
+ }
+
+ //Геттер конфига
+ public static FileConfiguration getConfig(){
+ return config;
+ }
+
+ //Обновить данные из конфига
+ public static void reloadMainConfig() {
+ loadMainConfig(true);
+ }
+
+ //Загрузить данные из конфига без указания параметра перезагрузки
+ public static void loadMainConfig() {
+ loadMainConfig(false);
+ }
+
+ //Загрузка данных из конфигфайла с указанным параметром перезагрузки
+ public static void loadMainConfig(Boolean isReload) {
+ DonationExecutor.getInstance().saveDefaultConfig();
+
+ //Если это перезагрузка, обновляем данные, очищаем список игроков
+ if (isReload) {
+ DonationExecutor.getInstance().reloadConfig();
+ DonationExecutor.getInstance().listOfStreamerPlayers.clear();
+ }
+
+ config = DonationExecutor.getInstance().getConfig();
+
+ String stringWithPlayersNames = config.getString("StreamersNamesList");
+ List streamerPlayersNamesList = new ArrayList(Arrays.asList(stringWithPlayersNames.split(",")));
+ for (String playerName : streamerPlayersNamesList) {
+ DonationExecutor.getInstance().listOfStreamerPlayers.addStreamerPlayer(playerName);
+ }
+
+ logToConsole("При чтении файла конфигурации было добавлено §b" + DonationExecutor.getInstance().listOfStreamerPlayers.getNumberOfStreamers() + "§f стримеров.");
+
+ dirtAmount = Integer.valueOf(config.getString("DirtAmount"));
+ diamondsAmount = Integer.valueOf(config.getString("DiamondsAmount"));
+ breadAmount = Integer.valueOf(config.getString("BreadAmount"));
+ bigBoomRadius = Integer.valueOf(config.getString("BigBoomRadius"));
+
+ token = config.getString("DonationAlertsToken");
+ listOfBlackListedSubstrings = Arrays.asList(config.getString("BlacklistedSubstrings").split(","));
+ listOfWhiteListedSubstrings = Arrays.asList(config.getString("WhitelistedSubstrings").split(","));
+
+ if (config.getString("TwitchFilter") == "true") {
+ twitchFilter = true;
+ } else if (config.getString("TwitchFilter") == "false") {
+ twitchFilter = false;
+ }
+ else {
+ logToConsole("Ошибка при чтении значение TwitchFilter");
+ }
+
+
+ }
+
+
+
+ public static void turnFilterOn() {
+ twitchFilter = true;
+ config.set("TwitchFilter", "true");
+ }
+
+ public static void turnFilterOff() {
+ twitchFilter = false;
+ config.set("TwitchFilter", "false");
+ }
+
+ public static Boolean getFilterStatus() {
+ return twitchFilter;
+ }
+
+ public static HashMap getNameAndExecution (@NotNull String donationAmount) {
+ String thisDonateForStreamerName = null;
+ String nameOfExecution = null;
+ for (String p : donationAmountsHashMap.keySet()) {
+ if (donationAmountsHashMap.get(p).containsKey(donationAmount)) {
+ HashMap temp = new HashMap();
+ thisDonateForStreamerName = p;
+ nameOfExecution = donationAmountsHashMap.get(p).get(donationAmount);
+ temp.put("name", p);
+ temp.put("execution", nameOfExecution);
+ return temp;
+ }
+ }
+
+ return null;
+ }
+
+
+}
diff --git a/src/main/java/igorlink/service/Utils.java b/src/main/java/igorlink/service/Utils.java
new file mode 100644
index 0000000..debc62b
--- /dev/null
+++ b/src/main/java/igorlink/service/Utils.java
@@ -0,0 +1,248 @@
+package igorlink.service;
+
+import com.destroystokyo.paper.Title;
+import igorlink.donationexecutor.DonationExecutor;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.entity.Player;
+import org.bukkit.util.Vector;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class Utils {
+ public static Boolean isPluginActive;
+
+ //Вывод сообщения в консоль
+ public static void logToConsole(String text){
+ Bukkit.getConsoleSender().sendMessage("§c[DonationExecutor] §f" + text);
+ }
+
+ //Отправка сообщения игроку со стороны плагина
+ public static void sendSysMsgToPlayer(Player player, String text){
+ player.sendMessage("§c[DE] §f" + text);
+ }
+
+ public static byte[] decodeUsingBigInteger(String hexString) {
+ byte[] byteArray = new BigInteger(hexString, 16).toByteArray();
+ if (byteArray[0] == 0) {
+ byte[] output = new byte[byteArray.length - 1];
+ System.arraycopy(byteArray, 1, output,0, output.length);
+ return output;
+ }
+ return byteArray;
+ }
+
+ public static Boolean CheckNameAndToken() {
+ isPluginActive = true;
+ if ((DonationExecutor.getInstance().getConfig().getString("DonationAlertsToken") == "") || (DonationExecutor.getInstance().getConfig().getString("DonationAlertsToken") == null)) {
+ logToConsole("Вы не указали свой токен DonationAlerts в файле конфигурации плагина, поэтому сейчас плагин не работает.");
+ isPluginActive = false;
+ } else if ((DonationExecutor.getInstance().getConfig().getString("Nickname") == "") || (DonationExecutor.getInstance().getConfig().getString("Nickname") == "")) {
+ logToConsole("Вы не указали свой игровой никнейм в файле конфигурации плагина, поэтому сейчас плагин не работает.");
+ isPluginActive = false;
+ }
+ return isPluginActive;
+ }
+
+ public static void announce(String donaterName, String subText, String alterSubtext, Player player, Boolean bigAnnounce) {
+ String _donaterName = donaterName;
+
+ if (bigAnnounce) {
+ if (donaterName.equals("")) {
+ _donaterName = "Кто-то";
+ }
+ Title title = new Title("§c" + _donaterName, "§f" + subText);
+ player.sendTitle(title);
+ player.sendMessage("§c[DE] §fДонатер §c" + _donaterName, "§f" + subText);
+ }
+
+ if (_donaterName == "") {
+ _donaterName = "Кто-то";
+ }
+ for (Player p : Bukkit.getOnlinePlayers()) {
+ if (!(p.getName() == player.getName())) {
+ p.sendMessage("§c[DE] §fДонатер §c" + _donaterName + " §f" + alterSubtext + " §b" + player.getName());
+ }
+ }
+
+
+ }
+
+ public static Vector genVec(Location a, Location b, Boolean isNormalized) {
+ Vector vec = locToVec(b).clone().subtract(locToVec(a));
+ if (isNormalized) {
+ return vec.normalize();
+ } else {
+ return vec;
+ }
+ }
+
+ public static Vector genVec(Location a, Location b) {
+ Vector vec = locToVec(b).clone().subtract(locToVec(a));
+ return vec.normalize();
+ }
+
+ public static Vector locToVec(Location loc) {
+ Vector vec = new Vector(loc.getX(), loc.getY(), loc.getZ());
+ return vec;
+ }
+
+ public static String cutOffKopeykis(String donationAmountWithKopeykis) {
+ String amountWithoutKopeykis = "";
+ for (int i = 0; i <= donationAmountWithKopeykis.length() - 1; i++) {
+ if (donationAmountWithKopeykis.charAt(i) == '.') {
+ break;
+ } else if (donationAmountWithKopeykis.charAt(i) == ' ') {
+ continue;
+ } else {
+ amountWithoutKopeykis = amountWithoutKopeykis + donationAmountWithKopeykis.charAt(i);
+ }
+ }
+
+ return amountWithoutKopeykis;
+ }
+
+ public static Boolean isBlackListed(String text) {
+ HashMap> mapOfSynonimousChars = new HashMap>();
+
+ mapOfSynonimousChars.put('h', (Arrays.asList('x', 'х', 'н', 'n'))); //eng
+ mapOfSynonimousChars.put('n', (Arrays.asList('н', 'й', 'и'))); //eng
+ mapOfSynonimousChars.put('н', (Arrays.asList('h', 'n', 'й', 'и'))); //rus
+ mapOfSynonimousChars.put('e', (Arrays.asList('е', '3', 'з'))); //eng
+ mapOfSynonimousChars.put('е', (Arrays.asList('e', '3', 'з'))); //rus
+ mapOfSynonimousChars.put('г', (Arrays.asList('r', 'я', 'g', '7'))); //rus
+ mapOfSynonimousChars.put('r', (Arrays.asList('г', 'я', 'g', '7'))); //eng
+ mapOfSynonimousChars.put('g', (Arrays.asList('г', 'r', '7'))); //eng
+ mapOfSynonimousChars.put('p', (Arrays.asList('п', 'р', 'n', 'я', 'r'))); //eng
+ mapOfSynonimousChars.put('р', (Arrays.asList('p', 'r', 'я'))); //rus
+ mapOfSynonimousChars.put('п', (Arrays.asList('p', 'n', 'и', 'р'))); //rus
+ mapOfSynonimousChars.put('o', (Arrays.asList('о', '0'))); //eng
+ mapOfSynonimousChars.put('о', (Arrays.asList('o', '0'))); //rus
+ mapOfSynonimousChars.put('a', (Arrays.asList('а'))); //eng
+ mapOfSynonimousChars.put('а', (Arrays.asList('a'))); //rus
+ mapOfSynonimousChars.put('и', (Arrays.asList('i', 'n', 'e', 'е', '|', 'l', '!', '1', '3', 'й'))); //rus
+ mapOfSynonimousChars.put('i', (Arrays.asList('1', 'и', 'e', 'е', '|', 'l', '!', 'й'))); //eng
+ mapOfSynonimousChars.put('с', (Arrays.asList('c', 's', '$', '5'))); //rus
+ mapOfSynonimousChars.put('s', (Arrays.asList('c', 'с', '$', '5'))); //eng
+ mapOfSynonimousChars.put('c', (Arrays.asList('s', 'с', '$', '5'))); //eng
+ mapOfSynonimousChars.put('л', (Arrays.asList('l', '1', '|'))); //rus
+ mapOfSynonimousChars.put('l', (Arrays.asList('л', '1', '|', '!'))); //eng
+ mapOfSynonimousChars.put('1', (Arrays.asList('л', 'i', 'l', '|'))); //eng
+ mapOfSynonimousChars.put('d', (Arrays.asList('д', 'л'))); //eng
+ mapOfSynonimousChars.put('д', (Arrays.asList('d', 'л', '9'))); //rus
+ mapOfSynonimousChars.put('y', (Arrays.asList('у', 'u', 'ы'))); //eng
+ mapOfSynonimousChars.put('у', (Arrays.asList('y', 'u', 'ы'))); //rus
+ mapOfSynonimousChars.put('x', (Arrays.asList('х', 'h'))); //eng
+ mapOfSynonimousChars.put('х', (Arrays.asList('x', 'h'))); //rus
+ mapOfSynonimousChars.put('ы', (Arrays.asList('у', 'u', 'y'))); //rus
+ mapOfSynonimousChars.put('ы', (Arrays.asList('у', 'u', 'y'))); //rus
+ mapOfSynonimousChars.put('ч', (Arrays.asList('4')));//rus
+ mapOfSynonimousChars.put('k', (Arrays.asList('к')));//eng
+ mapOfSynonimousChars.put('к', (Arrays.asList('k')));//rus
+ mapOfSynonimousChars.put('0', (Arrays.asList('o', 'о'))); //num
+ mapOfSynonimousChars.put('1', (Arrays.asList('i', 'l'))); //num
+ mapOfSynonimousChars.put('3', (Arrays.asList('e', 'е','з')));
+ mapOfSynonimousChars.put('4', (Arrays.asList('ч')));
+ mapOfSynonimousChars.put('5', (Arrays.asList('с', 'c', 's')));
+ mapOfSynonimousChars.put('9', (Arrays.asList('r', 'я')));
+
+
+ String validationText = text.toLowerCase();
+
+ Pattern pattern = Pattern.compile("[l1i]*[\\-]*[l1i]*");
+ Matcher matcher = pattern.matcher(validationText);
+ if ( (matcher.find()) && (matcher.group().length()>0) ) {
+ validationText = validationText.replace(matcher.group(), "н");
+ }
+
+ validationText = validationText.replace(" ", "");
+ validationText = validationText.replace(",", "");
+ validationText = validationText.replace(".", "");
+ validationText = validationText.replace("-", "");
+ validationText = validationText.replace("%", "");
+ validationText = validationText.replace("*", "");
+ validationText = validationText.replace("?", "");
+
+ if (validationText.length() == 0) {
+ return false;
+ }
+
+// for (String ss : MainConfig.listOfWhiteListedSubstrings) {
+// if (validationText.contains(ss)) {
+// validationText = validationText.replace(ss, "");
+// }
+// }
+
+
+ if (!(validationText.matches("[a-zа-я0-9$!ё]*"))) {
+ return true;
+ }
+
+
+ for (String ss : MainConfig.listOfBlackListedSubstrings) {
+ for (int i = 0; i <= validationText.length() - ss.length(); i++) {
+ int tempi = i;
+ for (int j = 0; j <= ss.length(); j++) {
+
+ if (j == ss.length()) {
+ return true;
+ }
+
+ if (validationText.charAt(tempi + j) == ss.charAt(j)) {
+ continue;
+ } else if ((mapOfSynonimousChars.containsKey(ss.charAt(j)))) {
+ if ((mapOfSynonimousChars.get(ss.charAt(j)).contains(validationText.charAt(tempi + j)))) {
+ continue;
+ }
+ }
+
+ Boolean repeated = true;
+ Boolean finishCycle = false;
+ while ((repeated) && (!finishCycle)) {
+ if (j==0) {
+ break;
+ }
+ if (!(validationText.charAt(tempi + j) == validationText.charAt(tempi + j - 1))) {
+ if (!(mapOfSynonimousChars.containsKey(validationText.charAt(tempi + j)))) {
+ repeated = false;
+ break;
+ } else if (!(mapOfSynonimousChars.get(validationText.charAt(tempi + j)).contains(validationText.charAt(tempi + j - 1)))) {
+ repeated = false;
+ break;
+ }
+ }
+ tempi++;
+ if ((validationText.length()-tempi-j) < (ss.length()-j)) {
+ finishCycle=true;
+ break;
+ }
+ }
+
+ if (finishCycle) {
+ break;
+ }
+
+ if (validationText.charAt(tempi + j) == ss.charAt(j)) {
+ continue;
+ } else if ((mapOfSynonimousChars.containsKey(ss.charAt(j)))) {
+ if ((mapOfSynonimousChars.get(ss.charAt(j)).contains(validationText.charAt(tempi + j)))) {
+ continue;
+ }
+ }
+
+ break;
+
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+}
+
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
new file mode 100644
index 0000000..f24a9d8
--- /dev/null
+++ b/src/main/resources/config.yml
@@ -0,0 +1,96 @@
+# Секретный токен Donation Alerts.
+# Находится на Donation Alerts на странице "Настройки" -> "Основные настройки".
+DonationAlertsToken:
+
+# Никнеймы стримеров в игре ЧЕРЕЗ ЗАПЯТУЮ БЕЗ ПРОБЕЛОВ!
+# Не забудьте про цветовые коды, если используете их
+StreamersNamesList: Evropejets,mdenz3
+
+# Точные суммы донатов для событий
+DonationAmounts:
+ # Имя первого стримера (ДОЛЖЕН СОВПАДАТЬ С ПЕРВЫМ ЗНАЧЕНИЕМ, УКАЗАННЫМ В StreamersNamesList)
+ Evropejets:
+ # Насрать стримеру в инвентарь подписанными стаками говна
+ ShitToInventory: 62
+ # Выбить предмет из рук
+ DropActiveItem: 65
+ # Дать леща - толчок вперед, который отнимет 1 сердечко
+ Lesch: 67
+ # Дать хлеб в количестве N кусков
+ GiveBread: 82
+ # Выдать определенное количество алмазов (настраивается дальше)
+ GiveDiamonds: 132
+ # Заспавнятся несколько сотрудников НКВД, которые заходят увести вас в ГУЛАГ
+ CallNKVD: 142
+ # Дать очень смачный пинок под зад, который отнимет 1.5 сердечка
+ PowerKick: 152
+ # В вашем инвентаре будет случайным образом заменено N слотов (по умолчанию -5)
+ # на некие предметы (по умолчанию - камни)
+ RandomChange: 197
+ # Заспавнить крипера за спиной
+ SpawnCreeper: 202
+ # Уничтожить вещи, выпавшие после последней смерти
+ ClearLastDeathDrop: 214
+ # Все прирученные игроком кошки снова станут дикими, а прирученные волки,
+ # помимо этого, еще и нападут на игрока, который был их хозяином
+ TamedBecomesEnemies: 252
+ # Заспавнить исполинского Иосифа Сталина, испепеляющий все вокруг
+ CallStalin: 352
+ # Оставить игроку лишь полсердечка
+ HalfHeart: 602
+ # Через N секунд (по умолчанию - 3) произойдет взрыв с радиусом M
+ # (по умолчанию - 20) вокруг игрока
+ BigBoom: 2002
+ # Выдать целый стак алмазов
+ GiveStackOfDiamonds: 2012
+ # Имя второго стримера (ДОЛЖЕН СОВПАДАТЬ СО ВТОРЫМ ЗНАЧЕНИЕМ, УКАЗАННЫМ В StreamersNamesList)
+ mdenz3:
+ # Насрать стримеру в инвентарь подписанными стаками говна
+ ShitToInventory: 61
+ # Выбить предмет из рук
+ DropActiveItem: 64
+ # Дать леща - толчок вперед, который отнимет 1 сердечко
+ Lesch: 66
+ # Дать хлеб в количестве N кусков
+ GiveBread: 81
+ # Выдать определенное количество алмазов (настраивается дальше)
+ GiveDiamonds: 131
+ # Заспавнятся несколько сотрудников НКВД, которые заходят увести вас в ГУЛАГ
+ CallNKVD: 141
+ # Дать очень смачный пинок под зад, который отнимет 1.5 сердечка
+ PowerKick: 151
+ # В вашем инвентаре будет случайным образом заменено N слотов (по умолчанию -5)
+ # на некие предметы (по умолчанию - камни)
+ RandomChange: 196
+ # Заспавнить крипера за спиной
+ SpawnCreeper: 201
+ # Уничтожить вещи, выпавшие после последней смерти
+ ClearLastDeathDrop: 213
+ # Все прирученные игроком кошки снова станут дикими, а прирученные волки,
+ # помимо этого, еще и нападут на игрока, который был их хозяином
+ TamedBecomesEnemies: 251
+ # Заспавнить исполинского Иосифа Сталина, испепеляющий все вокруг
+ CallStalin: 351
+ # Оставить игроку лишь полсердечка
+ HalfHeart: 601
+ # Через N секунд (по умолчанию - 3) произойдет взрыв с радиусом M
+ # (по умолчанию - 20) вокруг игрока
+ BigBoom: 2001
+ # Выдать целый стак алмазов
+ GiveStackOfDiamonds: 2011
+
+# Сколько блоков говна игроки будут получать в инвентарь от ShitToInventory
+DirtAmount: 10
+# Сколько алмазов игроки будут получать в инвентарь от GiveDiamonds
+DiamondsAmount: 4
+# Сколько хлеба игроки будут получать в инвентарь от GiveBread
+BreadAmount: 4
+# Радиус взрыва от BigBoom
+BigBoomRadius: 20
+
+TwitchFilter: true
+BlacklistedSubstrings: негр,пидо,пида,niga,нигр,ниге,додик,петух,петуч,куколд,симп,kukold,cuckold,fag,хуе,хуй,даун,кады,кадь,kadb,4e4e,4e4n,cheche,chechn,4echn,che4n,4eche,4eche
+WhitelistedSubstrings: книг,нигерия
+
+
+
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
new file mode 100644
index 0000000..d0af3eb
--- /dev/null
+++ b/src/main/resources/plugin.yml
@@ -0,0 +1,15 @@
+name: DonationExecutor
+version: 0.2 Beta
+main: igorlink.donationexecutor.DonationExecutor
+api-version: 1.18
+authors: [Igor Link]
+description: Executes donations
+commands:
+ donationexecutor: {
+ aliases: [d],
+ description: "Позволяет имитировать донаты для тестов или для воспроизведения события вручную",
+ usage: "§c[DonationExecutor] §fДоступные команды: \n
+ §c/d §7donate §b<СУММА> <ИМЯ> §7## §b<СООБЩЕНИЕ>§f - сымитировать донат\n
+ §c/d §7reload§f - перезагрузить настройки из конфига
+ "
+ }