Transport non-player entities through gates too
GateTeleportListener previously only listened to PlayerMoveEvent, so mobs, dropped items, minecarts, boats, and everything else that isn't a player just walked/rolled/drifted straight through the event horizon block with no effect. Added a Paper EntityMoveEvent handler sharing the same one-way/outgoing-only matching, safe-landing, and cooldown logic as the player path. Non-player entities are restricted to same-server destinations - the cross-server plugin-messaging protocol only carries a player's UUID and look direction across the proxy hop, not arbitrary entity state, so there's no way to hand off a mob or item to another backend.
This commit is contained in:
+65
-16
@@ -4,8 +4,11 @@ import dev.skywalker3200.stargate.paper.StargatePlugin;
|
||||
import dev.skywalker3200.stargate.paper.gate.GateManager;
|
||||
import dev.skywalker3200.stargate.paper.gate.RuntimeGate;
|
||||
import dev.skywalker3200.stargate.paper.network.CrossServerBridge;
|
||||
import io.papermc.paper.event.entity.EntityMoveEvent;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
@@ -18,12 +21,16 @@ import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Walking into the DIALING gate's event horizon teleports the player to the connected gate,
|
||||
* arriving just past its iris (never inside it) and facing the same absolute direction they
|
||||
* were already walking, so "enter forward" always means "exit forward". Travel is strictly
|
||||
* one-way: only the gate that was dialed (outgoing = true) can send anyone anywhere - stepping
|
||||
* into the receiving gate's horizon does nothing, matching the wormhole only running one
|
||||
* direction at a time.
|
||||
* Walking (or wandering, or drifting, or rolling) into the DIALING gate's event horizon
|
||||
* teleports whatever entered to the connected gate, arriving just past its iris (never inside
|
||||
* it) and facing the same absolute direction it was already moving, so "enter forward" always
|
||||
* means "exit forward". Travel is strictly one-way: only the gate that was dialed (outgoing =
|
||||
* true) can send anything anywhere - stepping into the receiving gate's horizon does nothing.
|
||||
*
|
||||
* Players get their own handler because cross-server travel needs a real client connection to
|
||||
* hand off through the proxy; every other entity (mobs, dropped items, minecarts, boats, arrows,
|
||||
* ...) is handled generically, but only for same-server destinations - there's no way to carry
|
||||
* an arbitrary entity's state across the BungeeCord/Velocity plugin-messaging hop.
|
||||
*/
|
||||
public class GateTeleportListener implements Listener {
|
||||
|
||||
@@ -40,31 +47,55 @@ public class GateTeleportListener implements Listener {
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onMove(PlayerMoveEvent event) {
|
||||
public void onPlayerMove(PlayerMoveEvent event) {
|
||||
Location to = event.getTo();
|
||||
if (to == null) return;
|
||||
if (event.getFrom().getBlockX() == to.getBlockX() && event.getFrom().getBlockY() == to.getBlockY()
|
||||
&& event.getFrom().getBlockZ() == to.getBlockZ()) return;
|
||||
if (sameBlock(event.getFrom(), to)) return;
|
||||
|
||||
Player player = event.getPlayer();
|
||||
Long until = cooldownUntil.get(player.getUniqueId());
|
||||
if (until != null && System.currentTimeMillis() < until) return;
|
||||
if (onCooldown(player.getUniqueId())) return;
|
||||
|
||||
Block standing = to.getBlock();
|
||||
RuntimeGate rg = findOutgoingGateAt(to.getBlock());
|
||||
if (rg != null) teleportPlayer(player, rg);
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onEntityMove(EntityMoveEvent event) {
|
||||
Entity entity = event.getEntity();
|
||||
if (entity instanceof Player) return; // handled separately above (needs cross-server support)
|
||||
|
||||
Location to = event.getTo();
|
||||
if (sameBlock(event.getFrom(), to)) return;
|
||||
if (onCooldown(entity.getUniqueId())) return;
|
||||
|
||||
RuntimeGate rg = findOutgoingGateAt(to.getBlock());
|
||||
if (rg != null) teleportEntity(entity, rg);
|
||||
}
|
||||
|
||||
private boolean sameBlock(Location a, Location b) {
|
||||
return a.getBlockX() == b.getBlockX() && a.getBlockY() == b.getBlockY() && a.getBlockZ() == b.getBlockZ();
|
||||
}
|
||||
|
||||
private boolean onCooldown(UUID id) {
|
||||
Long until = cooldownUntil.get(id);
|
||||
return until != null && System.currentTimeMillis() < until;
|
||||
}
|
||||
|
||||
private RuntimeGate findOutgoingGateAt(Block standing) {
|
||||
List<RuntimeGate> gates = gateManager.all();
|
||||
for (RuntimeGate rg : gates) {
|
||||
if (!rg.isOpen() || !rg.isOutgoing() || rg.getStructure() == null || rg.getConnectedTo() == null) continue;
|
||||
for (Block iris : rg.getStructure().getIris()) {
|
||||
if (iris.getX() == standing.getX() && iris.getY() == standing.getY() && iris.getZ() == standing.getZ()
|
||||
&& iris.getWorld().equals(standing.getWorld())) {
|
||||
teleport(player, rg);
|
||||
return;
|
||||
return rg;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void teleport(Player player, RuntimeGate entered) {
|
||||
private void teleportPlayer(Player player, RuntimeGate entered) {
|
||||
RuntimeGate dest = entered.getConnectedTo();
|
||||
if (dest == null) return;
|
||||
|
||||
@@ -84,6 +115,24 @@ public class GateTeleportListener implements Listener {
|
||||
cooldownUntil.put(player.getUniqueId(), System.currentTimeMillis() + COOLDOWN_MS);
|
||||
player.teleport(landing);
|
||||
player.setVelocity(velocity);
|
||||
player.playSound(landing, org.bukkit.Sound.ENTITY_ENDERMAN_TELEPORT, 1f, 1f);
|
||||
player.playSound(landing, Sound.ENTITY_ENDERMAN_TELEPORT, 1f, 1f);
|
||||
}
|
||||
|
||||
private void teleportEntity(Entity entity, RuntimeGate entered) {
|
||||
RuntimeGate dest = entered.getConnectedTo();
|
||||
if (dest == null) return;
|
||||
if (!dest.getGate().getServerId().equals(plugin.getServerId())) return; // no cross-server carry for non-players
|
||||
|
||||
Location loc = entity.getLocation();
|
||||
Vector direction = loc.getDirection();
|
||||
Vector velocity = entity.getVelocity();
|
||||
|
||||
Location landing = gateManager.computeSafeLanding(dest, direction, loc.getYaw(), loc.getPitch());
|
||||
if (landing == null) return;
|
||||
|
||||
cooldownUntil.put(entity.getUniqueId(), System.currentTimeMillis() + COOLDOWN_MS);
|
||||
entity.teleport(landing);
|
||||
entity.setVelocity(velocity);
|
||||
entity.getWorld().playSound(landing, Sound.ENTITY_ENDERMAN_TELEPORT, 1f, 1f);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user