sonolus.py 0.3.1__py3-none-any.whl → 0.3.3__py3-none-any.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.

Potentially problematic release.


This version of sonolus.py might be problematic. Click here for more details.

Files changed (36) hide show
  1. sonolus/backend/finalize.py +16 -4
  2. sonolus/backend/node.py +13 -5
  3. sonolus/backend/optimize/allocate.py +41 -4
  4. sonolus/backend/optimize/flow.py +24 -7
  5. sonolus/backend/optimize/optimize.py +2 -9
  6. sonolus/backend/utils.py +6 -1
  7. sonolus/backend/visitor.py +72 -23
  8. sonolus/build/cli.py +6 -1
  9. sonolus/build/engine.py +1 -1
  10. sonolus/script/archetype.py +52 -24
  11. sonolus/script/array.py +20 -8
  12. sonolus/script/array_like.py +30 -3
  13. sonolus/script/containers.py +27 -7
  14. sonolus/script/debug.py +66 -8
  15. sonolus/script/globals.py +17 -0
  16. sonolus/script/internal/builtin_impls.py +12 -8
  17. sonolus/script/internal/context.py +55 -1
  18. sonolus/script/internal/range.py +25 -2
  19. sonolus/script/internal/simulation_context.py +131 -0
  20. sonolus/script/internal/tuple_impl.py +18 -11
  21. sonolus/script/interval.py +60 -2
  22. sonolus/script/iterator.py +3 -2
  23. sonolus/script/num.py +11 -2
  24. sonolus/script/options.py +24 -1
  25. sonolus/script/quad.py +41 -3
  26. sonolus/script/record.py +24 -3
  27. sonolus/script/runtime.py +411 -0
  28. sonolus/script/stream.py +133 -16
  29. sonolus/script/transform.py +291 -2
  30. sonolus/script/values.py +9 -3
  31. sonolus/script/vec.py +14 -2
  32. {sonolus_py-0.3.1.dist-info → sonolus_py-0.3.3.dist-info}/METADATA +1 -1
  33. {sonolus_py-0.3.1.dist-info → sonolus_py-0.3.3.dist-info}/RECORD +36 -35
  34. {sonolus_py-0.3.1.dist-info → sonolus_py-0.3.3.dist-info}/WHEEL +0 -0
  35. {sonolus_py-0.3.1.dist-info → sonolus_py-0.3.3.dist-info}/entry_points.txt +0 -0
  36. {sonolus_py-0.3.1.dist-info → sonolus_py-0.3.3.dist-info}/licenses/LICENSE +0 -0
sonolus/script/runtime.py CHANGED
@@ -259,6 +259,382 @@ class _TutorialRuntimeUi:
259
259
  instruction: BasicRuntimeUiLayout
260
260
 
261
261
 
262
+ class UiLayout[T](Record):
263
+ """The layout of a UI element."""
264
+
265
+ _underlying: T
266
+
267
+ def update(
268
+ self,
269
+ anchor: Vec2 | None = None,
270
+ pivot: Vec2 | None = None,
271
+ dimensions: Vec2 | None = None,
272
+ rotation: float | None = None,
273
+ alpha: float | None = None,
274
+ horizontal_align: HorizontalAlign | None = None,
275
+ background: bool | None = None,
276
+ ):
277
+ """Update the layout properties if it's available in the current mode and do nothing otherwise."""
278
+ match self._underlying:
279
+ case RuntimeUiLayout():
280
+ self._underlying.update(
281
+ anchor=anchor,
282
+ pivot=pivot,
283
+ dimensions=dimensions,
284
+ rotation=rotation,
285
+ alpha=alpha,
286
+ horizontal_align=horizontal_align,
287
+ background=background,
288
+ )
289
+ case BasicRuntimeUiLayout():
290
+ self._underlying.update(
291
+ anchor=anchor,
292
+ pivot=pivot,
293
+ dimensions=dimensions,
294
+ rotation=rotation,
295
+ alpha=alpha,
296
+ background=background,
297
+ )
298
+ case _:
299
+ pass # do nothing
300
+
301
+ @property
302
+ def is_available(self) -> bool:
303
+ """Check if the layout is available in the current mode."""
304
+ return self._underlying is not None
305
+
306
+
307
+ class UiConfig[T](Record):
308
+ """The user configuration for a UI element."""
309
+
310
+ _underlying: T
311
+
312
+ @property
313
+ def scale(self) -> float:
314
+ """The scale of the UI element."""
315
+ match self._underlying:
316
+ case RuntimeUiConfig():
317
+ return self._underlying.scale
318
+ case _:
319
+ return 1.0 # Default scale if not available
320
+
321
+ @property
322
+ def alpha(self) -> float:
323
+ """The alpha (opacity) of the UI element."""
324
+ match self._underlying:
325
+ case RuntimeUiConfig():
326
+ return self._underlying.alpha
327
+ case _:
328
+ return 1.0 # Default alpha if not available
329
+
330
+ @property
331
+ def is_available(self) -> bool:
332
+ """Check if the config is available in the current mode."""
333
+ return self._underlying is not None
334
+
335
+
336
+ class RuntimeUi(Record):
337
+ """Holds the layouts for different UI elements across all modes."""
338
+
339
+ @property
340
+ @meta_fn
341
+ def menu(self) -> UiLayout:
342
+ """The configuration for the menu UI element.
343
+
344
+ Available in play, watch, preview, and tutorial mode.
345
+ """
346
+ match ctx().global_state.mode:
347
+ case Mode.PLAY:
348
+ return UiLayout(_PlayRuntimeUi.menu)
349
+ case Mode.WATCH:
350
+ return UiLayout(_WatchRuntimeUi.menu)
351
+ case Mode.PREVIEW:
352
+ return UiLayout(_PreviewRuntimeUi.menu)
353
+ case Mode.TUTORIAL:
354
+ return UiLayout(_TutorialRuntimeUi.menu)
355
+ case _:
356
+ raise RuntimeError("Unsupported mode for menu UI layout")
357
+
358
+ @property
359
+ @meta_fn
360
+ def menu_config(self) -> UiConfig:
361
+ """The configuration for the menu UI element.
362
+
363
+ Available in play, watch, preview, and tutorial mode.
364
+ """
365
+ match ctx().global_state.mode:
366
+ case Mode.PLAY:
367
+ return UiConfig(_PlayRuntimeUiConfigs.menu)
368
+ case Mode.WATCH:
369
+ return UiConfig(_WatchRuntimeUiConfigs.menu)
370
+ case Mode.PREVIEW:
371
+ return UiConfig(_PreviewRuntimeUiConfigs.menu)
372
+ case Mode.TUTORIAL:
373
+ return UiConfig(_TutorialRuntimeUiConfigs.menu)
374
+ case _:
375
+ raise RuntimeError("Unsupported mode for menu UI configuration")
376
+
377
+ @property
378
+ @meta_fn
379
+ def judgment(self) -> UiLayout:
380
+ """The configuration for the judgment UI element.
381
+
382
+ Available in play and watch mode.
383
+ """
384
+ match ctx().global_state.mode:
385
+ case Mode.PLAY:
386
+ return UiLayout(_PlayRuntimeUi.judgment)
387
+ case Mode.WATCH:
388
+ return UiLayout(_WatchRuntimeUi.judgment)
389
+ case _:
390
+ return UiLayout(None)
391
+
392
+ @property
393
+ @meta_fn
394
+ def judgment_config(self) -> UiConfig:
395
+ """The configuration for the judgment UI element.
396
+
397
+ Available in play and watch mode.
398
+ """
399
+ match ctx().global_state.mode:
400
+ case Mode.PLAY:
401
+ return UiConfig(_PlayRuntimeUiConfigs.judgment)
402
+ case Mode.WATCH:
403
+ return UiConfig(_WatchRuntimeUiConfigs.judgment)
404
+ case _:
405
+ return UiConfig(None)
406
+
407
+ @property
408
+ @meta_fn
409
+ def combo_value(self) -> UiLayout:
410
+ """The configuration for the combo value UI element.
411
+
412
+ Available in play and watch mode.
413
+ """
414
+ match ctx().global_state.mode:
415
+ case Mode.PLAY:
416
+ return UiLayout(_PlayRuntimeUi.combo_value)
417
+ case Mode.WATCH:
418
+ return UiLayout(_WatchRuntimeUi.combo_value)
419
+ case _:
420
+ return UiLayout(None)
421
+
422
+ @property
423
+ @meta_fn
424
+ def combo_text(self) -> UiLayout:
425
+ """The configuration for the combo text UI element.
426
+
427
+ Available in play and watch mode.
428
+ """
429
+ match ctx().global_state.mode:
430
+ case Mode.PLAY:
431
+ return UiLayout(_PlayRuntimeUi.combo_text)
432
+ case Mode.WATCH:
433
+ return UiLayout(_WatchRuntimeUi.combo_text)
434
+ case _:
435
+ return UiLayout(None)
436
+
437
+ @property
438
+ @meta_fn
439
+ def combo_config(self) -> UiConfig:
440
+ """The configuration for the combo UI element.
441
+
442
+ Available in play and watch mode.
443
+ """
444
+ match ctx().global_state.mode:
445
+ case Mode.PLAY:
446
+ return UiConfig(_PlayRuntimeUiConfigs.combo)
447
+ case Mode.WATCH:
448
+ return UiConfig(_WatchRuntimeUiConfigs.combo)
449
+ case _:
450
+ return UiConfig(None)
451
+
452
+ @property
453
+ @meta_fn
454
+ def primary_metric_bar(self) -> UiLayout:
455
+ """The configuration for the primary metric bar UI element.
456
+
457
+ Available in play and watch mode.
458
+ """
459
+ match ctx().global_state.mode:
460
+ case Mode.PLAY:
461
+ return UiLayout(_PlayRuntimeUi.primary_metric_bar)
462
+ case Mode.WATCH:
463
+ return UiLayout(_WatchRuntimeUi.primary_metric_bar)
464
+ case _:
465
+ return UiLayout(None)
466
+
467
+ @property
468
+ @meta_fn
469
+ def primary_metric_value(self) -> UiLayout:
470
+ """The configuration for the primary metric value UI element.
471
+
472
+ Available in play and watch mode.
473
+ """
474
+ match ctx().global_state.mode:
475
+ case Mode.PLAY:
476
+ return UiLayout(_PlayRuntimeUi.primary_metric_value)
477
+ case Mode.WATCH:
478
+ return UiLayout(_WatchRuntimeUi.primary_metric_value)
479
+ case _:
480
+ return UiLayout(None)
481
+
482
+ @property
483
+ @meta_fn
484
+ def primary_metric_config(self) -> UiConfig:
485
+ """The configuration for the primary metric UI element.
486
+
487
+ Available in play and watch mode.
488
+ """
489
+ match ctx().global_state.mode:
490
+ case Mode.PLAY:
491
+ return UiConfig(_PlayRuntimeUiConfigs.primary_metric)
492
+ case Mode.WATCH:
493
+ return UiConfig(_WatchRuntimeUiConfigs.primary_metric)
494
+ case _:
495
+ return UiConfig(None)
496
+
497
+ @property
498
+ @meta_fn
499
+ def secondary_metric_bar(self) -> UiLayout:
500
+ """The configuration for the secondary metric bar UI element.
501
+
502
+ Available in play and watch mode.
503
+ """
504
+ match ctx().global_state.mode:
505
+ case Mode.PLAY:
506
+ return UiLayout(_PlayRuntimeUi.secondary_metric_bar)
507
+ case Mode.WATCH:
508
+ return UiLayout(_WatchRuntimeUi.secondary_metric_bar)
509
+ case _:
510
+ return UiLayout(None)
511
+
512
+ @property
513
+ @meta_fn
514
+ def secondary_metric_value(self) -> UiLayout:
515
+ """The configuration for the secondary metric value UI element.
516
+
517
+ Available in play and watch mode.
518
+ """
519
+ match ctx().global_state.mode:
520
+ case Mode.PLAY:
521
+ return UiLayout(_PlayRuntimeUi.secondary_metric_value)
522
+ case Mode.WATCH:
523
+ return UiLayout(_WatchRuntimeUi.secondary_metric_value)
524
+ case _:
525
+ return UiLayout(None)
526
+
527
+ @property
528
+ @meta_fn
529
+ def secondary_metric_config(self) -> UiConfig:
530
+ """The configuration for the secondary metric UI element.
531
+
532
+ Available in play and watch mode.
533
+ """
534
+ match ctx().global_state.mode:
535
+ case Mode.PLAY:
536
+ return UiConfig(_PlayRuntimeUiConfigs.secondary_metric)
537
+ case Mode.WATCH:
538
+ return UiConfig(_WatchRuntimeUiConfigs.secondary_metric)
539
+ case _:
540
+ return UiConfig(None)
541
+
542
+ @property
543
+ @meta_fn
544
+ def progress(self) -> UiLayout:
545
+ """The configuration for the progress UI element.
546
+
547
+ Available in watch and preview mode.
548
+ """
549
+ match ctx().global_state.mode:
550
+ case Mode.WATCH:
551
+ return UiLayout(_WatchRuntimeUi.progress)
552
+ case Mode.PREVIEW:
553
+ return UiLayout(_PreviewRuntimeUi.progress)
554
+ case _:
555
+ return UiLayout(None)
556
+
557
+ @property
558
+ @meta_fn
559
+ def progress_config(self) -> UiConfig:
560
+ """The configuration for the progress UI element.
561
+
562
+ Available in watch and preview mode.
563
+ """
564
+ match ctx().global_state.mode:
565
+ case Mode.WATCH:
566
+ return UiConfig(_WatchRuntimeUiConfigs.progress)
567
+ case Mode.PREVIEW:
568
+ return UiConfig(_PreviewRuntimeUiConfigs.progress)
569
+ case _:
570
+ return UiConfig(None)
571
+
572
+ @property
573
+ @meta_fn
574
+ def previous(self) -> UiLayout:
575
+ """The configuration for the previous navigation UI element.
576
+
577
+ Available in tutorial mode.
578
+ """
579
+ match ctx().global_state.mode:
580
+ case Mode.TUTORIAL:
581
+ return UiLayout(_TutorialRuntimeUi.previous)
582
+ case _:
583
+ return UiLayout(None)
584
+
585
+ @property
586
+ @meta_fn
587
+ def next(self) -> UiLayout:
588
+ """The configuration for the next navigation UI element.
589
+
590
+ Available in tutorial mode.
591
+ """
592
+ match ctx().global_state.mode:
593
+ case Mode.TUTORIAL:
594
+ return UiLayout(_TutorialRuntimeUi.next)
595
+ case _:
596
+ return UiLayout(None)
597
+
598
+ @property
599
+ @meta_fn
600
+ def navigation_config(self) -> UiConfig:
601
+ """The configuration for the navigation UI element.
602
+
603
+ Available in tutorial mode.
604
+ """
605
+ match ctx().global_state.mode:
606
+ case Mode.TUTORIAL:
607
+ return UiConfig(_TutorialRuntimeUiConfigs.navigation)
608
+ case _:
609
+ return UiConfig(None)
610
+
611
+ @property
612
+ @meta_fn
613
+ def instruction(self) -> UiLayout:
614
+ """The configuration for the instruction UI element.
615
+
616
+ Available in tutorial mode.
617
+ """
618
+ match ctx().global_state.mode:
619
+ case Mode.TUTORIAL:
620
+ return UiLayout(_TutorialRuntimeUi.instruction)
621
+ case _:
622
+ return UiLayout(None)
623
+
624
+ @property
625
+ @meta_fn
626
+ def instruction_config(self) -> UiConfig:
627
+ """The configuration for the instruction UI element.
628
+
629
+ Available in tutorial mode.
630
+ """
631
+ match ctx().global_state.mode:
632
+ case Mode.TUTORIAL:
633
+ return UiConfig(_TutorialRuntimeUiConfigs.instruction)
634
+ case _:
635
+ return UiConfig(None)
636
+
637
+
262
638
  class Touch(Record):
263
639
  """Data of a touch event."""
264
640
 
@@ -612,6 +988,25 @@ def time() -> float:
612
988
  return 0
613
989
 
614
990
 
991
+ @meta_fn
992
+ def offset_adjusted_time() -> float:
993
+ """Get the current time of the game adjusted by the input offset.
994
+
995
+ Returns 0 in preview mode and tutorial mode.
996
+ """
997
+ if not ctx():
998
+ return 0
999
+ match ctx().global_state.mode:
1000
+ case Mode.PLAY:
1001
+ return _PlayRuntimeUpdate.time - _PlayRuntimeEnvironment.input_offset
1002
+ case Mode.WATCH:
1003
+ return _WatchRuntimeUpdate.time - _WatchRuntimeEnvironment.input_offset
1004
+ case Mode.TUTORIAL:
1005
+ return _TutorialRuntimeUpdate.time
1006
+ case _:
1007
+ return 0
1008
+
1009
+
615
1010
  @meta_fn
616
1011
  def delta_time() -> float:
617
1012
  """Get the time elapsed since the last frame.
@@ -650,6 +1045,15 @@ def scaled_time() -> float:
650
1045
  return 0
651
1046
 
652
1047
 
1048
+ @meta_fn
1049
+ def prev_time() -> float:
1050
+ """Get the time of the previous frame.
1051
+
1052
+ Returns 0 in preview mode.
1053
+ """
1054
+ return time() - delta_time()
1055
+
1056
+
653
1057
  @meta_fn
654
1058
  def touches() -> ArrayLike[Touch]:
655
1059
  """Get the current touches of the game."""
@@ -733,6 +1137,13 @@ preview_ui_configs = _PreviewRuntimeUiConfigs
733
1137
  tutorial_ui = _TutorialRuntimeUi
734
1138
  tutorial_ui_configs = _TutorialRuntimeUiConfigs
735
1139
 
1140
+ _runtime_ui = RuntimeUi()
1141
+
1142
+
1143
+ def runtime_ui() -> RuntimeUi:
1144
+ """Get the runtime UI configuration."""
1145
+ return _runtime_ui
1146
+
736
1147
 
737
1148
  def canvas() -> _PreviewRuntimeCanvas:
738
1149
  """Get the preview canvas."""