Skip to content

Commit

Permalink
feat: TNT minecart tracking (#1292)
Browse files Browse the repository at this point in the history
Signed-off-by: TTtie <[email protected]>
  • Loading branch information
TTtie authored Mar 10, 2024
1 parent ac7b590 commit ffd116e
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 14 deletions.
2 changes: 2 additions & 0 deletions core/src/main/java/tc/oc/pgm/PGMPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
import tc.oc.pgm.util.listener.ItemTransferListener;
import tc.oc.pgm.util.listener.PlayerBlockListener;
import tc.oc.pgm.util.listener.PlayerMoveListener;
import tc.oc.pgm.util.listener.TNTMinecartPlacementListener;
import tc.oc.pgm.util.nms.NMSHacks;
import tc.oc.pgm.util.parser.SyntaxException;
import tc.oc.pgm.util.tablist.TablistResizer;
Expand Down Expand Up @@ -359,6 +360,7 @@ private void registerListeners() {
registerEvents(new PlayerBlockListener());
registerEvents(new PlayerMoveListener());
registerEvents(new ItemTransferListener());
registerEvents(new TNTMinecartPlacementListener());
new BlockTransformListener(this).registerEvents();
registerEvents(matchManager);
if (matchTabManager != null) registerEvents(matchTabManager);
Expand Down
5 changes: 3 additions & 2 deletions core/src/main/java/tc/oc/pgm/core/CoreMatchModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,9 @@ public void breakCheck(final BlockTransformEvent event) {
}
}
} else if (event.getCause() instanceof EntityExplodeEvent) {
// this is a temp fix until there is a tracker for placed minecarts (only dispensed are
// tracked right now)
// If the platform doesn't provide enough data to tell
// who owns the TNT minecart that blew up the core, cancel the
// event to prevent possible team griefing
if (((EntityExplodeEvent) event.getCause()).getEntity() instanceof ExplosiveMinecart) {
event.setCancelled(true);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import tc.oc.pgm.api.match.MatchModule;
import tc.oc.pgm.api.match.MatchScope;
import tc.oc.pgm.api.player.MatchPlayer;
import tc.oc.pgm.api.player.ParticipantState;
import tc.oc.pgm.events.ListenerScope;
import tc.oc.pgm.events.ParticipantBlockTransformEvent;
import tc.oc.pgm.goals.ShowOption;
Expand Down Expand Up @@ -57,11 +58,18 @@ public void testBlockChange(BlockTransformEvent event) {
return;
}

// This is a temp fix until there is a tracker for placed minecarts (only dispensed are tracked
// right now)
if ((event.getCause() instanceof EntityExplodeEvent
&& ((EntityExplodeEvent) event.getCause()).getEntity() instanceof ExplosiveMinecart)
|| event.getCause() instanceof BlockPistonExtendEvent
ParticipantState player = ParticipantBlockTransformEvent.getPlayerState(event);

if (event.getCause() instanceof EntityExplodeEvent
&& ((EntityExplodeEvent) event.getCause()).getEntity() instanceof ExplosiveMinecart) {
// If the platform doesn't provide enough data to tell
// who owns the TNT minecart that blew up the destroyable,
// cancel the event to prevent possible team griefing
if (player == null) {
event.setCancelled(true);
return;
}
} else if (event.getCause() instanceof BlockPistonExtendEvent
|| event.getCause() instanceof BlockPistonRetractEvent) {

event.setCancelled(true);
Expand All @@ -70,10 +78,7 @@ public void testBlockChange(BlockTransformEvent event) {

for (Destroyable destroyable : this.destroyables) {
String reasonKey =
destroyable.testBlockChange(
event.getOldState(),
event.getNewState(),
ParticipantBlockTransformEvent.getPlayerState(event));
destroyable.testBlockChange(event.getOldState(), event.getNewState(), player);
if (reasonKey != null) {
event.setCancelled(translatable(reasonKey, destroyable.getComponentName()));
return;
Expand Down
21 changes: 18 additions & 3 deletions core/src/main/java/tc/oc/pgm/tracker/trackers/TNTTracker.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,22 @@
import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.entity.minecart.ExplosiveMinecart;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.ExplosionPrimeEvent;
import tc.oc.pgm.api.match.Match;
import tc.oc.pgm.api.player.ParticipantState;
import tc.oc.pgm.events.ParticipantBlockTransformEvent;
import tc.oc.pgm.tracker.TrackerMatchModule;
import tc.oc.pgm.tracker.info.EntityInfo;
import tc.oc.pgm.tracker.info.TNTInfo;
import tc.oc.pgm.util.event.block.BlockDispenseEntityEvent;
import tc.oc.pgm.util.event.entity.ExplosionPrimeByEntityEvent;
import tc.oc.pgm.util.event.player.PlayerSpawnEntityEvent;

/** Updates the state of owned TNT blocks and entities */
public class TNTTracker extends AbstractTracker<TNTInfo> {

public TNTTracker(TrackerMatchModule tmm, Match match) {
super(TNTInfo.class, tmm, match);
}
Expand Down Expand Up @@ -70,12 +72,25 @@ public void onPrime(ExplosionPrimeEvent event) {

@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onDispense(BlockDispenseEntityEvent event) {
if (event.getEntity() instanceof TNTPrimed) {
if ((event.getEntity() instanceof TNTPrimed)
|| (event.getEntity() instanceof ExplosiveMinecart)) {
ParticipantState owner = blocks().getOwner(event.getBlock());
if (owner != null) {
entities()
.trackEntity(event.getEntity(), new TNTInfo(owner, event.getEntity().getLocation()));
.trackEntity(
event.getEntity(),
(event.getEntity() instanceof TNTPrimed)
? new TNTInfo(owner, event.getEntity().getLocation())
: new EntityInfo(event.getEntity(), owner));
}
}
}

@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onSpawn(PlayerSpawnEntityEvent event) {
ParticipantState owner = match.getParticipantState(event.getPlayer());
if (event.getEntity() instanceof ExplosiveMinecart && owner != null) {
entities().trackEntity(event.getEntity(), new EntityInfo(event.getEntity(), owner));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package tc.oc.pgm.util.listener;

import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.entity.Vehicle;
import org.bukkit.entity.minecart.ExplosiveMinecart;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.vehicle.VehicleCreateEvent;
import org.bukkit.inventory.ItemStack;
import tc.oc.pgm.util.event.player.PlayerSpawnEntityEvent;

/**
* Transforms vehicle creation events along with player interaction events to a synthetic
* PlayerSpawnEntityEvent.
*
* <p>It works based on the fact that PlayerInteractEvent and VehicleCreateEvent are emitted in the
* same tick.
*
* <p>In modern versions of Minecraft, equivalent functionality is natively implemented in Bukkit as
* EntityPlaceEvent.
*/
public class TNTMinecartPlacementListener implements Listener {
private Player lastPlacer;
private ItemStack placingStack;
private Location railLocation;

private static void handleCall(Event pgmEvent, Event bukkitEvent) {
if (bukkitEvent instanceof Cancellable) {
((Cancellable) pgmEvent).setCancelled(((Cancellable) bukkitEvent).isCancelled());
Bukkit.getServer().getPluginManager().callEvent(pgmEvent);
((Cancellable) bukkitEvent).setCancelled(((Cancellable) pgmEvent).isCancelled());
} else {
Bukkit.getServer().getPluginManager().callEvent(pgmEvent);
}
}

@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onInteraction(PlayerInteractEvent event) {
ItemStack stack = event.getItem();
if (stack != null && stack.getType() == Material.EXPLOSIVE_MINECART) {
lastPlacer = event.getPlayer();
placingStack = stack.clone();
railLocation = event.getClickedBlock().getLocation();
}
}

@EventHandler
public void onVehicleCreate(VehicleCreateEvent event) {
/*
* Starting from 1.11.2, VehicleCreateEvent is natively cancellable.
* Even then, we should account for this case and reset the variables
* to ensure the tracking works reliably.
*/
if (!(event instanceof Cancellable) || !((Cancellable) event).isCancelled()) {
if (lastPlacer != null) {
Vehicle vehicle = event.getVehicle();
Location vehicleLocation = vehicle.getLocation();

if (vehicle instanceof ExplosiveMinecart
&& areBlockLocationsEqual(railLocation, vehicleLocation)) {
ItemStack itemInHand = lastPlacer.getItemInHand();

PlayerSpawnEntityEvent pgmEvent =
new PlayerSpawnEntityEvent(
lastPlacer,
vehicle,
vehicleLocation,
itemInHand != null ? itemInHand : placingStack);
handleCall(pgmEvent, event);

if (pgmEvent.isCancelled()) {
if (!(event instanceof Cancellable)) {
vehicle.remove();
}
lastPlacer.getInventory().setItemInHand(placingStack);
}
}
}
}
lastPlacer = null;
placingStack = null;
railLocation = null;
}

private static boolean areBlockLocationsEqual(Location locA, Location locB) {
return locA.getBlockX() == locB.getBlockX()
&& locA.getBlockY() == locB.getBlockY()
&& locA.getBlockZ() == locB.getBlockZ();
}
}

0 comments on commit ffd116e

Please sign in to comment.