bedrockplus 0.1.0b1__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 +99 -0
- bedrockplus/__main__.py +4 -0
- bedrockplus/_assets/Initialize-BedrockPlusServer.ps1 +395 -0
- bedrockplus/_assets/LICENSE.txt +87 -0
- bedrockplus/_assets/README.md +85 -0
- bedrockplus/_assets/SHA256SUMS +21 -0
- bedrockplus/_assets/Start-BedrockPlus.ps1 +151 -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 +35 -0
- bedrockplus/_assets/server/README.txt +10 -0
- bedrockplus/_assets/tools/bppack.py +1867 -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 +86 -0
- bedrockplus/cli.py +121 -0
- bedrockplus/commands.py +137 -0
- bedrockplus/events.py +377 -0
- bedrockplus/objects.py +820 -0
- bedrockplus/py.typed +1 -0
- bedrockplus/system.py +110 -0
- bedrockplus-0.1.0b1.dist-info/METADATA +50 -0
- bedrockplus-0.1.0b1.dist-info/RECORD +39 -0
- bedrockplus-0.1.0b1.dist-info/WHEEL +4 -0
- bedrockplus-0.1.0b1.dist-info/entry_points.txt +2 -0
- bedrockplus-0.1.0b1.dist-info/licenses/LICENSE.txt +87 -0
- bedrockplus-0.1.0b1.dist-info/licenses/THIRD_PARTY_NOTICES.md +26 -0
- bedrockplus-0.1.0b1.dist-info/licenses/microsoft-detours-MIT.txt +23 -0
- bedrockplus-0.1.0b1.dist-info/top_level.txt +1 -0
bedrockplus/__init__.py
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""Public, typed BedrockPlus Python plugin API."""
|
|
2
|
+
|
|
3
|
+
__version__ = "0.1.0b1"
|
|
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
|
+
PlayerCommandEvent,
|
|
26
|
+
PlayerJoinEvent,
|
|
27
|
+
PlayerJumpEvent,
|
|
28
|
+
PlayerKickEvent,
|
|
29
|
+
PlayerLoginEvent,
|
|
30
|
+
PlayerMoveEvent,
|
|
31
|
+
PlayerQuitEvent,
|
|
32
|
+
ServerCommandEvent,
|
|
33
|
+
ServerListPingEvent,
|
|
34
|
+
ServerTickEvent,
|
|
35
|
+
)
|
|
36
|
+
from .objects import (
|
|
37
|
+
Block,
|
|
38
|
+
ConnectionInfo,
|
|
39
|
+
Entity,
|
|
40
|
+
GameMode,
|
|
41
|
+
ItemStack,
|
|
42
|
+
Level,
|
|
43
|
+
Location,
|
|
44
|
+
Player,
|
|
45
|
+
Server,
|
|
46
|
+
SocketAddress,
|
|
47
|
+
Vector2,
|
|
48
|
+
Vector3,
|
|
49
|
+
World,
|
|
50
|
+
)
|
|
51
|
+
from .system import System
|
|
52
|
+
|
|
53
|
+
__all__ = [
|
|
54
|
+
"__version__",
|
|
55
|
+
"BlockBreakEvent",
|
|
56
|
+
"Block",
|
|
57
|
+
"BlockPlaceEvent",
|
|
58
|
+
"CancellableEvent",
|
|
59
|
+
"CommandArgument",
|
|
60
|
+
"CommandArgumentType",
|
|
61
|
+
"CommandCallback",
|
|
62
|
+
"CommandInvocation",
|
|
63
|
+
"CommandOverload",
|
|
64
|
+
"CommandResult",
|
|
65
|
+
"CommandReturn",
|
|
66
|
+
"CommandSourceKind",
|
|
67
|
+
"CommandValue",
|
|
68
|
+
"ConnectionInfo",
|
|
69
|
+
"Entity",
|
|
70
|
+
"GameMode",
|
|
71
|
+
"Event",
|
|
72
|
+
"EventCallback",
|
|
73
|
+
"EventName",
|
|
74
|
+
"EventPriority",
|
|
75
|
+
"PlayerChatEvent",
|
|
76
|
+
"PlayerCommandEvent",
|
|
77
|
+
"PlayerJoinEvent",
|
|
78
|
+
"PlayerJumpEvent",
|
|
79
|
+
"PlayerKickEvent",
|
|
80
|
+
"PlayerLoginEvent",
|
|
81
|
+
"PlayerMoveEvent",
|
|
82
|
+
"PlayerQuitEvent",
|
|
83
|
+
"Player",
|
|
84
|
+
"ItemStack",
|
|
85
|
+
"Level",
|
|
86
|
+
"Location",
|
|
87
|
+
"Plugin",
|
|
88
|
+
"PluginHost",
|
|
89
|
+
"ServerCommandEvent",
|
|
90
|
+
"ServerListPingEvent",
|
|
91
|
+
"ServerTickEvent",
|
|
92
|
+
"Server",
|
|
93
|
+
"SocketAddress",
|
|
94
|
+
"TaskCallback",
|
|
95
|
+
"System",
|
|
96
|
+
"Vector2",
|
|
97
|
+
"Vector3",
|
|
98
|
+
"World",
|
|
99
|
+
]
|
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=[{hour}:{minute}:{second}.{millisecond}]
|
|
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,87 @@
|
|
|
1
|
+
BEDROCKPLUS PROPRIETARY SOFTWARE LICENSE AGREEMENT
|
|
2
|
+
|
|
3
|
+
Version 1.0 — 8 October 2026
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2026 Turkmen. All rights reserved.
|
|
6
|
+
|
|
7
|
+
This agreement applies to the BedrockPlus server software, launcher, runtime,
|
|
8
|
+
software development kits, headers, examples, documentation, and accompanying
|
|
9
|
+
files (collectively, the "Software"). By installing, copying, or using the
|
|
10
|
+
Software, you agree to these terms.
|
|
11
|
+
|
|
12
|
+
1. Permitted use
|
|
13
|
+
|
|
14
|
+
You may install and run unmodified copies of the Software to operate Minecraft:
|
|
15
|
+
Bedrock Edition dedicated servers, including personal and commercial servers.
|
|
16
|
+
You may create, compile, package, and distribute plugins that use the public
|
|
17
|
+
BedrockPlus Python API, C++ SDK headers, or documented plugin ABI. Plugins you
|
|
18
|
+
create remain yours.
|
|
19
|
+
|
|
20
|
+
2. Redistribution
|
|
21
|
+
|
|
22
|
+
You may not redistribute the BedrockPlus runtime, launcher, binaries, SDK,
|
|
23
|
+
documentation, or modified copies of them without prior written permission from
|
|
24
|
+
the copyright holder. Instead, direct users to the official BedrockPlus
|
|
25
|
+
distribution channels. This restriction does not prevent redistribution of
|
|
26
|
+
your own plugins or inclusion of the minimum public SDK declarations required
|
|
27
|
+
inside their source code.
|
|
28
|
+
|
|
29
|
+
3. Restrictions
|
|
30
|
+
|
|
31
|
+
Except where applicable law expressly permits it, you may not modify, reverse
|
|
32
|
+
engineer, decompile, disassemble, bypass access controls in, sublicense, sell,
|
|
33
|
+
rent, or create derivative works of the closed-source BedrockPlus runtime. You
|
|
34
|
+
may not use the BedrockPlus name or marks to imply endorsement of an unofficial
|
|
35
|
+
distribution.
|
|
36
|
+
|
|
37
|
+
4. Third-party software and services
|
|
38
|
+
|
|
39
|
+
Third-party components remain governed by their own license terms, reproduced
|
|
40
|
+
in THIRD_PARTY_NOTICES.md and the accompanying license files. Minecraft and the
|
|
41
|
+
Bedrock Dedicated Server are products of Microsoft and Mojang. BedrockPlus is
|
|
42
|
+
not affiliated with, endorsed by, or sponsored by Microsoft or Mojang. The
|
|
43
|
+
official Bedrock Dedicated Server is downloaded separately and is not licensed
|
|
44
|
+
under this agreement.
|
|
45
|
+
|
|
46
|
+
5. Server and player data
|
|
47
|
+
|
|
48
|
+
BedrockPlus processes server and player data locally to provide its documented
|
|
49
|
+
server and plugin features. Server operators are responsible for configuring
|
|
50
|
+
their plugins, protecting logs and stored data, informing players where legally
|
|
51
|
+
required, and complying with applicable privacy and data-protection law.
|
|
52
|
+
|
|
53
|
+
6. Updates and compatibility
|
|
54
|
+
|
|
55
|
+
Pre-release versions may change without notice and may support only the exact
|
|
56
|
+
operating-system, Python, and Bedrock Dedicated Server versions stated in their
|
|
57
|
+
release notes. No compatibility, update, or continued-availability commitment
|
|
58
|
+
is made.
|
|
59
|
+
|
|
60
|
+
7. Disclaimer of warranty
|
|
61
|
+
|
|
62
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND "AS AVAILABLE", WITHOUT WARRANTIES OF ANY
|
|
63
|
+
KIND, EXPRESS OR IMPLIED, INCLUDING WARRANTIES OF MERCHANTABILITY, FITNESS FOR
|
|
64
|
+
A PARTICULAR PURPOSE, TITLE, AND NON-INFRINGEMENT. USE PRE-RELEASE SOFTWARE
|
|
65
|
+
ONLY AFTER BACKING UP WORLDS AND SERVER DATA.
|
|
66
|
+
|
|
67
|
+
8. Limitation of liability
|
|
68
|
+
|
|
69
|
+
TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE COPYRIGHT HOLDER WILL NOT BE LIABLE
|
|
70
|
+
FOR ANY INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, OR PUNITIVE DAMAGES, OR
|
|
71
|
+
FOR LOSS OF DATA, WORLDS, PROFITS, REVENUE, OR SERVER AVAILABILITY, ARISING FROM
|
|
72
|
+
THE SOFTWARE OR ITS USE.
|
|
73
|
+
|
|
74
|
+
9. Termination
|
|
75
|
+
|
|
76
|
+
Your rights under this agreement terminate automatically if you materially
|
|
77
|
+
breach it. On termination, you must stop using and delete your copies of the
|
|
78
|
+
Software, except for backups that applicable law requires you to retain.
|
|
79
|
+
|
|
80
|
+
10. Contact and separate permission
|
|
81
|
+
|
|
82
|
+
Requests for redistribution, commercial licensing beyond these terms, security
|
|
83
|
+
reports, or other permissions must be sent through the official BedrockPlus
|
|
84
|
+
website or project contact channel.
|
|
85
|
+
|
|
86
|
+
If any provision is unenforceable, the remaining provisions continue in effect.
|
|
87
|
+
This agreement does not limit rights that cannot legally be waived.
|
|
@@ -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.
|