Conversation
Update test fixtures to match current CueSpecs schema.
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Fixture patchingRemoving field-level defaults from The fixtures were patched with the script below, then round-tripped through pooltool's own import msgpack
from pathlib import Path
from pooltool.system.datatypes import System
DEFAULTS = {
"brand": "Pooltool",
"M": 0.567,
"length": 1.4732,
"tip_radius": 0.0106045,
"shaft_radius_at_tip": 0.0065,
"shaft_radius_at_butt": 0.02,
"end_mass": 0.170097 / 30,
}
EXPECTED_KEYS = set(DEFAULTS.keys())
def patch_specs(specs: dict) -> bool:
changed = False
for k in list(specs.keys()):
if k not in EXPECTED_KEYS:
del specs[k]
changed = True
for k, v in DEFAULTS.items():
if k not in specs:
specs[k] = v
changed = True
return changed
def patch_fixture(path: Path) -> bool:
with open(path, "rb") as f:
data = msgpack.unpackb(f.read(), raw=False)
changed = patch_specs(data["cue"]["specs"])
if "events" in data:
for event in data["events"]:
if "agents" in event:
for agent in event["agents"]:
if isinstance(agent, dict):
for state_key in ("initial", "final"):
state = agent.get(state_key)
if isinstance(state, dict) and "specs" in state:
changed |= patch_specs(state["specs"])
if changed:
with open(path, "wb") as f:
f.write(msgpack.packb(data, use_bin_type=True))
return changed
tests_dir = Path("tests")
fixtures = sorted(tests_dir.rglob("*.msgpack"))
for p in fixtures:
patched = patch_fixture(p)
status = "Patched" if patched else "OK"
print(f"{status}: {p.relative_to(tests_dir)}")
print("\nRound-tripping through pooltool serializer...")
for p in fixtures:
s = System.load(p)
s.save(p)
print(f"Re-saved: {p.relative_to(tests_dir)}") |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #283 +/- ##
==========================================
+ Coverage 46.23% 46.36% +0.13%
==========================================
Files 144 144
Lines 10287 10315 +28
==========================================
+ Hits 4756 4783 +27
- Misses 5531 5532 +1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
pooltool/objects/cue/datatypes.py
Outdated
| return CueSpecs() | ||
| return CueSpecs( | ||
| brand="Pooltool", | ||
| M=0.567, |
There was a problem hiding this comment.
My snooker que params as example:
M=0.478
length=1.475
shaft_radius_at_tip=0.0049
shaft_radius_at_butt=0.0124
I'm not sure what end_mass means. How to measure it?
There was a problem hiding this comment.
Thanks!
It's kind of an abstract concept. It's defined in here though: https://drdavepoolinfo.com/technical_proofs/new/TP_A-31.pdf
There was a problem hiding this comment.
https://drdavepoolinfo.com/technical_proofs/new/TP_A-31.pdf
From Claude:
The document uses a ball mass of 6 oz (about 170 g) and then works with mass ratios (m_b/m_e) that imply a range of end mass values.
From the plots on page 5, the end mass axis runs from roughly 5 to 15 grams. More specifically, the bounds used are m_b/50 on the low end and m_b/10 on the high end, which works out to about 3.4 g to 17 g.
The example calculations on page 6 give two representative cases:
- High-squirt cue (like a break cue): mass ratio of 15, meaning an end mass of about 11.3 g
- Low-squirt cue (a low-deflection playing shaft): mass ratio of 40, meaning an end mass of about 4.25 g
So the practical range for real cues appears to be roughly 4–12 grams — a surprisingly small amount of mass governing how much the cue ball deflects sideways.
Given this, I think it makes sense to replace 0.170097 / 30 (pool ball's mass over 30) with 0.140 / 30 (snooker ball's mass over 30).
There was a problem hiding this comment.
Do you have a number for the tip radius or should I leave it as 0.0106045?
|
The lint and test CI failures are unrelated to this PR — both failed because the Panda3D buildbot server ( |
This PR adds game-specific cue sticks, starting with a snooker cue.
CueSpecsrefactorCueSpecs.default(),CueSpecs.snooker()) in favor of thePrebuiltCueSpecsenum +CUE_SPECSdict pattern, mirroringPrebuiltBallParams/BALL_PARAMS.CueSpecs.default(game_type)andCueSpecs.prebuilt(name)classmethods.POOL_GENERIC,SNOOKER_GENERIC,BILLIARD_GENERIC(billiard currently copies pool values).Cue model support
model_name: str | NonetoCue, following the same pattern asBall.ballsetandTable.model_descr— a rendering identifier on the game object, with path resolution in the renderer.CUE_MODELSdict maps eachPrebuiltCueSpecsto a model directory name.models/cue/into subdirectories (cue/,cue_snooker/) so each cue model has its own directory.CueRender.init_model()resolves the model fromCue.model_name.Snooker cue model
models/cue/cue_snooker/cue.glb(new 3D model).Game type wiring
Cue.from_game_type()now sets bothspecsandmodel_namefrom the prebuilt mapping, so snooker games get the snooker cue automatically.Acknowledgements
Huge thanks to @alrusdi for creating the beautiful snooker cue model. It worked out of the box and looks great. Thanks!