225 lines
9.5 KiB
Java
225 lines
9.5 KiB
Java
package tc.oc.pgm.wool;
|
|
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Map.Entry;
|
|
import javax.inject.Inject;
|
|
|
|
import com.google.common.collect.ImmutableList;
|
|
import net.md_5.bungee.api.chat.BaseComponent;
|
|
import net.md_5.bungee.api.chat.TranslatableComponent;
|
|
import org.bukkit.ChatColor;
|
|
import org.bukkit.DyeColor;
|
|
import org.bukkit.Material;
|
|
import org.bukkit.block.BlockState;
|
|
import org.bukkit.entity.Player;
|
|
import org.bukkit.event.EventHandler;
|
|
import org.bukkit.event.EventPriority;
|
|
import org.bukkit.event.Listener;
|
|
import org.bukkit.event.block.BlockPlaceEvent;
|
|
import org.bukkit.event.inventory.InventoryMoveItemEvent;
|
|
import org.bukkit.event.inventory.InventoryOpenEvent;
|
|
import org.bukkit.event.inventory.PrepareItemCraftEvent;
|
|
import org.bukkit.inventory.Inventory;
|
|
import org.bukkit.inventory.InventoryHolder;
|
|
import org.bukkit.inventory.ItemStack;
|
|
import org.bukkit.util.Vector;
|
|
import tc.oc.commons.bukkit.util.BlockUtils;
|
|
import tc.oc.commons.bukkit.util.BukkitUtils;
|
|
import tc.oc.commons.core.stream.Collectors;
|
|
import tc.oc.time.Time;
|
|
import tc.oc.pgm.Config;
|
|
import tc.oc.pgm.PGMTranslations;
|
|
import tc.oc.pgm.events.BlockTransformEvent;
|
|
import tc.oc.pgm.events.ListenerScope;
|
|
import tc.oc.pgm.events.ParticipantBlockTransformEvent;
|
|
import tc.oc.pgm.goals.Contribution;
|
|
import tc.oc.pgm.goals.events.GoalCompleteEvent;
|
|
import tc.oc.pgm.goals.events.GoalStatusChangeEvent;
|
|
import tc.oc.pgm.match.Match;
|
|
import tc.oc.pgm.match.MatchModule;
|
|
import tc.oc.pgm.match.MatchPlayer;
|
|
import tc.oc.pgm.match.MatchScope;
|
|
import tc.oc.pgm.match.ParticipantState;
|
|
import tc.oc.pgm.match.Repeatable;
|
|
|
|
@ListenerScope(MatchScope.RUNNING)
|
|
public class WoolMatchModule extends MatchModule implements Listener {
|
|
private final List<MonumentWool> wools;
|
|
|
|
// Map of containers to a flag indicating whether they contained objective wool when the match started.
|
|
// For this to work, containers have to be checked for wool before their contents can be changed. To ensure this,
|
|
// containers are registered in this map the first time they are opened or accessed by a hopper or dispenser.
|
|
protected final Map<Inventory, Boolean> chests = new HashMap<>();
|
|
|
|
// Containers that did contain wool when the match started have an entry in this map representing the exact
|
|
// layout of the wools in the inventory. This is used to refill the container with wools.
|
|
protected final Map<Inventory, Map<Integer, ItemStack>> woolChests = new HashMap<>();
|
|
|
|
@Inject private WoolMatchModule(Match match, List<MonumentWoolFactory> wools) {
|
|
this.wools = wools.stream()
|
|
.map(def -> def.getGoal(match))
|
|
.collect(Collectors.toImmutableList());
|
|
}
|
|
|
|
private boolean isObjectiveWool(ItemStack stack) {
|
|
if(stack.getType() == Material.WOOL) {
|
|
for(MonumentWool wool : this.wools) {
|
|
if(wool.getDefinition().isObjectiveWool(stack)) return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private boolean containsObjectiveWool(Inventory inventory) {
|
|
for(MonumentWool wool : this.wools) {
|
|
if(wool.getDefinition().isHolding(inventory)) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private void registerContainer(Inventory inv) {
|
|
// When a chest (or other block inventory) is accessed, check if it's a wool chest
|
|
Boolean isWoolChest = this.chests.get(inv);
|
|
if(isWoolChest == null) {
|
|
// If we haven't seen this chest yet, check it for wool
|
|
isWoolChest = this.containsObjectiveWool(inv);
|
|
this.chests.put(inv, isWoolChest);
|
|
|
|
if(isWoolChest) {
|
|
// If it is a wool chest, take a snapshot of the wools
|
|
Map<Integer, ItemStack> contents = new HashMap<>();
|
|
this.woolChests.put(inv, contents);
|
|
for(int slot = 0; slot < inv.getSize(); ++slot) {
|
|
ItemStack stack = inv.getItem(slot);
|
|
if(stack != null && this.isObjectiveWool(stack)) {
|
|
contents.put(slot, stack.clone());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Repeatable(interval = @Time(seconds = 30), scope = MatchScope.RUNNING)
|
|
public void refillOneWoolPerContainer() {
|
|
if(!Config.Wool.autoRefillWoolChests()) return;
|
|
|
|
for(Entry<Inventory, Map<Integer, ItemStack>> chest : this.woolChests.entrySet()) {
|
|
Inventory inv = chest.getKey();
|
|
for(Entry<Integer, ItemStack> slotEntry : chest.getValue().entrySet()) {
|
|
int slot = slotEntry.getKey();
|
|
ItemStack wool = slotEntry.getValue();
|
|
ItemStack stack = inv.getItem(slotEntry.getKey());
|
|
|
|
if(stack == null) {
|
|
stack = wool.clone();
|
|
stack.setAmount(1);
|
|
inv.setItem(slot, stack);
|
|
break;
|
|
} else if(stack.isSimilar(wool) && stack.getAmount() < wool.getAmount()) {
|
|
stack.setAmount(stack.getAmount() + 1);
|
|
inv.setItem(slot, stack);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
|
public void onInventoryOpen(InventoryOpenEvent event) {
|
|
// Register container blocks when they are opened
|
|
this.registerContainer(event.getInventory());
|
|
}
|
|
|
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
|
public void onItemTransfer(InventoryMoveItemEvent event) {
|
|
// When a hopper or dispenser transfers an item, register both blocks involved
|
|
this.registerContainer(event.getSource());
|
|
this.registerContainer(event.getDestination());
|
|
}
|
|
|
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
|
public void onContainerPlace(BlockPlaceEvent event) {
|
|
// Blacklist any placed container blocks
|
|
if(event.getBlock().getState() instanceof InventoryHolder) {
|
|
this.chests.put(((InventoryHolder) event.getBlock().getState()).getInventory(), false);
|
|
}
|
|
}
|
|
|
|
@EventHandler(priority = EventPriority.MONITOR)
|
|
public void placementCheck(final BlockTransformEvent event) {
|
|
if(this.match.getWorld() != event.getWorld()) return;
|
|
|
|
final MonumentWool wool = this.findMonumentWool(BlockUtils.center(event.getNewState()).toVector());
|
|
if(wool == null) return;
|
|
|
|
if(event.getNewState().getType() == Material.AIR) { // block is being destroyed
|
|
if(isValidWool(wool.getDyeColor(), event.getOldState())) {
|
|
event.setCancelled(true);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// default to cancelled; only uncancel if player is placing the correct color wool (see below)
|
|
event.setCancelled(true);
|
|
|
|
ParticipantState player = ParticipantBlockTransformEvent.getPlayerState(event);
|
|
if(player != null) { // wool can only be placed by a player
|
|
BaseComponent woolName = BukkitUtils.woolName(wool.getDyeColor());
|
|
if(!isValidWool(wool.getDyeColor(), event.getNewState())) {
|
|
player.sendWarning(new TranslatableComponent("match.wool.placeWrong", woolName), true);
|
|
} else if(wool.getOwner() != player.getParty()) {
|
|
player.sendWarning(new TranslatableComponent("match.wool.placeOther", wool.getOwner().getComponentName(), woolName), true);
|
|
} else {
|
|
event.setCancelled(false);
|
|
wool.markPlaced();
|
|
this.match.callEvent(new GoalStatusChangeEvent(wool));
|
|
this.match.callEvent(new PlayerWoolPlaceEvent(player, wool, event.getNewState()));
|
|
this.match.callEvent(new GoalCompleteEvent(wool,
|
|
true,
|
|
c -> false,
|
|
c -> c.equals(wool.getOwner()),
|
|
ImmutableList.of(new Contribution(player, 1))));
|
|
}
|
|
}
|
|
}
|
|
|
|
@EventHandler
|
|
public void handleWoolCrafting(PrepareItemCraftEvent event) {
|
|
if(event.getRecipe() == null) return;
|
|
|
|
ItemStack result = event.getRecipe().getResult();
|
|
InventoryHolder holder = event.getInventory().getHolder();
|
|
|
|
if (holder instanceof Player) {
|
|
MatchPlayer playerHolder = this.match.getPlayer((Player) holder);
|
|
|
|
if (playerHolder != null && result != null && result.getType() == Material.WOOL) {
|
|
for(MonumentWool wool : this.wools) {
|
|
if(wool.getDefinition().isObjectiveWool(result)) {
|
|
if(!wool.getDefinition().isCraftable()) {
|
|
playerHolder.sendMessage(ChatColor.RED + PGMTranslations.t("match.wool.craftDisabled", playerHolder, BukkitUtils.woolMessage(wool.getDyeColor())));
|
|
event.getInventory().setResult(null);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private MonumentWool findMonumentWool(Vector point) {
|
|
for(MonumentWool wool : this.wools) {
|
|
if(wool.getDefinition().getPlacementRegion().contains(point)) {
|
|
return wool;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@SuppressWarnings("deprecation")
|
|
private static boolean isValidWool(DyeColor expectedColor, BlockState state) {
|
|
return state.getType() == Material.WOOL && expectedColor.getWoolData() == state.getRawData();
|
|
}
|
|
}
|