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.
Files changed (39) hide show
  1. bedrockplus/__init__.py +99 -0
  2. bedrockplus/__main__.py +4 -0
  3. bedrockplus/_assets/Initialize-BedrockPlusServer.ps1 +395 -0
  4. bedrockplus/_assets/LICENSE.txt +87 -0
  5. bedrockplus/_assets/README.md +85 -0
  6. bedrockplus/_assets/SHA256SUMS +21 -0
  7. bedrockplus/_assets/Start-BedrockPlus.ps1 +151 -0
  8. bedrockplus/_assets/THIRD_PARTY_NOTICES.md +26 -0
  9. bedrockplus/_assets/bedrockplus.exe +0 -0
  10. bedrockplus/_assets/bedrockplus_bootstrap.dll +0 -0
  11. bedrockplus/_assets/bedrockplus_plugin_host.dll +0 -0
  12. bedrockplus/_assets/bedrockplus_plugin_worker.dll +0 -0
  13. bedrockplus/_assets/bedrockplus_runtime.dll +0 -0
  14. bedrockplus/_assets/bin/bedrockplus.ps1 +192 -0
  15. bedrockplus/_assets/compatibility/bds/1.26.51.1/windows-x64.json +24 -0
  16. bedrockplus/_assets/compatibility/bds/supported-versions.json +14 -0
  17. bedrockplus/_assets/licenses/microsoft-detours-MIT.txt +23 -0
  18. bedrockplus/_assets/plugins/README.txt +11 -0
  19. bedrockplus/_assets/release-manifest.json +35 -0
  20. bedrockplus/_assets/server/README.txt +10 -0
  21. bedrockplus/_assets/tools/bppack.py +1867 -0
  22. bedrockplus/_assets/tools/init_python_plugin.py +140 -0
  23. bedrockplus/_assets/tools/pack_plugin.py +142 -0
  24. bedrockplus/_assets/tools/world_packs.py +530 -0
  25. bedrockplus/api.py +86 -0
  26. bedrockplus/cli.py +121 -0
  27. bedrockplus/commands.py +137 -0
  28. bedrockplus/events.py +377 -0
  29. bedrockplus/objects.py +820 -0
  30. bedrockplus/py.typed +1 -0
  31. bedrockplus/system.py +110 -0
  32. bedrockplus-0.1.0b1.dist-info/METADATA +50 -0
  33. bedrockplus-0.1.0b1.dist-info/RECORD +39 -0
  34. bedrockplus-0.1.0b1.dist-info/WHEEL +4 -0
  35. bedrockplus-0.1.0b1.dist-info/entry_points.txt +2 -0
  36. bedrockplus-0.1.0b1.dist-info/licenses/LICENSE.txt +87 -0
  37. bedrockplus-0.1.0b1.dist-info/licenses/THIRD_PARTY_NOTICES.md +26 -0
  38. bedrockplus-0.1.0b1.dist-info/licenses/microsoft-detours-MIT.txt +23 -0
  39. bedrockplus-0.1.0b1.dist-info/top_level.txt +1 -0
@@ -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
+ ]
@@ -0,0 +1,4 @@
1
+ from .cli import main
2
+
3
+
4
+ raise SystemExit(main())
@@ -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.