be22e9f358
- Der Host hält einen Schlag eines Gastes, der während der Abklingzeit ankommt, bis zum ersten Takt danach. Übers Internet ging sonst etwa jeder fünfte Schlag eines Gastes verloren. - ENet drosselt die Figuren nie mehr; sonst konnten die Figuren eines von zwei Gästen dauerhaft stehen bleiben. Figuren gehen geordnet, und eine stille Verbindung gilt nach höchstens acht Sekunden als verloren. - Positionen, die keine Zahlen sind, und Figuren von Spielern, die nicht online sind, werden verworfen. - Ein Host mit angehaltener Simulation sagt das in der Statuszeile. - Neue Tests: Schlag während der Abklingzeit, Zielauswahl von NetLink, verworfene Figuren, Neuabgleich über die Brücke. - Der Fragebogen sagt, was jeder Rechner braucht, und die Freigabe in der Firewall gehört zum Host. CLAUDE.md beschreibt das Halten der Schläge, die Drosselung und die Zeitüberschreitung und ergänzt die Vertrauensregel um die Schlüssel. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
75 lines
2.5 KiB
GDScript
75 lines
2.5 KiB
GDScript
class_name LaunchOptions
|
|
extends RefCounted
|
|
## What the command line asks for. Godot passes the arguments after "--":
|
|
## --profile=NAME keeps key, save and recordings in a folder of their own,
|
|
## so that two windows on one machine are two players
|
|
## --name=NAME the player's name; like a name typed in the menu, it is
|
|
## remembered for the next start
|
|
## --solo starts playing alone at once, without the menu
|
|
## --host opens the world for guests at once
|
|
## --port=PORT the port an open world listens on
|
|
## --join=ADDRESS joins a host at once; ADDRESS may end in ":PORT"
|
|
|
|
## Longest profile name.
|
|
const MAX_PROFILE_LENGTH := 32
|
|
## Characters a profile name may contain.
|
|
const PROFILE_CHARACTERS := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
|
|
|
|
var profile := ""
|
|
var player_name := ""
|
|
## How to start without the menu: "", "solo", "host" or "join".
|
|
var start := ""
|
|
var port := NetLink.DEFAULT_PORT
|
|
var address := ""
|
|
## Arguments that were not understood and are ignored.
|
|
var ignored := PackedStringArray()
|
|
|
|
|
|
## Reads `arguments`. Unknown arguments and bad values end up in `ignored`.
|
|
static func parse(arguments: PackedStringArray) -> LaunchOptions:
|
|
var options := LaunchOptions.new()
|
|
for argument in arguments:
|
|
var value := argument.get_slice("=", 1) if argument.contains("=") else ""
|
|
match argument.get_slice("=", 0):
|
|
"--profile":
|
|
if is_valid_profile(value):
|
|
options.profile = value
|
|
else:
|
|
options.ignored.append(argument)
|
|
"--name":
|
|
options.player_name = value
|
|
"--solo":
|
|
options.start = "solo"
|
|
"--host":
|
|
options.start = "host"
|
|
"--port":
|
|
if value.is_valid_int() and value.to_int() >= 0 and value.to_int() <= 65535:
|
|
options.port = value.to_int()
|
|
else:
|
|
options.ignored.append(argument)
|
|
"--join":
|
|
options.start = "join"
|
|
options.address = value
|
|
_:
|
|
options.ignored.append(argument)
|
|
return options
|
|
|
|
|
|
## Whether `name` can name a profile folder: up to 32 of the letters A to Z,
|
|
## digits, "-" and "_".
|
|
static func is_valid_profile(name: String) -> bool:
|
|
if name.is_empty() or name.length() > MAX_PROFILE_LENGTH:
|
|
return false
|
|
for character in name:
|
|
if not PROFILE_CHARACTERS.contains(character):
|
|
return false
|
|
return true
|
|
|
|
|
|
## The folder for the player's files. The default profile uses the user
|
|
## folder itself, so that saves of earlier versions stay where they are.
|
|
func storage_dir() -> String:
|
|
if profile.is_empty():
|
|
return "user://"
|
|
return "user://profiles".path_join(profile)
|