diff --git a/core/src/main/java/tc/oc/pgm/controlpoint/ControlPointMatchModule.java b/core/src/main/java/tc/oc/pgm/controlpoint/ControlPointMatchModule.java index 204928b2ad..0d55dbf2d9 100644 --- a/core/src/main/java/tc/oc/pgm/controlpoint/ControlPointMatchModule.java +++ b/core/src/main/java/tc/oc/pgm/controlpoint/ControlPointMatchModule.java @@ -6,24 +6,28 @@ 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.payload.PayloadListener; public class ControlPointMatchModule implements MatchModule { private final Match match; private final List controlPoints = new ArrayList<>(); private final ControlPointAnnouncer announcer; + private final PayloadListener payloadListener; public ControlPointMatchModule(Match match, List points) { this.match = match; this.controlPoints.addAll(points); this.announcer = new ControlPointAnnouncer(this.match); + this.payloadListener = new PayloadListener(); match.addTickable(new ControlPointTickTask(this.controlPoints), MatchScope.RUNNING); } @Override public void load() { this.match.addListener(this.announcer, MatchScope.RUNNING); + this.match.addListener(this.payloadListener, MatchScope.RUNNING); for (ControlPoint controlPoint : this.controlPoints) { controlPoint.registerEvents(); } @@ -35,5 +39,6 @@ public void unload() { controlPoint.unregisterEvents(); } HandlerList.unregisterAll(this.announcer); + HandlerList.unregisterAll(this.payloadListener); } } diff --git a/core/src/main/java/tc/oc/pgm/controlpoint/RegionPlayerTracker.java b/core/src/main/java/tc/oc/pgm/controlpoint/RegionPlayerTracker.java index d55f3e98d4..cda4c30d28 100644 --- a/core/src/main/java/tc/oc/pgm/controlpoint/RegionPlayerTracker.java +++ b/core/src/main/java/tc/oc/pgm/controlpoint/RegionPlayerTracker.java @@ -18,7 +18,7 @@ /** Tracks which players are on a control point and answers some queries about them */ public class RegionPlayerTracker implements Listener { private final Match match; - private final Set playersOnPoint = Sets.newHashSet(); + private final Set players = Sets.newHashSet(); private Region region; @@ -28,7 +28,7 @@ public RegionPlayerTracker(Match match, Region region) { } public Set getPlayers() { - return this.playersOnPoint; + return this.players; } public void setRegion(Region region) { @@ -53,14 +53,14 @@ public void handlePlayerMove(Player bukkit, Vector to) { if (!MatchPlayers.canInteract(player)) return; if (!player.getBukkit().isDead() && this.region.contains(to.toBlockVector())) { - this.playersOnPoint.add(player); + this.players.add(player); } else { - this.playersOnPoint.remove(player); + this.players.remove(player); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerDespawn(final ParticipantDespawnEvent event) { - playersOnPoint.remove(event.getPlayer()); + players.remove(event.getPlayer()); } } diff --git a/core/src/main/java/tc/oc/pgm/payload/Payload.java b/core/src/main/java/tc/oc/pgm/payload/Payload.java index cdf2417bbb..3a04195f54 100644 --- a/core/src/main/java/tc/oc/pgm/payload/Payload.java +++ b/core/src/main/java/tc/oc/pgm/payload/Payload.java @@ -1,25 +1,39 @@ package tc.oc.pgm.payload; import java.time.Duration; +import org.bukkit.ChatColor; import org.bukkit.Color; +import org.bukkit.DyeColor; import org.bukkit.Effect; import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Minecart; +import org.bukkit.material.Wool; +import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.util.Vector; +import tc.oc.pgm.api.PGM; import tc.oc.pgm.api.match.Match; import tc.oc.pgm.api.party.Competitor; import tc.oc.pgm.api.region.Region; import tc.oc.pgm.controlpoint.ControlPoint; import tc.oc.pgm.payload.track.Track; +import tc.oc.pgm.util.bukkit.BukkitUtils; public class Payload extends ControlPoint { private static final int PARTICLE_AMOUNT = 6; // 6 particles private static final int PARTICLE_ROTATION = 20; // ticks per full rotation + private static final String METADATA_KEY = "payload"; + + private static final Vector MINECART_OFFSET = new Vector(0, 0.0625, 0); + private static final double MAX_OFFSET_SQ = Math.pow(0.25, 2); // Max offset of 0.25 + private final Match match; private final PayloadDefinition definition; private final Track track; + private final Minecart minecart; private final PayloadRegion captureRegion; private Competitor dominantTeam; @@ -30,12 +44,25 @@ public Payload(Match match, PayloadDefinition definition) { this.match = match; this.definition = definition; - this.track = new Track(match, definition.getLocation()); this.position = definition.getLocation(); + + this.track = new Track(match, definition.getLocation()); + this.minecart = spawnMinecart(); this.captureRegion = new PayloadRegion(this::getCenterPoint, definition.getRadius()); + this.playerTracker.setRegion(captureRegion); } + private Minecart spawnMinecart() { + Minecart minecart = + match.getWorld().spawn(position.toLocation(match.getWorld()), Minecart.class); + + minecart.setDisplayBlock(new Wool(DyeColor.WHITE)); + minecart.setSlowWhenEmpty(true); + minecart.setMetadata(METADATA_KEY, new FixedMetadataValue(PGM.get(), true)); + return minecart; + } + @Override public Region getCaptureRegion() { return captureRegion; @@ -58,23 +85,23 @@ public void tick(Duration duration) { if (!oldPos.toBlockVector().equals(position.toBlockVector())) playerTracker.setRegion(captureRegion); - tickDisplay(match.getTick().tick); + tickParticles(match.getTick().tick); + tickMinecart(); } - private void tickDisplay(long tick) { - if (!definition.getDisplayFilter().query(match).isAllowed()) return; - Color color = - dominantTeam != null - ? dominantTeam.getFullColor() - : controllingTeam != null ? controllingTeam.getFullColor() : Color.WHITE; + private Competitor getDisplayTeam() { + return dominantTeam != null ? dominantTeam : controllingTeam != null ? controllingTeam : null; + } - Location loc = position.toLocation(match.getWorld()).add(0, 0.5, 0); - spawnParticle(loc, color); + private void tickParticles(long tick) { + if (!definition.getDisplayFilter().query(match).isAllowed()) return; + Competitor display = getDisplayTeam(); + Color color = display != null ? display.getFullColor() : Color.WHITE; double diff = Math.PI * 2 / PARTICLE_AMOUNT; double offset = (double) tick * diff / PARTICLE_ROTATION; - // Each iteration of this loop is one particle + Location loc = new Location(match.getWorld(), 0, 0, 0); for (int i = 0; i < PARTICLE_AMOUNT; i++) { double angle = i * diff + offset; // Height between 0.2 and 0.8 @@ -85,34 +112,56 @@ private void tickDisplay(long tick) { height, definition.getRadius() * Math.sin(angle)); loc.add(position); - spawnParticle(loc, color); + match + .getWorld() + .spigot() + .playEffect( + loc, + Effect.COLOURED_DUST, + 0, + (byte) 0, + rgbToParticle(color.getRed()), + rgbToParticle(color.getGreen()), + rgbToParticle(color.getBlue()), + 1, + 0, + 50); } } - private void spawnParticle(Location loc, Color color) { - match - .getWorld() - .spigot() - .playEffect( - loc, - Effect.COLOURED_DUST, - 0, - (byte) 0, - rgbToParticle(color.getRed()), - rgbToParticle(color.getGreen()), - rgbToParticle(color.getBlue()), - 1, - 0, - 200); - } - private float rgbToParticle(int rgb) { return (float) Math.max(0.001, rgb / 255.0); } + private void tickMinecart() { + Vector current = minecart.getLocation().toVector(); + Vector desired = position.clone().add(MINECART_OFFSET); + + if (current.distanceSquared(desired) > MAX_OFFSET_SQ) + minecart.teleport(desired.toLocation(minecart.getWorld())); + else minecart.setVelocity(desired.subtract(current)); + } + + private void updateWool() { + Competitor display = getDisplayTeam(); + DyeColor color = + BukkitUtils.chatColorToDyeColor(display != null ? display.getColor() : ChatColor.WHITE); + + Wool data = (Wool) minecart.getDisplayBlock(); + data.setColor(color); + minecart.setDisplayBlock(data); + } + @Override protected void dominate(Competitor dominantTeam, Duration dominantTime, boolean contested) { - this.dominantTeam = dominantTeam; + if (this.dominantTeam != dominantTeam) { + this.dominantTeam = dominantTeam; + updateWool(); + } super.dominate(dominantTeam, dominantTime, contested); } + + public static boolean isPayload(Entity entity) { + return entity.hasMetadata(METADATA_KEY); + } } diff --git a/core/src/main/java/tc/oc/pgm/payload/PayloadListener.java b/core/src/main/java/tc/oc/pgm/payload/PayloadListener.java new file mode 100644 index 0000000000..eed4f8c51e --- /dev/null +++ b/core/src/main/java/tc/oc/pgm/payload/PayloadListener.java @@ -0,0 +1,25 @@ +package tc.oc.pgm.payload; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.vehicle.VehicleDamageEvent; +import org.bukkit.event.vehicle.VehicleDestroyEvent; +import org.bukkit.event.vehicle.VehicleEnterEvent; + +public class PayloadListener implements Listener { + + @EventHandler + public void onVehicleDamage(final VehicleDamageEvent event) { + if (Payload.isPayload(event.getVehicle())) event.setCancelled(true); + } + + @EventHandler + public void onVehicleEnter(final VehicleEnterEvent event) { + if (Payload.isPayload(event.getVehicle())) event.setCancelled(true); + } + + @EventHandler + public void onVehicleDestroy(final VehicleDestroyEvent event) { + if (Payload.isPayload(event.getVehicle())) event.setCancelled(true); + } +} diff --git a/core/src/main/java/tc/oc/pgm/payload/PayloadRegion.java b/core/src/main/java/tc/oc/pgm/payload/PayloadRegion.java index 1ad3a0d131..fefa354b1d 100644 --- a/core/src/main/java/tc/oc/pgm/payload/PayloadRegion.java +++ b/core/src/main/java/tc/oc/pgm/payload/PayloadRegion.java @@ -7,24 +7,29 @@ import tc.oc.pgm.regions.AbstractRegion; import tc.oc.pgm.regions.Bounds; -/** This is a region that is not immutable. The origin point of the sphere can move. */ +/** This is a region that is not immutable. The origin point of the cylinder can move. */ public class PayloadRegion extends AbstractRegion { - private final Supplier origin; + private final Supplier base; private final double radius; private final double radiusSq; - public PayloadRegion(Supplier origin, double radius) { + public PayloadRegion(Supplier base, double radius) { checkArgument(radius >= 0); - this.origin = origin; + this.base = base; this.radius = radius; this.radiusSq = Math.pow(radius, 2); } @Override public boolean contains(Vector point) { - return origin.get().distanceSquared(point) <= radiusSq; + Vector base = this.base.get(); + + return point.getY() >= (base.getY() - 2.5) + && point.getY() <= (base.getY() + 2.5) + && Math.pow(point.getX() - base.getX(), 2) + Math.pow(point.getZ() - base.getZ(), 2) + < this.radiusSq; } @Override @@ -34,13 +39,14 @@ public boolean isBlockBounded() { @Override public Bounds getBounds() { - Vector diagonal = new Vector(this.radius, this.radius, this.radius); + Vector base = this.base.get(); return new Bounds( - origin.get().clone().subtract(diagonal), this.origin.get().clone().add(diagonal)); + new Vector(base.getX() - this.radius, base.getY() - 2.5, base.getZ() - this.radius), + new Vector(base.getX() + this.radius, base.getY() + 2.5, base.getZ() + this.radius)); } @Override public String toString() { - return "PayloadRegion{origin=[" + this.origin.get() + "],radiusSq=" + this.radiusSq + "}"; + return "PayloadRegion{base=[" + this.base.get() + "],radiusSq=" + this.radiusSq + "}"; } } diff --git a/core/src/main/java/tc/oc/pgm/payload/track/CurvedRail.java b/core/src/main/java/tc/oc/pgm/payload/track/CurvedRail.java index ff70c60d68..3398e55f35 100644 --- a/core/src/main/java/tc/oc/pgm/payload/track/CurvedRail.java +++ b/core/src/main/java/tc/oc/pgm/payload/track/CurvedRail.java @@ -14,10 +14,15 @@ public CurvedRail(BlockFace from, BlockFace to) { @Override public Vector getOffset(double progress) { - BlockFace direction = progress < 0.5 ? from : to; - // Frame progress between 0.5 -> 0 -> 0.5, but in different directions - progress = Math.abs(progress - 0.5); - return new Vector(direction.getModX(), 0, direction.getModZ()).multiply(progress).setY(-0.5); + double remaining = 1 - progress; + + progress *= 0.5; + remaining *= 0.5; + + return new Vector( + remaining * from.getModX() + progress * to.getModX(), + -0.5, + remaining * from.getModZ() + progress * to.getModZ()); } @Override