amulet-core 1.9.19__py3-none-any.whl → 1.9.20__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of amulet-core might be problematic. Click here for more details.

Files changed (198) hide show
  1. amulet/__init__.py +27 -27
  2. amulet/__pyinstaller/__init__.py +2 -2
  3. amulet/__pyinstaller/hook-amulet.py +4 -4
  4. amulet/_version.py +21 -21
  5. amulet/api/__init__.py +2 -2
  6. amulet/api/abstract_base_entity.py +128 -128
  7. amulet/api/block.py +630 -630
  8. amulet/api/block_entity.py +71 -71
  9. amulet/api/cache.py +107 -107
  10. amulet/api/chunk/__init__.py +6 -6
  11. amulet/api/chunk/biomes.py +207 -207
  12. amulet/api/chunk/block_entity_dict.py +175 -175
  13. amulet/api/chunk/blocks.py +46 -46
  14. amulet/api/chunk/chunk.py +389 -389
  15. amulet/api/chunk/entity_list.py +75 -75
  16. amulet/api/chunk/status.py +167 -167
  17. amulet/api/data_types/__init__.py +4 -4
  18. amulet/api/data_types/generic_types.py +4 -4
  19. amulet/api/data_types/operation_types.py +16 -16
  20. amulet/api/data_types/world_types.py +49 -49
  21. amulet/api/data_types/wrapper_types.py +71 -71
  22. amulet/api/entity.py +74 -74
  23. amulet/api/errors.py +119 -119
  24. amulet/api/history/__init__.py +36 -36
  25. amulet/api/history/base/__init__.py +3 -3
  26. amulet/api/history/base/base_history.py +26 -26
  27. amulet/api/history/base/history_manager.py +63 -63
  28. amulet/api/history/base/revision_manager.py +73 -73
  29. amulet/api/history/changeable.py +15 -15
  30. amulet/api/history/data_types.py +7 -7
  31. amulet/api/history/history_manager/__init__.py +3 -3
  32. amulet/api/history/history_manager/container.py +102 -102
  33. amulet/api/history/history_manager/database.py +279 -279
  34. amulet/api/history/history_manager/meta.py +93 -93
  35. amulet/api/history/history_manager/object.py +116 -116
  36. amulet/api/history/revision_manager/__init__.py +2 -2
  37. amulet/api/history/revision_manager/disk.py +33 -33
  38. amulet/api/history/revision_manager/ram.py +12 -12
  39. amulet/api/item.py +75 -75
  40. amulet/api/level/__init__.py +4 -4
  41. amulet/api/level/base_level/__init__.py +1 -1
  42. amulet/api/level/base_level/base_level.py +1035 -1026
  43. amulet/api/level/base_level/chunk_manager.py +227 -227
  44. amulet/api/level/base_level/clone.py +389 -389
  45. amulet/api/level/base_level/player_manager.py +101 -101
  46. amulet/api/level/immutable_structure/__init__.py +1 -1
  47. amulet/api/level/immutable_structure/immutable_structure.py +94 -94
  48. amulet/api/level/immutable_structure/void_format_wrapper.py +117 -117
  49. amulet/api/level/structure.py +22 -22
  50. amulet/api/level/world.py +19 -19
  51. amulet/api/partial_3d_array/__init__.py +2 -2
  52. amulet/api/partial_3d_array/base_partial_3d_array.py +263 -263
  53. amulet/api/partial_3d_array/bounded_partial_3d_array.py +528 -528
  54. amulet/api/partial_3d_array/data_types.py +15 -15
  55. amulet/api/partial_3d_array/unbounded_partial_3d_array.py +229 -229
  56. amulet/api/partial_3d_array/util.py +152 -152
  57. amulet/api/player.py +65 -65
  58. amulet/api/registry/__init__.py +2 -2
  59. amulet/api/registry/base_registry.py +34 -34
  60. amulet/api/registry/biome_manager.py +153 -153
  61. amulet/api/registry/block_manager.py +156 -156
  62. amulet/api/selection/__init__.py +2 -2
  63. amulet/api/selection/abstract_selection.py +315 -315
  64. amulet/api/selection/box.py +805 -805
  65. amulet/api/selection/group.py +488 -488
  66. amulet/api/structure.py +37 -37
  67. amulet/api/wrapper/__init__.py +8 -8
  68. amulet/api/wrapper/chunk/interface.py +441 -441
  69. amulet/api/wrapper/chunk/translator.py +567 -567
  70. amulet/api/wrapper/format_wrapper.py +772 -772
  71. amulet/api/wrapper/structure_format_wrapper.py +116 -116
  72. amulet/api/wrapper/world_format_wrapper.py +63 -63
  73. amulet/level/__init__.py +1 -1
  74. amulet/level/formats/anvil_forge_world.py +40 -40
  75. amulet/level/formats/anvil_world/__init__.py +3 -3
  76. amulet/level/formats/anvil_world/_sector_manager.py +291 -384
  77. amulet/level/formats/anvil_world/data_pack/__init__.py +2 -2
  78. amulet/level/formats/anvil_world/data_pack/data_pack.py +224 -224
  79. amulet/level/formats/anvil_world/data_pack/data_pack_manager.py +77 -77
  80. amulet/level/formats/anvil_world/dimension.py +177 -177
  81. amulet/level/formats/anvil_world/format.py +769 -769
  82. amulet/level/formats/anvil_world/region.py +384 -384
  83. amulet/level/formats/construction/__init__.py +3 -3
  84. amulet/level/formats/construction/format_wrapper.py +515 -515
  85. amulet/level/formats/construction/interface.py +134 -134
  86. amulet/level/formats/construction/section.py +60 -60
  87. amulet/level/formats/construction/util.py +165 -165
  88. amulet/level/formats/leveldb_world/__init__.py +3 -3
  89. amulet/level/formats/leveldb_world/chunk.py +33 -33
  90. amulet/level/formats/leveldb_world/dimension.py +385 -419
  91. amulet/level/formats/leveldb_world/format.py +659 -641
  92. amulet/level/formats/leveldb_world/interface/chunk/__init__.py +36 -36
  93. amulet/level/formats/leveldb_world/interface/chunk/base_leveldb_interface.py +836 -836
  94. amulet/level/formats/leveldb_world/interface/chunk/generate_interface.py +31 -31
  95. amulet/level/formats/leveldb_world/interface/chunk/leveldb_0.py +30 -30
  96. amulet/level/formats/leveldb_world/interface/chunk/leveldb_1.py +12 -12
  97. amulet/level/formats/leveldb_world/interface/chunk/leveldb_10.py +12 -12
  98. amulet/level/formats/leveldb_world/interface/chunk/leveldb_11.py +12 -12
  99. amulet/level/formats/leveldb_world/interface/chunk/leveldb_12.py +12 -12
  100. amulet/level/formats/leveldb_world/interface/chunk/leveldb_13.py +12 -12
  101. amulet/level/formats/leveldb_world/interface/chunk/leveldb_14.py +12 -12
  102. amulet/level/formats/leveldb_world/interface/chunk/leveldb_15.py +12 -12
  103. amulet/level/formats/leveldb_world/interface/chunk/leveldb_16.py +12 -12
  104. amulet/level/formats/leveldb_world/interface/chunk/leveldb_17.py +12 -12
  105. amulet/level/formats/leveldb_world/interface/chunk/leveldb_18.py +12 -12
  106. amulet/level/formats/leveldb_world/interface/chunk/leveldb_19.py +12 -12
  107. amulet/level/formats/leveldb_world/interface/chunk/leveldb_2.py +12 -12
  108. amulet/level/formats/leveldb_world/interface/chunk/leveldb_20.py +12 -12
  109. amulet/level/formats/leveldb_world/interface/chunk/leveldb_21.py +12 -12
  110. amulet/level/formats/leveldb_world/interface/chunk/leveldb_22.py +12 -12
  111. amulet/level/formats/leveldb_world/interface/chunk/leveldb_23.py +10 -10
  112. amulet/level/formats/leveldb_world/interface/chunk/leveldb_24.py +10 -10
  113. amulet/level/formats/leveldb_world/interface/chunk/leveldb_25.py +24 -24
  114. amulet/level/formats/leveldb_world/interface/chunk/leveldb_26.py +10 -10
  115. amulet/level/formats/leveldb_world/interface/chunk/leveldb_27.py +10 -10
  116. amulet/level/formats/leveldb_world/interface/chunk/leveldb_28.py +10 -10
  117. amulet/level/formats/leveldb_world/interface/chunk/leveldb_29.py +33 -33
  118. amulet/level/formats/leveldb_world/interface/chunk/leveldb_3.py +57 -57
  119. amulet/level/formats/leveldb_world/interface/chunk/leveldb_30.py +10 -10
  120. amulet/level/formats/leveldb_world/interface/chunk/leveldb_31.py +10 -10
  121. amulet/level/formats/leveldb_world/interface/chunk/leveldb_32.py +10 -10
  122. amulet/level/formats/leveldb_world/interface/chunk/leveldb_33.py +10 -10
  123. amulet/level/formats/leveldb_world/interface/chunk/leveldb_34.py +10 -10
  124. amulet/level/formats/leveldb_world/interface/chunk/leveldb_35.py +10 -10
  125. amulet/level/formats/leveldb_world/interface/chunk/leveldb_36.py +10 -10
  126. amulet/level/formats/leveldb_world/interface/chunk/leveldb_37.py +10 -10
  127. amulet/level/formats/leveldb_world/interface/chunk/leveldb_38.py +10 -10
  128. amulet/level/formats/leveldb_world/interface/chunk/leveldb_39.py +12 -12
  129. amulet/level/formats/leveldb_world/interface/chunk/leveldb_4.py +12 -12
  130. amulet/level/formats/leveldb_world/interface/chunk/leveldb_40.py +16 -16
  131. amulet/level/formats/leveldb_world/interface/chunk/leveldb_5.py +12 -12
  132. amulet/level/formats/leveldb_world/interface/chunk/leveldb_6.py +12 -12
  133. amulet/level/formats/leveldb_world/interface/chunk/leveldb_7.py +12 -12
  134. amulet/level/formats/leveldb_world/interface/chunk/leveldb_8.py +180 -180
  135. amulet/level/formats/leveldb_world/interface/chunk/leveldb_9.py +18 -18
  136. amulet/level/formats/leveldb_world/interface/chunk/leveldb_chunk_versions.py +79 -79
  137. amulet/level/formats/mcstructure/__init__.py +3 -3
  138. amulet/level/formats/mcstructure/chunk.py +50 -50
  139. amulet/level/formats/mcstructure/format_wrapper.py +408 -408
  140. amulet/level/formats/mcstructure/interface.py +175 -175
  141. amulet/level/formats/schematic/__init__.py +3 -3
  142. amulet/level/formats/schematic/chunk.py +55 -55
  143. amulet/level/formats/schematic/data_types.py +4 -4
  144. amulet/level/formats/schematic/format_wrapper.py +373 -373
  145. amulet/level/formats/schematic/interface.py +142 -142
  146. amulet/level/formats/sponge_schem/__init__.py +4 -4
  147. amulet/level/formats/sponge_schem/chunk.py +62 -62
  148. amulet/level/formats/sponge_schem/format_wrapper.py +463 -463
  149. amulet/level/formats/sponge_schem/interface.py +118 -118
  150. amulet/level/formats/sponge_schem/varint/__init__.py +1 -1
  151. amulet/level/formats/sponge_schem/varint/varint.py +87 -87
  152. amulet/level/interfaces/chunk/anvil/anvil_0.py +72 -72
  153. amulet/level/interfaces/chunk/anvil/anvil_1444.py +336 -336
  154. amulet/level/interfaces/chunk/anvil/anvil_1466.py +94 -94
  155. amulet/level/interfaces/chunk/anvil/anvil_1467.py +37 -37
  156. amulet/level/interfaces/chunk/anvil/anvil_1484.py +20 -20
  157. amulet/level/interfaces/chunk/anvil/anvil_1503.py +20 -20
  158. amulet/level/interfaces/chunk/anvil/anvil_1519.py +34 -34
  159. amulet/level/interfaces/chunk/anvil/anvil_1901.py +20 -20
  160. amulet/level/interfaces/chunk/anvil/anvil_1908.py +20 -20
  161. amulet/level/interfaces/chunk/anvil/anvil_1912.py +21 -21
  162. amulet/level/interfaces/chunk/anvil/anvil_1934.py +20 -20
  163. amulet/level/interfaces/chunk/anvil/anvil_2203.py +69 -69
  164. amulet/level/interfaces/chunk/anvil/anvil_2529.py +19 -19
  165. amulet/level/interfaces/chunk/anvil/anvil_2681.py +76 -76
  166. amulet/level/interfaces/chunk/anvil/anvil_2709.py +19 -19
  167. amulet/level/interfaces/chunk/anvil/anvil_2844.py +267 -267
  168. amulet/level/interfaces/chunk/anvil/anvil_3463.py +19 -19
  169. amulet/level/interfaces/chunk/anvil/anvil_na.py +607 -607
  170. amulet/level/interfaces/chunk/anvil/base_anvil_interface.py +326 -326
  171. amulet/level/load.py +59 -59
  172. amulet/level/loader.py +95 -95
  173. amulet/level/translators/chunk/bedrock/__init__.py +267 -267
  174. amulet/level/translators/chunk/bedrock/bedrock_nbt_blockstate_translator.py +46 -46
  175. amulet/level/translators/chunk/bedrock/bedrock_numerical_translator.py +39 -39
  176. amulet/level/translators/chunk/bedrock/bedrock_psudo_numerical_translator.py +37 -37
  177. amulet/level/translators/chunk/java/java_1_18_translator.py +40 -40
  178. amulet/level/translators/chunk/java/java_blockstate_translator.py +94 -94
  179. amulet/level/translators/chunk/java/java_numerical_translator.py +62 -62
  180. amulet/libs/leveldb/__init__.py +7 -7
  181. amulet/operations/__init__.py +5 -5
  182. amulet/operations/clone.py +18 -18
  183. amulet/operations/delete_chunk.py +32 -32
  184. amulet/operations/fill.py +30 -30
  185. amulet/operations/paste.py +65 -65
  186. amulet/operations/replace.py +58 -58
  187. amulet/utils/__init__.py +14 -14
  188. amulet/utils/format_utils.py +41 -41
  189. amulet/utils/generator.py +15 -15
  190. amulet/utils/matrix.py +243 -243
  191. amulet/utils/numpy_helpers.py +46 -46
  192. amulet/utils/world_utils.py +349 -349
  193. {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/METADATA +97 -97
  194. amulet_core-1.9.20.dist-info/RECORD +208 -0
  195. amulet_core-1.9.19.dist-info/RECORD +0 -208
  196. {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/WHEEL +0 -0
  197. {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/entry_points.txt +0 -0
  198. {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/top_level.txt +0 -0
@@ -1,93 +1,93 @@
1
- from typing import Tuple, Generator
2
-
3
- from amulet.utils.generator import generator_unpacker
4
- from amulet.api.history.base.history_manager import HistoryManager
5
- from .container import ContainerHistoryManager
6
-
7
- SnapshotType = Tuple[HistoryManager, ...]
8
-
9
-
10
- class MetaHistoryManager(ContainerHistoryManager):
11
- def __init__(self):
12
- super().__init__()
13
- self._world_managers = []
14
- self._non_world_managers = []
15
-
16
- def _check_snapshot(self, snapshot: SnapshotType):
17
- assert isinstance(snapshot, tuple) and all(
18
- isinstance(item, HistoryManager) for item in snapshot
19
- )
20
-
21
- def register(self, manager: HistoryManager, is_world_manager: bool):
22
- """
23
- Register a manager to track.
24
- :param manager: The manager to track
25
- :param is_world_manager: Is the manager tracking world data
26
- :return:
27
- """
28
- assert isinstance(
29
- manager, HistoryManager
30
- ), "manager must be an instance of BaseHistoryManager"
31
- if is_world_manager:
32
- self._world_managers.append(manager)
33
- else:
34
- self._non_world_managers.append(manager)
35
-
36
- def _undo(self, snapshot: SnapshotType):
37
- for item in snapshot:
38
- item.undo()
39
-
40
- def _redo(self, snapshot: SnapshotType):
41
- for item in snapshot:
42
- item.redo()
43
-
44
- def _mark_saved(self):
45
- for manager in self._managers():
46
- manager.mark_saved()
47
-
48
- def _managers(
49
- self, world: bool = True, non_world: bool = True
50
- ) -> Tuple[HistoryManager, ...]:
51
- return (
52
- tuple(self._world_managers) * world
53
- + tuple(self._non_world_managers) * non_world
54
- )
55
-
56
- @property
57
- def changed(self) -> bool:
58
- if super().changed:
59
- return True
60
- managers = self._managers(True, False)
61
- for manager in managers:
62
- if manager.changed:
63
- return True
64
- return False
65
-
66
- def create_undo_point(self, world=True, non_world=True) -> bool:
67
- return generator_unpacker(self.create_undo_point_iter(world, non_world))
68
-
69
- def create_undo_point_iter(
70
- self, world=True, non_world=True
71
- ) -> Generator[float, None, bool]:
72
- """Create an undo point.
73
-
74
- :param world: Should the world based history managers be included
75
- :param non_world: Should the non-world based history managers be included
76
- :return:
77
- """
78
- managers = self._managers(world, non_world)
79
- snapshot = []
80
- for manager in managers:
81
- changed = yield from manager.create_undo_point_iter()
82
- if changed:
83
- snapshot.append(manager)
84
- return self._register_snapshot(tuple(snapshot))
85
-
86
- def restore_last_undo_point(self):
87
- for manager in self._managers():
88
- manager.restore_last_undo_point()
89
-
90
- def purge(self):
91
- """Unload all history data. Restore to the state after creation."""
92
- for manager in self._managers():
93
- manager.purge()
1
+ from typing import Tuple, Generator
2
+
3
+ from amulet.utils.generator import generator_unpacker
4
+ from amulet.api.history.base.history_manager import HistoryManager
5
+ from .container import ContainerHistoryManager
6
+
7
+ SnapshotType = Tuple[HistoryManager, ...]
8
+
9
+
10
+ class MetaHistoryManager(ContainerHistoryManager):
11
+ def __init__(self):
12
+ super().__init__()
13
+ self._world_managers = []
14
+ self._non_world_managers = []
15
+
16
+ def _check_snapshot(self, snapshot: SnapshotType):
17
+ assert isinstance(snapshot, tuple) and all(
18
+ isinstance(item, HistoryManager) for item in snapshot
19
+ )
20
+
21
+ def register(self, manager: HistoryManager, is_world_manager: bool):
22
+ """
23
+ Register a manager to track.
24
+ :param manager: The manager to track
25
+ :param is_world_manager: Is the manager tracking world data
26
+ :return:
27
+ """
28
+ assert isinstance(
29
+ manager, HistoryManager
30
+ ), "manager must be an instance of BaseHistoryManager"
31
+ if is_world_manager:
32
+ self._world_managers.append(manager)
33
+ else:
34
+ self._non_world_managers.append(manager)
35
+
36
+ def _undo(self, snapshot: SnapshotType):
37
+ for item in snapshot:
38
+ item.undo()
39
+
40
+ def _redo(self, snapshot: SnapshotType):
41
+ for item in snapshot:
42
+ item.redo()
43
+
44
+ def _mark_saved(self):
45
+ for manager in self._managers():
46
+ manager.mark_saved()
47
+
48
+ def _managers(
49
+ self, world: bool = True, non_world: bool = True
50
+ ) -> Tuple[HistoryManager, ...]:
51
+ return (
52
+ tuple(self._world_managers) * world
53
+ + tuple(self._non_world_managers) * non_world
54
+ )
55
+
56
+ @property
57
+ def changed(self) -> bool:
58
+ if super().changed:
59
+ return True
60
+ managers = self._managers(True, False)
61
+ for manager in managers:
62
+ if manager.changed:
63
+ return True
64
+ return False
65
+
66
+ def create_undo_point(self, world=True, non_world=True) -> bool:
67
+ return generator_unpacker(self.create_undo_point_iter(world, non_world))
68
+
69
+ def create_undo_point_iter(
70
+ self, world=True, non_world=True
71
+ ) -> Generator[float, None, bool]:
72
+ """Create an undo point.
73
+
74
+ :param world: Should the world based history managers be included
75
+ :param non_world: Should the non-world based history managers be included
76
+ :return:
77
+ """
78
+ managers = self._managers(world, non_world)
79
+ snapshot = []
80
+ for manager in managers:
81
+ changed = yield from manager.create_undo_point_iter()
82
+ if changed:
83
+ snapshot.append(manager)
84
+ return self._register_snapshot(tuple(snapshot))
85
+
86
+ def restore_last_undo_point(self):
87
+ for manager in self._managers():
88
+ manager.restore_last_undo_point()
89
+
90
+ def purge(self):
91
+ """Unload all history data. Restore to the state after creation."""
92
+ for manager in self._managers():
93
+ manager.purge()
@@ -1,116 +1,116 @@
1
- from typing import Optional, Any, Generator
2
-
3
- from amulet.api.history import Changeable
4
- from ..base import RevisionManager
5
- from amulet.api.history.base.history_manager import HistoryManager
6
- from ..revision_manager import RAMRevisionManager
7
-
8
-
9
- class ObjectHistoryManager(HistoryManager):
10
- def __init__(self, original_entry: Changeable):
11
- super().__init__()
12
- self._value: Changeable = original_entry
13
- self._revision_manager = self._create_new_revision_manager(
14
- self._pack_value(self._value)
15
- )
16
- self._snapshots_size: int = 0
17
- self._snapshot_index: int = -1
18
-
19
- # the snapshot that was saved or the save branches off from
20
- self._last_save_snapshot = -1
21
- self._branch_save_count = 0 # if the user saves, undoes and does a new operation a save branch will be lost
22
- # This is the number of changes on that branch
23
-
24
- @property
25
- def value(self):
26
- return self._value
27
-
28
- @staticmethod
29
- def _create_new_revision_manager(original_entry: Optional[Any]) -> RevisionManager:
30
- """Create an RevisionManager as desired and populate it with the original entry."""
31
- return RAMRevisionManager(original_entry)
32
-
33
- def _register_snapshot(self):
34
- if self._last_save_snapshot > self._snapshot_index:
35
- # if the user has undone changes and made more changes things get a bit messy
36
- # This fixes the property storing the number of changes since the last save.
37
- self._branch_save_count += self._last_save_snapshot - self._snapshot_index
38
- self._last_save_snapshot = self._snapshot_index
39
- self._snapshot_index += 1
40
- self._snapshots_size = min(self._snapshots_size, self._snapshot_index) + 1
41
-
42
- def mark_saved(self):
43
- """Let the class know that the current state has been saved."""
44
- self._last_save_snapshot = self._snapshot_index
45
- self._branch_save_count = 0
46
- self._revision_manager.mark_saved()
47
-
48
- def purge(self):
49
- """Unload the cached objects and restore to the starting value."""
50
- self._revision_manager = self._create_new_revision_manager(
51
- self._pack_value(self._value)
52
- )
53
- self._snapshots_size: int = 0
54
- self._snapshot_index: int = -1
55
- self._last_save_snapshot = -1
56
- self._branch_save_count = 0
57
-
58
- @property
59
- def undo_count(self) -> int:
60
- return self._snapshot_index + 1
61
-
62
- @property
63
- def redo_count(self) -> int:
64
- return self._snapshots_size - (self._snapshot_index + 1)
65
-
66
- @property
67
- def unsaved_changes(self) -> int:
68
- """The number of changes that have been made since the last save"""
69
- return (
70
- abs(self._snapshot_index - self._last_save_snapshot)
71
- + self._branch_save_count
72
- )
73
-
74
- def undo(self):
75
- """Undoes the last set of changes to the object"""
76
- if self.undo_count > 0:
77
- self._revision_manager.undo()
78
- self._unpack()
79
- self._snapshot_index -= 1
80
-
81
- def redo(self):
82
- """Redoes the last set of changes to the object"""
83
- if self.redo_count > 0:
84
- self._snapshot_index += 1
85
- self._revision_manager.redo()
86
- self._unpack()
87
-
88
- @property
89
- def changed(self) -> bool:
90
- return bool(self.unsaved_changes)
91
-
92
- def create_undo_point_iter(self) -> Generator[float, None, bool]:
93
- yield 1
94
- if self._value.changed:
95
- self._value.changed = False
96
- self._pack()
97
- self._register_snapshot()
98
- return True
99
- else:
100
- self._unpack()
101
- return False
102
-
103
- def restore_last_undo_point(self):
104
- self._unpack()
105
-
106
- def _unpack(self):
107
- self._unpack_value(self._revision_manager.get_current_entry())
108
-
109
- def _unpack_value(self, value: Optional[Any]):
110
- self._value = value
111
-
112
- def _pack(self):
113
- self._revision_manager.put_new_entry(self._pack_value(self._value))
114
-
115
- def _pack_value(self, value: Optional[Any]) -> Optional[Any]:
116
- return value
1
+ from typing import Optional, Any, Generator
2
+
3
+ from amulet.api.history import Changeable
4
+ from ..base import RevisionManager
5
+ from amulet.api.history.base.history_manager import HistoryManager
6
+ from ..revision_manager import RAMRevisionManager
7
+
8
+
9
+ class ObjectHistoryManager(HistoryManager):
10
+ def __init__(self, original_entry: Changeable):
11
+ super().__init__()
12
+ self._value: Changeable = original_entry
13
+ self._revision_manager = self._create_new_revision_manager(
14
+ self._pack_value(self._value)
15
+ )
16
+ self._snapshots_size: int = 0
17
+ self._snapshot_index: int = -1
18
+
19
+ # the snapshot that was saved or the save branches off from
20
+ self._last_save_snapshot = -1
21
+ self._branch_save_count = 0 # if the user saves, undoes and does a new operation a save branch will be lost
22
+ # This is the number of changes on that branch
23
+
24
+ @property
25
+ def value(self):
26
+ return self._value
27
+
28
+ @staticmethod
29
+ def _create_new_revision_manager(original_entry: Optional[Any]) -> RevisionManager:
30
+ """Create an RevisionManager as desired and populate it with the original entry."""
31
+ return RAMRevisionManager(original_entry)
32
+
33
+ def _register_snapshot(self):
34
+ if self._last_save_snapshot > self._snapshot_index:
35
+ # if the user has undone changes and made more changes things get a bit messy
36
+ # This fixes the property storing the number of changes since the last save.
37
+ self._branch_save_count += self._last_save_snapshot - self._snapshot_index
38
+ self._last_save_snapshot = self._snapshot_index
39
+ self._snapshot_index += 1
40
+ self._snapshots_size = min(self._snapshots_size, self._snapshot_index) + 1
41
+
42
+ def mark_saved(self):
43
+ """Let the class know that the current state has been saved."""
44
+ self._last_save_snapshot = self._snapshot_index
45
+ self._branch_save_count = 0
46
+ self._revision_manager.mark_saved()
47
+
48
+ def purge(self):
49
+ """Unload the cached objects and restore to the starting value."""
50
+ self._revision_manager = self._create_new_revision_manager(
51
+ self._pack_value(self._value)
52
+ )
53
+ self._snapshots_size: int = 0
54
+ self._snapshot_index: int = -1
55
+ self._last_save_snapshot = -1
56
+ self._branch_save_count = 0
57
+
58
+ @property
59
+ def undo_count(self) -> int:
60
+ return self._snapshot_index + 1
61
+
62
+ @property
63
+ def redo_count(self) -> int:
64
+ return self._snapshots_size - (self._snapshot_index + 1)
65
+
66
+ @property
67
+ def unsaved_changes(self) -> int:
68
+ """The number of changes that have been made since the last save"""
69
+ return (
70
+ abs(self._snapshot_index - self._last_save_snapshot)
71
+ + self._branch_save_count
72
+ )
73
+
74
+ def undo(self):
75
+ """Undoes the last set of changes to the object"""
76
+ if self.undo_count > 0:
77
+ self._revision_manager.undo()
78
+ self._unpack()
79
+ self._snapshot_index -= 1
80
+
81
+ def redo(self):
82
+ """Redoes the last set of changes to the object"""
83
+ if self.redo_count > 0:
84
+ self._snapshot_index += 1
85
+ self._revision_manager.redo()
86
+ self._unpack()
87
+
88
+ @property
89
+ def changed(self) -> bool:
90
+ return bool(self.unsaved_changes)
91
+
92
+ def create_undo_point_iter(self) -> Generator[float, None, bool]:
93
+ yield 1
94
+ if self._value.changed:
95
+ self._value.changed = False
96
+ self._pack()
97
+ self._register_snapshot()
98
+ return True
99
+ else:
100
+ self._unpack()
101
+ return False
102
+
103
+ def restore_last_undo_point(self):
104
+ self._unpack()
105
+
106
+ def _unpack(self):
107
+ self._unpack_value(self._revision_manager.get_current_entry())
108
+
109
+ def _unpack_value(self, value: Optional[Any]):
110
+ self._value = value
111
+
112
+ def _pack(self):
113
+ self._revision_manager.put_new_entry(self._pack_value(self._value))
114
+
115
+ def _pack_value(self, value: Optional[Any]) -> Optional[Any]:
116
+ return value
@@ -1,2 +1,2 @@
1
- from .ram import RAMRevisionManager
2
- from .disk import DBRevisionManager
1
+ from .ram import RAMRevisionManager
2
+ from .disk import DBRevisionManager
@@ -1,33 +1,33 @@
1
- from abc import abstractmethod
2
- from typing import Optional
3
-
4
- from amulet.api.history.base import RevisionManager
5
- from ..data_types import EntryType
6
-
7
-
8
- class DBRevisionManager(RevisionManager):
9
- """A class to hold data about an entries history on disk.
10
- Revision indexes are still stored in RAM."""
11
-
12
- __slots__ = ("_prefix",)
13
-
14
- def __init__(self, prefix: str, initial_state: EntryType):
15
- self._prefix: str = prefix
16
- super().__init__(initial_state)
17
-
18
- def _store_entry(self, entry: EntryType):
19
- path = f"{self._prefix}/{len(self._revisions)}"
20
- path = self._serialise(path, entry)
21
- self._revisions.append(path)
22
-
23
- @abstractmethod
24
- def _serialise(self, path: str, entry: EntryType) -> Optional[str]:
25
- raise NotImplementedError
26
-
27
- def get_current_entry(self):
28
- path = self._revisions[self._current_revision_index]
29
- return self._deserialise(path)
30
-
31
- @abstractmethod
32
- def _deserialise(self, path: str) -> EntryType:
33
- raise NotImplementedError
1
+ from abc import abstractmethod
2
+ from typing import Optional
3
+
4
+ from amulet.api.history.base import RevisionManager
5
+ from ..data_types import EntryType
6
+
7
+
8
+ class DBRevisionManager(RevisionManager):
9
+ """A class to hold data about an entries history on disk.
10
+ Revision indexes are still stored in RAM."""
11
+
12
+ __slots__ = ("_prefix",)
13
+
14
+ def __init__(self, prefix: str, initial_state: EntryType):
15
+ self._prefix: str = prefix
16
+ super().__init__(initial_state)
17
+
18
+ def _store_entry(self, entry: EntryType):
19
+ path = f"{self._prefix}/{len(self._revisions)}"
20
+ path = self._serialise(path, entry)
21
+ self._revisions.append(path)
22
+
23
+ @abstractmethod
24
+ def _serialise(self, path: str, entry: EntryType) -> Optional[str]:
25
+ raise NotImplementedError
26
+
27
+ def get_current_entry(self):
28
+ path = self._revisions[self._current_revision_index]
29
+ return self._deserialise(path)
30
+
31
+ @abstractmethod
32
+ def _deserialise(self, path: str) -> EntryType:
33
+ raise NotImplementedError
@@ -1,12 +1,12 @@
1
- from amulet.api.history.base import RevisionManager
2
- from ..data_types import EntryType
3
-
4
-
5
- class RAMRevisionManager(RevisionManager):
6
- """A class to hold data about an entries history in RAM."""
7
-
8
- def _store_entry(self, entry: EntryType):
9
- self._revisions.append(entry)
10
-
11
- def get_current_entry(self):
12
- return self._revisions[self._current_revision_index]
1
+ from amulet.api.history.base import RevisionManager
2
+ from ..data_types import EntryType
3
+
4
+
5
+ class RAMRevisionManager(RevisionManager):
6
+ """A class to hold data about an entries history in RAM."""
7
+
8
+ def _store_entry(self, entry: EntryType):
9
+ self._revisions.append(entry)
10
+
11
+ def get_current_entry(self):
12
+ return self._revisions[self._current_revision_index]
amulet/api/item.py CHANGED
@@ -1,75 +1,75 @@
1
- from amulet_nbt import CompoundTag, StringTag
2
-
3
-
4
- class Item(CompoundTag):
5
- """
6
- {
7
- "namespace": StringTag,
8
- "base_name": StringTag,
9
- "metadata": CompoundTag
10
- }
11
- """
12
-
13
- def __init__(self, namespace: str, base_name: str, metadata: dict = None):
14
- super().__init__(
15
- {
16
- "namespace": StringTag(namespace),
17
- "base_name": StringTag(base_name),
18
- "metadata": CompoundTag(metadata or {}),
19
- }
20
- )
21
-
22
- @property
23
- def namespace(self) -> str:
24
- return self.get_string("namespace").py_str
25
-
26
- @property
27
- def base_name(self) -> str:
28
- return self.get_string("base_name").py_str
29
-
30
- @property
31
- def metadata(self) -> CompoundTag:
32
- return self.get_compound("metadata")
33
-
34
-
35
- class BlockItem(CompoundTag):
36
- """
37
- {
38
- "namespace": StringTag,
39
- "base_name": StringTag,
40
- "properties": CompoundTag
41
- "metadata": CompoundTag
42
- }
43
- """
44
-
45
- def __init__(
46
- self,
47
- namespace: str,
48
- base_name: str,
49
- properties: dict = None,
50
- metadata: dict = None,
51
- ):
52
- super().__init__(
53
- {
54
- "namespace": StringTag(namespace),
55
- "base_name": StringTag(base_name),
56
- "properties": CompoundTag(properties or {}),
57
- "metadata": CompoundTag(metadata or {}),
58
- }
59
- )
60
-
61
- @property
62
- def namespace(self) -> str:
63
- return self.get_string("namespace").py_str
64
-
65
- @property
66
- def base_name(self) -> str:
67
- return self.get_string("base_name").py_str
68
-
69
- @property
70
- def properties(self) -> CompoundTag:
71
- return self.get_compound("properties")
72
-
73
- @property
74
- def metadata(self) -> CompoundTag:
75
- return self.get_compound("metadata")
1
+ from amulet_nbt import CompoundTag, StringTag
2
+
3
+
4
+ class Item(CompoundTag):
5
+ """
6
+ {
7
+ "namespace": StringTag,
8
+ "base_name": StringTag,
9
+ "metadata": CompoundTag
10
+ }
11
+ """
12
+
13
+ def __init__(self, namespace: str, base_name: str, metadata: dict = None):
14
+ super().__init__(
15
+ {
16
+ "namespace": StringTag(namespace),
17
+ "base_name": StringTag(base_name),
18
+ "metadata": CompoundTag(metadata or {}),
19
+ }
20
+ )
21
+
22
+ @property
23
+ def namespace(self) -> str:
24
+ return self.get_string("namespace").py_str
25
+
26
+ @property
27
+ def base_name(self) -> str:
28
+ return self.get_string("base_name").py_str
29
+
30
+ @property
31
+ def metadata(self) -> CompoundTag:
32
+ return self.get_compound("metadata")
33
+
34
+
35
+ class BlockItem(CompoundTag):
36
+ """
37
+ {
38
+ "namespace": StringTag,
39
+ "base_name": StringTag,
40
+ "properties": CompoundTag
41
+ "metadata": CompoundTag
42
+ }
43
+ """
44
+
45
+ def __init__(
46
+ self,
47
+ namespace: str,
48
+ base_name: str,
49
+ properties: dict = None,
50
+ metadata: dict = None,
51
+ ):
52
+ super().__init__(
53
+ {
54
+ "namespace": StringTag(namespace),
55
+ "base_name": StringTag(base_name),
56
+ "properties": CompoundTag(properties or {}),
57
+ "metadata": CompoundTag(metadata or {}),
58
+ }
59
+ )
60
+
61
+ @property
62
+ def namespace(self) -> str:
63
+ return self.get_string("namespace").py_str
64
+
65
+ @property
66
+ def base_name(self) -> str:
67
+ return self.get_string("base_name").py_str
68
+
69
+ @property
70
+ def properties(self) -> CompoundTag:
71
+ return self.get_compound("properties")
72
+
73
+ @property
74
+ def metadata(self) -> CompoundTag:
75
+ return self.get_compound("metadata")