# Hurry Curry! - a game about cooking # Copyright (C) 2025 Hurry Curry! contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, version 3 of the License only. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # extends Menu var url_regex: RegEx = RegEx.new() @onready var server_list: VBoxContainer = $side/margin/options/second/ScrollContainerCustom/ServerList @onready var server_list_loading: Label = $side/margin/options/second/Loading @onready var server_list_empty: Label = $side/margin/options/second/NoServers @onready var connect_uri = $side/margin/options/second/connect/uri @onready var server = $side/margin/options/second/server @onready var server_control = $side/margin/options/second/server/control @onready var server_connect = $side/margin/options/second/server/connect @onready var editor_control = $side/margin/options/second/editor/control @onready var editor_connect = $side/margin/options/second/editor/connect @onready var editor_container = $side/margin/options/second/editor func _ready(): url_regex.compile("^(?:(ws|wss)://)?([^:]+)(?::([0-9]+))?$") if OS.has_feature("web"): server.hide() connect_uri.text = Global.get_profile("last_server_url") Sound.play_music("MainMenu") ServerList.update_server_list.connect(update_server_list) ServerList.update_loading.connect(update_server_list_loading) update_server_list(ServerList.current_list) update_server_list_loading(ServerList.loading) super() if not Global.get_profile("registry_asked"): var popup_data := MenuPopup.Data.new() popup_data.text = tr("c.menu.play.allow_query_registry").format([Global.get_setting("online.registry_url")]) var allow_button := Button.new() allow_button.text = tr("c.menu.accept") var deny_button := Button.new() deny_button.text = tr("c.menu.deny") allow_button.pressed.connect(func(): Global.set_setting("online.use_registry", true)) deny_button.pressed.connect(func(): Global.set_setting("online.use_registry", false)) popup_data.buttons = [allow_button, deny_button] await submenu("res://menu/popup.tscn", popup_data) Global.set_profile("registry_asked", true) Global.save_settings() Global.save_profile() ServerList.start() func update_server_list(lists: Array[Array]): # Find out the index of the currently focused server in the list var prev_selected_idx := -1 for i in range(server_list.get_children().size()): if server_list.get_child(i).has_focus(): prev_selected_idx = i break for c in server_list.get_children(): c.queue_free() var idx := 0 for l in lists: for i in l: var b := Button.new() b.text_overrun_behavior = TextServer.OVERRUN_TRIM_WORD_ELLIPSIS b.text = tr("c.menu.play.list_item").format([i.name, roundi(i.players_online)]) # TODO: Implement fallback address correctly if i.version[0] != Multiplayer.VERSION_MAJOR or i.version[1] > Multiplayer.VERSION_MINOR: b.disabled = true b.pressed.connect(connect_to.bind(i.address[0])) server_list.add_child(b) # Focus the same server with the same index as the previously focused one if idx == prev_selected_idx: b.grab_focus() idx += 1 if prev_selected_idx > idx: # Same index cannot be focused, since number of servers decreased if idx - 1 < 0: connect_uri.grab_focus() else: server_list.get_child(idx - 1).grab_focus() # Show message if no servers available server_list_empty.visible = idx == 0 func update_server_list_loading(status: bool): server_list_loading.visible = status func _menu_cover(state): $side.visible = not state func _on_connect_pressed(): var url = connect_uri.text var result := url_regex.search(url) if result != null: if result.get_string(1) == "": url = "ws://" + url # only set default port for non-tls websocket connections if result.get_string(3) == "" and result.get_string(1) != "wss": url = url + ":27032" connect_uri.text = url Global.set_profile("last_server_url", url) Global.save_profile() connect_to(url) func _on_quick_connect_pressed(): if OS.has_feature("web"): connect_to(JavaScriptBridge.eval(""" window.location.protocol.endsWith("s:") ? `wss://${window.location.host}/` : `ws://${window.location.hostname}:27032/` """)) else: connect_to("wss://hurrycurry.metamuffin.org/") func connect_to(url: String): print("Connecting to %s" % url) get_parent().replace_menu("res://menu/game.tscn", url) func _on_server_control_pressed(): match Server.state: Service.State.RUNNING: Server.stop() Service.State.STOPPED: Server.start() Service.State.FAILED: Server.start() func _on_editor_control_pressed(): match Editor.state: Service.State.RUNNING: Editor.stop() Service.State.STOPPED: Editor.start(); Server.start() Service.State.FAILED: Editor.start() func _on_server_connect_pressed(): connect_to("ws://%s:%d" % [Server.connect_address(), Global.get_setting("server.bind_port")]) func _on_editor_connect_pressed(): connect_to("ws://[::1]:27032/") func _process(_delta): server_control.disabled = false server_connect.visible = Server.state == Service.State.RUNNING server_control.modulate = Color.WHITE match Server.state: Service.State.RUNNING: server_control.text = tr("c.menu.play.server_stop") server_control.modulate = Color.AQUAMARINE Service.State.TESTING: server_control.text = tr("c.menu.play.server_testing") server_control.disabled = true Service.State.STARTING: server_control.text = tr("c.menu.play.server_starting") server_control.disabled = true Service.State.STOPPED: server_control.text = tr("c.menu.play.server_start") Service.State.FAILED: server_control.text = tr("c.menu.play.server_failed") server_control.modulate = Color(1, 0.4, 0.5) server_control.tooltip_text = tr("c.menu.play.server_failed_tooltip") Service.State.UNAVAILABLE: server_control.text = tr("c.menu.play.server_unavailable") server_control.disabled = true server_control.tooltip_text = tr("c.menu.play.server_binary_not_found") editor_control.disabled = false editor_connect.visible = Editor.state == Service.State.RUNNING editor_control.modulate = Color.WHITE editor_container.visible = Editor.state != Service.State.UNAVAILABLE match Editor.state: Service.State.RUNNING: editor_control.text = tr("c.menu.play.editor_stop") editor_control.modulate = Color.AQUAMARINE Service.State.TESTING: editor_control.text = tr("c.menu.play.editor_testing") editor_control.disabled = true Service.State.STARTING: editor_control.text = tr("c.menu.play.editor_starting") editor_control.disabled = true Service.State.STOPPED: editor_control.text = tr("c.menu.play.editor_start") Service.State.FAILED: editor_control.text = tr("c.menu.play.editor_failed") editor_control.modulate = Color(1, 0.4, 0.5) editor_control.tooltip_text = tr("c.menu.play.server_failed_tooltip") Service.State.UNAVAILABLE: editor_control.text = tr("c.menu.play.editor_unavailable") editor_control.disabled = true editor_control.tooltip_text = tr("c.menu.play.server_binary_not_found") func _on_uri_text_changed(new_text): connect_uri.modulate = Color.WHITE if url_regex.search(new_text) else Color.RED func _on_back_pressed(): exit() func _menu_exit(): ServerList.stop() super()