Files
pirate-dice/scripts/main.gd
team3 f97d741c91 Spielstart zuverlaessig machen, Client wieder scharf rendern
Der Client steckte die Partie in einen SubViewport. Der rendert mit der
Basisaufloesung 1280x720 und wurde danach hochskaliert - das Bild wurde
matschig und die Kantenglaettung fiel weg. Den eigenen Physikraum braucht
aber nur der Server, weil dort viele Partien nebeneinander laufen. Also
bekommt nur er SubViewports; der Client haengt die Partie direkt in die
Szene. Die Knotennamen bleiben gleich, daran haengt das RPC-Ziel.

Der Healthcheck oeffnete alle 30 Sekunden eine nackte TCP-Verbindung auf
den WebSocket-Port. Der Server lehnte sie ab ("Missing or invalid header
'upgrade'"), und dabei ging reproduzierbar ein Paket an einen echten
Spieler verloren. Traefik braucht den Check nicht, also raus damit.

Blieb ein seltener Verlust des Startpakets: der Spieler sass in der Lobby,
waehrend die anderen spielten. Der Server legt jetzt nach, bis jeder den
Start quittiert hat.

Ein Verbindungsabbruch im Menue lud ausserdem die Szene neu und warf die
Meldung dazu gleich wieder weg.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 22:43:02 +02:00

97 lines
2.8 KiB
GDScript

extends Node
## Wechselt zwischen Menü und laufenden Partien.
##
## Mit `-- server <port>` läuft dieselbe Datei als Spielserver: kein Menü, kein
## Bild, dafür beliebig viele Räume nebeneinander.
##
## Ein Raum steckt in einem SubViewport mit eigener World3D. Nur so hat jede
## Partie ihren eigenen Physikraum. Die Knotennamen sind auf Server und Client
## gleich - daran hängt das RPC-Ziel.
var menu: CanvasLayer
var raeume: Node
func _ready() -> void:
raeume = Node.new()
raeume.name = "Raeume"
add_child(raeume)
Net.game_started.connect(_raum_bauen)
Net.room_closed.connect(_raum_abbauen)
Net.server_closed.connect(_back_to_menu)
var args := OS.get_cmdline_user_args()
if args.size() >= 2 and args[0] == "server":
if not Net.serve(int(args[1])):
get_tree().quit(1)
return
menu = preload("res://scripts/menu.gd").new()
add_child(menu)
## Das Spiel startet im Vollbild; F11 schaltet um.
func _unhandled_key_input(event: InputEvent) -> void:
if event is InputEventKey and event.pressed and event.keycode == KEY_F11:
var full := DisplayServer.window_get_mode() == DisplayServer.WINDOW_MODE_FULLSCREEN
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED if full
else DisplayServer.WINDOW_MODE_FULLSCREEN)
get_viewport().set_input_as_handled()
func _raum_bauen(code: String, cfg: Dictionary) -> void:
if raeume.has_node(code):
return
if menu != null:
menu.queue_free()
menu = null
var raum := Node.new()
raum.name = code
raeume.add_child(raum)
var behaelter: Node
var sicht: Node
if Net.dedicated:
# Auf dem Server laufen viele Partien nebeneinander. Jede braucht ihren
# eigenen Physikraum, sonst lägen alle Würfel im selben.
var c := SubViewportContainer.new()
c.stretch = true
c.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
var v := SubViewport.new()
v.own_world_3d = true
behaelter = c
sicht = v
else:
# Der Client hat nur eine Partie und rendert direkt ins Fenster. Ein
# SubViewport würde hier nur Auflösung und Kantenglättung kosten.
# Die Knotennamen müssen trotzdem gleich heißen - daran hängt das
# Ziel jedes RPC.
behaelter = Node.new()
sicht = Node.new()
behaelter.name = "Container"
sicht.name = "Viewport"
raum.add_child(behaelter)
behaelter.add_child(sicht)
var game := Node3D.new()
game.set_script(preload("res://scripts/game.gd"))
game.name = "Game"
sicht.add_child(game)
game.setup(cfg)
func _raum_abbauen(code: String) -> void:
var raum := raeume.get_node_or_null(NodePath(code))
if raum != null:
raum.queue_free()
## Nur wenn wirklich eine Partie lief. Sonst würde ein Verbindungsabbruch im
## Menü die Szene neu laden und die Meldung dazu gleich wieder wegwerfen.
func _back_to_menu() -> void:
if raeume.get_child_count() == 0:
return
get_tree().change_scene_to_file("res://scenes/main.tscn")