297 lines
11 KiB
Java
297 lines
11 KiB
Java
package xyz.etztech.minealert.listeners;
|
|
|
|
import net.md_5.bungee.api.ChatColor;
|
|
import net.md_5.bungee.api.chat.BaseComponent;
|
|
import net.md_5.bungee.api.chat.ClickEvent;
|
|
import net.md_5.bungee.api.chat.ComponentBuilder;
|
|
import org.bukkit.Bukkit;
|
|
import org.bukkit.Location;
|
|
import org.bukkit.Material;
|
|
import org.bukkit.World;
|
|
import org.bukkit.block.Block;
|
|
import org.bukkit.entity.Player;
|
|
import org.bukkit.event.EventHandler;
|
|
import org.bukkit.event.Listener;
|
|
import org.bukkit.event.block.BlockBreakEvent;
|
|
import org.bukkit.event.block.BlockPlaceEvent;
|
|
import xyz.etztech.Javacord;
|
|
import xyz.etztech.Webhook;
|
|
import xyz.etztech.embed.Author;
|
|
import xyz.etztech.embed.Embed;
|
|
import xyz.etztech.minealert.Color;
|
|
import xyz.etztech.minealert.Lang;
|
|
import xyz.etztech.minealert.MineAlert;
|
|
import xyz.etztech.minealert.MuteType;
|
|
|
|
import java.time.OffsetDateTime;
|
|
import java.util.*;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
|
|
|
public class OreAlertListener implements Listener {
|
|
|
|
private final MineAlert plugin;
|
|
private static final Set<Location> cache = Collections.synchronizedSet(new HashSet<>());
|
|
private static final Map<UUID, List<BlockEvent>> map = new ConcurrentHashMap<>();
|
|
private static final Queue<BlockEvent> queue = new ConcurrentLinkedQueue<>();
|
|
|
|
public OreAlertListener(MineAlert plugin) {
|
|
this.plugin = plugin;
|
|
this.plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
|
this.plugin.getServer().getScheduler().runTaskAsynchronously(this.plugin, this::task);
|
|
this.plugin.getServer().getScheduler().runTaskTimerAsynchronously(this.plugin, this::cleanup, 0,
|
|
20 * 60 * this.plugin.getConfig().getInt("ore.cleanup", 5));
|
|
}
|
|
|
|
@EventHandler
|
|
public void onBlockBreak(BlockBreakEvent event) {
|
|
if (cache.contains(event.getBlock().getLocation())) return;
|
|
if (!isMaterialTracked(event.getBlock().getType())) return;
|
|
|
|
queue.add(new BlockEvent(event.getPlayer(), event.getBlock().getType(), event.getBlock().getLocation(), true));
|
|
|
|
int radius = this.plugin.getConfig().getInt("ore.radius", 3);
|
|
for (int x = -radius; x < radius; x++) {
|
|
for (int y = -radius; y < radius; y++) {
|
|
for (int z = -radius; z < radius; z++) {
|
|
if (x == 0 && y == 0 && z == 0) continue;
|
|
Block block = event.getBlock().getRelative(x, y, z);
|
|
if (cache.contains(block.getLocation())) continue;
|
|
if (!isMaterialTracked(block.getType())) continue;
|
|
queue.add(new BlockEvent(event.getPlayer(), block.getType(), block.getLocation(), false));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@EventHandler
|
|
public void onBlockPlace(BlockPlaceEvent event) {
|
|
this.plugin.getServer().getScheduler().runTaskAsynchronously(this.plugin, () -> {
|
|
Block eventBlock = event.getBlock();
|
|
if (isMaterialTracked(eventBlock.getType())) cache.add(eventBlock.getLocation());
|
|
if (eventBlock.getType() == Material.TNT || (eventBlock.getType().toString().contains("_BED") && eventBlock.getWorld().getEnvironment() == World.Environment.NETHER)) {
|
|
for (int x = -4; x < 4; x++) {
|
|
for (int y = -4; y < 4; y++) {
|
|
for (int z = -4; z < 4; z++) {
|
|
Block block = eventBlock.getRelative(x, y, z);
|
|
cache.add(block.getLocation());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
private boolean isMaterialTracked(Material material) {
|
|
for (String s: this.plugin.getConfig().getConfigurationSection("ore.blocks").getKeys(false)) {
|
|
if (Lang.getMaterialKey(material).equals(s)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private void task() {
|
|
while (this.plugin.isEnabled()) {
|
|
BlockEvent event = this.queue.poll();
|
|
if (event != null) {
|
|
if (cache.contains(event.getLocation())) continue;
|
|
cache.add(event.getLocation());
|
|
if (event.isParent()) {
|
|
addStrike(event);
|
|
check(event);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void addStrike(BlockEvent event) {
|
|
List<BlockEvent> events = map.getOrDefault(event.getPlayer().getUniqueId(), new ArrayList<>());
|
|
|
|
events.add(event);
|
|
map.put(event.getPlayer().getUniqueId(), events);
|
|
}
|
|
|
|
private void check(BlockEvent event) {
|
|
String blockKey = Lang.getMaterialKey(event.getMaterial());
|
|
int start = this.plugin.getConfigIntFallback(
|
|
5,
|
|
String.format("ore.blocks.%s.start", blockKey),
|
|
"ore.start"
|
|
);
|
|
int each = this.plugin.getConfigIntFallback(
|
|
1,
|
|
String.format("ore.blocks.%s.each", blockKey),
|
|
"ore.each"
|
|
);
|
|
int ping = this.plugin.getConfigIntFallback(
|
|
5,
|
|
String.format("ore.blocks.%s.ping", blockKey),
|
|
"ore.ping"
|
|
);
|
|
int belowY = this.plugin.getConfigIntFallback(
|
|
255,
|
|
String.format("ore.blocks.%s.below_y", blockKey),
|
|
"ore.below_y"
|
|
);
|
|
int aboveY = this.plugin.getConfigIntFallback(
|
|
0,
|
|
String.format("ore.blocks.%s.above_y", blockKey),
|
|
"ore.above_y"
|
|
);
|
|
purge(map.getOrDefault(event.getPlayer().getUniqueId(), new ArrayList<>()).iterator());
|
|
|
|
int yLevel = event.location.getBlockY();
|
|
if (yLevel > belowY || yLevel < aboveY) {
|
|
return;
|
|
}
|
|
|
|
if (MuteType.GRIEFALERT_MUTE.hasMuteStatus(event.getPlayer(), plugin)) {
|
|
return;
|
|
}
|
|
|
|
int strikes = 0;
|
|
for (BlockEvent e : map.getOrDefault(event.getPlayer().getUniqueId(), new ArrayList<>())) {
|
|
if (e.isParent() && e.getMaterial().name().equals(event.getMaterial().name())) {
|
|
strikes++;
|
|
}
|
|
}
|
|
|
|
double alert = (double) strikes / start;
|
|
if (alert == 1) {
|
|
sendAlert(event, strikes, true);
|
|
} else if (alert > 1) {
|
|
if (strikes % ping == 0) {
|
|
sendAlert(event, strikes, true);
|
|
} else if (strikes % each == 0) {
|
|
sendAlert(event, strikes, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void cleanup() {
|
|
for (Iterator<UUID> it = map.keySet().iterator(); it.hasNext(); ) {
|
|
UUID playerUUID = it.next();
|
|
purge(map.get(playerUUID).iterator());
|
|
if (map.get(playerUUID).isEmpty()) {
|
|
it.remove();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void purge(Iterator<BlockEvent> events) {
|
|
Date now = Calendar.getInstance().getTime();
|
|
while (events.hasNext()) {
|
|
BlockEvent e = events.next();
|
|
int purge = 1000 * 60 * this.plugin.getConfigIntFallback(
|
|
30,
|
|
String.format("ore.blocks.%s.purge", Lang.getMaterialKey(e.getMaterial())),
|
|
"ore.purge"
|
|
);
|
|
if (new Date(e.getTime().getTime() + purge).before(now)) {
|
|
cache.remove(e.getLocation());
|
|
events.remove();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void sendAlert(BlockEvent event, int strikes, boolean ping) {
|
|
String message = Lang.ORE_ALERT.getMessage(event.getPlayer().getName(), strikes, Lang.getMaterialName(event.getMaterial()));
|
|
String hexColor = this.plugin.getConfigStringFallback(
|
|
"#AAAAAA",
|
|
String.format("ore.blocks.%s.color", Lang.getMaterialKey(event.getMaterial())),
|
|
"ore.color"
|
|
);
|
|
String usernameURL = this.plugin.getConfigStringFallback(
|
|
"",
|
|
String.format("ore.blocks.%s.url", Lang.getMaterialKey(event.getMaterial())),
|
|
"ore.url",
|
|
"url"
|
|
).replaceAll("\\{username}", event.getPlayer().getName());
|
|
|
|
ComponentBuilder builder = new ComponentBuilder()
|
|
.append(message).color(ChatColor.of(hexColor));
|
|
if (!"".equals(usernameURL)) {
|
|
builder.event(new ClickEvent(ClickEvent.Action.OPEN_URL, usernameURL));
|
|
}
|
|
BaseComponent[] component = builder.create();
|
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
|
if (player.hasPermission("minealert.alert")) {
|
|
player.spigot().sendMessage(component);
|
|
}
|
|
}
|
|
|
|
// Webhook
|
|
String webhook = this.plugin.getConfigStringFallback(
|
|
"",
|
|
String.format("ore.blocks.%s.webhook", Lang.getMaterialKey(event.getMaterial())),
|
|
"ore.webhook",
|
|
"webhook"
|
|
);
|
|
if (!"".equals(webhook)) {
|
|
Embed embed = new Embed()
|
|
.color(Color.hexToInt(hexColor))
|
|
.description(Javacord.escapeFormat(message))
|
|
.timestamp(OffsetDateTime.now())
|
|
.author(new Author(event.getPlayer().getName(),
|
|
!"".equals(usernameURL) ? usernameURL : "",
|
|
String.format("https://minotar.net/helm/%s/100.png", event.getPlayer().getName()),
|
|
""));
|
|
this.plugin.getServer().getScheduler().runTaskAsynchronously(this.plugin, () -> {
|
|
try {
|
|
Javacord.sendWebhook(webhook, new Webhook(ping ? "@here" : "", embed));
|
|
} catch (Exception e) {
|
|
this.plugin.log(Lang.WEBHOOK_FAILED.getMessage());
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
public static Set<Location> getCache() {
|
|
return cache;
|
|
}
|
|
|
|
public static Map<UUID, List<BlockEvent>> getMap() {
|
|
return map;
|
|
}
|
|
|
|
public static Queue<BlockEvent> getQueue() {
|
|
return queue;
|
|
}
|
|
|
|
private static class BlockEvent {
|
|
private final Player player;
|
|
private final Material material;
|
|
private final Location location;
|
|
private final Boolean parent;
|
|
private final Date time;
|
|
|
|
BlockEvent(Player player, Material material, Location location, Boolean parent) {
|
|
this.player = player;
|
|
this.material = material;
|
|
this.location = location;
|
|
this.parent = parent;
|
|
this.time = Calendar.getInstance().getTime();
|
|
}
|
|
|
|
public Player getPlayer() {
|
|
return player;
|
|
}
|
|
|
|
public Material getMaterial() {
|
|
return material;
|
|
}
|
|
|
|
public Location getLocation() {
|
|
return location;
|
|
}
|
|
|
|
public Boolean isParent() {
|
|
return parent;
|
|
}
|
|
|
|
public Date getTime() {
|
|
return time;
|
|
}
|
|
}
|
|
} |