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:
@@ -60,12 +60,18 @@ material, unsealed interior, too far from the sign, etc.
|
||||
- **Left-click** the sign: dials the shown destination - chevrons light in sequence,
|
||||
then the interior becomes the event horizon (`gate.iris-open-material`, default
|
||||
water) and travel opens up. It auto-closes after `dialing.open-seconds`.
|
||||
- Travel is **one-way**: only the gate you dialed *from* can send you anywhere.
|
||||
Walking into its event horizon teleports you to the destination, arriving just
|
||||
clear of its iris (never inside it) and still facing whatever direction you were
|
||||
already walking, so entering forward always means exiting forward. The
|
||||
destination's horizon is visible but not walkable - stepping into it does nothing,
|
||||
same as a real Stargate only running one direction at a time.
|
||||
- Travel is **one-way**: only the gate you dialed *from* can send anything anywhere.
|
||||
Walking (or wandering, or drifting) into its event horizon teleports whatever
|
||||
entered to the destination, arriving just clear of its iris (never inside it) and
|
||||
still facing whatever direction it was already moving, so entering forward always
|
||||
means exiting forward. The destination's horizon is visible but not walkable -
|
||||
stepping into it does nothing, same as a real Stargate only running one direction
|
||||
at a time.
|
||||
- Not just players - mobs, dropped items, minecarts, boats, arrows, anything that
|
||||
moves through the event horizon gets sent through too. Non-player entities can
|
||||
only travel to a same-server destination, though; there's no way to carry an
|
||||
arbitrary entity's state across the Velocity/Bungee plugin-messaging hop, so a
|
||||
cross-server gate just won't move anything but players.
|
||||
- The **iris shield** is a separate, physical thing from the wormhole connection.
|
||||
**Right-click a button placed directly below the sign** to toggle it. Closed means
|
||||
closed - `gate.iris-shield-material` (default bedrock), solid, blocking everything -
|
||||
|
||||
+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