wire stream: a teleport's two answer ticks compare with each other, the rest on the script's clock

Aligning every tick after the teleport on its acceptance moved the script's own
packets (the button release, the 20-tick position) by the server's lag: on the
desktop vanilla got the answer at tick 26, Horizon at 29, and both clients'
packets were otherwise identical tick for tick.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Horizon agentandClaude Opus 5.5 committed 2026-11-05 23:06:50 +01:00
1 parent 422c36b236
commit 8d09d8b3f2
3 files changed
+29 -6

No files matched your search

+13
View File
@@ -87,6 +87,19 @@ class WireStreamTest(unittest.TestCase):
self.assertEqual(a[0][0]['packets'][0][1]['stale'], 0)
self.assertEqual(b[0][1]['packets'][0][1]['stale'], 1)
def test_a_late_answer_compares_with_vanilla_s_answer_and_the_script_keeps_its_clock(self):
tick = lambda *names: {'packets': [(n, {}) for n in names], 'frame': [], 'misplaced': []} # noqa
# The server's answer (an abort) reaches vanilla in tick 1 and Horizon in tick 2; the script acts in tick 3.
vanilla = [tick('punch'), tick('abort', 'punch'), tick('punch'), tick('pos'), tick()]
horizon = [tick('punch'), tick('punch'), tick('abort', 'punch'), tick('pos'), tick()]
self.assertEqual(wire_stream.compare_answered(vanilla, horizon, 4, 1, 2), [])
# What the answer brings is compared: a new dig instead of the abort.
restart = [tick('punch'), tick('punch'), tick('start', 'punch'), tick('pos'), tick()]
self.assertEqual([d[0] for d in wire_stream.compare_answered(vanilla, restart, 4, 1, 2)], [1])
# So is the script's clock: a packet a tick late anywhere else.
late = [tick('punch'), tick('punch'), tick('abort', 'punch'), tick(), tick('pos')]
self.assertEqual([d[0] for d in wire_stream.compare_answered(vanilla, late, 4, 1, 2)], [3, 4])
def test_compare_reports_the_first_field_that_differs(self):
tick = lambda y: {'packets': [('move_player_pos', {'x': 0.5, 'y': y})], 'frame': [], 'misplaced': []} # noqa
diffs = wire_stream.compare([tick(-60.0)], [tick(-60.0000001)], 0)
+3 -6
View File
@@ -416,18 +416,15 @@ def run(args, out):
def anchored_diffs(v, h, ticks, anchor, problems):
"""wire_stream.compare over the scenario's ticks. With an anchor (a frame packet the server's answer brings,
as AcceptTeleportation), the ticks before it compare one to one and the ticks from it on are aligned on it:
a loaded server answers a tick or more later in one run than in the other. Numbers are vanilla's ticks."""
as AcceptTeleportation), the two ticks that answer arrived in compare with each other
(wire_stream.compare_answered). Numbers are vanilla's ticks."""
if not anchor:
return wire_stream.compare(v, h, ticks)
av, ah = wire_stream.first_frame(v, anchor), wire_stream.first_frame(h, anchor)
if av is None or ah is None:
problems.append(f' no {anchor}: vanilla at tick {av}, Horizon at tick {ah}')
return wire_stream.compare(v, h, ticks)
# Between the two anchors both clients wait for the server: the ticks after the shorter wait are left out.
before = wire_stream.compare(v[:min(av, ah)], h[:min(av, ah)], min(av, ah) - 1)
after = wire_stream.compare(v[av:], h[ah:], ticks - max(av, ah))
return before + [(i + av, vt, ht) for i, vt, ht in after]
return wire_stream.compare_answered(v, h, ticks, av, ah)
def compare(captures, scenarios):
+13
View File
@@ -203,6 +203,19 @@ def compare(vanilla, horizon, ticks):
return out
def compare_answered(vanilla, horizon, ticks, av, ah):
"""compare, for a scenario the server answers once (a teleport): the tick each client received the answer
in (`av`, `ah`) compares with the other client's, every other tick with the same tick, on the script's
clock. A loaded server answers a few ticks later in one run than in the other, while the script's own
packets (a button released, the position resent every 20 ticks) keep its clock. Numbers are vanilla's."""
out = [d for d in compare(vanilla, horizon, ticks) if d[0] not in (av, ah)]
v = vanilla[av]['packets'] if av < len(vanilla) else None
h = horizon[ah]['packets'] if ah < len(horizon) else None
if v != h:
out.append((av, v, h))
return sorted(out, key=lambda d: d[0])
def describe(packets):
if packets is None:
return ' (no such tick)'