mirror of
https://github.com/thegatesbrowser/godot-multiplayer.git
synced 2025-10-15 08:03:33 -04:00
138 lines
3.2 KiB
GDScript
138 lines
3.2 KiB
GDScript
extends Control
|
|
|
|
signal start_server
|
|
signal connect_client(ip_address: String)
|
|
|
|
@export var hide_ui_and_connect: bool
|
|
|
|
const SAVE_FILE_PATH = "user://ip_settings.dat"
|
|
|
|
|
|
func _ready():
|
|
if Connection.is_server(): return
|
|
|
|
# Connect to connection events for error handling
|
|
var connection_node = get_node("/root/Main/Connection")
|
|
if connection_node:
|
|
connection_node.disconnected.connect(_on_connection_failed)
|
|
|
|
# Load saved IP address
|
|
_load_ip_address()
|
|
|
|
if hide_ui_and_connect:
|
|
connect_client_emit()
|
|
else:
|
|
show_ui()
|
|
|
|
|
|
func _input(event: InputEvent) -> void:
|
|
if event.is_action_pressed("quit_game"):
|
|
if $MainMenu.visible:
|
|
# If main menu is visible, quit the game
|
|
get_tree().quit()
|
|
elif $InGameUI.visible:
|
|
# If in-game UI is visible, return to main menu
|
|
# Disconnect from server/client first
|
|
if Connection.is_peer_connected:
|
|
multiplayer.multiplayer_peer.close()
|
|
show_ui()
|
|
|
|
|
|
func start_server_emit() -> void:
|
|
start_server.emit()
|
|
$MainMenu.visible = false
|
|
|
|
|
|
func connect_client_emit() -> void:
|
|
var ip_address = $MainMenu/MenuContainer/IPSection/IPInput.text.strip_edges()
|
|
if ip_address.is_empty():
|
|
ip_address = "localhost"
|
|
|
|
# Basic IP validation
|
|
if not _is_valid_ip_or_hostname(ip_address):
|
|
_show_connection_error("Invalid IP address or hostname!")
|
|
return
|
|
|
|
# Save IP address for next time
|
|
_save_ip_address(ip_address)
|
|
|
|
connect_client.emit(ip_address)
|
|
hide_ui()
|
|
|
|
|
|
func exit_game_emit() -> void:
|
|
get_tree().quit()
|
|
|
|
|
|
func hide_ui() -> void:
|
|
$MainMenu.visible = false
|
|
$InGameUI.visible = true
|
|
|
|
|
|
func show_ui() -> void:
|
|
$MainMenu.visible = true
|
|
$InGameUI.visible = false
|
|
|
|
|
|
func _is_valid_ip_or_hostname(address: String) -> bool:
|
|
if address.is_empty():
|
|
return false
|
|
|
|
# Allow localhost
|
|
if address == "localhost":
|
|
return true
|
|
|
|
# Basic hostname validation (alphanumeric, dots, hyphens)
|
|
var hostname_regex = RegEx.new()
|
|
hostname_regex.compile("^[a-zA-Z0-9.-]+$")
|
|
if hostname_regex.search(address):
|
|
return true
|
|
|
|
# Basic IP address validation
|
|
var parts = address.split(".")
|
|
if parts.size() != 4:
|
|
return false
|
|
|
|
for part in parts:
|
|
if not part.is_valid_int():
|
|
return false
|
|
var num = part.to_int()
|
|
if num < 0 or num > 255:
|
|
return false
|
|
|
|
return true
|
|
|
|
|
|
func _show_connection_error(message: String) -> void:
|
|
print("Connection error: " + message)
|
|
# Visual feedback by highlighting the IP input field
|
|
var ip_input = $MainMenu/MenuContainer/IPSection/IPInput
|
|
ip_input.modulate = Color.RED
|
|
|
|
# Reset color after 2 seconds
|
|
await get_tree().create_timer(2.0).timeout
|
|
ip_input.modulate = Color.WHITE
|
|
|
|
|
|
func _on_connection_failed() -> void:
|
|
# Show UI again if connection fails
|
|
if not $MainMenu.visible:
|
|
show_ui()
|
|
_show_connection_error("Failed to connect to server!")
|
|
|
|
|
|
func _save_ip_address(ip_address: String) -> void:
|
|
var file = FileAccess.open(SAVE_FILE_PATH, FileAccess.WRITE)
|
|
if file:
|
|
file.store_string(ip_address)
|
|
file.close()
|
|
|
|
|
|
func _load_ip_address() -> void:
|
|
if FileAccess.file_exists(SAVE_FILE_PATH):
|
|
var file = FileAccess.open(SAVE_FILE_PATH, FileAccess.READ)
|
|
if file:
|
|
var saved_ip = file.get_as_text().strip_edges()
|
|
file.close()
|
|
if not saved_ip.is_empty():
|
|
$MainMenu/MenuContainer/IPSection/IPInput.text = saved_ip
|