mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 11:06:11 -10:00
Respect entity-ticking loading status in execute loaded
Require completed saved-entity application and loading status without changing simulation or physical unload policy. Co-Authored-By: Codex <[email protected]>
This commit is contained in:
1 parent
aef74cd095
commit
52c79cedb1
5 files changed
+72
-7
No files matched your search
@@ -949,6 +949,17 @@ impl Game<'_> {
|
||||
let keep = results.iter().any(|r| r.is_some_and(|v| (v != 0) == want));
|
||||
Ok((keep, 0))
|
||||
}
|
||||
/// `ExecuteCommand.isChunkLoaded`: an entity-ticking loading status and
|
||||
/// completed entity loading, rather than merely a retained lit column.
|
||||
fn command_chunk_loaded(&self, x: i32, z: i32) -> bool {
|
||||
self.tickets.levels().loaded_entity_ticking(x, z)
|
||||
&& self.world.chunks.contains_key(&(x, z))
|
||||
&& self.streaming.is_lit(x, z)
|
||||
// Streaming queues the saved tags before making the column resident;
|
||||
// spawn_loaded_entities applies them before this chunk's entities run.
|
||||
&& !self.world.loaded_entities.iter().any(|(key, _)| *key == (x, z))
|
||||
}
|
||||
|
||||
fn condition_matches(&mut self, c: &Context) -> R<(bool, i32)> {
|
||||
let flag = |b: bool| (b, i32::from(b));
|
||||
if c.has("data") {
|
||||
@@ -976,12 +987,10 @@ impl Game<'_> {
|
||||
.coords(c, "pos")
|
||||
.map(|co| co.block(self.source_position(), self.source_rotation()));
|
||||
let dimension = self.command_source.map_or(self.dim, |s| s.dimension);
|
||||
// ExecuteCommand.isChunkLoaded: ENTITY_TICKING, which is past lit.
|
||||
let loaded = |p: [i32; 3]| {
|
||||
let key = (p[0] >> 4, p[2] >> 4);
|
||||
self.world.chunks.contains_key(&key) && self.streaming.is_lit(key.0, key.1)
|
||||
};
|
||||
return Ok(flag(dimension == self.dim && p.is_some_and(loaded)));
|
||||
return Ok(flag(
|
||||
dimension == self.dim
|
||||
&& p.is_some_and(|p| self.command_chunk_loaded(p[0] >> 4, p[2] >> 4)),
|
||||
));
|
||||
}
|
||||
if c.has("dimension") {
|
||||
let dimension = self.command_source.map_or(self.dim, |s| s.dimension);
|
||||
|
||||
@@ -209,6 +209,12 @@ impl Levels {
|
||||
pub fn random_tick_bounds(&self) -> Option<(i32, i32, i32, i32)> {
|
||||
self.1
|
||||
}
|
||||
/// The loading track has `FullChunkStatus.ENTITY_TICKING`, independently
|
||||
/// of whether the simulation tracker also permits entities to tick.
|
||||
pub fn loaded_entity_ticking(&self, x: i32, z: i32) -> bool {
|
||||
self.get(x, z)
|
||||
.is_none_or(|(loading, _)| loading <= ENTITY_TICKING)
|
||||
}
|
||||
/// `ChunkHolder.getFullStatus` is block ticking or more: the chunk's
|
||||
/// ticking future can complete (its saved ticks unpack then).
|
||||
pub fn loaded_ticking(&self, x: i32, z: i32) -> bool {
|
||||
@@ -475,6 +481,9 @@ mod tests {
|
||||
assert!(l.random_ticking(-4, 4) && !l.random_ticking(0, 5));
|
||||
assert!(l.block_ticking(5, 5) && !l.block_ticking(6, 0));
|
||||
assert!(l.loaded_ticking(9, 9) && !l.loaded_ticking(10, 0));
|
||||
// A command asks the loading status, not the smaller simulation area.
|
||||
assert!(l.loaded_entity_ticking(8, 8));
|
||||
assert!(!l.loaded_entity_ticking(9, 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -486,6 +495,8 @@ mod tests {
|
||||
assert!(l.entity_ticking(4, 0) && !l.entity_ticking(5, 0));
|
||||
assert!(l.random_ticking(5, 0) && !l.random_ticking(6, 0));
|
||||
assert!(l.block_ticking(5, 5) && !l.block_ticking(6, 0));
|
||||
assert!(l.loaded_entity_ticking(4, 0));
|
||||
assert!(!l.loaded_entity_ticking(5, 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -137,7 +137,7 @@ EnchantCommand.register port crates/horizon-command/src/vanilla.rs::registered e
|
||||
net/minecraft/server/commands/ExecuteCommand#wrapStores port crates/horizon-command/src/tree_execute.rs::store execute store syntax
|
||||
net/minecraft/server/commands/ExecuteCommand#storeValue port crates/horizon-client/src/game/commands/execute.rs::Game::store_value score and bossbar store targets
|
||||
net/minecraft/server/commands/ExecuteCommand#storeData port crates/horizon-client/src/game/commands/execute.rs::Game::store_value data target store with int, float, short, long, double tags
|
||||
net/minecraft/server/commands/ExecuteCommand#isChunkLoaded port crates/horizon-client/src/game/commands/execute.rs::Game::condition_matches gap: the loaded arm tests a chunk present with light (streaming.is_lit) and has no entity check, where vanilla wants the chunk at ENTITY_TICKING and level.areEntitiesLoaded
|
||||
net/minecraft/server/commands/ExecuteCommand#isChunkLoaded port crates/horizon-client/src/game/commands/execute.rs::Game::command_chunk_loaded ENTITY_TICKING loading status, resident light-ready column and completed saved-entity application
|
||||
net/minecraft/server/commands/ExecuteCommand#countItems port crates/horizon-client/src/game/commands/items.rs::Game::condition_items item count predicate
|
||||
net/minecraft/server/commands/ExecuteCommand#checkScore port crates/horizon-client/src/game/commands/execute.rs::Game::condition_score score comparison, both score holders
|
||||
net/minecraft/server/commands/ExecuteCommand#checkStopwatch port crates/horizon-client/src/game/commands/execute.rs::Game::condition_stopwatch stopwatch range check
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 66 and column 104.
|
@@ -91,6 +91,9 @@ def main():
|
||||
build.mkdir(parents=True, exist_ok=True)
|
||||
report_path = build / 'report.json'
|
||||
report_path.unlink(missing_ok=True)
|
||||
if args.loaded_fixture:
|
||||
for name in ['client_config.json', 'rust-client-config.json']:
|
||||
(build / name).unlink(missing_ok=True)
|
||||
if args.prepare:
|
||||
lab.prepare()
|
||||
lock, jars, libraries = base.verify_artifacts()
|
||||
@@ -168,6 +171,14 @@ def main():
|
||||
config = json.loads((build / name).read_text())
|
||||
if config.get('view_distance') != 2 or config.get('simulation_distance') != 2:
|
||||
sys.exit(f'actual login distance prerequisite failed: {name}: {config}')
|
||||
java = json.loads((build / 'client_config.json').read_text())
|
||||
if java.get('server_view') != 2 or java.get('server_simulation') != 2 or not java.get('client_loaded'):
|
||||
sys.exit(f'Java server/client-loaded prerequisite failed: {java}')
|
||||
for name in ['java.log', 'rust.log']:
|
||||
waits = re.findall(r'harness paced wait: (\d+) ticks, (\d+) ms', (build / name).read_text())
|
||||
if len(waits) != 2 or any(int(n) != ticks or not ticks * 50 <= int(ms) <= upper
|
||||
for (n, ms), ticks, upper in zip(waits, [40, 120], [4000, 10000])):
|
||||
sys.exit(f'bounded paced-wait prerequisite failed: {name}: {waits}')
|
||||
native = json.loads((build / 'rust-client-config.json').read_text())
|
||||
if native.get('render_setting') != 2 or native.get('simulation_setting') != 2 or not native.get('joined'):
|
||||
sys.exit(f'native settings/join prerequisite failed: {native}')
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Distance-two /execute loaded after forced-ticket removal.
|
||||
|
||||
The default90-record gate is strict. --block-diagnostic also retains30 FULL
|
||||
block-access observations, whose separate failures are outside this task.
|
||||
"""
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--binary', type=Path)
|
||||
parser.add_argument('--prepare', action='store_true')
|
||||
parser.add_argument('--block-diagnostic', action='store_true')
|
||||
args = parser.parse_args()
|
||||
root = Path(__file__).resolve().parents[1]
|
||||
folder = 'loaded-block-diagnostic' if args.block_diagnostic else 'loaded-command-parity'
|
||||
command = [sys.executable, str(root / 'tools/test_command_exec_parity.py'),
|
||||
'--loaded-fixture', '--only', 'loaded ticket removal',
|
||||
'--work-dir', str(root / '.local' / folder)]
|
||||
if args.binary:
|
||||
command += ['--binary', str(args.binary.resolve())]
|
||||
if args.prepare:
|
||||
command.append('--prepare')
|
||||
if args.block_diagnostic:
|
||||
command.append('--loaded-block-diagnostic')
|
||||
return subprocess.run(command, cwd=root).returncode
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
Reference in new issue
Block a user