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/objects.py
ADDED
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
"""Small typed object layer built on the stable BedrockPlus host API.
|
|
2
|
+
|
|
3
|
+
These wrappers deliberately expose only operations that the current host can
|
|
4
|
+
perform reliably. Command-backed methods return queue acceptance; they do not
|
|
5
|
+
claim that BDS successfully completed the command.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
import math
|
|
12
|
+
import re
|
|
13
|
+
from collections.abc import Mapping
|
|
14
|
+
from dataclasses import dataclass
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
from .api import PluginHost
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
_FORMAT_CODE = re.compile(r"&([0-9a-fk-or])", re.IGNORECASE)
|
|
21
|
+
_RESOURCE_ID = re.compile(r"^[a-z0-9_.-]+:[a-z0-9_./-]+$")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _format_message(message: str) -> str:
|
|
25
|
+
"""Translate plugin-friendly ``&a`` formatting to Minecraft ``§a``."""
|
|
26
|
+
if not isinstance(message, str):
|
|
27
|
+
raise TypeError("message must be a string")
|
|
28
|
+
if "\x00" in message or "\r" in message or "\n" in message:
|
|
29
|
+
raise ValueError("message may not contain NUL or line breaks")
|
|
30
|
+
if len(message) > 4096:
|
|
31
|
+
raise ValueError("message exceeds 4096 characters")
|
|
32
|
+
return _FORMAT_CODE.sub(lambda match: f"§{match.group(1)}", message)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _command_line(command: str) -> str:
|
|
36
|
+
if not isinstance(command, str):
|
|
37
|
+
raise TypeError("command must be a string")
|
|
38
|
+
command = command.strip()
|
|
39
|
+
if command.startswith("/"):
|
|
40
|
+
command = command[1:].lstrip()
|
|
41
|
+
if not command:
|
|
42
|
+
raise ValueError("command may not be empty")
|
|
43
|
+
if "\x00" in command or "\r" in command or "\n" in command:
|
|
44
|
+
raise ValueError("command may not contain NUL or line breaks")
|
|
45
|
+
if len(command) > 4096:
|
|
46
|
+
raise ValueError("command exceeds 4096 characters")
|
|
47
|
+
return command
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _selector_name(name: str) -> str:
|
|
51
|
+
if not isinstance(name, str):
|
|
52
|
+
raise TypeError("player name must be a string")
|
|
53
|
+
name = name.strip()
|
|
54
|
+
if not name:
|
|
55
|
+
raise ValueError("player name may not be empty")
|
|
56
|
+
if "\x00" in name or "\r" in name or "\n" in name:
|
|
57
|
+
raise ValueError("player name may not contain NUL or line breaks")
|
|
58
|
+
if len(name) > 128:
|
|
59
|
+
raise ValueError("player name exceeds 128 characters")
|
|
60
|
+
escaped = name.replace("\\", "\\\\").replace('"', '\\"')
|
|
61
|
+
return f'@a[name="{escaped}",c=1]'
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _optional_int(value: str | None) -> int | None:
|
|
65
|
+
if value is None or value == "":
|
|
66
|
+
return None
|
|
67
|
+
try:
|
|
68
|
+
return int(value)
|
|
69
|
+
except ValueError:
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _optional_float(value: str | None) -> float | None:
|
|
74
|
+
if value is None or value == "":
|
|
75
|
+
return None
|
|
76
|
+
try:
|
|
77
|
+
parsed = float(value)
|
|
78
|
+
except ValueError:
|
|
79
|
+
return None
|
|
80
|
+
return parsed if math.isfinite(parsed) else None
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@dataclass(frozen=True, slots=True)
|
|
84
|
+
class Vector3:
|
|
85
|
+
"""Immutable three-dimensional position or direction snapshot."""
|
|
86
|
+
|
|
87
|
+
x: float
|
|
88
|
+
y: float
|
|
89
|
+
z: float
|
|
90
|
+
|
|
91
|
+
def __post_init__(self) -> None:
|
|
92
|
+
for value in (self.x, self.y, self.z):
|
|
93
|
+
if not isinstance(value, (int, float)) or not math.isfinite(value):
|
|
94
|
+
raise ValueError("Vector3 values must be finite numbers")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@dataclass(frozen=True, slots=True)
|
|
98
|
+
class SocketAddress:
|
|
99
|
+
"""A copied network endpoint; no native connection object is retained."""
|
|
100
|
+
|
|
101
|
+
host: str
|
|
102
|
+
port: int
|
|
103
|
+
|
|
104
|
+
def __post_init__(self) -> None:
|
|
105
|
+
if not self.host or "\x00" in self.host or len(self.host) > 255:
|
|
106
|
+
raise ValueError("host must be a bounded non-empty string")
|
|
107
|
+
if not 0 <= self.port <= 65535:
|
|
108
|
+
raise ValueError("port must be between 0 and 65535")
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@dataclass(frozen=True, slots=True)
|
|
112
|
+
class ConnectionInfo:
|
|
113
|
+
"""Optional client-connection facts copied from an authenticated event.
|
|
114
|
+
|
|
115
|
+
Availability is capability-based. Unsupported or unavailable properties are
|
|
116
|
+
``None``/empty rather than guessed. Device IDs and IP addresses are sensitive
|
|
117
|
+
personal data and should not be logged or persisted without a clear need.
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
address: SocketAddress | None = None
|
|
121
|
+
ping_ms: int | None = None
|
|
122
|
+
device_id: str = ""
|
|
123
|
+
device_model: str = ""
|
|
124
|
+
device_os: str = ""
|
|
125
|
+
input_mode: str = ""
|
|
126
|
+
game_version: str = ""
|
|
127
|
+
locale: str = ""
|
|
128
|
+
client_fps: float | None = None
|
|
129
|
+
|
|
130
|
+
def __post_init__(self) -> None:
|
|
131
|
+
if self.ping_ms is not None and self.ping_ms < 0:
|
|
132
|
+
raise ValueError("ping_ms may not be negative")
|
|
133
|
+
if self.client_fps is not None and (
|
|
134
|
+
not math.isfinite(self.client_fps) or self.client_fps < 0
|
|
135
|
+
):
|
|
136
|
+
raise ValueError("client_fps must be a finite non-negative value")
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@dataclass(frozen=True, slots=True)
|
|
140
|
+
class Location:
|
|
141
|
+
"""Copied world location suitable for event snapshots."""
|
|
142
|
+
|
|
143
|
+
level_name: str
|
|
144
|
+
dimension_id: str
|
|
145
|
+
position: Vector3
|
|
146
|
+
yaw: float = 0.0
|
|
147
|
+
pitch: float = 0.0
|
|
148
|
+
|
|
149
|
+
def __post_init__(self) -> None:
|
|
150
|
+
if not self.level_name or len(self.level_name) > 128:
|
|
151
|
+
raise ValueError("level_name must be a bounded non-empty string")
|
|
152
|
+
if not self.dimension_id or len(self.dimension_id) > 128:
|
|
153
|
+
raise ValueError("dimension_id must be a bounded non-empty string")
|
|
154
|
+
if not math.isfinite(self.yaw) or not math.isfinite(self.pitch):
|
|
155
|
+
raise ValueError("yaw and pitch must be finite")
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@dataclass(frozen=True, slots=True)
|
|
159
|
+
class Level:
|
|
160
|
+
"""Lightweight identity for a BDS level and dimension."""
|
|
161
|
+
|
|
162
|
+
server: Server
|
|
163
|
+
name: str
|
|
164
|
+
dimension_id: str = "minecraft:overworld"
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
@dataclass(frozen=True, slots=True)
|
|
168
|
+
class Entity:
|
|
169
|
+
"""Copied entity identity; it never exposes or retains a BDS pointer."""
|
|
170
|
+
|
|
171
|
+
server: Server
|
|
172
|
+
runtime_id: int
|
|
173
|
+
type_id: str
|
|
174
|
+
location: Location | None = None
|
|
175
|
+
|
|
176
|
+
def __post_init__(self) -> None:
|
|
177
|
+
if self.runtime_id < 0:
|
|
178
|
+
raise ValueError("runtime_id may not be negative")
|
|
179
|
+
if not _RESOURCE_ID.fullmatch(self.type_id):
|
|
180
|
+
raise ValueError("type_id must be a namespaced resource identifier")
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
@dataclass(frozen=True, slots=True)
|
|
184
|
+
class ItemStack:
|
|
185
|
+
"""Immutable item snapshot used by inventory and item events."""
|
|
186
|
+
|
|
187
|
+
type_id: str
|
|
188
|
+
amount: int = 1
|
|
189
|
+
aux_value: int = 0
|
|
190
|
+
custom_name: str = ""
|
|
191
|
+
|
|
192
|
+
def __post_init__(self) -> None:
|
|
193
|
+
if not _RESOURCE_ID.fullmatch(self.type_id):
|
|
194
|
+
raise ValueError("type_id must be a namespaced resource identifier")
|
|
195
|
+
if not 0 <= self.amount <= 255:
|
|
196
|
+
raise ValueError("amount must be between 0 and 255")
|
|
197
|
+
if len(self.custom_name) > 1024 or any(c in self.custom_name for c in "\x00\r\n"):
|
|
198
|
+
raise ValueError("custom_name is invalid")
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
class Server:
|
|
202
|
+
"""Plugin-scoped view of the running BedrockPlus server."""
|
|
203
|
+
|
|
204
|
+
def __init__(self, host: PluginHost) -> None:
|
|
205
|
+
self._host = host
|
|
206
|
+
|
|
207
|
+
@property
|
|
208
|
+
def name(self) -> str:
|
|
209
|
+
"""Product name for this server runtime."""
|
|
210
|
+
return "BedrockPlus"
|
|
211
|
+
|
|
212
|
+
@property
|
|
213
|
+
def api_version(self) -> int:
|
|
214
|
+
"""BedrockPlus plugin API version implemented by this object."""
|
|
215
|
+
return 1
|
|
216
|
+
|
|
217
|
+
@property
|
|
218
|
+
def data_directory(self) -> Path:
|
|
219
|
+
"""Private writable data directory for the calling plugin."""
|
|
220
|
+
return Path(self._host.data_directory())
|
|
221
|
+
|
|
222
|
+
def dispatch_command(self, command: str) -> bool:
|
|
223
|
+
"""Queue a vanilla or BedrockPlus command as the server console."""
|
|
224
|
+
return self._host.dispatch_server_command(_command_line(command))
|
|
225
|
+
|
|
226
|
+
def broadcast(self, message: str) -> bool:
|
|
227
|
+
"""Queue a tellraw message for every online player.
|
|
228
|
+
|
|
229
|
+
Minecraft formatting such as ``&aGreen`` is translated to ``§aGreen``.
|
|
230
|
+
The JSON payload is ASCII-safe for the Windows BDS console boundary.
|
|
231
|
+
"""
|
|
232
|
+
payload = json.dumps(
|
|
233
|
+
{"rawtext": [{"text": _format_message(message)}]},
|
|
234
|
+
ensure_ascii=True,
|
|
235
|
+
separators=(",", ":"),
|
|
236
|
+
)
|
|
237
|
+
return self.dispatch_command(f"tellraw @a {payload}")
|
|
238
|
+
|
|
239
|
+
def player(self, name: str, session_id: str = "") -> Player:
|
|
240
|
+
"""Create a lightweight player reference from known identity fields."""
|
|
241
|
+
return Player(server=self, name=name, session_id=session_id)
|
|
242
|
+
|
|
243
|
+
def level(
|
|
244
|
+
self,
|
|
245
|
+
name: str = "BedrockPlus",
|
|
246
|
+
dimension_id: str = "minecraft:overworld",
|
|
247
|
+
) -> Level:
|
|
248
|
+
"""Create a lightweight level/dimension identity."""
|
|
249
|
+
return Level(server=self, name=name, dimension_id=dimension_id)
|
|
250
|
+
|
|
251
|
+
def entity(
|
|
252
|
+
self,
|
|
253
|
+
runtime_id: int,
|
|
254
|
+
type_id: str,
|
|
255
|
+
location: Location | None = None,
|
|
256
|
+
) -> Entity:
|
|
257
|
+
"""Create a copied entity snapshot without retaining native state."""
|
|
258
|
+
return Entity(self, runtime_id, type_id, location)
|
|
259
|
+
|
|
260
|
+
def item_stack(
|
|
261
|
+
self,
|
|
262
|
+
type_id: str,
|
|
263
|
+
amount: int = 1,
|
|
264
|
+
aux_value: int = 0,
|
|
265
|
+
custom_name: str = "",
|
|
266
|
+
) -> ItemStack:
|
|
267
|
+
"""Create an immutable item value for plugin-owned state and commands."""
|
|
268
|
+
return ItemStack(type_id, amount, aux_value, custom_name)
|
|
269
|
+
|
|
270
|
+
def player_from_event(self, event: Mapping[str, object]) -> Player:
|
|
271
|
+
"""Create a player reference from any event containing player fields.
|
|
272
|
+
|
|
273
|
+
``Mapping`` is intentional here: specialized event ``TypedDict`` types
|
|
274
|
+
such as :class:`PlayerJoinEvent` narrow ``fields`` to their own schema
|
|
275
|
+
and therefore are not type-compatible with the mutable generic
|
|
276
|
+
:class:`Event` dictionary.
|
|
277
|
+
"""
|
|
278
|
+
raw_fields = event.get("fields")
|
|
279
|
+
if not isinstance(raw_fields, Mapping):
|
|
280
|
+
raise ValueError("event does not contain player fields")
|
|
281
|
+
|
|
282
|
+
def text_field(key: str) -> str:
|
|
283
|
+
value = raw_fields.get(key)
|
|
284
|
+
return value if isinstance(value, str) else ""
|
|
285
|
+
|
|
286
|
+
name = text_field("player.name")
|
|
287
|
+
if not name:
|
|
288
|
+
raise ValueError("event does not contain player.name")
|
|
289
|
+
address = None
|
|
290
|
+
address_host = text_field("player.address")
|
|
291
|
+
address_port = _optional_int(text_field("player.port"))
|
|
292
|
+
if address_host and address_port is not None:
|
|
293
|
+
try:
|
|
294
|
+
address = SocketAddress(address_host, address_port)
|
|
295
|
+
except ValueError:
|
|
296
|
+
address = None
|
|
297
|
+
connection_values = (
|
|
298
|
+
address,
|
|
299
|
+
_optional_int(text_field("player.ping_ms")),
|
|
300
|
+
text_field("player.device_id"),
|
|
301
|
+
text_field("player.device_model"),
|
|
302
|
+
text_field("player.device_os"),
|
|
303
|
+
text_field("player.input_mode"),
|
|
304
|
+
text_field("player.game_version"),
|
|
305
|
+
text_field("player.locale"),
|
|
306
|
+
_optional_float(text_field("player.client_fps")),
|
|
307
|
+
)
|
|
308
|
+
connection = (
|
|
309
|
+
ConnectionInfo(*connection_values)
|
|
310
|
+
if any(value not in (None, "") for value in connection_values)
|
|
311
|
+
else None
|
|
312
|
+
)
|
|
313
|
+
return Player(
|
|
314
|
+
server=self,
|
|
315
|
+
name=name,
|
|
316
|
+
session_id=text_field("player.session"),
|
|
317
|
+
unique_id=text_field("player.uuid"),
|
|
318
|
+
xuid=text_field("player.xuid"),
|
|
319
|
+
connection=connection,
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
@dataclass(frozen=True, slots=True)
|
|
324
|
+
class Player:
|
|
325
|
+
"""Lightweight player identity with command-backed operations.
|
|
326
|
+
|
|
327
|
+
A ``Player`` does not keep a native BDS pointer and does not imply that the
|
|
328
|
+
player is still connected. It is safe to retain as identity data, while
|
|
329
|
+
methods may later be accepted by the queue but fail in BDS if the player left.
|
|
330
|
+
"""
|
|
331
|
+
|
|
332
|
+
server: Server
|
|
333
|
+
name: str
|
|
334
|
+
session_id: str = ""
|
|
335
|
+
unique_id: str = ""
|
|
336
|
+
xuid: str = ""
|
|
337
|
+
connection: ConnectionInfo | None = None
|
|
338
|
+
|
|
339
|
+
def __post_init__(self) -> None:
|
|
340
|
+
# Normalize and validate immutable identity fields once.
|
|
341
|
+
normalized_name = self.name.strip()
|
|
342
|
+
_selector_name(normalized_name)
|
|
343
|
+
object.__setattr__(self, "name", normalized_name)
|
|
344
|
+
for field_name in ("session_id", "unique_id", "xuid"):
|
|
345
|
+
value = getattr(self, field_name)
|
|
346
|
+
if not isinstance(value, str):
|
|
347
|
+
raise TypeError(f"{field_name} must be a string")
|
|
348
|
+
if any(character in value for character in "\x00\r\n"):
|
|
349
|
+
raise ValueError(f"{field_name} may not contain NUL or line breaks")
|
|
350
|
+
if len(value) > 512:
|
|
351
|
+
raise ValueError(f"{field_name} exceeds 512 characters")
|
|
352
|
+
|
|
353
|
+
@property
|
|
354
|
+
def display_name(self) -> str:
|
|
355
|
+
return self.name
|
|
356
|
+
|
|
357
|
+
@property
|
|
358
|
+
def selector(self) -> str:
|
|
359
|
+
"""Escaped one-player selector used by command-backed methods."""
|
|
360
|
+
return _selector_name(self.name)
|
|
361
|
+
|
|
362
|
+
@property
|
|
363
|
+
def address(self) -> SocketAddress | None:
|
|
364
|
+
return self.connection.address if self.connection else None
|
|
365
|
+
|
|
366
|
+
@property
|
|
367
|
+
def ping_ms(self) -> int | None:
|
|
368
|
+
return self.connection.ping_ms if self.connection else None
|
|
369
|
+
|
|
370
|
+
@property
|
|
371
|
+
def device_id(self) -> str:
|
|
372
|
+
return self.connection.device_id if self.connection else ""
|
|
373
|
+
|
|
374
|
+
@property
|
|
375
|
+
def device_model(self) -> str:
|
|
376
|
+
return self.connection.device_model if self.connection else ""
|
|
377
|
+
|
|
378
|
+
@property
|
|
379
|
+
def input_mode(self) -> str:
|
|
380
|
+
return self.connection.input_mode if self.connection else ""
|
|
381
|
+
|
|
382
|
+
@property
|
|
383
|
+
def device_os(self) -> str:
|
|
384
|
+
return self.connection.device_os if self.connection else ""
|
|
385
|
+
|
|
386
|
+
@property
|
|
387
|
+
def game_version(self) -> str:
|
|
388
|
+
return self.connection.game_version if self.connection else ""
|
|
389
|
+
|
|
390
|
+
@property
|
|
391
|
+
def locale(self) -> str:
|
|
392
|
+
return self.connection.locale if self.connection else ""
|
|
393
|
+
|
|
394
|
+
def send_message(self, message: str) -> bool:
|
|
395
|
+
"""Queue a private tellraw message for this player."""
|
|
396
|
+
payload = json.dumps(
|
|
397
|
+
{"rawtext": [{"text": _format_message(message)}]},
|
|
398
|
+
ensure_ascii=True,
|
|
399
|
+
separators=(",", ":"),
|
|
400
|
+
)
|
|
401
|
+
return self.server.dispatch_command(f"tellraw {self.selector} {payload}")
|
|
402
|
+
|
|
403
|
+
def run_command(self, command: str) -> bool:
|
|
404
|
+
"""Queue a command with this player as the execution origin entity."""
|
|
405
|
+
return self.server.dispatch_command(
|
|
406
|
+
f"execute as {self.selector} at @s run {_command_line(command)}"
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
def kick(self, reason: str = "Kicked by a BedrockPlus plugin") -> bool:
|
|
410
|
+
"""Queue a vanilla kick command for this player."""
|
|
411
|
+
return self.server.dispatch_command(
|
|
412
|
+
f"kick {self.selector} {_format_message(reason)}"
|
|
413
|
+
)
|
bedrockplus/py.typed
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: bedrockplus
|
|
3
|
+
Version: 0.1.0.dev1
|
|
4
|
+
Summary: BedrockPlus server command and typed Python plugin API
|
|
5
|
+
Author: Turkmen
|
|
6
|
+
Requires-Python: >=3.13,<3.14
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
9
|
+
Classifier: Environment :: Console
|
|
10
|
+
Classifier: Operating System :: Microsoft :: Windows :: Windows 10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Typing :: Typed
|
|
13
|
+
License-File: THIRD_PARTY_NOTICES.md
|
|
14
|
+
License-File: microsoft-detours-MIT.txt
|
|
15
|
+
|
|
16
|
+
# BedrockPlus
|
|
17
|
+
|
|
18
|
+
BedrockPlus is a Windows x64 Bedrock Dedicated Server and plugin platform
|
|
19
|
+
created by Turkmen. This pre-release package installs the global `bedrockplus`
|
|
20
|
+
command and the typed Python plugin API used by Visual Studio Code and other
|
|
21
|
+
Python language servers.
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
pip install bedrockplus
|
|
25
|
+
bedrockplus
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The first server initialization downloads the selected supported BDS archive
|
|
29
|
+
from the official source, verifies its SHA-256, and keeps it in the server's
|
|
30
|
+
`Downloads` directory. BedrockPlus itself does not redistribute BDS.
|
|
31
|
+
|
|
32
|
+
Plugin development commands are grouped below `bedrockplus plugin`:
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
bedrockplus plugin python init "My Plugin"
|
|
36
|
+
bedrockplus plugin pack
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
This package requires 64-bit Python 3.13 and currently supports Windows x64.
|
|
40
|
+
It includes public launcher code, API types, clean release binaries, required
|
|
41
|
+
notices, and no private BedrockPlus source code or debug files.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
bedrockplus-0.1.0.dev1.dist-info/METADATA,sha256=T7cPsYYFAd9EJWKAY9YrAvruvzJTftKqU-O67c6IqMc,1429
|
|
2
|
+
bedrockplus-0.1.0.dev1.dist-info/WHEEL,sha256=wiwg5m8WpyUtzKVa7RZ10snpJ3BzERMjpss-HwWwkpY,109
|
|
3
|
+
bedrockplus-0.1.0.dev1.dist-info/entry_points.txt,sha256=Eir8NvyMKKBDLKYcHXmk7A_9E3EzdcU1-RWq8N5Pnlw,53
|
|
4
|
+
bedrockplus-0.1.0.dev1.dist-info/licenses/THIRD_PARTY_NOTICES.md,sha256=MMxnOYvV7fYCVtVMrZarrHnDXY-x27768RSMbNIpf38,966
|
|
5
|
+
bedrockplus-0.1.0.dev1.dist-info/licenses/microsoft-detours-MIT.txt,sha256=FuPJzbT6FKhie8S17wI3dzp5w60dASwojzfilXPhFsw,1095
|
|
6
|
+
bedrockplus-0.1.0.dev1.dist-info/top_level.txt,sha256=HumA7phI-GEslUzJO2TiNLPq1w8P1SopWrCXeWo2AhQ,12
|
|
7
|
+
bedrockplus/__init__.py,sha256=Ju1K7GiqKYS6Xwok9TjaR55VTtqU_1jgskF_wOxuzGs,1895
|
|
8
|
+
bedrockplus/__main__.py,sha256=D31U8_ux95qF64EQ8ReT25nabzxh7ped5avpobXz_bM,49
|
|
9
|
+
bedrockplus/_assets/Initialize-BedrockPlusServer.ps1,sha256=IbJuQOgBWKKZFUNVl8HlzVB_-lBSA6SPJ_VIIS4s9Hc,16938
|
|
10
|
+
bedrockplus/_assets/README.md,sha256=M3pQZTExXfGWDNQiv1umJC5tVjSdUsbQPXdk9_WEh64,3353
|
|
11
|
+
bedrockplus/_assets/SHA256SUMS,sha256=2lsdwaXQEgDDr0C8t8cWXlPqVxLn0yHsXIdc50TEJCQ,1839
|
|
12
|
+
bedrockplus/_assets/Start-BedrockPlus.ps1,sha256=MNcQ96egCL-V0FHVlRT3sV5zfyfKFamgU_CLf81vIJE,4918
|
|
13
|
+
bedrockplus/_assets/THIRD_PARTY_NOTICES.md,sha256=MMxnOYvV7fYCVtVMrZarrHnDXY-x27768RSMbNIpf38,966
|
|
14
|
+
bedrockplus/_assets/bedrockplus.exe,sha256=93ziv6Nx51qPNCnERo6ina5jTopXqCDGld9XnsvLFtg,619520
|
|
15
|
+
bedrockplus/_assets/bedrockplus_bootstrap.dll,sha256=ZslxFuMtGqkD7_jqhHlNUvh-nynrnlTC2VJsUzF0oxQ,139264
|
|
16
|
+
bedrockplus/_assets/bedrockplus_plugin_host.dll,sha256=VKfNWPTsSt4IjB1EHjBNFtbqn60K54RLEtIO-yGRZMc,198656
|
|
17
|
+
bedrockplus/_assets/bedrockplus_plugin_worker.dll,sha256=hb-UQPe4MTSNaUFew0p0QwMQTnpsIB9YLja4PK-huPg,1275392
|
|
18
|
+
bedrockplus/_assets/bedrockplus_runtime.dll,sha256=VN7BIJHoGJy-HEsqIpcy3-czqfeQPzZZ9zya-LDcnWM,141824
|
|
19
|
+
bedrockplus/_assets/bin/bedrockplus.ps1,sha256=Um9dWDpSvQQBRTZS4Y6XJnTjblmvUElYZIpi01YBErg,7585
|
|
20
|
+
bedrockplus/_assets/compatibility/bds/1.26.51.1/windows-x64.json,sha256=zSEW0UaeZpIZJ4xoKqBK4TMWIpx_gcQEuHs5cob5auE,671
|
|
21
|
+
bedrockplus/_assets/compatibility/bds/supported-versions.json,sha256=pN4y1rikFDbfP46ApRD3ghnGTcRf2-DgvXEi4Okn0nQ,446
|
|
22
|
+
bedrockplus/_assets/licenses/microsoft-detours-MIT.txt,sha256=FuPJzbT6FKhie8S17wI3dzp5w60dASwojzfilXPhFsw,1095
|
|
23
|
+
bedrockplus/_assets/plugins/README.txt,sha256=m01CoSeU5sDfc3hczS5fl8eEw8QZ-a0tUDzl81BgZLY,564
|
|
24
|
+
bedrockplus/_assets/release-manifest.json,sha256=tMCPXP5YwR8AebIbMTKeOuz7VC08UysxglzeXXRsh-E,3599
|
|
25
|
+
bedrockplus/_assets/server/README.txt,sha256=N_BopYLhmNo2Mtv3igfP0icUcr7dxPnc5sO4GEEKdus,538
|
|
26
|
+
bedrockplus/_assets/tools/bppack.py,sha256=6LiT1WhgKuCYFKCBVuWbrQYLfXl7WfeWbu5qIp6l848,82264
|
|
27
|
+
bedrockplus/_assets/tools/init_python_plugin.py,sha256=nw7uRe-Nc8LS7eACsiRYkicPydcLg1m_K-3uE2q_P2M,4293
|
|
28
|
+
bedrockplus/_assets/tools/pack_plugin.py,sha256=20_fgpIeOXY_agJL350n-g7qku3zz2lGN3yDJjW4cSs,5193
|
|
29
|
+
bedrockplus/_assets/tools/world_packs.py,sha256=wFCAAMtUXtFzUDJglynuuZ6mSomsTcL8c4CovDScnPs,27312
|
|
30
|
+
bedrockplus/api.py,sha256=og8Ge3JgwEWbR40KjPdls37h26G6hOrr-Z3c16H2Og0,2146
|
|
31
|
+
bedrockplus/cli.py,sha256=cbdvlxooc3qgdmvRF7u2NW--kw7c4HnRAgwoIiDtCOU,4376
|
|
32
|
+
bedrockplus/commands.py,sha256=EXW6AXtRZBmqZ6rTV4sklJZJAJsKi7Cuo2Bb5eBsiUI,1240
|
|
33
|
+
bedrockplus/events.py,sha256=pRRedMNAAJSwlKohYQ71W85SuQlmrJTYGL8ObLgsZUw,2807
|
|
34
|
+
bedrockplus/objects.py,sha256=EpK41OhgBW0Bd4rn34M3ePcvFg1nMQ0FQgQpDUKJvo8,14246
|
|
35
|
+
bedrockplus/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
36
|
+
bedrockplus-0.1.0.dev1.dist-info/RECORD,,
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
## Microsoft Detours
|
|
4
|
+
|
|
5
|
+
- Version: 4.0.1, commit `e4bfd6b03e50de46b47abfbd1e46b384f0c5f833`
|
|
6
|
+
- Upstream: https://github.com/microsoft/Detours
|
|
7
|
+
- License: MIT
|
|
8
|
+
- Use: statically linked into `bedrockplus_plugin_worker.dll`
|
|
9
|
+
|
|
10
|
+
The complete required MIT license text is distributed in
|
|
11
|
+
`licenses/microsoft-detours-MIT.txt`.
|
|
12
|
+
|
|
13
|
+
## CPython
|
|
14
|
+
|
|
15
|
+
- Supported runtime: CPython 3.13 x64
|
|
16
|
+
- Upstream: https://www.python.org/ and https://github.com/python/cpython
|
|
17
|
+
- License: Python Software Foundation License Version 2 with CPython's
|
|
18
|
+
additional historical notices
|
|
19
|
+
- Use: supplied by the operator's Python installation and loaded by the
|
|
20
|
+
BedrockPlus Python plugin host
|
|
21
|
+
|
|
22
|
+
BedrockPlus does not bundle CPython in this release. If that policy changes,
|
|
23
|
+
the exact CPython license and component notices must be added to the release.
|
|
24
|
+
|
|
25
|
+
This file does not replace a complete license text when redistribution terms
|
|
26
|
+
require that text to accompany a source or binary distribution.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Copyright (c) Microsoft Corporation
|
|
2
|
+
|
|
3
|
+
All rights reserved.
|
|
4
|
+
|
|
5
|
+
MIT License
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
8
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
9
|
+
the Software without restriction, including without limitation the rights to
|
|
10
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
11
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
|
12
|
+
so, subject to the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
bedrockplus
|