hyperstellar 1.5.6__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hyperstellar/__init__.py +299 -0
- hyperstellar/__init__.pyi +1019 -0
- hyperstellar/_native/linux-x64/shaders/axis.frag +8 -0
- hyperstellar/_native/linux-x64/shaders/axis.vert +13 -0
- hyperstellar/_native/linux-x64/shaders/fragShader.frag +27 -0
- hyperstellar/_native/linux-x64/shaders/geoShader.geom +69 -0
- hyperstellar/_native/linux-x64/shaders/math.comp +2177 -0
- hyperstellar/_native/linux-x64/shaders/paint.comp +1214 -0
- hyperstellar/_native/linux-x64/shaders/quad.frag +26 -0
- hyperstellar/_native/linux-x64/shaders/quad.geom +149 -0
- hyperstellar/_native/linux-x64/shaders/quad.vert +39 -0
- hyperstellar/_native/linux-x64/shaders/vertexShader.vert +13 -0
- hyperstellar/_native/linux-x64/stellar.so +0 -0
- hyperstellar/_native/windows-x64/shaders/axis.frag +8 -0
- hyperstellar/_native/windows-x64/shaders/axis.vert +13 -0
- hyperstellar/_native/windows-x64/shaders/fragShader.frag +27 -0
- hyperstellar/_native/windows-x64/shaders/geoShader.geom +69 -0
- hyperstellar/_native/windows-x64/shaders/math.comp +2177 -0
- hyperstellar/_native/windows-x64/shaders/paint.comp +1214 -0
- hyperstellar/_native/windows-x64/shaders/quad.frag +26 -0
- hyperstellar/_native/windows-x64/shaders/quad.geom +149 -0
- hyperstellar/_native/windows-x64/shaders/quad.vert +39 -0
- hyperstellar/_native/windows-x64/shaders/vertexShader.vert +13 -0
- hyperstellar/_native/windows-x64/stellar.pyd +0 -0
- hyperstellar/debug.py +169 -0
- hyperstellar/jit.py +2010 -0
- hyperstellar/jit_linter.py +3 -0
- hyperstellar/py.typed +0 -0
- hyperstellar/shader.py +1356 -0
- hyperstellar/typed.py +152 -0
- hyperstellar-1.5.6.dist-info/METADATA +470 -0
- hyperstellar-1.5.6.dist-info/RECORD +35 -0
- hyperstellar-1.5.6.dist-info/WHEEL +5 -0
- hyperstellar-1.5.6.dist-info/licenses/LICENSE +24 -0
- hyperstellar-1.5.6.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,1019 @@
|
|
|
1
|
+
# Type stubs for hyperstellar package
|
|
2
|
+
import typing
|
|
3
|
+
from typing import Any, List, Dict, Optional, Union, Callable, ClassVar, Tuple, overload
|
|
4
|
+
|
|
5
|
+
# ============================================================================
|
|
6
|
+
# ENUMS
|
|
7
|
+
# ============================================================================
|
|
8
|
+
|
|
9
|
+
class SkinType:
|
|
10
|
+
"""Visual representation type for objects."""
|
|
11
|
+
CIRCLE: int
|
|
12
|
+
RECTANGLE: int
|
|
13
|
+
POLYGON: int
|
|
14
|
+
|
|
15
|
+
class CollisionShape:
|
|
16
|
+
"""Collision shape type for physics objects."""
|
|
17
|
+
NONE: int # No collision
|
|
18
|
+
CIRCLE: int # Circular collision shape
|
|
19
|
+
AABB: int # Axis-aligned bounding box
|
|
20
|
+
POLYGON: int # Polygon collision shape
|
|
21
|
+
|
|
22
|
+
class ConstraintType:
|
|
23
|
+
"""Type of physics constraint."""
|
|
24
|
+
DISTANCE: int # Distance constraint between objects
|
|
25
|
+
BOUNDARY: int # Boundary/box constraint
|
|
26
|
+
|
|
27
|
+
# ============================================================================
|
|
28
|
+
# DATA CLASSES
|
|
29
|
+
# ============================================================================
|
|
30
|
+
|
|
31
|
+
class ObjectState:
|
|
32
|
+
"""Complete state of a physics object.
|
|
33
|
+
|
|
34
|
+
Attributes:
|
|
35
|
+
x (float): X position
|
|
36
|
+
y (float): Y position
|
|
37
|
+
vx (float): X velocity
|
|
38
|
+
vy (float): Y velocity
|
|
39
|
+
mass (float): Mass of object
|
|
40
|
+
charge (float): Electric charge
|
|
41
|
+
rotation (float): Rotation angle in radians
|
|
42
|
+
angular_velocity (float): Angular velocity in rad/s
|
|
43
|
+
width (float): Width for rectangles
|
|
44
|
+
height (float): Height for rectangles
|
|
45
|
+
radius (float): Radius for circles/polygons
|
|
46
|
+
polygon_sides (int): Number of sides for polygons
|
|
47
|
+
skin_type (SkinType): Visual type
|
|
48
|
+
r,g,b,a (float): Color components (0.0-1.0)
|
|
49
|
+
"""
|
|
50
|
+
x: float
|
|
51
|
+
y: float
|
|
52
|
+
vx: float
|
|
53
|
+
vy: float
|
|
54
|
+
mass: float
|
|
55
|
+
charge: float
|
|
56
|
+
rotation: float
|
|
57
|
+
angular_velocity: float
|
|
58
|
+
width: float
|
|
59
|
+
height: float
|
|
60
|
+
radius: float
|
|
61
|
+
polygon_sides: int
|
|
62
|
+
skin_type: SkinType
|
|
63
|
+
r: float
|
|
64
|
+
g: float
|
|
65
|
+
b: float
|
|
66
|
+
a: float
|
|
67
|
+
|
|
68
|
+
def __init__(self) -> None: ...
|
|
69
|
+
def __repr__(self) -> str: ...
|
|
70
|
+
|
|
71
|
+
class CollisionConfig:
|
|
72
|
+
"""Collision configuration for an object.
|
|
73
|
+
|
|
74
|
+
Attributes:
|
|
75
|
+
enabled (bool): Whether collision detection is enabled
|
|
76
|
+
shape (CollisionShape): Collision shape type
|
|
77
|
+
restitution (float): Bounciness (0.0-1.0)
|
|
78
|
+
friction (float): Surface friction (0.0-1.0)
|
|
79
|
+
"""
|
|
80
|
+
enabled: bool
|
|
81
|
+
shape: CollisionShape
|
|
82
|
+
restitution: float
|
|
83
|
+
friction: float
|
|
84
|
+
|
|
85
|
+
def __init__(self) -> None: ...
|
|
86
|
+
def __repr__(self) -> str: ...
|
|
87
|
+
|
|
88
|
+
class KeyState:
|
|
89
|
+
"""Represents the state of a single keyboard key for the current frame.
|
|
90
|
+
|
|
91
|
+
Attributes:
|
|
92
|
+
pressed (bool): True if the key is currently held down.
|
|
93
|
+
released (bool): True if the key was just released this frame.
|
|
94
|
+
held (bool): Alias for pressed.
|
|
95
|
+
"""
|
|
96
|
+
@property
|
|
97
|
+
def pressed(self) -> bool: ...
|
|
98
|
+
@property
|
|
99
|
+
def released(self) -> bool: ...
|
|
100
|
+
@property
|
|
101
|
+
def held(self) -> bool: ...
|
|
102
|
+
def __repr__(self) -> str: ...
|
|
103
|
+
|
|
104
|
+
class KeyboardMonitor:
|
|
105
|
+
"""
|
|
106
|
+
Provides access to keyboard states via attributes or indexing.
|
|
107
|
+
|
|
108
|
+
Example:
|
|
109
|
+
if sim.keyboard.Z.pressed: ...
|
|
110
|
+
if sim.keyboard["Space"].released: ...
|
|
111
|
+
|
|
112
|
+
Supported key names include: A-Z, 0-9, Space, Shift, Control, Alt,
|
|
113
|
+
Escape, Enter, Tab, Backspace, Delete, Home, End, PageUp, PageDown,
|
|
114
|
+
Insert, Up, Down, Left, Right, F1-F12.
|
|
115
|
+
"""
|
|
116
|
+
def __init__(self, sim: "Simulation") -> None: ...
|
|
117
|
+
def __getattr__(self, name: str) -> KeyState: ...
|
|
118
|
+
def __getitem__(self, name: str) -> KeyState: ...
|
|
119
|
+
def get_key_state(self, key_name: str) -> KeyState:
|
|
120
|
+
"""Get the state of a specific key by name."""
|
|
121
|
+
...
|
|
122
|
+
|
|
123
|
+
class ObjectConfig:
|
|
124
|
+
"""Configuration for creating objects in batch mode.
|
|
125
|
+
|
|
126
|
+
Attributes:
|
|
127
|
+
x,y,vx,vy,mass,charge,rotation,angular_velocity: Same as ObjectState
|
|
128
|
+
skin (SkinType): Visual type
|
|
129
|
+
size (float): General size parameter
|
|
130
|
+
width,height (float): Dimensions for rectangles
|
|
131
|
+
r,g,b,a (float): Color
|
|
132
|
+
polygon_sides (int): Polygon sides
|
|
133
|
+
equation (str): Physics equation string
|
|
134
|
+
constraints (List[ConstraintConfig]): List of constraints
|
|
135
|
+
"""
|
|
136
|
+
x: float
|
|
137
|
+
y: float
|
|
138
|
+
vx: float
|
|
139
|
+
vy: float
|
|
140
|
+
mass: float
|
|
141
|
+
charge: float
|
|
142
|
+
rotation: float
|
|
143
|
+
angular_velocity: float
|
|
144
|
+
skin: SkinType
|
|
145
|
+
size: float
|
|
146
|
+
width: float
|
|
147
|
+
height: float
|
|
148
|
+
r: float
|
|
149
|
+
g: float
|
|
150
|
+
b: float
|
|
151
|
+
a: float
|
|
152
|
+
polygon_sides: int
|
|
153
|
+
equation: str
|
|
154
|
+
constraints: List["ConstraintConfig"]
|
|
155
|
+
|
|
156
|
+
def __init__(self) -> None: ...
|
|
157
|
+
def __repr__(self) -> str: ...
|
|
158
|
+
|
|
159
|
+
class ConstraintConfig:
|
|
160
|
+
"""Constraint configuration for batch mode.
|
|
161
|
+
|
|
162
|
+
Attributes:
|
|
163
|
+
type (ConstraintType): Constraint type (DISTANCE or BOUNDARY)
|
|
164
|
+
target (int): Target object ID
|
|
165
|
+
param1 (float): Distance: rest_length, Boundary: min_x, Angle: min_angle
|
|
166
|
+
param2 (float): Boundary: max_x, Angle: max_angle
|
|
167
|
+
param3 (float): Boundary: min_y
|
|
168
|
+
param4 (float): Boundary: max_y
|
|
169
|
+
"""
|
|
170
|
+
type: ConstraintType
|
|
171
|
+
target: int
|
|
172
|
+
param1: float
|
|
173
|
+
param2: float
|
|
174
|
+
param3: float
|
|
175
|
+
param4: float
|
|
176
|
+
|
|
177
|
+
def __init__(self) -> None: ...
|
|
178
|
+
|
|
179
|
+
class BatchConfig:
|
|
180
|
+
"""Configuration for batch simulations.
|
|
181
|
+
|
|
182
|
+
Attributes:
|
|
183
|
+
objects (list[ObjectConfig]): List of object configurations
|
|
184
|
+
duration (float): Simulation duration in seconds
|
|
185
|
+
dt (float): Time step per update
|
|
186
|
+
output_file (str): Optional output file path
|
|
187
|
+
"""
|
|
188
|
+
objects: List[ObjectConfig]
|
|
189
|
+
duration: float
|
|
190
|
+
dt: float
|
|
191
|
+
output_file: str
|
|
192
|
+
|
|
193
|
+
def __init__(self) -> None: ...
|
|
194
|
+
|
|
195
|
+
class BatchGetData:
|
|
196
|
+
"""Batch get data structure."""
|
|
197
|
+
x: float
|
|
198
|
+
y: float
|
|
199
|
+
vx: float
|
|
200
|
+
vy: float
|
|
201
|
+
mass: float
|
|
202
|
+
charge: float
|
|
203
|
+
rotation: float
|
|
204
|
+
angular_velocity: float
|
|
205
|
+
width: float
|
|
206
|
+
height: float
|
|
207
|
+
radius: float
|
|
208
|
+
polygon_sides: int
|
|
209
|
+
skin_type: int
|
|
210
|
+
r: float
|
|
211
|
+
g: float
|
|
212
|
+
b: float
|
|
213
|
+
a: float
|
|
214
|
+
|
|
215
|
+
def __init__(self) -> None: ...
|
|
216
|
+
|
|
217
|
+
class BatchUpdateData:
|
|
218
|
+
"""Batch update data structure."""
|
|
219
|
+
index: int
|
|
220
|
+
x: float
|
|
221
|
+
y: float
|
|
222
|
+
vx: float
|
|
223
|
+
vy: float
|
|
224
|
+
mass: float
|
|
225
|
+
charge: float
|
|
226
|
+
rotation: float
|
|
227
|
+
angular_velocity: float
|
|
228
|
+
size: float # radius for circle/polygon
|
|
229
|
+
width: float
|
|
230
|
+
height: float
|
|
231
|
+
r: float
|
|
232
|
+
g: float
|
|
233
|
+
b: float
|
|
234
|
+
a: float
|
|
235
|
+
polygon_sides: int
|
|
236
|
+
|
|
237
|
+
def __init__(self) -> None: ...
|
|
238
|
+
|
|
239
|
+
class DistanceConstraint:
|
|
240
|
+
"""Maintain distance between two objects.
|
|
241
|
+
|
|
242
|
+
Args:
|
|
243
|
+
target_object (int): ID of target object to maintain distance with
|
|
244
|
+
rest_length (float): Desired distance between objects
|
|
245
|
+
"""
|
|
246
|
+
target_object: int
|
|
247
|
+
rest_length: float
|
|
248
|
+
|
|
249
|
+
def __init__(self, target_object: int = 0, rest_length: float = 5.0) -> None: ...
|
|
250
|
+
def __repr__(self) -> str: ...
|
|
251
|
+
|
|
252
|
+
class BoundaryConstraint:
|
|
253
|
+
"""Keep object within a rectangular boundary.
|
|
254
|
+
|
|
255
|
+
Args:
|
|
256
|
+
min_x (float): Minimum X boundary
|
|
257
|
+
max_x (float): Maximum X boundary
|
|
258
|
+
min_y (float): Minimum Y boundary
|
|
259
|
+
max_y (float): Maximum Y boundary
|
|
260
|
+
"""
|
|
261
|
+
min_x: float
|
|
262
|
+
max_x: float
|
|
263
|
+
min_y: float
|
|
264
|
+
max_y: float
|
|
265
|
+
|
|
266
|
+
def __init__(self, min_x: float = -10.0, max_x: float = 10.0, min_y: float = -10.0, max_y: float = 10.0) -> None: ...
|
|
267
|
+
def __repr__(self) -> str: ...
|
|
268
|
+
|
|
269
|
+
# ============================================================================
|
|
270
|
+
# MAIN SIMULATION CLASS
|
|
271
|
+
# ============================================================================
|
|
272
|
+
|
|
273
|
+
class Simulation:
|
|
274
|
+
"""Main physics simulation class.
|
|
275
|
+
|
|
276
|
+
Provides real-time physics simulation with GPU acceleration.
|
|
277
|
+
Can run in headless mode (no window) or with OpenGL visualization.
|
|
278
|
+
"""
|
|
279
|
+
|
|
280
|
+
def __init__(self,
|
|
281
|
+
headless: bool = True,
|
|
282
|
+
width: int = 1280,
|
|
283
|
+
height: int = 720,
|
|
284
|
+
title: str = "Physics Simulation",
|
|
285
|
+
enable_grid: bool = True) -> None:
|
|
286
|
+
"""
|
|
287
|
+
Create a new simulation instance.
|
|
288
|
+
|
|
289
|
+
Args:
|
|
290
|
+
headless (bool): Run without graphical window. Default: True.
|
|
291
|
+
width (int): Window width in pixels. Default: 1280.
|
|
292
|
+
height (int): Window height in pixels. Default: 720.
|
|
293
|
+
title (str): Window title. Default: "Physics Simulation".
|
|
294
|
+
enable_grid (bool): Enable grid/axis rendering. Default: True.
|
|
295
|
+
|
|
296
|
+
Example:
|
|
297
|
+
>>> sim = Simulation(headless=True, enable_grid=False)
|
|
298
|
+
>>> sim = Simulation(width=1920, height=1080, title="My Simulation", enable_grid=True)
|
|
299
|
+
"""
|
|
300
|
+
...
|
|
301
|
+
|
|
302
|
+
# ========================================================================
|
|
303
|
+
# WINDOW MANAGEMENT
|
|
304
|
+
# ========================================================================
|
|
305
|
+
|
|
306
|
+
def render(self) -> None:
|
|
307
|
+
"""Render the current frame to the window (visual mode only)."""
|
|
308
|
+
...
|
|
309
|
+
|
|
310
|
+
def paint(self, arg: Union[str, int]) -> None:
|
|
311
|
+
"""
|
|
312
|
+
Unified paint method.
|
|
313
|
+
|
|
314
|
+
If arg is a string, it's treated as a DSL equation.
|
|
315
|
+
If arg is an int, it's treated as a JIT script ID (from register_script).
|
|
316
|
+
|
|
317
|
+
DSL equation variables: px, py, t, p[id].x etc.
|
|
318
|
+
Assign color.r, color.g, color.b.
|
|
319
|
+
"""
|
|
320
|
+
...
|
|
321
|
+
|
|
322
|
+
def set_paint_resolution(self, width: int, height: int) -> None:
|
|
323
|
+
"""Set internal resolution for paint shader (default = window size)."""
|
|
324
|
+
...
|
|
325
|
+
|
|
326
|
+
def process_input(self) -> None:
|
|
327
|
+
"""Process window input and camera controls (visual mode only)."""
|
|
328
|
+
...
|
|
329
|
+
|
|
330
|
+
def should_close(self) -> bool:
|
|
331
|
+
"""Check if window should close (visual mode only)."""
|
|
332
|
+
...
|
|
333
|
+
|
|
334
|
+
# ========================================================================
|
|
335
|
+
# GRID CONTROL
|
|
336
|
+
# ========================================================================
|
|
337
|
+
|
|
338
|
+
def set_grid_enabled(self, enabled: bool) -> None:
|
|
339
|
+
"""
|
|
340
|
+
Enable or disable grid/axis rendering.
|
|
341
|
+
|
|
342
|
+
Args:
|
|
343
|
+
enabled (bool): True to enable grid, False to disable
|
|
344
|
+
"""
|
|
345
|
+
...
|
|
346
|
+
|
|
347
|
+
def get_grid_enabled(self) -> bool:
|
|
348
|
+
"""
|
|
349
|
+
Check if grid/axis rendering is enabled.
|
|
350
|
+
|
|
351
|
+
Returns:
|
|
352
|
+
bool: True if grid is enabled, False otherwise
|
|
353
|
+
"""
|
|
354
|
+
...
|
|
355
|
+
|
|
356
|
+
# ========================================================================
|
|
357
|
+
# CORE SIMULATION
|
|
358
|
+
# ========================================================================
|
|
359
|
+
|
|
360
|
+
def update(self, dt: float = 0.016) -> None:
|
|
361
|
+
"""
|
|
362
|
+
Update physics simulation by dt seconds.
|
|
363
|
+
|
|
364
|
+
Args:
|
|
365
|
+
dt (float): Time step in seconds. Default: 0.016 (approx 60 FPS).
|
|
366
|
+
|
|
367
|
+
Example:
|
|
368
|
+
>>> sim.update(dt=0.01) # Update with 10ms time step
|
|
369
|
+
"""
|
|
370
|
+
...
|
|
371
|
+
|
|
372
|
+
def set_speed(self, speed: float) -> None:
|
|
373
|
+
"""
|
|
374
|
+
Set speed multiplier (1.0 = normal).
|
|
375
|
+
Higher values make simulation faster without affecting stability.
|
|
376
|
+
"""
|
|
377
|
+
...
|
|
378
|
+
|
|
379
|
+
def get_speed(self) -> float:
|
|
380
|
+
"""Get current speed multiplier."""
|
|
381
|
+
...
|
|
382
|
+
|
|
383
|
+
# ========================================================================
|
|
384
|
+
# OBJECT MANAGEMENT
|
|
385
|
+
# ========================================================================
|
|
386
|
+
|
|
387
|
+
def add_object(
|
|
388
|
+
self,
|
|
389
|
+
x: float = 0.0,
|
|
390
|
+
y: float = 0.0,
|
|
391
|
+
vx: float = 0.0,
|
|
392
|
+
vy: float = 0.0,
|
|
393
|
+
mass: float = 1.0,
|
|
394
|
+
charge: float = 0.0,
|
|
395
|
+
rotation: float = 0.0,
|
|
396
|
+
angular_velocity: float = 0.0,
|
|
397
|
+
skin: SkinType = SkinType.CIRCLE,
|
|
398
|
+
size: float = 0.3,
|
|
399
|
+
width: float = 0.5,
|
|
400
|
+
height: float = 0.3,
|
|
401
|
+
r: float = 1.0,
|
|
402
|
+
g: float = 1.0,
|
|
403
|
+
b: float = 1.0,
|
|
404
|
+
a: float = 1.0,
|
|
405
|
+
polygon_sides: int = 6
|
|
406
|
+
) -> int:
|
|
407
|
+
"""
|
|
408
|
+
Add an object with full property control.
|
|
409
|
+
|
|
410
|
+
Args:
|
|
411
|
+
x,y (float): Initial position
|
|
412
|
+
vx,vy (float): Initial velocity
|
|
413
|
+
mass (float): Object mass. Default: 1.0
|
|
414
|
+
charge (float): Electric charge. Default: 0.0
|
|
415
|
+
rotation (float): Initial rotation in radians. Default: 0.0
|
|
416
|
+
angular_velocity (float): Angular velocity in rad/s. Default: 0.0
|
|
417
|
+
skin (SkinType): Visual type. Default: CIRCLE
|
|
418
|
+
size (float): General size. Default: 0.3
|
|
419
|
+
width,height (float): Dimensions for rectangles. Default: 0.5, 0.3
|
|
420
|
+
r,g,b,a (float): Color (0.0-1.0). Default: white (1,1,1,1)
|
|
421
|
+
polygon_sides (int): Polygon sides. Default: 6
|
|
422
|
+
|
|
423
|
+
Returns:
|
|
424
|
+
int: Object ID for future reference
|
|
425
|
+
|
|
426
|
+
Example:
|
|
427
|
+
>>> obj_id = sim.add_object(x=10, y=5, mass=50, skin=SkinType.CIRCLE)
|
|
428
|
+
"""
|
|
429
|
+
...
|
|
430
|
+
|
|
431
|
+
# Overload for full update (all positional args)
|
|
432
|
+
@overload
|
|
433
|
+
def update_object(
|
|
434
|
+
self,
|
|
435
|
+
index: int,
|
|
436
|
+
x: float, y: float,
|
|
437
|
+
vx: float, vy: float,
|
|
438
|
+
mass: float, charge: float,
|
|
439
|
+
rotation: float, angular_velocity: float,
|
|
440
|
+
size: float,
|
|
441
|
+
width: float, height: float,
|
|
442
|
+
r: float, g: float, b: float, a: float,
|
|
443
|
+
polygon_sides: int = 0
|
|
444
|
+
) -> None: ...
|
|
445
|
+
|
|
446
|
+
# Overload for partial update with kwargs
|
|
447
|
+
@overload
|
|
448
|
+
def update_object(
|
|
449
|
+
self,
|
|
450
|
+
index: int,
|
|
451
|
+
*,
|
|
452
|
+
x: Optional[float] = None,
|
|
453
|
+
y: Optional[float] = None,
|
|
454
|
+
vx: Optional[float] = None,
|
|
455
|
+
vy: Optional[float] = None,
|
|
456
|
+
mass: Optional[float] = None,
|
|
457
|
+
charge: Optional[float] = None,
|
|
458
|
+
rotation: Optional[float] = None,
|
|
459
|
+
angular_velocity: Optional[float] = None,
|
|
460
|
+
size: Optional[float] = None,
|
|
461
|
+
width: Optional[float] = None,
|
|
462
|
+
height: Optional[float] = None,
|
|
463
|
+
r: Optional[float] = None,
|
|
464
|
+
g: Optional[float] = None,
|
|
465
|
+
b: Optional[float] = None,
|
|
466
|
+
a: Optional[float] = None,
|
|
467
|
+
polygon_sides: Optional[int] = None
|
|
468
|
+
) -> None: ...
|
|
469
|
+
|
|
470
|
+
def update_object(self, index: int, *args, **kwargs) -> None:
|
|
471
|
+
"""
|
|
472
|
+
Update all or partial properties of an existing object.
|
|
473
|
+
|
|
474
|
+
If called with all positional arguments, updates all properties.
|
|
475
|
+
If called with keyword arguments, only specified properties are updated.
|
|
476
|
+
|
|
477
|
+
Example:
|
|
478
|
+
# Full update
|
|
479
|
+
sim.update_object(0, 1.0, 2.0, 0.1, 0.2, 1.0, 0.0, 0.0, 0.0, 0.3, 0.5, 0.3, 1.0, 1.0, 1.0, 1.0)
|
|
480
|
+
# Partial update
|
|
481
|
+
sim.update_object(1, x=1.0, r=0.5)
|
|
482
|
+
"""
|
|
483
|
+
...
|
|
484
|
+
|
|
485
|
+
# ========================================================================
|
|
486
|
+
# BATCH OPERATIONS
|
|
487
|
+
# ========================================================================
|
|
488
|
+
|
|
489
|
+
def batch_get(self, indices: List[int]) -> List[BatchGetData]:
|
|
490
|
+
"""
|
|
491
|
+
Get properties for multiple objects at once.
|
|
492
|
+
|
|
493
|
+
Args:
|
|
494
|
+
indices (list[int]): List of object indices to fetch
|
|
495
|
+
|
|
496
|
+
Returns:
|
|
497
|
+
list: List of BatchGetData objects for each index
|
|
498
|
+
|
|
499
|
+
Example:
|
|
500
|
+
>>> states = sim.batch_get([0, 1, 2, 3])
|
|
501
|
+
>>> for state in states:
|
|
502
|
+
>>> print(f"x={state.x}, y={state.y}")
|
|
503
|
+
"""
|
|
504
|
+
...
|
|
505
|
+
|
|
506
|
+
def batch_update(self, updates: List[BatchUpdateData]) -> None:
|
|
507
|
+
"""
|
|
508
|
+
Update multiple objects at once.
|
|
509
|
+
|
|
510
|
+
Args:
|
|
511
|
+
updates (list[BatchUpdateData]): List of update data objects
|
|
512
|
+
|
|
513
|
+
Example:
|
|
514
|
+
>>> updates = [
|
|
515
|
+
>>> BatchUpdateData(index=0, x=1.0, y=2.0, ...),
|
|
516
|
+
>>> BatchUpdateData(index=1, x=3.0, y=4.0, ...)
|
|
517
|
+
>>> ]
|
|
518
|
+
>>> sim.batch_update(updates)
|
|
519
|
+
"""
|
|
520
|
+
...
|
|
521
|
+
|
|
522
|
+
def remove_object(self, index: int) -> None:
|
|
523
|
+
"""Remove an object by ID."""
|
|
524
|
+
...
|
|
525
|
+
|
|
526
|
+
def object_count(self) -> int:
|
|
527
|
+
"""Get number of objects in simulation."""
|
|
528
|
+
...
|
|
529
|
+
|
|
530
|
+
def get_object(self, index: int) -> ObjectState:
|
|
531
|
+
"""
|
|
532
|
+
Get complete object state.
|
|
533
|
+
|
|
534
|
+
Args:
|
|
535
|
+
index (int): Object ID
|
|
536
|
+
|
|
537
|
+
Returns:
|
|
538
|
+
ObjectState: Complete object state
|
|
539
|
+
"""
|
|
540
|
+
...
|
|
541
|
+
|
|
542
|
+
# ========================================================================
|
|
543
|
+
# CONVENIENCE METHODS
|
|
544
|
+
# ========================================================================
|
|
545
|
+
|
|
546
|
+
def set_rotation(self, index: int, rotation: float) -> None:
|
|
547
|
+
"""Set rotation angle in radians."""
|
|
548
|
+
...
|
|
549
|
+
|
|
550
|
+
def set_angular_velocity(self, index: int, angular_velocity: float) -> None:
|
|
551
|
+
"""Set angular velocity in rad/s."""
|
|
552
|
+
...
|
|
553
|
+
|
|
554
|
+
def set_dimensions(self, index: int, width: float, height: float) -> None:
|
|
555
|
+
"""Set width and height for rectangle objects."""
|
|
556
|
+
...
|
|
557
|
+
|
|
558
|
+
def set_radius(self, index: int, radius: float) -> None:
|
|
559
|
+
"""Set radius for circle/polygon objects."""
|
|
560
|
+
...
|
|
561
|
+
|
|
562
|
+
def get_rotation(self, index: int) -> float:
|
|
563
|
+
"""Get rotation angle in radians."""
|
|
564
|
+
...
|
|
565
|
+
|
|
566
|
+
def get_angular_velocity(self, index: int) -> float:
|
|
567
|
+
"""Get angular velocity in rad/s."""
|
|
568
|
+
...
|
|
569
|
+
|
|
570
|
+
# ========================================================================
|
|
571
|
+
# EQUATIONS AND SCRIPTS
|
|
572
|
+
# ========================================================================
|
|
573
|
+
|
|
574
|
+
def set_equation(self, object_index: int, equation_string: str) -> None:
|
|
575
|
+
"""
|
|
576
|
+
Set physics equation for object.
|
|
577
|
+
|
|
578
|
+
Args:
|
|
579
|
+
object_index (int): Object ID
|
|
580
|
+
equation_string (str): Physics equation
|
|
581
|
+
|
|
582
|
+
Equation syntax supports:
|
|
583
|
+
- Variables: x, y, vx, vy, mass, charge, time
|
|
584
|
+
- Object references: p[ID].x, p[ID].y, p[ID].mass
|
|
585
|
+
- Functions: sin, cos, tan, sqrt, exp, log
|
|
586
|
+
- Operators: +, -, *, /, ^ (power)
|
|
587
|
+
|
|
588
|
+
Example:
|
|
589
|
+
>>> sim.set_equation(0, "0.1*mass*(p[1].x - x)/distance^3")
|
|
590
|
+
"""
|
|
591
|
+
...
|
|
592
|
+
|
|
593
|
+
def register_script(self, source: str) -> int:
|
|
594
|
+
"""Compile a Python script (source) and return script ID."""
|
|
595
|
+
...
|
|
596
|
+
|
|
597
|
+
def set_script(self, object_index: int, script_id: int) -> None:
|
|
598
|
+
"""
|
|
599
|
+
Assign a JIT script to an object (use -1 to revert to default DSL).
|
|
600
|
+
"""
|
|
601
|
+
...
|
|
602
|
+
|
|
603
|
+
# ========================================================================
|
|
604
|
+
# CONSTRAINTS
|
|
605
|
+
# ========================================================================
|
|
606
|
+
|
|
607
|
+
def add_distance_constraint(self, object_index: int, constraint: DistanceConstraint) -> None:
|
|
608
|
+
"""Add distance constraint between objects."""
|
|
609
|
+
...
|
|
610
|
+
|
|
611
|
+
def add_boundary_constraint(self, object_index: int, constraint: BoundaryConstraint) -> None:
|
|
612
|
+
"""Add boundary constraint to object."""
|
|
613
|
+
...
|
|
614
|
+
|
|
615
|
+
def clear_constraints(self, object_index: int) -> None:
|
|
616
|
+
"""Clear all constraints from object."""
|
|
617
|
+
...
|
|
618
|
+
|
|
619
|
+
def clear_all_constraints(self) -> None:
|
|
620
|
+
"""Clear all constraints from all objects."""
|
|
621
|
+
...
|
|
622
|
+
|
|
623
|
+
# ========================================================================
|
|
624
|
+
# COLLISION SYSTEM
|
|
625
|
+
# ========================================================================
|
|
626
|
+
|
|
627
|
+
def set_collision_enabled(self, index: int, enabled: bool) -> None:
|
|
628
|
+
"""
|
|
629
|
+
Enable or disable collision detection for an object.
|
|
630
|
+
|
|
631
|
+
Args:
|
|
632
|
+
index (int): Object ID
|
|
633
|
+
enabled (bool): True to enable collisions, False to disable
|
|
634
|
+
|
|
635
|
+
Example:
|
|
636
|
+
>>> sim.set_collision_enabled(0, False) # Disable collisions for object 0
|
|
637
|
+
"""
|
|
638
|
+
...
|
|
639
|
+
|
|
640
|
+
def set_collision_shape(self, index: int, shape: CollisionShape) -> None:
|
|
641
|
+
"""
|
|
642
|
+
Set collision shape for an object.
|
|
643
|
+
|
|
644
|
+
Args:
|
|
645
|
+
index (int): Object ID
|
|
646
|
+
shape (CollisionShape): Collision shape type
|
|
647
|
+
|
|
648
|
+
Note: Shape is automatically set based on visual skin when adding objects.
|
|
649
|
+
|
|
650
|
+
Example:
|
|
651
|
+
>>> sim.set_collision_shape(0, CollisionShape.CIRCLE)
|
|
652
|
+
"""
|
|
653
|
+
...
|
|
654
|
+
|
|
655
|
+
def set_collision_properties(self, index: int, restitution: float, friction: float) -> None:
|
|
656
|
+
"""
|
|
657
|
+
Set collision physical properties.
|
|
658
|
+
|
|
659
|
+
Args:
|
|
660
|
+
index (int): Object ID
|
|
661
|
+
restitution (float): Bounciness (0.0-1.0)
|
|
662
|
+
0.0 = no bounce (inelastic collision)
|
|
663
|
+
1.0 = perfect bounce (elastic collision)
|
|
664
|
+
friction (float): Surface friction (0.0-1.0)
|
|
665
|
+
0.0 = frictionless (ice)
|
|
666
|
+
1.0 = maximum friction (rubber)
|
|
667
|
+
|
|
668
|
+
Example:
|
|
669
|
+
>>> sim.set_collision_properties(0, restitution=0.9, friction=0.1)
|
|
670
|
+
>>> # Makes object 0 very bouncy with low friction
|
|
671
|
+
"""
|
|
672
|
+
...
|
|
673
|
+
|
|
674
|
+
@overload
|
|
675
|
+
def set_collision(
|
|
676
|
+
self,
|
|
677
|
+
index: int,
|
|
678
|
+
*,
|
|
679
|
+
enabled: Optional[bool] = None,
|
|
680
|
+
shape: Optional[CollisionShape] = None,
|
|
681
|
+
restitution: Optional[float] = None,
|
|
682
|
+
friction: Optional[float] = None
|
|
683
|
+
) -> None: ...
|
|
684
|
+
|
|
685
|
+
def set_collision(self, index: int, **kwargs) -> None:
|
|
686
|
+
"""
|
|
687
|
+
Set collision properties for an object in a single call.
|
|
688
|
+
|
|
689
|
+
Args:
|
|
690
|
+
index (int): Object ID
|
|
691
|
+
enabled (bool, optional): Enable/disable collisions
|
|
692
|
+
shape (CollisionShape, optional): Collision shape type
|
|
693
|
+
restitution (float, optional): Bounciness (0.0-1.0)
|
|
694
|
+
friction (float, optional): Friction (0.0-1.0)
|
|
695
|
+
|
|
696
|
+
Example:
|
|
697
|
+
>>> sim.set_collision(0, shape=CollisionShape.CIRCLE, restitution=0.9, friction=0.1)
|
|
698
|
+
>>> sim.set_collision(1, enabled=False)
|
|
699
|
+
"""
|
|
700
|
+
...
|
|
701
|
+
|
|
702
|
+
def get_collision_config(self, index: int) -> CollisionConfig:
|
|
703
|
+
"""
|
|
704
|
+
Get collision configuration for an object.
|
|
705
|
+
|
|
706
|
+
Args:
|
|
707
|
+
index (int): Object ID
|
|
708
|
+
|
|
709
|
+
Returns:
|
|
710
|
+
CollisionConfig: Current collision settings
|
|
711
|
+
|
|
712
|
+
Example:
|
|
713
|
+
>>> config = sim.get_collision_config(0)
|
|
714
|
+
>>> print(f"Restitution: {config.restitution}")
|
|
715
|
+
"""
|
|
716
|
+
...
|
|
717
|
+
|
|
718
|
+
def enable_collision_between(self, obj1: int, obj2: int, enable: bool) -> None:
|
|
719
|
+
"""
|
|
720
|
+
Enable or disable collision detection between two specific objects.
|
|
721
|
+
|
|
722
|
+
Args:
|
|
723
|
+
obj1 (int): First object ID
|
|
724
|
+
obj2 (int): Second object ID
|
|
725
|
+
enable (bool): True to enable, False to disable
|
|
726
|
+
|
|
727
|
+
Useful for creating collision layers or groups.
|
|
728
|
+
|
|
729
|
+
Example:
|
|
730
|
+
>>> sim.enable_collision_between(0, 1, False)
|
|
731
|
+
>>> # Objects 0 and 1 will pass through each other
|
|
732
|
+
"""
|
|
733
|
+
...
|
|
734
|
+
|
|
735
|
+
def is_collision_enabled(self, index: int) -> bool:
|
|
736
|
+
"""
|
|
737
|
+
Check if collision detection is enabled for an object.
|
|
738
|
+
|
|
739
|
+
Args:
|
|
740
|
+
index (int): Object ID
|
|
741
|
+
|
|
742
|
+
Returns:
|
|
743
|
+
bool: True if collisions are enabled
|
|
744
|
+
"""
|
|
745
|
+
...
|
|
746
|
+
|
|
747
|
+
def set_collision_parameters(self, enable_warm_start: bool, max_contact_iterations: int) -> None:
|
|
748
|
+
"""
|
|
749
|
+
Set global collision parameters (warm start and iteration count).
|
|
750
|
+
|
|
751
|
+
Args:
|
|
752
|
+
enable_warm_start (bool): Enable warm starting for contacts
|
|
753
|
+
max_contact_iterations (int): Maximum iterations for contact resolution (1-20)
|
|
754
|
+
"""
|
|
755
|
+
...
|
|
756
|
+
|
|
757
|
+
def get_collision_parameters(self) -> Tuple[bool, int]:
|
|
758
|
+
"""
|
|
759
|
+
Get global collision parameters.
|
|
760
|
+
|
|
761
|
+
Returns:
|
|
762
|
+
tuple: (enable_warm_start, max_contact_iterations)
|
|
763
|
+
"""
|
|
764
|
+
...
|
|
765
|
+
|
|
766
|
+
# ========================================================================
|
|
767
|
+
# BATCH PROCESSING
|
|
768
|
+
# ========================================================================
|
|
769
|
+
|
|
770
|
+
def run_batch(
|
|
771
|
+
self,
|
|
772
|
+
configs: List[BatchConfig],
|
|
773
|
+
callback: Optional[Callable[[int, List[ObjectState]], None]] = None
|
|
774
|
+
) -> None:
|
|
775
|
+
"""
|
|
776
|
+
Run multiple simulations in batch mode.
|
|
777
|
+
|
|
778
|
+
Args:
|
|
779
|
+
configs (list[BatchConfig]): List of simulation configurations
|
|
780
|
+
callback (callable): Optional callback for progress/results
|
|
781
|
+
Called as: callback(batch_index, results)
|
|
782
|
+
|
|
783
|
+
Note: Only works in headless mode.
|
|
784
|
+
"""
|
|
785
|
+
...
|
|
786
|
+
|
|
787
|
+
# ========================================================================
|
|
788
|
+
# PARAMETERS
|
|
789
|
+
# ========================================================================
|
|
790
|
+
|
|
791
|
+
def set_parameter(self, name: str, value: float) -> None:
|
|
792
|
+
"""
|
|
793
|
+
Set global simulation parameter.
|
|
794
|
+
|
|
795
|
+
Args:
|
|
796
|
+
name (str): Parameter name
|
|
797
|
+
value (float): Parameter value
|
|
798
|
+
|
|
799
|
+
Available parameters:
|
|
800
|
+
- "gravity": Global gravity strength
|
|
801
|
+
- "damping": Velocity damping (0-1)
|
|
802
|
+
- "stiffness": Default constraint stiffness
|
|
803
|
+
"""
|
|
804
|
+
...
|
|
805
|
+
|
|
806
|
+
def get_parameter(self, name: str) -> float:
|
|
807
|
+
"""Get global parameter value by name."""
|
|
808
|
+
...
|
|
809
|
+
|
|
810
|
+
# ========================================================================
|
|
811
|
+
# SIMULATION CONTROL
|
|
812
|
+
# ========================================================================
|
|
813
|
+
|
|
814
|
+
def set_paused(self, paused: bool) -> None:
|
|
815
|
+
"""Pause or resume simulation."""
|
|
816
|
+
...
|
|
817
|
+
|
|
818
|
+
def is_paused(self) -> bool:
|
|
819
|
+
"""Check if simulation is paused."""
|
|
820
|
+
...
|
|
821
|
+
|
|
822
|
+
def update_shader_loading(self) -> None:
|
|
823
|
+
"""Update shader loading status."""
|
|
824
|
+
...
|
|
825
|
+
|
|
826
|
+
def are_all_shaders_ready(self) -> bool:
|
|
827
|
+
"""Check if all shaders are loaded."""
|
|
828
|
+
...
|
|
829
|
+
|
|
830
|
+
def get_shader_load_progress(self) -> float:
|
|
831
|
+
"""Get shader loading progress (0.0 to 1.0)."""
|
|
832
|
+
...
|
|
833
|
+
|
|
834
|
+
def get_shader_load_status(self) -> str:
|
|
835
|
+
"""Get current shader loading status message."""
|
|
836
|
+
...
|
|
837
|
+
|
|
838
|
+
def reset(self) -> None:
|
|
839
|
+
"""Reset simulation to initial state (keeps objects)."""
|
|
840
|
+
...
|
|
841
|
+
|
|
842
|
+
def cleanup(self) -> None:
|
|
843
|
+
"""Explicitly cleanup resources."""
|
|
844
|
+
...
|
|
845
|
+
|
|
846
|
+
# ========================================================================
|
|
847
|
+
# FILE I/O
|
|
848
|
+
# ========================================================================
|
|
849
|
+
|
|
850
|
+
def save_to_file(
|
|
851
|
+
self,
|
|
852
|
+
filename: str,
|
|
853
|
+
title: str = "",
|
|
854
|
+
author: str = "",
|
|
855
|
+
description: str = ""
|
|
856
|
+
) -> None:
|
|
857
|
+
"""
|
|
858
|
+
Save simulation state to .stellar file.
|
|
859
|
+
|
|
860
|
+
Args:
|
|
861
|
+
filename (str): Output file path
|
|
862
|
+
title (str): Simulation title
|
|
863
|
+
author (str): Author name
|
|
864
|
+
description (str): Simulation description
|
|
865
|
+
"""
|
|
866
|
+
...
|
|
867
|
+
|
|
868
|
+
def load_from_file(self, filename: str) -> None:
|
|
869
|
+
"""
|
|
870
|
+
Load simulation state from .stellar file.
|
|
871
|
+
|
|
872
|
+
Args:
|
|
873
|
+
filename (str): Input file path
|
|
874
|
+
"""
|
|
875
|
+
...
|
|
876
|
+
|
|
877
|
+
# ========================================================================
|
|
878
|
+
# KEYBOARD AND CAMERA
|
|
879
|
+
# ========================================================================
|
|
880
|
+
|
|
881
|
+
@property
|
|
882
|
+
def keyboard(self) -> KeyboardMonitor:
|
|
883
|
+
"""
|
|
884
|
+
Keyboard state monitor (e.g., sim.keyboard.Z.pressed, sim.keyboard.Space.released).
|
|
885
|
+
"""
|
|
886
|
+
...
|
|
887
|
+
|
|
888
|
+
def set_camera_position(self, x: float, y: float) -> None:
|
|
889
|
+
"""Set the camera position in world coordinates."""
|
|
890
|
+
...
|
|
891
|
+
|
|
892
|
+
def get_camera_position(self) -> Tuple[float, float]:
|
|
893
|
+
"""Return the current camera position as a tuple (x, y)."""
|
|
894
|
+
...
|
|
895
|
+
|
|
896
|
+
def set_camera_zoom(self, zoom: float) -> None:
|
|
897
|
+
"""Set the camera zoom level (1.0 = default)."""
|
|
898
|
+
...
|
|
899
|
+
|
|
900
|
+
def get_camera_zoom(self) -> float:
|
|
901
|
+
"""Return the current camera zoom level."""
|
|
902
|
+
...
|
|
903
|
+
|
|
904
|
+
# ========================================================================
|
|
905
|
+
# INPUT HELPERS
|
|
906
|
+
# ========================================================================
|
|
907
|
+
|
|
908
|
+
def default_input(self) -> None:
|
|
909
|
+
"""
|
|
910
|
+
Default WASD + Q/E zoom + ESC close camera controls.
|
|
911
|
+
Call this in your loop for standard behavior.
|
|
912
|
+
"""
|
|
913
|
+
...
|
|
914
|
+
|
|
915
|
+
def get_mouse_position(self) -> Tuple[float, float]:
|
|
916
|
+
"""
|
|
917
|
+
Returns the current mouse position in world coordinates.
|
|
918
|
+
"""
|
|
919
|
+
...
|
|
920
|
+
|
|
921
|
+
def get_mouse_delta(self) -> Tuple[float, float]:
|
|
922
|
+
"""
|
|
923
|
+
Returns the mouse movement delta (in pixels) since the last call.
|
|
924
|
+
"""
|
|
925
|
+
...
|
|
926
|
+
|
|
927
|
+
# ========================================================================
|
|
928
|
+
# PROPERTIES
|
|
929
|
+
# ========================================================================
|
|
930
|
+
|
|
931
|
+
@property
|
|
932
|
+
def is_headless(self) -> bool:
|
|
933
|
+
"""Check if simulation is running in headless mode."""
|
|
934
|
+
...
|
|
935
|
+
|
|
936
|
+
@property
|
|
937
|
+
def is_initialized(self) -> bool:
|
|
938
|
+
"""Check if simulation is fully initialized."""
|
|
939
|
+
...
|
|
940
|
+
|
|
941
|
+
# ========================================================================
|
|
942
|
+
# SCRATCHPAD
|
|
943
|
+
# ========================================================================
|
|
944
|
+
|
|
945
|
+
def create_scratchpad(self, size: int) -> int:
|
|
946
|
+
"""Create a scratchpad buffer with given number of floats."""
|
|
947
|
+
...
|
|
948
|
+
|
|
949
|
+
def destroy_scratchpad(self, id: int) -> None:
|
|
950
|
+
"""Destroy a scratchpad."""
|
|
951
|
+
...
|
|
952
|
+
|
|
953
|
+
def upload_scratchpad(self, id: int, data: List[float]) -> None:
|
|
954
|
+
"""Upload a list of floats to scratchpad."""
|
|
955
|
+
...
|
|
956
|
+
|
|
957
|
+
def map_scratchpad(self, id: int) -> List[float]:
|
|
958
|
+
"""Return a list of floats from scratchpad (CPU copy)."""
|
|
959
|
+
...
|
|
960
|
+
|
|
961
|
+
def scratchpad_size(self, id: int) -> int:
|
|
962
|
+
"""Get number of elements in scratchpad."""
|
|
963
|
+
...
|
|
964
|
+
|
|
965
|
+
def is_valid_scratchpad(self, id: int) -> bool:
|
|
966
|
+
"""Check if scratchpad ID is valid."""
|
|
967
|
+
...
|
|
968
|
+
|
|
969
|
+
# ========================================================================
|
|
970
|
+
# SIGNAL QUEUE
|
|
971
|
+
# ========================================================================
|
|
972
|
+
|
|
973
|
+
def set_signal_queue_capacity(self, capacity: int) -> None:
|
|
974
|
+
"""Set the maximum number of pending signals."""
|
|
975
|
+
...
|
|
976
|
+
|
|
977
|
+
def set_signal_queue_overflow_policy(self, policy: int) -> None:
|
|
978
|
+
"""Set overflow policy: 0=drop, 1=block."""
|
|
979
|
+
...
|
|
980
|
+
|
|
981
|
+
def clear_signal_queue(self) -> None:
|
|
982
|
+
"""Clear all pending signals."""
|
|
983
|
+
...
|
|
984
|
+
|
|
985
|
+
def get_signal_queue_count(self) -> int:
|
|
986
|
+
"""Get the number of pending signals."""
|
|
987
|
+
...
|
|
988
|
+
|
|
989
|
+
# ========================================================================
|
|
990
|
+
# AGENT DISPATCH
|
|
991
|
+
# ========================================================================
|
|
992
|
+
|
|
993
|
+
def dispatch_agent(self, agent_id: int, clear_after: bool = True) -> None:
|
|
994
|
+
"""
|
|
995
|
+
Dispatch a specific agent over all pending signals for that agent.
|
|
996
|
+
"""
|
|
997
|
+
...
|
|
998
|
+
|
|
999
|
+
def dispatch_all_agents(self, clear_after: bool = True) -> None:
|
|
1000
|
+
"""
|
|
1001
|
+
Dispatch all registered agents over pending signals
|
|
1002
|
+
(each agent processes its own).
|
|
1003
|
+
"""
|
|
1004
|
+
...
|
|
1005
|
+
|
|
1006
|
+
def register_agent(self, source: str) -> int:
|
|
1007
|
+
"""Compile an agent shader and return its ID."""
|
|
1008
|
+
...
|
|
1009
|
+
|
|
1010
|
+
def get_agent_ids(self) -> List[int]:
|
|
1011
|
+
"""Return a list of all registered agent IDs."""
|
|
1012
|
+
...
|
|
1013
|
+
|
|
1014
|
+
# ============================================================================
|
|
1015
|
+
# MODULE-LEVEL EXPORTS
|
|
1016
|
+
# ============================================================================
|
|
1017
|
+
|
|
1018
|
+
# Version information
|
|
1019
|
+
__version__: str
|