forked from SteamWar/SteamWar
Hide hulls from players by default in HullHider
Hull kept a set of affected players that was only filled by a join listener active in the Schem states, so spectators joining earlier were never hidden from the hull. The set was also a plain HashSet read on netty threads, where a racing lookup meant "not hidden". Invert it into a concurrent set of viewers (referees, own team, boarded players); everyone else is hidden by default. - Hull: viewer UUID set with addViewer/removeViewer/forgetViewer, a null player counts as hidden - Hull: entities are hidden/shown when they enter/leave the hull for all non-viewer online players; uncovered blocks go to non-viewers - HullHider: join/quit handled in a listener active in every state; quit clears the viewer entry - HullHider: TeamDeathEvent re-hides the enemy hull and resends its chunks - FightPlayer: stop the enter countdown before firing TeamDeathEvent so listeners see canEntern() == false
This commit is contained in:
@@ -69,8 +69,8 @@ public class FightPlayer {
|
||||
|
||||
public void setOut() {
|
||||
isOut = true;
|
||||
stopEnternCountdown(); // before the event, so listeners already see canEntern() == false
|
||||
Bukkit.getPluginManager().callEvent(new TeamDeathEvent(this));
|
||||
stopEnternCountdown();
|
||||
ifAI(AI::stop);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
@@ -43,6 +44,7 @@ import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.IntStream;
|
||||
@@ -65,7 +67,8 @@ public class Hull {
|
||||
private final HashMap<IntVector, BitSet> visibilityDirections = new HashMap<>(); // Contains the visible directions of each occluding visible block
|
||||
private final HashSet<IntVector> uncoveredSurface = new HashSet<>();
|
||||
|
||||
private final HashSet<Player> players = new HashSet<>();
|
||||
// Players that may see the hull contents (viewers). Everybody else is hidden from it (default deny). Concurrent as it is read on netty threads.
|
||||
private final Set<UUID> viewers = ConcurrentHashMap.newKeySet();
|
||||
private final HashSet<Entity> entities = new HashSet<>();
|
||||
private final HashSet<REntity> rentities = new HashSet<>();
|
||||
|
||||
@@ -87,27 +90,36 @@ public class Hull {
|
||||
}
|
||||
|
||||
public boolean blockPrecise(Player player, int chunkX, int chunkY, int chunkZ) {
|
||||
return players.contains(player) && !region.chunkSectionOutside(chunkX, chunkY, chunkZ);
|
||||
return !isViewer(player) && !region.chunkSectionOutside(chunkX, chunkY, chunkZ);
|
||||
}
|
||||
|
||||
public boolean isBlockHidden(Player player, int x, int y, int z) {
|
||||
return region.inRegion(x, y, z) && players.contains(player) && !visibility.get(((y - region.getMinY()) * region.getSizeZ() + (z - region.getMinZ())) * region.getSizeX() + (x - region.getMinX()));
|
||||
return region.inRegion(x, y, z) && !isViewer(player) && !visibility.get(((y - region.getMinY()) * region.getSizeZ() + (z - region.getMinZ())) * region.getSizeX() + (x - region.getMinX()));
|
||||
}
|
||||
|
||||
public boolean isLocationHidden(Player player, Location location) {
|
||||
return players.contains(player) && region.inRegion(location) && !visibility.get(new IntVector(location).toId(region));
|
||||
return !isViewer(player) && region.inRegion(location) && !visibility.get(new IntVector(location).toId(region));
|
||||
}
|
||||
|
||||
public void addPlayer(Player player) {
|
||||
if (players.add(player)) {
|
||||
for (Entity entity : entities) {
|
||||
untrackEntity(player, entity);
|
||||
}
|
||||
private boolean isViewer(Player player) {
|
||||
return player != null && viewers.contains(player.getUniqueId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the hull from this player (removes the viewer), also hiding all entities currently inside it.
|
||||
*/
|
||||
public void removeViewer(Player player) {
|
||||
viewers.remove(player.getUniqueId());
|
||||
for (Entity entity : entities) {
|
||||
if (!player.equals(entity)) untrackEntity(player, entity);
|
||||
}
|
||||
}
|
||||
|
||||
public void removePlayer(Player player, boolean activeRemoval) {
|
||||
if (players.remove(player) && activeRemoval) {
|
||||
/**
|
||||
* Allows this player to see the hull (adds a viewer).
|
||||
*/
|
||||
public void addViewer(Player player) {
|
||||
if (viewers.add(player.getUniqueId())) {
|
||||
for (Entity entity : entities) {
|
||||
trackEntity(player, entity);
|
||||
}
|
||||
@@ -115,18 +127,22 @@ public class Hull {
|
||||
}
|
||||
}
|
||||
|
||||
public void forgetViewer(Player player) {
|
||||
viewers.remove(player.getUniqueId());
|
||||
}
|
||||
|
||||
public void checkEntity(Entity entity) {
|
||||
Location location = entity.getLocation();
|
||||
if (region.inRegion(location) && !visibility.get(new IntVector(location).toId(region))) {
|
||||
if (entities.add(entity)) {
|
||||
for (Player player : players) {
|
||||
untrackEntity(player, entity);
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
if (!isViewer(player) && !player.equals(entity)) untrackEntity(player, entity);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (entities.remove(entity)) {
|
||||
for (Player player : players) {
|
||||
trackEntity(player, entity);
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
if (!isViewer(player) && !player.equals(entity)) trackEntity(player, entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -252,7 +268,7 @@ public class Hull {
|
||||
result = new ClientboundBlockUpdatePacket(new BlockPos(pos.getX(), pos.getY(), pos.getZ()), (BlockState) blockdata[0]);
|
||||
}
|
||||
Object packet = result;
|
||||
players.forEach(player -> TinyProtocol.instance.sendPacket(player, packet));
|
||||
Bukkit.getOnlinePlayers().stream().filter(player -> !isViewer(player)).forEach(player -> TinyProtocol.instance.sendPacket(player, packet));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ package de.steamwar.fightsystem.utils;
|
||||
|
||||
import de.steamwar.entity.REntity;
|
||||
import de.steamwar.fightsystem.Config;
|
||||
import de.steamwar.fightsystem.FightSystem;
|
||||
import de.steamwar.fightsystem.events.TeamDeathEvent;
|
||||
import de.steamwar.fightsystem.fight.Fight;
|
||||
import de.steamwar.fightsystem.fight.FightPlayer;
|
||||
import de.steamwar.fightsystem.fight.FightTeam;
|
||||
@@ -61,6 +63,7 @@ public class HullHider implements Listener {
|
||||
hulls = hullMap.values().toArray(new Hull[0]);
|
||||
|
||||
|
||||
new StateDependentListener(TechHiderWrapper.ENABLED, FightState.All, new MembershipListener());
|
||||
new StateDependentListener(TechHiderWrapper.ENABLED, FightState.Schem, this);
|
||||
new StateDependentTask(TechHiderWrapper.ENABLED, FightState.Schem, this::onTick, 0, 1);
|
||||
}
|
||||
@@ -75,14 +78,26 @@ public class HullHider implements Listener {
|
||||
hullMap.get(team).fill(visible);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onJoin(PlayerJoinEvent e) {
|
||||
updatePlayer(e.getPlayer());
|
||||
}
|
||||
// Registered in every state: players must be hidden from the hulls by default, no matter when they join.
|
||||
private class MembershipListener implements Listener {
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onJoin(PlayerJoinEvent e) {
|
||||
updatePlayer(e.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onLeave(PlayerQuitEvent e) {
|
||||
removePlayer(e.getPlayer(), false);
|
||||
@EventHandler
|
||||
public void onLeave(PlayerQuitEvent e) {
|
||||
forgetViewer(e.getPlayer());
|
||||
}
|
||||
|
||||
// A dead player loses the right to see the enemy hull again
|
||||
@EventHandler
|
||||
public void onTeamDeath(TeamDeathEvent e) {
|
||||
e.getFightPlayer().ifPlayer(player -> {
|
||||
updatePlayer(player);
|
||||
FightSystem.getTechHider().reloadChunks(player, Fight.getOpposite(e.getFightPlayer().getTeam()).getExtendRegion(), Region.EMPTY);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void updatePlayer(Player player) {
|
||||
@@ -92,16 +107,16 @@ public class HullHider implements Listener {
|
||||
FightPlayer fp = Fight.getFightPlayer(player);
|
||||
for (Map.Entry<FightTeam, Hull> hull : hullMap.entrySet()) {
|
||||
if (Config.isReferee(player) || hull.getKey() == team || (fp != null && fp.canEntern())) {
|
||||
hull.getValue().removePlayer(player, true);
|
||||
hull.getValue().addViewer(player);
|
||||
} else {
|
||||
hull.getValue().addPlayer(player);
|
||||
hull.getValue().removeViewer(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void removePlayer(Player player, boolean activeRemoval) {
|
||||
private void forgetViewer(Player player) {
|
||||
for (Hull hull : hulls) {
|
||||
hull.removePlayer(player, activeRemoval);
|
||||
hull.forgetViewer(player);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user