Debugging and Reject Reasons
First determine whether registration, admission or movement inside an existing relationship failed.
A public-function error is separate from a rejected hit candidate. If jolt_penetrator_tip returns undefined or a setter returns false, read jolt_get_error_message(). If the Tip exists, inspect its info, reject and all relationships after the physics update.
Text and geometry debug#
// Enable once.
jolt_debug_enable(true);
// Draw GUI:
jolt_penetration_debug_text(16, 16);
// Existing 3D Draw pass:
jolt_debug_draw(JOLT_DEBUG_SHAPES | JOLT_DEBUG_PENETRATION);jolt_penetration_debug_text(x=16,y=16) prints Tip/body IDs, enabled, reject, state, relationship count, target, has_entered, capture_source and depth. The geometry flag draws the Tip, entry point and channel axis/limit. Debug does not add forces or decide capture.
Complete reject-reason table#
These names correspond to the numeric native reject enum. The GML wrapper returns a number; it does not define a public JoltPenetrationReject enum. Do not confuse these values with JoltPenetrationState.
| Code | Name | What to check |
|---|---|---|
| 0 | None | No current rejection; not itself an entry event. |
| 1 | NotPenetrable | The target is not enabled for penetration. |
| 2 | MaskMismatch | mask and category_bits share no bit. |
| 3 | AngleRejected | Actual impact angle exceeds max_angle. |
| 4 | TipTooFar | No suitable nearby hit in the search; normal in free space. |
| 5 | OffAxis | Geometry did not satisfy axis entry. |
| 6 | LateralVelocity | Excessive incompatible lateral motion. |
| 7 | AngularVelocity | Incoming relative spin or the allowed motion budget. |
| 8 | AlreadyOccupied | The Tip reached its capacity or already has this target. Read relationships first. |
| 9 | PairNotCollidable | Sensor, layer or group rules for the pair. |
| 10 | UnsupportedShape | Unsupported collision shape. |
| 11 | UnsupportedMotion | The penetrator must be Dynamic; the target must not be Kinematic. |
| 12 | IncompatibleConstraint | Another user constraint attached to the penetrator. |
| 13 | CapacityFull | Tip, relationship or candidate-buffer capacity. |
| 14 | DeepOverlap | Initial intrusion beyond capture_overlap, the depth limit or an invalid ray start inside the target. |
| 15 | InvalidConfig | Invalid settings; check ranges and the error channel. |
| 16 | CommitFailed | Relationship creation did not complete; inspect rollbacks and body validity. |
| 17 | MovingOutward | Motion is not inward along both the surface and positive axis. |
| 18 | InvalidHandle | Stale Tip, body or world. |
| 19 | RearmPending | Insufficient geometric clearance after extraction. |
| 20 | CaptureSpeed | A positive max_capture_axial_speed is below the incoming speed. |
| 21 | IncompatibleChannel | Axis incompatible with an existing channel on the same body. |
| 22 | AwaitingContact | Waiting for acceptable proximity/conditions. Does not by itself prove an intent exists. |
| 23 | NoAxisSurface | The Tip-axis ray did not verify a finite target surface. |
| 24 | ContactRegion | Invalid front region, finite-surface/normal mismatch or another blocking overlap. |
Troubleshooting sequence#
- Tip creation fails: check local surface placement, a nonzero axis, supported Dynamic shape and parameter ranges.
- Tip exists but never enters: check capture_model, target enabled, mask, layer, current angle and relative motion.
- A relationship exists but is Captured: wait for actual nonnegative signed_depth; do not confuse this with registration failure.
- The tool captures but does not move inward: inspect forward_force, mass, impact energy and max_depth.
- Another hit fails: inspect RearmPending and whole-body clearance. Check that you are not treating an old relationship as current.
Metrics#
var metrics = jolt_penetration_metrics();
if (is_struct(metrics)) {
show_debug_message("Relationships: " + string(metrics.relationships));
show_debug_message("Candidate drops: " + string(metrics.candidate_drops));
show_debug_message("Event drops: " + string(metrics.event_drops));
}| Fields | Meaning |
|---|---|
| schema | Structure version, currently 1. |
| tips / relationships | Current live counts. |
| tip_capacity / relationship_capacity / event_capacity / event_count | Capacities 128 / 32 / 256 and current event-queue occupancy. |
| candidates / probes / valid_probes | Cumulative candidate and geometry-evaluation counts, not unique-hit counts. |
| commits / rollbacks / candidate_drops / event_drops | Created connections, rolled-back creation attempts, capacity drops and lost events. |
| contact_queries / contact_captures / primed_cancels | Contact queries, contact-assisted captures and cancellations before actual entry. contact_captures is not the total of all model 2 captures. |
| pre_update_us / probe_us / relationship_update_us / clearance_us / physics_us / contact_us | Timing diagnostics in µs, populated with native profiling enabled. They may remain 0 by default; the public penetration API has no profiling switch. |
Counters belong to the world and accumulate during its lifetime; compare two samples to measure an interval. Getters only read diagnostics. Metrics do not identify the exact first cause of every failed impact; record configuration and trajectory when reproducing a problem.
Verified operation contracts#
These contracts distinguish units, return values, errors and lifetime according to the current implementation. Check results: false, 0 and undefined can mean different things for different methods.
| Symbol / owner | Signature | Operation contract |
|---|---|---|
| jolt_penetration_debug_text | jolt_penetration_debug_text(x=16,y=16) | Draws diagnostic text at x/y, default 16/16. Call in the appropriate Draw context; not history or a getter. |
| jolt_penetration_metrics | jolt_penetration_metrics() | Current schema:1 events/metrics snapshot of the managed world, undefined on invalid world/transport; not a physics mutation command. |