extends Node var synchronizer: MultiplayerSynchronizer # Declare variable to keep reference # Signal emitted when network status or clipboard text changes signal status_changed(text: String) var server_ip: String = "127.0.0.1" var port_number: int = 8443 var secret_key: String = "ChangeMe123!" 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 var last_log_time: float = 0.0 const LOG_LIMIT_INTERVAL: float = 10.0 const CONFIG_PATH = "user://network_settings.cfg" func _ready() -> void: synchronizer = MultiplayerSynchronizer.new() #synchronizer.update_rate = 30.0 add_child(synchronizer) load_network_config() # 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) update_status("DISCONNECTED | Secure Clip: Empty") 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 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) update_status("%s | Secure Clip: %s" % [get_network_mode_text(), clipboard_text]) func start_server(active_port: int) -> void: is_connected_to_network = false is_reconnecting = false is_server_mode = true var peer = ENetMultiplayerPeer.new() if peer.create_server(active_port) == OK: multiplayer.multiplayer_peer = peer save_network_config(server_ip, active_port, secret_key) print("[Network] Server active on port: ", active_port) else: rate_limited_log("[Network Error] Failed to start server.") func start_client(active_ip: String, active_port: int) -> void: is_connected_to_network = false is_server_mode = false var peer = ENetMultiplayerPeer.new() var error = peer.create_client(active_ip, active_port) if error == OK: multiplayer.multiplayer_peer = peer save_network_config(active_ip, active_port, secret_key) is_reconnecting = true else: rate_limited_log("[Network Error] Failed to create client. Error: %d" % error) update_status("%s | Secure Clip: %s" % [get_network_mode_text(), clipboard_text]) # ========================================== # 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.") update_status("%s | Secure Clip: %s" % [get_network_mode_text(), clipboard_text]) func _on_connection_failed() -> void: is_connected_to_network = false 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.") update_status("%s | Secure Clip: %s" % [get_network_mode_text(), clipboard_text]) 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.") update_status("%s | Secure Clip: %s" % [get_network_mode_text(), clipboard_text]) func _on_peer_connected(_id: int) -> void: if is_server_mode: is_connected_to_network = true update_status("%s | Secure Clip: %s" % [get_network_mode_text(), clipboard_text]) func _on_peer_disconnected(_id: int) -> void: if is_server_mode and multiplayer.get_peers().size() == 0: is_connected_to_network = false update_status("%s | Secure Clip: %s" % [get_network_mode_text(), clipboard_text]) func silent_client_reconnect() -> void: 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)) # ========================================== # 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 & UTILITIES # ========================================== 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!") 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 func get_network_mode_text() -> String: var mode_text: String = "Mode: Server" if is_server_mode else "Mode: Client" if multiplayer.multiplayer_peer == null: mode_text = "Mode: Offline" elif is_reconnecting and not is_server_mode: mode_text = "Mode: Client (Reconnecting...)" return mode_text func update_status(text: String) -> void: status_changed.emit(text) 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 func generate_random_key(length: int) -> String: randomize() var chars: String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" var result: String = "" for i in range(length): result += chars[randi() % chars.length()] return result func copy_key_to_clipboard() -> void: DisplayServer.clipboard_set(secret_key) print("Copied to clipboard!")