mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-04-19 05:48:07 -04:00
This commit imports the C# engine code and game files, excluding C++ source code. [Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
191 lines
4.0 KiB
C#
191 lines
4.0 KiB
C#
namespace Editor;
|
|
|
|
[CustomEditor( typeof( ulong ), WithAllAttributes = new[] { typeof( Model.BodyGroupMaskAttribute ) } )]
|
|
public class BodyGroupsControlWidget : ControlWidget
|
|
{
|
|
// garry: I hate this, the way it looks, the way it works.
|
|
// We should make it a single informational line, that pops up
|
|
// a selector with more details and edits when you click it.
|
|
|
|
public override bool SupportsMultiEdit => true;
|
|
|
|
public BodyGroupsControlWidget( SerializedProperty property ) : base( property )
|
|
{
|
|
Layout = Layout.Grid();
|
|
Layout.Spacing = 2;
|
|
|
|
AcceptDrops = true;
|
|
|
|
Rebuild();
|
|
}
|
|
|
|
protected override void OnPaint()
|
|
{
|
|
|
|
}
|
|
|
|
Model Model
|
|
{
|
|
get
|
|
{
|
|
if ( !SerializedProperty.TryGetAttribute<Model.BodyGroupMaskAttribute>( out var attr ) )
|
|
return null;
|
|
|
|
var modelProperty = SerializedProperty.Parent.GetProperty( attr.ModelParameter );
|
|
if ( modelProperty is null )
|
|
return null;
|
|
|
|
if ( modelProperty.PropertyType == typeof( string ) )
|
|
{
|
|
var str = modelProperty.GetValue<string>();
|
|
if ( string.IsNullOrWhiteSpace( str ) ) return default;
|
|
return Model.Load( str );
|
|
}
|
|
|
|
return modelProperty.GetValue<Model>( null );
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets common body parts from multiple selected objects
|
|
/// </summary>
|
|
private HashSet<Model.BodyPart> GetCommonBodyParts()
|
|
{
|
|
HashSet<Model.BodyPart> commonBodyParts = null;
|
|
|
|
foreach ( var property in SerializedProperty.MultipleProperties )
|
|
{
|
|
if ( !property.TryGetAttribute<Model.BodyGroupMaskAttribute>( out var attr ) )
|
|
continue;
|
|
|
|
var prop = property.Parent.GetProperty( attr.ModelParameter );
|
|
if ( prop is null )
|
|
continue;
|
|
|
|
var model = prop.GetValue<Model>( null );
|
|
|
|
//
|
|
// Has no body parts, return empty set
|
|
//
|
|
if ( model is null || model.Parts.All.Count() == 0 )
|
|
return new();
|
|
|
|
var modelBodyParts = new HashSet<Model.BodyPart>( model.Parts.All.Where( x => x.Choices.Count > 1 ) );
|
|
|
|
if ( commonBodyParts == null )
|
|
{
|
|
commonBodyParts = modelBodyParts;
|
|
}
|
|
else
|
|
{
|
|
commonBodyParts.IntersectWith( modelBodyParts );
|
|
}
|
|
|
|
if ( commonBodyParts.Count == 0 )
|
|
break;
|
|
}
|
|
|
|
return commonBodyParts ?? new();
|
|
}
|
|
|
|
public void Rebuild()
|
|
{
|
|
Layout.Clear( true );
|
|
|
|
IEnumerable<Model.BodyPart> bodyParts;
|
|
|
|
if ( SerializedProperty.IsMultipleValues )
|
|
{
|
|
bodyParts = GetCommonBodyParts();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Single selection - get body parts directly from the model
|
|
//
|
|
var model = Model;
|
|
if ( model is null )
|
|
{
|
|
Layout.Add( new Label( "No Model" ) );
|
|
return;
|
|
}
|
|
|
|
bodyParts = model.Parts.All.Where( x => x.Choices.Count > 1 );
|
|
}
|
|
|
|
var totalParts = bodyParts.Sum( x => x.Choices.Count );
|
|
if ( totalParts <= 1 )
|
|
{
|
|
Layout.Add( new Label( "None" ) );
|
|
return;
|
|
}
|
|
|
|
var v = SerializedProperty.GetValue<ulong>();
|
|
|
|
var grid = Layout as GridLayout;
|
|
grid.HorizontalSpacing = 8;
|
|
grid.Spacing = 2;
|
|
|
|
int i = 0;
|
|
foreach ( var part in bodyParts )
|
|
{
|
|
if ( part.Choices.Count <= 1 )
|
|
continue;
|
|
|
|
grid.AddCell( 0, i, new Label( $"{part.Name}:", this ) );
|
|
var select = grid.AddCell( 1, i, new ComboBox( this ) );
|
|
|
|
foreach ( var c in part.Choices )
|
|
{
|
|
select.AddItem( $"{c.Name}", onSelected: () => SetModelMask( part, c ), selected: (v & part.Mask) == c.Mask && !SerializedProperty.IsMultipleDifferentValues );
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
grid.SetColumnStretch( 0, 1 );
|
|
|
|
FixedHeight = (Theme.RowHeight + grid.Spacing) * i;
|
|
grid.Margin = new( 0, 0, 0, 2 );
|
|
}
|
|
|
|
protected override void OnValueChanged()
|
|
{
|
|
Rebuild();
|
|
}
|
|
|
|
private void SetModelMask( Model.BodyPart part, Model.BodyPart.Choice c )
|
|
{
|
|
PropertyStartEdit();
|
|
|
|
var v = SerializedProperty.GetValue<ulong>();
|
|
|
|
v = v & ~part.Mask;
|
|
v = v | c.Mask;
|
|
|
|
SerializedProperty.SetValue( v );
|
|
|
|
PropertyFinishEdit();
|
|
}
|
|
|
|
protected override int ValueHash
|
|
{
|
|
get
|
|
{
|
|
var hc = new HashCode();
|
|
hc.Add( base.ValueHash );
|
|
hc.Add( Model );
|
|
|
|
if ( Model is not null )
|
|
{
|
|
foreach ( var val in Model.Parts.All )
|
|
{
|
|
hc.Add( val );
|
|
}
|
|
}
|
|
|
|
return hc.ToHashCode();
|
|
}
|
|
}
|
|
}
|