minions-plus/src/main/java/pw/hamzantal/minionsplus/manager/MinionManager.java

164 lines
5.7 KiB
Java

package pw.hamzantal.minionsplus.manager;
import com.google.gson.*;
import lombok.Getter;
import pw.hamzantal.minionsplus.MinionsPlus;
import pw.hamzantal.minionsplus.menu.MinionMenu;
import pw.hamzantal.minionsplus.model.Minion;
import pw.hamzantal.minionsplus.model.minions.ButcherMinion;
import pw.hamzantal.minionsplus.util.ItemUtil;
import pw.hamzantal.minionsplus.util.Text;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.player.PlayerArmorStandManipulateEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitTask;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.*;
public class MinionManager implements Listener {
private final MinionsPlus plugin;
private final BukkitTask animationTask;
private final BukkitTask tickTask;
@Getter
private final Map<LivingEntity, ButcherMinion> butcherKillMap = new HashMap<>();
@Getter
private Set<Minion> minions = new HashSet<>();
public MinionManager(MinionsPlus plugin) {
this.plugin = plugin;
this.animationTask = Bukkit.getScheduler().runTaskTimer(this.plugin, () -> this.minions.forEach(Minion::animationTick), 1, 1);
final int actionSpeed = this.plugin.getConfig().getInt("Action-Speed", 20);
this.tickTask = Bukkit.getScheduler().runTaskTimer(this.plugin, () -> this.minions.forEach(Minion::tick), actionSpeed, actionSpeed);
Bukkit.getPluginManager().registerEvents(this, this.plugin);
loadMinions();
}
public void close() {
this.animationTask.cancel();
this.tickTask.cancel();
HandlerList.unregisterAll(this);
saveMinions();
}
private void loadMinions() {
final File dataFile = new File(this.plugin.getDataFolder(), "minions.json");
if (!dataFile.exists()) return;
final Gson gson = new Gson();
try (final BufferedReader reader = Files.newBufferedReader(dataFile.toPath(), StandardCharsets.UTF_8)) {
JsonObject data = gson.fromJson(reader, JsonObject.class);
JsonArray minions = data.get("minions").getAsJsonArray();
for (JsonElement el : minions) {
try {
Minion minion = Minion.deserialize(this.plugin, el);
this.minions.add(minion);
} catch (Exception e) {
this.plugin.getLogger().severe("Failed to load minion.");
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void saveMinions() {
final File dataFile = new File(this.plugin.getDataFolder(), "minions.json");
final Gson gson = new Gson();
try (final BufferedWriter writer = Files.newBufferedWriter(dataFile.toPath(), StandardCharsets.UTF_8)) {
JsonObject data = new JsonObject();
JsonArray minions = new JsonArray();
for (Minion minion : this.minions) {
try {
minions.add(minion.serialize());
} catch (Exception e) {
this.plugin.getLogger().severe("Failed to save minion: " + minion.getOwnerName() + " : " + minion.getName());
e.printStackTrace();
}
}
data.add("minions", minions);
writer.write(gson.toJson(data));
} catch (IOException e) {
e.printStackTrace();
}
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onDamage(final EntityDamageEvent e) {
if (!(e.getEntity() instanceof ArmorStand)) return;
if (this.minions.stream()
.map(Minion::getId)
.filter(Objects::nonNull)
.anyMatch(uuid -> uuid.equals(e.getEntity().getUniqueId()))) {
e.setCancelled(true);
}
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onRightClick(final PlayerArmorStandManipulateEvent e) {
this.minions.stream()
.filter(minion -> minion.getId() != null)
.filter(minion -> minion.getId().equals(e.getRightClicked().getUniqueId()))
.findFirst().ifPresent(minion -> {
e.setCancelled(true);
if (!minion.getOwner().equals(e.getPlayer().getUniqueId())) {
e.getPlayer().sendMessage(Text.color("&cOnly the owner of the minion can interact with it."));
return;
}
if (e.getPlayer().isSneaking()) {
minion.despawn(e.getPlayer());
return;
}
new MinionMenu(minion, e.getPlayer());
});
}
@EventHandler(priority = EventPriority.LOWEST)
public void onPlace(PlayerInteractEvent e) {
if (!e.hasItem() || !Minion.isMinion(e.getItem())) return;
e.setCancelled(true);
if (!e.hasBlock()) return;
final Location loc = e.getClickedBlock().getRelative(e.getBlockFace()).getLocation().add(0.5, 0, 0.5);
final Minion minion = Minion.of(e.getItem(), loc);
minion.spawn(loc);
ItemUtil.consumeItem(e.getPlayer().getInventory(), 1, e.getItem());
}
@EventHandler
public void onLivingEntityDeath(final EntityDeathEvent e) {
if (!this.butcherKillMap.containsKey(e.getEntity())) return;
final ButcherMinion minion = this.butcherKillMap.remove(e.getEntity());
final List<ItemStack> drops = e.getDrops();
minion.getLinkedBlocks().stream().filter(b -> b.getState() instanceof InventoryHolder).forEachOrdered(b -> {
InventoryHolder inv = (InventoryHolder) b.getState();
final Collection<ItemStack> remaining = inv.getInventory().addItem(drops.toArray(new ItemStack[]{})).values();
drops.clear();
drops.addAll(remaining);
});
if (!drops.isEmpty()) {
drops.forEach(item -> minion.getLocation().getWorld().dropItemNaturally(minion.getLocation(), item));
}
}
}