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/__init__.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""Public, typed BedrockPlus Python plugin API."""
|
|
2
|
+
|
|
3
|
+
__version__ = "0.1.0.dev1"
|
|
4
|
+
|
|
5
|
+
from .api import EventCallback, Plugin, PluginHost, TaskCallback
|
|
6
|
+
from .commands import (
|
|
7
|
+
CommandArgument,
|
|
8
|
+
CommandArgumentType,
|
|
9
|
+
CommandCallback,
|
|
10
|
+
CommandInvocation,
|
|
11
|
+
CommandOverload,
|
|
12
|
+
CommandResult,
|
|
13
|
+
CommandReturn,
|
|
14
|
+
CommandSourceKind,
|
|
15
|
+
CommandValue,
|
|
16
|
+
)
|
|
17
|
+
from .events import (
|
|
18
|
+
BlockBreakEvent,
|
|
19
|
+
BlockPlaceEvent,
|
|
20
|
+
CancellableEvent,
|
|
21
|
+
Event,
|
|
22
|
+
EventName,
|
|
23
|
+
EventPriority,
|
|
24
|
+
PlayerChatEvent,
|
|
25
|
+
PlayerCommandFields,
|
|
26
|
+
PlayerCommandEvent,
|
|
27
|
+
PlayerJoinEvent,
|
|
28
|
+
PlayerJumpEvent,
|
|
29
|
+
PlayerKickEvent,
|
|
30
|
+
PlayerLoginEvent,
|
|
31
|
+
PlayerMoveEvent,
|
|
32
|
+
PlayerQuitEvent,
|
|
33
|
+
PlayerLifecycleFields,
|
|
34
|
+
ServerCommandFields,
|
|
35
|
+
ServerCommandEvent,
|
|
36
|
+
ServerListPingEvent,
|
|
37
|
+
ServerTickEvent,
|
|
38
|
+
)
|
|
39
|
+
from .objects import (
|
|
40
|
+
ConnectionInfo,
|
|
41
|
+
Entity,
|
|
42
|
+
ItemStack,
|
|
43
|
+
Level,
|
|
44
|
+
Location,
|
|
45
|
+
Player,
|
|
46
|
+
Server,
|
|
47
|
+
SocketAddress,
|
|
48
|
+
Vector3,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
__all__ = [
|
|
52
|
+
"__version__",
|
|
53
|
+
"BlockBreakEvent",
|
|
54
|
+
"BlockPlaceEvent",
|
|
55
|
+
"CancellableEvent",
|
|
56
|
+
"CommandArgument",
|
|
57
|
+
"CommandArgumentType",
|
|
58
|
+
"CommandCallback",
|
|
59
|
+
"CommandInvocation",
|
|
60
|
+
"CommandOverload",
|
|
61
|
+
"CommandResult",
|
|
62
|
+
"CommandReturn",
|
|
63
|
+
"CommandSourceKind",
|
|
64
|
+
"CommandValue",
|
|
65
|
+
"ConnectionInfo",
|
|
66
|
+
"Entity",
|
|
67
|
+
"Event",
|
|
68
|
+
"EventCallback",
|
|
69
|
+
"EventName",
|
|
70
|
+
"EventPriority",
|
|
71
|
+
"PlayerChatEvent",
|
|
72
|
+
"PlayerCommandFields",
|
|
73
|
+
"PlayerCommandEvent",
|
|
74
|
+
"PlayerJoinEvent",
|
|
75
|
+
"PlayerJumpEvent",
|
|
76
|
+
"PlayerKickEvent",
|
|
77
|
+
"PlayerLoginEvent",
|
|
78
|
+
"PlayerMoveEvent",
|
|
79
|
+
"PlayerQuitEvent",
|
|
80
|
+
"PlayerLifecycleFields",
|
|
81
|
+
"Player",
|
|
82
|
+
"ItemStack",
|
|
83
|
+
"Level",
|
|
84
|
+
"Location",
|
|
85
|
+
"Plugin",
|
|
86
|
+
"PluginHost",
|
|
87
|
+
"ServerCommandEvent",
|
|
88
|
+
"ServerCommandFields",
|
|
89
|
+
"ServerListPingEvent",
|
|
90
|
+
"ServerTickEvent",
|
|
91
|
+
"Server",
|
|
92
|
+
"SocketAddress",
|
|
93
|
+
"TaskCallback",
|
|
94
|
+
"Vector3",
|
|
95
|
+
]
|
bedrockplus/__main__.py
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
[CmdletBinding()]
|
|
2
|
+
param(
|
|
3
|
+
[string]$DestinationRoot = (Get-Location).Path,
|
|
4
|
+
[string]$BdsVersion = '',
|
|
5
|
+
[switch]$Yes,
|
|
6
|
+
[switch]$ListVersions,
|
|
7
|
+
[string]$ManifestPath = (Join-Path $PSScriptRoot 'compatibility\bds\supported-versions.json'),
|
|
8
|
+
[string]$ArchivePath = ''
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
Set-StrictMode -Version Latest
|
|
12
|
+
$ErrorActionPreference = 'Stop'
|
|
13
|
+
|
|
14
|
+
function Set-HiddenDirectory {
|
|
15
|
+
param([Parameter(Mandatory)][string]$Path)
|
|
16
|
+
|
|
17
|
+
$item = Get-Item -LiteralPath $Path -Force
|
|
18
|
+
$item.Attributes = $item.Attributes -bor [IO.FileAttributes]::Hidden
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function Get-Sha256 {
|
|
22
|
+
param([Parameter(Mandatory)][string]$Path)
|
|
23
|
+
|
|
24
|
+
$stream = [IO.File]::OpenRead($Path)
|
|
25
|
+
$hasher = [Security.Cryptography.SHA256]::Create()
|
|
26
|
+
try {
|
|
27
|
+
return ([BitConverter]::ToString($hasher.ComputeHash($stream))).Replace('-', '').ToLowerInvariant()
|
|
28
|
+
} finally {
|
|
29
|
+
$hasher.Dispose()
|
|
30
|
+
$stream.Dispose()
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function Invoke-BdsDownload {
|
|
35
|
+
param(
|
|
36
|
+
[Parameter(Mandatory)][string]$Uri,
|
|
37
|
+
[Parameter(Mandatory)][string]$Destination,
|
|
38
|
+
[Parameter(Mandatory)][string]$Version
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
Add-Type -AssemblyName System.Net.Http
|
|
42
|
+
$client = [Net.Http.HttpClient]::new()
|
|
43
|
+
$response = $null
|
|
44
|
+
$input = $null
|
|
45
|
+
$output = $null
|
|
46
|
+
try {
|
|
47
|
+
$response = $client.GetAsync(
|
|
48
|
+
$Uri,
|
|
49
|
+
[Net.Http.HttpCompletionOption]::ResponseHeadersRead
|
|
50
|
+
).GetAwaiter().GetResult()
|
|
51
|
+
$response.EnsureSuccessStatusCode()
|
|
52
|
+
$total = $response.Content.Headers.ContentLength
|
|
53
|
+
$input = $response.Content.ReadAsStreamAsync().GetAwaiter().GetResult()
|
|
54
|
+
$output = [IO.File]::Open($Destination, [IO.FileMode]::CreateNew, [IO.FileAccess]::Write, [IO.FileShare]::None)
|
|
55
|
+
$buffer = [byte[]]::new(1024 * 1024)
|
|
56
|
+
[long]$received = 0
|
|
57
|
+
while (($count = $input.Read($buffer, 0, $buffer.Length)) -gt 0) {
|
|
58
|
+
$output.Write($buffer, 0, $count)
|
|
59
|
+
$received += $count
|
|
60
|
+
if ($total -and $total -gt 0) {
|
|
61
|
+
$percent = [Math]::Min(100, [int](($received * 100) / $total))
|
|
62
|
+
Write-Progress -Activity "Downloading BDS $Version" -Status "$percent% ($([Math]::Round($received / 1MB, 1)) / $([Math]::Round($total / 1MB, 1)) MiB)" -PercentComplete $percent
|
|
63
|
+
} else {
|
|
64
|
+
Write-Progress -Activity "Downloading BDS $Version" -Status "$([Math]::Round($received / 1MB, 1)) MiB received" -PercentComplete 0
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
} finally {
|
|
68
|
+
Write-Progress -Activity "Downloading BDS $Version" -Completed
|
|
69
|
+
if ($output) { $output.Dispose() }
|
|
70
|
+
if ($input) { $input.Dispose() }
|
|
71
|
+
if ($response) { $response.Dispose() }
|
|
72
|
+
$client.Dispose()
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function Expand-BdsArchive {
|
|
77
|
+
param(
|
|
78
|
+
[Parameter(Mandatory)][string]$Path,
|
|
79
|
+
[Parameter(Mandatory)][string]$Destination,
|
|
80
|
+
[Parameter(Mandatory)][string]$Version
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
|
84
|
+
$archive = [IO.Compression.ZipFile]::OpenRead($Path)
|
|
85
|
+
try {
|
|
86
|
+
$total = $archive.Entries.Count
|
|
87
|
+
for ($index = 0; $index -lt $total; $index++) {
|
|
88
|
+
$entry = $archive.Entries[$index]
|
|
89
|
+
$target = [IO.Path]::GetFullPath((Join-Path $Destination $entry.FullName.Replace('/', '\')))
|
|
90
|
+
if ([string]::IsNullOrEmpty($entry.Name)) {
|
|
91
|
+
New-Item -ItemType Directory -Force -Path $target | Out-Null
|
|
92
|
+
} else {
|
|
93
|
+
$parent = Split-Path -Parent $target
|
|
94
|
+
if (-not (Test-Path -LiteralPath $parent -PathType Container)) {
|
|
95
|
+
New-Item -ItemType Directory -Force -Path $parent | Out-Null
|
|
96
|
+
}
|
|
97
|
+
[IO.Compression.ZipFileExtensions]::ExtractToFile($entry, $target, $false)
|
|
98
|
+
}
|
|
99
|
+
$percent = [int]((($index + 1) * 100) / [Math]::Max(1, $total))
|
|
100
|
+
Write-Progress -Activity "Installing BDS $Version" -Status "$percent% ($($index + 1) of $total files)" -PercentComplete $percent
|
|
101
|
+
}
|
|
102
|
+
} finally {
|
|
103
|
+
Write-Progress -Activity "Installing BDS $Version" -Completed
|
|
104
|
+
$archive.Dispose()
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function Assert-SafeArchive {
|
|
109
|
+
param(
|
|
110
|
+
[Parameter(Mandatory)][string]$Path,
|
|
111
|
+
[Parameter(Mandatory)][string]$ExtractionRoot
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
|
115
|
+
$root = [IO.Path]::GetFullPath($ExtractionRoot).TrimEnd('\') + '\'
|
|
116
|
+
$archive = [IO.Compression.ZipFile]::OpenRead($Path)
|
|
117
|
+
try {
|
|
118
|
+
if ($archive.Entries.Count -eq 0 -or $archive.Entries.Count -gt 20000) {
|
|
119
|
+
throw 'The BDS archive has an invalid number of entries.'
|
|
120
|
+
}
|
|
121
|
+
foreach ($entry in $archive.Entries) {
|
|
122
|
+
$name = $entry.FullName.Replace('/', '\')
|
|
123
|
+
if ([string]::IsNullOrWhiteSpace($name) -or
|
|
124
|
+
[IO.Path]::IsPathRooted($name) -or
|
|
125
|
+
$name.Contains(':') -or
|
|
126
|
+
$name.Contains([char]0)) {
|
|
127
|
+
throw "The BDS archive contains an unsafe path: $name"
|
|
128
|
+
}
|
|
129
|
+
$segments = @($name.Split('\') | Where-Object { $_ -ne '' })
|
|
130
|
+
if ($segments.Count -eq 0 -or $segments -contains '.' -or $segments -contains '..') {
|
|
131
|
+
throw "The BDS archive contains an unsafe path: $name"
|
|
132
|
+
}
|
|
133
|
+
$target = [IO.Path]::GetFullPath((Join-Path $ExtractionRoot $name))
|
|
134
|
+
if (-not $target.StartsWith($root, [StringComparison]::OrdinalIgnoreCase)) {
|
|
135
|
+
throw "The BDS archive path escapes its staging directory: $name"
|
|
136
|
+
}
|
|
137
|
+
$unixType = (($entry.ExternalAttributes -shr 16) -band 0xF000)
|
|
138
|
+
if ($unixType -eq 0xA000) {
|
|
139
|
+
throw "The BDS archive contains a symbolic link: $name"
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
} finally {
|
|
143
|
+
$archive.Dispose()
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function Set-ServerProperties {
|
|
148
|
+
param([Parameter(Mandatory)][string]$Path)
|
|
149
|
+
|
|
150
|
+
$properties = [IO.File]::ReadAllText($Path)
|
|
151
|
+
foreach ($setting in @(
|
|
152
|
+
@('server-name', 'BedrockPlus'),
|
|
153
|
+
@('level-name', 'BedrockPlus')
|
|
154
|
+
)) {
|
|
155
|
+
$key = $setting[0]
|
|
156
|
+
$value = $setting[1]
|
|
157
|
+
$pattern = "(?m)^$([Text.RegularExpressions.Regex]::Escape($key))=.*$"
|
|
158
|
+
if ($properties -match $pattern) {
|
|
159
|
+
$properties = [Text.RegularExpressions.Regex]::Replace(
|
|
160
|
+
$properties,
|
|
161
|
+
$pattern,
|
|
162
|
+
"$key=$value"
|
|
163
|
+
)
|
|
164
|
+
} else {
|
|
165
|
+
$properties = $properties.TrimEnd("`r", "`n") + "`r`n$key=$value`r`n"
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
[IO.File]::WriteAllText($Path, $properties, [Text.UTF8Encoding]::new($false))
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function Write-BedrockPlusSettings {
|
|
172
|
+
param([Parameter(Mandatory)][string]$Path)
|
|
173
|
+
|
|
174
|
+
$settings = @'
|
|
175
|
+
; BedrockPlus settings. server.properties remains owned by vanilla BDS.
|
|
176
|
+
[general]
|
|
177
|
+
channel=stable
|
|
178
|
+
auto-update=true
|
|
179
|
+
|
|
180
|
+
; These switches apply equally to the console and human-readable .log files.
|
|
181
|
+
; Full structured metadata is always retained in the parallel .jsonl log.
|
|
182
|
+
[logging]
|
|
183
|
+
prefix-timestamp=true
|
|
184
|
+
timestamp-pattern=[{year}-{month}-{day}T{hour}:{minute}:{second}.{millisecond}Z]
|
|
185
|
+
prefix-level=true
|
|
186
|
+
prefix-source=true
|
|
187
|
+
fields=false
|
|
188
|
+
'@
|
|
189
|
+
[IO.File]::WriteAllText($Path, $settings.TrimStart() + "`r`n", [Text.UTF8Encoding]::new($false))
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (-not (Test-Path -LiteralPath $ManifestPath -PathType Leaf)) {
|
|
193
|
+
throw "Supported-version manifest was not found: $ManifestPath"
|
|
194
|
+
}
|
|
195
|
+
$manifest = Get-Content -LiteralPath $ManifestPath -Raw | ConvertFrom-Json
|
|
196
|
+
if ($manifest.format_version -ne 1 -or -not $manifest.versions) {
|
|
197
|
+
throw 'The supported-version manifest is invalid.'
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if ($ListVersions) {
|
|
201
|
+
foreach ($entry in $manifest.versions) {
|
|
202
|
+
$default = if ($entry.version -eq $manifest.default_version) { ' (default)' } else { '' }
|
|
203
|
+
Write-Output "$($entry.version) [$($entry.channel), $($entry.platform)]$default"
|
|
204
|
+
}
|
|
205
|
+
exit 0
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if ([string]::IsNullOrWhiteSpace($BdsVersion)) {
|
|
209
|
+
if (-not $Yes) {
|
|
210
|
+
Write-Host 'BDS versions supported by this BedrockPlus build:'
|
|
211
|
+
foreach ($entry in $manifest.versions) {
|
|
212
|
+
$default = if ($entry.version -eq $manifest.default_version) { ' (default)' } else { '' }
|
|
213
|
+
Write-Host " $($entry.version) [$($entry.channel)]$default"
|
|
214
|
+
}
|
|
215
|
+
if (@($manifest.versions).Count -gt 1) {
|
|
216
|
+
$answer = Read-Host "Select BDS version [$($manifest.default_version)]"
|
|
217
|
+
if (-not [string]::IsNullOrWhiteSpace($answer)) {
|
|
218
|
+
$BdsVersion = $answer.Trim()
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if ([string]::IsNullOrWhiteSpace($BdsVersion)) {
|
|
223
|
+
$BdsVersion = [string]$manifest.default_version
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
$matches = @($manifest.versions | Where-Object { $_.version -eq $BdsVersion })
|
|
227
|
+
if ($matches.Count -ne 1) {
|
|
228
|
+
$supported = @($manifest.versions | ForEach-Object { $_.version }) -join ', '
|
|
229
|
+
throw "BDS $BdsVersion is not supported by this BedrockPlus build. Supported: $supported"
|
|
230
|
+
}
|
|
231
|
+
$selected = $matches[0]
|
|
232
|
+
if ($selected.platform -ne 'windows-x64' -or
|
|
233
|
+
$selected.download_url -notmatch '^https://www\.minecraft\.net/' -or
|
|
234
|
+
$selected.archive_sha256 -notmatch '^[0-9a-fA-F]{64}$') {
|
|
235
|
+
throw 'The selected BDS manifest entry is invalid or uses an unapproved download host.'
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
$DestinationRoot = [IO.Path]::GetFullPath($DestinationRoot).TrimEnd('\')
|
|
239
|
+
if ($DestinationRoot -split '[\\/]' -contains 'referenceOnly') {
|
|
240
|
+
throw 'A BedrockPlus server cannot be initialized inside referenceOnly.'
|
|
241
|
+
}
|
|
242
|
+
$downloadsRoot = Join-Path $DestinationRoot 'Downloads'
|
|
243
|
+
$archiveName = "bedrock-server-$($selected.version).zip"
|
|
244
|
+
$cachedArchive = Join-Path $downloadsRoot $archiveName
|
|
245
|
+
if (Test-Path -LiteralPath $DestinationRoot) {
|
|
246
|
+
if (-not (Test-Path -LiteralPath $DestinationRoot -PathType Container)) {
|
|
247
|
+
throw "DestinationRoot is not a directory: $DestinationRoot"
|
|
248
|
+
}
|
|
249
|
+
$existingItems = @(Get-ChildItem -LiteralPath $DestinationRoot -Force)
|
|
250
|
+
$unexpectedItems = @($existingItems | Where-Object { $_.Name -cne 'Downloads' })
|
|
251
|
+
if ($unexpectedItems.Count -ne 0) {
|
|
252
|
+
throw "DestinationRoot must be empty except for the managed Downloads cache; no files were changed: $DestinationRoot"
|
|
253
|
+
}
|
|
254
|
+
if ($existingItems.Count -eq 1) {
|
|
255
|
+
$downloadsItem = $existingItems[0]
|
|
256
|
+
if (-not $downloadsItem.PSIsContainer -or
|
|
257
|
+
($downloadsItem.Attributes -band [IO.FileAttributes]::ReparsePoint)) {
|
|
258
|
+
throw "The Downloads cache must be a normal local directory: $downloadsRoot"
|
|
259
|
+
}
|
|
260
|
+
foreach ($item in Get-ChildItem -LiteralPath $downloadsRoot -Force) {
|
|
261
|
+
if ($item.PSIsContainer -or
|
|
262
|
+
($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -or
|
|
263
|
+
$item.Name -notmatch '^bedrock-server-[0-9A-Za-z.+-]+\.zip$') {
|
|
264
|
+
throw "The Downloads cache contains an unmanaged entry; no files were changed: $($item.FullName)"
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
} else {
|
|
269
|
+
New-Item -ItemType Directory -Path $DestinationRoot | Out-Null
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (-not $Yes) {
|
|
273
|
+
Write-Host "BedrockPlus supports BDS $($selected.version) ($($selected.channel))."
|
|
274
|
+
Write-Host 'The official BDS archive will be downloaded from minecraft.net.'
|
|
275
|
+
Write-Host 'By continuing, you confirm that you accept the applicable Minecraft server terms.'
|
|
276
|
+
$answer = Read-Host "Install it into '$DestinationRoot'? [Y/n]"
|
|
277
|
+
if (-not [string]::IsNullOrWhiteSpace($answer) -and
|
|
278
|
+
$answer -notin @('y', 'Y', 'yes', 'YES', 'Yes')) {
|
|
279
|
+
Write-Host 'Initialization cancelled; no server files were installed.'
|
|
280
|
+
exit 2
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
$temporaryRoot = Join-Path ([IO.Path]::GetTempPath()) ("bedrockplus-init-" + [Guid]::NewGuid().ToString('N'))
|
|
285
|
+
$download = Join-Path $temporaryRoot $archiveName
|
|
286
|
+
$staging = Join-Path $temporaryRoot 'extracted'
|
|
287
|
+
$installedPaths = [Collections.Generic.List[string]]::new()
|
|
288
|
+
New-Item -ItemType Directory -Path $temporaryRoot, $staging | Out-Null
|
|
289
|
+
|
|
290
|
+
try {
|
|
291
|
+
if ([string]::IsNullOrWhiteSpace($ArchivePath)) {
|
|
292
|
+
$useCachedArchive = $false
|
|
293
|
+
if (Test-Path -LiteralPath $cachedArchive -PathType Leaf) {
|
|
294
|
+
$cachedHash = Get-Sha256 -Path $cachedArchive
|
|
295
|
+
$expectedHash = ([string]$selected.archive_sha256).ToLowerInvariant()
|
|
296
|
+
if ($cachedHash -eq $expectedHash) {
|
|
297
|
+
Write-Host "Using verified cached BDS $($selected.version) from Downloads."
|
|
298
|
+
Copy-Item -LiteralPath $cachedArchive -Destination $download
|
|
299
|
+
$useCachedArchive = $true
|
|
300
|
+
} else {
|
|
301
|
+
Write-Warning "The cached BDS $($selected.version) archive failed verification and will be replaced."
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
if (-not $useCachedArchive) {
|
|
305
|
+
Write-Host "Downloading official BDS $($selected.version)..."
|
|
306
|
+
Invoke-BdsDownload -Uri $selected.download_url -Destination $download -Version $selected.version
|
|
307
|
+
}
|
|
308
|
+
} else {
|
|
309
|
+
Copy-Item -LiteralPath ([IO.Path]::GetFullPath($ArchivePath)) -Destination $download
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
$actualHash = Get-Sha256 -Path $download
|
|
313
|
+
$expectedHash = ([string]$selected.archive_sha256).ToLowerInvariant()
|
|
314
|
+
if ($actualHash -ne $expectedHash) {
|
|
315
|
+
throw "BDS archive verification failed. Expected $expectedHash but received $actualHash."
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
Assert-SafeArchive -Path $download -ExtractionRoot $staging
|
|
319
|
+
Expand-BdsArchive -Path $download -Destination $staging -Version $selected.version
|
|
320
|
+
|
|
321
|
+
$serverExecutable = Join-Path $staging 'bedrock_server.exe'
|
|
322
|
+
$serverProperties = Join-Path $staging 'server.properties'
|
|
323
|
+
if (-not (Test-Path -LiteralPath $serverExecutable -PathType Leaf) -or
|
|
324
|
+
-not (Test-Path -LiteralPath $serverProperties -PathType Leaf)) {
|
|
325
|
+
throw 'The verified archive does not contain a complete Windows BDS layout.'
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
Set-ServerProperties -Path $serverProperties
|
|
329
|
+
Write-BedrockPlusSettings -Path (Join-Path $staging 'BedrockPlus.ini')
|
|
330
|
+
[IO.File]::WriteAllText(
|
|
331
|
+
(Join-Path $staging 'allowlist.json'),
|
|
332
|
+
"[]`r`n",
|
|
333
|
+
[Text.UTF8Encoding]::new($false)
|
|
334
|
+
)
|
|
335
|
+
[IO.File]::WriteAllText(
|
|
336
|
+
(Join-Path $staging 'permissions.json'),
|
|
337
|
+
"[]`r`n",
|
|
338
|
+
[Text.UTF8Encoding]::new($false)
|
|
339
|
+
)
|
|
340
|
+
New-Item -ItemType Directory -Force -Path `
|
|
341
|
+
(Join-Path $staging 'plugins'), `
|
|
342
|
+
(Join-Path $staging 'logs'), `
|
|
343
|
+
(Join-Path $staging 'Downloads'), `
|
|
344
|
+
(Join-Path $staging '.bedrockplus'), `
|
|
345
|
+
(Join-Path $staging '.bedrockplus\plugin-data') | Out-Null
|
|
346
|
+
Move-Item -LiteralPath $download -Destination (Join-Path $staging "Downloads\$archiveName")
|
|
347
|
+
|
|
348
|
+
[ordered]@{
|
|
349
|
+
product = 'BedrockPlus'
|
|
350
|
+
format_version = 1
|
|
351
|
+
bds_version = [string]$selected.version
|
|
352
|
+
bds_channel = [string]$selected.channel
|
|
353
|
+
created_by = 'Turkmen'
|
|
354
|
+
created_at_utc = [DateTime]::UtcNow.ToString('o')
|
|
355
|
+
} | ConvertTo-Json | Set-Content -LiteralPath `
|
|
356
|
+
(Join-Path $staging 'bedrockplus.instance.json') -Encoding UTF8
|
|
357
|
+
|
|
358
|
+
$installItems = @(Get-ChildItem -LiteralPath $staging -Force)
|
|
359
|
+
for ($index = 0; $index -lt $installItems.Count; $index++) {
|
|
360
|
+
$item = $installItems[$index]
|
|
361
|
+
if ($item.Name -ceq 'Downloads' -and
|
|
362
|
+
(Test-Path -LiteralPath $downloadsRoot -PathType Container)) {
|
|
363
|
+
foreach ($archiveItem in Get-ChildItem -LiteralPath $item.FullName -Force) {
|
|
364
|
+
Move-Item -LiteralPath $archiveItem.FullName -Destination $downloadsRoot -Force
|
|
365
|
+
}
|
|
366
|
+
Remove-Item -LiteralPath $item.FullName -Force
|
|
367
|
+
} else {
|
|
368
|
+
Move-Item -LiteralPath $item.FullName -Destination $DestinationRoot
|
|
369
|
+
$installedPaths.Add((Join-Path $DestinationRoot $item.Name))
|
|
370
|
+
}
|
|
371
|
+
$percent = [int]((($index + 1) * 100) / [Math]::Max(1, $installItems.Count))
|
|
372
|
+
Write-Progress -Activity 'Finalizing BedrockPlus server' -Status "$percent%" -PercentComplete $percent
|
|
373
|
+
}
|
|
374
|
+
Write-Progress -Activity 'Finalizing BedrockPlus server' -Completed
|
|
375
|
+
Set-HiddenDirectory -Path (Join-Path $DestinationRoot '.bedrockplus')
|
|
376
|
+
} catch {
|
|
377
|
+
# Remove only entries successfully moved by this initializer. A file created
|
|
378
|
+
# concurrently by the operator is never included in this rollback list.
|
|
379
|
+
foreach ($path in $installedPaths) {
|
|
380
|
+
Remove-Item -LiteralPath $path -Recurse -Force -ErrorAction SilentlyContinue
|
|
381
|
+
}
|
|
382
|
+
throw
|
|
383
|
+
} finally {
|
|
384
|
+
$tempBase = [IO.Path]::GetFullPath([IO.Path]::GetTempPath()).TrimEnd('\') + '\'
|
|
385
|
+
$resolvedTemporary = [IO.Path]::GetFullPath($temporaryRoot)
|
|
386
|
+
if ($resolvedTemporary.StartsWith($tempBase, [StringComparison]::OrdinalIgnoreCase) -and
|
|
387
|
+
(Split-Path $resolvedTemporary -Leaf).StartsWith('bedrockplus-init-', [StringComparison]::Ordinal)) {
|
|
388
|
+
Remove-Item -LiteralPath $resolvedTemporary -Recurse -Force -ErrorAction SilentlyContinue
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
Write-Host "Created BedrockPlus server: $DestinationRoot"
|
|
393
|
+
Write-Host "BDS version: $($selected.version)"
|
|
394
|
+
Write-Host "BDS archive: $(Join-Path $DestinationRoot "Downloads\$archiveName")"
|
|
395
|
+
Write-Host "Plugin inbox: $(Join-Path $DestinationRoot 'plugins')"
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# BedrockPlus Windows x64 pre-release
|
|
2
|
+
|
|
3
|
+
BedrockPlus is a BDS-native server and plugin platform created by Turkmen. This
|
|
4
|
+
package supports the exact BDS version recorded in `release-manifest.json` and
|
|
5
|
+
contains the BedrockPlus console launcher, runtime, Python and C++ plugin host,
|
|
6
|
+
plugin packaging tools, server initializer, documentation, and required legal
|
|
7
|
+
notices.
|
|
8
|
+
|
|
9
|
+
The package does **not** contain Minecraft Bedrock Dedicated Server, worlds,
|
|
10
|
+
plugins, private source code, debug symbols, signing keys, build directories,
|
|
11
|
+
or private development files. BDS is downloaded from the official source only
|
|
12
|
+
after the operator accepts the applicable Minecraft server terms.
|
|
13
|
+
|
|
14
|
+
This is a pre-release. Back up worlds before testing and use only the listed BDS
|
|
15
|
+
version. Python plugins require 64-bit CPython 3.13, which is also the supported
|
|
16
|
+
Python version for installing the BedrockPlus command package.
|
|
17
|
+
|
|
18
|
+
## Installed commands
|
|
19
|
+
|
|
20
|
+
After installing the public Python wheel, open Command Prompt in any directory:
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
bedrockplus
|
|
24
|
+
bedrockplus init
|
|
25
|
+
bedrockplus start
|
|
26
|
+
bedrockplus doctor
|
|
27
|
+
bedrockplus list-versions
|
|
28
|
+
bedrockplus plugin python init "My Plugin"
|
|
29
|
+
bedrockplus plugin pack
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Running `bedrockplus` in a fresh directory offers to install the supported BDS
|
|
33
|
+
version with Yes as the default. The verified official archive is retained in
|
|
34
|
+
the server-root `Downloads` directory. A matching archive already stored there
|
|
35
|
+
is verified and reused without another download.
|
|
36
|
+
|
|
37
|
+
## Release contents
|
|
38
|
+
|
|
39
|
+
The archive is assembled from an explicit allowlist and contains only:
|
|
40
|
+
|
|
41
|
+
- release BedrockPlus executables and DLLs;
|
|
42
|
+
- the command, initializer, launcher, and plugin packaging scripts;
|
|
43
|
+
- supported-version and compatibility data;
|
|
44
|
+
- this guide and third-party notices;
|
|
45
|
+
- a generated payload manifest and SHA-256 checksum list.
|
|
46
|
+
|
|
47
|
+
`release-manifest.json` records every distributed payload with its role, exact
|
|
48
|
+
byte size, and SHA-256. `SHA256SUMS` covers the payload and manifest. The outer
|
|
49
|
+
ZIP has a separate SHA-256 file. Do not use a package whose verification fails.
|
|
50
|
+
|
|
51
|
+
## Manual ZIP usage
|
|
52
|
+
|
|
53
|
+
The Python wheel is the recommended installation. For manual testing:
|
|
54
|
+
|
|
55
|
+
1. Install 64-bit CPython 3.13.
|
|
56
|
+
2. Extract this release to a new local directory.
|
|
57
|
+
3. Open Command Prompt in the directory where the server should be created.
|
|
58
|
+
4. Run the release's `bin\bedrockplus.ps1` through PowerShell.
|
|
59
|
+
5. Confirm the official BDS installation and start the server.
|
|
60
|
+
|
|
61
|
+
Keep `bedrock_server.exe`, `server.properties`, `BedrockPlus.ini`, `plugins`,
|
|
62
|
+
`Downloads`, `worlds`, and `logs` together in one server directory. BedrockPlus
|
|
63
|
+
keeps private runtime state and installed plugin contents below the hidden
|
|
64
|
+
`.bedrockplus` directory.
|
|
65
|
+
|
|
66
|
+
## Publisher build and validation
|
|
67
|
+
|
|
68
|
+
Use Visual Studio 2022 and the locked project-local environment:
|
|
69
|
+
|
|
70
|
+
```powershell
|
|
71
|
+
. .\toolchain\enter-dev-shell.ps1
|
|
72
|
+
pwsh -NoProfile -File .\toolchain\package-release.ps1
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The packaging task builds Release configuration, runs the complete test suite,
|
|
76
|
+
creates the allowlisted ZIP and checksum, extracts it into an isolated staging
|
|
77
|
+
directory, and verifies its exact contents. Artifacts are written below:
|
|
78
|
+
|
|
79
|
+
```text
|
|
80
|
+
out/build/windows-vs2022-release/packages/
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The public Python wheel is built separately from the verified runtime package.
|
|
84
|
+
Only the wheel is uploaded to PyPI; do not upload the source distribution or
|
|
85
|
+
the private repository.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
21b26e40e80158a29915435597c1e5cd507ffa505203a48f27f548212e2cf477 Initialize-BedrockPlusServer.ps1
|
|
2
|
+
337a506531315df1960cd422bf5ba6242e6d56349d52c6d03d7764f7f58487ae README.md
|
|
3
|
+
30d710f7a7a008bf95d051d59514f7b15e737f27ca15a9a053f08b7fcd6f2091 Start-BedrockPlus.ps1
|
|
4
|
+
30cc67398bd5edf60256d54cad96abac79c35d8fb1dbbefaf1148c6cd2297f7f THIRD_PARTY_NOTICES.md
|
|
5
|
+
f77ce2bfa371e75a8f3429c4468ea29dae634e8a57a820c695df579ecbcb16d8 bedrockplus.exe
|
|
6
|
+
66c97116e32d1aa903eff8ea84794d52f87e9f29eb9e54c2d9526c533174a314 bedrockplus_bootstrap.dll
|
|
7
|
+
54a7cd58f4ec4ade088c1d441e304d16d6ea9fad0ae7844b12d20efb219164c7 bedrockplus_plugin_host.dll
|
|
8
|
+
85bf9440f7b831348d69415ec34a744303104e7a6c201f582e36b83cafa1b8f8 bedrockplus_plugin_worker.dll
|
|
9
|
+
54dec12091e8189cbe1c4b2a229732dfe733a9f7903f3659f73c9af8b0dc9d63 bedrockplus_runtime.dll
|
|
10
|
+
526f5d583a52bd0401453652e18e972674e36e59af504958648a62d3560112b8 bin/bedrockplus.ps1
|
|
11
|
+
cd2116d1469e669219278c682aa04ae13316229c7f81c404b87b397286f96ae1 compatibility/bds/1.26.51.1/windows-x64.json
|
|
12
|
+
a4de32d6b8a41436df3f8e80a510f78219c64dc45fdbe0e0bd7122e0e927d274 compatibility/bds/supported-versions.json
|
|
13
|
+
16e3c9cdb4fa14a8627bc4b5ef0237773a79c3ad1d012c288f37e29573e116cc licenses/microsoft-detours-MIT.txt
|
|
14
|
+
9b4d42a12794e6c0df73785ccd2e5f97c784c3c419f9ad2d503ce5f3506064b6 plugins/README.txt
|
|
15
|
+
b4c08f5cfe58c11f0079b21b31329e3aecfb542d3c532b31825cde5d746c87e1 release-manifest.json
|
|
16
|
+
37f068a582e198da3632dbf78a07cfd2271472beddc4f9dce6c3b818410a76eb server/README.txt
|
|
17
|
+
e8b893d568602ae09814a08156e59bad060b7d797b59f7966eee6a229ea5f38f tools/bppack.py
|
|
18
|
+
9f0eee45ef8d73c2d2ede002b2245892270fc9d70b8359bf2bedee136abf3f63 tools/init_python_plugin.py
|
|
19
|
+
db4fdf82921e39763f6a024bdf9d27fa0eea92edf3cf6946377c832635b8712b tools/pack_plugin.py
|
|
20
|
+
c0508000cb545ed1735032609729eeb99ea64a89ac4dc2fc7380a8bc349c9cfb tools/world_packs.py
|