Skip to content

Raycast python layer (collision raycast foundation)#1030

Closed
sloppynacho wants to merge 11 commits into
apoguita:mainfrom
sloppynacho:raycastpy
Closed

Raycast python layer (collision raycast foundation)#1030
sloppynacho wants to merge 11 commits into
apoguita:mainfrom
sloppynacho:raycastpy

Conversation

@sloppynacho

@sloppynacho sloppynacho commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds the Python layer of the collision-raycast foundation: an ergonomic,
typed Map.Raycast API over the native PyMap bridge, with all geometry math
in Python
(the native side is a thin raw bridge — paired C++ change lives on
the Raycastcpp branch of the C++ repo). Enemy/agent detection is intentionally
kept out of the library foundation.

What's included

  • Map.Raycast (Py4GWCoreLib/Map.py) — new nested class beside Map.Pathing:
    • Cast(start, end) — combined terrain + walkable-prop (engine returns a point).
    • CastTerrain(start, end) — terrain only (scales the native fraction by seg_len).
    • CastInteractive(start, end) — interactive-prop meshes (doors/gates/gadgets).
    • HasLos(start, end, terrain=, props=) — nearest-block combine; .blocked is the LoS answer.
    • GetProps() / GetPropGeometry(prop_id) — prop enumeration + world-space collision mesh.
    • Returns typed RaycastHit / PropHit / PropInfo; not @frame_cache'd.
  • raycast_math.py (Py4GWCoreLib/native_src/internals/) — pure, DLL-free math
    helper (normalize, segment length, blocked decision, hit reconstruction, prop-mesh
    v*M) + the result NamedTuples. Unit-testable without the game running.
  • __init__.py — surfaces the native module (import PyMap + rebind).
  • stubs/PyMap.pyi — type stub for the thinned raw native signatures.
  • Raycaster Tester widget (Widgets/Coding/Debug/Guild Wars/) — renamed from
    LoS Tester; consumes Map.Raycast.*; cone/enemy detection stays widget-side;
    cone rays configurable up to 200.

Design notes

  • C++ is a faithful RAW bridge (engine intersect + live-memory walk only); every
    derived calculation lives in Python, so behavior is tunable without a rebuild.
  • CastTerrain corrects a pre-existing bug: the bound terrain kernel returns a
    parametric fraction [0,1], not world units — now scaled by seg_len so the
    hit lands at the wall, not the player's feet.
  • Availability is explicit: a probe that couldn't run is distinct from "clear LoS"
    (source='unavailable' / n_scanned == -1), so callers never read a failed
    probe as line of sight.

Test plan

  • raycast_math unit-tested during development (27 cases: normalize, hit
    reconstruction, blocked decision, v*M, nearest-block combine) — pass on
    Python 3.13 (32-bit), no DLL needed.
  • All touched modules ast.parse clean.
  • In-game parity via the Raycaster Tester widget: terrain/prop/cone behavior
    matches the pre-refactor LoS Tester; terrain block marker lands on the wall.

Notes

  • Breaking native change — requires the matching thinned Py4GW.dll from the
    C++ Raycastcpp branch. The Python wrapper and the rebuilt DLL must ship together.

…dow collapsed

An indentation regression left the "Follow Publish" section (thresholds,
unstuck knobs, dirty_runtime_cfg check) outside the `if ImGui.Begin(...)`
block. When the Follow Formations window was collapsed, Begin returned
False, skipping `dirty_runtime_cfg = False`, but the dedented
`if dirty_runtime_cfg:` still ran — raising UnboundLocalError every frame.

Re-indent the block back inside Begin and restore the "Show Flagging
Window" checkbox as a sibling of the dirty check (it was accidentally
nested under it, only rendering on frames where a setting changed)
  feat: add Map.Raycast python layer (collision raycast foundation)

  Python side of the collision-raycast foundation: surfaces the thinned native
  PyMap bridge as an ergonomic, typed Map.Raycast API, with ALL geometry math in
  Python (the native side returns raw engine numbers).

  - Py4GWCoreLib/Map.py: new nested Map.Raycast class beside Map.Pathing, with
    point->point primitives Cast / CastTerrain / CastInteractive / HasLos plus
    GetProps / GetPropGeometry. Returns typed RaycastHit / PropHit / PropInfo; not
    @frame_cache'd (results vary by start/end). CastTerrain scales the native
    terrain hit fraction [0,1] by seg_len to world units.
  - Py4GWCoreLib/native_src/internals/raycast_math.py: pure, DLL-free math helper
    (segment length, normalize, blocked decision, hit reconstruction, prop-mesh
    v*M transform) + frozen RaycastHit / PropHit / PropInfo result types.
  - Py4GWCoreLib/__init__.py: surface the native module (import PyMap + rebind),
    matching the PyAgent / PyPlayer precedent.
  - stubs/PyMap.pyi: type stub for the thinned raw native signatures.
  - Widgets/Coding/Debug/Guild Wars/Raycaster Tester.py: debug widget (renamed
    from LoS Tester) consuming Map.Raycast.*; cone/enemy detection stays widget
    side; cone rays configurable up to 200.

  Pairs with the native thinning on the Raycastcpp branch of the C++ repo. Enemy/
  agent detection is intentionally out of the library foundation.
@sloppynacho

Copy link
Copy Markdown
Contributor Author

Superseded by #1031. This PR accidentally bundled 3 unrelated commits (Bugfix Agents, Reverse change, UnboundLocalError fix) because the branch was cut from the fork's working branch instead of a clean upstream/main base. #1031 is the raycast-only change (5 files) off upstream/main.

@sloppynacho sloppynacho deleted the raycastpy branch June 16, 2026 23:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant