bedrockplus 0.1.0.dev1__py3-none-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.
Files changed (36) hide show
  1. bedrockplus/__init__.py +95 -0
  2. bedrockplus/__main__.py +4 -0
  3. bedrockplus/_assets/Initialize-BedrockPlusServer.ps1 +395 -0
  4. bedrockplus/_assets/README.md +85 -0
  5. bedrockplus/_assets/SHA256SUMS +20 -0
  6. bedrockplus/_assets/Start-BedrockPlus.ps1 +125 -0
  7. bedrockplus/_assets/THIRD_PARTY_NOTICES.md +26 -0
  8. bedrockplus/_assets/bedrockplus.exe +0 -0
  9. bedrockplus/_assets/bedrockplus_bootstrap.dll +0 -0
  10. bedrockplus/_assets/bedrockplus_plugin_host.dll +0 -0
  11. bedrockplus/_assets/bedrockplus_plugin_worker.dll +0 -0
  12. bedrockplus/_assets/bedrockplus_runtime.dll +0 -0
  13. bedrockplus/_assets/bin/bedrockplus.ps1 +192 -0
  14. bedrockplus/_assets/compatibility/bds/1.26.51.1/windows-x64.json +24 -0
  15. bedrockplus/_assets/compatibility/bds/supported-versions.json +14 -0
  16. bedrockplus/_assets/licenses/microsoft-detours-MIT.txt +23 -0
  17. bedrockplus/_assets/plugins/README.txt +11 -0
  18. bedrockplus/_assets/release-manifest.json +34 -0
  19. bedrockplus/_assets/server/README.txt +10 -0
  20. bedrockplus/_assets/tools/bppack.py +1865 -0
  21. bedrockplus/_assets/tools/init_python_plugin.py +140 -0
  22. bedrockplus/_assets/tools/pack_plugin.py +142 -0
  23. bedrockplus/_assets/tools/world_packs.py +530 -0
  24. bedrockplus/api.py +83 -0
  25. bedrockplus/cli.py +121 -0
  26. bedrockplus/commands.py +50 -0
  27. bedrockplus/events.py +138 -0
  28. bedrockplus/objects.py +413 -0
  29. bedrockplus/py.typed +1 -0
  30. bedrockplus-0.1.0.dev1.dist-info/METADATA +41 -0
  31. bedrockplus-0.1.0.dev1.dist-info/RECORD +36 -0
  32. bedrockplus-0.1.0.dev1.dist-info/WHEEL +4 -0
  33. bedrockplus-0.1.0.dev1.dist-info/entry_points.txt +2 -0
  34. bedrockplus-0.1.0.dev1.dist-info/licenses/THIRD_PARTY_NOTICES.md +26 -0
  35. bedrockplus-0.1.0.dev1.dist-info/licenses/microsoft-detours-MIT.txt +23 -0
  36. bedrockplus-0.1.0.dev1.dist-info/top_level.txt +1 -0
bedrockplus/cli.py ADDED
@@ -0,0 +1,121 @@
1
+ """Public command entry point for the BedrockPlus Windows distribution."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ import json
7
+ import os
8
+ from pathlib import Path
9
+ import shutil
10
+ import subprocess
11
+ import sys
12
+
13
+
14
+ class DistributionError(RuntimeError):
15
+ pass
16
+
17
+
18
+ def _release_root() -> tuple[Path, bool]:
19
+ packaged = Path(__file__).resolve().parent / "_assets"
20
+ if (packaged.joinpath("release-manifest.json").is_file()):
21
+ return packaged, True
22
+
23
+ # Editable SDK installs inside the private repository remain useful to the
24
+ # publisher without embedding private project files in the public wheel.
25
+ candidate = Path(__file__).resolve().parents[4]
26
+ if candidate.joinpath("bin", "bedrockplus.ps1").is_file():
27
+ return candidate, False
28
+ raise DistributionError(
29
+ "BedrockPlus runtime assets are missing. Reinstall the official Windows wheel."
30
+ )
31
+
32
+
33
+ def _verify_release(root: Path) -> None:
34
+ manifest_path = root / "release-manifest.json"
35
+ try:
36
+ manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
37
+ except (OSError, UnicodeError, json.JSONDecodeError) as error:
38
+ raise DistributionError("BedrockPlus release metadata is unreadable") from error
39
+ if (
40
+ not isinstance(manifest, dict)
41
+ or manifest.get("product") != "BedrockPlus"
42
+ or manifest.get("platform") != "windows-x64"
43
+ or not isinstance(manifest.get("files"), list)
44
+ ):
45
+ raise DistributionError("BedrockPlus release metadata is invalid")
46
+ for record in manifest["files"]:
47
+ if not isinstance(record, dict) or set(record) != {
48
+ "path", "role", "size_bytes", "sha256"
49
+ }:
50
+ raise DistributionError("BedrockPlus release inventory is invalid")
51
+ relative = record["path"]
52
+ if (
53
+ not isinstance(relative, str)
54
+ or not relative
55
+ or "\\" in relative
56
+ or relative.startswith("/")
57
+ or any(part in {"", ".", ".."} for part in relative.split("/"))
58
+ ):
59
+ raise DistributionError("BedrockPlus release path is invalid")
60
+ path = root.joinpath(*relative.split("/"))
61
+ try:
62
+ data = path.read_bytes()
63
+ except OSError as error:
64
+ raise DistributionError(f"BedrockPlus release file is missing: {relative}") from error
65
+ expected_size = record["size_bytes"]
66
+ expected_hash = record["sha256"]
67
+ if (
68
+ type(expected_size) is not int
69
+ or expected_size < 0
70
+ or not isinstance(expected_hash, str)
71
+ or len(expected_hash) != 64
72
+ or len(data) != expected_size
73
+ or hashlib.sha256(data).hexdigest() != expected_hash
74
+ ):
75
+ raise DistributionError(f"BedrockPlus release verification failed: {relative}")
76
+
77
+
78
+ def main() -> int:
79
+ if os.name != "nt" or sys.maxsize <= 2**32:
80
+ print("BedrockPlus currently requires 64-bit Windows.", file=sys.stderr)
81
+ return 1
82
+ if sys.version_info[:2] != (3, 13):
83
+ print("BedrockPlus currently requires Python 3.13.x.", file=sys.stderr)
84
+ return 1
85
+ try:
86
+ release_root, packaged = _release_root()
87
+ if packaged:
88
+ _verify_release(release_root)
89
+ wrapper = release_root / "bin" / "bedrockplus.ps1"
90
+ if not wrapper.is_file():
91
+ raise DistributionError("BedrockPlus command wrapper is missing")
92
+ powershell = shutil.which("powershell.exe")
93
+ if not powershell:
94
+ raise DistributionError("Windows PowerShell is required to run BedrockPlus")
95
+ environment = os.environ.copy()
96
+ environment["BEDROCKPLUS_PYTHON_EXECUTABLE"] = sys.executable
97
+ completed = subprocess.run(
98
+ [
99
+ powershell,
100
+ "-NoLogo",
101
+ "-NoProfile",
102
+ "-ExecutionPolicy",
103
+ "Bypass",
104
+ "-File",
105
+ str(wrapper),
106
+ *sys.argv[1:],
107
+ ],
108
+ env=environment,
109
+ check=False,
110
+ )
111
+ return completed.returncode
112
+ except KeyboardInterrupt:
113
+ print("\nBedrockPlus stopped.", file=sys.stderr)
114
+ return 130
115
+ except (DistributionError, OSError) as error:
116
+ print(f"BedrockPlus failed: {error}", file=sys.stderr)
117
+ return 1
118
+
119
+
120
+ if __name__ == "__main__":
121
+ raise SystemExit(main())
@@ -0,0 +1,50 @@
1
+ """Typed command declarations for BedrockPlus Python plugins."""
2
+
3
+ from collections.abc import Callable, Sequence
4
+ from enum import IntEnum
5
+ from typing import Literal, NotRequired, TypeAlias, TypedDict
6
+
7
+ CommandArgumentType: TypeAlias = Literal[
8
+ "int", "integer", "float", "real", "number", "string", "str", "text", "message", "enum"
9
+ ]
10
+ CommandValue: TypeAlias = int | float | str
11
+
12
+
13
+ class CommandSourceKind(IntEnum):
14
+ CONSOLE = 0
15
+ PLAYER = 1
16
+
17
+
18
+ class CommandArgument(TypedDict):
19
+ """One typed argument in a command overload."""
20
+
21
+ name: str
22
+ type: CommandArgumentType
23
+ optional: NotRequired[bool]
24
+ choices: NotRequired[Sequence[str]]
25
+
26
+
27
+ CommandOverload: TypeAlias = Sequence[CommandArgument]
28
+
29
+
30
+ class CommandInvocation(TypedDict):
31
+ """Input passed to a registered command callback."""
32
+
33
+ source_kind: CommandSourceKind
34
+ source_name: str
35
+ source_identity: str
36
+ command: str
37
+ arguments: str
38
+ args: list[CommandValue]
39
+
40
+
41
+ class CommandResult(TypedDict, total=False):
42
+ """Structured command callback result."""
43
+
44
+ succeeded: bool
45
+ message: str
46
+ error_code: str
47
+
48
+
49
+ CommandReturn: TypeAlias = None | bool | str | CommandResult
50
+ CommandCallback: TypeAlias = Callable[[CommandInvocation], CommandReturn]
bedrockplus/events.py ADDED
@@ -0,0 +1,138 @@
1
+ """Typed event declarations for BedrockPlus Python plugins.
2
+
3
+ Callbacks receive mutable dictionaries. For cancellable events, set
4
+ ``event["cancelled"] = True``. Mutable fields are written back by changing
5
+ entries in ``event["fields"]``.
6
+ """
7
+
8
+ from enum import IntEnum
9
+ from typing import Literal, NotRequired, Required, TypeAlias, TypedDict
10
+
11
+
12
+ class EventPriority(IntEnum):
13
+ LOWEST = -200
14
+ LOW = -100
15
+ NORMAL = 0
16
+ HIGH = 100
17
+ HIGHEST = 200
18
+ MONITOR = 300
19
+
20
+
21
+ EventName: TypeAlias = Literal[
22
+ "server.tick",
23
+ "player.join",
24
+ "player.quit",
25
+ "player.chat",
26
+ "block.break",
27
+ "block.place",
28
+ "server.list_ping",
29
+ "player.jump",
30
+ "player.kick",
31
+ "player.login",
32
+ "player.move",
33
+ "server.command",
34
+ "player.command",
35
+ ]
36
+
37
+
38
+ class Event(TypedDict):
39
+ name: EventName
40
+ sequence: int
41
+ fields: NotRequired[dict[str, str]]
42
+
43
+
44
+ class CancellableEvent(Event):
45
+ cancellable: bool
46
+ cancelled: bool
47
+
48
+
49
+ PlayerLifecycleFields = TypedDict(
50
+ "PlayerLifecycleFields",
51
+ {
52
+ "player.name": Required[str],
53
+ "player.session": Required[str],
54
+ "player.uuid": NotRequired[str],
55
+ "player.xuid": NotRequired[str],
56
+ "player.address": NotRequired[str],
57
+ "player.port": NotRequired[str],
58
+ "player.ping_ms": NotRequired[str],
59
+ "player.device_id": NotRequired[str],
60
+ "player.device_model": NotRequired[str],
61
+ "player.device_os": NotRequired[str],
62
+ "player.input_mode": NotRequired[str],
63
+ "player.game_version": NotRequired[str],
64
+ "player.locale": NotRequired[str],
65
+ "player.client_fps": NotRequired[str],
66
+ },
67
+ )
68
+ ServerCommandFields = TypedDict(
69
+ "ServerCommandFields",
70
+ {
71
+ "command": str,
72
+ "command.name": str,
73
+ "source.kind": str,
74
+ "source.name": str,
75
+ },
76
+ )
77
+ PlayerCommandFields = TypedDict(
78
+ "PlayerCommandFields",
79
+ {
80
+ "command": str,
81
+ "command.name": str,
82
+ "source.kind": str,
83
+ "source.name": str,
84
+ "player.name": str,
85
+ },
86
+ )
87
+
88
+
89
+ class ServerTickEvent(Event):
90
+ pass
91
+
92
+
93
+ class PlayerJoinEvent(Event):
94
+ fields: Required[PlayerLifecycleFields]
95
+
96
+
97
+ class PlayerQuitEvent(Event):
98
+ fields: Required[PlayerLifecycleFields]
99
+
100
+
101
+ class PlayerChatEvent(CancellableEvent):
102
+ pass
103
+
104
+
105
+ class BlockBreakEvent(CancellableEvent):
106
+ pass
107
+
108
+
109
+ class BlockPlaceEvent(CancellableEvent):
110
+ pass
111
+
112
+
113
+ class ServerListPingEvent(Event):
114
+ pass
115
+
116
+
117
+ class PlayerJumpEvent(Event):
118
+ pass
119
+
120
+
121
+ class PlayerKickEvent(CancellableEvent):
122
+ pass
123
+
124
+
125
+ class PlayerLoginEvent(CancellableEvent):
126
+ pass
127
+
128
+
129
+ class PlayerMoveEvent(CancellableEvent):
130
+ pass
131
+
132
+
133
+ class ServerCommandEvent(CancellableEvent):
134
+ fields: Required[ServerCommandFields]
135
+
136
+
137
+ class PlayerCommandEvent(CancellableEvent):
138
+ fields: Required[PlayerCommandFields]