Clone-and-play multiplayer for Godot. Drop in a MimicSync node and make your scenes network-aware, with high-level nodes for connection and gameplay.
Mimic Multiplayer is currently a small connection and configuration addon for Godot 4. It manages a Mimic autoload, exposes typed Project Settings, starts ENet and WebSocket peers, reserves MimicConnector for connection UI, and provides MimicSync for scene-level authoring.
This project is intentionally smaller than full networking frameworks. Mimic is for developers who want a lightweight helper around Godot's built-in high-level multiplayer API, not a prediction, rollback, interpolation, lag compensation, relay, or full gameplay framework.
- Current Scope
- Requirements
- Installation
- Configure Connection Defaults
- Start Networking From Code
- Listen For Connection Events
- Use MimicConnector
- Use MimicSync
- Logging
- Mimic Or NetFox?
- Current Limitations
- Minimal Local Test
- Editor Multi-Instance Testing
Mimic keeps the current project shape explicit instead of carrying compatibility layers for older names, behavior, files, scenes, or configuration. After updating Mimic, review your code, scenes, and Project Settings > Mimic Multiplayer against this README and update them to the current model.
Mimic is focused on connection setup, project configuration, and a stable visible component shape.
Working now:
- Plugin-managed
Mimicsingleton. - Project Settings for connection defaults.
- ENet server/client startup.
- WebSocket server/client startup.
- Offline state and an Offline transport selection that intentionally does not start a network peer.
- WebRTC transport selection reserved for future signaling support, currently unsupported.
- Optional UPnP port forwarding.
- Runtime connection state, status helpers, and lifecycle signals.
- Project Settings auto-connect for startup scenes and local multi-instance testing.
MimicConnectorplaceholder for future connection form UI.MimicSynccomponent that subclasses Godot'sMultiplayerSynchronizer.
Not ready yet:
- Automatic dynamic spawn/despawn replication.
- Late-join spawn replay or spawn-state transfer from
SceneReplicationConfigspawn properties. - Built-in connector UI controls.
- Prediction, rollback, interpolation, lag compensation, matchmaking, relay services, or raw packet protocols.
- Godot 4.6 or newer.
- A project using Godot's high-level multiplayer API.
Copy the addon into your project:
res://addons/mimic/
The scripts developers usually add to scenes live in:
res://addons/mimic/nodes/
Enable the plugin:
- Open Project > Project Settings.
- Go to the Plugins tab.
- Enable
Mimic.
When enabled, the plugin adds a Mimic singleton so your scripts can call Mimic.start_server(), Mimic.start_client(), and related helpers.
Open Project > Project Settings and search for Mimic Multiplayer.
Godot does not currently expose a description field for custom Project Settings added through ProjectSettings.add_property_info(), so Mimic documents setting meanings here instead of relying on tooltips.
Connection:
mimic_multiplayer/connection/transport: Offline, ENet, WebSocket, or WebRTC (Unsupported)
mimic_multiplayer/connection/editor_auto_connect: Disabled, Server Then Client, Client, or Server
mimic_multiplayer/connection/address: Client address, default 127.0.0.1
mimic_multiplayer/connection/port: Server/client port, default 15490
mimic_multiplayer/connection/max_clients: Max ENet server clients, default 32
WebSocket:
mimic_multiplayer/websocket/client_use_tls: Use wss:// when joining a WebSocket server, default false
Port Forwarding:
mimic_multiplayer/port_forwarding/enabled: Try UPnP port forwarding when hosting, default false
Advanced settings are hidden unless Advanced Settings is enabled in Project Settings.
Advanced connection settings:
mimic_multiplayer/connection/bind_address: Local bind address for server sockets and ENet client local binding, default *
Advanced ENet settings:
mimic_multiplayer/enet/channel_count: ENet channel count, default 0
mimic_multiplayer/enet/in_bandwidth: Incoming bandwidth limit in bytes per second, 0 for unlimited
mimic_multiplayer/enet/out_bandwidth: Outgoing bandwidth limit in bytes per second, 0 for unlimited
mimic_multiplayer/enet/client_local_port: Local ENet client port, 0 for ephemeral
Advanced WebSocket settings:
mimic_multiplayer/websocket/path: Optional path appended to WebSocket client URLs, default empty
mimic_multiplayer/websocket/handshake_timeout: WebSocket handshake timeout in seconds, default 3.0
Advanced port forwarding settings:
mimic_multiplayer/port_forwarding/delete_mapping_on_stop: Delete owned UPnP mappings when networking stops, default true
mimic_multiplayer/port_forwarding/query_external_address: Query the gateway external address after mapping, default true
mimic_multiplayer/port_forwarding/protocol: TCP/UDP mapping protocol selection, default Transport Default
mimic_multiplayer/port_forwarding/duration: UPnP mapping lease duration in seconds, default 7200; 0 requests permanent
mimic_multiplayer/port_forwarding/discover_timeout_ms: UPnP discovery timeout in milliseconds, default 2000
mimic_multiplayer/port_forwarding/discover_ttl: UPnP discovery time-to-live hop count, default 2
Debug:
mimic_multiplayer/debug/log_level: All, Warning, Error, or None, default Warning
UPnP discovery and port mapping run in a background thread so hosting does not block the main thread while the router responds.
Port forwarding depends on the user's router, network, and platform. Treat it as a convenience for local testing, not a guaranteed matchmaking or NAT traversal solution.
Host a server using the Project Settings defaults:
var error := Mimic.start_server()
if error != OK:
MimicLog.error("Failed to start server: %s" % error_string(error))Join a server using the Project Settings defaults:
var error := Mimic.start_client()
if error != OK:
MimicLog.error("Failed to start client: %s" % error_string(error))Override the address or port for a single call:
Mimic.start_server(9000)
Mimic.start_client("192.168.1.25", 9000)Stop networking:
Mimic.stop()Cancel an in-progress client connection:
Mimic.cancel_connection()Start as server if possible, otherwise connect as a client:
Mimic.start_server_or_client()This is useful for quick local multi-instance testing. The first running instance usually binds the port and becomes server; later instances fail to bind and fall back to client.
Project Settings auto-connect only runs when Godot has the editor feature tag, so exported builds should start connections from game code or UI.
Connect to Mimic signals from any script:
func _ready() -> void:
Mimic.state_changed.connect(_on_state_changed)
Mimic.start_failed.connect(_on_start_failed)
Mimic.server_started.connect(_on_server_started)
Mimic.client_started.connect(_on_client_started)
Mimic.client_connected.connect(_on_client_connected)
Mimic.client_connection_failed.connect(_on_client_connection_failed)
Mimic.server_disconnected.connect(_on_server_disconnected)
Mimic.peer_connected.connect(_on_peer_connected)
Mimic.peer_disconnected.connect(_on_peer_disconnected)
Mimic.stopped.connect(_on_stopped)
Mimic.port_mapping_finished.connect(_on_port_mapping_finished)
func _on_state_changed(state: Mimic.NetworkState, previous_state: Mimic.NetworkState) -> void:
MimicLog.log("State changed from", previous_state, "to", state)
func _on_start_failed(_attempted_state: Mimic.NetworkState, error: Error, message: String) -> void:
MimicLog.warning("%s (%s)" % [message, error_string(error)])
func _on_server_started(port: int) -> void:
MimicLog.log("Server listening on", port)
func _on_client_started(address: String, port: int) -> void:
MimicLog.log("Connecting to %s:%d" % [address, port])
func _on_client_connected() -> void:
MimicLog.log("Connected")
func _on_client_connection_failed(message: String) -> void:
MimicLog.warning(message)
func _on_server_disconnected() -> void:
MimicLog.log("Disconnected from server")
func _on_peer_connected(peer_id: int) -> void:
MimicLog.log("Peer connected:", peer_id)
func _on_peer_disconnected(peer_id: int) -> void:
MimicLog.log("Peer disconnected:", peer_id)
func _on_stopped() -> void:
MimicLog.log("Networking stopped")
func _on_port_mapping_finished(result: UPNP.UPNPResult, external_address: String) -> void:
MimicLog.log("Port mapping result:", result, external_address)Useful state helpers:
Mimic.is_offline()
Mimic.is_connecting()
Mimic.is_server()
Mimic.is_client()
Mimic.get_state()
Mimic.get_local_peer_id()
Mimic.get_peer_ids()
Mimic.get_external_address()MimicConnector is reserved for a future drag-and-drop connection form with an IP field, port field, Host button, Join button, and Stop button. It does not start networking on its own.
For now, wire your own UI directly to the Mimic singleton:
func _on_host_pressed() -> void:
Mimic.start_server()
func _on_join_pressed() -> void:
Mimic.start_client()
func _on_stop_pressed() -> void:
Mimic.stop()Use Project Settings for editor-only startup auto-connect:
mimic_multiplayer/connection/editor_auto_connect = Disabled
mimic_multiplayer/connection/editor_auto_connect = Server Then Client
mimic_multiplayer/connection/editor_auto_connect = Client
mimic_multiplayer/connection/editor_auto_connect = Server
Add a MimicSync node under a scene/entity you want to prepare for synchronization.
MimicSync is a MultiplayerSynchronizer, so configure it like Godot's native synchronizer:
- Add
MimicSyncas a child of the node you want to sync. - Set or confirm its
root_path. - Assign a
SceneReplicationConfig. - Choose the properties Godot should replicate.
Current note: runtime property replication remains Godot's native MultiplayerSynchronizer behavior. Mimic does not yet replace MultiplayerSpawner or perform automatic dynamic spawning in the current connection MVP.
Mimic logs connection attempts, connection results, peer changes, stop events, and UPnP results.
Set log output in Project Settings:
mimic_multiplayer/debug/log_level: All, Warning, Error, None
Example log line:
[05-29 22:14:03] [2 mimic._on_connected_to_server] Connected to server.
In the editor Output panel the bracketed timestamp and source tag are dimmed on informational log lines so the message stands out. The color is applied with Godot's print_rich() BBCode, which the editor renders and strips from saved log files, so log files stay plain text. If an informational log message contains [, Mimic uses plain output for that line so literal BBCode-like text stays unchanged in both the editor and saved logs.
The number inside the source tag appears only in editor-launched runs, and only when a connected multiplayer peer has a valid local peer ID. The source tag falls back to Mimic when GDScript call stacks are unavailable; release exports need debug/settings/gdscript/always_track_call_stacks enabled to include caller names.
Use MimicLog.log(), MimicLog.warning(), and MimicLog.error() for messages that should respect mimic_multiplayer/debug/log_level. Use MimicLog.log_forced(), MimicLog.warning_forced(), and MimicLog.error_forced() for diagnostics that should always output logs.
To route Mimic output yourself, set MimicLog.output_handler. The handler receives the plain formatted line without editor color markup:
var mimic_log_messages: PackedStringArray = []
MimicLog.output_handler = func(level: MimicLog.Level, message: String) -> void:
mimic_log_messages.append(message)Mimic and NetFox are not trying to be the same thing.
Use Mimic if you want:
- A smaller helper around Godot's built-in high-level multiplayer API.
- Basic connection setup through project settings.
- A lightweight host/join/stop workflow.
- A future path toward simpler
MultiplayerSpawnerandMultiplayerSynchronizerauthoring. - Fewer systems to learn before prototyping.
Use NetFox if you need:
- Consistent network timing.
- Rollback.
- Client-side prediction.
- Server reconciliation.
- Interpolation helpers.
- Lag compensation.
- Noray integration.
- A more complete networking framework for responsive online games.
NetFox is the better fit when your game needs advanced netcode features. Mimic is intentionally smaller and aims to make the common Godot multiplayer setup easier rather than replacing a full-featured framework.
- WebRTC is listed but not implemented.
- ENet is not available in web exports; use WebSocket for browser clients.
- WebSocket server TLS is not configured by Mimic yet; terminate
wss://at a proxy. - WebSocket subprotocols and custom handshake headers are not exposed yet.
- Mimic does not yet perform dynamic spawn/despawn replication.
- Mimic does not yet package spawn properties from
SceneReplicationConfig. - Mimic does not yet provide built-in UI controls.
- Mimic does not provide prediction, rollback, interpolation, lag compensation, matchmaking, or relay services.
- Set
mimic_multiplayer/connection/transporttoENet. - Set
mimic_multiplayer/connection/editor_auto_connecttoServer Then Client. - Set
mimic_multiplayer/connection/addressto127.0.0.1. - Set
mimic_multiplayer/connection/portto15490. - Run two game instances.
Expected result:
- The first instance starts as server.
- The second instance joins as client.
- Connection events appear in the Godot output.
Godot can launch multiple local game instances from the editor:
- Open Debug > Customize Run Instances...
- Set the number of instances you want.
- Run the project.
For easier window tiling, add res://addons/mimic/testing/mimic_run_instance_grid.gd as an AutoLoad named MimicRunInstanceGrid.
Also disable Game > Embedding Options > Embed Game on Next Play so each instance opens in its own window. When multiple editor-launched instances start together, MimicRunInstanceGrid arranges them into a grid and appends their instance index to the window title.