amulet-core 2.0a8__cp311-cp311-win_amd64.whl → 2.0.1.0.1297307203.19.43.34808.0a0__cp311-cp311-win_amd64.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 (271) hide show
  1. amulet/core/__init__.py +36 -0
  2. amulet/core/__pyinstaller/hook-amulet.core.py +4 -0
  3. amulet/core/_amulet_core.cp311-win_amd64.pyd +0 -0
  4. amulet/core/_amulet_core.pyi +7 -0
  5. amulet/{_version.py → core/_version.py} +3 -3
  6. amulet/core/amulet_core.dll +0 -0
  7. amulet/core/amulet_core.lib +0 -0
  8. amulet/core/amulet_coreConfig.cmake +18 -0
  9. amulet/{biome.pyi → core/biome/__init__.pyi} +3 -3
  10. amulet/core/biome/biome.hpp +53 -0
  11. amulet/{block.pyi → core/block/__init__.pyi} +25 -26
  12. amulet/core/block/block.hpp +156 -0
  13. amulet/{block_entity.pyi → core/block_entity/__init__.pyi} +7 -7
  14. amulet/core/block_entity/block_entity.hpp +84 -0
  15. amulet/{errors.py → core/chunk/__init__.pyi} +37 -33
  16. amulet/core/chunk/chunk.hpp +126 -0
  17. amulet/core/chunk/component/__init__.pyi +18 -0
  18. amulet/core/chunk/component/biome_3d_component.hpp +96 -0
  19. amulet/core/chunk/component/block_component.hpp +101 -0
  20. amulet/core/chunk/component/block_component.pyi +28 -0
  21. amulet/core/chunk/component/block_entity_component.hpp +119 -0
  22. amulet/core/chunk/component/section_array_map.hpp +129 -0
  23. amulet/{chunk_components.pyi → core/chunk/component/section_array_map.pyi} +4 -24
  24. amulet/core/dll.hpp +21 -0
  25. amulet/core/entity/__init__.pyi +105 -0
  26. amulet/core/entity/entity.hpp +100 -0
  27. amulet/{palette → core/palette}/__init__.pyi +2 -2
  28. amulet/core/palette/biome_palette.hpp +65 -0
  29. amulet/{palette → core/palette}/biome_palette.pyi +8 -8
  30. amulet/core/palette/block_palette.hpp +71 -0
  31. amulet/{palette → core/palette}/block_palette.pyi +12 -10
  32. amulet/core/selection/__init__.pyi +8 -0
  33. amulet/core/selection/box.hpp +86 -0
  34. amulet/core/selection/box.pyi +215 -0
  35. amulet/core/selection/group.hpp +80 -0
  36. amulet/core/selection/group.pyi +213 -0
  37. amulet/{version.pyi → core/version/__init__.pyi} +58 -10
  38. amulet/core/version/version.hpp +204 -0
  39. {amulet_core-2.0a8.dist-info → amulet_core-2.0.1.0.1297307203.19.43.34808.0a0.dist-info}/METADATA +25 -20
  40. amulet_core-2.0.1.0.1297307203.19.43.34808.0a0.dist-info/RECORD +45 -0
  41. {amulet_core-2.0a8.dist-info → amulet_core-2.0.1.0.1297307203.19.43.34808.0a0.dist-info}/WHEEL +1 -1
  42. amulet_core-2.0.1.0.1297307203.19.43.34808.0a0.dist-info/entry_points.txt +2 -0
  43. amulet/__init__.cp311-win_amd64.pyd +0 -0
  44. amulet/__init__.py.cpp +0 -45
  45. amulet/__init__.pyi +0 -30
  46. amulet/__pyinstaller/hook-amulet.py +0 -4
  47. amulet/_init.py +0 -26
  48. amulet/biome.cpp +0 -36
  49. amulet/biome.hpp +0 -43
  50. amulet/biome.py.cpp +0 -122
  51. amulet/block.cpp +0 -435
  52. amulet/block.hpp +0 -119
  53. amulet/block.py.cpp +0 -377
  54. amulet/block_entity.cpp +0 -12
  55. amulet/block_entity.hpp +0 -56
  56. amulet/block_entity.py.cpp +0 -115
  57. amulet/chunk.cpp +0 -16
  58. amulet/chunk.hpp +0 -100
  59. amulet/chunk.py.cpp +0 -80
  60. amulet/chunk.pyi +0 -28
  61. amulet/chunk_components/biome_3d_component.cpp +0 -5
  62. amulet/chunk_components/biome_3d_component.hpp +0 -79
  63. amulet/chunk_components/block_component.cpp +0 -41
  64. amulet/chunk_components/block_component.hpp +0 -88
  65. amulet/chunk_components/block_entity_component.cpp +0 -5
  66. amulet/chunk_components/block_entity_component.hpp +0 -147
  67. amulet/chunk_components/section_array_map.cpp +0 -129
  68. amulet/chunk_components/section_array_map.hpp +0 -147
  69. amulet/collections/eq.py.hpp +0 -37
  70. amulet/collections/hash.py.hpp +0 -27
  71. amulet/collections/holder.py.hpp +0 -37
  72. amulet/collections/iterator.py.hpp +0 -80
  73. amulet/collections/mapping.py.hpp +0 -199
  74. amulet/collections/mutable_mapping.py.hpp +0 -226
  75. amulet/collections/sequence.py.hpp +0 -163
  76. amulet/collections.pyi +0 -40
  77. amulet/data_types.py +0 -29
  78. amulet/entity.py +0 -182
  79. amulet/game/__init__.py +0 -7
  80. amulet/game/_game.py +0 -152
  81. amulet/game/_universal/__init__.py +0 -1
  82. amulet/game/_universal/_biome.py +0 -17
  83. amulet/game/_universal/_block.py +0 -47
  84. amulet/game/_universal/_version.py +0 -68
  85. amulet/game/abc/__init__.py +0 -22
  86. amulet/game/abc/_block_specification.py +0 -150
  87. amulet/game/abc/biome.py +0 -213
  88. amulet/game/abc/block.py +0 -331
  89. amulet/game/abc/game_version_container.py +0 -25
  90. amulet/game/abc/json_interface.py +0 -27
  91. amulet/game/abc/version.py +0 -44
  92. amulet/game/bedrock/__init__.py +0 -1
  93. amulet/game/bedrock/_biome.py +0 -35
  94. amulet/game/bedrock/_block.py +0 -42
  95. amulet/game/bedrock/_version.py +0 -165
  96. amulet/game/java/__init__.py +0 -2
  97. amulet/game/java/_biome.py +0 -35
  98. amulet/game/java/_block.py +0 -60
  99. amulet/game/java/_version.py +0 -176
  100. amulet/game/translate/__init__.py +0 -12
  101. amulet/game/translate/_functions/__init__.py +0 -15
  102. amulet/game/translate/_functions/_code_functions/__init__.py +0 -0
  103. amulet/game/translate/_functions/_code_functions/_text.py +0 -553
  104. amulet/game/translate/_functions/_code_functions/banner_pattern.py +0 -67
  105. amulet/game/translate/_functions/_code_functions/bedrock_chest_connection.py +0 -152
  106. amulet/game/translate/_functions/_code_functions/bedrock_moving_block_pos.py +0 -88
  107. amulet/game/translate/_functions/_code_functions/bedrock_sign.py +0 -152
  108. amulet/game/translate/_functions/_code_functions/bedrock_skull_rotation.py +0 -16
  109. amulet/game/translate/_functions/_code_functions/custom_name.py +0 -146
  110. amulet/game/translate/_functions/_frozen.py +0 -66
  111. amulet/game/translate/_functions/_state.py +0 -54
  112. amulet/game/translate/_functions/_typing.py +0 -98
  113. amulet/game/translate/_functions/abc.py +0 -123
  114. amulet/game/translate/_functions/carry_nbt.py +0 -160
  115. amulet/game/translate/_functions/carry_properties.py +0 -80
  116. amulet/game/translate/_functions/code.py +0 -143
  117. amulet/game/translate/_functions/map_block_name.py +0 -66
  118. amulet/game/translate/_functions/map_nbt.py +0 -111
  119. amulet/game/translate/_functions/map_properties.py +0 -93
  120. amulet/game/translate/_functions/multiblock.py +0 -112
  121. amulet/game/translate/_functions/new_block.py +0 -42
  122. amulet/game/translate/_functions/new_entity.py +0 -43
  123. amulet/game/translate/_functions/new_nbt.py +0 -206
  124. amulet/game/translate/_functions/new_properties.py +0 -64
  125. amulet/game/translate/_functions/sequence.py +0 -51
  126. amulet/game/translate/_functions/walk_input_nbt.py +0 -331
  127. amulet/game/translate/_translator.py +0 -433
  128. amulet/img/__init__.py +0 -10
  129. amulet/img/missing_no.png +0 -0
  130. amulet/img/missing_pack.png +0 -0
  131. amulet/img/missing_world.png +0 -0
  132. amulet/io/binary_reader.hpp +0 -45
  133. amulet/io/binary_writer.hpp +0 -30
  134. amulet/item.py +0 -75
  135. amulet/level/__init__.pyi +0 -23
  136. amulet/level/_load.py +0 -100
  137. amulet/level/abc/__init__.py +0 -12
  138. amulet/level/abc/_chunk_handle.py +0 -358
  139. amulet/level/abc/_dimension.py +0 -86
  140. amulet/level/abc/_history/__init__.py +0 -1
  141. amulet/level/abc/_history/_cache.py +0 -224
  142. amulet/level/abc/_history/_history_manager.py +0 -291
  143. amulet/level/abc/_level/__init__.py +0 -5
  144. amulet/level/abc/_level/_compactable_level.py +0 -10
  145. amulet/level/abc/_level/_creatable_level.py +0 -28
  146. amulet/level/abc/_level/_disk_level.py +0 -17
  147. amulet/level/abc/_level/_level.py +0 -449
  148. amulet/level/abc/_level/_loadable_level.py +0 -42
  149. amulet/level/abc/_player_storage.py +0 -7
  150. amulet/level/abc/_raw_level.py +0 -187
  151. amulet/level/abc/_registry.py +0 -40
  152. amulet/level/java/__init__.pyi +0 -16
  153. amulet/level/java/_chunk_handle.py +0 -17
  154. amulet/level/java/_dimension.py +0 -20
  155. amulet/level/java/_level.py +0 -184
  156. amulet/level/java/_raw/__init__.pyi +0 -15
  157. amulet/level/java/_raw/_chunk.pyi +0 -23
  158. amulet/level/java/_raw/_constant.py +0 -9
  159. amulet/level/java/_raw/_data_pack/__init__.py +0 -2
  160. amulet/level/java/_raw/_data_pack/data_pack.py +0 -241
  161. amulet/level/java/_raw/_data_pack/data_pack_manager.py +0 -77
  162. amulet/level/java/_raw/_dimension.py +0 -86
  163. amulet/level/java/_raw/_level.py +0 -507
  164. amulet/level/java/_raw/_typing.py +0 -3
  165. amulet/level/java/_raw/java_chunk_decode.cpp +0 -531
  166. amulet/level/java/_raw/java_chunk_decode.hpp +0 -23
  167. amulet/level/java/_raw/java_chunk_encode.cpp +0 -25
  168. amulet/level/java/_raw/java_chunk_encode.hpp +0 -23
  169. amulet/level/java/anvil/__init__.py +0 -2
  170. amulet/level/java/anvil/_dimension.py +0 -170
  171. amulet/level/java/anvil/_region.py +0 -421
  172. amulet/level/java/anvil/_sector_manager.py +0 -223
  173. amulet/level/java/chunk.pyi +0 -81
  174. amulet/level/java/chunk_/_chunk.py +0 -260
  175. amulet/level/java/chunk_/components/inhabited_time.py +0 -12
  176. amulet/level/java/chunk_/components/last_update.py +0 -12
  177. amulet/level/java/chunk_/components/legacy_version.py +0 -12
  178. amulet/level/java/chunk_/components/light_populated.py +0 -12
  179. amulet/level/java/chunk_/components/named_height_2d.py +0 -37
  180. amulet/level/java/chunk_/components/status.py +0 -11
  181. amulet/level/java/chunk_/components/terrain_populated.py +0 -12
  182. amulet/level/java/chunk_components/data_version_component.cpp +0 -32
  183. amulet/level/java/chunk_components/data_version_component.hpp +0 -31
  184. amulet/level/java/chunk_components/java_raw_chunk_component.cpp +0 -56
  185. amulet/level/java/chunk_components/java_raw_chunk_component.hpp +0 -45
  186. amulet/level/java/chunk_components.pyi +0 -22
  187. amulet/level/java/java_chunk.cpp +0 -170
  188. amulet/level/java/java_chunk.hpp +0 -141
  189. amulet/level/java/long_array.hpp +0 -175
  190. amulet/level/java/long_array.pyi +0 -39
  191. amulet/level/temporary_level/__init__.py +0 -1
  192. amulet/level/temporary_level/_level.py +0 -16
  193. amulet/mesh/__init__.py +0 -0
  194. amulet/mesh/block/__init__.pyi +0 -301
  195. amulet/mesh/block/_cube.py +0 -198
  196. amulet/mesh/block/_missing_block.py +0 -20
  197. amulet/mesh/block/block_mesh.cpp +0 -107
  198. amulet/mesh/block/block_mesh.hpp +0 -207
  199. amulet/mesh/util.py +0 -17
  200. amulet/palette/biome_palette.hpp +0 -85
  201. amulet/palette/block_palette.cpp +0 -32
  202. amulet/palette/block_palette.hpp +0 -93
  203. amulet/player.py +0 -62
  204. amulet/pybind11/collections.hpp +0 -118
  205. amulet/pybind11/numpy.hpp +0 -26
  206. amulet/pybind11/py_module.hpp +0 -34
  207. amulet/pybind11/type_hints.hpp +0 -51
  208. amulet/pybind11/types.hpp +0 -25
  209. amulet/pybind11/typing.hpp +0 -7
  210. amulet/resource_pack/__init__.py +0 -63
  211. amulet/resource_pack/abc/__init__.py +0 -2
  212. amulet/resource_pack/abc/resource_pack.py +0 -38
  213. amulet/resource_pack/abc/resource_pack_manager.py +0 -85
  214. amulet/resource_pack/java/__init__.py +0 -2
  215. amulet/resource_pack/java/download_resources.py +0 -212
  216. amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_black.png +0 -0
  217. amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_blue.png +0 -0
  218. amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_brown.png +0 -0
  219. amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_cyan.png +0 -0
  220. amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_gray.png +0 -0
  221. amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_green.png +0 -0
  222. amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_light_blue.png +0 -0
  223. amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_light_gray.png +0 -0
  224. amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_lime.png +0 -0
  225. amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_magenta.png +0 -0
  226. amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_orange.png +0 -0
  227. amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_pink.png +0 -0
  228. amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_purple.png +0 -0
  229. amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_red.png +0 -0
  230. amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_white.png +0 -0
  231. amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/banner/banner_yellow.png +0 -0
  232. amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/barrier.png +0 -0
  233. amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/end_portal.png +0 -0
  234. amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/grass.png +0 -0
  235. amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/lava.png +0 -0
  236. amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/structure_void.png +0 -0
  237. amulet/resource_pack/java/java_vanilla_fix/assets/minecraft/textures/block/water.png +0 -0
  238. amulet/resource_pack/java/java_vanilla_fix/pack.png +0 -0
  239. amulet/resource_pack/java/resource_pack.py +0 -44
  240. amulet/resource_pack/java/resource_pack_manager.py +0 -563
  241. amulet/resource_pack/unknown_resource_pack.py +0 -10
  242. amulet/selection/__init__.py +0 -2
  243. amulet/selection/abstract_selection.py +0 -342
  244. amulet/selection/box.py +0 -852
  245. amulet/selection/group.py +0 -481
  246. amulet/utils/__init__.pyi +0 -23
  247. amulet/utils/call_spec/__init__.py +0 -24
  248. amulet/utils/call_spec/_call_spec.py +0 -257
  249. amulet/utils/cast.py +0 -10
  250. amulet/utils/comment_json.py +0 -188
  251. amulet/utils/format_utils.py +0 -41
  252. amulet/utils/generator.py +0 -18
  253. amulet/utils/matrix.py +0 -243
  254. amulet/utils/numpy.hpp +0 -36
  255. amulet/utils/numpy.pyi +0 -11
  256. amulet/utils/numpy_helpers.py +0 -19
  257. amulet/utils/shareable_lock.py +0 -335
  258. amulet/utils/signal/__init__.py +0 -10
  259. amulet/utils/signal/_signal.py +0 -228
  260. amulet/utils/task_manager.py +0 -235
  261. amulet/utils/typed_property.py +0 -111
  262. amulet/utils/weakref.py +0 -70
  263. amulet/utils/world_utils.py +0 -102
  264. amulet/version.cpp +0 -136
  265. amulet/version.hpp +0 -142
  266. amulet/version.py.cpp +0 -281
  267. amulet_core-2.0a8.dist-info/RECORD +0 -241
  268. amulet_core-2.0a8.dist-info/entry_points.txt +0 -2
  269. /amulet/{__pyinstaller → core/__pyinstaller}/__init__.py +0 -0
  270. /amulet/{py.typed → core/py.typed} +0 -0
  271. {amulet_core-2.0a8.dist-info → amulet_core-2.0.1.0.1297307203.19.43.34808.0a0.dist-info}/top_level.txt +0 -0
amulet/level/_load.py DELETED
@@ -1,100 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import Type, Any
4
- import logging
5
- from inspect import isclass
6
- from threading import Lock
7
- from weakref import WeakValueDictionary
8
-
9
- from amulet.level.abc import LoadableLevel
10
-
11
-
12
- log = logging.getLogger(__name__)
13
-
14
-
15
- _level_classes = set[Type[LoadableLevel]]()
16
- _levels = WeakValueDictionary[Any, LoadableLevel]()
17
- _lock = Lock()
18
-
19
-
20
- def _check_loadable_level(cls: Any) -> None:
21
- if not (isclass(cls) and issubclass(cls, LoadableLevel)):
22
- raise TypeError(
23
- "cls must be a subclass of amulet.level.abc.Level and amulet.level.abc.LoadableLevel"
24
- )
25
-
26
-
27
- def register_level_class(cls: Type[LoadableLevel]) -> None:
28
- """Add a level class to be considered when getting a level.
29
-
30
- :param cls: The Level subclass to register.
31
- :return:
32
- """
33
- _check_loadable_level(cls)
34
- with _lock:
35
- _level_classes.add(cls)
36
-
37
-
38
- def unregister_level_class(cls: Type[LoadableLevel]) -> None:
39
- """Remove a level class from consideration when getting a level.
40
-
41
- Note that any instances of the class will remain.
42
-
43
- :param cls: The Level subclass to unregister.
44
- """
45
- _check_loadable_level(cls)
46
- with _lock:
47
- _level_classes.discard(cls)
48
-
49
-
50
- class NoValidLevel(Exception):
51
- """An error thrown if no level could load the token."""
52
-
53
- pass
54
-
55
-
56
- def get_level(token: Any) -> LoadableLevel:
57
- """Get the level for the given token.
58
-
59
- If a level object already exists for this token then that will be returned.
60
- This will return a subclass of Level specialised for that level type.
61
- Note that the returned level may or may not be open.
62
- The level will automatically close itself when the last reference is lost so you must hold a strong reference to it.
63
-
64
- :param token: The token to load. This may be a file/directory path or some other token.
65
- :return: The level instance.
66
- :raises:
67
- NoValidLevel: If no level could load the token.
68
-
69
- Exception: Other errors.
70
- """
71
- level: None | LoadableLevel
72
- with _lock:
73
- # Find the level to load the token
74
- cls = next((cls for cls in _level_classes if cls.can_load(token)), None)
75
-
76
- if cls is None:
77
- # If no level could load the token then raise
78
- raise NoValidLevel(f"Could not load {token}")
79
-
80
- try:
81
- # Try and get a cached instance of the level
82
- level = _levels.get(token)
83
- if level is not None:
84
- # If there is a cached instance then return it
85
- return level
86
- except TypeError:
87
- # If the token is not hashable
88
- pass
89
-
90
- # Load the level
91
- level = cls.load(token)
92
-
93
- try:
94
- # Cache the level
95
- _levels[token] = level
96
- except TypeError:
97
- # Token may not be hashable
98
- pass
99
-
100
- return level
@@ -1,12 +0,0 @@
1
- from ._level import *
2
- from ._chunk_handle import ChunkHandle
3
- from ._player_storage import PlayerStorage
4
- from ._raw_level import (
5
- RawLevel,
6
- RawLevelFriend,
7
- RawLevelPlayerComponent,
8
- RawLevelBufferedComponent,
9
- RawDimension,
10
- )
11
- from ._dimension import Dimension
12
- from ._registry import IdRegistry
@@ -1,358 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import pickle
4
- from typing import Optional, TYPE_CHECKING, Generic, TypeVar, Callable, Self
5
- from collections.abc import Iterator, Iterable
6
- from contextlib import contextmanager
7
- from threading import RLock
8
- from abc import ABC, abstractmethod
9
-
10
- from amulet.utils.shareable_lock import LockNotAcquired
11
- from amulet.chunk import Chunk, get_null_chunk
12
- from amulet.data_types import DimensionId
13
- from amulet.errors import ChunkDoesNotExist, ChunkLoadError
14
- from amulet.utils.signal import Signal
15
- from amulet.utils.shareable_lock import ShareableRLock
16
-
17
- from ._level import LevelFriend, LevelT
18
- from ._history import HistoryManagerLayer
19
-
20
-
21
- if TYPE_CHECKING:
22
- from ._level import Level
23
- from ._raw_level import RawDimension
24
-
25
-
26
- ChunkT = TypeVar("ChunkT", bound=Chunk)
27
- RawDimensionT = TypeVar("RawDimensionT", bound="RawDimension")
28
-
29
-
30
- class ChunkKey(tuple[int, int]):
31
- def __new__(cls, cx: int, cz: int) -> Self:
32
- return tuple.__new__(cls, (cx, cz))
33
-
34
- def __init__(self, cx: int, cz: int) -> None:
35
- self._bytes: Optional[bytes] = None
36
-
37
- @property
38
- def cx(self) -> int:
39
- return self[0]
40
-
41
- @property
42
- def cz(self) -> int:
43
- return self[1]
44
-
45
- def __bytes__(self) -> bytes:
46
- if self._bytes is None:
47
- self._bytes = b"/".join((str(self[0]).encode(), str(self[1]).encode()))
48
- return self._bytes
49
-
50
-
51
- class ChunkHandle(
52
- LevelFriend[LevelT],
53
- ABC,
54
- Generic[LevelT, RawDimensionT, ChunkT],
55
- ):
56
- """
57
- A class which manages chunk data.
58
- You must acquire the lock for the chunk before reading or writing data.
59
- Some internal synchronisation is done to catch some threading issues.
60
- """
61
-
62
- _lock: ShareableRLock
63
- _dimension: DimensionId
64
- _key: ChunkKey
65
- _chunk_history: HistoryManagerLayer[ChunkKey]
66
- _chunk_data_history: HistoryManagerLayer[bytes]
67
- _raw_dimension: Optional[RawDimensionT]
68
-
69
- __slots__ = (
70
- "_lock",
71
- "_dimension_id",
72
- "_key",
73
- "_chunk_history",
74
- "_chunk_data_history",
75
- "_raw_dimension",
76
- )
77
-
78
- def __init__(
79
- self,
80
- level_ref: Callable[[], LevelT | None],
81
- chunk_history: HistoryManagerLayer[ChunkKey],
82
- chunk_data_history: HistoryManagerLayer[bytes],
83
- dimension_id: DimensionId,
84
- cx: int,
85
- cz: int,
86
- ) -> None:
87
- super().__init__(level_ref)
88
- self._lock = ShareableRLock()
89
- self._dimension_id = dimension_id
90
- self._key = ChunkKey(cx, cz)
91
- self._chunk_history = chunk_history
92
- self._chunk_data_history = chunk_data_history
93
- self._raw_dimension = None
94
-
95
- changed = Signal[()]()
96
-
97
- @property
98
- def dimension_id(self) -> DimensionId:
99
- return self._dimension_id
100
-
101
- @property
102
- def cx(self) -> int:
103
- return self._key.cx
104
-
105
- @property
106
- def cz(self) -> int:
107
- return self._key.cz
108
-
109
- def _get_raw_dimension(self) -> RawDimensionT:
110
- if self._raw_dimension is None:
111
- self._raw_dimension = self._l.raw.get_dimension(self.dimension_id)
112
- return self._raw_dimension
113
-
114
- @contextmanager
115
- def lock(
116
- self,
117
- *,
118
- blocking: bool = True,
119
- timeout: float = -1,
120
- ) -> Iterator[None]:
121
- """
122
- Lock access to the chunk.
123
-
124
- >>> level: Level
125
- >>> dimension_name: str
126
- >>> cx: int
127
- >>> cz: int
128
- >>> with level.get_dimension(dimension_name).get_chunk_handle(cx, cz).lock():
129
- >>> # Do what you need to with the chunk
130
- >>> # No other threads are able to edit or set the chunk while in this with block.
131
-
132
- If you want to lock, get and set the chunk data :meth:`edit` is probably a better fit.
133
-
134
- :param blocking: Should this block until the lock is acquired.
135
- :param timeout: The amount of time to wait for the lock.
136
- :raises:
137
- LockNotAcquired: If the lock could not be acquired.
138
- """
139
- return self._lock.unique(blocking, timeout)
140
-
141
- @contextmanager
142
- def edit(
143
- self,
144
- *,
145
- components: Iterable[str] | None = None,
146
- blocking: bool = True,
147
- timeout: float = -1,
148
- ) -> Iterator[ChunkT | None]:
149
- """Lock and edit a chunk.
150
-
151
- If you only want to access/modify parts of the chunk data you can specify the components you want to load.
152
- This makes it faster because you don't need to load unneeded parts.
153
-
154
- >>> level: Level
155
- >>> dimension_name: str
156
- >>> cx: int
157
- >>> cz: int
158
- >>> with level.get_dimension(dimension_name).get_chunk_handle(cx, cz).edit() as chunk:
159
- >>> # Edit the chunk data
160
- >>> # No other threads are able to edit the chunk while in this with block.
161
- >>> # When the with block exits the edited chunk will be automatically set if no exception occurred.
162
-
163
- :param components: None to load all components or an iterable of component strings to load.
164
- :param blocking: Should this block until the lock is acquired.
165
- :param timeout: The amount of time to wait for the lock.
166
- :raises:
167
- LockNotAcquired: If the lock could not be acquired.
168
- """
169
- with self._lock.unique(blocking=blocking, timeout=timeout):
170
- chunk = self.get(components)
171
- yield chunk
172
- # If an exception occurs in user code, this line won't be run.
173
- self._set(chunk)
174
- self.changed.emit()
175
- self._l.changed.emit()
176
-
177
- def exists(self) -> bool:
178
- """
179
- Does the chunk exist. This is a quick way to check if the chunk exists without loading it.
180
-
181
- This state may change if the lock is not acquired.
182
-
183
- :return: True if the chunk exists. Calling get on this chunk handle may still throw ChunkLoadError
184
- """
185
- with self._lock.shared():
186
- if self._chunk_history.has_resource(self._key):
187
- return self._chunk_history.resource_exists(self._key)
188
- else:
189
- # The history system is not aware of the chunk. Look in the level data
190
- return self._get_raw_dimension().has_chunk(self.cx, self.cz)
191
-
192
- def _preload(self) -> None:
193
- """
194
- Load the chunk data if it has not already been loaded.
195
- The lock must be acquired in unique mode before calling this.
196
- """
197
- if not self._chunk_history.has_resource(self._key):
198
- # The history system is not aware of the chunk. Load from the level data
199
- chunk: Chunk
200
- try:
201
- raw_chunk = self._get_raw_dimension().get_raw_chunk(self.cx, self.cz)
202
- chunk = self._get_raw_dimension().raw_chunk_to_native_chunk(
203
- raw_chunk,
204
- self.cx,
205
- self.cz,
206
- )
207
- except ChunkDoesNotExist:
208
- self._chunk_history.set_initial_resource(self._key, b"")
209
- except ChunkLoadError as e:
210
- self._chunk_history.set_initial_resource(self._key, pickle.dumps(e))
211
- else:
212
- self._chunk_history.set_initial_resource(
213
- self._key, pickle.dumps(chunk.chunk_id)
214
- )
215
- for component_id, component_data in chunk.serialise_chunk().items():
216
- if component_data is None:
217
- raise RuntimeError(
218
- "Component must not be None when initialising chunk"
219
- )
220
- self._chunk_data_history.set_initial_resource(
221
- b"/".join((bytes(self._key), component_id.encode())),
222
- component_data,
223
- )
224
-
225
- def _get_null_chunk(self) -> ChunkT:
226
- """Get a null chunk instance used for this chunk.
227
-
228
- :raises:
229
- ChunkDoesNotExist if the chunk does not exist.
230
- """
231
- data = self._chunk_history.get_resource(self._key)
232
- if data:
233
- obj: ChunkLoadError | str = pickle.loads(data)
234
- if isinstance(obj, ChunkLoadError):
235
- raise obj
236
- elif isinstance(obj, str):
237
- return get_null_chunk(obj) # type: ignore
238
- else:
239
- raise RuntimeError
240
- else:
241
- raise ChunkDoesNotExist
242
-
243
- def get_class(self) -> type[ChunkT]:
244
- """Get the chunk class used for this chunk.
245
-
246
- :raises:
247
- ChunkDoesNotExist if the chunk does not exist.
248
- """
249
- return type(self._get_null_chunk())
250
-
251
- def get(self, components: Iterable[str] | None = None) -> ChunkT:
252
- """Get a unique copy of the chunk data.
253
-
254
- If you want to edit the chunk, use :meth:`edit` instead.
255
-
256
- If you only want to access/modify parts of the chunk data you can specify the components you want to load.
257
- This makes it faster because you don't need to load unneeded parts.
258
-
259
- :param components: None to load all components or an iterable of component strings to load.
260
- :return: A unique copy of the chunk data.
261
- """
262
-
263
- def get_chunk() -> ChunkT:
264
- nonlocal components
265
- chunk = self._get_null_chunk()
266
- if components is None:
267
- components = chunk.component_ids
268
- else:
269
- # Ensure all component ids are valid for this class.
270
- components = set(components).intersection(chunk.component_ids)
271
- chunk_components = dict[str, bytes | None]()
272
- for component_id in components:
273
- chunk_components[component_id] = self._chunk_data_history.get_resource(
274
- b"/".join((bytes(self._key), component_id.encode()))
275
- )
276
- chunk.reconstruct_chunk(chunk_components)
277
- return chunk
278
-
279
- # Block if the chunk is locked in unique mode.
280
- with self._lock.shared():
281
- if self._chunk_history.has_resource(self._key):
282
- # Does not need loading from disk.
283
- return get_chunk()
284
-
285
- # Acquire the lock in unique mode.
286
- with self._lock.unique():
287
- # If it wasn't already loaded by another thread.
288
- if not self._chunk_history.has_resource(self._key):
289
- # Load it from disk.
290
- self._preload()
291
-
292
- with self._lock.shared():
293
- # If it was loaded in another thread just read it from the cache.
294
- return get_chunk()
295
-
296
- def _set(self, chunk: ChunkT | None) -> None:
297
- """lock must be acquired in unique mode before calling this."""
298
- history = self._chunk_history
299
- if not history.has_resource(self._key):
300
- if self._l.history_enabled:
301
- self._preload()
302
- else:
303
- history.set_initial_resource(self._key, b"")
304
- if chunk is None:
305
- history.set_resource(self._key, b"")
306
- else:
307
- self._validate_chunk(chunk)
308
- try:
309
- old_chunk_class = self.get_class()
310
- except ChunkLoadError:
311
- old_chunk_class = None
312
- new_chunk_class = type(chunk)
313
- component_data = chunk.serialise_chunk()
314
- if old_chunk_class != new_chunk_class and None in component_data.values():
315
- raise RuntimeError(
316
- "When changing chunk class all the data must be present."
317
- )
318
- history.set_resource(self._key, pickle.dumps(new_chunk_class))
319
- for component_id, data in component_data.items():
320
- if data is None:
321
- continue
322
- self._chunk_data_history.set_resource(
323
- b"/".join((bytes(self._key), component_id.encode())),
324
- data,
325
- )
326
-
327
- @staticmethod
328
- @abstractmethod
329
- def _validate_chunk(chunk: ChunkT) -> None:
330
- raise NotImplementedError
331
-
332
- def set(self, chunk: ChunkT) -> None:
333
- """
334
- Overwrite the chunk data.
335
- You must acquire the chunk lock before setting.
336
- If you want to edit the chunk, use :meth:`edit` instead.
337
-
338
- :param chunk: The chunk data to set.
339
- :raises:
340
- LockNotAcquired: If the chunk is already locked by another thread.
341
- """
342
- with self._lock.unique(blocking=False):
343
- self._set(chunk)
344
- self.changed.emit()
345
- self._l.changed.emit()
346
-
347
- def delete(self) -> None:
348
- """
349
- Delete the chunk from the level.
350
- You must acquire the chunk lock before deleting.
351
-
352
- :raises:
353
- LockNotAcquired: If the chunk is already locked by another thread.
354
- """
355
- with self._lock.unique(blocking=False):
356
- self._set(None)
357
- self.changed.emit()
358
- self._l.changed.emit()
@@ -1,86 +0,0 @@
1
- from abc import ABC, abstractmethod
2
- from typing import Generic, TypeVar, Callable
3
- from weakref import WeakValueDictionary
4
- from threading import Lock
5
-
6
- from amulet.data_types import DimensionId
7
- from amulet.block import BlockStack
8
- from amulet.biome import Biome
9
- from amulet.selection import SelectionGroup
10
-
11
- from ._level import LevelFriend, LevelT
12
- from ._history import HistoryManagerLayer
13
- from ._chunk_handle import ChunkKey, ChunkHandle
14
- from ._raw_level import RawDimension
15
-
16
-
17
- ChunkHandleT = TypeVar("ChunkHandleT", bound=ChunkHandle)
18
- RawDimensionT = TypeVar("RawDimensionT", bound=RawDimension)
19
-
20
-
21
- class Dimension(LevelFriend[LevelT], ABC, Generic[LevelT, RawDimensionT, ChunkHandleT]):
22
- _dimension_id: DimensionId
23
- _chunk_handles: WeakValueDictionary[tuple[int, int], ChunkHandleT]
24
- _chunk_handle_lock: Lock
25
- _chunk_history: HistoryManagerLayer[ChunkKey]
26
- _chunk_data_history: HistoryManagerLayer[bytes]
27
- _raw: RawDimensionT
28
-
29
- def __init__(
30
- self, level_ref: Callable[[], LevelT | None], dimension_id: DimensionId
31
- ) -> None:
32
- super().__init__(level_ref)
33
- self._dimension_id = dimension_id
34
- self._chunk_handles = WeakValueDictionary()
35
- self._chunk_handle_lock = Lock()
36
- self._chunk_history = self._l._o.history_manager.new_layer()
37
- self._chunk_data_history = self._l._o.history_manager.new_layer()
38
- self._raw = self._l.raw.get_dimension(self._dimension_id)
39
-
40
- @property
41
- def dimension_id(self) -> DimensionId:
42
- return self._dimension_id
43
-
44
- def bounds(self) -> SelectionGroup:
45
- """The editable region of the dimension."""
46
- return self._raw.bounds()
47
-
48
- def default_block(self) -> BlockStack:
49
- """The default block for this dimension"""
50
- return self._raw.default_block()
51
-
52
- def default_biome(self) -> Biome:
53
- """The default biome for this dimension"""
54
- return self._raw.default_biome()
55
-
56
- def chunk_coords(self) -> set[tuple[int, int]]:
57
- """
58
- The coordinates of every chunk that exists in this dimension.
59
-
60
- This is the combination of chunks saved to the level and chunks yet to be saved.
61
- """
62
- chunks: set[tuple[int, int]] = set(self._raw.all_chunk_coords())
63
- for key, state in self._chunk_history.resources_exist_map().items():
64
- if state:
65
- chunks.add((key.cx, key.cz))
66
- else:
67
- chunks.discard((key.cx, key.cz))
68
- return chunks
69
-
70
- def changed_chunk_coords(self) -> set[tuple[int, int]]:
71
- """The coordinates of every chunk in this dimension that have been changed since the last save."""
72
- return {(key.cx, key.cz) for key in self._chunk_history.changed_resources()}
73
-
74
- @abstractmethod
75
- def _create_chunk_handle(self, cx: int, cz: int) -> ChunkHandleT:
76
- raise NotImplementedError
77
-
78
- def get_chunk_handle(self, cx: int, cz: int) -> ChunkHandleT:
79
- key = cx, cz
80
- with self._chunk_handle_lock:
81
- chunk_handle = self._chunk_handles.get(key)
82
- if chunk_handle is None:
83
- chunk_handle = self._chunk_handles[key] = self._create_chunk_handle(
84
- cx, cz
85
- )
86
- return chunk_handle
@@ -1 +0,0 @@
1
- from ._history_manager import HistoryManager, HistoryManagerLayer