Multiplayer netcode for Godot C#
Nebula is a tick-based, server-authoritative networking framework that makes building responsive online games in Godot straightforward. It handles the hard partsβclient-side prediction, rollback, interpolation, and state synchronizationβso you can focus on your game.
- Why Nebula?
- Quick Example
- Jump In
- Features
- Installation
- Core Concepts
- Comparison
- Documentation
- Roadmap
- Community
- Contributing
Building multiplayer games is hard. Building multiplayer games that feel good in Godot is even harder. Nebula solves the core challenges:
- Instant responsiveness β Client-side prediction means players see immediate feedback, not 100ms of input lag
- Cheat resistance β Server-authoritative model where the server is always the source of truth
- Smooth visuals β Automatic interpolation for non-owned entities eliminates jitter
- Simple API β Annotate properties with
[NetProperty]and let the source generator handle the rest - Zero-allocation hot paths β Carefully optimized to avoid GC pressure; no lag spikes from garbage collection during gameplay
using Godot;
using Nebula;
public partial class Player : NetNode3D
{
public Player()
{
Network.InitializeInput<PlayerInput>();
}
// Synced to all clients, with rollback and interpolation for smooth movement
[NetProperty(Interpolate = true, Predicted = true, NotifyOnChange = true)]
public Vector3 Position { get; set; }
// Defines misprediction threshold for automagic rollback
public float PositionPredictionTolerance { get; set; } = 2f;
// Interest management - only visible to specific players
[NetProperty(InterestMask = 0x02)]
public int SecretScore { get; set; }
// Called when Position changes on clients
protected virtual void OnNetChangePosition(int tick, Vector3 oldVal, Vector3 newVal)
{
GD.Print($"Moved to {newVal}");
}
public override void _NetworkProcess(int tick)
{
// Both server AND owning client run this for prediction
ref readonly var input = ref Network.GetInput<PlayerInput>();
// Normalized inputs for easy cheat/hack prevention!
Position += new Vector3(input.MoveX, 0, input.MoveY).Normalized() * Speed;
}
}If you're eager to get started quickly, you can follow the Big Chungus tutorial to build your first game with Nebula + Godot right away.
- Tick-based synchronization β Deterministic simulation at configurable tick rates (default 30Hz)
- Server-authoritative β Single source of truth prevents cheating and ensures consistency
- Input authority β Clients control specific entities; server validates and processes inputs
- Interest management β Fine-grained control over what data each player receives
- Instant feedback β Players see results immediately, not after round-trip latency
- Automatic rollback β When predictions are wrong, Nebula corrects seamlessly
- Configurable tolerance β Tune misprediction thresholds per-property
- Interpolation β Smooth movement for entities you don't control
- Prediction + Interpolation β Owned entities predict, others interpolateβsame property, automatic switching
- Source generators β No boilerplate; annotate properties and methods
- Compile-time validation β Errors like missing handlers caught at build time
- Typed inputs β Zero-allocation input structs with full type safety
- Virtual methods β Hook into network events with overridable virtual methods
- GC-friendly design β Hot paths avoid allocations; no lag spikes from .NET garbage collection
- Struct-based serialization β Inputs and state use unmanaged structs, not heap objects
- Pooled buffers β Network buffers are reused, not allocated per-packet
- No boxing β PropertyCache union type avoids boxing value types
- Multiple worlds β Run separate game instances (dungeons, lobbies, matches) in one server process
- Flexible serialization β Built-in support for primitives, vectors, quaternions, and custom types
- ENet transport β Reliable UDP with automatic connection management
- Godot 4.5+ with .NET support
- .NET 10.0+
-
Add Nebula to your project
Copy the
addons/Nebulafolder into your project'saddonsdirectory. -
Import in your .csproj
<Project Sdk="Godot.NET.Sdk/4.5.1"> <PropertyGroup> <TargetFramework>net10.0</TargetFramework> </PropertyGroup> <Import Project="addons\Nebula\Nebula.props" /> </Project>
-
Build your project
This compiles Nebula, allowing you to enable the plugin.
-
Enable the plugin
In Godot: Project β Project Settings β Plugins β Enable "Nebula"
Inherit from NetNode, NetNode2D, or NetNode3D to create networked entities:
public partial class Enemy : NetNode3D
{
[NetProperty]
public int Health { get; set; } = 100;
}Mark properties for synchronization with [NetProperty]:
[NetProperty] // Basic sync
[NetProperty(NotifyOnChange = true)] // Triggers OnNetChange{Name}() on change
[NetProperty(Interpolate = true)] // Smooth interpolation for non-owners
[NetProperty(Predicted = true)] // Client-side prediction for owners
[NetProperty(InterestMask = 0x04)] // Only sync to players with this interest layerDefine input structs and process them on both server and client:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct PlayerInput
{
public float MoveX;
public float MoveY;
public bool Jump;
}
// In your node:
public override void _PhysicsProcess(double delta)
{
Network.SetInput(new PlayerInput
{
MoveX = Input.GetAxis("left", "right"),
MoveY = Input.GetAxis("up", "down"),
Jump = Input.IsActionPressed("jump")
});
}// Server-side spawning with input authority
var player = playerScene.Instantiate<Player>();
worldRunner.Spawn(player, inputAuthority: peer);Nebula's version of an RPC.
[NetFunction(Source = NetFunction.NetworkSources.Client, ExecuteOnCaller = false)]
public void JoinGame()
{
var player = playerScene.Instantiate<Player>();
Network.CurrentWorld.Spawn(newPlayer, inputAuthority: Network.CurrentWorld.NetFunctionContext.Caller);
}| Feature | Nebula | Godot Built-in | Netfox |
|---|---|---|---|
| Language | C# only | GDScript & C# | GDScript & C# |
| Architecture | Server-authoritative | Flexible (RPC-based) | Server-authoritative |
| Client-side Prediction | β Built-in | β Manual | β Built-in |
| Rollback/Reconciliation | β Automatic | β Manual | β Automatic |
| Interpolation | β Per-property | β MultiplayerSynchronizer | β Built-in |
| Interest Management | β Fine-grained (property-level) | β Not built-in | |
| Multiple Game Worlds | β Built-in | β Manual | β Not built-in |
| Tick-based Simulation | β Yes | β Frame-based | β Yes |
| Source Generation | β Zero boilerplate | β N/A | β N/A |
| Compile-time Validation | β Yes | β No | β No |
| Transport | ENet (UDP) | ENet, WebSocket, WebRTC | Godot's built-in |
| Learning Curve | Moderate | Low | Moderate |
Choose Nebula if you:
- Are building in C#, want maximum type safety, and performance optimization
- Need fine-grained control over what data each player sees
- Want prediction and interpolation to "just work" together
- Are building a game with instances areas, lobbies, matches (multiple worlds)
Choose Godot's built-in multiplayer if you:
- Want the simplest possible setup
- Are building a casual/turn-based game where latency isn't critical
- Prefer GDScript and minimal dependencies
Choose Netfox if you:
- Prefer GDScript but still want prediction/rollback
- Want the noray integration for easier connectivity
- Are looking for a middle-ground solution
Comprehensive documentation is available at: https://nebula.heavenlode.com
For implementation details and architecture overview, see NEBULA_OVERVIEW.mdc. This file is particularly useful for AI/vibe coding as well.
- Client-side prediction and rollback
- Property interpolation
- Interest management
- Multiple world support
- Physics rollback (blocked by Godot #2821)
- Lag compensation for projectiles/hitscan
- Discord β Chat, questions, and support
- GitHub Issues β Bug reports and feature requests
Contributions are welcome! Whether it's bug reports, feature requests, documentation improvements, or code contributions.
- Questions or ideas? Drop by the Discord or open an issue
- Want to contribute code? Please open an issue first to discuss your proposal
- Found a bug? Bug reports with reproduction steps are incredibly helpful
Built with π for the Godot community
