mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-01-02 11:28:19 -05:00
This commit imports the C# engine code and game files, excluding C++ source code. [Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
108 lines
3.8 KiB
C#
108 lines
3.8 KiB
C#
using System.Text.Json.Serialization;
|
|
|
|
namespace Sandbox;
|
|
|
|
#nullable enable
|
|
|
|
/// <summary>
|
|
/// A serialized reference to a <see cref="GameObject"/> that can be resolved at runtime.
|
|
/// Can either have a <see cref="GameObjectId"/> for objects in a scene, or a <see cref="PrefabPath"/>
|
|
/// if we're referencing a prefab.
|
|
/// </summary>
|
|
[ActionGraphExposeWhenCached]
|
|
internal readonly struct GameObjectReference
|
|
{
|
|
private const string ExpectedReferenceType = "gameobject";
|
|
|
|
/// <summary>
|
|
/// Reference a <see cref="GameObject"/> in a scene by its <see cref="GameObject.Id"/>.
|
|
/// </summary>
|
|
public static GameObjectReference FromId( Guid id ) => new( ExpectedReferenceType, gameObjectId: id );
|
|
|
|
/// <summary>
|
|
/// Reference a prefab by its <see cref="Resource.ResourcePath"/>.
|
|
/// </summary>
|
|
public static GameObjectReference FromPrefabPath( string prefabPath ) => new( ExpectedReferenceType, prefabPath: prefabPath );
|
|
|
|
/// <summary>
|
|
/// Reference a given <see cref="GameObject"/>.
|
|
/// </summary>
|
|
public static GameObjectReference FromInstance( GameObject go )
|
|
{
|
|
// If we reference a prefab scene, use the prefab path instead of the ID.
|
|
// But only if the prefab scene is not the active scene.
|
|
// If the prefab is the active scene, we can use the ID, as users may want to reference the prefab root from within the prefab scene.
|
|
if ( go is PrefabScene prefabRoot && go.Scene != Game.ActiveScene )
|
|
{
|
|
Assert.NotNull( prefabRoot.Source, "Prefab root should have a source" );
|
|
return FromPrefabPath( prefabRoot.Source.ResourcePath );
|
|
}
|
|
|
|
return FromId( go.Id );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Expected to be <c>"gameobject"</c> for a game object reference.
|
|
/// </summary>
|
|
[JsonPropertyName( "_type" )]
|
|
public string ReferenceType { get; }
|
|
|
|
/// <summary>
|
|
/// If we're referencing an object in a scene, this is its <see cref="GameObject.Id"/>.
|
|
/// </summary>
|
|
[JsonPropertyName( "go" ), JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingDefault )]
|
|
public Guid GameObjectId { get; }
|
|
|
|
/// <summary>
|
|
/// If we're referencing a prefab, this is its <see cref="Resource.ResourcePath"/>.
|
|
/// </summary>
|
|
[JsonPropertyName( "prefab" ), JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
|
|
public string? PrefabPath { get; }
|
|
|
|
[JsonConstructor]
|
|
private GameObjectReference( string referenceType, Guid gameObjectId = default, string? prefabPath = null )
|
|
{
|
|
ReferenceType = referenceType;
|
|
GameObjectId = gameObjectId;
|
|
PrefabPath = prefabPath;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Attempt to resolve this reference in the current <see cref="Game.ActiveScene"/>. Returns <see langword="null"/> if
|
|
/// the reference couldn't be resolved, and logs a warning.
|
|
/// </summary>
|
|
public GameObject? Resolve() => Resolve( Game.ActiveScene );
|
|
|
|
/// <summary>
|
|
/// Attempt to resolve this reference in the given <paramref name="scene"/>. Returns <see langword="null"/> if
|
|
/// the reference couldn't be resolved.
|
|
/// </summary>
|
|
/// <param name="scene">Scene to attempt to resolve the reference in.</param>
|
|
/// <param name="warn">If true, log a warning to the console if the reference couldn't be resolved.</param>
|
|
public GameObject? Resolve( Scene scene, bool warn = false )
|
|
{
|
|
if ( ReferenceType != ExpectedReferenceType )
|
|
throw new( $"Tried to deserialize unknown type '{ReferenceType ?? "null"}' as GameObject" );
|
|
|
|
if ( !string.IsNullOrWhiteSpace( PrefabPath ) )
|
|
{
|
|
var prefabFile = (PrefabFile)GameResource.GetPromise( typeof( PrefabFile ), PrefabPath );
|
|
return SceneUtility.GetPrefabScene( prefabFile );
|
|
}
|
|
|
|
var go = scene.Directory.FindByGuid( GameObjectId );
|
|
|
|
if ( !go.IsValid() )
|
|
{
|
|
// Conna: this is okay - we may be deserializing over the network and this is a property
|
|
// referring to a GameObject that we don't know about. Let's just make the reference null.
|
|
|
|
if ( warn ) Log.Warning( $"Unknown GameObject {GameObjectId}" );
|
|
|
|
return null;
|
|
}
|
|
|
|
return go;
|
|
}
|
|
}
|