874b6f20c2
Основа — Horizon (MIT). История апстрима не переносится: этот репозиторий ведёт свою.
92 lines
4.0 KiB
Python
Executable File
92 lines
4.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""The End of a dedicated server nobody has entered, force-loaded from the console, against vanilla's.
|
|
|
|
A vanilla dedicated server and Horizon's each open a copy of one world vanilla generated (its End not made yet).
|
|
With no player online, the console force-loads the End's main island and its arena. A FORCED ticket keeps its level active
|
|
(`ServerChunkCache.hasActiveTickets`, `TicketType.FORCED`), so the chunks are generated, loaded and ticked
|
|
without a player in the dimension. With nobody in the fight, `EnderDragonFight.tick` neither scans the state nor
|
|
places the exit portal: no bedrock and no torches around 0, 0. Both servers must answer the same.
|
|
"""
|
|
import os
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
|
|
try:
|
|
from . import lab, test_rust_parity as base
|
|
from .test_dedicated_server_parity import Server, wait_ticks
|
|
from .test_locator_bar_parity import generate_world, server_dir
|
|
except ImportError:
|
|
import lab
|
|
import test_rust_parity as base
|
|
from test_dedicated_server_parity import Server, wait_ticks
|
|
from test_locator_bar_parity import generate_world, server_dir
|
|
|
|
NAME = 'forced-end-parity'
|
|
END = 'execute in minecraft:the_end'
|
|
QUERIES = [
|
|
f'{END} run fill -3 0 -3 3 255 3 minecraft:air replace minecraft:bedrock',
|
|
f'{END} run fill -3 0 -3 3 255 3 minecraft:air replace minecraft:wall_torch',
|
|
]
|
|
|
|
|
|
def answer(server, command, n):
|
|
start = len(server.lines)
|
|
server.console(command)
|
|
server.console(f'say done {n}')
|
|
server.wait_for(rf'\[Server\] done {n}$', timeout=120)
|
|
replies = [l.split(']: ', 1)[-1] for l in server.lines[start:] if 'done ' not in l]
|
|
return ' / '.join(r for r in replies if r) or '(no reply)'
|
|
|
|
|
|
def run_side(label, command, build, world):
|
|
directory = build / label
|
|
server_dir(directory, world)
|
|
server = Server(command, directory, label)
|
|
try:
|
|
server.wait_for(r'Done \(')
|
|
# The main island's arena (EnderDragonFight.isArenaLoaded: chunks -8..8), in pieces of at most 256 chunks.
|
|
for area in ('-128 -128 143 -1', '-128 0 143 143'):
|
|
server.console(f'{END} run forceload add {area}')
|
|
deadline = time.time() + 600
|
|
for poll in range(1_000_000):
|
|
reply = answer(server, f'{END} if loaded 0 0 0', f'loaded {poll}')
|
|
if 'passed' in reply:
|
|
break
|
|
if time.time() > deadline:
|
|
raise AssertionError(f'{label}: the End centre never loaded')
|
|
time.sleep(2)
|
|
wait_ticks(server, 200)
|
|
return {q: answer(server, q, i) for i, q in enumerate(QUERIES)}
|
|
finally:
|
|
server.stop()
|
|
|
|
|
|
def main():
|
|
_, jars, libraries = base.verify_artifacts()
|
|
build = lab.LOCAL / NAME
|
|
build.mkdir(parents=True, exist_ok=True)
|
|
dependencies = os.pathsep.join(map(str, [jars['server'], *libraries]))
|
|
subprocess.run(['cargo', 'build', '--release', '-p', 'horizon-client', '--bin', 'horizon-client'], cwd=lab.ROOT,
|
|
check=True, capture_output=True)
|
|
binary = lab.cargo_target() / 'release' / ('horizon-client.exe' if os.name == 'nt' else 'horizon-client')
|
|
vanilla_server = ['java', '-Xmx2g', '-Duser.timezone=UTC', '-cp', dependencies, 'net.minecraft.server.Main', 'nogui']
|
|
horizon_server = [binary, '--resources', lab.LOCAL / 'horizon-client/26.3', '--dedicated', '--nogui']
|
|
world = generate_world(vanilla_server, build)
|
|
vanilla = run_side('vanilla', vanilla_server, build, world)
|
|
horizon = run_side('horizon', horizon_server, build, world)
|
|
normal = lambda s: re.sub(r'\s+', ' ', s).strip()
|
|
problems = [f'{q}\n vanilla: {vanilla[q]}\n horizon: {horizon[q]}'
|
|
for q in QUERIES if normal(vanilla[q]) != normal(horizon[q])]
|
|
if problems:
|
|
raise AssertionError('the forced End differs:\n' + '\n'.join(problems))
|
|
print(f'forced End: loaded and ticked with nobody in it, no exit portal, as vanilla ({vanilla[QUERIES[0]]})')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
try:
|
|
main()
|
|
except AssertionError as error:
|
|
sys.exit(f'{NAME}: {error}')
|