874b6f20c2
Основа — Horizon (MIT). История апстрима не переносится: этот репозиторий ведёт свою.
104 lines
4.9 KiB
Python
104 lines
4.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Compare how a client walks a living entity along its server's positions with vanilla.
|
|
|
|
Vanilla's unmodified SteppedInterpolationHandler.InterpolationData (VanillaSteppedInterpolationOracle
|
|
drives it as the handler does) and horizon-world's SteppedInterpolation replay the same packets and
|
|
client ticks: move packets with and without a position or rotation, straight or stepped paths,
|
|
repeats of the one the entity is headed for, packets a tick apart that pile up and others after it
|
|
stopped, for update intervals of 1 to 3 ticks, plus a punched pig's knockback as the server sends it
|
|
(its first move at once, `needsSync`, then every update interval). The entity's position and rotation
|
|
after every event must match bit for bit. The handler's entity hooks (deltas, passengers) are out of
|
|
scope.
|
|
"""
|
|
import os
|
|
import random
|
|
import subprocess
|
|
try:
|
|
from . import lab, test_rust_parity as base
|
|
except ImportError:
|
|
import lab
|
|
import test_rust_parity as base
|
|
|
|
# A pig punched on flat ground, its positions on the server tick by tick (knockback 0.4 along x).
|
|
KNOCKBACK = [(0.0, 0.0), (0.3032, 0.3608), (0.4638, 0.636), (0.6049, 0.8273), (0.7279, 0.9363), (0.8345, 0.9648),
|
|
(0.926, 0.9143), (1.0037, 0.7864), (1.0688, 0.5827), (1.1223, 0.3046), (1.1654, 0.0), (1.1147, 0.0),
|
|
(0.9968, 0.0), (0.8418, 0.0), (0.6664, 0.0)]
|
|
|
|
|
|
def position(rng, p):
|
|
return [round(v + rng.uniform(-0.6, 0.6), rng.choice([2, 4, 17])) for v in p]
|
|
|
|
|
|
def rotation(rng):
|
|
return [round(rng.uniform(-400, 400), rng.choice([0, 1, 3])), round(rng.uniform(-120, 120), rng.choice([0, 2]))]
|
|
|
|
|
|
def cases(count, seed):
|
|
rng = random.Random(seed)
|
|
lines = []
|
|
for interval in (1, 2, 3):
|
|
# The knockback: a packet for the hit tick's move, then every interval (each phase).
|
|
for phase in range(interval):
|
|
lines.append(f'case {interval} 10.5 64.0 0.5 90.0 0.0')
|
|
for k in range(1, len(KNOCKBACK)):
|
|
if k == 1 or (k + phase) % interval == 0:
|
|
x, y = KNOCKBACK[k]
|
|
lines.append(f'move L {10.5 + x!r} {64 + y!r} 0.5 -')
|
|
lines.append('tick')
|
|
lines += ['tick'] * 6
|
|
for _ in range(count):
|
|
p = [rng.uniform(-100, 100), rng.uniform(-64, 300), rng.uniform(-100, 100)]
|
|
yaw, pitch = rotation(rng)
|
|
lines.append(f'case {rng.choice([1, 2, 3, 3, 3])} {p[0]!r} {p[1]!r} {p[2]!r} {yaw!r} {pitch!r}')
|
|
last = None
|
|
for _ in range(rng.randrange(1, 40)):
|
|
if rng.random() < 0.45:
|
|
lines.append('tick')
|
|
continue
|
|
if last is not None and rng.random() < 0.15:
|
|
line = last # the same packet again
|
|
else:
|
|
if rng.random() < 0.1:
|
|
line = 'move N'
|
|
elif rng.random() < 0.2:
|
|
n = rng.randrange(1, 5)
|
|
steps = []
|
|
for _ in range(n):
|
|
p = position(rng, p)
|
|
steps.append(f'{p[0]!r} {p[1]!r} {p[2]!r} {rng.randrange(1, 4)}')
|
|
line = f'move S {n} ' + ' '.join(steps)
|
|
else:
|
|
p = position(rng, p) if rng.random() < 0.9 else p
|
|
line = f'move L {p[0]!r} {p[1]!r} {p[2]!r}'
|
|
rot = rotation(rng) if rng.random() < 0.6 else None
|
|
line += f' R {rot[0]!r} {rot[1]!r}' if rot else ' -'
|
|
last = line
|
|
lines.append(line)
|
|
lines += ['tick'] * rng.choice([0, 1, 1, 2, 3, 6])
|
|
return lines
|
|
|
|
|
|
def main():
|
|
lock, jars, libraries = base.verify_artifacts()
|
|
build = lab.LOCAL / 'stepped-interpolation-parity'
|
|
build.mkdir(parents=True, exist_ok=True)
|
|
classes = build / 'classes'
|
|
classes.mkdir(exist_ok=True)
|
|
events = build / 'events.txt'
|
|
events.write_text('\n'.join(cases(3000, 1374)) + '\n', encoding='utf-8')
|
|
classpath = os.pathsep.join(map(str, [jars['client'], *libraries]))
|
|
oracle = lab.ROOT / 'mods/horizon/src/test/java/dev/horizonlab/parity/VanillaSteppedInterpolationOracle.java'
|
|
subprocess.run(['javac', '--release', str(lock['minecraft']['java_major']), '-proc:none',
|
|
'-cp', classpath, '-d', str(classes), str(oracle)], check=True)
|
|
subprocess.run(['java', '-Xmx512M', '-cp', str(classes) + os.pathsep + classpath,
|
|
'dev.horizonlab.parity.VanillaSteppedInterpolationOracle', str(events), str(build / 'vanilla.txt')],
|
|
check=True)
|
|
subprocess.run(['cargo', 'run', '--quiet', '--release', '-p', 'horizon-world', '--example',
|
|
'world_probe', '--', 'stepped_interpolation_fixture', str(events), str(build / 'rust.txt')], cwd=lab.ROOT, check=True)
|
|
matched = base.compare(build / 'vanilla.txt', build / 'rust.txt')
|
|
print(f'Stepped interpolation parity passed: {matched} entity positions and rotations match vanilla')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|