From aa787b5a25f27fc70351f3581d0aea687480ee75 Mon Sep 17 00:00:00 2001 From: Manuel Frohn Date: Wed, 30 Apr 2025 12:17:48 +0200 Subject: [PATCH] Implemented cursor manager for deduplicated cursor updating --- .../bausystem/utils/{ => cursor}/RCursor.java | 43 +++++++---- .../utils/cursor/RCursorManager.java | 77 +++++++++++++++++++ 2 files changed, 106 insertions(+), 14 deletions(-) rename BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/{ => cursor}/RCursor.java (59%) create mode 100644 BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/cursor/RCursorManager.java diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/RCursor.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/cursor/RCursor.java similarity index 59% rename from BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/RCursor.java rename to BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/cursor/RCursor.java index e1d133b7..bae58778 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/RCursor.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/cursor/RCursor.java @@ -1,51 +1,66 @@ -package de.steamwar.bausystem.utils; +package de.steamwar.bausystem.utils.cursor; +import de.steamwar.bausystem.utils.RayTraceUtils; import de.steamwar.entity.REntity; import de.steamwar.entity.REntityServer; import de.steamwar.entity.RFallingBlockEntity; +import lombok.Getter; +import lombok.Setter; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.util.Vector; +@Getter public class RCursor { - private Player owner; - private REntityServer targetServer; + private final REntityServer targetServer; + + private final Player owner; + private final Material highlightMaterial; + @Setter + private Material cursorMaterial; private RFallingBlockEntity cursorEntity; - private Material highlightMaterial; - private Material cursorMaterial; - - public RCursor(REntityServer targetServer, Material highlightMaterial, Material cursorMaterial) { + public RCursor(REntityServer targetServer, Player owner, Material highlightMaterial, Material cursorMaterial) { this.targetServer = targetServer; + this.owner = owner; this.highlightMaterial = highlightMaterial; this.cursorMaterial = cursorMaterial; + + RCursorManager.getInstance().registerCursor(this); } public void render() { RayTraceUtils.RRayTraceResult rayTraceResult = RayTraceUtils.traceREntity(owner, owner.getLocation(), targetServer.getEntities()); - if(rayTraceResult == null) { + if (rayTraceResult == null) { cursorEntity.die(); return; } - REntity hitEntity = rayTraceResult.getHitEntity(); + REntity hitEntity = rayTraceResult.getHitEntity() == cursorEntity ? null : rayTraceResult.getHitEntity(); + Material activeCursorMaterial = hitEntity == null ? cursorMaterial : highlightMaterial; Location activeCursorLocation = hitEntity == null ? rayTraceResult.getHitPosition().toLocation(owner.getWorld()) : new Vector(hitEntity.getX(), hitEntity.getY(), hitEntity.getZ()).toLocation(owner.getWorld()); - if(cursorEntity == null) { + if (cursorEntity == null) { cursorEntity = new RFallingBlockEntity(targetServer, activeCursorLocation, activeCursorMaterial); - } - else if(cursorEntity.getMaterial() == activeCursorMaterial) { + cursorEntity.setNoGravity(true); + } else if (cursorEntity.getMaterial() == activeCursorMaterial) { cursorEntity.move(activeCursorLocation); - } - else { + } else { cursorEntity.die(); cursorEntity = new RFallingBlockEntity(targetServer, activeCursorLocation, activeCursorMaterial); + cursorEntity.setNoGravity(true); + } + } + + public void hide() { + if (cursorEntity != null) { + cursorEntity.die(); } } } diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/cursor/RCursorManager.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/cursor/RCursorManager.java new file mode 100644 index 00000000..82554406 --- /dev/null +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/cursor/RCursorManager.java @@ -0,0 +1,77 @@ +package de.steamwar.bausystem.utils.cursor; + +import com.comphenix.tinyprotocol.TinyProtocol; +import de.steamwar.Reflection; +import de.steamwar.bausystem.BauSystem; +import de.steamwar.linkage.Linked; +import lombok.Getter; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import java.lang.ref.SoftReference; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.function.BiFunction; + +@Linked +public class RCursorManager { + @Getter + private static RCursorManager instance; + + private final Set calculationActive = new HashSet<>(); + private final Map> activeCursors = new HashMap<>(); + + public RCursorManager() { + if (instance == null) { + instance = this; + } + + BiFunction function = (player, object) -> { + updateCursor(player); + return object; + }; + + Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> { + Set playersWithActiveCursor = activeCursors.keySet(); + + playersWithActiveCursor.forEach(this::updateCursor); + }, 0); + + Class positionPacketClass = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$Pos"); + Class lookPacketClass = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$Rot"); + Class positionLookPacketClass = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$PosRot"); + + TinyProtocol.instance.addFilter(positionPacketClass, function); + TinyProtocol.instance.addFilter(lookPacketClass, function); + TinyProtocol.instance.addFilter(positionLookPacketClass, function); + } + + public void registerCursor(RCursor cursor) { + activeCursors.put(cursor.getOwner(), new SoftReference<>(cursor)); + } + + private void updateCursor(Player player) { + synchronized (calculationActive) { + if (calculationActive.contains(player)) { + return; + } else { + calculationActive.add(player); + } + } + + SoftReference cursorRef = activeCursors.get(player); + RCursor cursor = cursorRef.get(); + + if (cursor == null) { + activeCursors.remove(player); + } else { + cursor.render(); + } + + synchronized (calculationActive) { + calculationActive.remove(player); + } + } +}