Merge pull request 'Remove global Entity Interact callback' (#404) from SpigotCore/RemoveGlobalEntityServerCallback into main

Reviewed-on: SteamWar/SteamWar#404
Reviewed-by: D4rkr34lm <dark@steamwar.de>
This commit is contained in:
2026-05-30 15:27:45 +02:00
11 changed files with 98 additions and 62 deletions
@@ -21,10 +21,7 @@ package de.steamwar.bausystem.features.design.endstone;
import de.steamwar.bausystem.BauSystem; import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.region.Region; import de.steamwar.bausystem.region.Region;
import de.steamwar.entity.REntity; import de.steamwar.entity.*;
import de.steamwar.entity.REntityAction;
import de.steamwar.entity.REntityServer;
import de.steamwar.entity.RFallingBlockEntity;
import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.ChatMessageType;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
@@ -60,15 +57,15 @@ public class DesignEndStone {
.filter(material -> material.getBlastResistance() > region.getGameModeConfig().Schematic.MaxDesignBlastResistance) .filter(material -> material.getBlastResistance() > region.getGameModeConfig().Schematic.MaxDesignBlastResistance)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
calculateFromBottom = region.getGameModeConfig().Arena.NoFloor; calculateFromBottom = region.getGameModeConfig().Arena.NoFloor;
}
entityServer.setCallback((player, rEntity, entityAction) -> { private void interact(Player player, RInteraction entity, REntityAction action) {
if (entityAction != REntityAction.ATTACK) return; if (action != REntityAction.ATTACK) return;
Location location = new Location(WORLD, rEntity.getX(), rEntity.getY(), rEntity.getZ()); Location location = new Location(WORLD, entity.getX(), entity.getY(), entity.getZ());
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> { Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
location.getBlock().breakNaturally(); location.getBlock().breakNaturally();
calc(); calc();
}, 1); }, 1);
});
} }
public void calc() { public void calc() {
@@ -111,12 +108,15 @@ public class DesignEndStone {
Material material = WORLD.getBlockAt(cx, cy, cz).getType(); Material material = WORLD.getBlockAt(cx, cy, cz).getType();
if (material != Material.WATER && material != Material.LAVA && limited.contains(material)) { if (material != Material.WATER && material != Material.LAVA && limited.contains(material)) {
Location location = new Location(WORLD, cx + 0.5, cy, cz + 0.5); Location location = new Location(WORLD, cx, cy, cz);
if (!locations.add(location)) break; if (!locations.add(location)) break;
RFallingBlockEntity entity = new RFallingBlockEntity(entityServer, location, Material.RED_STAINED_GLASS); RBlockDisplay entity = new RBlockDisplay(entityServer, location);
entity.setNoGravity(true); entity.setBlock(Material.RED_STAINED_GLASS.createBlockData());
entity.setGlowing(true); entity.setGlowing(true);
entities.add(entity); entities.add(entity);
RInteraction interaction = new RInteraction(entityServer, location);
interaction.setCallback(this::interact);
entities.add(interaction);
break; break;
} else if (!material.isAir() && material != Material.WATER && material != Material.LAVA) { } else if (!material.isAir() && material != Material.WATER && material != Material.LAVA) {
break; break;
@@ -26,8 +26,9 @@ import de.steamwar.bausystem.features.autostart.AutostartListener;
import de.steamwar.bausystem.features.detonator.storage.DetonatorStorage; import de.steamwar.bausystem.features.detonator.storage.DetonatorStorage;
import de.steamwar.bausystem.features.detonator.storage.ItemStorage; import de.steamwar.bausystem.features.detonator.storage.ItemStorage;
import de.steamwar.core.SWPlayer; import de.steamwar.core.SWPlayer;
import de.steamwar.entity.RBlockDisplay;
import de.steamwar.entity.REntityServer; import de.steamwar.entity.REntityServer;
import de.steamwar.entity.RFallingBlockEntity; import de.steamwar.entity.RInteraction;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
@@ -58,10 +59,6 @@ public class Detonator {
@Override @Override
public void onMount(SWPlayer player) { public void onMount(SWPlayer player) {
entities.addPlayer(player.getPlayer()); entities.addPlayer(player.getPlayer());
entities.setCallback((player1, entity, action) -> {
Vector vector = new Vector(entity.getX(), entity.getY(), entity.getZ());
DetonatorListener.addLocationToDetonator(vector.toLocation(player.getWorld()).getBlock().getLocation(), player1);
});
} }
@Override @Override
@@ -70,8 +67,6 @@ public class Detonator {
} }
} }
private static final Vector HALF = new Vector(0.5, 0, 0.5);
public static boolean isDetonator(ItemStack itemStack) { public static boolean isDetonator(ItemStack itemStack) {
return ItemStorage.isDetonator(itemStack); return ItemStorage.isDetonator(itemStack);
} }
@@ -79,8 +74,14 @@ public class Detonator {
public static void showDetonator(Player p, List<Location> locs) { public static void showDetonator(Player p, List<Location> locs) {
DetonatorComponent detonatorComponent = SWPlayer.of(p).getComponentOrDefault(DetonatorComponent.class, DetonatorComponent::new); DetonatorComponent detonatorComponent = SWPlayer.of(p).getComponentOrDefault(DetonatorComponent.class, DetonatorComponent::new);
locs.forEach(location -> { locs.forEach(location -> {
RFallingBlockEntity entity = new RFallingBlockEntity(detonatorComponent.entities, location.clone().add(HALF), Material.RED_STAINED_GLASS); RBlockDisplay blockDisplay = new RBlockDisplay(detonatorComponent.entities, location);
entity.setNoGravity(true); blockDisplay.setBlock(Material.RED_STAINED_GLASS.createBlockData());
RInteraction interaction = new RInteraction(detonatorComponent.entities, location);
interaction.setCallback((player, entity, action) -> {
Vector vector = new Vector(entity.getX(), entity.getY(), entity.getZ());
DetonatorListener.addLocationToDetonator(vector.toLocation(player.getWorld()).getBlock().getLocation(), player);
});
}); });
} }
@@ -24,9 +24,9 @@ import de.steamwar.bausystem.region.Point;
import de.steamwar.bausystem.region.Region; import de.steamwar.bausystem.region.Region;
import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar; import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar;
import de.steamwar.bausystem.utils.bossbar.BossBarService; import de.steamwar.bausystem.utils.bossbar.BossBarService;
import de.steamwar.entity.RBlockDisplay;
import de.steamwar.entity.REntity; import de.steamwar.entity.REntity;
import de.steamwar.entity.REntityServer; import de.steamwar.entity.REntityServer;
import de.steamwar.entity.RFallingBlockEntity;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
@@ -290,8 +290,8 @@ public class KillcheckerVisualizer {
} }
rEntities.get(point).die(); rEntities.get(point).die();
} }
RFallingBlockEntity entity = new RFallingBlockEntity(outlinePoints.contains(point) ? outline : inner, point.toLocation(WORLD, 0.5, 0, 0.5), MATERIALS[Math.min(count - 1, MATERIALS.length) - 1]); RBlockDisplay entity = new RBlockDisplay(outlinePoints.contains(point) ? outline : inner, point.toLocation(WORLD, 0.5, 0, 0.5));
entity.setNoGravity(true); entity.setBlock(MATERIALS[Math.min(count - 1, MATERIALS.length) - 1].createBlockData());
rEntities.put(point, entity); rEntities.put(point, entity);
if (outlinePoints.contains(point)) outlinePointsCache.add(point); if (outlinePoints.contains(point)) outlinePointsCache.add(point);
killCount.put(point, count); killCount.put(point, count);
@@ -20,8 +20,8 @@
package de.steamwar.bausystem.features.tracer.rendering; package de.steamwar.bausystem.features.tracer.rendering;
import de.steamwar.bausystem.features.tracer.TNTPoint; import de.steamwar.bausystem.features.tracer.TNTPoint;
import de.steamwar.entity.RBlockDisplay;
import de.steamwar.entity.REntityServer; import de.steamwar.entity.REntityServer;
import de.steamwar.entity.RFallingBlockEntity;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
@@ -129,8 +129,8 @@ public abstract class ViewFlag {
Location yLocation = previous.getLocation().clone().add(0, delta.getY(), 0); Location yLocation = previous.getLocation().clone().add(0, delta.getY(), 0);
if (yLocation.distanceSquared(representative.getLocation()) >= 1.0 / 256.0 && yLocation.distanceSquared(previous.getLocation()) >= 1.0 / 256.0) { if (yLocation.distanceSquared(representative.getLocation()) >= 1.0 / 256.0 && yLocation.distanceSquared(previous.getLocation()) >= 1.0 / 256.0) {
RFallingBlockEntity y = new RFallingBlockEntity(server, yLocation, Material.WHITE_STAINED_GLASS); RBlockDisplay y = new RBlockDisplay(server, yLocation);
y.setNoGravity(true); y.setBlock(Material.WHITE_STAINED_GLASS.createBlockData());
} }
Location secoundLocation; Location secoundLocation;
@@ -141,8 +141,8 @@ public abstract class ViewFlag {
} }
if (secoundLocation.distanceSquared(representative.getLocation()) >= 1.0 / 256.0 && secoundLocation.distanceSquared(previous.getLocation()) >= 1.0 / 256.0) { if (secoundLocation.distanceSquared(representative.getLocation()) >= 1.0 / 256.0 && secoundLocation.distanceSquared(previous.getLocation()) >= 1.0 / 256.0) {
RFallingBlockEntity second = new RFallingBlockEntity(server, secoundLocation, Material.WHITE_STAINED_GLASS); RBlockDisplay second = new RBlockDisplay(server, secoundLocation);
second.setNoGravity(true); second.setBlock(Material.WHITE_STAINED_GLASS.createBlockData());
} }
} }
} }
@@ -22,6 +22,7 @@ package de.steamwar.lobby.boatrace;
import de.steamwar.entity.REntity; import de.steamwar.entity.REntity;
import de.steamwar.entity.REntityAction; import de.steamwar.entity.REntityAction;
import de.steamwar.entity.REntityServer; import de.steamwar.entity.REntityServer;
import de.steamwar.entity.RInteraction;
import de.steamwar.lobby.LobbySystem; import de.steamwar.lobby.LobbySystem;
import de.steamwar.lobby.util.LeaderboardManager; import de.steamwar.lobby.util.LeaderboardManager;
import de.steamwar.sql.SteamwarUser; import de.steamwar.sql.SteamwarUser;
@@ -59,11 +60,12 @@ public class BoatRace implements EventListener, Listener {
static { static {
boatNpcServer = new REntityServer(); boatNpcServer = new REntityServer();
REntity starter = new REntity(boatNpcServer, EntityType.VILLAGER, BoatRacePositions.NPC); new REntity(boatNpcServer, EntityType.VILLAGER, BoatRacePositions.NPC);
boatNpcServer.setCallback((player, rEntity, entityAction) -> { RInteraction interaction = new RInteraction(boatNpcServer, BoatRacePositions.NPC.clone().subtract(0.5, 0, 0.5));
if (rEntity != starter) return; interaction.setInteractionHeight(1.95f);
Bukkit.getWorlds().get(0).getEntities().stream().filter(entity -> entity.getType() == EntityType.END_CRYSTAL).forEach(Entity::remove); interaction.setCallback((player, entity, action) -> {
if (entityAction == REntityAction.INTERACT && !oneNotStarted) { Bukkit.getWorlds().get(0).getEntities().stream().filter(e -> e.getType() == EntityType.END_CRYSTAL).forEach(Entity::remove);
if (action == REntityAction.INTERACT && !oneNotStarted) {
oneNotStarted = true; oneNotStarted = true;
new BoatRace(player); new BoatRace(player);
} }
@@ -20,6 +20,7 @@
package de.steamwar.entity; package de.steamwar.entity;
import lombok.Getter; import lombok.Getter;
import lombok.Setter;
import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.EntityDataSerializers;
import org.bukkit.Location; import org.bukkit.Location;
@@ -27,13 +28,16 @@ import org.bukkit.entity.EntityType;
import java.util.function.Consumer; import java.util.function.Consumer;
public class RArmorStand extends REntity { @Getter
public class RArmorStand extends REntity implements RInteractableEntity<RArmorStand> {
private static final EntityDataAccessor<Byte> sizeWatcher = new EntityDataAccessor<>(15, EntityDataSerializers.BYTE); private static final EntityDataAccessor<Byte> sizeWatcher = new EntityDataAccessor<>(15, EntityDataSerializers.BYTE);
@Getter
private final Size size; private final Size size;
@Setter
private REntityActionListener<RArmorStand> callback = null;
public RArmorStand(REntityServer server, Location location, Size size) { public RArmorStand(REntityServer server, Location location, Size size) {
super(server, EntityType.ARMOR_STAND, location, 0); super(server, EntityType.ARMOR_STAND, location, 0);
this.size = size; this.size = size;
@@ -21,7 +21,6 @@ package de.steamwar.entity;
import com.comphenix.tinyprotocol.TinyProtocol; import com.comphenix.tinyprotocol.TinyProtocol;
import de.steamwar.core.Core; import de.steamwar.core.Core;
import lombok.Setter;
import net.minecraft.network.protocol.game.ServerboundInteractPacket; import net.minecraft.network.protocol.game.ServerboundInteractPacket;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
@@ -52,8 +51,6 @@ public class REntityServer implements Listener {
private final HashMap<Player, Location> lastLocation = new HashMap<>(); private final HashMap<Player, Location> lastLocation = new HashMap<>();
private final HashMap<Player, Integer> viewDistance = new HashMap<>(); private final HashMap<Player, Integer> viewDistance = new HashMap<>();
@Setter
private REntityActionListener<REntity> callback = null;
private final Set<Player> playersThatClicked = Collections.synchronizedSet(new HashSet<>()); private final Set<Player> playersThatClicked = Collections.synchronizedSet(new HashSet<>());
private final BiFunction<Player, ServerboundInteractPacket, Object> filter = (player, packet) -> { private final BiFunction<Player, ServerboundInteractPacket, Object> filter = (player, packet) -> {
@@ -66,11 +63,8 @@ public class REntityServer implements Listener {
REntityAction action = packet.isAttack() ? REntityAction.ATTACK : REntityAction.INTERACT; REntityAction action = packet.isAttack() ? REntityAction.ATTACK : REntityAction.INTERACT;
Bukkit.getScheduler().runTask(Core.getInstance(), () -> { Bukkit.getScheduler().runTask(Core.getInstance(), () -> {
playersThatClicked.remove(player); playersThatClicked.remove(player);
if (entity instanceof RInteraction interaction && interaction.callback != null) { if (entity instanceof RInteractableEntity interactable && interactable.getCallback() != null) {
interaction.callback.onAction(player, interaction, action); interactable.getCallback().onAction(player, entity, action);
}
if (callback != null) {
callback.onAction(player, entity, action);
} }
}); });
return null; return null;
@@ -20,16 +20,21 @@
package de.steamwar.entity; package de.steamwar.entity;
import de.steamwar.techhider.BlockIds; import de.steamwar.techhider.BlockIds;
import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.Setter;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
@Getter @Getter
public class RFallingBlockEntity extends REntity { public class RFallingBlockEntity extends REntity implements RInteractableEntity<RFallingBlockEntity> {
private final Material material; private final Material material;
@Setter
private REntityActionListener<RFallingBlockEntity> callback = null;
public RFallingBlockEntity(REntityServer server, Location location, Material material) { public RFallingBlockEntity(REntityServer server, Location location, Material material) {
super(server, EntityType.FALLING_BLOCK, location, BlockIds.impl.materialToId(material)); super(server, EntityType.FALLING_BLOCK, location, BlockIds.impl.materialToId(material));
this.material = material; this.material = material;
@@ -0,0 +1,34 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.entity;
import org.bukkit.entity.Player;
import java.util.function.BiConsumer;
public interface RInteractableEntity<E extends REntity> {
REntityActionListener<E> getCallback();
void setCallback(REntityActionListener<E> callback);
default void setCallback(BiConsumer<Player, REntityAction> callback) {
setCallback((player, interaction, entityAction) -> callback.accept(player, entityAction));
}
}
@@ -20,11 +20,10 @@
package de.steamwar.entity; package de.steamwar.entity;
import de.steamwar.core.BountifulWrapper; import de.steamwar.core.BountifulWrapper;
import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.Setter;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -35,12 +34,12 @@ import java.util.function.Consumer;
* !! This class cannot be used in Versions lower than or equal to 1.19.4 !! * !! This class cannot be used in Versions lower than or equal to 1.19.4 !!
*/ */
@Getter @Getter
public class RInteraction extends REntity { public class RInteraction extends REntity implements RInteractableEntity<RInteraction> {
protected final Consumer<Object> updatePacketSink = o -> server.updateEntity(this, o); protected final Consumer<Object> updatePacketSink = o -> server.updateEntity(this, o);
@Getter(AccessLevel.PRIVATE) @Setter
protected REntityActionListener<RInteraction> callback = null; private REntityActionListener<RInteraction> callback = null;
private float interactionWidth = 1.0f; private float interactionWidth = 1.0f;
private float interactionHeight = 1.0f; private float interactionHeight = 1.0f;
@@ -114,12 +113,4 @@ public class RInteraction extends REntity {
dataSink.accept(responsiveWatcher, responsive); dataSink.accept(responsiveWatcher, responsive);
} }
} }
public void setCallback(REntityActionListener<RInteraction> callback) {
this.callback = callback;
}
public void setCallback(BiConsumer<Player, REntityAction> callback) {
this.callback = (player, interaction, entityAction) -> callback.accept(player, entityAction);
}
} }
@@ -27,6 +27,7 @@ import de.steamwar.network.CoreNetworkHandler;
import de.steamwar.network.NetworkSender; import de.steamwar.network.NetworkSender;
import de.steamwar.network.packets.common.PlayerSkinRequestPacket; import de.steamwar.network.packets.common.PlayerSkinRequestPacket;
import lombok.Getter; import lombok.Getter;
import lombok.Setter;
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import org.bukkit.GameMode; import org.bukkit.GameMode;
@@ -39,7 +40,7 @@ import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.function.Consumer; import java.util.function.Consumer;
public class RPlayer extends REntity { public class RPlayer extends REntity implements RInteractableEntity<RPlayer> {
private static final Object skinPartsDataWatcher = BountifulWrapper.impl.getDataWatcherObject(17, Byte.class); private static final Object skinPartsDataWatcher = BountifulWrapper.impl.getDataWatcherObject(17, Byte.class);
@@ -48,6 +49,10 @@ public class RPlayer extends REntity {
@Getter @Getter
private final String name; private final String name;
@Setter
@Getter
private REntityActionListener<RPlayer> callback = null;
public RPlayer(REntityServer server, UUID uuid, String name, Location location) { public RPlayer(REntityServer server, UUID uuid, String name, Location location) {
super(server, EntityType.PLAYER, UUID.nameUUIDFromBytes(uuid.toString().getBytes(StandardCharsets.UTF_8)), location, 0); super(server, EntityType.PLAYER, UUID.nameUUIDFromBytes(uuid.toString().getBytes(StandardCharsets.UTF_8)), location, 0);
this.actualUUID = uuid; this.actualUUID = uuid;