M2.7: Host Game, backups, launchd/systemd samples, hosting and Tailscale guide
This commit is contained in:
@@ -87,8 +87,10 @@ func _ready() -> void:
|
||||
_pages["profile"] = _profile_page()
|
||||
_pages["join"] = _join_page()
|
||||
_pages["lobby"] = _lobby_page()
|
||||
_pages["host"] = _host_page()
|
||||
for p in _pages.values():
|
||||
col.add_child(p)
|
||||
Net.host_status.connect(_on_host_status)
|
||||
Net.joined.connect(_enter_server_world)
|
||||
Net.join_failed.connect(_on_join_failed)
|
||||
Net.left.connect(_on_left)
|
||||
@@ -127,7 +129,7 @@ func _maybe_capture() -> void:
|
||||
var me: RefCounted = Net.get_identity()
|
||||
if me.name.is_empty():
|
||||
me.name = "Paul" # in memory only, for the pictures
|
||||
for page in ["main", "new", "load", "profile", "join", "lobby"]:
|
||||
for page in ["main", "new", "load", "profile", "join", "host", "lobby"]:
|
||||
if page == "lobby":
|
||||
# Sample data: the lobby normally needs a live server.
|
||||
Net.server_info = {"server_name": "Paul's island", "motd": "Welcome! Be nice to the wolves.",
|
||||
@@ -147,7 +149,8 @@ func _unhandled_input(event: InputEvent) -> void:
|
||||
if event is InputEventKey and event.pressed and event.keycode == KEY_ESCAPE and not _pages["main"].visible:
|
||||
if _pages["lobby"].visible:
|
||||
Net.leave()
|
||||
elif Net.state == "connecting":
|
||||
elif Net.state == "connecting" or Net.hosting:
|
||||
Net.stop_hosting()
|
||||
Net.stop()
|
||||
_join_msg.text = ""
|
||||
_show("main")
|
||||
@@ -155,16 +158,19 @@ func _unhandled_input(event: InputEvent) -> void:
|
||||
_show("main")
|
||||
|
||||
func _show(page: String) -> void:
|
||||
# Joining needs a name: send people to their profile first.
|
||||
if page == "join" and Identity.name_problem(Net.get_identity().name) != "":
|
||||
_after_profile = "join"
|
||||
# Joining (or hosting) needs a name: send people to their profile first.
|
||||
if page in ["join", "host"] and Identity.name_problem(Net.get_identity().name) != "":
|
||||
_after_profile = page
|
||||
page = "profile"
|
||||
if page == "host":
|
||||
_fill_host()
|
||||
for k in _pages:
|
||||
_pages[k].visible = k == page
|
||||
_armed_delete = ""
|
||||
if page == "profile":
|
||||
_fill_profile()
|
||||
elif page == "join":
|
||||
_join_shown_at = Time.get_ticks_msec()
|
||||
_join_addr.text = Net.get_identity().last_server
|
||||
_join_btn.disabled = false
|
||||
_join_addr.grab_focus()
|
||||
@@ -199,6 +205,7 @@ func _main_page() -> Control:
|
||||
var lb := _button("Load World", _show.bind("load"))
|
||||
lb.disabled = worlds.is_empty()
|
||||
v.add_child(lb)
|
||||
v.add_child(_button("Host Game", _show.bind("host")))
|
||||
v.add_child(_button("Join Game", _show.bind("join")))
|
||||
var n: String = Net.get_identity().name
|
||||
v.add_child(_button("Profile: %s" % n if not n.is_empty() else "Set Up Your Profile",
|
||||
@@ -315,6 +322,119 @@ func _save_profile() -> void:
|
||||
_rebuild_main()
|
||||
_show(_after_profile)
|
||||
|
||||
var _join_shown_at := -100000
|
||||
|
||||
# --- hosting (M2.7) -------------------------------------------------------------
|
||||
|
||||
var _host_name: LineEdit
|
||||
var _host_pw: LineEdit
|
||||
var _host_port: LineEdit
|
||||
var _host_seed: LineEdit
|
||||
var _host_seed_label: Label
|
||||
var _host_preset: OptionButton
|
||||
var _host_msg: Label
|
||||
var _host_btn: Button
|
||||
const PRESET_IDS := ["co-op", "rivals", "adversarial"]
|
||||
const PRESET_NAMES := ["Co-op: no PvP, bases safe, friends share", "Friendly rivals: PvP on, bases safe",
|
||||
"Adversarial: PvP, raiding, locks, drop everything on death"]
|
||||
|
||||
func _host_page() -> Control:
|
||||
var p := UITheme.panel()
|
||||
var v := VBoxContainer.new()
|
||||
v.add_theme_constant_override("separation", 7)
|
||||
p.add_child(v)
|
||||
v.add_child(UITheme.label("Host a game", 24))
|
||||
v.add_child(UITheme.label("Runs a server on this computer and puts you in it. Friends join with your address.", 13, UITheme.TEXT_DIM))
|
||||
v.add_child(UITheme.label("Server name", 15, UITheme.TEXT_DIM))
|
||||
_host_name = LineEdit.new()
|
||||
_host_name.custom_minimum_size = Vector2(420, 38)
|
||||
_host_name.max_length = 40
|
||||
v.add_child(_host_name)
|
||||
v.add_child(UITheme.label("Rules", 15, UITheme.TEXT_DIM))
|
||||
_host_preset = OptionButton.new()
|
||||
for n in PRESET_NAMES:
|
||||
_host_preset.add_item(n)
|
||||
_host_preset.custom_minimum_size = Vector2(420, 36)
|
||||
v.add_child(_host_preset)
|
||||
var row := HBoxContainer.new()
|
||||
row.add_theme_constant_override("separation", 10)
|
||||
var c1 := VBoxContainer.new()
|
||||
c1.add_child(UITheme.label("Password (optional)", 15, UITheme.TEXT_DIM))
|
||||
_host_pw = LineEdit.new()
|
||||
_host_pw.secret = true
|
||||
_host_pw.custom_minimum_size = Vector2(200, 38)
|
||||
c1.add_child(_host_pw)
|
||||
row.add_child(c1)
|
||||
var c2 := VBoxContainer.new()
|
||||
c2.add_child(UITheme.label("Port (UDP)", 15, UITheme.TEXT_DIM))
|
||||
_host_port = LineEdit.new()
|
||||
_host_port.custom_minimum_size = Vector2(100, 38)
|
||||
c2.add_child(_host_port)
|
||||
row.add_child(c2)
|
||||
var c3 := VBoxContainer.new()
|
||||
_host_seed_label = UITheme.label("Seed", 15, UITheme.TEXT_DIM)
|
||||
c3.add_child(_host_seed_label)
|
||||
_host_seed = LineEdit.new()
|
||||
_host_seed.placeholder_text = "random"
|
||||
_host_seed.custom_minimum_size = Vector2(100, 38)
|
||||
c3.add_child(_host_seed)
|
||||
row.add_child(c3)
|
||||
v.add_child(row)
|
||||
_host_msg = UITheme.label("", 14, UITheme.TEXT_DIM)
|
||||
_host_msg.autowrap_mode = TextServer.AUTOWRAP_WORD
|
||||
_host_msg.custom_minimum_size = Vector2(420, 0)
|
||||
v.add_child(_host_msg)
|
||||
var h := HBoxContainer.new()
|
||||
h.add_theme_constant_override("separation", 10)
|
||||
_host_btn = _button("Start", _start_host, 140)
|
||||
h.add_child(_host_btn)
|
||||
h.add_child(_button("Back", func():
|
||||
Net.stop_hosting()
|
||||
Net.stop()
|
||||
_show("main"), 120))
|
||||
v.add_child(h)
|
||||
return p
|
||||
|
||||
func _fill_host() -> void:
|
||||
var c: RefCounted = load("res://scripts/net/server_config.gd").open(Net.host_config)
|
||||
var n: String = c.data.server_name
|
||||
_host_name.text = "%s's island" % Net.get_identity().name if n == "Emberwild server" else n
|
||||
_host_port.text = str(int(c.data.port))
|
||||
_host_pw.text = String(c.data.password)
|
||||
var preset := "co-op"
|
||||
if bool(c.data.pvp):
|
||||
preset = "adversarial" if bool(c.data.raiding) else "rivals"
|
||||
_host_preset.select(PRESET_IDS.find(preset))
|
||||
var meta_path: String = Net.host_config.get_base_dir().path_join("worlds/server-world/meta.json")
|
||||
var existing: bool = FileAccess.file_exists(meta_path)
|
||||
_host_seed.editable = not existing
|
||||
_host_seed_label.text = "Seed" if not existing else "Seed (kept)"
|
||||
_host_seed.text = "" if not existing else str(int(c.data.seed))
|
||||
_host_msg.text = "Your hosted island carries on where you left it." if existing else "A new island will be made."
|
||||
_host_msg.add_theme_color_override("font_color", UITheme.TEXT_DIM)
|
||||
_host_btn.disabled = false
|
||||
|
||||
func _start_host() -> void:
|
||||
var port_t := _host_port.text.strip_edges()
|
||||
if not port_t.is_valid_int() or int(port_t) < 1024 or int(port_t) > 65535:
|
||||
_on_host_status("The port is a number from 1024 to 65535 (24242 is the usual one)", true)
|
||||
return
|
||||
var seed_t := _host_seed.text.strip_edges()
|
||||
var seed := int(seed_t) if seed_t.is_valid_int() else (seed_t.hash() if not seed_t.is_empty() else randi() % 1000000)
|
||||
var name := _host_name.text.strip_edges()
|
||||
if name.is_empty():
|
||||
name = "%s's island" % Net.get_identity().name
|
||||
_host_btn.disabled = true
|
||||
Net.host(name, _host_pw.text, int(port_t), PRESET_IDS[maxi(_host_preset.selected, 0)], seed)
|
||||
|
||||
func _on_host_status(text: String, failed: bool) -> void:
|
||||
if not _pages["host"].visible:
|
||||
return
|
||||
_host_msg.text = text
|
||||
_host_msg.add_theme_color_override("font_color", UITheme.BAD if failed else UITheme.TEXT_DIM)
|
||||
if failed:
|
||||
_host_btn.disabled = false
|
||||
|
||||
func _join_page() -> Control:
|
||||
var p := UITheme.panel()
|
||||
var v := VBoxContainer.new()
|
||||
@@ -350,6 +470,9 @@ func _join_page() -> Control:
|
||||
return p
|
||||
|
||||
func _connect() -> void:
|
||||
# (A click or Enter carried over from the page before can't connect.)
|
||||
if Time.get_ticks_msec() - _join_shown_at < 400:
|
||||
return
|
||||
if _join_addr.text.strip_edges().is_empty():
|
||||
_join_msg.text = "Enter the server's address"
|
||||
_join_msg.add_theme_color_override("font_color", UITheme.BAD)
|
||||
@@ -360,6 +483,9 @@ func _connect() -> void:
|
||||
Net.join(_join_addr.text, _join_pw.text)
|
||||
|
||||
func _on_join_failed(reason: String) -> void:
|
||||
if _pages["host"].visible:
|
||||
_on_host_status(reason, true)
|
||||
return
|
||||
_join_btn.disabled = false
|
||||
_join_msg.text = reason
|
||||
_join_msg.add_theme_color_override("font_color", UITheme.BAD)
|
||||
|
||||
Reference in New Issue
Block a user