Widen four parity harnesses' inputs

Cover all block states, registered enchantments, lore styles and
representative Lunge tiers using the existing vanilla oracles.

Co-Authored-By: pi coding agent (DeepSeek-V4.1-Flash) <[email protected]>
Co-Authored-By: Codex (gpt-6.1-sol) <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>

Claude-Session: https://claude.ai/code/session_01WZzq8KX3vDMZy53y1vXqeT
This commit is contained in:
committed 2026-11-06 20:32:02 +01:00
1 parent 41f822b659
commit f7190cff67
4 files changed
+161 -20

No files matched your search

+14 -4
View File
@@ -1,8 +1,10 @@
#!/usr/bin/env python3
"""Compare level-free block-model tints with actual 26.3 BlockTintSources.
Every state of blocks with registered sources, plus untinted carried blocks,
is checked at indices -1, 0, 1 and 2. Geometry and framebuffer are separate checks.
Every state of every registered block -- not only the hand-picked tinted
families -- is checked at indices -1, 0, 1 and 2: a block Horizon tints and
vanilla does not (or the other way round) only shows up in that sweep.
Geometry and framebuffer are separate checks.
"""
import json
try:
@@ -18,9 +20,15 @@ attached_pumpkin_stem melon_stem pumpkin_stem lily_pad stone poppy red_mushroom
brown_mushroom crimson_fungus warped_roots carved_pumpkin""".split()
def sweep(states):
"""The hand-picked families plus every other registered block name."""
names = {name.split(':', 1)[-1] for name in states.by_name}
return sorted(set(BLOCKS) | names)
def make_input(build):
states = mesh.States(lab.RESOURCES)
ids = sorted({state for name in BLOCKS for state in states.by_name["minecraft:" + name]})
ids = sorted({state for name in sweep(states) for state in states.by_name.get("minecraft:" + name, [])})
rows = [[state, index] for state in ids for index in [-1, 0, 1, 2]]
path = build / "input.json"
path.write_text(json.dumps(dict(resources=str(lab.RESOURCES), cases=rows)))
@@ -29,7 +37,9 @@ def make_input(build):
def main():
harness.differential("block-tint-parity", "VanillaBlockTintOracle", "block_tint_probe",
make_input, "BlockTintSource.color(state), all states of tinted blocks and untinted carried blocks; per-face tint indices, no level/biome. Not model or framebuffer parity.",
make_input, "BlockTintSource.color(state) at indices -1, 0, 1 and 2 for every state of every registered block, "
"not just the hand-picked tinted families; per-face tint indices, no level/biome. "
"Not model or framebuffer parity.",
sources=[lab.ROOT / "tools/test_block_tint_parity.py", lab.ROOT / "crates/horizon-client-render/src/mesher.rs",
lab.ROOT / "crates/horizon-client/src/item_render.rs"])
@@ -1,5 +1,6 @@
#!/usr/bin/env python3
"""Compare persistent enchantment levels and display names with vanilla 26.3."""
import json
import os
from pathlib import Path
import subprocess
@@ -11,6 +12,16 @@ except ImportError:
import test_rust_parity as base
def registry():
"""Every enchantment the prepared data pack registers, with its max_level."""
root = lab.RESOURCES / 'data/minecraft/enchantment'
out = []
for path in sorted(root.glob('*.json')):
data = json.loads(path.read_text(encoding='utf-8'))
out.append((f'minecraft:{path.stem}', int(data.get('max_level', 1))))
return out
def corpus():
values = [
'-2147483648', '-1', '0', '1', '10', '11', '254', '255', '256', '32767',
@@ -26,6 +37,26 @@ def corpus():
for label, levels in cases:
yield (f'{index}:{label}\t{{"minecraft:damage":12,"{key}":'
f'{levels},"{other}":{{mending:1}}}}')
# Every registered enchantment at every interesting level, alone and beside a
# second enchantment: the level ranges each definition declares (its
# max_level, one below, one above, far above), the byte range the component
# stores, and levels the display name turns into a numeral or a number.
enchantments = registry()
for index, key in enumerate(keys):
other = keys[1 - index]
for name, maximum in enchantments:
levels = sorted({-2147483648, -1, 0, 1, 2, max(1, maximum - 1), maximum,
maximum + 1, 255, 256, 32767, 2147483647})
for level in levels:
yield (f'{index}:{name[10:]}-{level}\t{{"minecraft:damage":12,"{key}":'
f'{{"{name}":{level}}},"{other}":{{"minecraft:mending":1}}}}')
for level in sorted({0, 1, maximum, maximum + 1}) if name != "minecraft:sharpness" else ():
yield (f'{index}:{name[10:]}-{level}-pair\t{{"minecraft:damage":12,"{key}":'
f'{{"minecraft:sharpness":{maximum},"{name}":{level}}}}}')
for label, level in [('all-max', None), ('all-one', 1), ('all-zero', 0)]:
levels = {name: (maximum if level is None else level) for name, maximum in enchantments}
body = ','.join(f'"{name}":{value}' for name, value in levels.items())
yield f'{index}:{label}\t{{"minecraft:damage":12,"{key}":{{{body}}}}}'
def main():
+88 -4
View File
@@ -5,6 +5,8 @@ Vanilla prints what ``ItemLore.addToTooltip`` adds after ``ComponentUtils.mergeS
with dark purple italic (VanillaLoreTooltipOracle). Horizon prints what
``item_tooltip::lore_texts`` gives (examples/probe/lore_tooltip_fixture).
"""
import json
try:
from . import lab, oracle_harness as harness
except ImportError:
@@ -30,21 +32,103 @@ CASES = [
]
COLORS = ['black', 'dark_blue', 'dark_green', 'dark_aqua', 'dark_red', 'dark_purple', 'gold',
'gray', 'dark_gray', 'blue', 'green', 'aqua', 'red', 'light_purple', 'yellow', 'white',
'#000000', '#ffffff', '#12ab34', '#c0ffee']
STYLES = ['bold', 'italic', 'underlined', 'strikethrough', 'obfuscated']
def stack(entries, display=None):
"""SNBT of a stick whose lore is the given list of NBT text components."""
components = '"minecraft:lore":[' + ','.join(entries) + ']'
if display is not None:
components += ',"minecraft:tooltip_display":' + display
return '{id:"minecraft:stick",count:1,components:{' + components + '}}'
def component(value):
"""A lore entry: a plain string stays a string, an object is JSON in NBT single quotes."""
return "'" + json.dumps(value, separators=(',', ':'), ensure_ascii=False) + "'"
def lore(*entries):
return stack([component(entry) for entry in entries])
def generated():
"""Styles, colours and nesting across the whole text-component surface."""
out = []
for color in COLORS:
out.append(lore({'text': 'C', 'color': color}))
for style in STYLES:
out.append(lore({'text': 'S', style: True}))
out.append(lore({'text': 'S', style: False}))
# The dark purple italic line style under an explicit false, and a child
# that turns the line's style back on or off.
out.append(lore({'text': 'P', style: False, 'extra': [{'text': 'C', style: True}]}))
out.append(lore({'text': 'P', style: True, 'extra': [{'text': 'C', style: False}]}))
out.append(lore({'text': 'P', style: True, 'extra': ['plain']}))
for color in COLORS[:16]:
for style in STYLES:
out.append(lore({'text': 'P', 'color': color, style: True,
'extra': [{'text': 'C', 'color': 'red', 'italic': False}]}))
# Nesting chains: each level overrides one more field.
for depth in range(1, 5):
child = {'text': 'd' + str(depth), 'color': COLORS[depth % len(COLORS)],
'bold': bool(depth % 2), 'italic': bool((depth + 1) % 2),
'underlined': bool(depth % 3 == 0), 'strikethrough': bool(depth % 2 == 0)}
for level in range(depth - 1, 0, -1):
child = {'text': 'd' + str(level), 'color': COLORS[level % len(COLORS)],
'extra': [child], 'bold': bool(level % 2),
'obfuscated': bool(level % 4 == 0)}
out.append(lore(child))
# Siblings at one level, one plain string and one object, and empty texts.
out.append(lore({'extra': [{'text': 'A', 'color': 'gold'}, 'B', {'text': '', 'color': 'red'},
{'extra': [{'text': 'C', 'italic': False}]}]}))
out.append(lore({'text': ''}))
out.append(lore({'text': '', 'color': 'aqua'}))
out.append(lore('', {'text': ''}))
# Many lines: order, mixed styles and repeated colours.
out.append(lore(*[{'text': 'L' + str(i), 'color': COLORS[i % len(COLORS)],
'bold': bool(i % 2), 'italic': bool(i % 3 == 0)} for i in range(10)]))
out.append(lore(*['line' + str(i) for i in range(6)]))
# Text outside ASCII, with styles, and a nested non-ASCII child.
out.append(lore({'text': '\u00e9\u4e2d\U0001F600', 'color': 'gold', 'bold': True}))
out.append(lore({'text': 'p', 'extra': [{'text': '\U0001F600'}], 'italic': False}))
# tooltip_display: hidden lore, another hidden component, an empty and a
# repeated entry, and hide_tooltip (which must not hide the lore lines).
out.append(stack([component({'text': 'H'})], '{hidden_components:["minecraft:lore"]}'))
out.append(stack([component({'text': 'H'})], '{hidden_components:["minecraft:enchantments"]}'))
out.append(stack([component({'text': 'H'})], '{hidden_components:[]}'))
out.append(stack([component({'text': 'H'})], '{hidden_components:["minecraft:lore","minecraft:lore"]}'))
out.append(stack([component({'text': 'H'})], '{hide_tooltip:1b}'))
out.append(stack([component({'text': 'H'})], '{hide_tooltip:1b,hidden_components:["minecraft:enchantments"]}'))
out.append(stack([component({'text': 'H'})], '{hide_tooltip:0b,hidden_components:["minecraft:lore"]}'))
return out
def corpus():
return CASES + generated()
def cases(build):
lines = corpus()
path = build / 'cases.txt'
path.write_text(''.join(line + '\n' for line in CASES))
return path, len(CASES)
path.write_text(''.join(line + '\n' for line in lines))
return path, len(lines)
if __name__ == '__main__':
harness.differential(
'lore-tooltip-parity', 'VanillaLoreTooltipOracle', 'lore_tooltip_fixture', cases,
'Item lore tooltip lines: dark purple italic, child colours, explicit non-italic, a line with no text of its own,'
' plain-string children and packed colours, and tooltip_display',
' plain-string children and packed colours, and tooltip_display; every named and packed colour, every style flag'
' explicit and inherited, nesting four levels deep, sibling strings and objects, empty texts, ten-line lore,'
' non-ASCII text and the hidden_components/hide_tooltip combinations',
sources=[
lab.ROOT / 'crates/horizon-client/src/item_tooltip.rs',
lab.ROOT / 'crates/horizon-items/src/item_data.rs',
lab.ROOT / 'crates/horizon-client-core/src/text.rs',
lab.ROOT / 'crates/horizon-client-core/src/component.rs',
],
expected_lines=len(CASES))
expected_lines=len(corpus()))
+28 -12
View File
@@ -17,17 +17,33 @@ except ImportError:
NAME = 'lunge-motion-parity'
# server_dir and generate_world write these server.properties.
locator.PROPERTIES = dict(locator.PROPERTIES, gamemode='survival')
SCRIPT = [
# The jump ends on the ground: the join's position said otherwise, and a server's copy goes by what it is told.
('setup', ['cmd Alice give @s minecraft:netherite_spear[enchantments={lunge:3}]', 'arc Alice -1']),
('ground', ['stab Alice']),
('same-tick', ['arc Alice 0']),
('rising', ['arc Alice 3']),
('falling', ['arc Alice 8']),
locator.PROPERTIES = dict(locator.PROPERTIES, gamemode='survival', difficulty='peaceful')
# Exercise the lowest and an intermediate tier/level as well as the original maximum.
# The extra tiers jab standing: repeating every jump phase drifts Alice far enough
# from the spawn that vanilla's own real-time steps occasionally miss the jab, and
# the original maximum keeps all four phases (the same distance as before).
PHASES = [('ground', ['stab Alice']), ('same-tick', ['arc Alice 0']), ('rising', ['arc Alice 3']),
('falling', ['arc Alice 8'])]
GROUND = [PHASES[0]]
SPEARS = [('wooden_spear', 1, GROUND), ('iron_spear', 2, GROUND), ('netherite_spear', 3, PHASES)]
def script():
# Peaceful: the flat world's slimes would otherwise hit Alice while the
# script is idle before the first command (and kill her), adding motions.
steps = [('setup', ['arc Alice -1'])]
for spear, level, phases in SPEARS:
steps.append(('setup', ['cmd Alice clear @s',
f'cmd Alice give @s minecraft:{spear}[enchantments={{lunge:{level}}}]']))
for phase, actions in phases:
steps.append((f'{spear}-{level}-{phase}', list(actions)))
# jumpFromGround gives a sprinting server copy 0.2 forward too.
('sprinting', ['sprint Alice', 'arc Alice 3']),
]
steps.append(('sprinting', ['sprint Alice', 'arc Alice 3']))
return steps
SCRIPT = script()
def shown(lines):
@@ -38,13 +54,13 @@ def shown(lines):
def check(vanilla, vanilla_all):
steps = {line.split()[1] for line in vanilla}
missing = {f'step={step}' for step, _ in SCRIPT[1:]} - steps
missing = {f'step={step}' for step, _ in SCRIPT if step != 'setup'} - steps
return f'vanilla sent no motion in {sorted(missing)}' if missing else None
def main():
lines = locator.one_player(NAME, SCRIPT, shown, check, "A spear's Lunge standing and at three points of a jump "
'on a dedicated server: the motion the player is sent.', step_seconds=2.0)
'on a dedicated server: motion for wooden Lunge I, iron Lunge II and netherite Lunge III.', step_seconds=2.0)
print(f'lunge motion: {len(lines)} lines identical')