scratchattach 2.1.15b0__py3-none-any.whl → 3.0.0b0__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.
- scratchattach/__init__.py +14 -6
- scratchattach/__main__.py +93 -0
- {scratchattach-2.1.15b0.dist-info → scratchattach-3.0.0b0.dist-info}/METADATA +7 -11
- scratchattach-3.0.0b0.dist-info/RECORD +8 -0
- {scratchattach-2.1.15b0.dist-info → scratchattach-3.0.0b0.dist-info}/WHEEL +1 -1
- scratchattach-3.0.0b0.dist-info/entry_points.txt +2 -0
- scratchattach/cloud/__init__.py +0 -2
- scratchattach/cloud/_base.py +0 -458
- scratchattach/cloud/cloud.py +0 -183
- scratchattach/editor/__init__.py +0 -21
- scratchattach/editor/asset.py +0 -253
- scratchattach/editor/backpack_json.py +0 -117
- scratchattach/editor/base.py +0 -193
- scratchattach/editor/block.py +0 -579
- scratchattach/editor/blockshape.py +0 -357
- scratchattach/editor/build_defaulting.py +0 -51
- scratchattach/editor/code_translation/__init__.py +0 -0
- scratchattach/editor/code_translation/parse.py +0 -177
- scratchattach/editor/comment.py +0 -80
- scratchattach/editor/commons.py +0 -273
- scratchattach/editor/extension.py +0 -50
- scratchattach/editor/field.py +0 -99
- scratchattach/editor/inputs.py +0 -135
- scratchattach/editor/meta.py +0 -114
- scratchattach/editor/monitor.py +0 -183
- scratchattach/editor/mutation.py +0 -324
- scratchattach/editor/pallete.py +0 -90
- scratchattach/editor/prim.py +0 -170
- scratchattach/editor/project.py +0 -279
- scratchattach/editor/sprite.py +0 -599
- scratchattach/editor/twconfig.py +0 -114
- scratchattach/editor/vlb.py +0 -134
- scratchattach/eventhandlers/__init__.py +0 -0
- scratchattach/eventhandlers/_base.py +0 -100
- scratchattach/eventhandlers/cloud_events.py +0 -110
- scratchattach/eventhandlers/cloud_recorder.py +0 -26
- scratchattach/eventhandlers/cloud_requests.py +0 -459
- scratchattach/eventhandlers/cloud_server.py +0 -246
- scratchattach/eventhandlers/cloud_storage.py +0 -136
- scratchattach/eventhandlers/combine.py +0 -30
- scratchattach/eventhandlers/filterbot.py +0 -161
- scratchattach/eventhandlers/message_events.py +0 -42
- scratchattach/other/__init__.py +0 -0
- scratchattach/other/other_apis.py +0 -284
- scratchattach/other/project_json_capabilities.py +0 -475
- scratchattach/site/__init__.py +0 -0
- scratchattach/site/_base.py +0 -66
- scratchattach/site/activity.py +0 -382
- scratchattach/site/alert.py +0 -227
- scratchattach/site/backpack_asset.py +0 -118
- scratchattach/site/browser_cookie3_stub.py +0 -17
- scratchattach/site/browser_cookies.py +0 -61
- scratchattach/site/classroom.py +0 -447
- scratchattach/site/cloud_activity.py +0 -107
- scratchattach/site/comment.py +0 -242
- scratchattach/site/forum.py +0 -432
- scratchattach/site/project.py +0 -826
- scratchattach/site/session.py +0 -1238
- scratchattach/site/studio.py +0 -611
- scratchattach/site/user.py +0 -956
- scratchattach/utils/__init__.py +0 -0
- scratchattach/utils/commons.py +0 -255
- scratchattach/utils/encoder.py +0 -158
- scratchattach/utils/enums.py +0 -236
- scratchattach/utils/exceptions.py +0 -243
- scratchattach/utils/requests.py +0 -93
- scratchattach-2.1.15b0.dist-info/RECORD +0 -66
- {scratchattach-2.1.15b0.dist-info → scratchattach-3.0.0b0.dist-info}/licenses/LICENSE +0 -0
- {scratchattach-2.1.15b0.dist-info → scratchattach-3.0.0b0.dist-info}/top_level.txt +0 -0
scratchattach/editor/prim.py
DELETED
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import warnings
|
|
4
|
-
from dataclasses import dataclass
|
|
5
|
-
from typing import Optional, Callable, Final
|
|
6
|
-
|
|
7
|
-
from . import base, sprite, vlb, commons, build_defaulting
|
|
8
|
-
from scratchattach.utils import enums, exceptions
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@dataclass
|
|
12
|
-
class PrimType(base.JSONSerializable):
|
|
13
|
-
code: int
|
|
14
|
-
name: str
|
|
15
|
-
attrs: list = None
|
|
16
|
-
opcode: str = None
|
|
17
|
-
|
|
18
|
-
def __eq__(self, other):
|
|
19
|
-
if isinstance(other, str):
|
|
20
|
-
return self.name == other
|
|
21
|
-
elif isinstance(other, enums._EnumWrapper):
|
|
22
|
-
other = other.value
|
|
23
|
-
return super().__eq__(other)
|
|
24
|
-
|
|
25
|
-
@staticmethod
|
|
26
|
-
def from_json(data: int):
|
|
27
|
-
return PrimTypes.find(data, "code")
|
|
28
|
-
|
|
29
|
-
def to_json(self) -> int:
|
|
30
|
-
return self.code
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
BASIC_ATTRS: Final[tuple[str]] = ("value",)
|
|
34
|
-
VLB_ATTRS: Final[tuple[str]] = ("name", "id", "x", "y")
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
class PrimTypes(enums._EnumWrapper):
|
|
38
|
-
# Yeah, they actually do have opcodes
|
|
39
|
-
NUMBER = PrimType(4, "number", BASIC_ATTRS, "math_number")
|
|
40
|
-
POSITIVE_NUMBER = PrimType(5, "positive number", BASIC_ATTRS, "math_positive_number")
|
|
41
|
-
POSITIVE_INTEGER = PrimType(6, "positive integer", BASIC_ATTRS, "math_whole_number")
|
|
42
|
-
INTEGER = PrimType(7, "integer", BASIC_ATTRS, "math_integer")
|
|
43
|
-
ANGLE = PrimType(8, "angle", BASIC_ATTRS, "math_angle")
|
|
44
|
-
COLOR = PrimType(9, "color", BASIC_ATTRS, "colour_picker")
|
|
45
|
-
STRING = PrimType(10, "string", BASIC_ATTRS, "text")
|
|
46
|
-
BROADCAST = PrimType(11, "broadcast", VLB_ATTRS, "event_broadcast_menu")
|
|
47
|
-
VARIABLE = PrimType(12, "variable", VLB_ATTRS, "data_variable")
|
|
48
|
-
LIST = PrimType(13, "list", VLB_ATTRS, "data_listcontents")
|
|
49
|
-
|
|
50
|
-
@classmethod
|
|
51
|
-
def find(cls, value, by: str, apply_func: Optional[Callable] = None) -> PrimType:
|
|
52
|
-
return super().find(value, by, apply_func=apply_func)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def is_prim_opcode(opcode: str):
|
|
56
|
-
return opcode in PrimTypes.all_of("opcode") and opcode is not None
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
class Prim(base.SpriteSubComponent):
|
|
60
|
-
def __init__(self, _primtype: PrimType | PrimTypes, _value: Optional[str | vlb.Variable | vlb.List | vlb.Broadcast] = None,
|
|
61
|
-
_name: Optional[str] = None, _id: Optional[str] = None, _x: Optional[int] = None,
|
|
62
|
-
_y: Optional[int] = None, _sprite: sprite.Sprite = build_defaulting.SPRITE_DEFAULT):
|
|
63
|
-
"""
|
|
64
|
-
Class representing a Scratch string, number, angle, variable etc.
|
|
65
|
-
Technically blocks but behave differently
|
|
66
|
-
https://en.scratch-wiki.info/wiki/Scratch_File_Format#Targets:~:text=A%20few%20blocks,13
|
|
67
|
-
"""
|
|
68
|
-
if isinstance(_primtype, PrimTypes):
|
|
69
|
-
_primtype = _primtype.value
|
|
70
|
-
|
|
71
|
-
self.type = _primtype
|
|
72
|
-
|
|
73
|
-
self.value = _value
|
|
74
|
-
|
|
75
|
-
self.name = _name
|
|
76
|
-
"""
|
|
77
|
-
Once you get the object associated with this primitive (sprite.link_prims()),
|
|
78
|
-
the name will be removed and the value will be changed from ``None``
|
|
79
|
-
"""
|
|
80
|
-
self.value_id = _id
|
|
81
|
-
"""
|
|
82
|
-
It's not an object accessed by id, but it may reference an object with an id.
|
|
83
|
-
|
|
84
|
-
----
|
|
85
|
-
|
|
86
|
-
Once you get the object associated with it (sprite.link_prims()),
|
|
87
|
-
the id will be removed and the value will be changed from ``None``
|
|
88
|
-
"""
|
|
89
|
-
|
|
90
|
-
self.x = _x
|
|
91
|
-
self.y = _y
|
|
92
|
-
|
|
93
|
-
super().__init__(_sprite)
|
|
94
|
-
|
|
95
|
-
def __repr__(self):
|
|
96
|
-
if self.is_basic:
|
|
97
|
-
return f"Prim<{self.type.name}: {self.value}>"
|
|
98
|
-
elif self.is_vlb:
|
|
99
|
-
return f"Prim<{self.type.name}: {self.value}>"
|
|
100
|
-
else:
|
|
101
|
-
return f"Prim<{self.type.name}>"
|
|
102
|
-
|
|
103
|
-
@property
|
|
104
|
-
def is_vlb(self):
|
|
105
|
-
return self.type.attrs == VLB_ATTRS
|
|
106
|
-
|
|
107
|
-
@property
|
|
108
|
-
def is_basic(self):
|
|
109
|
-
return self.type.attrs == BASIC_ATTRS
|
|
110
|
-
|
|
111
|
-
@staticmethod
|
|
112
|
-
def from_json(data: list):
|
|
113
|
-
assert isinstance(data, list)
|
|
114
|
-
|
|
115
|
-
_type_idx = data[0]
|
|
116
|
-
_prim_type = PrimTypes.find(_type_idx, "code")
|
|
117
|
-
|
|
118
|
-
_value, _name, _value_id, _x, _y = (None,) * 5
|
|
119
|
-
if _prim_type.attrs == BASIC_ATTRS:
|
|
120
|
-
assert len(data) == 2
|
|
121
|
-
_value = data[1]
|
|
122
|
-
|
|
123
|
-
elif _prim_type.attrs == VLB_ATTRS:
|
|
124
|
-
assert len(data) in (3, 5)
|
|
125
|
-
_name, _value_id = data[1:3]
|
|
126
|
-
|
|
127
|
-
if len(data) == 5:
|
|
128
|
-
_x, _y = data[3:]
|
|
129
|
-
|
|
130
|
-
return Prim(_prim_type, _value, _name, _value_id, _x, _y)
|
|
131
|
-
|
|
132
|
-
def to_json(self) -> list:
|
|
133
|
-
if self.type.attrs == BASIC_ATTRS:
|
|
134
|
-
return [self.type.code, self.value]
|
|
135
|
-
else:
|
|
136
|
-
return commons.trim_final_nones([self.type.code, self.value.name, self.value.id, self.x, self.y])
|
|
137
|
-
|
|
138
|
-
def link_using_sprite(self):
|
|
139
|
-
# Link prim to var/list/broadcast
|
|
140
|
-
if self.is_vlb:
|
|
141
|
-
if self.type.name == "variable":
|
|
142
|
-
self.value = self.sprite.find_variable(self.value_id, "id")
|
|
143
|
-
|
|
144
|
-
elif self.type.name == "list":
|
|
145
|
-
self.value = self.sprite.find_list(self.value_id, "id")
|
|
146
|
-
|
|
147
|
-
elif self.type.name == "broadcast":
|
|
148
|
-
self.value = self.sprite.find_broadcast(self.value_id, "id")
|
|
149
|
-
else:
|
|
150
|
-
# This should never happen
|
|
151
|
-
raise exceptions.BadVLBPrimitiveError(f"{self} claims to be VLB, but is {self.type.name}")
|
|
152
|
-
|
|
153
|
-
if self.value is None:
|
|
154
|
-
if not self.project:
|
|
155
|
-
new_vlb = vlb.construct(self.type.name.lower(), self.value_id, self.name)
|
|
156
|
-
self.sprite.add_local_global(new_vlb)
|
|
157
|
-
self.value = new_vlb
|
|
158
|
-
|
|
159
|
-
else:
|
|
160
|
-
new_vlb = vlb.construct(self.type.name.lower(), self.value_id, self.name)
|
|
161
|
-
self.sprite.stage.add_vlb(new_vlb)
|
|
162
|
-
|
|
163
|
-
warnings.warn(
|
|
164
|
-
f"Prim<name={self.name!r}, id={self.name!r}> has unknown {self.type.name} id; adding as global variable")
|
|
165
|
-
self.name = None
|
|
166
|
-
self.value_id = None
|
|
167
|
-
|
|
168
|
-
@property
|
|
169
|
-
def can_next(self):
|
|
170
|
-
return False
|
scratchattach/editor/project.py
DELETED
|
@@ -1,279 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import json
|
|
4
|
-
import os
|
|
5
|
-
import warnings
|
|
6
|
-
from io import BytesIO, TextIOWrapper
|
|
7
|
-
from typing import Optional, Iterable, Generator, BinaryIO
|
|
8
|
-
from zipfile import ZipFile
|
|
9
|
-
|
|
10
|
-
from . import base, meta, extension, monitor, sprite, asset, vlb, twconfig, comment, commons
|
|
11
|
-
from scratchattach.site import session
|
|
12
|
-
from scratchattach.site.project import get_project
|
|
13
|
-
from scratchattach.utils import exceptions
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class Project(base.JSONExtractable):
|
|
17
|
-
"""
|
|
18
|
-
sa.editor's equivalent of the ProjectBody. Represents the editor contents of a scratch project
|
|
19
|
-
"""
|
|
20
|
-
def __init__(self, _name: Optional[str] = None, _meta: Optional[meta.Meta] = None, _extensions: Iterable[extension.Extension] = (),
|
|
21
|
-
_monitors: Iterable[monitor.Monitor] = (), _sprites: Iterable[sprite.Sprite] = (), *,
|
|
22
|
-
_asset_data: Optional[list[asset.AssetFile]] = None, _session: Optional[session.Session] = None):
|
|
23
|
-
# Defaulting for list parameters
|
|
24
|
-
if _meta is None:
|
|
25
|
-
_meta = meta.Meta()
|
|
26
|
-
if _asset_data is None:
|
|
27
|
-
_asset_data = []
|
|
28
|
-
|
|
29
|
-
self._session = _session
|
|
30
|
-
|
|
31
|
-
self.name = _name
|
|
32
|
-
|
|
33
|
-
self.meta = _meta
|
|
34
|
-
self.extensions = _extensions
|
|
35
|
-
self.monitors = list(_monitors)
|
|
36
|
-
self.sprites = list(_sprites)
|
|
37
|
-
|
|
38
|
-
self.asset_data = _asset_data
|
|
39
|
-
|
|
40
|
-
self._tw_config_comment = None
|
|
41
|
-
|
|
42
|
-
# Link subcomponents
|
|
43
|
-
for iterable in (self.monitors, self.sprites):
|
|
44
|
-
for _subcomponent in iterable:
|
|
45
|
-
_subcomponent.project = self
|
|
46
|
-
|
|
47
|
-
# Link sprites
|
|
48
|
-
_stage_count = 0
|
|
49
|
-
|
|
50
|
-
for _sprite in self.sprites:
|
|
51
|
-
if _sprite.is_stage:
|
|
52
|
-
_stage_count += 1
|
|
53
|
-
|
|
54
|
-
_sprite.link_subcomponents()
|
|
55
|
-
|
|
56
|
-
# Link monitors
|
|
57
|
-
for _monitor in self.monitors:
|
|
58
|
-
_monitor.link_using_project()
|
|
59
|
-
|
|
60
|
-
if _stage_count != 1:
|
|
61
|
-
raise exceptions.InvalidStageCount(f"Project {self}")
|
|
62
|
-
|
|
63
|
-
def __repr__(self):
|
|
64
|
-
_ret = "Project<"
|
|
65
|
-
if self.name is not None:
|
|
66
|
-
_ret += f"name={self.name}, "
|
|
67
|
-
_ret += f"meta={self.meta}"
|
|
68
|
-
_ret += '>'
|
|
69
|
-
return _ret
|
|
70
|
-
|
|
71
|
-
@property
|
|
72
|
-
def stage(self) -> sprite.Sprite:
|
|
73
|
-
for _sprite in self.sprites:
|
|
74
|
-
if _sprite.is_stage:
|
|
75
|
-
return _sprite
|
|
76
|
-
warnings.warn(f"Could not find stage for {self.name}")
|
|
77
|
-
|
|
78
|
-
def to_json(self) -> dict:
|
|
79
|
-
_json = {
|
|
80
|
-
"targets": [_sprite.to_json() for _sprite in self.sprites],
|
|
81
|
-
"monitors": [_monitor.to_json() for _monitor in self.monitors],
|
|
82
|
-
"extensions": [_extension.to_json() for _extension in self.extensions],
|
|
83
|
-
"meta": self.meta.to_json(),
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return _json
|
|
87
|
-
|
|
88
|
-
@property
|
|
89
|
-
def assets(self) -> Generator[asset.Asset, None, None]:
|
|
90
|
-
for _sprite in self.sprites:
|
|
91
|
-
for _asset in _sprite.assets:
|
|
92
|
-
yield _asset
|
|
93
|
-
|
|
94
|
-
@property
|
|
95
|
-
def tw_config_comment(self) -> comment.Comment | None:
|
|
96
|
-
for _comment in self.stage.comments:
|
|
97
|
-
if twconfig.is_valid_twconfig(_comment.text):
|
|
98
|
-
return _comment
|
|
99
|
-
return None
|
|
100
|
-
|
|
101
|
-
@property
|
|
102
|
-
def tw_config(self) -> twconfig.TWConfig | None:
|
|
103
|
-
_comment = self.tw_config_comment
|
|
104
|
-
if _comment:
|
|
105
|
-
return twconfig.TWConfig.from_str(_comment.text)
|
|
106
|
-
return None
|
|
107
|
-
|
|
108
|
-
@property
|
|
109
|
-
def all_ids(self):
|
|
110
|
-
_ret = []
|
|
111
|
-
for _sprite in self.sprites:
|
|
112
|
-
_ret += _sprite.all_ids
|
|
113
|
-
return _ret
|
|
114
|
-
|
|
115
|
-
@property
|
|
116
|
-
def new_id(self):
|
|
117
|
-
return commons.gen_id()
|
|
118
|
-
|
|
119
|
-
@staticmethod
|
|
120
|
-
def from_json(data: dict):
|
|
121
|
-
assert isinstance(data, dict)
|
|
122
|
-
|
|
123
|
-
# Load metadata
|
|
124
|
-
_meta = meta.Meta.from_json(data.get("meta"))
|
|
125
|
-
|
|
126
|
-
# Load extensions
|
|
127
|
-
_extensions = []
|
|
128
|
-
for _extension_data in data.get("extensions", []):
|
|
129
|
-
_extensions.append(extension.Extension.from_json(_extension_data))
|
|
130
|
-
|
|
131
|
-
# Load monitors
|
|
132
|
-
_monitors = []
|
|
133
|
-
for _monitor_data in data.get("monitors", []):
|
|
134
|
-
_monitors.append(monitor.Monitor.from_json(_monitor_data))
|
|
135
|
-
|
|
136
|
-
# Load sprites (targets)
|
|
137
|
-
_sprites = []
|
|
138
|
-
for _sprite_data in data.get("targets", []):
|
|
139
|
-
_sprites.append(sprite.Sprite.from_json(_sprite_data))
|
|
140
|
-
|
|
141
|
-
return Project(None, _meta, _extensions, _monitors, _sprites)
|
|
142
|
-
|
|
143
|
-
@staticmethod
|
|
144
|
-
def load_json(data: str | bytes | TextIOWrapper | BinaryIO, load_assets: bool = True, _name: Optional[str] = None):
|
|
145
|
-
"""
|
|
146
|
-
Load project JSON and assets from an .sb3 file/bytes/file path
|
|
147
|
-
:return: Project name, asset data, json string
|
|
148
|
-
"""
|
|
149
|
-
_dir_for_name = None
|
|
150
|
-
|
|
151
|
-
if _name is None:
|
|
152
|
-
if hasattr(data, "name"):
|
|
153
|
-
_dir_for_name = data.name
|
|
154
|
-
|
|
155
|
-
if not isinstance(_name, str) and _name is not None:
|
|
156
|
-
_name = str(_name)
|
|
157
|
-
|
|
158
|
-
if isinstance(data, bytes):
|
|
159
|
-
data = BytesIO(data)
|
|
160
|
-
|
|
161
|
-
elif isinstance(data, str):
|
|
162
|
-
_dir_for_name = data
|
|
163
|
-
data = open(data, "rb")
|
|
164
|
-
|
|
165
|
-
if _name is None and _dir_for_name is not None:
|
|
166
|
-
# Remove any directory names and the file extension
|
|
167
|
-
_name = _dir_for_name.split('/')[-1]
|
|
168
|
-
_name = '.'.join(_name.split('.')[:-1])
|
|
169
|
-
|
|
170
|
-
asset_data = []
|
|
171
|
-
with data:
|
|
172
|
-
# For if the sb3 is just JSON (e.g. if it's exported from scratchattach)
|
|
173
|
-
if commons.is_valid_json(data):
|
|
174
|
-
json_str = data
|
|
175
|
-
|
|
176
|
-
else:
|
|
177
|
-
with ZipFile(data) as archive:
|
|
178
|
-
json_str = archive.read("project.json")
|
|
179
|
-
|
|
180
|
-
# Also load assets
|
|
181
|
-
if load_assets:
|
|
182
|
-
for filename in archive.namelist():
|
|
183
|
-
if filename != "project.json":
|
|
184
|
-
md5_hash = filename.split('.')[0]
|
|
185
|
-
|
|
186
|
-
asset_data.append(
|
|
187
|
-
asset.AssetFile(filename, archive.read(filename), md5_hash)
|
|
188
|
-
)
|
|
189
|
-
|
|
190
|
-
else:
|
|
191
|
-
warnings.warn(
|
|
192
|
-
"Loading sb3 without loading assets. When exporting the project, there may be errors due to assets not being uploaded to the Scratch website")
|
|
193
|
-
|
|
194
|
-
return _name, asset_data, json_str
|
|
195
|
-
|
|
196
|
-
@classmethod
|
|
197
|
-
def from_sb3(cls, data: str | bytes | TextIOWrapper | BinaryIO, load_assets: bool = True, _name: Optional[str] = None):
|
|
198
|
-
"""
|
|
199
|
-
Load a project from an .sb3 file/bytes/file path
|
|
200
|
-
"""
|
|
201
|
-
_name, asset_data, json_str = cls.load_json(data, load_assets, _name)
|
|
202
|
-
data = json.loads(json_str)
|
|
203
|
-
|
|
204
|
-
project = cls.from_json(data)
|
|
205
|
-
project.name = _name
|
|
206
|
-
project.asset_data = asset_data
|
|
207
|
-
|
|
208
|
-
return project
|
|
209
|
-
|
|
210
|
-
@staticmethod
|
|
211
|
-
def from_id(project_id: int, _name: Optional[str] = None):
|
|
212
|
-
_proj = get_project(project_id)
|
|
213
|
-
data = json.loads(_proj.get_json())
|
|
214
|
-
|
|
215
|
-
if _name is None:
|
|
216
|
-
_name = _proj.title
|
|
217
|
-
_name = str(_name)
|
|
218
|
-
|
|
219
|
-
_proj = Project.from_json(data)
|
|
220
|
-
_proj.name = _name
|
|
221
|
-
return _proj
|
|
222
|
-
|
|
223
|
-
def find_vlb(self, value: str | None, by: str = "name",
|
|
224
|
-
multiple: bool = False) -> vlb.Variable | vlb.List | vlb.Broadcast | list[
|
|
225
|
-
vlb.Variable | vlb.List | vlb.Broadcast]:
|
|
226
|
-
_ret = []
|
|
227
|
-
for _sprite in self.sprites:
|
|
228
|
-
val = _sprite.find_vlb(value, by, multiple)
|
|
229
|
-
if multiple:
|
|
230
|
-
_ret += val
|
|
231
|
-
else:
|
|
232
|
-
if val is not None:
|
|
233
|
-
return val
|
|
234
|
-
if multiple:
|
|
235
|
-
return _ret
|
|
236
|
-
|
|
237
|
-
def find_sprite(self, value: str | None, by: str = "name",
|
|
238
|
-
multiple: bool = False) -> sprite.Sprite | list[sprite.Sprite]:
|
|
239
|
-
_ret = []
|
|
240
|
-
for _sprite in self.sprites:
|
|
241
|
-
if by == "name":
|
|
242
|
-
_val = _sprite.name
|
|
243
|
-
else:
|
|
244
|
-
_val = getattr(_sprite, by)
|
|
245
|
-
|
|
246
|
-
if _val == value:
|
|
247
|
-
if multiple:
|
|
248
|
-
_ret.append(_sprite)
|
|
249
|
-
else:
|
|
250
|
-
return _sprite
|
|
251
|
-
|
|
252
|
-
if multiple:
|
|
253
|
-
return _ret
|
|
254
|
-
|
|
255
|
-
def export(self, fp: str, *, auto_open: bool = False, export_as_zip: bool = True):
|
|
256
|
-
data = self.to_json()
|
|
257
|
-
|
|
258
|
-
if export_as_zip:
|
|
259
|
-
with ZipFile(fp, "w") as archive:
|
|
260
|
-
for _asset in self.assets:
|
|
261
|
-
asset_file = _asset.asset_file
|
|
262
|
-
if asset_file.filename not in archive.namelist():
|
|
263
|
-
archive.writestr(asset_file.filename, asset_file.data)
|
|
264
|
-
|
|
265
|
-
archive.writestr("project.json", json.dumps(data))
|
|
266
|
-
else:
|
|
267
|
-
with open(fp, "w") as json_file:
|
|
268
|
-
json.dump(data, json_file)
|
|
269
|
-
|
|
270
|
-
if auto_open:
|
|
271
|
-
os.system(f"explorer.exe \"{fp}\"")
|
|
272
|
-
|
|
273
|
-
def add_monitor(self, _monitor: monitor.Monitor) -> monitor.Monitor:
|
|
274
|
-
"""
|
|
275
|
-
Bind a monitor to this project. Doing these manually can lead to interesting results.
|
|
276
|
-
"""
|
|
277
|
-
_monitor.project = self
|
|
278
|
-
_monitor.reporter_id = self.new_id
|
|
279
|
-
self.monitors.append(_monitor)
|