Files
Emberwild/scripts/net/server_config.gd

107 lines
3.2 KiB
GDScript

extends RefCounted
## A dedicated server's preferences (`server.json`) and its reserved names
## (`names.json` alongside). Created with defaults on first run and meant to
## be edited by hand; command-line flags override single values for one run.
## See docs/MULTIPLAYER_PLAN.md §4.
const DEFAULT_PATH := "user://server/server.json"
const DEFAULTS := {
"server_name": "Emberwild server",
"motd": "Welcome!",
"port": 24242,
"max_players": 8,
"password": "",
"world": "server-world",
"worldlet": "valley",
"seed": 1337,
"pvp": false,
"raiding": false,
"locks": "owner_and_friends",
"death_penalty": "grave",
"sleep": "all_online",
"pause_when_empty": true,
"day_length_minutes": 20,
"wolf_grace_days": 3,
"difficulty": "normal",
"autosave_minutes": 2,
"backups_kept": 10,
"admins": [],
"allowlist": [],
"banned": [],
}
## Settings sent to players when they join (never the password or the lists).
const PUBLIC := ["server_name", "motd", "max_players", "worldlet", "pvp", "raiding", "locks",
"death_penalty", "sleep", "pause_when_empty", "day_length_minutes", "wolf_grace_days", "difficulty"]
var path := DEFAULT_PATH
var data: Dictionary = {} ## what's in server.json (saved)
var overrides: Dictionary = {} ## command-line flags for this run (never saved)
## Reserved names: lower-case name -> {"name": as typed, "id": player id}.
var names: Dictionary = {}
static func open(p: String = DEFAULT_PATH) -> RefCounted:
var c = load("res://scripts/net/server_config.gd").new()
c.path = p
DirAccess.make_dir_recursive_absolute(p.get_base_dir())
var loaded: Variant = JSON.parse_string(FileAccess.get_file_as_string(p)) if FileAccess.file_exists(p) else null
c.data = DEFAULTS.duplicate(true)
if loaded is Dictionary:
for k in loaded:
c.data[k] = loaded[k]
else:
c.save() # first run: write the defaults so they can be edited
var n: Variant = JSON.parse_string(FileAccess.get_file_as_string(c.names_path())) \
if FileAccess.file_exists(c.names_path()) else null
if n is Dictionary:
c.names = n
return c
func names_path() -> String:
return path.get_base_dir().path_join("names.json")
func save() -> void:
_write(path, data)
func save_names() -> void:
_write(names_path(), names)
static func _write(p: String, d: Dictionary) -> void:
var tmp := p + ".tmp"
var f := FileAccess.open(tmp, FileAccess.WRITE)
if f == null:
push_error("[server] couldn't write %s" % p)
return
f.store_string(JSON.stringify(d, "\t"))
f.close()
DirAccess.rename_absolute(tmp, p)
## A setting's value for this run (a flag beats the file).
func v(k: String) -> Variant:
return overrides.get(k, data.get(k))
func public_info() -> Dictionary:
var out := {}
for k in PUBLIC:
out[k] = v(k)
return out
## The player id holding `n`, or "" if it's free.
func name_owner(n: String) -> String:
return String(names.get(n.to_lower(), {}).get("id", ""))
## Gives `n` to `id`, releasing any other name that id held.
func reserve_name(n: String, id: String) -> void:
for k in names.keys():
if names[k].id == id and k != n.to_lower():
names.erase(k)
names[n.to_lower()] = {"name": n, "id": id}
save_names()
func is_admin(id: String) -> bool:
return id in data.admins
func add_admin(id: String) -> void:
if not id in data.admins:
data.admins.append(id)
save()