Jump to content

OpenSimulator Internals/Code Map/Scene

From Open Simulator Technical Help

OpenSimulator Internals/Code Map/Scene

[edit]

Overview

[edit]

Scene is the central object of the region simulator. One Scene instance exists per region. It holds all in-world state and coordinates between the physics engine, script engine, client connections, storage, and grid services.

Class hierarchy:

Scene → SceneBase → RegionApplicationBase

Source: OpenSim/Region/Framework/Scenes/Scene.cs

Scene.cs is a partial class -- additional methods are in other files in the same directory.


Constructor

[edit]

Two constructors:

Scene(RegionInfo regInfo)  -- base constructor
Scene(RegionInfo, AgentCircuitManager, ISimulationDataService, IEstateDataService, IConfigSource, string version)  -- full constructor

Base constructor:

  1. Creates SceneGraph (holds all entities and physics)
  2. Hooks SceneGraph.UnRecoverableError -- triggers RestartNow() on physics crash
  3. Sets defaults: PhysicalPrims=true, CollidablePrims=true, PhysicsEnabled=true, AllowAvatarCrossing=true, PeriodicBackup=true
  4. Creates EventManager
  5. Creates ScenePermissions

Full constructor (called from OpenSimBase.CreateScene()):

  1. Loads RegionSettings from SimulationDataService -- sets default terrain textures if missing, copies classic textures to PBR slots if PBR not set
  2. Loads EstateSettings from EstateDataService
  3. Creates SceneGridInfo from config and ServerURI
  4. Hooks EventManager land object events to SimulationDataService storage
  5. Reads [Startup] config -- draw distances, prim limits, physics flags, script engine, persistence timings, frame rate, viewer allow/deny lists, coarse location update interval, terrain update interval, backup interval
  6. Reads [EntityTransfer] config -- AllowAvatarCrossing, DisableObjectTransfer
  7. Reads [InterestManagement] config -- update prioritization scheme, reprioritization settings, object culling by distance
  8. Creates SimStatsReporter
  9. Starts timer watchdog

Service References

[edit]

All grid services are accessed through lazy-loaded properties backed by RequestModuleInterface<T>(). They throw if the service is not available (except EstateDataServiceSafe which returns null).

Property Interface Notes
AssetService IAssetService throws if missing
InventoryService IInventoryService throws if missing, with detailed error message about config
GridService IGridService throws if missing
SimulationDataService ISimulationDataService throws if missing
EstateDataService IEstateDataService throws if missing
UserAccountService IUserAccountService null if missing
PresenceService IPresenceService null if missing
AuthenticationService IAuthenticationService null if missing
AvatarService IAvatarService null if missing
GridUserService IGridUserService null if missing
AgentPreferencesService IAgentPreferencesService null if missing
AuthorizationService IAuthorizationService null if missing
LibraryService ILibraryService null if missing
SimulationService ISimulationService null if missing

Module references (set by SetModuleInterfaces() after modules load):

Property Interface
EntityTransferModule IEntityTransferModule -- teleport and region crossing
AttachmentsModule IAttachmentsModule
AgentTransactionsModule IAgentAssetTransactions
UserManagementModule IUserManagement
AvatarFactory IAvatarFactoryModule
CapsModule ICapabilitiesModule

The Main Loop (Heartbeat)

[edit]

The scene runs one thread: the Heartbeat thread. Started by Start():

Heartbeat()
  TriggerOnRegionStarted()
  Update(1)  -- first frame, watchdog not yet active
  Watchdog alarm enabled
  Update(-1)  -- runs until shutdown

Update() loop runs once per frame:

Per frame (every frame unless noted):

  1. CheckTerrainUpdates() -- every 4 frames
  2. UpdateTerrain() -- every m_update_terrain frames (default 1000)
  3. UpdatePreparePhysics() -- physics pre-step
  4. SendCoarseLocations() -- every 5 frames, async via thread pool
  5. UpdatePhysics(FrameTime) -- main physics step, returns physicsFPS
  6. CheckAtTargets() -- check llMoveToTarget / llRotLookAt
  7. UpdateObjectGroups() -- send queued object updates to clients
  8. UpdatePresences() -- send presence updates to clients
  9. CleanTempObjects() -- every 180 frames, async
  10. UpdateEvents() -- fires EventManager.OnFrame
  11. UpdateStorageBackup() -- every 200 frames, async
  12. Frame 20: enable logins, inform neighbours region is up, set Ready=true, GC compact

Frame timing: FrameTime defaults to 0.0908s (~11fps). Sleep is calculated to hit target frame time. Stats normalized to 55fps for viewer display.

Backup runs asynchronously every 200 frames. Objects are only persisted if they have been changed for at least MinimumTimeBeforePersistenceConsidered (default 60s) and no longer than MaximumTimeBeforePersistenceConsidered (default 600s).


Startup Sequence (called from OpenSimBase.CreateRegion)

[edit]

After construction:

  1. scene.SetModuleInterfaces() -- wires up module references from loaded region modules
  2. loadAllLandObjectsFromStorage() -- loads parcels from region database
  3. LoadPrimsFromStorage() -- loads all objects, calls AddRestoredSceneObject() for each
  4. RegisterRegionWithGrid() -- calls GridService.RegisterRegion(), throws on failure
  5. CreateScriptInstances() -- starts script engine for all loaded objects
  6. scene.Start() -- starts Heartbeat thread

AllModulesLoaded() is called after all modules are loaded. Pushes simulator feature data to ISimulatorFeaturesModule (FPS, prim limits, grid info, search URL, etc).


Region Crossing and Teleport

[edit]

All teleport and crossing logic is delegated to EntityTransferModule:

RequestTeleportLocation()  →  EntityTransferModule.Teleport()
CrossAgentToNewRegion()    →  EntityTransferModule.Cross()
TeleportClientHome()       →  EntityTransferModule.TeleportHome()

Incoming objects and attachments from crossings:

IncomingCreateObject()     →  EntityTransferModule.HandleIncomingSceneObject()
IncomingAttechments()      →  EntityTransferModule.HandleIncomingAttachments()

Note: IncomingAttechments() -- the typo is in the source. See WTF file.

OtherRegionUp() is called when a neighbouring region comes online. If within border distance, enables child agents in that region for all current root avatars via EntityTransferModule.EnableChildAgent().


Avatar Connection (NewUserConnection)

[edit]

Called by the login service or another simulator to initiate a connection. Not triggered by the viewer directly.

  1. Checks logins enabled
  2. Checks viewer allow/deny lists
  3. Handles existing ScenePresence (zombie root agents, race conditions during teleport)
  4. Clamps start position within region bounds
  5. CheckLandPositionAccess() -- checks telehub, parcel access, agent limit
  6. VerifyUserPresence() -- checks PresenceService for active session
  7. AuthorizeUser() -- checks estate ban, public access, access list, group membership
  8. Sets up CAPS via CapsModule
  9. ActivateCaps()

Connection is activated later when the viewer sends UseCircuitCodePacket UDP packet.


Avatar Removal (RemoveClient)

[edit]
  1. Sends shutdown notice to child agents if root
  2. Avatar stands up if seated
  3. Closes child agent connections on neighbouring regions (async)
  4. Triggers ClientClosed and OnRemovePresence events
  5. De-rezzes attachments (root only)
  6. Sends KillObject to all clients
  7. Removes agent transactions
  8. Removes circuit, scene presence, client manager entry, CAPS

Shutdown (Close)

[edit]
  1. Deregisters from GridService
  2. Kicks all root avatars with shutdown message
  3. Sets m_shuttingDown = true
  4. Sleeps 500ms to let kick messages reach clients
  5. Closes all agents
  6. Triggers SceneShuttingDown event
  7. Backup(true) -- force persist all pending changes
  8. Closes SceneGraph
  9. Disposes PhysicsScene last (scripts may reference physics during shutdown)

Object Management

[edit]

Key methods:

Method Notes
AddNewPrim() Creates a new prim via raycast. Checks permissions. Uses entity creator registry if available, else creates SceneObjectGroup directly. Applies user default permissions from AgentPreferencesService.
AddRestoredSceneObject() Adds object loaded from storage. Delegates to SceneGraph.
AddNewSceneObject() Adds newly created object. Delegates to SceneGraph. Triggers ObjectAddedToScene event.
DeleteSceneObject() Removes scripts, keyframe motion, email listeners, physics actors. Unlinks from scene. Triggers ObjectBeingRemovedFromScene.
UnlinkSceneObject() Removes record from scene without destroying. On hard delete, removes from database.
IncomingCreateObject() Handles object arriving from region crossing. Delegates to EntityTransferModule.
ForceSceneObjectBackup() Synchronous backup of a single object. Used for deletes and link/unlink.

Client Event Subscriptions

[edit]

SubscribeToClientEvents() wires all viewer protocol events to scene handlers:

  • Terrain events (currently empty)
  • Prim events: position, rotation, scale, shape, texture, name, material, link/unlink, duplicate, permissions, grab, spin, undo/redo
  • Prim rez events: OnAddPrim → AddNewPrim(), OnRezObject → RezObject()
  • Inventory events: folder and item CRUD, task inventory, rez script
  • Teleport events: OnTeleportLocationRequest → RequestTeleportLocation()
  • Script events: reset, get/set running
  • Parcel events: return objects, set clean time, buy
  • Grid events: money transfer
  • Network events: stats update, viewer effect

Note: UnSubscribeToClientEvents() is defined but marked FIXME -- not called anywhere. See WTF file.


Health Monitoring

[edit]

GetHealth() returns an integer 1-5:

Value Meaning
0 Starting up
1 HTTP alive but heartbeat stopped -- possible lockup
2 Heartbeat running (frame tick < 4s ago)
3 One packet thread running
4 Both packet threads running
5 New user logged in within last 4 minutes

TimerWatchdog runs every second. Pushes health and root agent count to etcd if the IEtcdModule is present.


Persistence

[edit]

Objects are persisted via EventManager.OnBackup → SimulationDataService. Objects qualify for persistence if:

  • HasGroupChanged = true
  • Time since last change > MinimumTimeBeforePersistenceConsidered (default 60s)
  • Time since last change < MaximumTimeBeforePersistenceConsidered (default 600s) OR forced=true

Auto-return queued in m_returns dictionary. Return messages sent via IMessageTransferModule on next backup cycle.


Notable Details

[edit]
  • MegaRegions (CombineContiguousRegions) are explicitly rejected on startup with a fatal error
  • The restart console command is registered but disabled -- marked unreliable in source
  • IncomingAttechments() has a typo -- see WTF file for both file locations
  • GOTO is used in AuthorizeUser() for group access checks -- commented in source as "some say GOTO is ugly"
  • Heartbeat restart limit: if heartbeat thread dies and restarts more than 10 times, Environment.Exit(1)
  • GC.Collect() is called explicitly at frame 20 and on map tile regeneration
  • etcd integration is optional -- IEtcdModule only -- used for external health monitoring

See Also

[edit]