Merge pull request 'fix(SpigotCore): small collection of rendering bugs in new cursor' (#413) from BauSystem/fix-small-sim-cursor-bug into main

Reviewed-on: SteamWar/SteamWar#413
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
This commit is contained in:
2026-06-02 21:39:13 +02:00
3 changed files with 78 additions and 15 deletions
@@ -53,6 +53,8 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.block.Action; import org.bukkit.event.block.Action;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerItemHeldEvent; import org.bukkit.event.player.PlayerItemHeldEvent;
import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerJoinEvent;
@@ -83,22 +85,40 @@ public class SimulatorCursor implements Listener {
return isSimulatorItem(player.getInventory().getItemInMainHand()) || isSimulatorItem(player.getInventory().getItemInOffHand()); return isSimulatorItem(player.getInventory().getItemInMainHand()) || isSimulatorItem(player.getInventory().getItemInOffHand());
} }
private static void scheduleCursorUpdate(Player player) {
BauSystem.runTaskLater(BauSystem.getInstance(), () -> calcCursor(player), 1);
}
@EventHandler @EventHandler
public void onPlayerJoin(PlayerJoinEvent event) { public void onPlayerJoin(PlayerJoinEvent event) {
if (!Permission.BUILD.hasPermission(event.getPlayer())) return; if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> calcCursor(event.getPlayer()), 0); scheduleCursorUpdate(event.getPlayer());
} }
@EventHandler @EventHandler
public void onPlayerDropItem(PlayerDropItemEvent event) { public void onPlayerDropItem(PlayerDropItemEvent event) {
if (!Permission.BUILD.hasPermission(event.getPlayer())) return; if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
calcCursor(event.getPlayer()); scheduleCursorUpdate(event.getPlayer());
} }
@EventHandler @EventHandler
public void onPlayerItemHeld(PlayerItemHeldEvent event) { public void onPlayerItemHeld(PlayerItemHeldEvent event) {
if (!Permission.BUILD.hasPermission(event.getPlayer())) return; if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> calcCursor(event.getPlayer()), 1); scheduleCursorUpdate(event.getPlayer());
}
@EventHandler
public void onInventoryClick(InventoryClickEvent event) {
if (!(event.getWhoClicked() instanceof Player player)) return;
if (!Permission.BUILD.hasPermission(player)) return;
scheduleCursorUpdate(player);
}
@EventHandler
public void onInventoryDrag(InventoryDragEvent event) {
if (!(event.getWhoClicked() instanceof Player player)) return;
if (!Permission.BUILD.hasPermission(player)) return;
scheduleCursorUpdate(player);
} }
@EventHandler @EventHandler
@@ -221,7 +241,7 @@ public class SimulatorCursor implements Listener {
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
public enum CursorType { public enum CursorType {
TNT(Material.TNT, Material.GUNPOWDER, List.of(Cursor.CursorMode.FREE), "TNT", vector -> new TNTElement(vector).add(new TNTPhase())), TNT(Material.TNT, Material.GUNPOWDER, List.of(Cursor.CursorMode.FREE, Cursor.CursorMode.SURFACE_ALIGNED), "TNT", vector -> new TNTElement(vector).add(new TNTPhase())),
REDSTONE_BLOCK(Material.REDSTONE_BLOCK, Material.REDSTONE, List.of(Cursor.CursorMode.BLOCK_ALIGNED), "Redstone Block", vector -> new RedstoneElement(vector).add(new RedstonePhase())), REDSTONE_BLOCK(Material.REDSTONE_BLOCK, Material.REDSTONE, List.of(Cursor.CursorMode.BLOCK_ALIGNED), "Redstone Block", vector -> new RedstoneElement(vector).add(new RedstonePhase())),
OBSERVER(Material.OBSERVER, Material.QUARTZ, List.of(Cursor.CursorMode.BLOCK_ALIGNED), "Observer", vector -> new ObserverElement(vector).add(new ObserverPhase())), OBSERVER(Material.OBSERVER, Material.QUARTZ, List.of(Cursor.CursorMode.BLOCK_ALIGNED), "Observer", vector -> new ObserverElement(vector).add(new ObserverPhase())),
; ;
@@ -7,7 +7,6 @@ import de.steamwar.entity.RFallingBlockEntity;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.apache.logging.log4j.util.TriConsumer;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
@@ -44,16 +43,16 @@ public class Cursor implements SWPlayer.Component {
@Setter @Setter
private List<CursorMode> allowedCursorModes; private List<CursorMode> allowedCursorModes;
private final Material highlightMaterial; private final Material highlightMaterial;
private final TriConsumer<Location, Optional<REntity>, Action> onClick; private final ClickHandler onClick;
private final BiConsumer<Location, Optional<REntity>> onRender; private final BiConsumer<Location, Optional<REntity>> onRender;
public Cursor(REntityServer targetServer, Player owner, Material highlightMaterial, Material cursorMaterial, List<CursorMode> allowedModes, TriConsumer<Location, Optional<REntity>, Action> onClick) { public Cursor(REntityServer targetServer, Player owner, Material highlightMaterial, Material cursorMaterial, List<CursorMode> allowedModes, ClickHandler onClick) {
this(targetServer, owner, highlightMaterial, cursorMaterial, allowedModes, onClick, (location, hitEntity) -> { this(targetServer, owner, highlightMaterial, cursorMaterial, allowedModes, onClick, (location, hitEntity) -> {
}); });
} }
public Cursor(REntityServer targetServer, Player owner, Material highlightMaterial, Material cursorMaterial, List<CursorMode> allowedModes, TriConsumer<Location, Optional<REntity>, Action> onClick, BiConsumer<Location, Optional<REntity>> onRender) { public Cursor(REntityServer targetServer, Player owner, Material highlightMaterial, Material cursorMaterial, List<CursorMode> allowedModes, ClickHandler onClick, BiConsumer<Location, Optional<REntity>> onRender) {
this.targetServer = targetServer; this.targetServer = targetServer;
this.owner = owner; this.owner = owner;
this.highlightMaterial = highlightMaterial; this.highlightMaterial = highlightMaterial;
@@ -118,7 +117,7 @@ public class Cursor implements SWPlayer.Component {
protected void handlePlayerClick(Action clickAction) { protected void handlePlayerClick(Action clickAction) {
renderDeduplicated(); renderDeduplicated();
onClick.accept(this.cursorLocation, Optional.ofNullable(this.hitEntity), clickAction); onClick.onClick(this.cursorLocation, Optional.ofNullable(this.hitEntity), clickAction);
} }
@Override @Override
@@ -161,7 +160,43 @@ public class Cursor implements SWPlayer.Component {
return pos; return pos;
}, Player::isSneaking), }, Player::isSneaking),
BLOCK_ALIGNED(0, (player, rayTraceResult) -> { SURFACE_ALIGNED(2, (player, rayTraceResult) -> {
Vector hitPosition = rayTraceResult.getHitPosition().clone();
Vector pos = blockAlignedPosition(rayTraceResult);
BlockFace face = rayTraceResult.getHitBlockFace();
if (face != null && face != BlockFace.SELF) {
switch (face) {
case UP:
pos.setY(hitPosition.getY());
break;
case DOWN:
pos.setY(hitPosition.getY() + face.getModY());
break;
case EAST:
case WEST:
pos.setX(hitPosition.getX() + face.getModX() * 0.5);
break;
case NORTH:
case SOUTH:
pos.setZ(hitPosition.getZ() + face.getModZ() * 0.5);
break;
default:
break;
}
}
return pos;
}, (player) -> true),
BLOCK_ALIGNED(0, (player, rayTraceResult) -> blockAlignedPosition(rayTraceResult), (player) -> true);
private final int priority;
private final BiFunction<Player, RayTraceUtils.RRayTraceResult, Vector> positionTransform;
private final Predicate<Player> isActive;
private static Vector blockAlignedPosition(RayTraceUtils.RRayTraceResult rayTraceResult) {
Vector pos = rayTraceResult.getHitPosition(); Vector pos = rayTraceResult.getHitPosition();
BlockFace face = rayTraceResult.getHitBlockFace(); BlockFace face = rayTraceResult.getHitBlockFace();
@@ -195,11 +230,11 @@ public class Cursor implements SWPlayer.Component {
} }
pos.setZ(pos.getBlockZ() + 0.5); pos.setZ(pos.getBlockZ() + 0.5);
return pos; return pos;
}, (player) -> true); }
}
private final int priority; @FunctionalInterface
private final BiFunction<Player, RayTraceUtils.RRayTraceResult, Vector> positionTransform; public interface ClickHandler {
private final Predicate<Player> isActive; void onClick(Location location, Optional<REntity> hitEntity, Action action);
} }
} }
@@ -1,11 +1,13 @@
package de.steamwar.cursor; package de.steamwar.cursor;
import com.comphenix.tinyprotocol.TinyProtocol; import com.comphenix.tinyprotocol.TinyProtocol;
import de.steamwar.core.Core;
import de.steamwar.core.SWPlayer; import de.steamwar.core.SWPlayer;
import de.steamwar.linkage.Linked; import de.steamwar.linkage.Linked;
import lombok.Getter; import lombok.Getter;
import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
@@ -27,6 +29,12 @@ public class CursorListener implements Listener {
TinyProtocol.instance.addFilter(ServerboundMovePlayerPacket.Pos.class, this::updateCursorFromPacket); TinyProtocol.instance.addFilter(ServerboundMovePlayerPacket.Pos.class, this::updateCursorFromPacket);
TinyProtocol.instance.addFilter(ServerboundMovePlayerPacket.Rot.class, this::updateCursorFromPacket); TinyProtocol.instance.addFilter(ServerboundMovePlayerPacket.Rot.class, this::updateCursorFromPacket);
TinyProtocol.instance.addFilter(ServerboundMovePlayerPacket.PosRot.class, this::updateCursorFromPacket); TinyProtocol.instance.addFilter(ServerboundMovePlayerPacket.PosRot.class, this::updateCursorFromPacket);
Bukkit.getScheduler().runTaskTimer(Core.getInstance(), () -> {
SWPlayer.allWithSingleComponent(Cursor.class)
.map(SWPlayer.SWPlayerWithComponent::getComponent)
.forEach(Cursor::renderDeduplicated);
}, 1, 1);
} }
public Packet<?> updateCursorFromPacket(Player player, Packet<?> packet) { public Packet<?> updateCursorFromPacket(Player player, Packet<?> packet) {