first commit

This commit is contained in:
Valera
2025-06-11 20:19:35 +07:00
commit 35790cbd34
107 changed files with 3400 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
using Editor;
using Sandbox;
using VeloX.Audio;
namespace VeloX;
[CustomEditor( typeof( Controller ) )]
public class ControllerWidget : ControlObjectWidget
{
public override bool SupportsMultiEdit => false;
public override bool IsWideMode => true;
public ControllerWidget( SerializedProperty property ) : base( property, true )
{
Layout = Layout.Column();
SerializedObject.TryGetProperty( nameof( Controller.InputParameter ), out var inputType );
Layout.Add( Create( inputType ) );
SerializedObject.TryGetProperty( nameof( Controller.InputRange ), out var inputRange );
Layout.Add( Create( inputRange ) );
SerializedObject.TryGetProperty( nameof( Controller.OutputParameter ), out var outputType );
Layout.Add( Create( outputType ) );
SerializedObject.TryGetProperty( nameof( Controller.OutputRange ), out var outputRange );
Layout.Add( Create( outputRange ) );
}
protected override void OnPaint() { }
}

View File

@@ -0,0 +1,144 @@
using Editor;
using Sandbox;
using static Editor.Inspectors.AssetInspector;
using static VeloX.EngineStream;
namespace VeloX;
[Dock( "Editor", "Engine Stream Editor", "local_fire_department" )]
[CanEdit( "asset:engstr" )]
internal sealed class EngineStreamEditor : Widget, IAssetInspector
{
public EngineStreamEditor( Widget parent ) : base( parent, false )
{
CreateEditor();
}
public static EngineStreamEditor Instance { get; private set; }
private EngineStream ActiveStream;
private SerializedObject StreamSO;
private ScrollArea StreamTabs;
//[EditorEvent.Hotload]
//internal void Reload()
//{
// if ( Instance.IsValid() )
// CreateEditor();
//}
//[Menu( "Editor", "VeloX/Engine Stream Editor", "time_to_leave" )]
internal static void Open()
{
Instance = new EngineStreamEditor();
}
internal EngineStreamEditor()
{
Size = new Vector2( 1300, 700 );
CreateEditor();
Show();
}
private class LayerObject
{
public Layer Layer { get; set; }
public string Id { get; set; }
}
private void CreateEditor()
{
WindowTitle = "Engine Stream Editor";
Layout = Layout.Column();
//Canvas = new( null )
//{
// Layout = Layout,
//};
CreateHeader();
var b = Layout.AddRow();
CreateTabs( b );
CreateRightMenu( b );
}
private void CreateHeader()
{
var a = Layout.AddRow();
a.Margin = new Sandbox.UI.Margin( 8, 12, 8, 16 );
a.Alignment = TextFlag.Left;
a.Spacing = 12;
var fileButton = a.Add( new Button( "Open File" ), 0 );
fileButton.Clicked = () =>
{
var picker = AssetPicker.Create( this,
AssetType.FromType( typeof( EngineStream ) ),
new() { EnableCloud = true, SeparateCloudTab = false }
);
picker.OnAssetPicked += asset => CreateStreamEditor( asset[0].LoadResource<EngineStream>() );
picker.Show();
};
}
Layout RightLayout;
SimulatedEngineWidget SimulatedEngineWidget;
private void CreateRightMenu( Layout layout )
{
RightLayout = layout.AddColumn( 1 );
RightLayout.Alignment = TextFlag.Top;
RebuildRightMenu();
}
private void RebuildRightMenu()
{
RightLayout.Clear( true );
RightLayout.Spacing = 12;
var layoutTop = RightLayout.AddColumn();
SimulatedEngineWidget = new SimulatedEngineWidget( null, ActiveStream );
layoutTop.Add( SimulatedEngineWidget );
if ( StreamSO is not null )
layoutTop.Add( new ParametersWidget( StreamSO.GetProperty( nameof( EngineStream.Parameters ) ) ) );
}
private void CreateTabs( Layout layout )
{
StreamTabs = layout.Add( new ScrollArea( this ), 5 );
StreamTabs.Canvas = new Widget( StreamTabs )
{
Layout = Layout.Column(),
VerticalSizeMode = (SizeMode)3,
};
StreamTabs.Canvas.Layout.Margin = new Sandbox.UI.Margin( 8, 8, 16, 8 );
StreamTabs.Canvas.Layout.Alignment = TextFlag.Top;
}
public void RebuildLayers()
{
StreamTabs.Canvas.Layout.Clear( true );
StreamSO = ActiveStream.GetSerialized();
if ( !StreamSO.TryGetProperty( nameof( EngineStream.Layers ), out var layers ) )
return;
StreamTabs.Canvas.Layout.Add( new LayersEditorWidget( layers, ActiveStream, SimulatedEngineWidget ) );
}
private void CreateStreamEditor( EngineStream stream )
{
ActiveStream = stream;
StreamSO = ActiveStream.GetSerialized();
RebuildRightMenu();
RebuildLayers();
}
public void SetAsset( Asset asset )
{
CreateStreamEditor( asset.LoadResource<EngineStream>() );
}
}

View File

@@ -0,0 +1,154 @@
using Editor;
using Sandbox;
using System.Numerics;
using VeloX.Audio;
using static VeloX.EngineStream;
namespace VeloX;
internal class LayerObjectWidget : ControlObjectWidget
{
private SerializedProperty Index;
private SerializedCollection Controllers;
private class ControllerWidget : ControlObjectWidget
{
public ControllerWidget( LayerObjectWidget parent, SerializedProperty property ) : base( property, true )
{
PaintBackground = false;
Layout = Layout.Row();
HorizontalSizeMode = (SizeMode)3;
//SetStyles( "background-color: #123; color: white; font-weight: 600;" );
SerializedObject.TryGetProperty( nameof( Controller.InputParameter ), out var inputType );
Layout.Add( EnumControlWidget.Create( inputType ), 1 );
SerializedObject.TryGetProperty( nameof( Controller.InputRange ), out var inputRange );
Layout.Add( ValueRangeWidget.Create( inputRange ), 12 );
SerializedObject.TryGetProperty( nameof( Controller.OutputParameter ), out var outputType );
Layout.Add( EnumControlWidget.Create( outputType ), 1 );
SerializedObject.TryGetProperty( nameof( Controller.OutputRange ), out var outputRange );
Layout.Add( ValueRangeWidget.Create( outputRange ), 12 );
var removeButton = new IconButton( "clear", () => parent.RemoveEntry( property ) ) { ToolTip = "Remove", Background = Theme.ControlBackground, FixedWidth = Theme.RowHeight, FixedHeight = Theme.RowHeight };
Layout.Add( removeButton );
}
}
void RemoveEntry( SerializedProperty index )
{
Controllers.Remove( index );
Rebuild();
}
private SerializedCollection layers;
SimulatedEngineWidget SimulatedEngine;
public LayerObjectWidget( SerializedProperty property, SerializedProperty index, SerializedCollection layers, SimulatedEngineWidget SimulatedEngine ) : base( property, true )
{
this.SimulatedEngine = SimulatedEngine;
SetStyles( "background-color: #;" );
this.layers = layers;
Index = index;
Layout = Layout.Column();
Layout.SizeConstraint = SizeConstraint.SetMaximumSize;
Layout.Alignment = TextFlag.Top;
Layout.Margin = 4;
Layout.Spacing = 4;
Rebuild();
}
protected override void PaintUnder()
{
base.PaintUnder();
if ( SimulatedEngine is null )
return;
if ( SimulatedEngine.Player is null )
return;
var layer = SimulatedEngine.Player.Stream.Layers[Index.GetValue<string>()];
if ( SimulatedEngine.Player.EngineSounds.TryGetValue( layer, out var handle ) )
{
Paint.SetBrush( Color.Gray );
Rect localRect = base.LocalRect;
var newVolume = localRect.Width * handle.Volume;
Paint.DrawRect( new( 0, 0, newVolume, localRect.Height ) );
Update();
}
}
public void Rebuild()
{
using var _ = SuspendUpdates.For( this );
Layout.Clear( true );
VerticalSizeMode = SizeMode.CanShrink;
var layout = Layout.AddRow();
layout.Alignment = TextFlag.Top;
var id = layout.Add(
StringControlWidget.Create( Index ), 1
).HorizontalSizeMode = SizeMode.Flexible;
layout.Add(
ResourceControlWidget.Create( SerializedObject.GetProperty( nameof( Layer.AudioPath ) ) ), 3
).HorizontalSizeMode = SizeMode.Flexible;
var ctlrs = Layout.AddColumn();
ctlrs.Spacing = 2;
ctlrs.Margin = 4;
var hints = ctlrs.AddRow();
hints.Add( new Label( "Input Type" ), 3 );
hints.Add( new Label( "Input Min" ), 2 );
hints.Add( new Label( "Input Max" ), 2 );
hints.Add( new Label( "Output Type" ), 3 );
hints.Add( new Label( "Output Min" ), 2 );
hints.Add( new Label( "Output Max" ), 2 );
if ( !SerializedObject.TryGetProperty( nameof( Layer.Controllers ), out var constrollers ) )
return;
if ( !constrollers.TryGetAsObject( out var so ) || so is not SerializedCollection sc )
return;
Controllers = sc;
Controllers.OnEntryAdded = Rebuild;
Controllers.OnEntryRemoved = Rebuild;
foreach ( var controller in sc )
{
ctlrs.Add( new ControllerWidget( this, controller ) );
}
var footer = ctlrs.AddRow();
var controls = footer.AddRow();
controls.Alignment = TextFlag.Left;
controls.Spacing = 4;
var useRedline = SerializedObject.GetProperty( nameof( Layer.UseRedline ) );
controls.Add( new BoolControlWidget( useRedline ) );
controls.Add( new Label( useRedline.Description ) );
var isMuted = SerializedObject.GetProperty( nameof( Layer.IsMuted ) );
controls.Add( new BoolControlWidget( isMuted ) );
controls.Add( new Label( isMuted.DisplayName ) );
var cont = footer.AddRow();
cont.Spacing = 4;
cont.Alignment = TextFlag.Right;
cont.Add( new Button( "Add Controller" ) ).Clicked = () =>
{
Controllers.Add( null );
};
cont.Add( new Button( "Remove Layer" ) ).Clicked = () =>
{
layers.RemoveAt( Index.GetValue<string>() );
};
}
}

View File

@@ -0,0 +1,49 @@
using Editor;
using Sandbox;
using System.IO;
namespace VeloX;
internal sealed class LayersEditorWidget : ControlObjectWidget
{
public EngineStream Stream;
SimulatedEngineWidget SimulatedEngineWidget;
public LayersEditorWidget( SerializedProperty property, EngineStream stream, SimulatedEngineWidget SimulatedEngine ) : base( property, true )
{
SimulatedEngineWidget = SimulatedEngine;
PaintBackground = false;
Stream = stream;
Layout = Layout.Column();
Layout.SizeConstraint = SizeConstraint.SetMaximumSize;
Layout.Spacing = 12;
SetStyles( "background-color:rgba(0,0,0,0);" );
if ( SerializedObject is not SerializedCollection sc )
return;
sc.OnEntryAdded += Rebuild;
sc.OnEntryRemoved += Rebuild;
Rebuild();
}
private void Rebuild()
{
Layout.Clear( true );
if ( SerializedObject is not SerializedCollection sc )
return;
foreach ( var t in sc )
{
var id = t.GetKey();
Layout.Add( new LayerObjectWidget( t, id, sc, SimulatedEngineWidget ) );
}
Layout.Add( new Button( "Add Layer" ) ).Clicked = () =>
{
sc.Add( "", null );
};
}
}

View File

@@ -0,0 +1,44 @@
using Editor;
using Sandbox;
namespace VeloX;
internal sealed class ParametersWidget : ControlObjectWidget
{
public ParametersWidget( SerializedProperty property ) : base( property, true )
{
Layout = Layout.Column();
Layout.Spacing = 6;
Layout.Margin = new Sandbox.UI.Margin( 8, 8, 16, 8 );
Layout.Alignment = TextFlag.Top;
Layout.SizeConstraint = SizeConstraint.SetMinimumSize;
var title = new Label( "Stream Parameters" );
title.SetStyles( "background-color:rgba(29, 62, 81, 200);" );
title.Alignment = TextFlag.CenterHorizontally;
title.Margin = 4;
Layout.Add( title );
if ( !property.TryGetAsObject( out var so ) )
return;
var StreamTabs = Layout.Add( new ScrollArea( this ) );
StreamTabs.Canvas = new Widget( StreamTabs )
{
Layout = Layout.Column(),
VerticalSizeMode = (SizeMode)3,
};
StreamTabs.Canvas.Layout.Margin = new Sandbox.UI.Margin( 8, 8, 16, 8 );
StreamTabs.Canvas.Layout.Alignment = TextFlag.Top;
foreach ( var item in TypeLibrary.GetType<StreamParameters>().Properties )
{
var row = StreamTabs.Canvas.Layout.AddColumn();
var propetry = so.GetProperty( item.Name );
row.Add( new Label( propetry.DisplayName ) );
row.Add( Create( propetry ) );
}
}
}

View File

@@ -0,0 +1,91 @@
using Editor;
using Sandbox;
namespace VeloX;
internal sealed class SimulatedEngineWidget : Widget
{
public FloatSlider Throttle;
public FloatSlider RPM;
public EngineStreamPlayer Player { get; private set; }
public bool IsPlaying { get; private set; }
public SimulatedEngineWidget( Widget parent, EngineStream stream ) : base( parent )
{
Player = new EngineStreamPlayer( stream );
Layout = Layout.Column();
Layout.Alignment = TextFlag.Top;
Layout.Spacing = 6;
Layout.Margin = new Sandbox.UI.Margin( 8, 8, 16, 8 );
var title = new Label( "Simulated Engine" );
title.SetStyles( "background-color:rgba(29, 62, 81, 200);" );
title.Alignment = TextFlag.CenterHorizontally;
title.Margin = 8;
var startButton = new Button( "Toggle Engine" )
{
Clicked = () =>
{
IsPlaying = !IsPlaying;
}
};
Layout.Add( title );
Layout.Add( startButton );
var rpmTitle = new Label( "RPM" );
Layout.Add( rpmTitle );
RPM = new FloatSlider( rpmTitle )
{
Maximum = 1,
Value = 0.5f
};
Layout.Add( RPM );
var throttleTitle = new Label( "Throttle" );
Layout.Add( throttleTitle );
Throttle = new FloatSlider( throttleTitle )
{
Maximum = 1,
Value = 0.5f
};
Layout.Add( Throttle );
}
[EditorEvent.Hotload]
internal void Dispose()
{
Player.Dispose();
}
protected override void OnClosed()
{
base.OnClosed();
Dispose();
}
public override void OnDestroyed()
{
base.OnDestroyed();
Dispose();
}
bool IsRedlining;
[EditorEvent.Frame]
public void OnFrame()
{
if ( Player.Stream is null )
return;
Player.EngineState = IsPlaying ? EngineState.Running : EngineState.Off;
Player.Throttle = Throttle.Value;
Player.RPMPercent = RPM.Value;
IsRedlining = RPM.Value == 1 && !IsRedlining;
Player.IsRedlining = IsRedlining;
Player.Update( Time.Delta, Vector3.Zero, true );
}
}

View File

@@ -0,0 +1,55 @@
//using Editor;
//using Editor.Assets;
//using Sandbox;
//using VeloX;
//using static Editor.Inspectors.AssetInspector;
//[CanEdit( "asset:engstr" )]
//public class EngineStreamInspector : Widget, IAssetInspector
//{
// EngineStream EngineStream;
// ControlSheet MainSheet;
// public EngineStreamInspector( Widget parent ) : base( parent )
// {
// Layout = Layout.Column();
// Layout.Margin = 12;
// Layout.Spacing = 12;
// MainSheet = new ControlSheet();
// Layout.Add( MainSheet, 1 );
// }
// [EditorEvent.Hotload]
// void RebuildSheet()
// {
// if ( EngineStream is null || MainSheet is null )
// return;
// Layout.Clear( true );
// var text = Layout.Add( new Editor.TextEdit() );
// var but = Layout.Add( new Editor.Button( "Load JSON" ) );
// but.Clicked += () =>
// {
// EngineStream.LoadFromJson( text.PlainText );
// };
// var so = EngineStream.GetSerialized();
// so.OnPropertyChanged += _ =>
// {
// EngineStream.StateHasChanged();
// };
// Layout.Add( ControlWidget.Create( so.GetProperty( nameof( EngineStream.Layers ) ) ) );
// Layout.Add( ControlWidget.Create( so.GetProperty( nameof( EngineStream.Parameters ) ) ) );
// }
// public void SetAsset( Asset asset )
// {
// EngineStream = asset.LoadResource<EngineStream>();
// RebuildSheet();
// }
//}

View File

@@ -0,0 +1,26 @@
using Editor;
using Sandbox;
using VeloX.Audio;
namespace VeloX;
[CustomEditor( typeof( ValueRange ) )]
public class ValueRangeWidget : ControlObjectWidget
{
public override bool SupportsMultiEdit => false;
public override bool IsWideMode => true;
public ValueRangeWidget( SerializedProperty property ) : base( property, true )
{
Layout = Layout.Row();
SerializedObject.TryGetProperty( nameof( ValueRange.Min ), out var min );
Layout.Add( Create( min ) );
SerializedObject.TryGetProperty( nameof( ValueRange.Max ), out var max );
Layout.Add( Create( max ) );
}
protected override void OnPaint() { }
}