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.
- bedrockplus/__init__.py +95 -0
- bedrockplus/__main__.py +4 -0
- bedrockplus/_assets/Initialize-BedrockPlusServer.ps1 +395 -0
- bedrockplus/_assets/README.md +85 -0
- bedrockplus/_assets/SHA256SUMS +20 -0
- bedrockplus/_assets/Start-BedrockPlus.ps1 +125 -0
- bedrockplus/_assets/THIRD_PARTY_NOTICES.md +26 -0
- bedrockplus/_assets/bedrockplus.exe +0 -0
- bedrockplus/_assets/bedrockplus_bootstrap.dll +0 -0
- bedrockplus/_assets/bedrockplus_plugin_host.dll +0 -0
- bedrockplus/_assets/bedrockplus_plugin_worker.dll +0 -0
- bedrockplus/_assets/bedrockplus_runtime.dll +0 -0
- bedrockplus/_assets/bin/bedrockplus.ps1 +192 -0
- bedrockplus/_assets/compatibility/bds/1.26.51.1/windows-x64.json +24 -0
- bedrockplus/_assets/compatibility/bds/supported-versions.json +14 -0
- bedrockplus/_assets/licenses/microsoft-detours-MIT.txt +23 -0
- bedrockplus/_assets/plugins/README.txt +11 -0
- bedrockplus/_assets/release-manifest.json +34 -0
- bedrockplus/_assets/server/README.txt +10 -0
- bedrockplus/_assets/tools/bppack.py +1865 -0
- bedrockplus/_assets/tools/init_python_plugin.py +140 -0
- bedrockplus/_assets/tools/pack_plugin.py +142 -0
- bedrockplus/_assets/tools/world_packs.py +530 -0
- bedrockplus/api.py +83 -0
- bedrockplus/cli.py +121 -0
- bedrockplus/commands.py +50 -0
- bedrockplus/events.py +138 -0
- bedrockplus/objects.py +413 -0
- bedrockplus/py.typed +1 -0
- bedrockplus-0.1.0.dev1.dist-info/METADATA +41 -0
- bedrockplus-0.1.0.dev1.dist-info/RECORD +36 -0
- bedrockplus-0.1.0.dev1.dist-info/WHEEL +4 -0
- bedrockplus-0.1.0.dev1.dist-info/entry_points.txt +2 -0
- bedrockplus-0.1.0.dev1.dist-info/licenses/THIRD_PARTY_NOTICES.md +26 -0
- bedrockplus-0.1.0.dev1.dist-info/licenses/microsoft-detours-MIT.txt +23 -0
- 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())
|
bedrockplus/commands.py
ADDED
|
@@ -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]
|