sonolus.py 0.1.3__py3-none-any.whl → 0.1.5__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.
- sonolus/backend/blocks.py +756 -756
- sonolus/backend/excepthook.py +37 -37
- sonolus/backend/finalize.py +77 -69
- sonolus/backend/interpret.py +7 -7
- sonolus/backend/ir.py +29 -3
- sonolus/backend/mode.py +24 -24
- sonolus/backend/node.py +40 -40
- sonolus/backend/ops.py +197 -197
- sonolus/backend/optimize/__init__.py +0 -0
- sonolus/backend/optimize/allocate.py +126 -0
- sonolus/backend/optimize/constant_evaluation.py +374 -0
- sonolus/backend/optimize/copy_coalesce.py +85 -0
- sonolus/backend/optimize/dead_code.py +185 -0
- sonolus/backend/optimize/dominance.py +96 -0
- sonolus/backend/{flow.py → optimize/flow.py} +122 -92
- sonolus/backend/optimize/inlining.py +137 -0
- sonolus/backend/optimize/liveness.py +177 -0
- sonolus/backend/optimize/optimize.py +44 -0
- sonolus/backend/optimize/passes.py +52 -0
- sonolus/backend/optimize/simplify.py +191 -0
- sonolus/backend/optimize/ssa.py +200 -0
- sonolus/backend/place.py +17 -25
- sonolus/backend/utils.py +58 -48
- sonolus/backend/visitor.py +1151 -882
- sonolus/build/cli.py +7 -1
- sonolus/build/compile.py +88 -90
- sonolus/build/engine.py +10 -5
- sonolus/build/level.py +24 -23
- sonolus/build/node.py +43 -43
- sonolus/script/archetype.py +438 -139
- sonolus/script/array.py +27 -10
- sonolus/script/array_like.py +297 -0
- sonolus/script/bucket.py +253 -191
- sonolus/script/containers.py +257 -51
- sonolus/script/debug.py +26 -10
- sonolus/script/easing.py +365 -0
- sonolus/script/effect.py +191 -131
- sonolus/script/engine.py +71 -4
- sonolus/script/globals.py +303 -269
- sonolus/script/instruction.py +205 -151
- sonolus/script/internal/__init__.py +5 -5
- sonolus/script/internal/builtin_impls.py +255 -144
- sonolus/script/{callbacks.py → internal/callbacks.py} +127 -127
- sonolus/script/internal/constant.py +139 -0
- sonolus/script/internal/context.py +26 -9
- sonolus/script/internal/descriptor.py +17 -17
- sonolus/script/internal/dict_impl.py +65 -0
- sonolus/script/internal/generic.py +6 -9
- sonolus/script/internal/impl.py +38 -13
- sonolus/script/internal/introspection.py +17 -14
- sonolus/script/internal/math_impls.py +121 -0
- sonolus/script/internal/native.py +40 -38
- sonolus/script/internal/random.py +67 -0
- sonolus/script/internal/range.py +81 -0
- sonolus/script/internal/transient.py +51 -0
- sonolus/script/internal/tuple_impl.py +113 -0
- sonolus/script/internal/value.py +3 -3
- sonolus/script/interval.py +338 -112
- sonolus/script/iterator.py +167 -214
- sonolus/script/level.py +24 -0
- sonolus/script/num.py +80 -48
- sonolus/script/options.py +257 -191
- sonolus/script/particle.py +190 -157
- sonolus/script/pointer.py +30 -30
- sonolus/script/print.py +102 -81
- sonolus/script/project.py +8 -0
- sonolus/script/quad.py +263 -0
- sonolus/script/record.py +47 -16
- sonolus/script/runtime.py +52 -1
- sonolus/script/sprite.py +418 -333
- sonolus/script/text.py +409 -407
- sonolus/script/timing.py +114 -42
- sonolus/script/transform.py +332 -48
- sonolus/script/ui.py +216 -160
- sonolus/script/values.py +6 -13
- sonolus/script/vec.py +196 -78
- {sonolus_py-0.1.3.dist-info → sonolus_py-0.1.5.dist-info}/METADATA +1 -1
- sonolus_py-0.1.5.dist-info/RECORD +89 -0
- {sonolus_py-0.1.3.dist-info → sonolus_py-0.1.5.dist-info}/WHEEL +1 -1
- {sonolus_py-0.1.3.dist-info → sonolus_py-0.1.5.dist-info}/licenses/LICENSE +21 -21
- sonolus/backend/allocate.py +0 -51
- sonolus/backend/optimize.py +0 -9
- sonolus/backend/passes.py +0 -6
- sonolus/backend/simplify.py +0 -30
- sonolus/script/comptime.py +0 -160
- sonolus/script/graphics.py +0 -150
- sonolus/script/math.py +0 -92
- sonolus/script/range.py +0 -58
- sonolus_py-0.1.3.dist-info/RECORD +0 -75
- {sonolus_py-0.1.3.dist-info → sonolus_py-0.1.5.dist-info}/entry_points.txt +0 -0
sonolus/script/particle.py
CHANGED
|
@@ -1,157 +1,190 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from dataclasses import dataclass
|
|
4
|
-
from typing import Annotated, Any, NewType, dataclass_transform, get_origin
|
|
5
|
-
|
|
6
|
-
from sonolus.backend.ops import Op
|
|
7
|
-
from sonolus.script.
|
|
8
|
-
from sonolus.script.internal.
|
|
9
|
-
from sonolus.script.
|
|
10
|
-
from sonolus.script.record import Record
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class Particle(Record):
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return
|
|
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
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Annotated, Any, NewType, dataclass_transform, get_origin
|
|
5
|
+
|
|
6
|
+
from sonolus.backend.ops import Op
|
|
7
|
+
from sonolus.script.internal.introspection import get_field_specifiers
|
|
8
|
+
from sonolus.script.internal.native import native_function
|
|
9
|
+
from sonolus.script.quad import QuadLike, flatten_quad
|
|
10
|
+
from sonolus.script.record import Record
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Particle(Record):
|
|
14
|
+
"""A particle effect."""
|
|
15
|
+
|
|
16
|
+
id: int
|
|
17
|
+
|
|
18
|
+
def is_available(self) -> bool:
|
|
19
|
+
"""Check if the particle effect is available."""
|
|
20
|
+
return _has_particle_effect(self.id)
|
|
21
|
+
|
|
22
|
+
def spawn(self, quad: QuadLike, duration: float, loop: bool = False) -> ParticleHandle:
|
|
23
|
+
"""Spawn the particle effect.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
quad: The quad to spawn the particle effect on.
|
|
27
|
+
duration: The duration of the particle effect.
|
|
28
|
+
loop: Whether to loop the particle effect.
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
ParticleHandle: A handle to the spawned particle effect.
|
|
32
|
+
"""
|
|
33
|
+
return ParticleHandle(_spawn_particle_effect(self.id, *flatten_quad(quad), duration, loop))
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class ParticleHandle(Record):
|
|
37
|
+
"""A handle to a looping particle effect."""
|
|
38
|
+
|
|
39
|
+
id: int
|
|
40
|
+
|
|
41
|
+
def move(self, quad: QuadLike) -> None:
|
|
42
|
+
"""Move the particle effect to a new location.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
quad: The new quad to move the particle effect to.
|
|
46
|
+
"""
|
|
47
|
+
_move_particle_effect(self.id, *flatten_quad(quad))
|
|
48
|
+
|
|
49
|
+
def destroy(self) -> None:
|
|
50
|
+
"""Destroy the particle effect."""
|
|
51
|
+
_destroy_particle_effect(self.id)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@native_function(Op.HasParticleEffect)
|
|
55
|
+
def _has_particle_effect(particle_id: int) -> bool:
|
|
56
|
+
raise NotImplementedError
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@native_function(Op.SpawnParticleEffect)
|
|
60
|
+
def _spawn_particle_effect(
|
|
61
|
+
particle_id: int,
|
|
62
|
+
x1: float,
|
|
63
|
+
y1: float,
|
|
64
|
+
x2: float,
|
|
65
|
+
y2: float,
|
|
66
|
+
x3: float,
|
|
67
|
+
y3: float,
|
|
68
|
+
x4: float,
|
|
69
|
+
y4: float,
|
|
70
|
+
duration: float,
|
|
71
|
+
loop: bool,
|
|
72
|
+
) -> int:
|
|
73
|
+
raise NotImplementedError
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@native_function(Op.MoveParticleEffect)
|
|
77
|
+
def _move_particle_effect(
|
|
78
|
+
handle: int, x1: float, y1: float, x2: float, y2: float, x3: float, y3: float, x4: float, y4: float
|
|
79
|
+
) -> None:
|
|
80
|
+
raise NotImplementedError
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@native_function(Op.DestroyParticleEffect)
|
|
84
|
+
def _destroy_particle_effect(handle: int) -> None:
|
|
85
|
+
raise NotImplementedError
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@dataclass
|
|
89
|
+
class _ParticleInfo:
|
|
90
|
+
name: str
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def particle(name: str) -> Any:
|
|
94
|
+
return _ParticleInfo(name)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
type Particles = NewType("Particles", Any)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@dataclass_transform()
|
|
101
|
+
def particles[T](cls: type[T]) -> T | Particles:
|
|
102
|
+
"""Decorator to define particles.
|
|
103
|
+
|
|
104
|
+
Usage:
|
|
105
|
+
```python
|
|
106
|
+
@particles
|
|
107
|
+
class Particles:
|
|
108
|
+
tap: StandardParticle.NOTE_CIRCULAR_TAP_RED
|
|
109
|
+
other: Particle = particle("other")
|
|
110
|
+
```
|
|
111
|
+
"""
|
|
112
|
+
if len(cls.__bases__) != 1:
|
|
113
|
+
raise ValueError("Particles class must not inherit from any class (except object)")
|
|
114
|
+
instance = cls()
|
|
115
|
+
names = []
|
|
116
|
+
for i, (name, annotation) in enumerate(get_field_specifiers(cls).items()):
|
|
117
|
+
if get_origin(annotation) is not Annotated:
|
|
118
|
+
raise TypeError(f"Invalid annotation for particles: {annotation}")
|
|
119
|
+
annotation_type = annotation.__args__[0]
|
|
120
|
+
annotation_values = annotation.__metadata__
|
|
121
|
+
if annotation_type is not Particle:
|
|
122
|
+
raise TypeError(f"Invalid annotation for particles: {annotation}, expected annotation of type Particle")
|
|
123
|
+
if len(annotation_values) != 1 or not isinstance(annotation_values[0], _ParticleInfo):
|
|
124
|
+
raise TypeError(
|
|
125
|
+
f"Invalid annotation for particles: {annotation}, expected a single string annotation value"
|
|
126
|
+
)
|
|
127
|
+
particle_name = annotation_values[0].name
|
|
128
|
+
names.append(particle_name)
|
|
129
|
+
setattr(instance, name, Particle(i))
|
|
130
|
+
instance._particles_ = names
|
|
131
|
+
instance._is_comptime_value_ = True
|
|
132
|
+
return instance
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class StandardParticle:
|
|
136
|
+
"""Standard particles."""
|
|
137
|
+
|
|
138
|
+
NOTE_CIRCULAR_TAP_NEUTRAL = Annotated[Particle, particle("#NOTE_CIRCULAR_TAP_NEUTRAL")]
|
|
139
|
+
NOTE_CIRCULAR_TAP_RED = Annotated[Particle, particle("#NOTE_CIRCULAR_TAP_RED")]
|
|
140
|
+
NOTE_CIRCULAR_TAP_GREEN = Annotated[Particle, particle("#NOTE_CIRCULAR_TAP_GREEN")]
|
|
141
|
+
NOTE_CIRCULAR_TAP_BLUE = Annotated[Particle, particle("#NOTE_CIRCULAR_TAP_BLUE")]
|
|
142
|
+
NOTE_CIRCULAR_TAP_YELLOW = Annotated[Particle, particle("#NOTE_CIRCULAR_TAP_YELLOW")]
|
|
143
|
+
NOTE_CIRCULAR_TAP_PURPLE = Annotated[Particle, particle("#NOTE_CIRCULAR_TAP_PURPLE")]
|
|
144
|
+
NOTE_CIRCULAR_TAP_CYAN = Annotated[Particle, particle("#NOTE_CIRCULAR_TAP_CYAN")]
|
|
145
|
+
NOTE_CIRCULAR_ALTERNATIVE_NEUTRAL = Annotated[Particle, particle("#NOTE_CIRCULAR_ALTERNATIVE_NEUTRAL")]
|
|
146
|
+
NOTE_CIRCULAR_ALTERNATIVE_RED = Annotated[Particle, particle("#NOTE_CIRCULAR_ALTERNATIVE_RED")]
|
|
147
|
+
NOTE_CIRCULAR_ALTERNATIVE_GREEN = Annotated[Particle, particle("#NOTE_CIRCULAR_ALTERNATIVE_GREEN")]
|
|
148
|
+
NOTE_CIRCULAR_ALTERNATIVE_BLUE = Annotated[Particle, particle("#NOTE_CIRCULAR_ALTERNATIVE_BLUE")]
|
|
149
|
+
NOTE_CIRCULAR_ALTERNATIVE_YELLOW = Annotated[Particle, particle("#NOTE_CIRCULAR_ALTERNATIVE_YELLOW")]
|
|
150
|
+
NOTE_CIRCULAR_ALTERNATIVE_PURPLE = Annotated[Particle, particle("#NOTE_CIRCULAR_ALTERNATIVE_PURPLE")]
|
|
151
|
+
NOTE_CIRCULAR_ALTERNATIVE_CYAN = Annotated[Particle, particle("#NOTE_CIRCULAR_ALTERNATIVE_CYAN")]
|
|
152
|
+
NOTE_CIRCULAR_HOLD_NEUTRAL = Annotated[Particle, particle("#NOTE_CIRCULAR_HOLD_NEUTRAL")]
|
|
153
|
+
NOTE_CIRCULAR_HOLD_RED = Annotated[Particle, particle("#NOTE_CIRCULAR_HOLD_RED")]
|
|
154
|
+
NOTE_CIRCULAR_HOLD_GREEN = Annotated[Particle, particle("#NOTE_CIRCULAR_HOLD_GREEN")]
|
|
155
|
+
NOTE_CIRCULAR_HOLD_BLUE = Annotated[Particle, particle("#NOTE_CIRCULAR_HOLD_BLUE")]
|
|
156
|
+
NOTE_CIRCULAR_HOLD_YELLOW = Annotated[Particle, particle("#NOTE_CIRCULAR_HOLD_YELLOW")]
|
|
157
|
+
NOTE_CIRCULAR_HOLD_PURPLE = Annotated[Particle, particle("#NOTE_CIRCULAR_HOLD_PURPLE")]
|
|
158
|
+
NOTE_CIRCULAR_HOLD_CYAN = Annotated[Particle, particle("#NOTE_CIRCULAR_HOLD_CYAN")]
|
|
159
|
+
NOTE_LINEAR_TAP_NEUTRAL = Annotated[Particle, particle("#NOTE_LINEAR_TAP_NEUTRAL")]
|
|
160
|
+
NOTE_LINEAR_TAP_RED = Annotated[Particle, particle("#NOTE_LINEAR_TAP_RED")]
|
|
161
|
+
NOTE_LINEAR_TAP_GREEN = Annotated[Particle, particle("#NOTE_LINEAR_TAP_GREEN")]
|
|
162
|
+
NOTE_LINEAR_TAP_BLUE = Annotated[Particle, particle("#NOTE_LINEAR_TAP_BLUE")]
|
|
163
|
+
NOTE_LINEAR_TAP_YELLOW = Annotated[Particle, particle("#NOTE_LINEAR_TAP_YELLOW")]
|
|
164
|
+
NOTE_LINEAR_TAP_PURPLE = Annotated[Particle, particle("#NOTE_LINEAR_TAP_PURPLE")]
|
|
165
|
+
NOTE_LINEAR_TAP_CYAN = Annotated[Particle, particle("#NOTE_LINEAR_TAP_CYAN")]
|
|
166
|
+
NOTE_LINEAR_ALTERNATIVE_NEUTRAL = Annotated[Particle, particle("#NOTE_LINEAR_ALTERNATIVE_NEUTRAL")]
|
|
167
|
+
NOTE_LINEAR_ALTERNATIVE_RED = Annotated[Particle, particle("#NOTE_LINEAR_ALTERNATIVE_RED")]
|
|
168
|
+
NOTE_LINEAR_ALTERNATIVE_GREEN = Annotated[Particle, particle("#NOTE_LINEAR_ALTERNATIVE_GREEN")]
|
|
169
|
+
NOTE_LINEAR_ALTERNATIVE_BLUE = Annotated[Particle, particle("#NOTE_LINEAR_ALTERNATIVE_BLUE")]
|
|
170
|
+
NOTE_LINEAR_ALTERNATIVE_YELLOW = Annotated[Particle, particle("#NOTE_LINEAR_ALTERNATIVE_YELLOW")]
|
|
171
|
+
NOTE_LINEAR_ALTERNATIVE_PURPLE = Annotated[Particle, particle("#NOTE_LINEAR_ALTERNATIVE_PURPLE")]
|
|
172
|
+
NOTE_LINEAR_ALTERNATIVE_CYAN = Annotated[Particle, particle("#NOTE_LINEAR_ALTERNATIVE_CYAN")]
|
|
173
|
+
NOTE_LINEAR_HOLD_NEUTRAL = Annotated[Particle, particle("#NOTE_LINEAR_HOLD_NEUTRAL")]
|
|
174
|
+
NOTE_LINEAR_HOLD_RED = Annotated[Particle, particle("#NOTE_LINEAR_HOLD_RED")]
|
|
175
|
+
NOTE_LINEAR_HOLD_GREEN = Annotated[Particle, particle("#NOTE_LINEAR_HOLD_GREEN")]
|
|
176
|
+
NOTE_LINEAR_HOLD_BLUE = Annotated[Particle, particle("#NOTE_LINEAR_HOLD_BLUE")]
|
|
177
|
+
NOTE_LINEAR_HOLD_YELLOW = Annotated[Particle, particle("#NOTE_LINEAR_HOLD_YELLOW")]
|
|
178
|
+
NOTE_LINEAR_HOLD_PURPLE = Annotated[Particle, particle("#NOTE_LINEAR_HOLD_PURPLE")]
|
|
179
|
+
NOTE_LINEAR_HOLD_CYAN = Annotated[Particle, particle("#NOTE_LINEAR_HOLD_CYAN")]
|
|
180
|
+
LANE_CIRCULAR = Annotated[Particle, particle("#LANE_CIRCULAR")]
|
|
181
|
+
LANE_LINEAR = Annotated[Particle, particle("#LANE_LINEAR")]
|
|
182
|
+
SLOT_CIRCULAR = Annotated[Particle, particle("#SLOT_CIRCULAR")]
|
|
183
|
+
SLOT_LINEAR = Annotated[Particle, particle("#SLOT_LINEAR")]
|
|
184
|
+
JUDGE_LINE_CIRCULAR = Annotated[Particle, particle("#JUDGE_LINE_CIRCULAR")]
|
|
185
|
+
JUDGE_LINE_LINEAR = Annotated[Particle, particle("#JUDGE_LINE_LINEAR")]
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
@particles
|
|
189
|
+
class EmptyParticles:
|
|
190
|
+
pass
|
sonolus/script/pointer.py
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
from sonolus.backend.place import BlockPlace
|
|
2
|
-
from sonolus.script.internal.impl import meta_fn, validate_value
|
|
3
|
-
from sonolus.script.internal.value import Value
|
|
4
|
-
from sonolus.script.num import Num,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
@meta_fn
|
|
8
|
-
def
|
|
9
|
-
block = Num._accept_(block)
|
|
10
|
-
offset = Num._accept_(offset)
|
|
11
|
-
type_ = validate_value(type_)._as_py_()
|
|
12
|
-
if block._is_py_():
|
|
13
|
-
block = block._as_py_()
|
|
14
|
-
if not isinstance(block, int):
|
|
15
|
-
raise TypeError("block must be an integer")
|
|
16
|
-
else:
|
|
17
|
-
if not
|
|
18
|
-
raise TypeError("block must be a Num")
|
|
19
|
-
block = block.index()
|
|
20
|
-
if offset._is_py_():
|
|
21
|
-
offset = offset._as_py_()
|
|
22
|
-
if not isinstance(offset, int):
|
|
23
|
-
raise TypeError("offset must be an integer")
|
|
24
|
-
else:
|
|
25
|
-
if not
|
|
26
|
-
raise TypeError("offset must be a Num")
|
|
27
|
-
offset = offset.index()
|
|
28
|
-
if not (isinstance(type_, type) and issubclass(type_, Value)):
|
|
29
|
-
raise TypeError("type_ must be a Value")
|
|
30
|
-
return type_._from_place_(BlockPlace(block, offset))
|
|
1
|
+
from sonolus.backend.place import BlockPlace
|
|
2
|
+
from sonolus.script.internal.impl import meta_fn, validate_value
|
|
3
|
+
from sonolus.script.internal.value import Value
|
|
4
|
+
from sonolus.script.num import Num, _is_num
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@meta_fn
|
|
8
|
+
def _deref[T: Value](block: Num, offset: Num, type_: type[T]) -> T:
|
|
9
|
+
block = Num._accept_(block)
|
|
10
|
+
offset = Num._accept_(offset)
|
|
11
|
+
type_ = validate_value(type_)._as_py_()
|
|
12
|
+
if block._is_py_():
|
|
13
|
+
block = block._as_py_()
|
|
14
|
+
if not isinstance(block, int):
|
|
15
|
+
raise TypeError("block must be an integer")
|
|
16
|
+
else:
|
|
17
|
+
if not _is_num(block):
|
|
18
|
+
raise TypeError("block must be a Num")
|
|
19
|
+
block = block.index()
|
|
20
|
+
if offset._is_py_():
|
|
21
|
+
offset = offset._as_py_()
|
|
22
|
+
if not isinstance(offset, int):
|
|
23
|
+
raise TypeError("offset must be an integer")
|
|
24
|
+
else:
|
|
25
|
+
if not _is_num(offset):
|
|
26
|
+
raise TypeError("offset must be a Num")
|
|
27
|
+
offset = offset.index()
|
|
28
|
+
if not (isinstance(type_, type) and issubclass(type_, Value)):
|
|
29
|
+
raise TypeError("type_ must be a Value")
|
|
30
|
+
return type_._from_place_(BlockPlace(block, offset))
|
sonolus/script/print.py
CHANGED
|
@@ -1,81 +1,102 @@
|
|
|
1
|
-
from enum import IntEnum
|
|
2
|
-
|
|
3
|
-
from sonolus.backend.ops import Op
|
|
4
|
-
from sonolus.script.internal.native import native_function
|
|
5
|
-
from sonolus.script.runtime import HorizontalAlign
|
|
6
|
-
from sonolus.script.vec import Vec2
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class PrintFormat(IntEnum):
|
|
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
|
-
|
|
1
|
+
from enum import IntEnum
|
|
2
|
+
|
|
3
|
+
from sonolus.backend.ops import Op
|
|
4
|
+
from sonolus.script.internal.native import native_function
|
|
5
|
+
from sonolus.script.runtime import HorizontalAlign
|
|
6
|
+
from sonolus.script.vec import Vec2
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class PrintFormat(IntEnum):
|
|
10
|
+
"""Print format."""
|
|
11
|
+
|
|
12
|
+
NUMBER = 0
|
|
13
|
+
PERCENTAGE = 1
|
|
14
|
+
TIME = 10
|
|
15
|
+
SCORE = 11
|
|
16
|
+
BPM = 20
|
|
17
|
+
TIMESCALE = 21
|
|
18
|
+
BEAT_COUNT = 30
|
|
19
|
+
MEASURE_COUNT = 31
|
|
20
|
+
ENTITY_COUNT = 32
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class PrintColor(IntEnum):
|
|
24
|
+
"""Print color."""
|
|
25
|
+
|
|
26
|
+
THEME = -1
|
|
27
|
+
NEUTRAL = 0
|
|
28
|
+
RED = 1
|
|
29
|
+
GREEN = 2
|
|
30
|
+
BLUE = 3
|
|
31
|
+
YELLOW = 4
|
|
32
|
+
PURPLE = 5
|
|
33
|
+
CYAN = 6
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@native_function(Op.Print)
|
|
37
|
+
def _print(
|
|
38
|
+
value: int | float,
|
|
39
|
+
format: PrintFormat, # noqa: A002
|
|
40
|
+
decimal_places: int,
|
|
41
|
+
anchor_x: float,
|
|
42
|
+
anchor_y: float,
|
|
43
|
+
pivot_x: float,
|
|
44
|
+
pivot_y: float,
|
|
45
|
+
width: float,
|
|
46
|
+
height: float,
|
|
47
|
+
rotation: float,
|
|
48
|
+
color: PrintColor,
|
|
49
|
+
alpha: float,
|
|
50
|
+
horizontal_align: HorizontalAlign,
|
|
51
|
+
background: bool,
|
|
52
|
+
) -> None:
|
|
53
|
+
raise NotImplementedError
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def print_number(
|
|
57
|
+
value: int | float,
|
|
58
|
+
*,
|
|
59
|
+
fmt: PrintFormat,
|
|
60
|
+
decimal_places: int = 0,
|
|
61
|
+
anchor: Vec2,
|
|
62
|
+
pivot: Vec2,
|
|
63
|
+
dimensions: Vec2,
|
|
64
|
+
rotation: float = 0,
|
|
65
|
+
color: PrintColor = PrintColor.THEME,
|
|
66
|
+
alpha: float = 1,
|
|
67
|
+
horizontal_align: HorizontalAlign = HorizontalAlign.LEFT,
|
|
68
|
+
background: bool = False,
|
|
69
|
+
):
|
|
70
|
+
"""Print a number.
|
|
71
|
+
|
|
72
|
+
Only supported in preview mode.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
value: The value to print.
|
|
76
|
+
fmt: The print format.
|
|
77
|
+
decimal_places: The number of decimal places.
|
|
78
|
+
anchor: The anchor.
|
|
79
|
+
pivot: The pivot.
|
|
80
|
+
dimensions: The dimensions.
|
|
81
|
+
rotation: The rotation.
|
|
82
|
+
color: The color.
|
|
83
|
+
alpha: The alpha.
|
|
84
|
+
horizontal_align: The horizontal alignment.
|
|
85
|
+
background: Whether to show a background.
|
|
86
|
+
"""
|
|
87
|
+
_print(
|
|
88
|
+
value,
|
|
89
|
+
fmt,
|
|
90
|
+
decimal_places,
|
|
91
|
+
anchor.x,
|
|
92
|
+
anchor.y,
|
|
93
|
+
pivot.x,
|
|
94
|
+
pivot.y,
|
|
95
|
+
dimensions.x,
|
|
96
|
+
dimensions.y,
|
|
97
|
+
rotation,
|
|
98
|
+
color,
|
|
99
|
+
alpha,
|
|
100
|
+
horizontal_align,
|
|
101
|
+
background,
|
|
102
|
+
)
|
sonolus/script/project.py
CHANGED
|
@@ -6,6 +6,14 @@ from sonolus.script.level import Level
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class Project:
|
|
9
|
+
"""A Sonolus.py project.
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
engine: The engine of the project.
|
|
13
|
+
levels: The levels of the project.
|
|
14
|
+
resources: The path to the resources of the project.
|
|
15
|
+
"""
|
|
16
|
+
|
|
9
17
|
def __init__(
|
|
10
18
|
self,
|
|
11
19
|
engine: Engine,
|