sonolus.py 0.1.3__py3-none-any.whl → 0.1.4__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/allocate.py +125 -51
- sonolus/backend/blocks.py +756 -756
- sonolus/backend/coalesce.py +85 -0
- sonolus/backend/constant_evaluation.py +374 -0
- sonolus/backend/dead_code.py +80 -0
- sonolus/backend/dominance.py +111 -0
- sonolus/backend/excepthook.py +37 -37
- sonolus/backend/finalize.py +69 -69
- sonolus/backend/flow.py +121 -92
- sonolus/backend/inlining.py +150 -0
- sonolus/backend/ir.py +5 -3
- sonolus/backend/liveness.py +173 -0
- sonolus/backend/mode.py +24 -24
- sonolus/backend/node.py +40 -40
- sonolus/backend/ops.py +197 -197
- sonolus/backend/optimize.py +37 -9
- sonolus/backend/passes.py +52 -6
- sonolus/backend/simplify.py +47 -30
- sonolus/backend/ssa.py +187 -0
- sonolus/backend/utils.py +48 -48
- sonolus/backend/visitor.py +892 -882
- sonolus/build/cli.py +7 -1
- sonolus/build/compile.py +88 -90
- sonolus/build/level.py +24 -23
- sonolus/build/node.py +43 -43
- sonolus/script/archetype.py +23 -6
- sonolus/script/array.py +2 -2
- sonolus/script/bucket.py +191 -191
- sonolus/script/callbacks.py +127 -127
- sonolus/script/comptime.py +1 -1
- sonolus/script/containers.py +23 -0
- sonolus/script/debug.py +19 -3
- sonolus/script/easing.py +323 -0
- sonolus/script/effect.py +131 -131
- sonolus/script/globals.py +269 -269
- sonolus/script/graphics.py +200 -150
- sonolus/script/instruction.py +151 -151
- sonolus/script/internal/__init__.py +5 -5
- sonolus/script/internal/builtin_impls.py +144 -144
- sonolus/script/internal/context.py +12 -4
- sonolus/script/internal/descriptor.py +17 -17
- sonolus/script/internal/introspection.py +14 -14
- sonolus/script/internal/native.py +40 -38
- sonolus/script/internal/value.py +3 -3
- sonolus/script/interval.py +120 -112
- sonolus/script/iterator.py +214 -214
- sonolus/script/math.py +30 -1
- sonolus/script/num.py +1 -1
- sonolus/script/options.py +191 -191
- sonolus/script/particle.py +157 -157
- sonolus/script/pointer.py +30 -30
- sonolus/script/print.py +81 -81
- sonolus/script/random.py +14 -0
- sonolus/script/range.py +58 -58
- sonolus/script/record.py +3 -3
- sonolus/script/runtime.py +2 -0
- sonolus/script/sprite.py +333 -333
- sonolus/script/text.py +407 -407
- sonolus/script/timing.py +42 -42
- sonolus/script/transform.py +77 -23
- sonolus/script/ui.py +160 -160
- sonolus/script/vec.py +81 -78
- {sonolus_py-0.1.3.dist-info → sonolus_py-0.1.4.dist-info}/METADATA +1 -1
- sonolus_py-0.1.4.dist-info/RECORD +84 -0
- {sonolus_py-0.1.3.dist-info → sonolus_py-0.1.4.dist-info}/WHEEL +1 -1
- {sonolus_py-0.1.3.dist-info → sonolus_py-0.1.4.dist-info}/licenses/LICENSE +21 -21
- sonolus_py-0.1.3.dist-info/RECORD +0 -75
- {sonolus_py-0.1.3.dist-info → sonolus_py-0.1.4.dist-info}/entry_points.txt +0 -0
sonolus/script/bucket.py
CHANGED
|
@@ -1,191 +1,191 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from dataclasses import dataclass
|
|
4
|
-
from enum import IntEnum
|
|
5
|
-
from typing import Annotated, Any, NewType, dataclass_transform, get_origin
|
|
6
|
-
|
|
7
|
-
from sonolus.backend.mode import Mode
|
|
8
|
-
from sonolus.backend.ops import Op
|
|
9
|
-
from sonolus.script.internal.context import ctx
|
|
10
|
-
from sonolus.script.internal.impl import meta_fn
|
|
11
|
-
from sonolus.script.internal.introspection import get_field_specifiers
|
|
12
|
-
from sonolus.script.internal.native import native_function
|
|
13
|
-
from sonolus.script.interval import Interval
|
|
14
|
-
from sonolus.script.pointer import deref
|
|
15
|
-
from sonolus.script.record import Record
|
|
16
|
-
from sonolus.script.sprite import Sprite
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class JudgmentWindow(Record):
|
|
20
|
-
perfect: Interval
|
|
21
|
-
great: Interval
|
|
22
|
-
good: Interval
|
|
23
|
-
|
|
24
|
-
def update(
|
|
25
|
-
self,
|
|
26
|
-
perfect: Interval | None = None,
|
|
27
|
-
great: Interval | None = None,
|
|
28
|
-
good: Interval | None = None,
|
|
29
|
-
):
|
|
30
|
-
if perfect is not None:
|
|
31
|
-
self.perfect = perfect
|
|
32
|
-
if great is not None:
|
|
33
|
-
self.great = great
|
|
34
|
-
if good is not None:
|
|
35
|
-
self.good = good
|
|
36
|
-
|
|
37
|
-
def judge(self, actual: float, target: float) -> Judgment:
|
|
38
|
-
return _judge(
|
|
39
|
-
actual,
|
|
40
|
-
target,
|
|
41
|
-
*self.perfect.tuple,
|
|
42
|
-
*self.great.tuple,
|
|
43
|
-
*self.good.tuple,
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
def __mul__(self, other: float | int) -> JudgmentWindow:
|
|
47
|
-
return JudgmentWindow(
|
|
48
|
-
self.perfect * other,
|
|
49
|
-
self.great * other,
|
|
50
|
-
self.good * other,
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
class Judgment(IntEnum):
|
|
55
|
-
MISS = 0
|
|
56
|
-
PERFECT = 1
|
|
57
|
-
GREAT = 2
|
|
58
|
-
GOOD = 3
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
@native_function(Op.Judge)
|
|
62
|
-
def _judge(
|
|
63
|
-
actual: float,
|
|
64
|
-
target: float,
|
|
65
|
-
perfect_min: float,
|
|
66
|
-
perfect_max: float,
|
|
67
|
-
great_min: float,
|
|
68
|
-
great_max: float,
|
|
69
|
-
good_min: float,
|
|
70
|
-
good_max: float,
|
|
71
|
-
) -> Judgment:
|
|
72
|
-
diff = actual - target
|
|
73
|
-
if perfect_min <= diff <= perfect_max:
|
|
74
|
-
return Judgment.PERFECT
|
|
75
|
-
if great_min <= diff <= great_max:
|
|
76
|
-
return Judgment.GREAT
|
|
77
|
-
if good_min <= diff <= good_max:
|
|
78
|
-
return Judgment.GOOD
|
|
79
|
-
return Judgment.MISS
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
class Bucket(Record):
|
|
83
|
-
id: int
|
|
84
|
-
|
|
85
|
-
@property
|
|
86
|
-
@meta_fn
|
|
87
|
-
def window(self) -> JudgmentWindow:
|
|
88
|
-
if not ctx():
|
|
89
|
-
raise RuntimeError("Bucket window access outside of compilation")
|
|
90
|
-
match ctx().global_state.mode:
|
|
91
|
-
case Mode.PLAY:
|
|
92
|
-
return deref(ctx().blocks.LevelBucket, self.id * JudgmentWindow._size_(), JudgmentWindow)
|
|
93
|
-
case Mode.WATCH:
|
|
94
|
-
return deref(ctx().blocks.LevelBucket, self.id * JudgmentWindow._size_(), JudgmentWindow)
|
|
95
|
-
case _:
|
|
96
|
-
raise RuntimeError("Invalid mode for bucket window access")
|
|
97
|
-
|
|
98
|
-
@window.setter
|
|
99
|
-
@meta_fn
|
|
100
|
-
def window(self, value: JudgmentWindow):
|
|
101
|
-
if not ctx():
|
|
102
|
-
raise RuntimeError("Bucket window access outside of compilation")
|
|
103
|
-
self.window.update(value.perfect, value.great, value.good)
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
@dataclass
|
|
107
|
-
class BucketSprite:
|
|
108
|
-
id: int
|
|
109
|
-
fallback_id: int | None
|
|
110
|
-
x: int
|
|
111
|
-
y: int
|
|
112
|
-
w: int
|
|
113
|
-
h: int
|
|
114
|
-
rotation: float
|
|
115
|
-
|
|
116
|
-
def to_dict(self):
|
|
117
|
-
results = {
|
|
118
|
-
"id": self.id,
|
|
119
|
-
"x": self.x,
|
|
120
|
-
"y": self.y,
|
|
121
|
-
"w": self.w,
|
|
122
|
-
"h": self.h,
|
|
123
|
-
"rotation": self.rotation,
|
|
124
|
-
}
|
|
125
|
-
if self.fallback_id is not None:
|
|
126
|
-
results["fallbackId"] = self.fallback_id
|
|
127
|
-
return results
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
@dataclass
|
|
131
|
-
class BucketInfo:
|
|
132
|
-
sprites: list[BucketSprite]
|
|
133
|
-
unit: str | None = None
|
|
134
|
-
|
|
135
|
-
def to_dict(self):
|
|
136
|
-
results = {
|
|
137
|
-
"sprites": [sprite.to_dict() for sprite in self.sprites],
|
|
138
|
-
}
|
|
139
|
-
if self.unit is not None:
|
|
140
|
-
results["unit"] = self.unit
|
|
141
|
-
return results
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
def bucket_sprite(
|
|
145
|
-
*,
|
|
146
|
-
sprite: Sprite,
|
|
147
|
-
fallback_sprite: Sprite | None = None,
|
|
148
|
-
x: int,
|
|
149
|
-
y: int,
|
|
150
|
-
w: int,
|
|
151
|
-
h: int,
|
|
152
|
-
rotation: float = 0,
|
|
153
|
-
) -> BucketSprite:
|
|
154
|
-
return BucketSprite(sprite.id, fallback_sprite.id if fallback_sprite else None, x, y, w, h, rotation)
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
def bucket(*, sprites: list[BucketSprite], unit: str | None = None) -> Any:
|
|
158
|
-
return BucketInfo(sprites, unit)
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
type Buckets = NewType("Buckets", Any)
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
@dataclass_transform()
|
|
165
|
-
def buckets[T](cls: type[T]) -> T | Buckets:
|
|
166
|
-
if len(cls.__bases__) != 1:
|
|
167
|
-
raise ValueError("Buckets class must not inherit from any class (except object)")
|
|
168
|
-
instance = cls()
|
|
169
|
-
bucket_info = []
|
|
170
|
-
for i, (name, annotation) in enumerate(get_field_specifiers(cls).items()):
|
|
171
|
-
if get_origin(annotation) is not Annotated:
|
|
172
|
-
raise TypeError(f"Invalid annotation for buckets: {annotation}")
|
|
173
|
-
annotation_type = annotation.__args__[0]
|
|
174
|
-
annotation_values = annotation.__metadata__
|
|
175
|
-
if annotation_type is not Bucket:
|
|
176
|
-
raise TypeError(f"Invalid annotation for buckets: {annotation}, expected annotation of type Bucket")
|
|
177
|
-
if len(annotation_values) != 1 or not isinstance(annotation_values[0], BucketInfo):
|
|
178
|
-
raise TypeError(
|
|
179
|
-
f"Invalid annotation for buckets: {annotation}, expected a single BucketInfo annotation value"
|
|
180
|
-
)
|
|
181
|
-
info = annotation_values[0]
|
|
182
|
-
bucket_info.append(info)
|
|
183
|
-
setattr(instance, name, Bucket(i))
|
|
184
|
-
instance._buckets_ = bucket_info
|
|
185
|
-
instance._is_comptime_value_ = True
|
|
186
|
-
return instance
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
@buckets
|
|
190
|
-
class EmptyBuckets:
|
|
191
|
-
pass
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from enum import IntEnum
|
|
5
|
+
from typing import Annotated, Any, NewType, dataclass_transform, get_origin
|
|
6
|
+
|
|
7
|
+
from sonolus.backend.mode import Mode
|
|
8
|
+
from sonolus.backend.ops import Op
|
|
9
|
+
from sonolus.script.internal.context import ctx
|
|
10
|
+
from sonolus.script.internal.impl import meta_fn
|
|
11
|
+
from sonolus.script.internal.introspection import get_field_specifiers
|
|
12
|
+
from sonolus.script.internal.native import native_function
|
|
13
|
+
from sonolus.script.interval import Interval
|
|
14
|
+
from sonolus.script.pointer import deref
|
|
15
|
+
from sonolus.script.record import Record
|
|
16
|
+
from sonolus.script.sprite import Sprite
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class JudgmentWindow(Record):
|
|
20
|
+
perfect: Interval
|
|
21
|
+
great: Interval
|
|
22
|
+
good: Interval
|
|
23
|
+
|
|
24
|
+
def update(
|
|
25
|
+
self,
|
|
26
|
+
perfect: Interval | None = None,
|
|
27
|
+
great: Interval | None = None,
|
|
28
|
+
good: Interval | None = None,
|
|
29
|
+
):
|
|
30
|
+
if perfect is not None:
|
|
31
|
+
self.perfect = perfect
|
|
32
|
+
if great is not None:
|
|
33
|
+
self.great = great
|
|
34
|
+
if good is not None:
|
|
35
|
+
self.good = good
|
|
36
|
+
|
|
37
|
+
def judge(self, actual: float, target: float) -> Judgment:
|
|
38
|
+
return _judge(
|
|
39
|
+
actual,
|
|
40
|
+
target,
|
|
41
|
+
*self.perfect.tuple,
|
|
42
|
+
*self.great.tuple,
|
|
43
|
+
*self.good.tuple,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
def __mul__(self, other: float | int) -> JudgmentWindow:
|
|
47
|
+
return JudgmentWindow(
|
|
48
|
+
self.perfect * other,
|
|
49
|
+
self.great * other,
|
|
50
|
+
self.good * other,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class Judgment(IntEnum):
|
|
55
|
+
MISS = 0
|
|
56
|
+
PERFECT = 1
|
|
57
|
+
GREAT = 2
|
|
58
|
+
GOOD = 3
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@native_function(Op.Judge)
|
|
62
|
+
def _judge(
|
|
63
|
+
actual: float,
|
|
64
|
+
target: float,
|
|
65
|
+
perfect_min: float,
|
|
66
|
+
perfect_max: float,
|
|
67
|
+
great_min: float,
|
|
68
|
+
great_max: float,
|
|
69
|
+
good_min: float,
|
|
70
|
+
good_max: float,
|
|
71
|
+
) -> Judgment:
|
|
72
|
+
diff = actual - target
|
|
73
|
+
if perfect_min <= diff <= perfect_max:
|
|
74
|
+
return Judgment.PERFECT
|
|
75
|
+
if great_min <= diff <= great_max:
|
|
76
|
+
return Judgment.GREAT
|
|
77
|
+
if good_min <= diff <= good_max:
|
|
78
|
+
return Judgment.GOOD
|
|
79
|
+
return Judgment.MISS
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class Bucket(Record):
|
|
83
|
+
id: int
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
@meta_fn
|
|
87
|
+
def window(self) -> JudgmentWindow:
|
|
88
|
+
if not ctx():
|
|
89
|
+
raise RuntimeError("Bucket window access outside of compilation")
|
|
90
|
+
match ctx().global_state.mode:
|
|
91
|
+
case Mode.PLAY:
|
|
92
|
+
return deref(ctx().blocks.LevelBucket, self.id * JudgmentWindow._size_(), JudgmentWindow)
|
|
93
|
+
case Mode.WATCH:
|
|
94
|
+
return deref(ctx().blocks.LevelBucket, self.id * JudgmentWindow._size_(), JudgmentWindow)
|
|
95
|
+
case _:
|
|
96
|
+
raise RuntimeError("Invalid mode for bucket window access")
|
|
97
|
+
|
|
98
|
+
@window.setter
|
|
99
|
+
@meta_fn
|
|
100
|
+
def window(self, value: JudgmentWindow):
|
|
101
|
+
if not ctx():
|
|
102
|
+
raise RuntimeError("Bucket window access outside of compilation")
|
|
103
|
+
self.window.update(value.perfect, value.great, value.good)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@dataclass
|
|
107
|
+
class BucketSprite:
|
|
108
|
+
id: int
|
|
109
|
+
fallback_id: int | None
|
|
110
|
+
x: int
|
|
111
|
+
y: int
|
|
112
|
+
w: int
|
|
113
|
+
h: int
|
|
114
|
+
rotation: float
|
|
115
|
+
|
|
116
|
+
def to_dict(self):
|
|
117
|
+
results = {
|
|
118
|
+
"id": self.id,
|
|
119
|
+
"x": self.x,
|
|
120
|
+
"y": self.y,
|
|
121
|
+
"w": self.w,
|
|
122
|
+
"h": self.h,
|
|
123
|
+
"rotation": self.rotation,
|
|
124
|
+
}
|
|
125
|
+
if self.fallback_id is not None:
|
|
126
|
+
results["fallbackId"] = self.fallback_id
|
|
127
|
+
return results
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@dataclass
|
|
131
|
+
class BucketInfo:
|
|
132
|
+
sprites: list[BucketSprite]
|
|
133
|
+
unit: str | None = None
|
|
134
|
+
|
|
135
|
+
def to_dict(self):
|
|
136
|
+
results = {
|
|
137
|
+
"sprites": [sprite.to_dict() for sprite in self.sprites],
|
|
138
|
+
}
|
|
139
|
+
if self.unit is not None:
|
|
140
|
+
results["unit"] = self.unit
|
|
141
|
+
return results
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def bucket_sprite(
|
|
145
|
+
*,
|
|
146
|
+
sprite: Sprite,
|
|
147
|
+
fallback_sprite: Sprite | None = None,
|
|
148
|
+
x: int,
|
|
149
|
+
y: int,
|
|
150
|
+
w: int,
|
|
151
|
+
h: int,
|
|
152
|
+
rotation: float = 0,
|
|
153
|
+
) -> BucketSprite:
|
|
154
|
+
return BucketSprite(sprite.id, fallback_sprite.id if fallback_sprite else None, x, y, w, h, rotation)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def bucket(*, sprites: list[BucketSprite], unit: str | None = None) -> Any:
|
|
158
|
+
return BucketInfo(sprites, unit)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
type Buckets = NewType("Buckets", Any)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
@dataclass_transform()
|
|
165
|
+
def buckets[T](cls: type[T]) -> T | Buckets:
|
|
166
|
+
if len(cls.__bases__) != 1:
|
|
167
|
+
raise ValueError("Buckets class must not inherit from any class (except object)")
|
|
168
|
+
instance = cls()
|
|
169
|
+
bucket_info = []
|
|
170
|
+
for i, (name, annotation) in enumerate(get_field_specifiers(cls).items()):
|
|
171
|
+
if get_origin(annotation) is not Annotated:
|
|
172
|
+
raise TypeError(f"Invalid annotation for buckets: {annotation}")
|
|
173
|
+
annotation_type = annotation.__args__[0]
|
|
174
|
+
annotation_values = annotation.__metadata__
|
|
175
|
+
if annotation_type is not Bucket:
|
|
176
|
+
raise TypeError(f"Invalid annotation for buckets: {annotation}, expected annotation of type Bucket")
|
|
177
|
+
if len(annotation_values) != 1 or not isinstance(annotation_values[0], BucketInfo):
|
|
178
|
+
raise TypeError(
|
|
179
|
+
f"Invalid annotation for buckets: {annotation}, expected a single BucketInfo annotation value"
|
|
180
|
+
)
|
|
181
|
+
info = annotation_values[0]
|
|
182
|
+
bucket_info.append(info)
|
|
183
|
+
setattr(instance, name, Bucket(i))
|
|
184
|
+
instance._buckets_ = bucket_info
|
|
185
|
+
instance._is_comptime_value_ = True
|
|
186
|
+
return instance
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
@buckets
|
|
190
|
+
class EmptyBuckets:
|
|
191
|
+
pass
|
sonolus/script/callbacks.py
CHANGED
|
@@ -1,127 +1,127 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
@dataclass
|
|
5
|
-
class CallbackInfo:
|
|
6
|
-
name: str
|
|
7
|
-
py_name: str
|
|
8
|
-
supports_order: bool
|
|
9
|
-
returns_value: bool
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
preprocess_callback = CallbackInfo(
|
|
13
|
-
name="preprocess",
|
|
14
|
-
py_name="preprocess",
|
|
15
|
-
supports_order=True,
|
|
16
|
-
returns_value=False,
|
|
17
|
-
)
|
|
18
|
-
spawn_order_callback = CallbackInfo(
|
|
19
|
-
name="spawnOrder",
|
|
20
|
-
py_name="spawn_order",
|
|
21
|
-
supports_order=True,
|
|
22
|
-
returns_value=True,
|
|
23
|
-
)
|
|
24
|
-
should_spawn_callback = CallbackInfo(
|
|
25
|
-
name="shouldSpawn",
|
|
26
|
-
py_name="should_spawn",
|
|
27
|
-
supports_order=False,
|
|
28
|
-
returns_value=True,
|
|
29
|
-
)
|
|
30
|
-
initialize_callback = CallbackInfo(
|
|
31
|
-
name="initialize",
|
|
32
|
-
py_name="initialize",
|
|
33
|
-
supports_order=False,
|
|
34
|
-
returns_value=False,
|
|
35
|
-
)
|
|
36
|
-
update_sequential_callback = CallbackInfo(
|
|
37
|
-
name="updateSequential",
|
|
38
|
-
py_name="update_sequential",
|
|
39
|
-
supports_order=True,
|
|
40
|
-
returns_value=False,
|
|
41
|
-
)
|
|
42
|
-
touch_callback = CallbackInfo(
|
|
43
|
-
name="touch",
|
|
44
|
-
py_name="touch",
|
|
45
|
-
supports_order=True,
|
|
46
|
-
returns_value=False,
|
|
47
|
-
)
|
|
48
|
-
update_parallel_callback = CallbackInfo(
|
|
49
|
-
name="updateParallel",
|
|
50
|
-
py_name="update_parallel",
|
|
51
|
-
supports_order=False,
|
|
52
|
-
returns_value=False,
|
|
53
|
-
)
|
|
54
|
-
terminate_callback = CallbackInfo(
|
|
55
|
-
name="terminate",
|
|
56
|
-
py_name="terminate",
|
|
57
|
-
supports_order=False,
|
|
58
|
-
returns_value=False,
|
|
59
|
-
)
|
|
60
|
-
spawn_time_callback = CallbackInfo(
|
|
61
|
-
name="spawnTime",
|
|
62
|
-
py_name="spawn_time",
|
|
63
|
-
supports_order=False,
|
|
64
|
-
returns_value=True,
|
|
65
|
-
)
|
|
66
|
-
despawn_time_callback = CallbackInfo(
|
|
67
|
-
name="despawnTime",
|
|
68
|
-
py_name="despawn_time",
|
|
69
|
-
supports_order=False,
|
|
70
|
-
returns_value=True,
|
|
71
|
-
)
|
|
72
|
-
update_spawn_callback = CallbackInfo(
|
|
73
|
-
name="updateSpawn",
|
|
74
|
-
py_name="update_spawn",
|
|
75
|
-
supports_order=False,
|
|
76
|
-
returns_value=True,
|
|
77
|
-
)
|
|
78
|
-
render_callback = CallbackInfo(
|
|
79
|
-
name="render",
|
|
80
|
-
py_name="render",
|
|
81
|
-
supports_order=False,
|
|
82
|
-
returns_value=False,
|
|
83
|
-
)
|
|
84
|
-
navigate_callback = CallbackInfo(
|
|
85
|
-
name="navigate",
|
|
86
|
-
py_name="navigate",
|
|
87
|
-
supports_order=False,
|
|
88
|
-
returns_value=False,
|
|
89
|
-
)
|
|
90
|
-
update_callback = CallbackInfo(
|
|
91
|
-
name="update",
|
|
92
|
-
py_name="update",
|
|
93
|
-
supports_order=False,
|
|
94
|
-
returns_value=False,
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
def _by_name(*callbacks: CallbackInfo) -> dict[str, CallbackInfo]:
|
|
99
|
-
return {cb.py_name: cb for cb in callbacks}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
PLAY_CALLBACKS = _by_name(
|
|
103
|
-
preprocess_callback,
|
|
104
|
-
spawn_order_callback,
|
|
105
|
-
should_spawn_callback,
|
|
106
|
-
initialize_callback,
|
|
107
|
-
update_sequential_callback,
|
|
108
|
-
touch_callback,
|
|
109
|
-
update_parallel_callback,
|
|
110
|
-
terminate_callback,
|
|
111
|
-
)
|
|
112
|
-
WATCH_ARCHETYPE_CALLBACKS = _by_name(
|
|
113
|
-
preprocess_callback,
|
|
114
|
-
spawn_time_callback,
|
|
115
|
-
despawn_time_callback,
|
|
116
|
-
initialize_callback,
|
|
117
|
-
update_sequential_callback,
|
|
118
|
-
update_parallel_callback,
|
|
119
|
-
terminate_callback,
|
|
120
|
-
)
|
|
121
|
-
WATCH_GLOBAL_CALLBACKS = _by_name(
|
|
122
|
-
update_spawn_callback,
|
|
123
|
-
)
|
|
124
|
-
PREVIEW_CALLBACKS = _by_name(
|
|
125
|
-
preprocess_callback,
|
|
126
|
-
render_callback,
|
|
127
|
-
)
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@dataclass
|
|
5
|
+
class CallbackInfo:
|
|
6
|
+
name: str
|
|
7
|
+
py_name: str
|
|
8
|
+
supports_order: bool
|
|
9
|
+
returns_value: bool
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
preprocess_callback = CallbackInfo(
|
|
13
|
+
name="preprocess",
|
|
14
|
+
py_name="preprocess",
|
|
15
|
+
supports_order=True,
|
|
16
|
+
returns_value=False,
|
|
17
|
+
)
|
|
18
|
+
spawn_order_callback = CallbackInfo(
|
|
19
|
+
name="spawnOrder",
|
|
20
|
+
py_name="spawn_order",
|
|
21
|
+
supports_order=True,
|
|
22
|
+
returns_value=True,
|
|
23
|
+
)
|
|
24
|
+
should_spawn_callback = CallbackInfo(
|
|
25
|
+
name="shouldSpawn",
|
|
26
|
+
py_name="should_spawn",
|
|
27
|
+
supports_order=False,
|
|
28
|
+
returns_value=True,
|
|
29
|
+
)
|
|
30
|
+
initialize_callback = CallbackInfo(
|
|
31
|
+
name="initialize",
|
|
32
|
+
py_name="initialize",
|
|
33
|
+
supports_order=False,
|
|
34
|
+
returns_value=False,
|
|
35
|
+
)
|
|
36
|
+
update_sequential_callback = CallbackInfo(
|
|
37
|
+
name="updateSequential",
|
|
38
|
+
py_name="update_sequential",
|
|
39
|
+
supports_order=True,
|
|
40
|
+
returns_value=False,
|
|
41
|
+
)
|
|
42
|
+
touch_callback = CallbackInfo(
|
|
43
|
+
name="touch",
|
|
44
|
+
py_name="touch",
|
|
45
|
+
supports_order=True,
|
|
46
|
+
returns_value=False,
|
|
47
|
+
)
|
|
48
|
+
update_parallel_callback = CallbackInfo(
|
|
49
|
+
name="updateParallel",
|
|
50
|
+
py_name="update_parallel",
|
|
51
|
+
supports_order=False,
|
|
52
|
+
returns_value=False,
|
|
53
|
+
)
|
|
54
|
+
terminate_callback = CallbackInfo(
|
|
55
|
+
name="terminate",
|
|
56
|
+
py_name="terminate",
|
|
57
|
+
supports_order=False,
|
|
58
|
+
returns_value=False,
|
|
59
|
+
)
|
|
60
|
+
spawn_time_callback = CallbackInfo(
|
|
61
|
+
name="spawnTime",
|
|
62
|
+
py_name="spawn_time",
|
|
63
|
+
supports_order=False,
|
|
64
|
+
returns_value=True,
|
|
65
|
+
)
|
|
66
|
+
despawn_time_callback = CallbackInfo(
|
|
67
|
+
name="despawnTime",
|
|
68
|
+
py_name="despawn_time",
|
|
69
|
+
supports_order=False,
|
|
70
|
+
returns_value=True,
|
|
71
|
+
)
|
|
72
|
+
update_spawn_callback = CallbackInfo(
|
|
73
|
+
name="updateSpawn",
|
|
74
|
+
py_name="update_spawn",
|
|
75
|
+
supports_order=False,
|
|
76
|
+
returns_value=True,
|
|
77
|
+
)
|
|
78
|
+
render_callback = CallbackInfo(
|
|
79
|
+
name="render",
|
|
80
|
+
py_name="render",
|
|
81
|
+
supports_order=False,
|
|
82
|
+
returns_value=False,
|
|
83
|
+
)
|
|
84
|
+
navigate_callback = CallbackInfo(
|
|
85
|
+
name="navigate",
|
|
86
|
+
py_name="navigate",
|
|
87
|
+
supports_order=False,
|
|
88
|
+
returns_value=False,
|
|
89
|
+
)
|
|
90
|
+
update_callback = CallbackInfo(
|
|
91
|
+
name="update",
|
|
92
|
+
py_name="update",
|
|
93
|
+
supports_order=False,
|
|
94
|
+
returns_value=False,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _by_name(*callbacks: CallbackInfo) -> dict[str, CallbackInfo]:
|
|
99
|
+
return {cb.py_name: cb for cb in callbacks}
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
PLAY_CALLBACKS = _by_name(
|
|
103
|
+
preprocess_callback,
|
|
104
|
+
spawn_order_callback,
|
|
105
|
+
should_spawn_callback,
|
|
106
|
+
initialize_callback,
|
|
107
|
+
update_sequential_callback,
|
|
108
|
+
touch_callback,
|
|
109
|
+
update_parallel_callback,
|
|
110
|
+
terminate_callback,
|
|
111
|
+
)
|
|
112
|
+
WATCH_ARCHETYPE_CALLBACKS = _by_name(
|
|
113
|
+
preprocess_callback,
|
|
114
|
+
spawn_time_callback,
|
|
115
|
+
despawn_time_callback,
|
|
116
|
+
initialize_callback,
|
|
117
|
+
update_sequential_callback,
|
|
118
|
+
update_parallel_callback,
|
|
119
|
+
terminate_callback,
|
|
120
|
+
)
|
|
121
|
+
WATCH_GLOBAL_CALLBACKS = _by_name(
|
|
122
|
+
update_spawn_callback,
|
|
123
|
+
)
|
|
124
|
+
PREVIEW_CALLBACKS = _by_name(
|
|
125
|
+
preprocess_callback,
|
|
126
|
+
render_callback,
|
|
127
|
+
)
|
sonolus/script/comptime.py
CHANGED
|
@@ -69,7 +69,7 @@ class _Comptime[T, V](GenericValue):
|
|
|
69
69
|
def _from_list_(cls, values: Iterable[float | BlockPlace]) -> Self:
|
|
70
70
|
return cls._instance
|
|
71
71
|
|
|
72
|
-
def _to_list_(self) -> list[float | BlockPlace]:
|
|
72
|
+
def _to_list_(self, level_refs: dict[Any, int] | None = None) -> list[float | BlockPlace]:
|
|
73
73
|
return []
|
|
74
74
|
|
|
75
75
|
@classmethod
|
sonolus/script/containers.py
CHANGED
|
@@ -12,6 +12,26 @@ class Pair[T, U](Record):
|
|
|
12
12
|
first: T
|
|
13
13
|
second: U
|
|
14
14
|
|
|
15
|
+
def __lt__(self, other):
|
|
16
|
+
if self.first == other.first:
|
|
17
|
+
return self.second < other.second
|
|
18
|
+
return self.first < other.first
|
|
19
|
+
|
|
20
|
+
def __le__(self, other):
|
|
21
|
+
if self.first == other.first:
|
|
22
|
+
return self.second <= other.second
|
|
23
|
+
return self.first <= other.first
|
|
24
|
+
|
|
25
|
+
def __gt__(self, other):
|
|
26
|
+
if self.first == other.first:
|
|
27
|
+
return self.second > other.second
|
|
28
|
+
return self.first > other.first
|
|
29
|
+
|
|
30
|
+
def __ge__(self, other):
|
|
31
|
+
if self.first == other.first:
|
|
32
|
+
return self.second >= other.second
|
|
33
|
+
return self.first >= other.first
|
|
34
|
+
|
|
15
35
|
|
|
16
36
|
class VarArray[T, Capacity](Record, ArrayLike[T]):
|
|
17
37
|
_size: int
|
|
@@ -170,6 +190,9 @@ class ArrayMap[K, V, Capacity](Record):
|
|
|
170
190
|
def items(self) -> SonolusIterator[tuple[K, V]]:
|
|
171
191
|
return ArrayMapEntryIterator(self, 0)
|
|
172
192
|
|
|
193
|
+
def __iter__(self):
|
|
194
|
+
return self.keys()
|
|
195
|
+
|
|
173
196
|
def __getitem__(self, key: K) -> V:
|
|
174
197
|
for i in Range(self._size):
|
|
175
198
|
entry = self._array[i]
|