Back to the blog

Release

Nebula 0.1.0-beta.2

This release follows beta.1. A Portal now connects two scopes, and bodies, shots, and cameras work across it. A world can be as large as a planet without losing precision, and a player can drive a server-owned vehicle with no input delay. A Linux server can be a release build or use IL2CPP. This release replaces InstanceBoundary, so projects that use it need a port, and clients built for beta.1 must be rebuilt.

Connect two scopes with a portal

A scope is a separate space in your world, such as an apartment interior or a dungeon. Until now, InstanceBoundary was the only way between a scope and the world. It prepared a crossing for each player who came near, held the player at the door until the destination answered, and loaded the whole interior inside the worker's tick.

Portal replaces it. A portal is a component at a face, with an opening called the aperture and a far side that is either a template (one far scope per party) or a fixed scope. Your game calls Open(party, members) and Close(party). Each party has a link whose state is Closed, Preparing, Open, or Closing, and whose Wait value always says why the link is not open yet.

  • Any entity that is spawned and not pinned crosses an open link on its own: a player, a crate, a projectile, an NPC, or a vehicle with its riders. A fast body is tested on the step to come, so a projectile never simulates a step behind the face.
  • CanEnter and the new CanLeave let your game decide what may cross in each direction.
  • The interior's content loads asynchronously, and the link reports FarWorkerContent while it waits.
  • Linked scopes stay on one worker, and a crossing between workers is one handover.
  • A link can hold for CloseHoldSeconds so that a door closes over a far side that is still drawn.
Create private instances

Collide, cast, and look through a portal

Each scope is its own physics scene, so a shot at a door used to hit the door or nothing. Across an open portal:

  • A body whose extent touches the opening gets a kinematic proxy in the other scope, so it collides with what is on the other side before it crosses.
  • PortalQueries offers Raycast, sweeps, and overlaps that continue through an open link. Raycast can also report where the cast went through (PortalCrossing). Lag-compensated rewind covers the far scope.
  • A client that may look through a portal draws the other side in its own pose, and several scopes can be drawn at once. Each drawn scope can have its own rendering layer.
  • Portals.Map, Portals.TryMap, and Portals.Turn carry a pose or a direction between two scopes, in double precision.

A portal can stand in a chunk of a planet, and a body can cross into a scope whose container simulates in a physics frame.

Build planet-sized worlds

A physics frame is a moving or turning space of its own, such as a ship or a planet. Several changes make large frames work at distances where a 32-bit float is meters apart.

  • A scope can host chunk grids in a container, with NebulaChunkedWorld.ActivateHostedGrid. A planet that is a carrier can stream its ground in chunks around players, and a game with a different shape, such as a cube sphere, supplies its own IChunkGridGeometry.
  • You can place an entity, or commit a transfer, at a pose in a frame's own coordinates, composed in double. An entity placed on a pad of a planet 300,000 km out lands within a millimeter of it.
  • A client draws a large frame about a render origin near the camera, so ground 200 km from a planet's center no longer shakes as the planet turns, and a client predicts far out about the same origin its worker uses.
  • A far relevance tier lets a large or important entity be seen as a marker far beyond the interest radius: a ship 50 km away in orbit can be a dot the player sees and targets. Set FarRelevanceRadius on the entity and read NebulaClient.FarEntities.
  • Container.FrameApproachMargin lets a client outside a planet's box see what stands on it. It is off by default and set per container.
  • A container with a very large carried box no longer stalls the worker's broad phase, which a planet-sized frame did.
Physics frames
Interest management

Drive a server-owned vehicle with no input delay

A boat or a car that no player owns used to answer the wheel after a round trip plus the interpolation delay: 140 ms on a 30 ms link and 273 ms on a 150 ms link in our measurements, and a driver steering by what they saw overshot the heading they wanted.

Call NetworkIdentity.SetDriver(clientId) to give the wheel to a client. That client predicts the vehicle every tick and is reconciled to the worker, as it is for its own pawn. A driver whose input stops for 30 ticks loses the wheel, and the driver travels with a handover. The vehicle's model must be deterministic and kinematic; a NetworkRigidbody vehicle is not predicted. A driven vehicle sample shows the code.

Prediction and reconciliation

Smooth entities that update slowly

A client drew every remote entity three ticks behind the newest state. An entity whose state arrived further apart than that (for example, one updated every six ticks, or one in a slow distance tier) was held still, extrapolated, and pulled back. A crowd 50 m away stood and jumped twice a second.

The client now measures how far apart each entity's states arrive and draws that entity by its own gap later, up to NebulaConfig.SlowUpdateMaxDelayTicks (30; 0 turns it off). An entity sent every tick or two gets no extra delay, so players and nearby vehicles are drawn as before.

Build, measure, and test servers

  • Release and IL2CPP builds. A Linux server build was always a Mono development build. NebulaConfig now has ServerBuildDevelopment and ServerBuildScriptingBackend, and nebula build --linux and nebula deploy take --release-build, --development-build, --il2cpp, and --mono for one build. A project that changes nothing builds as before.
  • Worker memory and frame time. Each worker reports resident, native, and managed memory in nebula status, the dashboard, and its profile log line. The profile line also splits the whole Unity frame into physics, FixedUpdate, Update, and LateUpdate time, and NebulaProfiler.Section times a section of your own.
  • Load tests that behave like players. nebula-loadgen clients can wander, follow a path, travel between scopes, send RPCs, and churn, from a seeded, weighted mix. A game adds its own behaviors in a separate assembly with --plugin.
  • Multiplayer Play Mode. Exactly one virtual player hosts the server, and every other virtual player joins as its own client. The server starts without anyone ticking a virtual player.
  • Chunk ring margin. ChunkedWorldServerRingMargin sets how many chunks beyond NearCells a worker leases around each pawn. The default of 1 keeps today's ring.
Load testing a gateway fleet
Configure Nebula

Things to know

  • The scene render origin is on by default. When the camera is more than 1,024 m from Unity's origin, a client moves every loaded scene's root objects before drawing and restores them afterward. Static-batched meshes, world-space particles, trails, and light probes are not moved. A game with a large map and none of the new frame features can set SceneRenderOrigin.Enabled to false. We are considering making it opt-in.
  • Slow entities and lag compensation. A client draws a slowly updated entity up to half a second behind, but a lag-compensated shot still claims the client's global render tick, so a hit on such an entity can be checked against a pose that is not the one the shooter saw. If you use lag compensation with UpdateInterval or distance tiers, set SlowUpdateMaxDelayTicks to 0 for now.
  • The local save file is version 3. A game that runs on the local store and moves back to beta.1 will find the file unreadable, ignore it, and overwrite it on the next save. Keep a backup of world.bin before you try beta.2.
  • IL2CPP stripping. Nebula finds RPCs, network variables, and serializable types by reflection, so keep your own assemblies with a link.xml beside your scripts. We have not yet tested a stripped IL2CPP build.
  • Portals, instance scenes, and physics frames use 3D physics only.

Upgrade to beta.2

0.1.0-beta.2 uses wire protocol 28, and a gateway admits only clients of protocol 28. It refuses older clients, including those built for beta.1, with ProtocolUnsupported. Rebuild your clients against this version. Gateways and workers of one mesh must still run the same build.

InstanceBoundary, InstanceCrossingState, ObservePublic, PublicView, and ObserveHost are removed, with no compatibility shim. Port each boundary to a Portal. A template and its key carry over, so saved instances are still found. The package changelog lists what replaces each setting.

Create private instances
Replace gateways and workers
0.1.0-beta.2 release