extends Node2D @onready var line_edit: LineEdit = $LineEdit @onready var synchronizer: MultiplayerSynchronizer = $MultiplayerSynchronizer var server_ip: String = "127.0.0.1" var port_number: int = 8443 var secret_key: String = "ChangeMe123!" @export var clipboard_text: String = "Waiting for connection..." var is_connected_to_network: bool = false var is_server_mode: bool = false # Reconnection and Rate-Limiting Tracker variables var is_reconnecting: bool = false var retry_timer: float = 0.0 const RETRY_INTERVAL: float = 10.0 # Reconnect attempt frequency in seconds var last_log_time: float = 0.0 const LOG_LIMIT_INTERVAL: float = 10.0 # Suppresses error logs within this timeframe const CONFIG_PATH = "user://network_settings.cfg" var ip_input: LineEdit var port_input: LineEdit var key_input: LineEdit func _ready() -> void: line_edit.position = Vector2(50, 195) line_edit.custom_minimum_size = Vector2(400, 40) line_edit.placeholder_text = "Type and press Enter to securely sync..." line_edit.text_submitted.connect(_on_text_submitted) # Connect Godot's network lifecycle signals multiplayer.connected_to_server.connect(_on_connected_ok) multiplayer.connection_failed.connect(_on_connection_failed) multiplayer.server_disconnected.connect(_on_disconnected) multiplayer.peer_connected.connect(_on_peer_connected) multiplayer.peer_disconnected.connect(_on_peer_disconnected) create_network_interface() var has_config = load_network_config() if has_config: print("[Autoconnect] Secure config file loaded. Instantiating auto-client...") start_client() else: print("[Autoconnect] Initial default config file created.") func _process(delta: float) -> void: # 1. Manage Clipboard Synchronization var current_sys_clip = DisplayServer.clipboard_get() if current_sys_clip != clipboard_text: if multiplayer.is_server() or line_edit.has_focus() or current_sys_clip != "": var encrypted_payload = encrypt_string(current_sys_clip) rpc("receive_secure_clipboard", encrypted_payload) # 2. Manage Automatic Client Reconnection Loop if is_reconnecting and not is_server_mode: retry_timer += delta if retry_timer >= RETRY_INTERVAL: retry_timer = 0.0 rate_limited_log("[Network Recovery] 10 seconds elapsed. Attempting background reconnect...") silent_client_reconnect() @rpc("any_peer", "call_local", "reliable") func receive_secure_clipboard(encrypted_data: PackedByteArray) -> void: var decrypted_text = decrypt_string(encrypted_data) clipboard_text = decrypted_text DisplayServer.clipboard_set(decrypted_text) queue_redraw() func _on_text_submitted(new_text: String) -> void: var encrypted_payload = encrypt_string(new_text) rpc("receive_secure_clipboard", encrypted_payload) line_edit.text = "" func _draw() -> void: draw_rect(Rect2(50, 270, 500, 80), Color(0.15, 0.15, 0.15, 1.0)) var system_font = ThemeDB.fallback_font var draw_position = Vector2(60, 320) var network_status = "Mode: Server" if is_server_mode else "Mode: Client" if multiplayer.multiplayer_peer == null: network_status = "Mode: Offline" elif is_reconnecting and not is_server_mode: network_status = "Mode: Client (Reconnecting...)" var current_text_color = Color.GREEN if is_connected_to_network else Color.YELLOW draw_string(system_font, draw_position, network_status + " | Secure Clip: " + clipboard_text, HORIZONTAL_ALIGNMENT_LEFT, -1, 18, current_text_color) # ========================================== # MULTIPLAYER SIGNAL & RECONNECT CALLBACKS # ========================================== func _on_connected_ok() -> void: is_connected_to_network = true is_reconnecting = false retry_timer = 0.0 print("[Network Status] Connection successful. Text changed to GREEN.") queue_redraw() func _on_connection_failed() -> void: is_connected_to_network = false # Trigger the reconnection routine cleanly if we aren't already hunting a link if not is_reconnecting: is_reconnecting = true retry_timer = 0.0 rate_limited_log("[Network Error] Initial handshake failed. Suppressing cascade logs; retrying in 10s.") queue_redraw() func _on_disconnected() -> void: is_connected_to_network = false is_reconnecting = true retry_timer = 0.0 print("[Network Status] Disconnected from host. Text changed to YELLOW. Starting 10s retry cadence.") queue_redraw() func _on_peer_connected(_id: int) -> void: if is_server_mode: is_connected_to_network = true queue_redraw() func _on_peer_disconnected(_id: int) -> void: if is_server_mode and multiplayer.get_peers().size() == 0: is_connected_to_network = false queue_redraw() func silent_client_reconnect() -> void: # Explicitly clean up old hanging connection references before attempting a new socket allocation multiplayer.multiplayer_peer = null var peer = ENetMultiplayerPeer.new() var error = peer.create_client(server_ip, port_number) if error == OK: multiplayer.multiplayer_peer = peer else: rate_limited_log("[Network Error] Peer creation failed silently: " + str(error)) # Custom logger to ensure your output terminal stays pristine instead of printing millions of loops func rate_limited_log(message: String) -> void: var current_time = Time.get_ticks_msec() / 1000.0 if current_time - last_log_time >= LOG_LIMIT_INTERVAL: print(message) last_log_time = current_time # ========================================== # AES-256 ENCRYPTION & DECRYPTION LOGIC # ========================================== func get_hashed_key() -> PackedByteArray: var ctx = HashingContext.new() ctx.start(HashingContext.HASH_SHA256) ctx.update(secret_key.to_utf8_buffer()) return ctx.finish() func encrypt_string(plain_text: String) -> PackedByteArray: var aes = AESContext.new() var key = get_hashed_key() var data_bytes = plain_text.to_utf8_buffer() var padding_needed = 16 - (data_bytes.size() % 16) for i in range(padding_needed): data_bytes.append(padding_needed) aes.start(AESContext.MODE_ECB_ENCRYPT, key) var encrypted = aes.update(data_bytes) aes.finish() return encrypted func decrypt_string(encrypted_bytes: PackedByteArray) -> String: if encrypted_bytes.is_empty(): return "" var aes = AESContext.new() var key = get_hashed_key() aes.start(AESContext.MODE_ECB_DECRYPT, key) var decrypted = aes.update(encrypted_bytes) aes.finish() if decrypted.size() > 0: var padding_count = decrypted[decrypted.size() - 1] if padding_count > 0 and padding_count <= 16: decrypted = decrypted.slice(0, decrypted.size() - padding_count) return decrypted.get_string_from_utf8() # ========================================== # CONFIGURATION FILE SAVE & LOAD LOGIC # ========================================== func load_network_config() -> bool: var config = ConfigFile.new() var error = config.load(CONFIG_PATH) if error == OK: server_ip = config.get_value("Network", "server_ip", "127.0.0.1") port_number = config.get_value("Network", "port_number", 8443) secret_key = config.get_value("Network", "secret_key", "ChangeMe123!") if ip_input and port_input and key_input: ip_input.text = server_ip port_input.text = str(port_number) key_input.text = secret_key return true else: save_network_config("127.0.0.1", 8443, "ChangeMe123!") return false func save_network_config(ip: String, port: int, key: String) -> void: var config = ConfigFile.new() config.set_value("Network", "server_ip", ip) config.set_value("Network", "port_number", port) config.set_value("Network", "secret_key", key) if config.save(CONFIG_PATH) == OK: server_ip = ip port_number = port secret_key = key # ========================================== # INTERFACE IMPLEMENTATION # ========================================== func create_network_interface() -> void: var btn_server = Button.new() btn_server.text = "Start Server" btn_server.position = Vector2(50, 40) btn_server.pressed.connect(start_server) add_child(btn_server) var btn_client = Button.new() btn_client.text = "Connect Client" btn_client.position = Vector2(160, 40) btn_client.pressed.connect(start_client) add_child(btn_client) ip_input = LineEdit.new() ip_input.text = server_ip ip_input.placeholder_text = "Target Server IP" ip_input.position = Vector2(50, 100) ip_input.custom_minimum_size = Vector2(180, 35) add_child(ip_input) port_input = LineEdit.new() port_input.text = str(port_number) port_input.placeholder_text = "Port" port_input.position = Vector2(250, 100) port_input.custom_minimum_size = Vector2(100, 35) add_child(port_input) key_input = LineEdit.new() key_input.text = secret_key key_input.secret = true key_input.placeholder_text = "Shared Secret Key Passphrase" key_input.position = Vector2(50, 150) key_input.custom_minimum_size = Vector2(300, 35) add_child(key_input) key_input = LineEdit.new() key_input.text = secret_key key_input.secret = true key_input.placeholder_text = "Shared Secret Key Passphrase" key_input.position = Vector2(50, 150) key_input.custom_minimum_size = Vector2(300, 35) add_child(key_input) var btn_generate = Button.new() btn_generate.text = "New Key" btn_generate.position = Vector2(358, 150) btn_generate.size.y = 34 btn_generate.pressed.connect(_on_generate_pressed) add_child(btn_generate) var btn_copy = Button.new() btn_copy.text = "Copy Key" btn_copy.position = Vector2(440, 150) btn_copy.size.y = 34 btn_copy.pressed.connect(_on_copy_pressed) add_child(btn_copy) func start_server() -> void: is_connected_to_network = false is_reconnecting = false is_server_mode = true var active_port = int(port_input.text) save_network_config(ip_input.text, active_port, key_input.text) var peer = ENetMultiplayerPeer.new() if peer.create_server(active_port) != OK: return multiplayer.multiplayer_peer = peer print("[Network] Server active on port: ", active_port) queue_redraw() func start_client() -> void: is_connected_to_network = false is_server_mode = false var active_ip = ip_input.text var active_port = int(port_input.text) save_network_config(active_ip, active_port, key_input.text) var peer = ENetMultiplayerPeer.new() var error = peer.create_client(active_ip, active_port) if error == OK: multiplayer.multiplayer_peer = peer is_reconnecting = true # Instantly engage our automated monitoring pipeline queue_redraw() func _on_generate_pressed() -> void: key_input.text = generate_random_key(16) func _on_copy_pressed() -> void: if key_input.text.is_empty(): return DisplayServer.clipboard_set(key_input.text) print("Copied to clipboard!") func generate_random_key(length: int) -> String: var chars: String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" var result: String = "" for i in range(length): result += chars[randi() % chars.length()] return result