Compare commits

...
Author SHA1 Message Date
rdbt 2d277eca26 Merge branch 'main' into agent/polytone-ticker-timing 2026-11-13 02:50:47 +00:00
rdbt 9f42064c11 Merge pull request #15867 from rdbtCVS/fix/pet-owner-teleport-stroll
pet_owner_teleport: a wolf that came may stroll off; count 16 blocks as near
2026-11-13 02:39:12 +00:00
rdbtCVSandClaude Opus 5.5 a13a21c522 pet_owner_teleport: count a wolf within 16 blocks as come to its owner
A tame wolf that teleported to Alice keeps strolling (WaterAvoidingRandomStrollGoal,
up to 10 blocks) and only walks back from 10 blocks, so a few seconds later it can
be 6 to 12 blocks from her, in vanilla as in Horizon. The 6-block check failed on
that at random (#15483; parity-main 43332620951 bisected it to unrelated merges).
Wolves left behind stay 28 blocks or more away.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-13 02:35:07 +00:00
rdbtCVSandGPT 6.1 Sol 6b7072d5eb Merge main and adapt Polytone timing test's particle level
Initialize the cached chunk required by the merged particle lookup optimization, as requested in the review of PR #14185.

Co-Authored-By: GPT 6.1 Sol <[email protected]>
2026-11-11 20:30:24 +00:00
Vinícius MoreiraandClaude Opus 5.5 ed63fd0057 Polytone: a timing test for custom particle tickers
custom_ticker_cost (ignored) ticks a firefly-like custom particle (five expressions with
sines and a named custom) and prints the time a tick takes, about 0.7 µs in release.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-09 18:52:13 +01:00
2 changed files with 60 additions and 4 deletions

No files matched your search

@@ -1799,6 +1799,58 @@ mod tests {
std::fs::remove_dir_all(root).unwrap();
}
/// Times a firefly-like custom particle's ticker (five expressions and a named custom a
/// tick): `cargo test --release -p horizon-client-render --lib custom_ticker_cost --
/// --ignored --nocapture`.
#[test]
#[ignore = "timing, not a check"]
fn custom_ticker_cost() {
let blocks = blocks();
let root = pack(&[
(
"assets/test/polytone/custom_particles/spark.json",
serde_json::json!({
"has_physics": false,
"initializer": {"lifetime": "100000", "custom": "0.3"},
"ticker": {
"alpha": "(0.7 + 0.3*sin(o.age*0.18 + o.custom*13000)) * min(o.age/(o.life*0.15),1)",
"size": "(0.65 + o.custom*0.15) * min(o.age/(o.life*0.12),1)",
"dx": "(0.014 + 0.006*sin(o.age*0.04 + o.custom*3000)) * sin(o.custom*200000 + o.age*0.035)",
"dz": "(0.014 + 0.006*sin(o.age*0.04 + o.custom*3000)) * cos(o.custom*200000 + o.age*0.035)",
"dy": "0.006*sin(o.age*0.08 + o.custom*9000)",
"customs": {"Glow": "o.custom('glow') + 1"}
}
}),
),
(
"assets/test/polytone/block_modifiers/torch.json",
serde_json::json!({
"targets": ["minecraft:torch"],
"particle_emitters": [{"particle": "test:spark", "chance": "1", "x": "0.5", "y": "1", "z": "0.5"}]
}),
),
]);
let scene = scene(blocks);
let level = ParticleLevel {
world: &scene.world,
facts: &scene.facts,
collision: &scene.collision,
player: None,
cached_chunk: std::cell::Cell::new(None),
};
let mut engine = engine(Registry::read(&root, Default::default(), blocks));
engine.polytone_animate(&level, [1, 64, 1]);
let mut p = engine.pending.pop().unwrap();
let ticks = 200_000;
let start = std::time::Instant::now();
for _ in 0..ticks {
engine.tick_particle(&mut p, &level);
}
let per = start.elapsed() / ticks;
println!("one custom particle tick: {per:?} (x {:.4})", p.position[0]);
std::fs::remove_dir_all(root).unwrap();
}
#[test]
fn the_ticker_moves_the_particle_and_removes_it() {
let blocks = blocks();
+8 -4
View File
@@ -6,8 +6,10 @@ vanilla generated first, with Alice an operator. Three standing wolves she owns
held by a pig that never moves (NoAI), one sitting in a boat. She then teleports 40 blocks away.
`TamableAnimal.shouldTryTeleportToOwner` (12 blocks or more) sends a pet to its owner unless `unableToMoveToOwner`:
ordered to sit, `isPassenger`, `mayBeLeashed` or an owner who is a spectator. So only the free wolf comes to her.
Whether each wolf is within 6 blocks of Alice afterwards is compared (where exactly a teleported wolf lands is a random
draw, not under test).
Whether each wolf is within 16 blocks of Alice afterwards is compared. Where exactly a teleported wolf lands is a random
draw, not under test, and so is what it does next: a tame wolf still strolls (`WaterAvoidingRandomStrollGoal`, up to 10
blocks) and only follows its owner back from 10 blocks (`FollowOwnerGoal`), teleporting again from 12. A wolf that came
can be 6 to 12 blocks from her a few seconds later, in vanilla as in Horizon; a wolf that stayed behind is 28 or more.
"""
import re
import sys
@@ -35,10 +37,12 @@ SCRIPT = [
]
# Where `away` puts Alice.
AWAY = (0.5, -60.0, 40.5)
# A wolf this close came to her: past the 12 blocks a pet teleports from, short of the 28 a wolf left behind keeps.
NEAR = 16.0
def shown(lines):
"""Whether each wolf ended within 6 blocks of Alice, from its `Pos`."""
"""Whether each wolf ended within `NEAR` blocks of Alice, from its `Pos`."""
out = []
for line in lines:
parts = line.split(' ', 3)
@@ -49,7 +53,7 @@ def shown(lines):
position = [float(v) for v in re.findall(r'"text":"(-?[0-9.]+)","color":"gold"', line)]
if len(position) != 3:
continue
near = sum((a - b) ** 2 for a, b in zip(position, AWAY)) <= 36.0
near = sum((a - b) ** 2 for a, b in zip(position, AWAY)) <= NEAR * NEAR
out.append(f'{parts[0]} {parts[1]} {"near" if near else "behind"}')
return out