parity: world_reopen and server_player_sculk count ticks, not request round trips
On playhorizon (frames drawn on the CPU, control requests answered slowly) world_reopen read the minecarts before the mineshaft's last one arrived (3 then 4 on every reopen), and the sculk walk polled the sensor with separate requests that missed its 30-tick active window. The minecart list is read once it stops changing; both clients sample the sensor every tick from one ctl script, alongside the walk. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@ hosts: the guest always uses the server-player path.
|
||||
import json
|
||||
import math
|
||||
import subprocess
|
||||
import threading
|
||||
|
||||
import lab
|
||||
import lan_e2e as lan
|
||||
@@ -43,17 +44,29 @@ def check_walk(host, guest, out, role):
|
||||
until(host, lambda: phase(host), lambda s: 'sculk_sensor_phase=inactive' in s)
|
||||
player.wait(10)
|
||||
assert 'sculk_sensor_phase=inactive' in phase(host), 'setup activated the sensor'
|
||||
player.raw('key', 'w', 'down')
|
||||
# The sensor stays active 30 ticks. Each client samples it every tick from inside one ctl script, so a
|
||||
# runner that answers control requests slowly (frames drawn on the CPU) can't miss that window between
|
||||
# separate requests; the other client samples alongside the walk.
|
||||
probe = f'getblock {sensor[0]} {sensor[1]} {sensor[2]}'
|
||||
other = guest if player is host else host
|
||||
seen = {}
|
||||
|
||||
def watch(viewer, lines):
|
||||
seen[viewer.name] = [r['block'] for r in viewer.script(lines, every=True) if 'block' in r]
|
||||
watcher = threading.Thread(target=watch, args=(other, ['wait 1', probe] * 100))
|
||||
watcher.start()
|
||||
try:
|
||||
player.wait(15)
|
||||
watch(player, ['key w down', *['wait 1', probe] * 15, 'key w up', *['wait 1', probe] * 85])
|
||||
finally:
|
||||
player.raw('key', 'w', 'up')
|
||||
watcher.join()
|
||||
moved = {'client': math.dist(lan.pos_of(player), start),
|
||||
'server': math.dist(lan.server_player(host, player)['position'], start)}
|
||||
assert all(d > 1 for d in moved.values()), moved
|
||||
for viewer in (host, guest):
|
||||
until(viewer, lambda: phase(viewer), lambda s: 'sculk_sensor_phase=active' in s, ticks=85)
|
||||
return {'moved': moved, 'phase': phase(host)}
|
||||
active = {name: next((i for i, s in enumerate(states) if 'sculk_sensor_phase=active' in s), None)
|
||||
for name, states in seen.items()}
|
||||
assert len(active) == 2 and all(i is not None for i in active.values()), f'sensor never active: {seen}'
|
||||
return {'moved': moved, 'first_active_sample': active}
|
||||
finally:
|
||||
player.raw('key', 'w', 'up')
|
||||
host('command', command=f'fill {x - 2} {y} {z - 2} {x + 5} {y + 3} {z + 5} minecraft:air')
|
||||
|
||||
@@ -68,8 +68,16 @@ def main():
|
||||
return json.loads(result.stdout) if result.stdout.strip().startswith('{') else result.stdout
|
||||
|
||||
def carts():
|
||||
found = ctl('status')['carts']
|
||||
return sorted((c['kind'], *(round(v, 1) for v in c['position'])) for c in found)
|
||||
"""The loaded minecarts once their list stops changing: on a loaded runner the mineshaft's chunks and their
|
||||
entities keep arriving after the world counts as loaded, so one reading can be short of a cart."""
|
||||
last = None
|
||||
for _ in range(30):
|
||||
found = sorted((c['kind'], *(round(v, 1) for v in c['position'])) for c in ctl('status')['carts'])
|
||||
if found == last:
|
||||
return found
|
||||
last = found
|
||||
ctl('wait', '40')
|
||||
return last
|
||||
|
||||
ctl('launch', '--resources', str(RESOURCES), '--world', 'reopen', '--seed', '7', '--creative',
|
||||
'--render-distance', '4', *extra)
|
||||
|
||||
Reference in New Issue
Block a user