diff --git a/core/src/main/java/tc/oc/pgm/api/Modules.java b/core/src/main/java/tc/oc/pgm/api/Modules.java index cf49096ba2..0efef28bd3 100644 --- a/core/src/main/java/tc/oc/pgm/api/Modules.java +++ b/core/src/main/java/tc/oc/pgm/api/Modules.java @@ -35,6 +35,8 @@ import tc.oc.pgm.destroyable.DestroyableMatchModule; import tc.oc.pgm.destroyable.DestroyableModule; import tc.oc.pgm.doublejump.DoubleJumpMatchModule; +import tc.oc.pgm.enderchest.EnderChestMatchModule; +import tc.oc.pgm.enderchest.EnderChestModule; import tc.oc.pgm.fallingblocks.FallingBlocksMatchModule; import tc.oc.pgm.fallingblocks.FallingBlocksModule; import tc.oc.pgm.ffa.FreeForAllMatchModule; @@ -259,6 +261,7 @@ static void registerAll() { WorldBorderModule.class, WorldBorderMatchModule.class, new WorldBorderModule.Factory()); register(SpawnerModule.class, SpawnerMatchModule.class, new SpawnerModule.Factory()); register(ShopModule.class, ShopMatchModule.class, new ShopModule.Factory()); + register(EnderChestModule.class, EnderChestMatchModule.class, new EnderChestModule.Factory()); // MapModules that are also MatchModules register(WorldTimeModule.class, WorldTimeModule.class, new WorldTimeModule.Factory()); diff --git a/core/src/main/java/tc/oc/pgm/enderchest/Dropoff.java b/core/src/main/java/tc/oc/pgm/enderchest/Dropoff.java new file mode 100644 index 0000000000..17fa858b5f --- /dev/null +++ b/core/src/main/java/tc/oc/pgm/enderchest/Dropoff.java @@ -0,0 +1,23 @@ +package tc.oc.pgm.enderchest; + +import tc.oc.pgm.api.filter.Filter; +import tc.oc.pgm.api.region.Region; + +public class Dropoff { + + private final Region region; + private final Filter filter; + + public Dropoff(Region region, Filter filter) { + this.region = region; + this.filter = filter; + } + + public Region getRegion() { + return region; + } + + public Filter getFilter() { + return filter; + } +} diff --git a/core/src/main/java/tc/oc/pgm/enderchest/DropoffFallback.java b/core/src/main/java/tc/oc/pgm/enderchest/DropoffFallback.java new file mode 100644 index 0000000000..d9fba35f44 --- /dev/null +++ b/core/src/main/java/tc/oc/pgm/enderchest/DropoffFallback.java @@ -0,0 +1,8 @@ +package tc.oc.pgm.enderchest; + +/** what behavior enderchests will fallback on in the absence of dropoff locations * */ +public enum DropoffFallback { + KEEP, + DELETE, + AUTO; +} diff --git a/core/src/main/java/tc/oc/pgm/enderchest/EnderChestMatchModule.java b/core/src/main/java/tc/oc/pgm/enderchest/EnderChestMatchModule.java new file mode 100644 index 0000000000..5a915ee466 --- /dev/null +++ b/core/src/main/java/tc/oc/pgm/enderchest/EnderChestMatchModule.java @@ -0,0 +1,90 @@ +package tc.oc.pgm.enderchest; + +import com.google.common.collect.ImmutableList; +import java.util.List; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import tc.oc.pgm.api.match.Match; +import tc.oc.pgm.api.match.MatchModule; +import tc.oc.pgm.api.match.MatchScope; +import tc.oc.pgm.api.party.Competitor; +import tc.oc.pgm.api.party.Party; +import tc.oc.pgm.events.ListenerScope; +import tc.oc.pgm.events.PlayerJoinMatchEvent; +import tc.oc.pgm.events.PlayerPartyChangeEvent; + +@ListenerScope(MatchScope.LOADED) +public class EnderChestMatchModule implements MatchModule, Listener { + + private final Match match; + private final boolean enabled; + private final DropoffFallback fallback; + + private final ImmutableList dropoffs; + + public EnderChestMatchModule( + Match match, boolean enabled, List dropoffs, DropoffFallback fallback) { + this.match = match; + this.enabled = enabled; + this.dropoffs = ImmutableList.copyOf(dropoffs); + this.fallback = fallback; + } + + public boolean isEnabled() { + return enabled; + } + + @EventHandler + public void onPlayerJoin(PlayerJoinMatchEvent event) { + event.getPlayer().getBukkit().getEnderChest().clear(); + } + + @EventHandler + public void onParticipantLeave(PlayerPartyChangeEvent event) { + if (!isEnabled()) return; + if (dropoffs.isEmpty()) return; + Party oldParty = event.getOldParty(); + if (!(oldParty instanceof Competitor)) return; + + Inventory enderchest = event.getPlayer().getBukkit().getEnderChest(); + + boolean dropped = false; + for (Dropoff dropoff : dropoffs) { + if (dropoff.getFilter().query(oldParty).isAllowed()) { + drop( + enderchest, + dropoff.getRegion().getRandom(match.getRandom()).toLocation(match.getWorld())); + dropped = true; + break; + } + } + + if (!dropped) { + switch (fallback) { + case AUTO: + if (dropoffs.isEmpty()) { + enderchest.clear(); + } + break; + case DELETE: + enderchest.clear(); + break; + default: + break; + } + } + } + + private void drop(Inventory inventory, Location location) { + for (ItemStack item : inventory.getContents()) { + if (item != null && item.getType() != Material.AIR) { + location.getWorld().dropItem(location, item); + } + } + inventory.clear(); + } +} diff --git a/core/src/main/java/tc/oc/pgm/enderchest/EnderChestModule.java b/core/src/main/java/tc/oc/pgm/enderchest/EnderChestModule.java new file mode 100644 index 0000000000..1fac94b30c --- /dev/null +++ b/core/src/main/java/tc/oc/pgm/enderchest/EnderChestModule.java @@ -0,0 +1,71 @@ +package tc.oc.pgm.enderchest; + +import com.google.common.collect.Lists; +import java.util.List; +import java.util.logging.Logger; +import org.jdom2.Document; +import org.jdom2.Element; +import tc.oc.pgm.api.filter.Filter; +import tc.oc.pgm.api.map.MapModule; +import tc.oc.pgm.api.map.factory.MapFactory; +import tc.oc.pgm.api.map.factory.MapModuleFactory; +import tc.oc.pgm.api.match.Match; +import tc.oc.pgm.api.match.MatchModule; +import tc.oc.pgm.api.region.Region; +import tc.oc.pgm.filters.parse.FilterParser; +import tc.oc.pgm.regions.RandomPointsValidation; +import tc.oc.pgm.regions.RegionParser; +import tc.oc.pgm.util.xml.InvalidXMLException; +import tc.oc.pgm.util.xml.Node; +import tc.oc.pgm.util.xml.XMLUtils; + +public class EnderChestModule implements MapModule { + + private final boolean enabled; + private final List dropoffs; + private final DropoffFallback fallback; + + public EnderChestModule(boolean enabled, List dropoffs, DropoffFallback fallback) { + this.enabled = enabled; + this.dropoffs = dropoffs; + this.fallback = fallback; + } + + @Override + public MatchModule createMatchModule(Match match) { + return new EnderChestMatchModule(match, enabled, dropoffs, fallback); + } + + public static class Factory implements MapModuleFactory { + @Override + public EnderChestModule parse(MapFactory factory, Logger logger, Document doc) + throws InvalidXMLException { + FilterParser filters = factory.getFilters(); + RegionParser regions = factory.getRegions(); + + boolean enabled = false; + DropoffFallback fallback = DropoffFallback.AUTO; + List dropoffs = Lists.newArrayList(); + + for (Element enderchestEl : doc.getRootElement().getChildren("enderchest")) { + fallback = + XMLUtils.parseEnum( + Node.fromAttr(enderchestEl, "fallback"), + DropoffFallback.class, + "fallback", + DropoffFallback.AUTO); + enabled = true; + } + + for (Element dropoffEl : + XMLUtils.flattenElements(doc.getRootElement(), "enderchest", "dropoff")) { + Region region = + regions.parseRequiredProperty(dropoffEl, "region", RandomPointsValidation.INSTANCE); + Filter filter = filters.parseRequiredProperty(dropoffEl, "filter"); + dropoffs.add(new Dropoff(region, filter)); + } + + return new EnderChestModule(enabled, dropoffs, fallback); + } + } +}