Building boxes: no per-level clone, linear per-turn snapshot

GameLevel borrows guest_boxes outside a guest turn instead of cloning them,
and for_turn only searches the few borrowed ancestors, so a turn costs
O(players) rather than O(players^2) for each guest every tick.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Horizon agentandClaude Opus 5.5 committed 2026-11-05 12:40:26 +01:00
1 parent ceb886b00f
commit c17d14c739
2 files changed
+21 -9

No files matched your search

+12 -8
View File
@@ -959,8 +959,9 @@ struct GameLevel<'w> {
player_box: Option<([f64; 3], [f64; 3])>,
/// The LAN guests in this level who trigger blocks (not spectators).
guest_boxes: Vec<([f64; 3], [f64; 3])>,
/// Other players that block placement, including a detached guest turn.
building_player_boxes: Vec<([f64; 3], [f64; 3])>,
/// Other players that block placement during a guest turn, whose hub is
/// borrowed out; None outside one, where `guest_boxes` are those players.
building_player_boxes: Option<Vec<([f64; 3], [f64; 3])>>,
player_collision: Option<PlayerCollision>,
/// Minecart boxes (detector rails).
cart_boxes: Vec<([f64; 3], [f64; 3])>,
@@ -1151,7 +1152,11 @@ impl GameLevel<'_> {
let b = self.entities;
self.player_box
.iter()
.chain(&self.building_player_boxes)
.chain(
self.building_player_boxes
.as_ref()
.unwrap_or(&self.guest_boxes),
)
.chain(&self.cart_boxes)
.map(boxed)
.chain(b.mobs.iter().filter(|m| !m.removed).map(Mob::bounds))
@@ -4638,11 +4643,10 @@ impl Game<'_> {
})
.collect();
let guest_boxes = self.lan_block_trigger_boxes();
let building_player_boxes = if self.lan_acting.is_some() {
self.lan_building_boxes.boxes(self.dim)
} else {
guest_boxes.clone()
};
let building_player_boxes = self
.lan_acting
.is_some()
.then(|| self.lan_building_boxes.boxes(self.dim));
let dimension = match self.dim {
Dim::Overworld => LevelDimension::Overworld,
Dim::Nether => LevelDimension::Nether,
@@ -23,6 +23,9 @@ impl BuildingPlayers {
outer: Option<BuildingPlayer>,
current: Vec<BuildingPlayer>,
) -> Self {
// The borrowed ancestors are the few nested turns (usually none or
// one): only they are searched, so a turn costs O(players), not
// O(players²), every guest's turn of every tick.
let mut players: Vec<_> = self
.0
.iter()
@@ -41,8 +44,13 @@ impl BuildingPlayers {
players.push(outer);
}
}
let ancestors = players.len();
players.reserve(current.len());
for player in current {
if player.conn != Some(actor) && !players.iter().any(|p| p.conn == player.conn) {
// Hub conns are unique, so only the ancestors can already hold one.
if player.conn != Some(actor)
&& !players[..ancestors].iter().any(|p| p.conn == player.conn)
{
players.push(player);
}
}