Make TechHider access checks player-scoped

AccessPrivilegeProvider#forPlayer returns a PlayerAccess that resolves
the player's hidden region once. TechHider creates it once per outer
packet (shared across bundle sub-packets) and passes it to every
processor, so all decisions within a packet are consistent and the
region/referee lookup no longer runs per block on the netty thread.
This commit is contained in:
2026-10-27 09:50:59 +01:00
parent 8381cacdf8
commit 7cd2e540ef
5 changed files with 192 additions and 116 deletions
@@ -34,9 +34,11 @@ import org.bukkit.util.Vector;
import java.io.File;
import java.util.Collections;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import java.util.stream.Collectors;
public class Config {
@@ -80,7 +82,7 @@ public class Config {
//event parameter
public static final EventFight EventKampf;
private static final Set<Integer> Referees;
private static final Set<UUID> Referees;
public static final int EventTeamBlueID;
public static final int EventTeamRedID;
public static final boolean BothTeamsPublic;
@@ -237,7 +239,11 @@ public class Config {
BothTeamsPublic = EventTeamRedID == 0 && EventTeamBlueID == 0;
SpectatePort = EventKampf.getSpectatePort() == null ? 0 : EventKampf.getSpectatePort();
LiveReplay = SpectatePort != 0;
Referees = Referee.get(Config.EventKampf.getEventID());
Referees = Referee.get(Config.EventKampf.getEventID()).stream()
.map(SteamwarUser::byId)
.filter(Objects::nonNull)
.map(SteamwarUser::getUUID)
.collect(Collectors.toUnmodifiableSet());
Event event = Event.byId(EventKampf.getEventID());
if (BothTeamsPublic) {
@@ -305,6 +311,6 @@ public class Config {
}
public static boolean isReferee(Player player) {
return Referees.contains(SteamwarUser.get(player.getUniqueId()).getId());
return Referees.contains(player.getUniqueId());
}
}
@@ -31,6 +31,7 @@ import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependent;
import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.techhider.AccessPrivilegeProvider;
import de.steamwar.techhider.AccessPrivilegeProvider.ForPlayer;
import de.steamwar.techhider.TechHider;
import lombok.Getter;
import net.minecraft.core.Holder;
@@ -91,49 +92,82 @@ public class TechHiderWrapper extends StateDependent implements Listener {
.map(Holder.Reference::value)
.collect(Collectors.toUnmodifiableSet());
new TechHider(CraftMagicNumbers.getBlock(Config.GameModeConfig.Techhider.ObfuscateWith), new AccessPrivilegeProvider() {
new TechHider(CraftMagicNumbers.getBlock(Config.GameModeConfig.Techhider.ObfuscateWith), newProvider(blockStatesToObfuscate, blocksToObfuscate, blockEntityTypeToObfuscate));
}
private AccessPrivilegeProvider newProvider(Set<BlockState> blockStatesToObfuscate, Set<Block> blocksToObfuscate, Set<BlockEntityType<?>> blockEntityTypeToObfuscate) {
return new AccessPrivilegeProvider() {
@Override
public boolean isEveryonePrivilegedToAccessAllDataWithinChunk(int chunkX, int chunkZ) {
return Fight.teams().stream().map(FightTeam::getExtendRegion).allMatch(region -> region.chunkOutside(chunkX, chunkZ));
}
@Override
public boolean isPlayerPrivilegedToAccessPosition(Player p, int blockX, int blockY, int blockZ) {
return !hullHider.isBlockHidden(p, blockX, blockY, blockZ);
}
@Override
public boolean isPlayerPrivilegedToAccessBlock(Player p, int blockX, int blockY, int blockZ, Block block) {
return !getHiddenRegion(p).inRegion(blockX, blockY, blockZ) || !blocksToObfuscate.contains(block);
}
@Override
public boolean isPlayerPrivilegedToAccessBlockState(Player p, int blockX, int blockY, int blockZ, BlockState blockState) {
return !getHiddenRegion(p).inRegion(blockX, blockY, blockZ) || !blockStatesToObfuscate.contains(blockState);
}
// TODO will require entity tracking on the netty thread to prevent future race conditions
@Override
public boolean isPlayerPrivilegedToAccessEntity(Player p, int entityId) {
net.minecraft.world.entity.Entity nmsEntity = ((CraftWorld) p.getWorld()).getHandle().moonrise$getEntityLookup().get(entityId);
if (nmsEntity != null) {
return !hullHider.isBlockHidden(p, nmsEntity.getBlockX(), nmsEntity.getBlockY(), nmsEntity.getBlockZ());
} else {
return true;
}
}
@Override
public boolean isPlayerPrivilegedToAccessBlockEntity(Player p, int blockX, int blockY, int blockZ, BlockEntityType<?> type) {
return !getHiddenRegion(p).inRegion(blockX, blockY, blockZ) || !blockEntityTypeToObfuscate.contains(type);
public ForPlayer forPlayer(Player p) {
return new FightPlayerAccess(p, getHiddenRegion(p), blockStatesToObfuscate, blocksToObfuscate, blockEntityTypeToObfuscate);
}
@Override
public boolean isPlayerPrivilegedToPerformAction(Player p) {
return p.getGameMode() != GameMode.SPECTATOR;
}
});
};
}
/**
* Snapshot of what one player may access, taken once per outgoing packet on the netty thread.
*/
private class FightPlayerAccess implements ForPlayer {
private final Player player;
private final Region hiddenRegion;
private final Set<BlockState> blockStatesToObfuscate;
private final Set<Block> blocksToObfuscate;
private final Set<BlockEntityType<?>> blockEntityTypeToObfuscate;
private FightPlayerAccess(Player player, Region hiddenRegion, Set<BlockState> blockStatesToObfuscate, Set<Block> blocksToObfuscate, Set<BlockEntityType<?>> blockEntityTypeToObfuscate) {
this.player = player;
this.hiddenRegion = hiddenRegion;
this.blockStatesToObfuscate = blockStatesToObfuscate;
this.blocksToObfuscate = blocksToObfuscate;
this.blockEntityTypeToObfuscate = blockEntityTypeToObfuscate;
}
@Override
public Player getPlayer() {
return player;
}
@Override
public boolean canAccessPosition(int blockX, int blockY, int blockZ) {
return !hullHider.isBlockHidden(player, blockX, blockY, blockZ);
}
@Override
public boolean canAccessBlock(int blockX, int blockY, int blockZ, Block block) {
return !hiddenRegion.inRegion(blockX, blockY, blockZ) || !blocksToObfuscate.contains(block);
}
@Override
public boolean canAccessBlockState(int blockX, int blockY, int blockZ, BlockState blockState) {
return !hiddenRegion.inRegion(blockX, blockY, blockZ) || !blockStatesToObfuscate.contains(blockState);
}
// TODO will require entity tracking on the netty thread to prevent future race conditions
@Override
public boolean canAccessEntity(int entityId) {
net.minecraft.world.entity.Entity nmsEntity = ((CraftWorld) player.getWorld()).getHandle().moonrise$getEntityLookup().get(entityId);
if (nmsEntity != null) {
return !hullHider.isBlockHidden(player, nmsEntity.getBlockX(), nmsEntity.getBlockY(), nmsEntity.getBlockZ());
} else {
return true;
}
}
@Override
public boolean canAccessBlockEntity(int blockX, int blockY, int blockZ, BlockEntityType<?> type) {
return !hiddenRegion.inRegion(blockX, blockY, blockZ) || !blockEntityTypeToObfuscate.contains(type);
}
}
@Override