Prepare tester feedback and reproducible alpha builds

This commit is contained in:
Emporex committed 2026-10-04 14:35:50 +02:00
1 parent cad08aafb7
commit 235d7f3810
7 files changed
+120 -4

No files matched your search

+46
View File
@@ -0,0 +1,46 @@
# Void Bastion – Alpha-Testcheckliste
Diese Liste wird vor jeder öffentlichen Windows-Alpha vollständig abgearbeitet. Automatische Prüfungen sind mit **A**, manuelle Sicht- und Bedienprüfungen mit **M** gekennzeichnet.
## Build und Installation
- [ ] **A** `tests/smoke_test.gd` läuft ohne Fehler.
- [ ] **A** `tests/online_integration_test.gd` läuft gegen `api.void-bastion.gergames.de` ohne Fehler.
- [ ] **A** Windows-Export und Setup werden mit `packaging/windows/build.ps1` reproduzierbar erstellt.
- [ ] **A** Entwicklerwerkzeuge, Tests, Serverdateien und interne MCP-Konfigurationen sind nicht im Windows-Paket enthalten.
- [ ] **M** Setup installiert ohne Administratorrechte, Startmenü- und Desktop-Verknüpfung funktionieren.
- [ ] **M** Deinstallation entfernt Programmdateien und Verknüpfungen vollständig.
- [ ] **M** Windows-SmartScreen-Hinweis ist in den Testhinweisen genannt, solange der Installer noch nicht signiert ist.
## Darstellung und Bedienung
- [ ] **M** 1920 × 1080, 2560 × 1440 und eine kleinere 16:9-Auflösung prüfen: Karte und UI bleiben scharf und vollständig sichtbar.
- [ ] **M** Alle drei Karten prüfen: Straße, Gegnerlaufweg, Raster und Bausperren stimmen exakt überein.
- [ ] **M** Reaktoren und freie Weltraumbereiche sind auf allen Karten unbebaubar.
- [ ] **M** Reichweitenvorschau erscheint vor dem Bau; Turmwerte und Upgrade-Mehrwert sind lesbar.
- [ ] **M** Zurück-Schaltfläche bricht eine laufende Runde verständlich ab.
## Spielablauf
- [ ] **M** Jede Karte einmal auf Leicht, Mittel und Schwer starten; Startressourcen und Gegnerdruck unterscheiden sich sichtbar.
- [ ] **M** Eine Mission bis Welle 15 spielen: Sieg kann beendet oder freiwillig als Endloslauf fortgesetzt werden.
- [ ] **M** Eine Niederlage im Endlosmodus wird nicht als gescheiterte Mission gewertet.
- [ ] **M** Kernkristall-Belohnung wird nach erfolgreicher Karte gespeichert.
- [ ] **M** Spielstand, Einstellungen und Bestwerte bleiben nach einem Neustart erhalten.
## Konto und Onlinefunktionen
- [ ] **M** Gastkonto wird beim ersten Start erzeugt; Spielername lässt sich ändern.
- [ ] **M** Profil zeigt Version, gekürzte Spieler-ID, Datenschutz und Support/Feedback.
- [ ] **M** Bestenliste lädt; ein neuer Bestwert wird korrekt übertragen und dem sichtbaren Spielernamen zugeordnet.
- [ ] **M** Kontolöschung verlangt eine zweite Bestätigung und erzeugt anschließend ein neues Gastprofil.
- [ ] **M** Privater Raum: Erstellen, Code eingeben, Bereit-Lobby, Partiestart und Abbruch mit zwei Geräten prüfen.
- [ ] **M** Kurzen Netzabbruch während einer Onlinepartie und die Wiederverbindung prüfen.
- [ ] **M** Lokaler Koop mit KI: getrennte Ressourcen, zwei Gegnerwege, Seitenwechsel und gemeinsames Reaktorleben prüfen.
## Veröffentlichung
- [ ] **M** Setup-Datei und SHA-256-Prüfsumme stimmen mit der öffentlichen Release-Datei überein.
- [ ] **M** Download-Schaltfläche auf `https://void-bastion.gergames.de/` lädt die aktuelle Setup-Datei.
- [ ] **M** Datenschutz, Impressum, Supportadresse und Kontolöschseite sind öffentlich erreichbar.
- [ ] **M** Änderungen, bekannte Fehler und Testhinweise stehen in den Release-Notizen.
+5 -2
View File
@@ -1,4 +1,4 @@
# Void Bastion – spielbarer Prototyp 0.23
# Void Bastion - Alpha 0.1.0
Ein plattformübergreifender 2D-Tower-Defense-Prototyp für Godot 4. Der aktuelle Stand ist für Windows, Android und später iOS ausgelegt.
@@ -41,6 +41,7 @@ Ein plattformübergreifender 2D-Tower-Defense-Prototyp für Godot 4. Der aktuell
- frei wählbarer Spielername mit identischer Prüfung im Spiel und auf dem Server
- zweistufige Kontolöschung direkt im Pilotenprofil; danach wird ein neues lokales Gastprofil erstellt
- direkter Datenschutz-Link im Pilotenprofil
- sichtbare App-Version und vorbereitete Support-Mail an `support@gergames.de` im Pilotenprofil; Version, Plattform und gekürzte Spieler-ID werden für eine schnellere Fehlerzuordnung eingesetzt
- wartende, lokal gespeicherte Highscore-Einträge für die spätere sichere Serverübertragung
- eigener Multiplayerbereich mit schneller Spielersuche sowie privaten Koop-Räumen mit sechsstelligen Raumcodes
- gemeinsame Online-Lobby mit Spielernamen, festen Verteidigungsseiten und manuellem Bereit-Status für beide Piloten
@@ -81,6 +82,8 @@ Der Prototyp wurde mit der offiziellen Godot-Version 4.7.2 importiert und im aut
Der mitgelieferte Logiktest lässt sich bei Bedarf mit `godot --headless --path . --script res://tests/smoke_test.gd` erneut ausführen.
Für reproduzierbare Windows-Builds steht `packaging/windows/build.ps1` bereit. Godot und NSIS werden als Parameter übergeben; das Skript exportiert das Spiel, erstellt den Installer und gibt anschließend Größe und SHA-256-Prüfsumme aus. Die manuellen Freigabeprüfungen stehen in `ALPHA_TEST_CHECKLIST.md`.
## Werbung und Datenschutz
Die mobile Werbeanbindung ist technisch vorbereitet, aber absichtlich noch nicht für echte Werbung freigeschaltet:
@@ -107,7 +110,7 @@ Die öffentliche Spiel-API ist unter `api.void-bastion.gergames.de` erreichbar.
## Steuerung
> **Online-Stand 0.23:** Der offizielle Nakama-Godot-Client, automatische Gastanmeldung, servergeprüfte öffentliche Spielernamen, Kontolöschung im Spiel, 36 autoritative Ranglisten, geprüfte Ergebnisübermittlung, Echtzeit-Sockets, serverautoritativer Zwei-Spieler-Koop, private Räume per Raumcode, eine Bereit-Lobby und Wiederverbindung sind eingebaut. Ranglisten lösen den aktuellen öffentlichen Profilnamen über die unveränderliche Spieler-ID auf. Die öffentliche API ist über `https://api.void-bastion.gergames.de` mit einem gültigen Let's-Encrypt-Zertifikat freigeschaltet. Details stehen in `ONLINE_SETUP.md`.
> **Online-Stand Alpha 0.1.0:** Der offizielle Nakama-Godot-Client, automatische Gastanmeldung, servergeprüfte öffentliche Spielernamen, Kontolöschung im Spiel, 36 autoritative Ranglisten, geprüfte Ergebnisübermittlung, Echtzeit-Sockets, serverautoritativer Zwei-Spieler-Koop, private Räume per Raumcode, eine Bereit-Lobby und Wiederverbindung sind eingebaut. Ranglisten lösen den aktuellen öffentlichen Profilnamen über die unveränderliche Spieler-ID auf. Die öffentliche API ist über `https://api.void-bastion.gergames.de` mit einem gültigen Let's-Encrypt-Zertifikat freigeschaltet. Details stehen in `ONLINE_SETUP.md`.
Die Schaltfläche **Bestenliste** im Hauptmenü zeigt die zwölf besten Piloten für die aktuell gewählte Karte und Schwierigkeit. Zwischen Mission und Endlosmodus kann direkt in der Ansicht umgeschaltet werden; der eigene Eintrag wird farblich hervorgehoben.
+1 -1
View File
@@ -8,7 +8,7 @@ dedicated_server=false
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
exclude_filter=".mcp.json,*.md,tests/*,server/*,tools/*,packaging/*,addons/agent_tools/*,build/*,dist/*"
export_path="build/windows/Void-Bastion.exe"
patches=PackedStringArray()
+19
View File
@@ -155,6 +155,7 @@ var profile_name_input := ""
var profile_message := ""
var profile_delete_armed := false
var profile_rename_button := Rect2(220, 305, 250, 48)
var profile_support_button := Rect2(570, 685, 250, 48)
var profile_privacy_button := Rect2(840, 685, 250, 48)
var profile_delete_button := Rect2(1110, 685, 250, 48)
var profile_name_input_rect := Rect2(460, 330, 680, 82)
@@ -505,6 +506,8 @@ func _handle_pointer(position: Vector2, is_touch := false) -> void:
game_mode = "menu"
elif profile_rename_button.has_point(position):
_open_profile_name_entry()
elif profile_support_button.has_point(position):
OS.shell_open(_support_email_url())
elif profile_privacy_button.has_point(position):
OS.shell_open("https://void-bastion.gergames.de/privacy.html")
elif profile_delete_button.has_point(position):
@@ -742,6 +745,20 @@ func _hide_virtual_keyboard() -> void:
DisplayServer.virtual_keyboard_hide()
func _app_version() -> String:
return str(ProjectSettings.get_setting("application/config/version", "Entwicklung"))
func _support_email_url() -> String:
var subject := "Void Bastion Feedback %s" % _app_version()
var body := "Version: %s\nPlattform: %s\nSpieler-ID: %s\n\nBeschreibung:\n" % [
_app_version(),
OS.get_name(),
account_manager.short_id(),
]
return "mailto:support@gergames.de?subject=%s&body=%s" % [subject.uri_encode(), body.uri_encode()]
func _open_profile_name_entry() -> void:
profile_name_input = account_manager.display_name
profile_message = ""
@@ -1796,6 +1813,7 @@ func _draw_profile() -> void:
draw_rect(Rect2(Vector2.ZERO, SCREEN), Color(0.005, 0.015, 0.035, 0.76))
_draw_button(profile_back_button, "< ZURÜCK", false, Color("26394a"))
draw_string(font, Vector2(0, 112), "PILOTENPROFIL", HORIZONTAL_ALIGNMENT_CENTER, 1600, 44, Color("c7f5ff"))
draw_string(font, Vector2(1110, 112), "VERSION %s" % _app_version(), HORIZONTAL_ALIGNMENT_RIGHT, 290, 14, Color("91a8bc"))
draw_rect(Rect2(170, 155, 1260, 600), Color(0.012, 0.035, 0.065, 0.94), true)
draw_rect(Rect2(170, 155, 1260, 600), Color("4ab8d1"), false, 2.0)
draw_string(font, Vector2(220, 220), account_manager.display_name, HORIZONTAL_ALIGNMENT_LEFT, 520, 30, Color("8ff4ff"))
@@ -1824,6 +1842,7 @@ func _draw_profile() -> void:
draw_string(font, Vector2(1160, y), "%07d" % score, HORIZONTAL_ALIGNMENT_CENTER, 180, 16, Color("8fffea"))
if not profile_message.is_empty():
draw_string(font, Vector2(220, 658), profile_message, HORIZONTAL_ALIGNMENT_CENTER, 1160, 14, Color("ffcf7a"))
_draw_button(profile_support_button, "SUPPORT / FEEDBACK", false, Color("24516a"))
_draw_button(profile_privacy_button, "DATENSCHUTZ", false, Color("24475b"))
_draw_button(profile_delete_button, "LÖSCHEN BESTÄTIGEN" if profile_delete_armed else "KONTO LÖSCHEN", profile_delete_armed, Color("6b2d3b"))
+1 -1
View File
@@ -129,7 +129,7 @@ func submit_run(record: Dictionary) -> bool:
if not is_authenticated():
return false
var payload := record.duplicate(true)
payload["client_version"] = "0.23"
payload["client_version"] = str(ProjectSettings.get_setting("application/config/version", "development"))
var result = await client.rpc_async(session, "submit_run", JSON.stringify(payload))
var parsed := _parse_rpc_result(result)
if parsed.is_empty() or not bool(parsed.get("accepted", false)):
+44
View File
@@ -0,0 +1,44 @@
param(
[Parameter(Mandatory = $true)]
[string]$GodotExe,
[Parameter(Mandatory = $true)]
[string]$MakeNsisExe
)
$ErrorActionPreference = "Stop"
$projectRoot = (Resolve-Path (Join-Path $PSScriptRoot "..\..")).Path
$gameExe = Join-Path $projectRoot "build\windows\Void-Bastion.exe"
$installer = Join-Path $projectRoot "dist\Void-Bastion-Setup-x64.exe"
$installerScript = Join-Path $PSScriptRoot "installer.nsi"
foreach ($requiredFile in @($GodotExe, $MakeNsisExe, $installerScript)) {
if (-not (Test-Path -LiteralPath $requiredFile -PathType Leaf)) {
throw "Benötigte Datei fehlt: $requiredFile"
}
}
New-Item -ItemType Directory -Force -Path (Split-Path $gameExe), (Split-Path $installer) | Out-Null
& $GodotExe --headless --path $projectRoot --export-release "Windows x64" $gameExe
if ($LASTEXITCODE -ne 0 -or -not (Test-Path -LiteralPath $gameExe)) {
throw "Der Godot-Windows-Export ist fehlgeschlagen."
}
Push-Location $PSScriptRoot
try {
& $MakeNsisExe $installerScript
if ($LASTEXITCODE -ne 0 -or -not (Test-Path -LiteralPath $installer)) {
throw "Die Installer-Erstellung mit NSIS ist fehlgeschlagen."
}
}
finally {
Pop-Location
}
$installerFile = Get-Item -LiteralPath $installer
$hash = Get-FileHash -Algorithm SHA256 -LiteralPath $installer
Write-Host "Windows-Installer erfolgreich erstellt:"
Write-Host " Datei: $($installerFile.FullName)"
Write-Host " Größe: $([math]::Round($installerFile.Length / 1MB, 1)) MiB"
Write-Host " SHA256: $($hash.Hash)"
+4
View File
@@ -82,6 +82,10 @@ func _run() -> void:
assert(game.get("game_mode") == "menu", "Die Bestenliste benötigt einen funktionierenden Zurück-Button.")
assert(not account_manager.player_id.is_empty(), "Beim ersten Start muss automatisch ein stabiles Gastprofil angelegt werden.")
assert(not account_manager.display_name.is_empty(), "Das Gastprofil benötigt einen sichtbaren Pilotennamen.")
assert(game.call("_app_version") == "0.1.0-alpha", "Profil, Installer und Online-Übertragung müssen dieselbe Alpha-Version verwenden.")
var support_url: String = game.call("_support_email_url")
assert(support_url.begins_with("mailto:support@gergames.de?"), "Die Feedback-Schaltfläche muss die öffentliche Supportadresse verwenden.")
assert(support_url.contains("0.1.0-alpha") and support_url.contains(account_manager.short_id()), "Die Support-Mail muss Version und gekürzte Spieler-ID zur Fehlerzuordnung enthalten.")
account_manager.storage_enabled = false
var original_display_name: String = account_manager.display_name
assert(account_manager.validate_display_name("Kommandant Ägir").is_empty(), "Ein normaler internationaler Spielername muss gültig sein.")