118 lines
3.6 KiB
GDScript
118 lines
3.6 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.rejoin_requested.connect(_wiedereinstieg)
|
|
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)
|
|
|
|
# "Nochmal" nach einer Solopartie: das Menü wird übersprungen.
|
|
if not Net.rematch.is_empty():
|
|
var r: Dictionary = Net.rematch
|
|
Net.rematch = {}
|
|
Net.start_singleplayer(String(r.name), int(r.ai), int(r.stufe))
|
|
|
|
|
|
## 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)
|
|
|
|
|
|
## Nur Server: ein Rückkehrer klopft an. Gibt es seinen verwaisten Platz
|
|
## noch, übernimmt er ihn wieder vom Bot.
|
|
func _wiedereinstieg(code: String, peer: int, pname: String) -> void:
|
|
var game := raeume.get_node_or_null(NodePath(code + "/Container/Viewport/Game"))
|
|
if game == null:
|
|
Net.abweisen(peer, "In dem Raum läuft schon eine Partie.")
|
|
return
|
|
var cfg: Dictionary = game.wiedereinstieg(peer, pname)
|
|
if cfg.is_empty():
|
|
Net.abweisen(peer, "In dem Raum läuft schon eine Partie, und kein Platz heißt %s." % pname)
|
|
return
|
|
Net.rejoin_annehmen(code, peer, pname, 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")
|