amulet-core 2.0a5__cp312-cp312-macosx_10_13_universal2.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 amulet-core might be problematic. Click here for more details.

Files changed (210) hide show
  1. amulet/__init__.cpython-312-darwin.so +0 -0
  2. amulet/__init__.pyi +30 -0
  3. amulet/__pyinstaller/__init__.py +2 -0
  4. amulet/__pyinstaller/hook-amulet.py +4 -0
  5. amulet/_init.py +28 -0
  6. amulet/_version.py +21 -0
  7. amulet/biome.cpp +36 -0
  8. amulet/biome.hpp +43 -0
  9. amulet/biome.pyi +77 -0
  10. amulet/block.cpp +435 -0
  11. amulet/block.hpp +119 -0
  12. amulet/block.pyi +273 -0
  13. amulet/block_entity.cpp +12 -0
  14. amulet/block_entity.hpp +56 -0
  15. amulet/block_entity.pyi +80 -0
  16. amulet/chunk.cpp +16 -0
  17. amulet/chunk.hpp +99 -0
  18. amulet/chunk.pyi +30 -0
  19. amulet/chunk_/components/biome.py +155 -0
  20. amulet/chunk_/components/block_entity.py +117 -0
  21. amulet/chunk_/components/entity.py +64 -0
  22. amulet/chunk_/components/height_2d.py +16 -0
  23. amulet/chunk_components.pyi +95 -0
  24. amulet/collections.pyi +37 -0
  25. amulet/data_types.py +29 -0
  26. amulet/entity.py +180 -0
  27. amulet/errors.py +63 -0
  28. amulet/game/__init__.py +7 -0
  29. amulet/game/_game.py +152 -0
  30. amulet/game/_universal/__init__.py +1 -0
  31. amulet/game/_universal/_biome.py +17 -0
  32. amulet/game/_universal/_block.py +47 -0
  33. amulet/game/_universal/_version.py +68 -0
  34. amulet/game/abc/__init__.py +22 -0
  35. amulet/game/abc/_block_specification.py +150 -0
  36. amulet/game/abc/biome.py +213 -0
  37. amulet/game/abc/block.py +331 -0
  38. amulet/game/abc/game_version_container.py +25 -0
  39. amulet/game/abc/json_interface.py +27 -0
  40. amulet/game/abc/version.py +44 -0
  41. amulet/game/bedrock/__init__.py +1 -0
  42. amulet/game/bedrock/_biome.py +35 -0
  43. amulet/game/bedrock/_block.py +42 -0
  44. amulet/game/bedrock/_version.py +165 -0
  45. amulet/game/java/__init__.py +2 -0
  46. amulet/game/java/_biome.py +35 -0
  47. amulet/game/java/_block.py +60 -0
  48. amulet/game/java/_version.py +176 -0
  49. amulet/game/translate/__init__.py +12 -0
  50. amulet/game/translate/_functions/__init__.py +15 -0
  51. amulet/game/translate/_functions/_code_functions/__init__.py +0 -0
  52. amulet/game/translate/_functions/_code_functions/_text.py +553 -0
  53. amulet/game/translate/_functions/_code_functions/banner_pattern.py +67 -0
  54. amulet/game/translate/_functions/_code_functions/bedrock_chest_connection.py +152 -0
  55. amulet/game/translate/_functions/_code_functions/bedrock_moving_block_pos.py +88 -0
  56. amulet/game/translate/_functions/_code_functions/bedrock_sign.py +152 -0
  57. amulet/game/translate/_functions/_code_functions/bedrock_skull_rotation.py +16 -0
  58. amulet/game/translate/_functions/_code_functions/custom_name.py +146 -0
  59. amulet/game/translate/_functions/_frozen.py +66 -0
  60. amulet/game/translate/_functions/_state.py +54 -0
  61. amulet/game/translate/_functions/_typing.py +98 -0
  62. amulet/game/translate/_functions/abc.py +116 -0
  63. amulet/game/translate/_functions/carry_nbt.py +160 -0
  64. amulet/game/translate/_functions/carry_properties.py +80 -0
  65. amulet/game/translate/_functions/code.py +143 -0
  66. amulet/game/translate/_functions/map_block_name.py +66 -0
  67. amulet/game/translate/_functions/map_nbt.py +111 -0
  68. amulet/game/translate/_functions/map_properties.py +93 -0
  69. amulet/game/translate/_functions/multiblock.py +112 -0
  70. amulet/game/translate/_functions/new_block.py +42 -0
  71. amulet/game/translate/_functions/new_entity.py +43 -0
  72. amulet/game/translate/_functions/new_nbt.py +206 -0
  73. amulet/game/translate/_functions/new_properties.py +64 -0
  74. amulet/game/translate/_functions/sequence.py +51 -0
  75. amulet/game/translate/_functions/walk_input_nbt.py +331 -0
  76. amulet/game/translate/_translator.py +433 -0
  77. amulet/item.py +75 -0
  78. amulet/level/__init__.pyi +27 -0
  79. amulet/level/_load.py +100 -0
  80. amulet/level/abc/__init__.py +12 -0
  81. amulet/level/abc/_chunk_handle.py +335 -0
  82. amulet/level/abc/_dimension.py +86 -0
  83. amulet/level/abc/_history/__init__.py +1 -0
  84. amulet/level/abc/_history/_cache.py +224 -0
  85. amulet/level/abc/_history/_history_manager.py +291 -0
  86. amulet/level/abc/_level/__init__.py +5 -0
  87. amulet/level/abc/_level/_compactable_level.py +10 -0
  88. amulet/level/abc/_level/_creatable_level.py +29 -0
  89. amulet/level/abc/_level/_disk_level.py +17 -0
  90. amulet/level/abc/_level/_level.py +453 -0
  91. amulet/level/abc/_level/_loadable_level.py +42 -0
  92. amulet/level/abc/_player_storage.py +7 -0
  93. amulet/level/abc/_raw_level.py +187 -0
  94. amulet/level/abc/_registry.py +40 -0
  95. amulet/level/bedrock/__init__.py +2 -0
  96. amulet/level/bedrock/_chunk_handle.py +19 -0
  97. amulet/level/bedrock/_dimension.py +22 -0
  98. amulet/level/bedrock/_level.py +187 -0
  99. amulet/level/bedrock/_raw/__init__.py +5 -0
  100. amulet/level/bedrock/_raw/_actor_counter.py +53 -0
  101. amulet/level/bedrock/_raw/_chunk.py +54 -0
  102. amulet/level/bedrock/_raw/_chunk_decode.py +668 -0
  103. amulet/level/bedrock/_raw/_chunk_encode.py +602 -0
  104. amulet/level/bedrock/_raw/_constant.py +9 -0
  105. amulet/level/bedrock/_raw/_dimension.py +343 -0
  106. amulet/level/bedrock/_raw/_level.py +463 -0
  107. amulet/level/bedrock/_raw/_level_dat.py +90 -0
  108. amulet/level/bedrock/_raw/_typing.py +6 -0
  109. amulet/level/bedrock/_raw/leveldb_chunk_versions.py +83 -0
  110. amulet/level/bedrock/chunk/__init__.py +1 -0
  111. amulet/level/bedrock/chunk/_chunk.py +126 -0
  112. amulet/level/bedrock/chunk/components/__init__.py +0 -0
  113. amulet/level/bedrock/chunk/components/chunk_version.py +12 -0
  114. amulet/level/bedrock/chunk/components/finalised_state.py +13 -0
  115. amulet/level/bedrock/chunk/components/raw_chunk.py +15 -0
  116. amulet/level/construction/__init__.py +0 -0
  117. amulet/level/java/__init__.pyi +21 -0
  118. amulet/level/java/_chunk_handle.py +17 -0
  119. amulet/level/java/_chunk_handle.pyi +15 -0
  120. amulet/level/java/_dimension.py +20 -0
  121. amulet/level/java/_dimension.pyi +13 -0
  122. amulet/level/java/_level.py +184 -0
  123. amulet/level/java/_level.pyi +120 -0
  124. amulet/level/java/_raw/__init__.pyi +19 -0
  125. amulet/level/java/_raw/_chunk.pyi +23 -0
  126. amulet/level/java/_raw/_chunk_decode.py +561 -0
  127. amulet/level/java/_raw/_chunk_encode.py +463 -0
  128. amulet/level/java/_raw/_constant.py +9 -0
  129. amulet/level/java/_raw/_constant.pyi +20 -0
  130. amulet/level/java/_raw/_data_pack/__init__.py +2 -0
  131. amulet/level/java/_raw/_data_pack/__init__.pyi +8 -0
  132. amulet/level/java/_raw/_data_pack/data_pack.py +241 -0
  133. amulet/level/java/_raw/_data_pack/data_pack.pyi +197 -0
  134. amulet/level/java/_raw/_data_pack/data_pack_manager.py +77 -0
  135. amulet/level/java/_raw/_data_pack/data_pack_manager.pyi +75 -0
  136. amulet/level/java/_raw/_dimension.py +86 -0
  137. amulet/level/java/_raw/_dimension.pyi +72 -0
  138. amulet/level/java/_raw/_level.py +507 -0
  139. amulet/level/java/_raw/_level.pyi +238 -0
  140. amulet/level/java/_raw/_typing.py +3 -0
  141. amulet/level/java/_raw/_typing.pyi +5 -0
  142. amulet/level/java/anvil/__init__.py +2 -0
  143. amulet/level/java/anvil/__init__.pyi +11 -0
  144. amulet/level/java/anvil/_dimension.py +170 -0
  145. amulet/level/java/anvil/_dimension.pyi +109 -0
  146. amulet/level/java/anvil/_region.py +421 -0
  147. amulet/level/java/anvil/_region.pyi +197 -0
  148. amulet/level/java/anvil/_sector_manager.py +223 -0
  149. amulet/level/java/anvil/_sector_manager.pyi +142 -0
  150. amulet/level/java/chunk.pyi +81 -0
  151. amulet/level/java/chunk_/_chunk.py +260 -0
  152. amulet/level/java/chunk_/components/inhabited_time.py +12 -0
  153. amulet/level/java/chunk_/components/last_update.py +12 -0
  154. amulet/level/java/chunk_/components/legacy_version.py +12 -0
  155. amulet/level/java/chunk_/components/light_populated.py +12 -0
  156. amulet/level/java/chunk_/components/named_height_2d.py +37 -0
  157. amulet/level/java/chunk_/components/status.py +11 -0
  158. amulet/level/java/chunk_/components/terrain_populated.py +12 -0
  159. amulet/level/java/chunk_components.pyi +22 -0
  160. amulet/level/java/long_array.pyi +38 -0
  161. amulet/level/java_forge/__init__.py +0 -0
  162. amulet/level/mcstructure/__init__.py +0 -0
  163. amulet/level/nbt/__init__.py +0 -0
  164. amulet/level/schematic/__init__.py +0 -0
  165. amulet/level/sponge_schematic/__init__.py +0 -0
  166. amulet/level/temporary_level/__init__.py +1 -0
  167. amulet/level/temporary_level/_level.py +16 -0
  168. amulet/palette/__init__.pyi +8 -0
  169. amulet/palette/biome_palette.pyi +45 -0
  170. amulet/palette/block_palette.pyi +45 -0
  171. amulet/player.py +64 -0
  172. amulet/py.typed +0 -0
  173. amulet/selection/__init__.py +2 -0
  174. amulet/selection/abstract_selection.py +342 -0
  175. amulet/selection/box.py +852 -0
  176. amulet/selection/group.py +481 -0
  177. amulet/utils/__init__.pyi +28 -0
  178. amulet/utils/call_spec/__init__.py +24 -0
  179. amulet/utils/call_spec/__init__.pyi +53 -0
  180. amulet/utils/call_spec/_call_spec.py +262 -0
  181. amulet/utils/call_spec/_call_spec.pyi +272 -0
  182. amulet/utils/format_utils.py +41 -0
  183. amulet/utils/generator.py +18 -0
  184. amulet/utils/matrix.py +243 -0
  185. amulet/utils/matrix.pyi +177 -0
  186. amulet/utils/numpy.pyi +11 -0
  187. amulet/utils/numpy_helpers.py +19 -0
  188. amulet/utils/shareable_lock.py +335 -0
  189. amulet/utils/shareable_lock.pyi +190 -0
  190. amulet/utils/signal/__init__.py +10 -0
  191. amulet/utils/signal/__init__.pyi +25 -0
  192. amulet/utils/signal/_signal.py +228 -0
  193. amulet/utils/signal/_signal.pyi +84 -0
  194. amulet/utils/task_manager.py +235 -0
  195. amulet/utils/task_manager.pyi +168 -0
  196. amulet/utils/typed_property.py +111 -0
  197. amulet/utils/typing.py +4 -0
  198. amulet/utils/typing.pyi +6 -0
  199. amulet/utils/weakref.py +70 -0
  200. amulet/utils/weakref.pyi +50 -0
  201. amulet/utils/world_utils.py +102 -0
  202. amulet/utils/world_utils.pyi +109 -0
  203. amulet/version.cpp +136 -0
  204. amulet/version.hpp +142 -0
  205. amulet/version.pyi +94 -0
  206. amulet_core-2.0a5.dist-info/METADATA +103 -0
  207. amulet_core-2.0a5.dist-info/RECORD +210 -0
  208. amulet_core-2.0a5.dist-info/WHEEL +5 -0
  209. amulet_core-2.0a5.dist-info/entry_points.txt +2 -0
  210. amulet_core-2.0a5.dist-info/top_level.txt +1 -0
@@ -0,0 +1,291 @@
1
+ from __future__ import annotations
2
+
3
+ from uuid import uuid4
4
+ from threading import Lock
5
+ from typing import Sequence, Protocol, TypeVar, Generic, Mapping, Any
6
+ from weakref import WeakSet, WeakValueDictionary
7
+ from collections.abc import MutableMapping
8
+
9
+ from amulet.utils.signal import Signal, SignalInstanceCacheName
10
+
11
+ from ._cache import GlobalDiskCache
12
+
13
+ # TODO: consider adding a max undo option
14
+ # TODO: if we clear old undo info we should remove that data from the cache
15
+ # TODO: compact the cache periodically
16
+
17
+
18
+ class ResourceId(Protocol):
19
+ def __hash__(self) -> int:
20
+ """A constant hash"""
21
+ ...
22
+
23
+ def __eq__(self, other: Any) -> bool: ...
24
+
25
+ def __bytes__(self) -> bytes:
26
+ """A constant bytes representation"""
27
+ ...
28
+
29
+
30
+ ResourceIdT = TypeVar("ResourceIdT", bound=ResourceId)
31
+
32
+
33
+ class Resource:
34
+ __slots__ = ("index", "saved_index", "global_index", "exists")
35
+
36
+ def __init__(self) -> None:
37
+ # The index of the currently active revision
38
+ self.index: int = 0
39
+ # The index of the saved revision. -1 if the index no longer exists (overwritten or destroyed future)
40
+ self.saved_index: int = 0
41
+ # The global history index
42
+ self.global_index: int = 0
43
+ # Does the resource data exist
44
+ self.exists: list[bool] = [True]
45
+
46
+ def get_resource_key(self, uuid: bytes, resource_id: ResourceId) -> bytes:
47
+ return b"/".join((uuid, bytes(resource_id), str(self.index).encode()))
48
+
49
+
50
+ class HistoryManagerPrivate:
51
+ lock: Lock
52
+ resources: WeakValueDictionary[bytes, MutableMapping[ResourceId, Resource]]
53
+ history: list[WeakSet[Resource]]
54
+ history_index: int
55
+ has_redo: bool
56
+ cache: GlobalDiskCache
57
+
58
+ def __init__(self) -> None:
59
+ self.lock = Lock()
60
+ self.resources = WeakValueDictionary()
61
+ self.history = [WeakSet()]
62
+ self.history_index = 0
63
+ self.has_redo = False
64
+ self.cache = GlobalDiskCache.instance()
65
+
66
+ def invalidate_future(self) -> None:
67
+ """Destroy all future redo bins. Caller must acquire the lock"""
68
+ if self.has_redo:
69
+ self.has_redo = False
70
+ del self.history[self.history_index + 1 :]
71
+ for layer in self.resources.values():
72
+ for resource in layer.values():
73
+ if resource.saved_index > resource.index:
74
+ # A future index is saved that just got invalidated
75
+ resource.saved_index = -1
76
+
77
+ def reset(self) -> None:
78
+ with self.lock:
79
+ for layer in self.resources.values():
80
+ layer.clear()
81
+ self.history = [WeakSet()]
82
+ self.history_index = 0
83
+ self.has_redo = False
84
+
85
+
86
+ class CustomDict(dict):
87
+ pass
88
+
89
+
90
+ class HistoryManager:
91
+ __slots__ = (SignalInstanceCacheName, "_h")
92
+
93
+ _h: HistoryManagerPrivate
94
+
95
+ def __init__(self) -> None:
96
+ self._h = HistoryManagerPrivate()
97
+
98
+ def new_layer(self) -> HistoryManagerLayer:
99
+ uuid = uuid4().bytes
100
+ resources: MutableMapping[ResourceId, Resource] = CustomDict()
101
+ self._h.resources[uuid] = resources
102
+ return HistoryManagerLayer(self._h, uuid, resources)
103
+
104
+ history_changed = Signal[()]()
105
+
106
+ def create_undo_bin(self) -> None:
107
+ """
108
+ Call this to create a new undo bin.
109
+ All changes made after this point will be part of the same undo bin until this is called again.
110
+ If this is not called, all changes will be part of the previous undo bin.
111
+ """
112
+ with self._h.lock:
113
+ self._h.invalidate_future()
114
+ self._h.history_index += 1
115
+ self._h.history.append(WeakSet())
116
+
117
+ def mark_saved(self) -> None:
118
+ with self._h.lock:
119
+ for layer in self._h.resources.values():
120
+ for resource in layer.values():
121
+ resource.saved_index = resource.index
122
+
123
+ @property
124
+ def undo_count(self) -> int:
125
+ """The number of times undo can be called."""
126
+ with self._h.lock:
127
+ return self._h.history_index
128
+
129
+ def undo(self) -> None:
130
+ """Undo the changes in the current undo bin."""
131
+ with self._h.lock:
132
+ if self._h.history_index <= 0:
133
+ raise RuntimeError
134
+ for resource in self._h.history[self._h.history_index]:
135
+ resource.index -= 1
136
+ self._h.history_index -= 1
137
+ self._h.has_redo = True
138
+
139
+ def _redo_count(self) -> int:
140
+ return len(self._h.history) - (self._h.history_index + 1)
141
+
142
+ @property
143
+ def redo_count(self) -> int:
144
+ """The number of times redo can be called."""
145
+ with self._h.lock:
146
+ return self._redo_count()
147
+
148
+ def redo(self) -> None:
149
+ """Redo the changes in the next undo bin."""
150
+ with self._h.lock:
151
+ if not self._h.has_redo:
152
+ raise RuntimeError
153
+ self._h.history_index += 1
154
+ for resource in self._h.history[self._h.history_index]:
155
+ resource.index += 1
156
+ self._h.has_redo = bool(self._redo_count())
157
+
158
+ def reset(self) -> None:
159
+ """Reset to the factory state."""
160
+ self._h.reset()
161
+
162
+
163
+ class HistoryManagerLayer(Generic[ResourceIdT]):
164
+ __slots__ = ("_h", "_uuid", "_resources")
165
+
166
+ _h: HistoryManagerPrivate
167
+ _uuid: bytes
168
+ _resources: MutableMapping[ResourceIdT, Resource]
169
+
170
+ def __init__(
171
+ self,
172
+ _h: HistoryManagerPrivate,
173
+ uuid: bytes,
174
+ resources: MutableMapping[ResourceIdT, Resource],
175
+ ) -> None:
176
+ """This must not be used directly."""
177
+ self._h = _h
178
+ self._uuid = uuid
179
+ self._resources = resources
180
+
181
+ def resources(self) -> Sequence[ResourceIdT]:
182
+ """
183
+ Get all resource ids from this layer.
184
+ :return:
185
+ """
186
+ with self._h.lock:
187
+ return list(self._resources)
188
+
189
+ def changed_resources(self) -> Sequence[ResourceIdT]:
190
+ """
191
+ Get all resource ids from this layer that have changed since the last call to mark_saved.
192
+ :return:
193
+ """
194
+ with self._h.lock:
195
+ return [
196
+ resource_id
197
+ for resource_id, resource in self._resources.items()
198
+ if resource.saved_index != resource.index
199
+ ]
200
+
201
+ def resources_exist_map(self) -> Mapping[ResourceIdT, bool]:
202
+ """
203
+ Get a mapping from the resource ids to a bool stating if the data exists for that resource.
204
+ If false that resource has been deleted.
205
+ """
206
+ with self._h.lock:
207
+ return {
208
+ resource_id: resource.exists[resource.index]
209
+ for resource_id, resource in self._resources.items()
210
+ }
211
+
212
+ def has_resource(self, resource_id: ResourceIdT) -> bool:
213
+ """
214
+ Check if a resource entry exists.
215
+ If the resource has been loaded this will be True regardless if the resource data has been deleted.
216
+ Use :meth:`resource_exists` to check if the resource data has been deleted.
217
+ Calling :meth:`get_resource` or :meth:`set_resource` when this is False will error.
218
+ :param resource_id: The resource identifier
219
+ :return:
220
+ """
221
+ with self._h.lock:
222
+ return resource_id in self._resources
223
+
224
+ def resource_exists(self, resource_id: ResourceIdT) -> bool:
225
+ """
226
+ A fast way to check if the resource data exists without loading it.
227
+ :param resource_id: The resource identifier
228
+ :return: True if the data exists.
229
+ """
230
+ with self._h.lock:
231
+ resource = self._resources[resource_id]
232
+ return resource.exists[resource.index]
233
+
234
+ def get_resource(self, resource_id: ResourceIdT) -> bytes:
235
+ """
236
+ Get the newest resource data.
237
+ :param resource_id: The resource identifier
238
+ :return: The binary data that was previously set. An empty bytes object for the deleted state.
239
+ """
240
+ with self._h.lock:
241
+ resource = self._resources[resource_id]
242
+ if resource.exists[resource.index]:
243
+ return self._h.cache[resource.get_resource_key(self._uuid, resource_id)]
244
+ else:
245
+ return b""
246
+
247
+ def set_initial_resource(self, resource_id: ResourceIdT, data: bytes) -> None:
248
+ """
249
+ Set the data for the resource.
250
+ This can only be used if the resource does not already exist.
251
+ :param resource_id: The resource identifier
252
+ :param data: The binary data to set. An empty bytes object for the deleted state.
253
+ :return:
254
+ """
255
+ with self._h.lock:
256
+ if resource_id in self._resources:
257
+ raise RuntimeError("Resource already exists")
258
+ resource = self._resources[resource_id] = Resource()
259
+ if data:
260
+ # Save the data to the cache if it exists
261
+ self._h.cache[resource.get_resource_key(self._uuid, resource_id)] = data
262
+ # Store a flag if it exists
263
+ resource.exists[resource.index] = bool(data)
264
+
265
+ def set_resource(self, resource_id: ResourceIdT, data: bytes) -> None:
266
+ """
267
+ Set the data for the resource.
268
+ :param resource_id: The resource identifier
269
+ :param data: The binary data to set. An empty bytes object for the deleted state.
270
+ :return:
271
+ """
272
+ with self._h.lock:
273
+ self._h.invalidate_future()
274
+ resource = self._resources[resource_id]
275
+ if resource.global_index != self._h.history_index:
276
+ # The global history index has been increased since the last change to this resource
277
+ # Add a new state
278
+ resource.index += 1
279
+ resource.global_index = self._h.history_index
280
+ resource.exists.append(False)
281
+ if resource.index == resource.saved_index:
282
+ # The saved index has been directly modified
283
+ resource.saved_index = -1
284
+ if data:
285
+ # Save the data to the cache if it exists
286
+ self._h.cache[resource.get_resource_key(self._uuid, resource_id)] = data
287
+ # Store a flag if it exists
288
+ resource.exists[resource.index] = bool(data)
289
+ if self._h.history_index:
290
+ # Add the resource to the history bin if one has been created
291
+ self._h.history[self._h.history_index].add(resource)
@@ -0,0 +1,5 @@
1
+ from ._level import LevelOpenData, Level, LevelT, LevelFriend
2
+ from ._compactable_level import CompactableLevel
3
+ from ._creatable_level import CreatableLevel
4
+ from ._disk_level import DiskLevel
5
+ from ._loadable_level import LoadableLevel
@@ -0,0 +1,10 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+
4
+ class CompactableLevel(ABC):
5
+ __slots__ = ()
6
+
7
+ @abstractmethod
8
+ def compact(self) -> None:
9
+ """Compact level data to reduce file size."""
10
+ raise NotImplementedError
@@ -0,0 +1,29 @@
1
+ from __future__ import annotations
2
+ from abc import ABC, abstractmethod
3
+ from typing import TYPE_CHECKING, Any
4
+
5
+ from amulet.utils.typing import Intersection
6
+ from amulet.utils.call_spec import method_spec
7
+
8
+
9
+ if TYPE_CHECKING:
10
+ from ._level import Level
11
+
12
+
13
+ class CreatableLevel(ABC):
14
+ """Level extension class for levels that can be created without data."""
15
+
16
+ __slots__ = ()
17
+
18
+ @classmethod
19
+ @abstractmethod
20
+ @method_spec()
21
+ def create(cls, *args: Any, **kwargs: Any) -> Intersection[Level, CreatableLevel]:
22
+ """
23
+ Create a new instance without any existing data.
24
+ You must call :meth:`~amulet.level.abc.Level.open` to open the level for editing.
25
+ :return: A new Level instance
26
+ """
27
+ # If writing data to disk, it must write a valid level.
28
+ # If only setting attributes, the open method must be aware that it should not load data from disk.
29
+ raise NotImplementedError
@@ -0,0 +1,17 @@
1
+ from __future__ import annotations
2
+
3
+ from abc import abstractmethod
4
+
5
+ from ._level import Level, OpenLevelDataT, RawLevelT, DimensionT
6
+
7
+
8
+ class DiskLevel(Level[OpenLevelDataT, DimensionT, RawLevelT]):
9
+ """A level base class for all levels with data on disk."""
10
+
11
+ __slots__ = ()
12
+
13
+ @property
14
+ @abstractmethod
15
+ def path(self) -> str:
16
+ """The path to the level on disk."""
17
+ raise NotImplementedError