mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-11 02:21:38 -10:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b880384691 | ||
|
|
77a34310b0 | ||
|
|
7627df18b0 | ||
|
|
ee66246131 | ||
|
|
766a5d4c87 | ||
|
|
938dcd673c |
No files matched your search
+12
-12
@@ -1,16 +1,16 @@
|
||||
# Changes to these files wait for Ludovic's review once branch protection requires code owners' reviews
|
||||
# Changes to these files wait for a council member's review (council poll P35, 2026-11-10) once branch protection requires code owners' reviews
|
||||
# (tools/ci/protect_pipeline.sh, docs/security.md). They are what builds, signs and ships releases, the code that
|
||||
# checks downloads before installing them (backend.rs downloads, installs and updates the launcher itself; links.json
|
||||
# says where from; the Cargo.toml files pick the crates that do it), and this file. Everything else merges as soon as
|
||||
# `verify` passes.
|
||||
/.github/ @ludovic111
|
||||
/tools/ci/ @ludovic111
|
||||
/tools/release_train.py @ludovic111
|
||||
/crates/horizon-release-sign/ @ludovic111
|
||||
/crates/horizon-server/src/update.rs @ludovic111
|
||||
/crates/horizon-server/Cargo.toml @ludovic111
|
||||
/launcher/src/signed.rs @ludovic111
|
||||
/launcher/src/backend.rs @ludovic111
|
||||
/launcher/links.json @ludovic111
|
||||
/launcher/Cargo.toml @ludovic111
|
||||
/packaging/ @ludovic111
|
||||
/.github/ @horizon-rust/council
|
||||
/tools/ci/ @horizon-rust/council
|
||||
/tools/release_train.py @horizon-rust/council
|
||||
/crates/horizon-release-sign/ @horizon-rust/council
|
||||
/crates/horizon-server/src/update.rs @horizon-rust/council
|
||||
/crates/horizon-server/Cargo.toml @horizon-rust/council
|
||||
/launcher/src/signed.rs @horizon-rust/council
|
||||
/launcher/src/backend.rs @horizon-rust/council
|
||||
/launcher/links.json @horizon-rust/council
|
||||
/launcher/Cargo.toml @horizon-rust/council
|
||||
/packaging/ @horizon-rust/council
|
||||
@@ -1146,8 +1146,8 @@ impl Game<'_> {
|
||||
/// `DistanceManager.inEntityTickingRange` in an entity-ticking chunk
|
||||
/// (block coordinates), from every player's tickets (`update_chunk_tickets`).
|
||||
pub(super) fn entity_ticking_area(&self) -> impl Fn(i32, i32) -> bool + use<> {
|
||||
self.tickets
|
||||
.entity_ticking_area(&self.world.chunks, self.remote.is_none())
|
||||
let levels = self.tickets.levels();
|
||||
move |x, z| levels.entity_ticking_at(x, z)
|
||||
}
|
||||
/// The entity phase of `tick_creatures`: every mob's tick, deaths, and the
|
||||
/// projectiles and effects that follow from them.
|
||||
|
||||
@@ -1351,16 +1351,10 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
game.options.dedicated = Some(Vec::new());
|
||||
// Entity ticking waits for every chunk within 2 columns
|
||||
// (`ChunkMap.prepareEntityTickingChunk`).
|
||||
for z in -2..=2 {
|
||||
for x in -2..=2 {
|
||||
game.world.chunks.insert(
|
||||
(x, z),
|
||||
std::sync::Arc::new(horizon_client::chunk::Chunk::empty(x, z)),
|
||||
);
|
||||
}
|
||||
}
|
||||
game.world.chunks.insert(
|
||||
(0, 0),
|
||||
std::sync::Arc::new(horizon_client::chunk::Chunk::empty(0, 0)),
|
||||
);
|
||||
game.streaming.forced.insert((0, 0));
|
||||
Some(game)
|
||||
}
|
||||
@@ -1847,30 +1841,6 @@ mod tests {
|
||||
game.particles.requested.as_ref().unwrap().len()
|
||||
}
|
||||
|
||||
/// #13852: a chunk enters entity ticking only once every chunk within 2
|
||||
/// columns is loaded (`ChunkMap.prepareEntityTickingChunk`), so TNT beside
|
||||
/// a missing chunk keeps its fuse until the neighbourhood is whole.
|
||||
#[test]
|
||||
fn tnt_waits_while_a_chunk_two_columns_away_is_missing() {
|
||||
let Some(mut game) = server_game() else {
|
||||
return;
|
||||
};
|
||||
game.world.chunks.remove(&(2, 0));
|
||||
game.add_primed_tnt(BlockPos::new(8, 64, 8), 0.0, 80, None, None);
|
||||
game.tnts[0].no_gravity = true;
|
||||
game.tnts[0].velocity = Vec3::ZERO;
|
||||
for _ in 0..3 {
|
||||
game.tick_world(true).unwrap();
|
||||
}
|
||||
assert_eq!(game.tnts[0].fuse, 80, "no entity ticking yet");
|
||||
game.world.chunks.insert(
|
||||
(2, 0),
|
||||
std::sync::Arc::new(horizon_client::chunk::Chunk::empty(2, 0)),
|
||||
);
|
||||
game.tick_world(true).unwrap();
|
||||
assert!(game.tnts[0].fuse < 80, "ticks once the chunk is back");
|
||||
}
|
||||
|
||||
/// #10063: TNT lit between level ticks (flint and steel, a command) has its
|
||||
/// first tick in the next level tick, so its fuse reads 79 after it, and it
|
||||
/// explodes on the 80th (`PrimedTnt.tick`). Horizon held every TNT that
|
||||
|
||||
@@ -186,10 +186,6 @@ impl Levels {
|
||||
fn get(&self, x: i32, z: i32) -> Option<(u8, u8)> {
|
||||
Some(self.0.as_ref()?.get(x, z))
|
||||
}
|
||||
/// Whether any ticket exists; with none, everything ticks.
|
||||
pub fn has_tickets(&self) -> bool {
|
||||
self.0.is_some()
|
||||
}
|
||||
/// `DistanceManager.inEntityTickingRange`, in an entity-ticking chunk:
|
||||
/// where entities tick.
|
||||
pub fn entity_ticking(&self, x: i32, z: i32) -> bool {
|
||||
@@ -256,41 +252,9 @@ pub struct ChunkTickets {
|
||||
sources: Option<Sources>,
|
||||
levels: Levels,
|
||||
portal: Vec<PortalTicket>,
|
||||
/// The resident chunk keys at one membership revision.
|
||||
resident: std::sync::Mutex<(u64, Arc<crate::fast_hash::FxHashSet<(i32, i32)>>)>,
|
||||
}
|
||||
|
||||
impl ChunkTickets {
|
||||
/// `Levels::entity_ticking_at`, held back as `ChunkMap.prepareEntityTickingChunk`
|
||||
/// does: a chunk waits until every chunk within 2 columns is loaded. With no
|
||||
/// tickets everything ticks.
|
||||
pub fn entity_ticking_area(
|
||||
&self,
|
||||
chunks: &crate::chunk_map::ChunkMap,
|
||||
gate: bool,
|
||||
) -> impl Fn(i32, i32) -> bool + use<> {
|
||||
let levels = self.levels.clone();
|
||||
let resident = (gate && levels.0.is_some()).then(|| {
|
||||
let revision = chunks.membership_revision();
|
||||
let mut cache = self.resident.lock().unwrap_or_else(|e| e.into_inner());
|
||||
if cache.0 != revision {
|
||||
*cache = (revision, Arc::new(chunks.keys().copied().collect()));
|
||||
}
|
||||
cache.1.clone()
|
||||
});
|
||||
// Callers ask once per entity: remember each chunk's answer, so an
|
||||
// entity costs one lookup instead of the 25 of its neighbourhood.
|
||||
let surrounded = std::cell::RefCell::new(crate::fast_hash::FxHashMap::default());
|
||||
move |x, z| {
|
||||
levels.entity_ticking_at(x, z)
|
||||
&& resident.as_ref().is_none_or(|keys| {
|
||||
let (cx, cz) = (x >> 4, z >> 4);
|
||||
*surrounded.borrow_mut().entry((cx, cz)).or_insert_with(|| {
|
||||
(cz - 2..=cz + 2).all(|z| (cx - 2..=cx + 2).all(|x| keys.contains(&(x, z))))
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
/// `None`: tick everywhere.
|
||||
pub fn update(&mut self, mut sources: Option<Sources>) {
|
||||
// The game submits a fresh `Sources` value every tick even when no
|
||||
|
||||
@@ -136,6 +136,9 @@ public final class VanillaContainerScreenOracle {
|
||||
put(screen, Screen.class, "children", new ArrayList<>());
|
||||
put(screen, AbstractContainerScreen.class, "quickCraftSlots", new HashSet<Slot>());
|
||||
put(screen, AbstractContainerScreen.class, "lastQuickMoved", ItemStack.EMPTY);
|
||||
// alloc skips the constructor, which sets skipNextRelease = true:
|
||||
// a fresh screen swallows a release with no press before it.
|
||||
put(screen, AbstractContainerScreen.class, "skipNextRelease", true);
|
||||
if (c.has("book")) {
|
||||
var book = c.getAsJsonArray("book");
|
||||
var component = alloc(CraftingRecipeBookComponent.class);
|
||||
|
||||
@@ -75,7 +75,8 @@
|
||||
"unused_feature_startup": "capture-preserving harness: needs --kind, --output (a new capture folder) and --binary, which an automatic run doesn't pass, so it fails at startup whatever changed",
|
||||
"warden_owned_memories": "capture-preserving harness: writes .local/h029/capture and asserts it is new, so it fails at startup on any checkout that ran it before (the Mac mini runner)",
|
||||
"shulker_lock_drop": "capture-preserving harness: needs --work-dir (a fresh capture folder) and --reference-dir, which an automatic run doesn't pass, so it fails at startup whatever changed",
|
||||
"pot_hopper": "capture-preserving harness: needs --work-dir (a fresh capture folder) and --reference-dir, which an automatic run doesn't pass, so it fails at startup whatever changed"
|
||||
"pot_hopper": "capture-preserving harness: needs --work-dir (a fresh capture folder) and --reference-dir, which an automatic run doesn't pass, so it fails at startup whatever changed",
|
||||
"stand_lodestone": "capture-preserving harness: needs --work-dir (a new capture folder), --reference-dir and --binary, which an automatic run doesn't pass, so it fails at startup whatever changed"
|
||||
},
|
||||
"known_flaky": {
|
||||
"world_reopen": "counted 4 minecarts instead of 3 once on a loaded Mac mini runner, then passed at the same head (10-26)",
|
||||
|
||||
Reference in new issue
Block a user