M2.1: dedicated server, joining, identity handshake, names, lobby
- Net autoload: headless dedicated server (--server) on UDP 24242 via ENet, server.json preferences (flags override per run, never saved), reserved names in names.json - Identity: RSA-2048 key per install (Godot has no Ed25519), player id = key hash, challenge/response so ids can't be faked; profile with name and limited appearance (tunic, hair, beard) - Server refuses bans, allowlist misses, duplicate logins, bad or taken names, wrong passwords, old protocol versions and a full server, each with a clear reason; first player on a new server becomes admin - Title screen: Profile, Join Game, and a lobby with server info, rules and who's online - test_net_lobby: real headless server + bot processes over UDP (38 checks); --exit-with so test servers never outlive the test
This commit is contained in:
57
tests/net_bot.gd
Normal file
57
tests/net_bot.gd
Normal file
@@ -0,0 +1,57 @@
|
||||
extends SceneTree
|
||||
## A scripted headless player for the network tests (tests/test_net_lobby.gd
|
||||
## starts several of these as separate processes).
|
||||
##
|
||||
## Args (after --): --identity <dir> --name <name> --address host:port
|
||||
## [--password p] [--stay seconds] [--result <json path>] [--forge] [--protocol n]
|
||||
## Joins, stays a while noting who it saw, leaves, writes the outcome to the
|
||||
## result file and quits. Gives up after 20 s whatever happens.
|
||||
|
||||
var _outcome := ""
|
||||
var _reason := ""
|
||||
|
||||
func _initialize() -> void:
|
||||
_run.call_deferred()
|
||||
|
||||
func _run() -> void:
|
||||
var net: Node = root.get_node("Net")
|
||||
var args: Dictionary = net.parse_args(OS.get_cmdline_user_args())
|
||||
var Identity = load("res://scripts/net/identity.gd")
|
||||
var me = Identity.open(String(args.get("identity", "user://test_net/bot")))
|
||||
if args.has("name"):
|
||||
me.name = String(args.name)
|
||||
net.identity = me
|
||||
net.debug_forge = args.has("forge")
|
||||
net.debug_protocol = int(args.get("protocol", 0))
|
||||
net.debug_skip_name_check = args.has("raw-name")
|
||||
net.joined.connect(func(): _outcome = "joined")
|
||||
net.join_failed.connect(func(r): _outcome = "rejected"; _reason = r)
|
||||
var res := {"joined": false, "reason": "", "saw": [], "admin": false, "server_name": "", "id": me.player_id}
|
||||
net.join(String(args.get("address", "127.0.0.1")), String(args.get("password", "")))
|
||||
var start := Time.get_ticks_msec()
|
||||
while _outcome.is_empty() and Time.get_ticks_msec() - start < 20000:
|
||||
await process_frame
|
||||
if _outcome == "joined":
|
||||
res.joined = true
|
||||
res.server_name = net.server_info.get("server_name", "")
|
||||
res.admin = bool(net.players.get(net.local_peer, {}).get("admin", false))
|
||||
var saw := {}
|
||||
var stay := float(args.get("stay", 2.0))
|
||||
var s := 0.0
|
||||
while s < stay and net.state == "connected":
|
||||
for p in net.players.values():
|
||||
saw[p.name] = true
|
||||
await create_timer(0.1).timeout
|
||||
s += 0.1
|
||||
res.saw = saw.keys()
|
||||
net.leave()
|
||||
for _i in range(10):
|
||||
await process_frame
|
||||
else:
|
||||
res.reason = _reason if not _reason.is_empty() else "timed out"
|
||||
if args.has("result"):
|
||||
var f := FileAccess.open(String(args.result), FileAccess.WRITE)
|
||||
f.store_string(JSON.stringify(res))
|
||||
f.close()
|
||||
print("[bot %s] %s" % [me.name, JSON.stringify(res)])
|
||||
quit()
|
||||
Reference in New Issue
Block a user