Add dedicated server runtime

This commit is contained in:
Alexander Sellite 2026-08-10 13:56:03 -04:00
parent e204279b09
commit 74c82696fe
14 changed files with 595 additions and 47 deletions

View file

@ -0,0 +1,51 @@
extends SceneTree
const TEST_PORT: int = 35777
func _init() -> void:
call_deferred("_run")
func _run() -> void:
var harness := Node.new()
root.add_child(harness)
var players := Node3D.new()
harness.add_child(players)
var spawn_service := PlayerSpawnService.new()
harness.add_child(spawn_service)
spawn_service.setup(players, null, Transform3D.IDENTITY)
var host_identity := HostIdentityStore.new()
harness.add_child(host_identity)
var known_players := KnownPlayerStore.new()
harness.add_child(known_players)
var host_bans := HostBanStore.new()
harness.add_child(host_bans)
var session := NetworkSession.new()
harness.add_child(session)
await process_frame
session.setup(
null,
null,
spawn_service,
null,
host_identity,
known_players,
null,
host_bans,
true,
)
assert(session.start_dedicated_host(TEST_PORT, 5, "127.0.0.1"))
assert(session.is_dedicated_host())
assert(session.get_local_peer_id() == 0)
assert(session.get_player_count() == 0)
assert(session.get_session_max_players() == 5)
assert(session.get_host_port() == TEST_PORT)
assert(session.set_host_open(true))
assert(session.is_open_host())
session.disconnect_session("Dedicated host validation complete.")
assert(not session.is_session_active())
assert(not session.is_dedicated_host())
harness.queue_free()
print("DEDICATED_HOST_SESSION_VALIDATION_OK")
quit(0)

View file

@ -0,0 +1 @@
uid://ctky0gkb63nqa

View file

@ -0,0 +1,49 @@
extends SceneTree
const MainScene = preload("res://main/main.tscn")
const TEST_ENDPOINT: String = "127.0.0.1:7777"
const EXPECTED_SERVER_NAME: String = "Dedicated-Client-Test"
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
root.size = Vector2i(1280, 720)
var main: Node = MainScene.instantiate()
root.add_child(main)
for _frame: int in 4:
await process_frame
if not bool(main.get("_application_initialized")):
main.call("_activate_selected_data_path", "", true)
for _frame: int in 8:
await process_frame
assert(bool(main.get("_application_initialized")))
main.call("_on_title_join_game_requested", TEST_ENDPOINT)
var session := main.get_node("%NetworkSession") as NetworkSession
var joined: bool = false
var deadline: int = Time.get_ticks_msec() + 20000
while Time.get_ticks_msec() < deadline:
await process_frame
if session.state == NetworkSession.State.VERIFYING_SERVER_IDENTITY:
main.call("_confirm_server_trust")
if session.is_joined_client() and bool(main.get("_gameplay_started")):
joined = true
break
assert(joined)
assert(session.get_local_peer_id() > 1)
assert(session.get_player_count() == 1)
var metadata: Dictionary = session.get_last_server_metadata()
assert(str(metadata.get("server_display_name", "")) == EXPECTED_SERVER_NAME)
var spawn_service := main.get_node(
"%PlayerSpawnService"
) as PlayerSpawnService
assert(spawn_service.get_avatar(1) == null)
assert(spawn_service.get_avatar(session.get_local_peer_id()) != null)
print("DEDICATED_SERVER_CLIENT_VALIDATION_OK")
session.disconnect_session("Dedicated client validation complete.")
main.queue_free()
for _frame: int in 4:
await process_frame
quit()

View file

@ -0,0 +1 @@
uid://cwum3r4puerll

View file

@ -0,0 +1,63 @@
extends SceneTree
const ConfigType = preload("res://server/dedicated_server_config.gd")
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
var defaults := ConfigType.new()
defaults.set("data_directory", "/tmp/netfishing-server")
defaults.call("_validate")
assert(defaults.is_valid())
assert(not bool(defaults.get("public_listing")))
var path: String = ProjectSettings.globalize_path(
"user://dedicated-server-validation.cfg"
)
var file := ConfigFile.new()
file.set_value("server", "name", "Configured Room")
file.set_value("server", "bind_address", "127.0.0.1")
file.set_value("server", "port", 17777)
file.set_value("server", "max_players", 12)
file.set_value("server", "public", true)
file.set_value("server", "data_directory", "/tmp/configured-server")
file.set_value("discovery", "url", "https://discovery.netfishing.org/")
assert(file.save(path) == OK)
var configured := ConfigType.new()
assert(bool(configured.call("_load_file", path)))
configured.call("_validate")
assert(configured.is_valid())
assert(str(configured.get("server_name")) == "Configured Room")
assert(str(configured.get("bind_address")) == "127.0.0.1")
assert(int(configured.get("port")) == 17777)
assert(int(configured.get("max_players")) == 12)
assert(bool(configured.get("public_listing")))
assert(str(configured.get("discovery_url")) == "https://discovery.netfishing.org")
assert(DirAccess.remove_absolute(path) == OK)
var invalid := ConfigType.new()
invalid.set("public_listing", true)
invalid.set("data_directory", "/tmp/invalid-server")
invalid.call("_validate")
assert(not invalid.is_valid())
var discovery := DiscoveryClient.new()
assert(bool(discovery.call("_valid_public_room", {
"room_id": "empty-dedicated-room",
"room_name": "Empty Dedicated Room",
"address": "203.0.113.10",
"port": 7777,
"current_players": 0,
"max_players": 8,
"game_version": str(ProjectSettings.get_setting(
"application/config/version", "unknown"
)),
"protocol_version": NetworkProtocol.PROTOCOL_VERSION,
})))
discovery.free()
print("DEDICATED_SERVER_CONFIG_VALIDATION_OK")
quit()

View file

@ -0,0 +1 @@
uid://vm5lql2w6h3e