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,343 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Callable
4
+ import struct
5
+ from contextlib import suppress
6
+ import logging
7
+ from collections.abc import Iterator
8
+
9
+ from amulet_nbt import (
10
+ NamedTag,
11
+ LongTag,
12
+ StringTag,
13
+ CompoundTag,
14
+ NBTLoadError,
15
+ read_nbt,
16
+ utf8_escape_encoding,
17
+ )
18
+
19
+ from amulet.data_types import DimensionId, ChunkCoordinates
20
+ from amulet.block import Block, BlockStack
21
+ from amulet.biome import Biome
22
+ from amulet.selection import SelectionGroup
23
+ from amulet.errors import ChunkDoesNotExist
24
+ from amulet.version import VersionNumber
25
+ from amulet.level.abc import RawDimension, RawLevelFriend
26
+ from ._chunk import BedrockRawChunk
27
+ from ._chunk_decode import raw_to_native
28
+ from ._chunk_encode import native_to_raw
29
+ from ._constant import THE_NETHER, THE_END
30
+ from ._typing import InternalDimension
31
+ from ..chunk import BedrockChunk
32
+
33
+ if TYPE_CHECKING:
34
+ from ._level import BedrockRawLevel
35
+
36
+ log = logging.getLogger(__name__)
37
+
38
+
39
+ class BedrockRawDimension(
40
+ RawLevelFriend["BedrockRawLevel"], RawDimension[BedrockRawChunk, BedrockChunk]
41
+ ):
42
+ def __init__(
43
+ self,
44
+ raw_level_ref: Callable[[], BedrockRawLevel | None],
45
+ internal_dimension: InternalDimension,
46
+ alias: DimensionId,
47
+ bounds: SelectionGroup,
48
+ ) -> None:
49
+ super().__init__(raw_level_ref)
50
+ self._internal_dimension = internal_dimension
51
+ self._alias = alias
52
+ self._bounds = bounds
53
+
54
+ @property
55
+ def dimension_id(self) -> DimensionId:
56
+ return self._alias
57
+
58
+ @property
59
+ def internal_dimension_id(self) -> InternalDimension:
60
+ return self._internal_dimension
61
+
62
+ def bounds(self) -> SelectionGroup:
63
+ """The editable region of the dimension."""
64
+ return self._bounds
65
+
66
+ def default_block(self) -> BlockStack:
67
+ """The default block for this dimension"""
68
+ return BlockStack(
69
+ Block("bedrock", VersionNumber(1, 20, 61), "minecraft", "air")
70
+ )
71
+
72
+ def default_biome(self) -> Biome:
73
+ """The default biome for this dimension"""
74
+ # todo: is this stored in the data somewhere?
75
+ if self.dimension_id == THE_NETHER:
76
+ return Biome("bedrock", VersionNumber(1, 20, 61), "minecraft", "hell")
77
+ elif self.dimension_id == THE_END:
78
+ return Biome("bedrock", VersionNumber(1, 20, 61), "minecraft", "the_end")
79
+ else:
80
+ return Biome("bedrock", VersionNumber(1, 20, 61), "minecraft", "plains")
81
+
82
+ def all_chunk_coords(self) -> Iterator[ChunkCoordinates]:
83
+ if self._internal_dimension is None:
84
+ mask = slice(8, 9)
85
+ key_len = 9
86
+ keys = (b",", b"v")
87
+ else:
88
+ mask = slice(8, 13)
89
+ key_len = 13
90
+ dim = struct.pack("<i", self._internal_dimension)
91
+ keys = (dim + b",", dim + b"v")
92
+ for key in self._r.level_db.keys():
93
+ if len(key) == key_len and key[mask] in keys:
94
+ yield struct.unpack("<ii", key[:8])
95
+
96
+ def _chunk_prefix(self, cx: int, cz: int) -> bytes:
97
+ if self._internal_dimension is None:
98
+ return struct.pack("<ii", cx, cz)
99
+ else:
100
+ return struct.pack("<iii", cx, cz, self._internal_dimension)
101
+
102
+ def has_chunk(self, cx: int, cz: int) -> bool:
103
+ key = self._chunk_prefix(cx, cz)
104
+ return any(key + tag in self._r.level_db for tag in (b",", b"v"))
105
+
106
+ def delete_chunk(self, cx: int, cz: int) -> None:
107
+ if not self.has_chunk(cx, cz):
108
+ return # chunk does not exists
109
+
110
+ db = self._r.level_db
111
+ prefix = self._chunk_prefix(cx, cz)
112
+ prefix_len = len(prefix)
113
+ iter_end = prefix + b"\xff\xff\xff\xff"
114
+ keys = []
115
+ for key, _ in db.iterate(prefix, iter_end):
116
+ if key[:prefix_len] == prefix and len(key) <= prefix_len + 2:
117
+ keys.append(key)
118
+ for key in keys:
119
+ db.delete(key)
120
+
121
+ try:
122
+ digp = db.get(b"digp" + prefix)
123
+ except KeyError:
124
+ pass
125
+ else:
126
+ db.delete(b"digp" + prefix)
127
+ for i in range(0, len(digp) // 8 * 8, 8):
128
+ actor_key = b"actorprefix" + digp[i : i + 8]
129
+ db.delete(actor_key)
130
+
131
+ def get_raw_chunk(self, cx: int, cz: int) -> BedrockRawChunk:
132
+ """Get the raw data for the chunk.
133
+
134
+ :param cx: The chunk x coordinate
135
+ :param cz: The chunk z coordinate
136
+ :return:
137
+ :raises:
138
+ ChunkDoesNotExist if the chunk does not exist
139
+ """
140
+ if not self.has_chunk(cx, cz):
141
+ raise ChunkDoesNotExist
142
+
143
+ prefix = self._chunk_prefix(cx, cz)
144
+ prefix_len = len(prefix)
145
+ iter_end = prefix + b"\xff\xff\xff\xff"
146
+
147
+ chunk_data = BedrockRawChunk()
148
+ for key, val in self._r.level_db.iterate(prefix, iter_end):
149
+ if key[:prefix_len] == prefix and len(key) <= prefix_len + 2:
150
+ chunk_data.chunk_data[key[prefix_len:]] = val
151
+
152
+ with suppress(KeyError):
153
+ digp_key = b"digp" + prefix
154
+ digp = self._r.level_db.get(digp_key)
155
+ chunk_data.chunk_data[b"digp"] = (
156
+ b"" # The presence of this key signals to the put method that this should be created and written
157
+ )
158
+ for i in range(0, (len(digp) // 8) * 8, 8):
159
+ actor_key = b"actorprefix" + digp[i : i + 8]
160
+ try:
161
+ actor_bytes = self._r.level_db.get(actor_key)
162
+ actor = read_nbt(
163
+ actor_bytes,
164
+ little_endian=True,
165
+ string_encoding=utf8_escape_encoding,
166
+ )
167
+ actor_tag = actor.compound
168
+ except KeyError:
169
+ log.error(f"Could not find actor {actor_key!r}. Skipping.")
170
+ except NBTLoadError:
171
+ log.error(f"Failed to parse actor {actor_key!r}. Skipping.")
172
+ else:
173
+ actor_tag.pop("UniqueID", None)
174
+ internal_components = actor_tag.setdefault(
175
+ "internalComponents",
176
+ CompoundTag(
177
+ EntityStorageKeyComponent=CompoundTag(
178
+ StorageKey=StringTag()
179
+ )
180
+ ),
181
+ ) # 717
182
+ if (
183
+ isinstance(internal_components, CompoundTag)
184
+ and internal_components
185
+ ):
186
+ if "EntityStorageKeyComponent" in internal_components:
187
+ # it is an entity
188
+ entity_component = internal_components[
189
+ "EntityStorageKeyComponent"
190
+ ]
191
+ if isinstance(entity_component, CompoundTag):
192
+ # delete the storage key component
193
+ if isinstance(
194
+ entity_component.get("StorageKey"), StringTag
195
+ ):
196
+ del entity_component["StorageKey"]
197
+ # if there is no other data then delete internalComponents
198
+ if (
199
+ len(entity_component) == 0
200
+ and len(internal_components) == 1
201
+ ):
202
+ del actor_tag["internalComponents"]
203
+ else:
204
+ log.warning(
205
+ f"Extra components found {repr(entity_component)}"
206
+ )
207
+ else:
208
+ log.warning(
209
+ f"Unrecognised EntityStorageKeyComponent type {repr(entity_component)}"
210
+ )
211
+
212
+ chunk_data.entity_actor.append(actor)
213
+ else:
214
+ # it is an unknown actor
215
+ log.warning(
216
+ f"Actor {actor_key!r} has an unknown format. Please report this to a developer {repr(internal_components)}"
217
+ )
218
+ for k, v in internal_components.items():
219
+ if isinstance(v, CompoundTag) and isinstance(
220
+ v.get("StorageKey"), StringTag
221
+ ):
222
+ v["StorageKey"] = StringTag()
223
+ chunk_data.unknown_actor.append(actor)
224
+ else:
225
+ log.error(
226
+ f"internalComponents was not valid for actor {actor_key!r}. Skipping."
227
+ )
228
+ continue
229
+
230
+ return chunk_data
231
+
232
+ def set_raw_chunk(self, cx: int, cz: int, chunk: BedrockRawChunk) -> None:
233
+ """
234
+ Set the raw data for a chunk
235
+ :param cx: The chunk x coordinate
236
+ :param cz: The chunk z coordinate
237
+ :param chunk: The chunk data to set.
238
+ :return:
239
+ """
240
+ key_prefix = self._chunk_prefix(cx, cz)
241
+
242
+ batch = {}
243
+
244
+ if b"digp" in chunk.chunk_data:
245
+ # if writing the digp key we need to delete all actors pointed to by the old digp key otherwise there will be memory leaks
246
+ digp_key = b"digp" + key_prefix
247
+ try:
248
+ old_digp = self._r.level_db.get(digp_key)
249
+ except KeyError:
250
+ pass
251
+ else:
252
+ for i in range(0, len(old_digp) // 8 * 8, 8):
253
+ actor_key = b"actorprefix" + old_digp[i : i + 8]
254
+ self._r.level_db.delete(actor_key)
255
+
256
+ digp = []
257
+
258
+ def add_actor(actor: NamedTag, is_entity: bool) -> None:
259
+ if not (
260
+ isinstance(actor, NamedTag) and isinstance(actor.tag, CompoundTag)
261
+ ):
262
+ log.error(f"Actor must be a NamedTag[Compound]")
263
+ return
264
+ actor_tag = actor.compound
265
+ internal_components = actor_tag.setdefault(
266
+ "internalComponents", CompoundTag()
267
+ )
268
+ if not isinstance(internal_components, CompoundTag):
269
+ log.error(
270
+ f"Invalid internalComponents value. Must be Compound. Skipping. {repr(internal_components)}"
271
+ )
272
+ return
273
+
274
+ if is_entity:
275
+ entity_storage = internal_components.setdefault(
276
+ "EntityStorageKeyComponent", CompoundTag()
277
+ )
278
+ if not isinstance(entity_storage, CompoundTag):
279
+ log.error(
280
+ f"Invalid EntityStorageKeyComponent value. Must be Compound. Skipping. {repr(entity_storage)}"
281
+ )
282
+ return
283
+ storages = [entity_storage]
284
+ else:
285
+ storages = []
286
+ for storage in internal_components.values():
287
+ if (
288
+ isinstance(storage, CompoundTag)
289
+ and storage.get("StorageKey") == StringTag()
290
+ ):
291
+ storages.append(storage)
292
+ if not storages:
293
+ log.error(
294
+ f"No valid StorageKeyComponent to write in for unknown actor {internal_components}"
295
+ )
296
+ return
297
+
298
+ session, uid = self._r._o.actor_counter.next()
299
+ # session is already negative
300
+ key = struct.pack(">ii", -session, uid)
301
+ # b'\x00\x00\x00\x01\x00\x00\x00\x0c' 1, 12
302
+ for storage in storages:
303
+ storage["StorageKey"] = StringTag(utf8_escape_encoding.decode(key))
304
+ # -4294967284 ">q" b'\xff\xff\xff\xff\x00\x00\x00\x0c' ">ii" -1, 12
305
+ actor_tag["UniqueID"] = LongTag(
306
+ struct.unpack(">q", struct.pack(">ii", session, uid))[0]
307
+ )
308
+
309
+ batch[b"actorprefix" + key] = actor.save_to(
310
+ little_endian=True,
311
+ compressed=False,
312
+ string_encoding=utf8_escape_encoding,
313
+ )
314
+ digp.append(key)
315
+
316
+ for actor_ in chunk.entity_actor:
317
+ add_actor(actor_, True)
318
+
319
+ for actor_ in chunk.unknown_actor:
320
+ add_actor(actor_, False)
321
+
322
+ del chunk.chunk_data[b"digp"]
323
+ batch[digp_key] = b"".join(digp)
324
+
325
+ # TODO: find all existing keys for this chunk in the database and delete them
326
+ for key, val in chunk.chunk_data.items():
327
+ key = key_prefix + key
328
+ if val is None:
329
+ self._r.level_db.delete(key)
330
+ else:
331
+ batch[key] = val
332
+ if batch:
333
+ self._r.level_db.putBatch(batch)
334
+
335
+ def raw_chunk_to_native_chunk(
336
+ self, raw_chunk: BedrockRawChunk, cx: int, cz: int
337
+ ) -> BedrockChunk:
338
+ return raw_to_native(self._r, self, raw_chunk)
339
+
340
+ def native_chunk_to_raw_chunk(
341
+ self, chunk: BedrockChunk, cx: int, cz: int
342
+ ) -> BedrockRawChunk:
343
+ return native_to_raw(self._r, self, chunk)