summaryrefslogtreecommitdiffhomepage
path: root/sig/jolt.rbs
blob: 1bb73f68fe2f190e926443f3ccd2f17d15a250ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
# Jolt Physics Ruby API signatures (hand-written from docs/API_SPEC_JOLT.md).
# Mirrors mrbgems/jolt/mrblib/jolt.rb (public API) + the low-level C primitives
# in mrbgems/jolt/src/jolt_bindings.c (the Jolt::World#_* and Jolt._* methods
# the sugar wraps). Vectors accept Array[Numeric] or Rl::Vector3/Vector4 and are
# returned as Rl::Vector3/Vector4 when raylib is present (the documented contract).

# A 3-component vector: a plain Array of numerics [x, y, z] or an Rl::Vector3.
type vec3 = Array[Numeric] | Rl::Vector3

# A quaternion / 4-component vector: [x, y, z, w] or an Rl::Vector4.
type quat = Array[Numeric] | Rl::Vector4

module Jolt
  # Motion types (Integer constants). A body's collision layer is derived from
  # its motion type (static -> STATIC layer, else MOVING layer).
  STATIC: Integer
  KINEMATIC: Integer
  DYNAMIC: Integer

  # --- shape factories (module functions) ---
  # Full dimensions, NOT half-extents (box divides by 2 internally).
  def self.box: (Numeric width, Numeric height, Numeric depth) -> Jolt::Shape
  def self.sphere: (Numeric radius) -> Jolt::Shape
  # half_height = half the cylindrical section (capsule/cylinder).
  def self.capsule: (Numeric half_height, Numeric radius) -> Jolt::Shape
  def self.cylinder: (Numeric half_height, Numeric radius) -> Jolt::Shape
  # Convex hull from points: Array of [x,y,z] triplets OR a flat [x,y,z,...] Array.
  def self.convex_hull: (Array[Array[Numeric] | Numeric] points) -> Jolt::Shape
  # Triangle mesh (STATIC bodies only): Array of [x,y,z] triples or flat; 3 verts/tri.
  def self.mesh: (Array[Array[Numeric] | Numeric] vertices) -> Jolt::Shape

  # --- vector coercion helpers (internal; in => Array[Float], out => Rl type) ---
  def self.v3: (vec3 v) -> Array[Float]
  def self.v4: (quat v) -> Array[Float]
  # Whether raylib (Rl::Vector3/4) is available for output coercion (memoized).
  def self.rl?: () -> bool
  # Wrap a 3/4-float Array into Rl::Vector3/4 when raylib is present, else return it.
  def self.out3: (Array[Numeric] a) -> (Rl::Vector3 | Array[Numeric])
  def self.out4: (Array[Numeric] a) -> (Rl::Vector4 | Array[Numeric])

  # --- low-level shape primitives (jolt_bindings.c; take half-extents) ---
  def self._box: (Float hx, Float hy, Float hz) -> Jolt::Shape
  def self._sphere: (Float r) -> Jolt::Shape
  def self._capsule: (Float half_height, Float r) -> Jolt::Shape
  def self._cylinder: (Float half_height, Float r) -> Jolt::Shape
  def self._convex_hull: (Array[Numeric] points) -> Jolt::Shape
  def self._mesh: (Array[Numeric] vertices) -> Jolt::Shape
end

# A reusable collision volume (box/sphere/capsule/cylinder/convex_hull/mesh).
# Reference-counted in Jolt; the body holds a ref. Opaque data object.
class Jolt::Shape
end

class Jolt::World
  def initialize: (?gravity: vec3, ?max_bodies: Integer) -> void

  # --- simulation ---
  def gravity=: (vec3 v) -> vec3
  # Advance the simulation. `collision_steps` = sub-steps per call. Returns self.
  def step: (?Float dt, ?collision_steps: Integer) -> Jolt::World
  alias update step
  def optimize_broad_phase: () -> Jolt::World

  # --- bodies ---
  # Create + add a body. `shape` required; all others have defaults.
  # `motion`: Jolt::STATIC/KINEMATIC/DYNAMIC. `mass`: nil = density-derived.
  # `velocity`/`user_data`/`mass` default to nil. Returns the new Body.
  def body: (
    shape: Jolt::Shape,
    ?position: vec3,
    ?rotation: quat,
    ?motion: Integer,
    ?restitution: Float,
    ?friction: Float,
    ?activate: bool,
    ?velocity: vec3?,
    ?user_data: Integer?,
    ?linear_damping: Float,
    ?angular_damping: Float,
    ?mass: Float?,
    ?ccd: bool,
    ?sensor: bool
  ) -> Jolt::Body
  alias add_body body

  # Bodies whose shape contains `point` (overlap query).
  def overlap_point: (vec3 point) -> Array[Jolt::Body]

  # Collisions that BEGAN this step (OnContactAdded only — not persisted, so small).
  def contacts: () -> Array[Jolt::Contact]
  # Collisions that ENDED this step (stopped touching). Pair with sensor bodies
  # for trigger leave events.
  def contacts_ended: () -> Array[Jolt::ContactEnd]

  # --- constraints / joints (the world retains each; call #remove to delete) ---
  # weld two bodies rigidly at their current relative transform.
  def weld: (Jolt::Body a, Jolt::Body b) -> Jolt::Constraint
  # point-to-point joint (free rotation about a world-space point).
  def ball_joint: (Jolt::Body a, Jolt::Body b, vec3 point) -> Jolt::Constraint
  # rope/rod between two world-space attach points within [min, max] metres.
  def distance_joint: (Jolt::Body a, Jolt::Body b, vec3 point_a, vec3 point_b, ?min: Float, ?max: Float?) -> Jolt::Constraint
  # hinge (door) about `axis` through world `point`; angle limits in DEGREES.
  def hinge: (Jolt::Body a, Jolt::Body b, vec3 point, vec3 axis, ?min_deg: Float, ?max_deg: Float) -> Jolt::Constraint
  # slider (piston) along `axis` through world `point`; limits in METRES.
  def slider: (Jolt::Body a, Jolt::Body b, vec3 point, vec3 axis, ?min: Float, ?max: Float) -> Jolt::Constraint
  # cone / swing limit about `axis` through world `point`; half-angle in DEGREES.
  def cone: (Jolt::Body a, Jolt::Body b, vec3 point, vec3 axis, ?half_angle_deg: Float) -> Jolt::Constraint

  # --- character controller + ragdoll ---
  # Kinematic player capsule (Jolt CharacterVirtual) with stair/slope handling.
  def character: (shape: Jolt::Shape, ?position: vec3, ?max_slope_deg: Float, ?mass: Float) -> Jolt::Character
  # Tree of dynamic bodies wired with swing-twist joints. `parts` listed
  # PARENTS BEFORE CHILDREN (skeleton order); each is a Hash (see API_SPEC_JOLT.md §4b).
  def ragdoll: (parts: Array[Hash[Symbol, untyped]], ?user_data: Integer) -> Jolt::Ragdoll

  # --- queries ---
  # Cast a ray (direction is the full ray vector). nil if nothing is hit.
  def raycast: (vec3 origin, vec3 direction) -> Jolt::RayHit?

  # --- internal retain/forget (the world owns its joints/ragdolls; see #initialize) ---
  def _retain_joint: (Jolt::Constraint c) -> Jolt::Constraint
  def _forget_joint: (Jolt::Constraint c) -> Jolt::Constraint?
  def _forget_ragdoll: (Jolt::Ragdoll r) -> Jolt::Ragdoll?

  # --- low-level C primitives (jolt_bindings.c) ---
  def _setup: (Float gx, Float gy, Float gz, Integer max_bodies) -> Jolt::World
  def _step: (Float dt, Integer collision_steps) -> Jolt::World
  def _optimize: () -> Jolt::World
  def _set_gravity: (Float x, Float y, Float z) -> Jolt::World
  # -> body id (Integer). 17-arg format "offfffffiffbfffbb" (see jolt-binding.md).
  def _add_body: (
    Jolt::Shape shape,
    Float px, Float py, Float pz,
    Float qx, Float qy, Float qz, Float qw,
    Integer motion,
    Float restitution, Float friction,
    bool activate,
    Float linear_damping, Float angular_damping, Float mass,
    bool ccd, bool sensor
  ) -> Integer
  def _remove_body: (Integer id) -> Jolt::World
  def _position: (Integer id) -> Array[Float]
  def _com_position: (Integer id) -> Array[Float]
  def _rotation: (Integer id) -> Array[Float]
  def _set_transform: (Integer id, Float px, Float py, Float pz, Float qx, Float qy, Float qz, Float qw, bool activate) -> Jolt::World
  def _linear_velocity: (Integer id) -> Array[Float]
  def _set_linear_velocity: (Integer id, Float x, Float y, Float z) -> Jolt::World
  def _angular_velocity: (Integer id) -> Array[Float]
  def _set_angular_velocity: (Integer id, Float x, Float y, Float z) -> Jolt::World
  def _add_force: (Integer id, Float x, Float y, Float z) -> Jolt::World
  def _add_impulse: (Integer id, Float x, Float y, Float z) -> Jolt::World
  def _add_torque: (Integer id, Float x, Float y, Float z) -> Jolt::World
  def _active?: (Integer id) -> bool
  def _activate: (Integer id) -> Jolt::World
  def _deactivate: (Integer id) -> Jolt::World
  # -> [body_id, fraction, hx,hy,hz, nx,ny,nz] | nil
  def _raycast: (Float ox, Float oy, Float oz, Float dx, Float dy, Float dz) -> Array[untyped]?
  # -> Array of [idA, idB, px,py,pz, nx,ny,nz]
  def _contacts: () -> Array[Array[untyped]]
  # -> Array of [idA, idB]
  def _contacts_ended: () -> Array[[Integer, Integer]]
  # -> Array of body ids whose shape contains the point
  def _overlap_point: (Float x, Float y, Float z) -> Array[Integer]
  def _set_sensor: (Integer id, bool v) -> Jolt::World
  def _set_ccd: (Integer id, bool v) -> Jolt::World
  def _fixed: (Integer a, Integer b) -> Jolt::Constraint
  def _point: (Integer a, Integer b, Float px, Float py, Float pz) -> Jolt::Constraint
  def _distance: (Integer a, Integer b, Float ax, Float ay, Float az, Float bx, Float by, Float bz, Float min, Float max) -> Jolt::Constraint
  def _hinge: (Integer a, Integer b, Float px, Float py, Float pz, Float ax, Float ay, Float az, Float min, Float max) -> Jolt::Constraint
  def _slider: (Integer a, Integer b, Float px, Float py, Float pz, Float ax, Float ay, Float az, Float min, Float max) -> Jolt::Constraint
  def _cone: (Integer a, Integer b, Float px, Float py, Float pz, Float ax, Float ay, Float az, Float half) -> Jolt::Constraint
  def _user_data: (Integer id) -> Integer
  def _set_user_data: (Integer id, Integer v) -> Jolt::World
  def _motion_type: (Integer id) -> Integer
  def _set_motion_type: (Integer id, Integer mt, bool activate) -> Jolt::World
  def _friction: (Integer id) -> Float
  def _set_friction: (Integer id, Float v) -> Jolt::World
  def _restitution: (Integer id) -> Float
  def _set_restitution: (Integer id, Float v) -> Jolt::World
  def _gravity_factor: (Integer id) -> Float
  def _set_gravity_factor: (Integer id, Float v) -> Jolt::World
  def _character: (Jolt::Shape shape, Float px, Float py, Float pz, Float slope_deg, Float mass) -> Jolt::Character
  def _ragdoll: (Array[Array[untyped]] parts, Integer user_data) -> Jolt::Ragdoll
end

# A rigid body: a body id bound to its world. Created by World#body (not
# constructed directly by game code).
class Jolt::Body
  attr_reader id: Integer
  attr_reader world: Jolt::World

  def initialize: (Jolt::World world, Integer id) -> void
  def to_i: () -> Integer
  alias to_int to_i

  def position: () -> Rl::Vector3
  def position=: (vec3 v) -> vec3
  def center_of_mass: () -> Rl::Vector3
  def rotation: () -> Rl::Vector4
  def set_transform: (position: vec3, ?rotation: quat?, ?activate: bool) -> Jolt::Body

  def linear_velocity: () -> Rl::Vector3
  def linear_velocity=: (vec3 v) -> vec3
  def angular_velocity: () -> Rl::Vector3
  def angular_velocity=: (vec3 v) -> vec3

  # Chainable: apply a force/impulse/torque (world-space vector) to the body.
  def apply_force: (vec3 v) -> Jolt::Body
  def apply_impulse: (vec3 v) -> Jolt::Body
  def apply_torque: (vec3 v) -> Jolt::Body

  def active?: () -> bool
  def activate: () -> Jolt::Body
  def deactivate: () -> Jolt::Body
  def remove: () -> void

  # 64-bit tag (e.g. a flecs entity id) for collision lookup.
  def user_data: () -> Integer
  def user_data=: (Integer v) -> Integer

  def motion_type: () -> Integer
  def motion_type=: (Integer mt) -> Integer
  def set_motion_type: (Integer mt, ?activate: bool) -> Jolt::Body

  # tunable properties (get + set)
  def friction: () -> Float
  def friction=: (Float v) -> Float
  def restitution: () -> Float
  def restitution=: (Float v) -> Float
  def gravity_factor: () -> Float
  def gravity_factor=: (Float v) -> Float
  # sensor: detects overlaps (contacts/contacts_ended) without a physical response.
  def sensor=: (bool v) -> bool
  # continuous collision detection (linear cast) — fast bodies vs thin walls.
  def ccd=: (bool v) -> bool

  def ==: (untyped other) -> bool
  def inspect: () -> String
end

# Result of World#raycast (nil if nothing was hit).
class Jolt::RayHit
  attr_reader body_id: Integer
  attr_reader fraction: Float
  attr_reader point: Rl::Vector3
  attr_reader normal: Rl::Vector3

  def body: () -> Jolt::Body
end

# A constraint/joint (World#weld/ball_joint/distance_joint/hinge/slider/cone).
# The world retains it; you don't need to hold the handle to keep the joint alive.
class Jolt::Constraint
  # detach + destroy now (also done on GC). Chainable.
  def remove: () -> Jolt::Constraint
  def _remove: () -> Jolt::Constraint
end

# A collision that began this step (from World#contacts).
class Jolt::Contact
  attr_reader body_a_id: Integer
  attr_reader body_b_id: Integer
  attr_reader point: Rl::Vector3
  attr_reader normal: Rl::Vector3

  def body_a: () -> Jolt::Body
  def body_b: () -> Jolt::Body
  # is a given body/id in this contact?
  def involves?: (Jolt::Body | Integer x) -> bool
  # the *other* body in the contact.
  def other: (Jolt::Body | Integer x) -> Jolt::Body
end

# A collision that ENDED this step (from World#contacts_ended). No point/normal.
class Jolt::ContactEnd
  attr_reader body_a_id: Integer
  attr_reader body_b_id: Integer

  def body_a: () -> Jolt::Body
  def body_b: () -> Jolt::Body
  def involves?: (Jolt::Body | Integer x) -> bool
  def other: (Jolt::Body | Integer x) -> Jolt::Body
end

# Kinematic character controller (Jolt CharacterVirtual). Not a rigid body — you
# set its velocity each frame (applying gravity/jump yourself) and call #update,
# which moves and slides it along the world, stepping stairs and handling slopes.
class Jolt::Character
  GROUND: Hash[Integer, Symbol]

  def update: (?Float dt) -> Jolt::Character
  def position: () -> Rl::Vector3
  def position=: (vec3 v) -> vec3
  def velocity: () -> Rl::Vector3
  def velocity=: (vec3 v) -> vec3

  # :on_ground | :on_steep | :not_supported | :in_air
  def ground_state: () -> Symbol
  def on_ground?: () -> bool
  def supported?: () -> bool
  def ground_normal: () -> Rl::Vector3

  # velocity of the surface underfoot (moving platform / elevator); zero if airborne.
  def ground_velocity: () -> Rl::Vector3
  # the body the character stands on, or nil when airborne.
  def ground_body: () -> Jolt::Body?

  # like #update, but first ADDS ground_velocity so a KINEMATIC platform carries
  # the player. Only STATIC/KINEMATIC ground is inherited (dynamic ground ignored).
  def ride: (?Float dt) -> Jolt::Character

  # max force (N) exerted on dynamic bodies it walks into (raise above 100 N default).
  def max_strength: () -> Float
  def max_strength=: (Float v) -> Float
  # effective mass vs. dynamic bodies (still kinematic to gravity). Setter only.
  def mass=: (Float v) -> Float

  # --- low-level C primitives (jolt_bindings.c) ---
  def _update: (Float dt) -> Jolt::Character
  def _position: () -> Array[Float]
  def _set_position: (Float x, Float y, Float z) -> Jolt::Character
  def _velocity: () -> Array[Float]
  def _set_velocity: (Float x, Float y, Float z) -> Jolt::Character
  def _ground_state: () -> Integer
  def _ground_normal: () -> Array[Float]
  def _supported?: () -> bool
  def _ground_velocity: () -> Array[Float]
  def _ground_body_id: () -> Integer
  def _max_strength: () -> Float
  def _set_max_strength: (Float v) -> Jolt::Character
  def _set_mass: (Float v) -> Jolt::Character
end

# A ragdoll: a tree of dynamic bodies wired with swing-twist joints (from
# World#ragdoll). Each body is a normal Jolt::Body — read position/rotation to
# render, apply impulses to fling it around.
class Jolt::Ragdoll
  # Array<Jolt::Body>, one per part, in skeleton order (memoized).
  def bodies: () -> Array[Jolt::Body]
  def body_count: () -> Integer
  def []: (Integer i) -> Jolt::Body
  def activate: () -> Jolt::Ragdoll
  # take it out of the world (also on GC). Chainable.
  def remove: () -> Jolt::Ragdoll

  # --- low-level C primitives (jolt_bindings.c) ---
  def _body_count: () -> Integer
  def _body_id: (Integer i) -> Integer
  def _activate: () -> Jolt::Ragdoll
  def _remove: () -> Jolt::Ragdoll
end