Space Content

Space content refers to all the persistent (saved) and non-persistent (temporary) objects in a Space server instance.

We expose the content of a space and server objects through the ISpaceContentService. This service provides access to specific object types, and allows you to spawn your own custom Network Objects as well as objects that are built in to Spatial (such as avatars).

All objects representing content in a space are exposed as ISpaceObject instances. You can interact with the networking layer directly through these objects and modify built-in object types.

All Network Objects are Space Objects. Space Objects are used for more abstract access to content in a space, and are not limited to Network Objects.

Accessing Space Content

Space content can be accessed through the ISpaceContentService which gives you access to all objects and their state via the ISpaceObject interface.

private void Start()
{
foreach (IReadOnlySpaceObject obj in SpatialOS.SpatialBridge.spaceContentService.allObjects.Values)
{
Debug.Log($"ID: {obj.objectID} Owner: {obj.ownerActorNumber} ObjectType: {obj.objectType}");
}
}
private void Start()
{
foreach (IReadOnlySpaceObject obj in SpatialOS.SpatialBridge.spaceContentService.allObjects.Values)
{
Debug.Log($"ID: {obj.objectID} Owner: {obj.ownerActorNumber} ObjectType: {obj.objectType}");
}
}

Note that IReadOnlySpaceObject types can be cast to ISpaceObject and back, but you should generally use the read-only interface when you don't have state authority over the object.

Spatial Scene Model

Content state in a space is organized in a structure commonly referred to as ECS (Entity-Component-System). To put it simply, we store state for various components in dictionaries keyed by object IDs. This allows us to dynamically add and remove state and behaviour to objects as needed.

Our model looks something like this (simplified for this example):

public class SceneState : StateObject
{
// Framework/System components
public StateDictionary<SceneObjectID, SceneObjectState> objects { get; private set; }
public StateDictionary<SceneObjectID, SceneTransformState> transforms { get; private set; }

// Content-specific components
public StateDictionary<SceneObjectID, ImageState> images { get; private set; }
public StateDictionary<SceneObjectID, VideoPlayerState> videoPlayers { get; private set; }
public StateDictionary<SceneObjectID, ModelState> models { get; private set; }
public StateDictionary<SceneObjectID, StickyNoteState> stickyNotes { get; private set; }
// ...

// SDK components
public StateDictionary<SceneObjectID, SDKNetworkObjectState> networkObjects { get; private set; }
public StateDictionary<SceneObjectID, SDKNetworkVariablesState> networkVariables { get; private set; }backwards compatibility

// Non-serialized content-specific components
[NonSerializedState] public StateDictionary<SceneObjectID, AvatarState> avatars { get; private set; }
}
public class SceneState : StateObject
{
// Framework/System components
public StateDictionary<SceneObjectID, SceneObjectState> objects { get; private set; }
public StateDictionary<SceneObjectID, SceneTransformState> transforms { get; private set; }

// Content-specific components
public StateDictionary<SceneObjectID, ImageState> images { get; private set; }
public StateDictionary<SceneObjectID, VideoPlayerState> videoPlayers { get; private set; }
public StateDictionary<SceneObjectID, ModelState> models { get; private set; }
public StateDictionary<SceneObjectID, StickyNoteState> stickyNotes { get; private set; }
// ...

// SDK components
public StateDictionary<SceneObjectID, SDKNetworkObjectState> networkObjects { get; private set; }
public StateDictionary<SceneObjectID, SDKNetworkVariablesState> networkVariables { get; private set; }backwards compatibility

// Non-serialized content-specific components
[NonSerializedState] public StateDictionary<SceneObjectID, AvatarState> avatars { get; private set; }
}

Where SceneObjectState and SceneTransformState are defined as:

public class SceneObjectState : SceneObjectComponent
{
[NonSerializedState] public StatePrimitive<int> creatorActor { get; private set; }
[NonSerializedState] public StatePrimitive<int> ownerActor { get; private set; }
[NonSerializedState] public StatePrimitive<OwnershipMode> ownershipMode { get; private set; }

public StatePrimitive<SceneObjectFlags> flags { get; private set; }
public StatePrimitive<string> viewPrefab { get; private set; }
}


public class SceneTransformState : SceneObjectComponent
{
public StatePrimitive<Vector3> localPosition { get; private set; }
public StatePrimitive<Quaternion> localRotation { get; private set; }
public StatePrimitive<Vector3> localScale { get; private set; }
}
public class SceneObjectState : SceneObjectComponent
{
[NonSerializedState] public StatePrimitive<int> creatorActor { get; private set; }
[NonSerializedState] public StatePrimitive<int> ownerActor { get; private set; }
[NonSerializedState] public StatePrimitive<OwnershipMode> ownershipMode { get; private set; }

public StatePrimitive<SceneObjectFlags> flags { get; private set; }
public StatePrimitive<string> viewPrefab { get; private set; }
}


public class SceneTransformState : SceneObjectComponent
{
public StatePrimitive<Vector3> localPosition { get; private set; }
public StatePrimitive<Quaternion> localRotation { get; private set; }
public StatePrimitive<Vector3> localScale { get; private set; }
}

For example, an image object would be represented by 3 component states: SceneObjectState, SceneTransformState, and ImageState (Represented as JSON for illustrative purposes).

{
"objects": {
"1": {
"creatorActor": 1,
"ownerActor": 1,
"ownershipMode": 1,
"flags": 0,
"viewPrefab": "image"
}
},
"transforms": {
"1": {
"localPosition": [0, 0, 0],
"localRotation": [0, 0, 0, 1],
"localScale": [1, 1, 1]
}
},
"images": {
"1": {
"url": "https://example.com/image.jpg"
}
}
}
{
"objects": {
"1": {
"creatorActor": 1,
"ownerActor": 1,
"ownershipMode": 1,
"flags": 0,
"viewPrefab": "image"
}
},
"transforms": {
"1": {
"localPosition": [0, 0, 0],
"localRotation": [0, 0, 0, 1],
"localScale": [1, 1, 1]
}
},
"images": {
"1": {
"url": "https://example.com/image.jpg"
}
}
}

While we don't expose this scene model directly through the SDK, we expose some of the components through the ISpaceContentService interface:

  • ISpaceContentService.allObjects
  • ISpaceContentService.avatars
  • ISpaceContentService.prefabs
  • ISpaceContentService.networkObjects

Over time we will expose more components and object types which will allow you to control built-in object types directly from your custom C# code.