mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-01-03 03:48:24 -05:00
This commit imports the C# engine code and game files, excluding C++ source code. [Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
229 lines
6.0 KiB
C#
229 lines
6.0 KiB
C#
using System.Text.Json.Nodes;
|
|
using System.Text.Json.Serialization;
|
|
|
|
namespace Sandbox;
|
|
|
|
/// <summary>
|
|
/// Renders particles as models, using the particle's position, rotation, and size.
|
|
/// </summary>
|
|
[Expose]
|
|
[Title( "Particle Model Renderer" )]
|
|
[Category( "Particles" )]
|
|
[Icon( "category" )]
|
|
public sealed class ParticleModelRenderer : ParticleController, Component.ExecuteInEditor
|
|
{
|
|
/// <summary>
|
|
/// Render options for advanced rendering.
|
|
/// </summary>
|
|
[Property, Order( -100 ), InlineEditor( Label = false ), Group( "Advanced Rendering", StartFolded = true )]
|
|
public RenderOptions RenderOptions { get; } = new RenderOptions( null );
|
|
|
|
/// <summary>
|
|
/// Entry for a model, including its material group and body group settings.
|
|
/// </summary>
|
|
[Expose]
|
|
public sealed class ModelEntry
|
|
{
|
|
private Model _model;
|
|
|
|
/// <summary>
|
|
/// The model associated with this entry.
|
|
/// </summary>
|
|
[KeyProperty]
|
|
public Model Model
|
|
{
|
|
get => _model;
|
|
set
|
|
{
|
|
if ( _model == value )
|
|
return;
|
|
|
|
_model = value;
|
|
|
|
MaterialGroup = default;
|
|
BodyGroups = _model?.Parts.DefaultMask ?? default;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Material group for the model.
|
|
/// </summary>
|
|
[Model.MaterialGroup, ShowIf( nameof( HasMaterialGroups ), true )]
|
|
public string MaterialGroup { get; set; }
|
|
|
|
/// <summary>
|
|
/// Body group mask for the model.
|
|
/// </summary>
|
|
[Model.BodyGroupMask, ShowIf( nameof( HasBodyGroups ), true )]
|
|
public ulong BodyGroups { get; set; }
|
|
|
|
/// <summary>
|
|
/// Indicates whether the model has material groups.
|
|
/// </summary>
|
|
[Hide, JsonIgnore]
|
|
public bool HasMaterialGroups => Model?.MaterialGroupCount > 0;
|
|
|
|
/// <summary>
|
|
/// Indicates whether the model has body groups.
|
|
/// </summary>
|
|
[Hide, JsonIgnore]
|
|
public bool HasBodyGroups => Model?.Parts.All.Sum( x => x.Choices.Count ) > 1;
|
|
|
|
/// <summary>
|
|
/// Converts a <see cref="Model"/> to a <see cref="ModelEntry"/>.
|
|
/// </summary>
|
|
/// <param name="model">The model to convert.</param>
|
|
/// <returns>A new <see cref="ModelEntry"/> instance.</returns>
|
|
public static implicit operator ModelEntry( Model model ) => new() { Model = model };
|
|
}
|
|
|
|
/// <summary>
|
|
/// List of models for rendering. This property is obsolete; use <see cref="Choices"/> instead.
|
|
/// </summary>
|
|
[Hide, Obsolete( "Use Choices" )]
|
|
public List<Model> Models { get; set; } = new();
|
|
|
|
/// <summary>
|
|
/// List of model entries available for rendering.
|
|
/// </summary>
|
|
[Property]
|
|
public List<ModelEntry> Choices { get; set; } = new List<ModelEntry> { Model.Cube };
|
|
|
|
/// <summary>
|
|
/// Material override for rendering.
|
|
/// </summary>
|
|
[Property]
|
|
public Material MaterialOverride { get; set; }
|
|
|
|
/// <summary>
|
|
/// If true, the models will rotate relative to the this GameObject
|
|
/// </summary>
|
|
[Property]
|
|
public bool RotateWithGameObject { get; set; }
|
|
|
|
/// <summary>
|
|
/// Scale factor for particle rendering.
|
|
/// </summary>
|
|
[Property]
|
|
public ParticleFloat Scale { get; set; } = 1;
|
|
|
|
/// <summary>
|
|
/// Indicates whether particles cast shadows.
|
|
/// </summary>
|
|
[Property]
|
|
public bool CastShadows { get; set; } = true;
|
|
|
|
/// <summary>
|
|
/// Called when a particle is created.
|
|
/// </summary>
|
|
/// <param name="p">The particle being created.</param>
|
|
protected override void OnParticleCreated( Particle p )
|
|
{
|
|
p.AddListener( new ParticleModel( this ), this );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Version of the component.
|
|
/// </summary>
|
|
public override int ComponentVersion => 1;
|
|
|
|
/// <summary>
|
|
/// Upgrades the JSON representation of the particle model renderer to version 1.
|
|
/// </summary>
|
|
/// <param name="obj">The JSON object to upgrade.</param>
|
|
[Expose, JsonUpgrader( typeof( ParticleModelRenderer ), 1 )]
|
|
static void Upgrader_v1( JsonObject obj )
|
|
{
|
|
if ( obj.TryGetPropertyValue( "Models", out var node ) )
|
|
{
|
|
var choices = new JsonArray();
|
|
|
|
foreach ( var model in node.AsArray() )
|
|
{
|
|
if ( model is null )
|
|
continue;
|
|
|
|
choices.Add( new JsonObject { ["Model"] = model.ToString() } );
|
|
}
|
|
|
|
obj["Choices"] = choices;
|
|
obj.Remove( "Models" );
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Represents a particle model listener that updates the scene object based on particle properties.
|
|
/// </summary>
|
|
file class ParticleModel : Particle.BaseListener
|
|
{
|
|
/// <summary>
|
|
/// Renderer associated with this particle model.
|
|
/// </summary>
|
|
public ParticleModelRenderer Renderer;
|
|
|
|
SceneObject so;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="ParticleModel"/> class.
|
|
/// </summary>
|
|
/// <param name="renderer">The particle model renderer.</param>
|
|
public ParticleModel( ParticleModelRenderer renderer )
|
|
{
|
|
Renderer = renderer;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when the particle is enabled.
|
|
/// </summary>
|
|
/// <param name="p">The particle being enabled.</param>
|
|
public override void OnEnabled( Particle p )
|
|
{
|
|
var entry = Random.Shared.FromList( Renderer.Choices );
|
|
var model = entry?.Model;
|
|
so = new SceneObject( Renderer.Scene.SceneWorld, model ?? Model.Cube );
|
|
|
|
if ( model is not null )
|
|
{
|
|
so.MeshGroupMask = entry.BodyGroups;
|
|
so.SetMaterialGroup( entry.MaterialGroup );
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when the particle is disabled.
|
|
/// </summary>
|
|
/// <param name="p">The particle being disabled.</param>
|
|
public override void OnDisabled( Particle p )
|
|
{
|
|
if ( !so.IsValid() ) return;
|
|
|
|
so.Delete();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the particle.
|
|
/// </summary>
|
|
/// <param name="p">The particle being updated.</param>
|
|
/// <param name="dt">The delta time since the last update.</param>
|
|
public override void OnUpdate( Particle p, float dt )
|
|
{
|
|
if ( !so.IsValid() ) return;
|
|
|
|
var rot = p.Angles.ToRotation();
|
|
|
|
if ( Renderer.RotateWithGameObject )
|
|
{
|
|
// Rotate the particle with the object
|
|
rot = Renderer.WorldRotation * rot;
|
|
}
|
|
|
|
so.Transform = new Transform( p.Position, rot, p.Size * Renderer.Scale.Evaluate( p, 2356 ) );
|
|
so.ColorTint = p.Color.WithAlphaMultiplied( p.Alpha );
|
|
so.Flags.CastShadows = Renderer.CastShadows;
|
|
so.SetMaterialOverride( Renderer.MaterialOverride );
|
|
|
|
Renderer.RenderOptions.Apply( so );
|
|
}
|
|
}
|