Editor tool UI and actions for the Ultimate Light Manager. Defines an editor tool with move/rotate/scale subtools, a sidebar window and panel that build the UI for creating, selecting and managing light presets, and a static actions class that loads/saves builder state, applies presets and manipulates scene objects.
using Sandbox;
using global::Editor;
using Dreams.UltimateLightManager;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Dreams.UltimateLightManager.Editor;
[EditorTool( "tools.ultimate-light-manager" )]
[Title( "Ultimate Light Manager" )]
[Icon( "tungsten" )]
[Group( "Scene" )]
[Order( -9998 )]
internal sealed class UltimateLightManagerEditorTool : ObjectEditorTool
{
private UltimateLightManagerToolWindow _window;
public UltimateLightManagerEditorTool()
{
RebuildSidebarOnSelectionChange = false;
}
public override IEnumerable<EditorTool> GetSubtools()
{
yield return new UltimateLightManagerPositionTool();
yield return new UltimateLightManagerRotationTool();
yield return new UltimateLightManagerScaleTool();
}
public override Widget CreateToolSidebar() => null;
public override void OnEnabled()
{
base.OnEnabled();
_window = new UltimateLightManagerToolWindow( this );
AddOverlay( _window, TextFlag.RightTop, 10 );
_window.RefreshAll();
}
public override void OnSelectionChanged()
{
base.OnSelectionChanged();
_window?.RefreshSelection();
}
public override void BuildSceneContextMenu( Menu menu, Ray ray, SceneTraceResult? trace )
{
if ( !TryGetSpawnPositionFromRay( ray, trace, out var worldPosition ) )
{
return;
}
var texts = UltimateLightManagerToolTexts.For( UltimateLightManagerEditorActions.LoadState().ToolLanguage );
menu.AddSeparator();
menu.AddOption( texts["scene.create_here"], "tungsten", () =>
{
var state = UltimateLightManagerEditorActions.LoadState();
UltimateLightManagerEditorActions.CreateLightFromDraft( state.Draft, worldPosition, GetSpawnRotation( ray.Forward ) );
} );
}
private bool TryGetSpawnPositionFromRay( Ray ray, SceneTraceResult? trace, out Vector3 worldPosition )
{
if ( trace is { } hit && hit.Hit )
{
worldPosition = hit.HitPosition + hit.Normal * 2.0f;
return true;
}
if ( Scene != null )
{
var sceneTrace = Scene.Trace.Ray( ray, Gizmo.RayDepth )
.UseRenderMeshes( true )
.WithoutTags( "hidden" )
.UsePhysicsWorld( false )
.Run();
if ( sceneTrace.Hit )
{
worldPosition = sceneTrace.HitPosition + sceneTrace.Normal * 2.0f;
return true;
}
}
var plane = new Plane( Vector3.Up, 0.0f );
if ( plane.TryTrace( ray, out var point, true, Gizmo.RayDepth ) )
{
worldPosition = point;
return true;
}
if ( ray.Forward.Length.AlmostEqual( 0.0f ) )
{
worldPosition = default;
return false;
}
worldPosition = ray.Position + ray.Forward * 300.0f;
return true;
}
private Rotation GetSpawnRotation( Vector3 forward )
{
if ( Camera.IsValid() )
{
return Camera.WorldRotation;
}
return forward.Length.AlmostEqual( 0.0f ) ? Rotation.Identity : Rotation.LookAt( forward, Vector3.Up );
}
[Shortcut( "tools.ultimate-light-manager", "u", typeof( SceneViewWidget ) )]
public static void ActivateTool()
{
EditorToolManager.SetTool( nameof( UltimateLightManagerEditorTool ) );
}
}
[Title( "Move" )]
[Icon( "control_camera" )]
[Group( "1" )]
[Order( 0 )]
internal sealed class UltimateLightManagerPositionTool : PositionEditorTool
{
[Shortcut( "tools.ultimate-light-manager.move", "w", typeof( SceneViewWidget ) )]
public static new void ActivateSubTool()
{
if ( EditorToolManager.CurrentModeName != nameof( UltimateLightManagerEditorTool ) )
{
return;
}
EditorToolManager.SetSubTool( nameof( UltimateLightManagerPositionTool ) );
}
}
[Title( "Rotate" )]
[Icon( "360" )]
[Group( "1" )]
[Order( 1 )]
internal sealed class UltimateLightManagerRotationTool : RotationEditorTool
{
[Shortcut( "tools.ultimate-light-manager.rotate", "e", typeof( SceneViewWidget ) )]
public static new void ActivateSubTool()
{
if ( EditorToolManager.CurrentModeName != nameof( UltimateLightManagerEditorTool ) )
{
return;
}
EditorToolManager.SetSubTool( nameof( UltimateLightManagerRotationTool ) );
}
}
[Title( "Scale" )]
[Icon( "zoom_out_map" )]
[Group( "1" )]
[Order( 2 )]
internal sealed class UltimateLightManagerScaleTool : ScaleEditorTool
{
[Shortcut( "tools.ultimate-light-manager.scale", "r", typeof( SceneViewWidget ) )]
public static new void ActivateSubTool()
{
if ( EditorToolManager.CurrentModeName != nameof( UltimateLightManagerEditorTool ) )
{
return;
}
EditorToolManager.SetSubTool( nameof( UltimateLightManagerScaleTool ) );
}
}
internal sealed class UltimateLightManagerToolWindow : WidgetWindow
{
private readonly UltimateLightManagerToolPanel _panel;
public UltimateLightManagerToolWindow( UltimateLightManagerEditorTool tool ) : base( tool.SceneOverlay, "Ultimate Light Manager" )
{
Icon = "tungsten";
Size = new Vector2( 460, 760 );
MinimumWidth = 380;
MinimumHeight = 520;
Layout = Layout.Column();
Layout.Margin = 0;
Layout.Spacing = 0;
_panel = new UltimateLightManagerToolPanel( tool, this );
Layout.Add( _panel, 1 );
}
public void RefreshAll()
{
_panel.Rebuild();
}
public void RefreshSelection()
{
_panel.RefreshSelection();
}
}
internal sealed class UltimateLightManagerToolPanel : ToolSidebarWidget
{
private readonly UltimateLightManagerEditorTool _tool;
private readonly UltimateLightManagerBuilderState _state;
private readonly UltimateLightManagerBuilderDraft _draft;
private readonly SerializedObject _draftObject;
private readonly List<PresetEntry> _presetEntries = new();
private readonly UltimateLightManagerToolLanguage[] _languageOptions = Enum.GetValues<UltimateLightManagerToolLanguage>();
private ComboBox _presetCombo;
private ComboBox _languageCombo;
private Label _presetStatusLabel;
private Button _savePresetButton;
private Button _duplicatePresetButton;
private Button _renamePresetButton;
private Button _deletePresetButton;
private Button _revertPresetButton;
private bool _isUpdatingPresetCombo;
private bool _isUpdatingLanguageCombo;
private UltimateLightManagerToolTexts Texts => UltimateLightManagerToolTexts.For( _state.ToolLanguage );
public UltimateLightManagerToolPanel( UltimateLightManagerEditorTool tool, Widget parent = null ) : base( parent )
{
_tool = tool;
_state = UltimateLightManagerEditorActions.LoadState();
_draft = _state.Draft ?? new UltimateLightManagerBuilderDraft();
_state.Draft = _draft;
_draftObject = _draft.GetSerialized();
_draftObject.OnPropertyChanged += OnDraftPropertyChanged;
Layout.Margin = 0;
Layout.Spacing = 0;
BuildUi();
}
protected override void OnPaint()
{
}
public void Rebuild()
{
BuildUi();
}
public void RefreshSelection()
{
BuildUi();
}
private void BuildUi()
{
Layout.Clear( true );
if ( Parent is WidgetWindow window )
{
window.WindowTitle = T( "window.title" );
}
var tabs = Layout.Add( new TabWidget( this ), 1 );
tabs.ShowText = true;
var creationPage = AddPage( tabs, T( "tab.creation" ), "add_circle" );
BuildCreationPage( creationPage );
var selectionPage = AddPage( tabs, T( "tab.selection" ), "tune" );
BuildSelectionPage( selectionPage );
var groupsPage = AddPage( tabs, T( "tab.groups" ), "groups" );
BuildGroupsPage( groupsPage );
var settingsPage = AddPage( tabs, T( "tab.settings" ), "settings" );
BuildSettingsPage( settingsPage );
tabs.StateCookie = "ultimate-light-manager.tool-window";
}
private static UltimateLightManagerPage AddPage( TabWidget tabs, string title, string icon )
{
var scroll = new ScrollArea( tabs );
var page = new UltimateLightManagerPage( scroll );
scroll.Canvas = page;
tabs.AddPage( title, icon, scroll );
return page;
}
private void BuildCreationPage( UltimateLightManagerPage page )
{
var group = page.AddGroup( T( "group.creation" ), SizeMode.Flexible );
AddOptionalHint( group, "hint.creation_intro", page );
var presetRow = group.AddRow();
presetRow.Spacing = 6;
presetRow.Add( new Label( T( "label.preset" ), page ) { FixedWidth = 60, Alignment = TextFlag.LeftCenter } );
_presetCombo = presetRow.Add( new ComboBox( page ), 1 );
_presetCombo.ItemChanged += OnPresetSelectionChanged;
presetRow.Add( new Button( T( "button.from_selection" ), page )
{
Icon = "south_west",
Clicked = LoadFromSelection,
Enabled = UltimateLightManagerEditorActions.GetSelectedLightManagers().Length > 0
} );
RebuildPresetCombo();
_presetStatusLabel = new Label( GetPresetStatusText(), page )
{
WordWrap = true
};
_presetStatusLabel.SetStyles( $"color: {Theme.Text.WithAlpha( 0.7f ).Hex};" );
group.Add( _presetStatusLabel );
AddOptionalHint( group, "hint.preset_workflow", page, 0.6f );
var primaryActionRow = group.AddRow();
primaryActionRow.Spacing = 6;
primaryActionRow.Add( _savePresetButton = new Button( T( "button.save" ), page )
{
Icon = "save",
Clicked = HandleSavePreset
}, 1 );
primaryActionRow.Add( _duplicatePresetButton = new Button( T( "button.duplicate" ), page )
{
Icon = "content_copy",
Clicked = OpenDuplicatePresetDialog
}, 1 );
primaryActionRow.Add( _revertPresetButton = new Button( T( "button.revert" ), page )
{
Icon = "restore",
Clicked = RevertToLoadedPreset
}, 1 );
var secondaryActionRow = group.AddRow();
secondaryActionRow.Spacing = 6;
secondaryActionRow.Add( _renamePresetButton = new Button( T( "button.rename" ), page )
{
Icon = "drive_file_rename_outline",
Clicked = OpenRenamePresetDialog
}, 1 );
secondaryActionRow.Add( _deletePresetButton = new Button( T( "button.delete" ), page )
{
Icon = "delete",
Clicked = ConfirmDeleteSelectedPreset
}, 1 );
secondaryActionRow.Add( new Button( T( "button.reset" ), page )
{
Icon = "restart_alt",
Clicked = ResetDraft
}, 1 );
RefreshPresetWorkflowUi();
var sheet = new ControlSheet();
sheet.AddObject( _draftObject, ShouldShowDraftProperty );
group.Add( sheet );
AddOptionalHint( group, "hint.create_center", page, 0.6f );
}
private void BuildSelectionPage( UltimateLightManagerPage page )
{
var lights = UltimateLightManagerEditorActions.GetSelectedLightManagers();
var manipulationGroup = page.AddGroup( T( "group.manipulation" ) );
AddOptionalHint( manipulationGroup, "hint.manipulation", page );
var toolRow = manipulationGroup.AddRow();
toolRow.Spacing = 6;
toolRow.Add( new Button( T( "button.move" ), page )
{
Icon = "control_camera",
Clicked = () => EditorToolManager.SetSubTool( nameof( UltimateLightManagerPositionTool ) ),
Enabled = lights.Length > 0
}, 1 );
toolRow.Add( new Button( T( "button.rotate" ), page )
{
Icon = "360",
Clicked = () => EditorToolManager.SetSubTool( nameof( UltimateLightManagerRotationTool ) ),
Enabled = lights.Length > 0
}, 1 );
toolRow.Add( new Button( T( "button.scale" ), page )
{
Icon = "zoom_out_map",
Clicked = () => EditorToolManager.SetSubTool( nameof( UltimateLightManagerScaleTool ) ),
Enabled = lights.Length > 0
}, 1 );
manipulationGroup.Add( new Label( TF( "label.active_mode_format", GetCurrentTransformModeName() ), page ) );
var selectionGroup = page.AddGroup( T( "group.selection" ), SizeMode.Flexible );
selectionGroup.Add( new Label( GetSelectionSummaryText( lights.Length ), page ) { WordWrap = true } );
if ( lights.Length == 0 )
{
AddOptionalHint( selectionGroup, "hint.no_selection", page, 0.6f );
return;
}
var groupName = UltimateLightManagerEditorActions.GetSelectionSummary( lights, x => x.LightGroup );
var gridName = UltimateLightManagerEditorActions.GetSelectionSummary( lights, x => x.PowerGridTag );
if ( !string.IsNullOrWhiteSpace( groupName ) )
{
selectionGroup.Add( new Label( TF( "label.group_format", groupName ), page ) );
}
if ( !string.IsNullOrWhiteSpace( gridName ) )
{
selectionGroup.Add( new Label( TF( "label.power_grid_format", gridName ), page ) );
}
selectionGroup.Add( new Button( T( "button.apply_draft_selection" ), page )
{
Icon = "playlist_add_check",
Clicked = () => UltimateLightManagerEditorActions.ApplyDraftToSelection( _draft )
} );
var quickActions = selectionGroup.AddRow();
quickActions.Spacing = 6;
quickActions.Add( new Button( T( "button.on" ), page )
{
Icon = "toggle_on",
Clicked = () => UltimateLightManagerEditorActions.ApplyToSelection( "Turn On Light(s)", light => light.TurnOn() )
}, 1 );
quickActions.Add( new Button( T( "button.off" ), page )
{
Icon = "toggle_off",
Clicked = () => UltimateLightManagerEditorActions.ApplyToSelection( "Turn Off Light(s)", light => light.TurnOff() )
}, 1 );
quickActions.Add( new Button( T( "button.toggle" ), page )
{
Icon = "sync_alt",
Clicked = () => UltimateLightManagerEditorActions.ApplyToSelection( "Toggle Light(s)", light => light.Toggle() )
}, 1 );
var inspectorGroup = page.AddGroup( T( "group.parameters" ), SizeMode.Flexible );
AddOptionalHint( inspectorGroup, "hint.parameters", page, 0.6f );
var selectionObject = GetSelectionObject( lights );
if ( selectionObject != null )
{
var sheet = new ControlSheet();
sheet.AddObject( selectionObject );
inspectorGroup.Add( sheet );
}
}
private void BuildGroupsPage( UltimateLightManagerPage page )
{
var lights = UltimateLightManagerEditorActions.GetSelectedLightManagers();
var firstLight = lights.FirstOrDefault();
var group = page.AddGroup( T( "group.groups" ) );
AddOptionalHint( group, "hint.groups", page );
group.Add( new Button( T( "button.assign_group" ), page )
{
Icon = "groups",
Clicked = OpenAssignGroupDialog,
Enabled = lights.Length > 0
} );
group.Add( new Button( T( "button.assign_power_grid" ), page )
{
Icon = "electrical_services",
Clicked = OpenAssignPowerGridDialog,
Enabled = lights.Length > 0
} );
var selectionRow = group.AddRow();
selectionRow.Spacing = 6;
selectionRow.Add( new Button( T( "button.select_same_group" ), page )
{
Icon = "group_work",
Clicked = UltimateLightManagerEditorActions.SelectSameGroup,
Enabled = firstLight != null && !string.IsNullOrWhiteSpace( firstLight.LightGroup )
}, 1 );
selectionRow.Add( new Button( T( "button.select_same_grid" ), page )
{
Icon = "hub",
Clicked = UltimateLightManagerEditorActions.SelectSamePowerGrid,
Enabled = firstLight != null && !string.IsNullOrWhiteSpace( firstLight.PowerGridTag )
}, 1 );
var gameplay = page.AddGroup( T( "group.gameplay" ) );
AddOptionalHint( gameplay, "hint.gameplay", page );
var example = new Label( T( "example.group_state" ), page )
{
WordWrap = true
};
example.SetStyles( $"color: {Theme.Text.WithAlpha( 0.55f ).Hex};" );
gameplay.Add( example );
if ( _state.ShowShortcutSection )
{
page.AddShortcuts(
( T( "shortcut.activate_tool" ), "U" ),
( T( "shortcut.move_gizmo" ), "W" ),
( T( "shortcut.rotate_gizmo" ), "E" ),
( T( "shortcut.scale_gizmo" ), "R" ),
( T( "shortcut.create_here" ), T( "shortcut.right_click" ) )
);
}
}
private void BuildSettingsPage( UltimateLightManagerPage page )
{
var settingsGroup = page.AddGroup( T( "group.settings" ) );
AddOptionalHint( settingsGroup, "hint.settings", page );
var languageRow = settingsGroup.AddRow();
languageRow.Spacing = 6;
languageRow.Add( new Label( T( "label.language" ), page ) { FixedWidth = 90, Alignment = TextFlag.LeftCenter } );
_languageCombo = languageRow.Add( new ComboBox( page ), 1 );
_languageCombo.ItemChanged += OnLanguageSelectionChanged;
RebuildLanguageCombo();
settingsGroup.Add( new Label( TF( "settings.current_language_format", Texts.GetLanguageName( _state.ToolLanguage ) ), page ) { WordWrap = true } );
var displayGroup = page.AddGroup( T( "group.display" ) );
var helpRow = displayGroup.AddRow();
helpRow.Spacing = 6;
helpRow.Add( new Label( T( "label.help_texts" ), page ) { Alignment = TextFlag.LeftCenter }, 1 );
helpRow.Add( new Button( _state.ShowHelpTexts ? T( "settings.help_on" ) : T( "settings.help_off" ), page )
{
Icon = _state.ShowHelpTexts ? "visibility" : "visibility_off",
Clicked = ToggleHelpTexts
} );
var shortcutsRow = displayGroup.AddRow();
shortcutsRow.Spacing = 6;
shortcutsRow.Add( new Label( T( "label.shortcuts_panel" ), page ) { Alignment = TextFlag.LeftCenter }, 1 );
shortcutsRow.Add( new Button( _state.ShowShortcutSection ? T( "settings.shortcuts_on" ) : T( "settings.shortcuts_off" ), page )
{
Icon = _state.ShowShortcutSection ? "keyboard_command_key" : "disabled_by_default",
Clicked = ToggleShortcutSection
} );
}
private void ResetDraft()
{
string lightName = _draft.LightName;
var lightType = _draft.TargetLightType;
_draft.ApplyPresetData( new UltimateLightManagerPresetData() );
_draft.LightName = lightName;
_draft.TargetLightType = lightType;
_state.SelectedPresetKey = UltimateLightManagerEditorActions.GetBuiltInPresetKey( UltimateLightManager.LightPreset.Custom );
_state.LoadedPresetKey = string.Empty;
UltimateLightManagerEditorActions.SaveState( _state );
RefreshPresetWorkflowUi();
BuildUi();
}
private void OnDraftPropertyChanged( SerializedProperty property )
{
UltimateLightManagerEditorActions.SaveState( _state );
RefreshPresetWorkflowUi();
}
private void OnLanguageSelectionChanged()
{
if ( _isUpdatingLanguageCombo )
{
return;
}
int index = _languageCombo?.CurrentIndex ?? -1;
if ( index < 0 || index >= _languageOptions.Length )
{
return;
}
_state.ToolLanguage = _languageOptions[index];
UltimateLightManagerEditorActions.SaveState( _state );
BuildUi();
}
private void OnPresetSelectionChanged()
{
if ( _isUpdatingPresetCombo )
{
return;
}
int index = _presetCombo?.CurrentIndex ?? -1;
if ( index < 0 || index >= _presetEntries.Count )
{
return;
}
var entry = _presetEntries[index];
_state.SelectedPresetKey = entry.Key;
_state.LoadedPresetKey = entry.Key;
if ( entry.IsCustom )
{
_draft.ApplyPresetData( entry.CustomPreset.Data );
}
else
{
UltimateLightManagerEditorActions.ApplyBuiltInPresetToDraft( _draft, entry.BuiltInPreset );
}
UltimateLightManagerEditorActions.SaveState( _state );
BuildUi();
}
private void RebuildPresetCombo()
{
if ( _presetCombo == null )
{
return;
}
_isUpdatingPresetCombo = true;
_presetEntries.Clear();
_presetCombo.Clear();
AddBuiltInPreset( UltimateLightManager.LightPreset.Custom );
AddBuiltInPreset( UltimateLightManager.LightPreset.Candle );
AddBuiltInPreset( UltimateLightManager.LightPreset.Torch );
AddBuiltInPreset( UltimateLightManager.LightPreset.Neon );
AddBuiltInPreset( UltimateLightManager.LightPreset.Alarm );
AddBuiltInPreset( UltimateLightManager.LightPreset.BrokenLamp );
AddBuiltInPreset( UltimateLightManager.LightPreset.SciFi );
AddBuiltInPreset( UltimateLightManager.LightPreset.StreetLight );
foreach ( var preset in _state.CustomPresets
.Where( x => !string.IsNullOrWhiteSpace( x?.Name ) )
.OrderBy( x => x.Name, StringComparer.OrdinalIgnoreCase ) )
{
_presetEntries.Add( PresetEntry.ForCustom( preset ) );
_presetCombo.AddItem( Texts.GetCustomPresetLabel( preset.Name ) );
}
string selectedKey = _state.SelectedPresetKey;
if ( string.IsNullOrWhiteSpace( selectedKey ) )
{
selectedKey = UltimateLightManagerEditorActions.GetBuiltInPresetKey( UltimateLightManager.LightPreset.Custom );
_state.SelectedPresetKey = selectedKey;
}
int selectedIndex = _presetEntries.FindIndex( x => x.Key == selectedKey );
_presetCombo.CurrentIndex = selectedIndex >= 0 ? selectedIndex : 0;
_isUpdatingPresetCombo = false;
}
private void RebuildLanguageCombo()
{
if ( _languageCombo == null )
{
return;
}
_isUpdatingLanguageCombo = true;
_languageCombo.Clear();
foreach ( var language in _languageOptions )
{
_languageCombo.AddItem( Texts.GetLanguageName( language ) );
}
_languageCombo.CurrentIndex = Array.IndexOf( _languageOptions, _state.ToolLanguage );
_isUpdatingLanguageCombo = false;
}
private void AddBuiltInPreset( UltimateLightManager.LightPreset preset )
{
_presetEntries.Add( PresetEntry.ForBuiltIn( preset ) );
_presetCombo.AddItem( Texts.GetBuiltInPresetLabel( preset ) );
}
private void OpenSavePresetDialog()
{
Dialog.AskString(
SavePreset,
T( "dialog.save_preset.prompt" ),
okay: T( "dialog.save_preset.ok" ),
title: T( "dialog.save_preset.title" ),
minLength: 1
);
}
private void HandleSavePreset()
{
var loadedPreset = GetLoadedCustomPreset();
if ( loadedPreset == null )
{
OpenSavePresetDialog();
return;
}
SaveDraftIntoPreset( loadedPreset, loadedPreset.Name );
}
private void SavePreset( string presetName )
{
var targetName = ResolveUniquePresetName( presetName );
if ( string.IsNullOrWhiteSpace( targetName ) )
{
return;
}
var existing = FindCustomPresetByName( targetName );
if ( existing == null )
{
existing = new UltimateLightManagerCustomPreset();
_state.CustomPresets.Add( existing );
}
SaveDraftIntoPreset( existing, targetName );
}
private void OpenDuplicatePresetDialog()
{
Dialog.AskString(
DuplicatePreset,
T( "dialog.duplicate_preset.prompt" ),
okay: T( "dialog.duplicate_preset.ok" ),
title: T( "dialog.duplicate_preset.title" ),
minLength: 1
);
}
private void DuplicatePreset( string presetName )
{
var targetName = ResolveUniquePresetName( presetName );
if ( string.IsNullOrWhiteSpace( targetName ) )
{
return;
}
var copy = new UltimateLightManagerCustomPreset();
_state.CustomPresets.Add( copy );
SaveDraftIntoPreset( copy, targetName );
}
private void OpenRenamePresetDialog()
{
if ( GetLoadedCustomPreset() == null )
{
return;
}
Dialog.AskString(
RenameLoadedPreset,
T( "dialog.rename_preset.prompt" ),
okay: T( "dialog.rename_preset.ok" ),
title: T( "dialog.rename_preset.title" ),
minLength: 1
);
}
private void RenameLoadedPreset( string presetName )
{
var loadedPreset = GetLoadedCustomPreset();
if ( loadedPreset == null )
{
return;
}
var targetName = ResolveUniquePresetName( presetName, loadedPreset );
if ( string.IsNullOrWhiteSpace( targetName ) )
{
return;
}
loadedPreset.Name = targetName;
_state.SelectedPresetKey = UltimateLightManagerEditorActions.GetCustomPresetKey( targetName );
_state.LoadedPresetKey = _state.SelectedPresetKey;
UltimateLightManagerEditorActions.SaveState( _state );
RefreshPresetWorkflowUi();
BuildUi();
}
private void ConfirmDeleteSelectedPreset()
{
var selectedPreset = GetLoadedCustomPreset();
if ( selectedPreset == null )
{
return;
}
Dialog.AskConfirm(
() => DeletePreset( selectedPreset ),
TF( "dialog.delete_preset.message", selectedPreset.Name ),
T( "dialog.delete_preset.title" ),
T( "dialog.delete_preset.ok" ),
T( "dialog.cancel" )
);
}
private void DeletePreset( UltimateLightManagerCustomPreset preset )
{
_state.CustomPresets.Remove( preset );
_state.SelectedPresetKey = UltimateLightManagerEditorActions.GetBuiltInPresetKey( UltimateLightManager.LightPreset.Custom );
_state.LoadedPresetKey = string.Empty;
UltimateLightManagerEditorActions.SaveState( _state );
RefreshPresetWorkflowUi();
BuildUi();
}
private void LoadFromSelection()
{
if ( !UltimateLightManagerEditorActions.LoadDraftFromSelection( _draft ) )
{
return;
}
_state.SelectedPresetKey = UltimateLightManagerEditorActions.GetBuiltInPresetKey( _draft.SelectedPreset );
_state.LoadedPresetKey = string.Empty;
UltimateLightManagerEditorActions.SaveState( _state );
RefreshPresetWorkflowUi();
BuildUi();
}
private void OpenAssignGroupDialog()
{
Dialog.AskString(
AssignGroupToSelection,
T( "dialog.assign_group.prompt" ),
okay: T( "dialog.assign_group.ok" ),
title: T( "dialog.assign_group.title" ),
minLength: 1
);
}
private void AssignGroupToSelection( string groupName )
{
UltimateLightManagerEditorActions.AssignGroupToSelection( groupName );
}
private void OpenAssignPowerGridDialog()
{
Dialog.AskString(
AssignPowerGridToSelection,
T( "dialog.assign_grid.prompt" ),
okay: T( "dialog.assign_grid.ok" ),
title: T( "dialog.assign_grid.title" ),
minLength: 1
);
}
private void AssignPowerGridToSelection( string powerGridTag )
{
UltimateLightManagerEditorActions.AssignPowerGridToSelection( powerGridTag );
}
private void RevertToLoadedPreset()
{
if ( !UltimateLightManagerEditorActions.TryGetPresetSnapshot( _state, _state.LoadedPresetKey, out var presetData ) )
{
return;
}
_draft.ApplyPresetData( presetData );
UltimateLightManagerEditorActions.SaveState( _state );
RefreshPresetWorkflowUi();
BuildUi();
}
private UltimateLightManagerCustomPreset GetSelectedCustomPreset()
{
int index = _presetCombo?.CurrentIndex ?? -1;
if ( index < 0 || index >= _presetEntries.Count )
{
return null;
}
return _presetEntries[index].IsCustom ? _presetEntries[index].CustomPreset : null;
}
private UltimateLightManagerCustomPreset GetLoadedCustomPreset()
{
if ( string.IsNullOrWhiteSpace( _state.LoadedPresetKey ) || !UltimateLightManagerEditorActions.IsCustomPresetKey( _state.LoadedPresetKey ) )
{
return null;
}
return _state.CustomPresets.FirstOrDefault( preset =>
string.Equals( UltimateLightManagerEditorActions.GetCustomPresetKey( preset.Name ), _state.LoadedPresetKey, StringComparison.OrdinalIgnoreCase ) );
}
private UltimateLightManagerCustomPreset FindCustomPresetByName( string presetName )
{
return _state.CustomPresets.FirstOrDefault( preset => string.Equals( preset.Name, presetName, StringComparison.OrdinalIgnoreCase ) );
}
private string ResolveUniquePresetName( string presetName, UltimateLightManagerCustomPreset ignoredPreset = null )
{
presetName = presetName?.Trim();
if ( string.IsNullOrWhiteSpace( presetName ) )
{
return string.Empty;
}
string candidate = presetName;
int suffix = 2;
while ( _state.CustomPresets.Any( preset =>
!ReferenceEquals( preset, ignoredPreset ) &&
string.Equals( preset.Name, candidate, StringComparison.OrdinalIgnoreCase ) ) )
{
candidate = $"{presetName} {suffix}";
suffix++;
}
return candidate;
}
private void SaveDraftIntoPreset( UltimateLightManagerCustomPreset preset, string presetName )
{
if ( preset == null )
{
return;
}
preset.Name = presetName;
preset.Data = _draft.ToPresetData();
_state.SelectedPresetKey = UltimateLightManagerEditorActions.GetCustomPresetKey( presetName );
_state.LoadedPresetKey = _state.SelectedPresetKey;
UltimateLightManagerEditorActions.SaveState( _state );
RefreshPresetWorkflowUi();
BuildUi();
}
private UltimateLightManagerPresetData GetCurrentDraftSnapshot()
{
return _draft.Clone();
}
private bool IsDraftModifiedFromLoadedPreset()
{
if ( !UltimateLightManagerEditorActions.TryGetPresetSnapshot( _state, _state.LoadedPresetKey, out var presetData ) )
{
return false;
}
return !GetCurrentDraftSnapshot().ContentEquals( presetData );
}
private string GetPresetStatusText()
{
if ( !TryGetLoadedPresetLabel( out var presetLabel ) )
{
return T( "status.preset_free" );
}
return IsDraftModifiedFromLoadedPreset()
? TF( "status.preset_modified_format", presetLabel )
: TF( "status.preset_clean_format", presetLabel );
}
private bool TryGetLoadedPresetLabel( out string presetLabel )
{
presetLabel = string.Empty;
if ( string.IsNullOrWhiteSpace( _state.LoadedPresetKey ) )
{
return false;
}
if ( UltimateLightManagerEditorActions.TryParseBuiltInPresetKey( _state.LoadedPresetKey, out var builtInPreset ) )
{
presetLabel = Texts.GetBuiltInPresetLabel( builtInPreset );
return true;
}
var customPreset = GetLoadedCustomPreset();
if ( customPreset == null )
{
return false;
}
presetLabel = Texts.GetCustomPresetLabel( customPreset.Name );
return true;
}
private void RefreshPresetWorkflowUi()
{
bool hasLoadedPreset = UltimateLightManagerEditorActions.TryGetPresetSnapshot( _state, _state.LoadedPresetKey, out _ );
bool isModified = hasLoadedPreset && IsDraftModifiedFromLoadedPreset();
bool hasLoadedCustomPreset = GetLoadedCustomPreset() != null;
if ( _presetStatusLabel != null )
{
_presetStatusLabel.Text = GetPresetStatusText();
}
if ( _renamePresetButton != null )
{
_renamePresetButton.Enabled = hasLoadedCustomPreset;
}
if ( _deletePresetButton != null )
{
_deletePresetButton.Enabled = hasLoadedCustomPreset;
}
if ( _revertPresetButton != null )
{
_revertPresetButton.Enabled = isModified;
}
if ( _duplicatePresetButton != null )
{
_duplicatePresetButton.Enabled = true;
}
if ( _savePresetButton != null )
{
_savePresetButton.Enabled = true;
}
}
private SerializedObject GetSelectionObject( UltimateLightManager[] lights )
{
if ( lights == null || lights.Length == 0 )
{
return null;
}
if ( lights.Length == 1 )
{
return lights[0].GetSerialized();
}
var multi = new MultiSerializedObject();
foreach ( var light in lights )
{
if ( light == null )
{
continue;
}
multi.Add( light.GetSerialized() );
}
multi.Rebuild();
return multi;
}
private string GetCurrentTransformModeName()
{
return _tool.CurrentTool switch
{
UltimateLightManagerRotationTool => T( "mode.rotate" ),
UltimateLightManagerScaleTool => T( "mode.scale" ),
_ => T( "mode.move" )
};
}
private string GetSelectionSummaryText( int count )
{
return count switch
{
0 => T( "summary.none_selected" ),
1 => T( "summary.one_selected" ),
_ => TF( "summary.many_selected", count )
};
}
private void ToggleHelpTexts()
{
_state.ShowHelpTexts = !_state.ShowHelpTexts;
UltimateLightManagerEditorActions.SaveState( _state );
BuildUi();
}
private void ToggleShortcutSection()
{
_state.ShowShortcutSection = !_state.ShowShortcutSection;
UltimateLightManagerEditorActions.SaveState( _state );
BuildUi();
}
private bool ShouldShowDraftProperty( SerializedProperty property )
{
if ( property == null )
{
return false;
}
if ( property.Name == nameof( UltimateLightManagerPresetData.SelectedPreset ) )
{
return false;
}
if ( property.Name == nameof( UltimateLightManagerPresetData.AutoApplyPreset ) )
{
return false;
}
if ( property.Name == nameof( UltimateLightManagerPresetData.ShowDebugGizmos ) )
{
return false;
}
if ( property.Name == nameof( UltimateLightManagerPresetData.AmbientSound ) ||
property.Name == nameof( UltimateLightManagerPresetData.ToggleOnSound ) ||
property.Name == nameof( UltimateLightManagerPresetData.ToggleOffSound ) ||
property.Name == nameof( UltimateLightManagerPresetData.ModulateVolumeWithLight ) ||
property.Name == nameof( UltimateLightManagerPresetData.ModulatePitchWithLight ) ||
property.Name == nameof( UltimateLightManagerPresetData.BaseVolume ) ||
property.Name == nameof( UltimateLightManagerPresetData.MinPitch ) ||
property.Name == nameof( UltimateLightManagerPresetData.MaxPitch ) )
{
return false;
}
if ( property.Name == nameof( UltimateLightManagerPresetData.MaxDistance ) ||
property.Name == nameof( UltimateLightManagerPresetData.ShadowMaxDistance ) ||
property.Name == nameof( UltimateLightManagerPresetData.EnableCulling ) ||
property.Name == nameof( UltimateLightManagerPresetData.EnableAdaptiveUpdates ) ||
property.Name == nameof( UltimateLightManagerPresetData.NearUpdateRate ) ||
property.Name == nameof( UltimateLightManagerPresetData.FarUpdateRate ) )
{
return false;
}
if ( property.Name == nameof( UltimateLightManagerPresetData.DefaultAlarmDuration ) ||
property.Name == nameof( UltimateLightManagerPresetData.AlarmColor ) ||
property.Name == nameof( UltimateLightManagerPresetData.AlarmStrobeSpeed ) ||
property.Name == nameof( UltimateLightManagerPresetData.AlarmBrightnessMultiplier ) )
{
return false;
}
if ( property.Name == nameof( UltimateLightManagerPresetData.EnableFire ) ||
property.Name == nameof( UltimateLightManagerPresetData.FireSpeed ) ||
property.Name == nameof( UltimateLightManagerPresetData.FireIntensity ) ||
property.Name == nameof( UltimateLightManagerPresetData.FireChaos ) ||
property.Name == nameof( UltimateLightManagerPresetData.EnableHorror ) ||
property.Name == nameof( UltimateLightManagerPresetData.MinFlickerDelay ) ||
property.Name == nameof( UltimateLightManagerPresetData.MaxFlickerDelay ) ||
property.Name == nameof( UltimateLightManagerPresetData.DamageSeverity ) ||
property.Name == nameof( UltimateLightManagerPresetData.SparkSound ) ||
property.Name == nameof( UltimateLightManagerPresetData.EnableDisco ) ||
property.Name == nameof( UltimateLightManagerPresetData.DiscoSpeed ) ||
property.Name == nameof( UltimateLightManagerPresetData.DiscoSaturation ) ||
property.Name == nameof( UltimateLightManagerPresetData.DiscoValue ) ||
property.Name == nameof( UltimateLightManagerPresetData.EnableColorTransition ) ||
property.Name == nameof( UltimateLightManagerPresetData.SecondaryColor ) ||
property.Name == nameof( UltimateLightManagerPresetData.ColorTransitionSpeed ) ||
property.Name == nameof( UltimateLightManagerPresetData.EnableSensor ) ||
property.Name == nameof( UltimateLightManagerPresetData.SensorRange ) ||
property.Name == nameof( UltimateLightManagerPresetData.SensorMinBrightness ) ||
property.Name == nameof( UltimateLightManagerPresetData.SensorMaxBrightness ) ||
property.Name == nameof( UltimateLightManagerPresetData.SensorSmoothness ) ||
property.Name == nameof( UltimateLightManagerPresetData.InvertSensor ) ||
property.Name == nameof( UltimateLightManagerPresetData.EnableSway ) ||
property.Name == nameof( UltimateLightManagerPresetData.SwaySpeedPitch ) ||
property.Name == nameof( UltimateLightManagerPresetData.SwayAmountPitch ) ||
property.Name == nameof( UltimateLightManagerPresetData.SwaySpeedRoll ) ||
property.Name == nameof( UltimateLightManagerPresetData.SwayAmountRoll ) ||
property.Name == nameof( UltimateLightManagerPresetData.EnablePattern ) ||
property.Name == nameof( UltimateLightManagerPresetData.Pattern ) ||
property.Name == nameof( UltimateLightManagerPresetData.PatternSpeed ) ||
property.Name == nameof( UltimateLightManagerPresetData.EnablePulse ) ||
property.Name == nameof( UltimateLightManagerPresetData.PulseSpeed ) ||
property.Name == nameof( UltimateLightManagerPresetData.PulseMin ) ||
property.Name == nameof( UltimateLightManagerPresetData.EnableStrobe ) ||
property.Name == nameof( UltimateLightManagerPresetData.StrobeSpeed ) ||
property.Name == nameof( UltimateLightManagerPresetData.StrobeDutyCycle ) ||
property.Name == nameof( UltimateLightManagerPresetData.EnableKelvin ) ||
property.Name == nameof( UltimateLightManagerPresetData.KelvinTemperature ) ||
property.Name == nameof( UltimateLightManagerPresetData.EnablePowerSurge ) ||
property.Name == nameof( UltimateLightManagerPresetData.SurgeMinInterval ) ||
property.Name == nameof( UltimateLightManagerPresetData.SurgeMaxInterval ) ||
property.Name == nameof( UltimateLightManagerPresetData.SurgeDuration ) ||
property.Name == nameof( UltimateLightManagerPresetData.SurgeBrightnessMultiplier ) )
{
return false;
}
return true;
}
private void AddOptionalHint( Layout layout, string key, Widget parent, float alpha = 0.7f )
{
if ( !_state.ShowHelpTexts )
{
return;
}
layout.Add( CreateHintLabel( T( key ), parent, alpha ) );
}
private string T( string key )
{
return Texts[key];
}
private string TF( string key, params object[] args )
{
return Texts.Format( key, args );
}
private static Label CreateHintLabel( string text, Widget parent, float alpha = 0.7f )
{
var label = new Label( text, parent )
{
WordWrap = true
};
label.SetStyles( $"color: {Theme.Text.WithAlpha( alpha ).Hex};" );
return label;
}
private sealed class PresetEntry
{
public string Key { get; init; }
public bool IsCustom { get; init; }
public UltimateLightManager.LightPreset BuiltInPreset { get; init; }
public UltimateLightManagerCustomPreset CustomPreset { get; init; }
public static PresetEntry ForBuiltIn( UltimateLightManager.LightPreset preset )
{
return new PresetEntry
{
Key = UltimateLightManagerEditorActions.GetBuiltInPresetKey( preset ),
BuiltInPreset = preset
};
}
public static PresetEntry ForCustom( UltimateLightManagerCustomPreset preset )
{
return new PresetEntry
{
Key = UltimateLightManagerEditorActions.GetCustomPresetKey( preset.Name ),
IsCustom = true,
CustomPreset = preset
};
}
}
}
internal sealed class UltimateLightManagerPage : ToolSidebarWidget
{
public UltimateLightManagerPage( Widget parent = null ) : base( parent )
{
VerticalSizeMode = SizeMode.CanGrow;
HorizontalSizeMode = SizeMode.Flexible;
Layout.Margin = 8;
Layout.Spacing = 4;
}
protected override void OnPaint()
{
}
}
internal static class UltimateLightManagerEditorActions
{
private const string StatePath = "ultimate_light_manager_builder.json";
public static UltimateLightManagerBuilderState LoadState()
{
var loaded = global::Editor.FileSystem.ProjectSettings.ReadJsonOrDefault<UltimateLightManagerBuilderState>( StatePath ) ?? new UltimateLightManagerBuilderState();
UltimateLightManagerToolStateMigration.ApplyDefaults( loaded );
loaded.Draft ??= new UltimateLightManagerBuilderDraft();
loaded.CustomPresets ??= new List<UltimateLightManagerCustomPreset>();
loaded.CustomPresets = loaded.CustomPresets
.Where( x => x != null && !string.IsNullOrWhiteSpace( x.Name ) )
.GroupBy( x => x.Name, StringComparer.OrdinalIgnoreCase )
.Select( x => x.Last() )
.ToList();
loaded.SelectedPresetKey ??= GetBuiltInPresetKey( UltimateLightManager.LightPreset.Custom );
loaded.LoadedPresetKey ??= string.Empty;
foreach ( var preset in loaded.CustomPresets )
{
preset.Data ??= new UltimateLightManagerPresetData();
}
if ( IsCustomPresetKey( loaded.LoadedPresetKey ) &&
!loaded.CustomPresets.Any( preset => string.Equals( GetCustomPresetKey( preset.Name ), loaded.LoadedPresetKey, StringComparison.OrdinalIgnoreCase ) ) )
{
loaded.LoadedPresetKey = string.Empty;
}
return loaded;
}
public static void SaveState( UltimateLightManagerBuilderState state )
{
if ( state == null )
{
return;
}
state.Draft ??= new UltimateLightManagerBuilderDraft();
state.CustomPresets ??= new List<UltimateLightManagerCustomPreset>();
global::Editor.FileSystem.ProjectSettings.WriteJson( StatePath, state );
}
public static string GetBuiltInPresetKey( UltimateLightManager.LightPreset preset )
{
return $"builtin:{preset}";
}
public static string GetCustomPresetKey( string presetName )
{
return $"custom:{presetName?.Trim()}";
}
public static bool IsCustomPresetKey( string presetKey )
{
return !string.IsNullOrWhiteSpace( presetKey ) && presetKey.StartsWith( "custom:", StringComparison.OrdinalIgnoreCase );
}
public static bool TryParseBuiltInPresetKey( string presetKey, out UltimateLightManager.LightPreset preset )
{
preset = UltimateLightManager.LightPreset.Custom;
if ( string.IsNullOrWhiteSpace( presetKey ) || !presetKey.StartsWith( "builtin:", StringComparison.OrdinalIgnoreCase ) )
{
return false;
}
return Enum.TryParse( presetKey["builtin:".Length..], true, out preset );
}
public static bool TryGetPresetSnapshot( UltimateLightManagerBuilderState state, string presetKey, out UltimateLightManagerPresetData data )
{
data = null;
if ( state == null || string.IsNullOrWhiteSpace( presetKey ) )
{
return false;
}
if ( TryParseBuiltInPresetKey( presetKey, out var builtInPreset ) )
{
var draft = new UltimateLightManagerBuilderDraft();
ApplyBuiltInPresetToDraft( draft, builtInPreset );
data = draft.Clone();
return true;
}
var customPreset = state.CustomPresets?.FirstOrDefault( preset =>
string.Equals( GetCustomPresetKey( preset.Name ), presetKey, StringComparison.OrdinalIgnoreCase ) );
if ( customPreset?.Data == null )
{
return false;
}
data = customPreset.Data.Clone();
return true;
}
public static void ApplyBuiltInPresetToDraft( UltimateLightManagerBuilderDraft draft, UltimateLightManager.LightPreset preset )
{
if ( draft == null )
{
return;
}
draft.SelectedPreset = preset;
draft.AutoApplyPreset = false;
if ( preset == UltimateLightManager.LightPreset.Custom )
{
return;
}
ResetDraftLookSettings( draft );
switch ( preset )
{
case UltimateLightManager.LightPreset.Candle:
draft.Brightness = 0.75f;
draft.LightColor = new Color( 1.0f, 0.76f, 0.5f );
draft.SecondaryColor = new Color( 1.0f, 0.66f, 0.35f );
draft.EnableKelvin = true;
draft.KelvinTemperature = 1800;
draft.EnableFire = true;
draft.FireSpeed = 10.0f;
draft.FireIntensity = 0.18f;
draft.FireChaos = 0.6f;
draft.VolumetricBoost = 0.6f;
break;
case UltimateLightManager.LightPreset.Torch:
draft.Brightness = 1.35f;
draft.LightColor = new Color( 1.0f, 0.72f, 0.38f );
draft.SecondaryColor = new Color( 1.0f, 0.45f, 0.2f );
draft.EnableKelvin = true;
draft.KelvinTemperature = 2200;
draft.EnableFire = true;
draft.FireSpeed = 13.0f;
draft.FireIntensity = 0.28f;
draft.FireChaos = 1.0f;
draft.VolumetricBoost = 1.4f;
break;
case UltimateLightManager.LightPreset.Neon:
draft.Brightness = 1.15f;
draft.LightColor = new Color( 0.2f, 0.95f, 1.0f );
draft.SecondaryColor = new Color( 1.0f, 0.2f, 0.85f );
draft.EnableColorTransition = true;
draft.ColorTransitionSpeed = 0.65f;
draft.EnablePulse = true;
draft.PulseSpeed = 1.2f;
draft.PulseMin = 0.75f;
draft.CastShadows = false;
draft.VolumetricBoost = 0.25f;
break;
case UltimateLightManager.LightPreset.Alarm:
draft.Brightness = 2.0f;
draft.LightColor = new Color( 1.0f, 0.18f, 0.12f );
draft.AlarmColor = draft.LightColor;
draft.EnableStrobe = true;
draft.StrobeSpeed = 7.0f;
draft.StrobeDutyCycle = 0.45f;
draft.CastShadows = false;
draft.VolumetricBoost = 1.1f;
break;
case UltimateLightManager.LightPreset.BrokenLamp:
draft.Brightness = 1.0f;
draft.LightColor = new Color( 1.0f, 0.93f, 0.82f );
draft.EnableHorror = true;
draft.MinFlickerDelay = 0.04f;
draft.MaxFlickerDelay = 0.25f;
draft.DamageSeverity = 0.85f;
draft.EnableKelvin = true;
draft.KelvinTemperature = 3400;
break;
case UltimateLightManager.LightPreset.SciFi:
draft.Brightness = 1.6f;
draft.LightColor = new Color( 0.35f, 0.78f, 1.0f );
draft.SecondaryColor = new Color( 0.1f, 1.0f, 0.8f );
draft.EnableColorTransition = true;
draft.ColorTransitionSpeed = 1.15f;
draft.EnablePulse = true;
draft.PulseSpeed = 0.85f;
draft.PulseMin = 0.55f;
draft.VolumetricBoost = 2.0f;
break;
case UltimateLightManager.LightPreset.StreetLight:
draft.Brightness = 1.4f;
draft.LightColor = new Color( 1.0f, 0.84f, 0.68f );
draft.EnableKelvin = true;
draft.KelvinTemperature = 3500;
draft.MaxDistance = 4500.0f;
draft.ShadowMaxDistance = 1200.0f;
draft.VolumetricBoost = 0.55f;
break;
case UltimateLightManager.LightPreset.Custom:
default:
break;
}
}
public static void CreateLightFromDraft( UltimateLightManagerBuilderDraft draft, Vector3? worldPosition = null, Rotation? worldRotation = null )
{
var session = SceneEditorSession.Active;
if ( session?.Scene == null || draft == null )
{
return;
}
using var scope = SceneEditorSession.Scope();
using ( session.UndoScope( $"Create {draft.GetSafeLightName()}" ).WithGameObjectCreations().WithComponentCreations().Push() )
{
var go = new GameObject( true, draft.GetSafeLightName() );
go.NetworkMode = NetworkMode.Object;
var parent = GetSelectedParentGameObject();
if ( parent != null )
{
go.WorldTransform = parent.WorldTransform;
go.SetParent( parent, true );
}
if ( worldPosition.HasValue )
{
go.WorldPosition = worldPosition.Value;
}
if ( worldRotation.HasValue )
{
go.WorldRotation = worldRotation.Value;
}
var light = go.GetOrAddComponent<UltimateLightManager>( true );
ApplyDraftToLight( draft, light );
EditorScene.Selection.Clear();
EditorScene.Selection.Add( go );
}
}
public static void ApplyDraftToSelection( UltimateLightManagerBuilderDraft draft )
{
if ( draft == null )
{
return;
}
var lights = GetSelectedLightManagers();
if ( lights.Length == 0 )
{
return;
}
var session = SceneEditorSession.Active;
if ( session == null )
{
return;
}
using var scope = SceneEditorSession.Scope();
using ( session.UndoScope( "Apply Ultimate Light Draft" ).WithComponentChanges( lights ).Push() )
{
foreach ( var light in lights )
{
ApplyDraftToLight( draft, light );
}
}
}
public static bool LoadDraftFromSelection( UltimateLightManagerBuilderDraft draft )
{
var selectedLight = GetSelectedLightManagers().FirstOrDefault();
if ( selectedLight == null || draft == null )
{
return false;
}
draft.LightName = string.IsNullOrWhiteSpace( selectedLight.GameObject?.Name ) ? draft.LightName : selectedLight.GameObject.Name;
draft.CaptureFromLight( selectedLight );
return true;
}
public static void AssignGroupToSelection( string groupName )
{
groupName = groupName?.Trim();
if ( string.IsNullOrWhiteSpace( groupName ) )
{
return;
}
ApplyToSelection( $"Assign Group {groupName}", light => light.LightGroup = groupName );
}
public static void AssignPowerGridToSelection( string powerGridTag )
{
powerGridTag = powerGridTag?.Trim();
if ( string.IsNullOrWhiteSpace( powerGridTag ) )
{
return;
}
ApplyToSelection( $"Assign Power Grid {powerGridTag}", light => light.PowerGridTag = powerGridTag );
}
public static void SelectSameGroup()
{
var source = GetSelectedLightManagers().FirstOrDefault();
var session = SceneEditorSession.Active;
if ( source == null || session?.Scene == null || string.IsNullOrWhiteSpace( source.LightGroup ) )
{
return;
}
SelectLightsInScene( session, light => string.Equals( light.LightGroup, source.LightGroup, StringComparison.OrdinalIgnoreCase ) );
}
public static void SelectSamePowerGrid()
{
var source = GetSelectedLightManagers().FirstOrDefault();
var session = SceneEditorSession.Active;
if ( source == null || session?.Scene == null || string.IsNullOrWhiteSpace( source.PowerGridTag ) )
{
return;
}
SelectLightsInScene( session, light => string.Equals( light.PowerGridTag, source.PowerGridTag, StringComparison.OrdinalIgnoreCase ) );
}
public static void ApplyToSelection( string undoName, Action<UltimateLightManager> action )
{
var session = SceneEditorSession.Active;
if ( session == null || action == null )
{
return;
}
var lights = GetSelectedLightManagers();
if ( lights.Length == 0 )
{
return;
}
using var scope = SceneEditorSession.Scope();
using ( session.UndoScope( undoName ).WithComponentChanges( lights ).Push() )
{
foreach ( var light in lights )
{
action( light );
}
}
}
public static UltimateLightManager[] GetSelectedLightManagers()
{
var lights = new HashSet<UltimateLightManager>();
foreach ( var light in EditorScene.Selection.OfType<UltimateLightManager>() )
{
if ( light != null )
{
lights.Add( light );
}
}
foreach ( var component in EditorScene.Selection.OfType<Component>() )
{
if ( component is UltimateLightManager light )
{
lights.Add( light );
}
}
foreach ( var go in GetSelectedGameObjects() )
{
foreach ( var light in go.Components.GetAll<UltimateLightManager>( FindMode.InSelf | FindMode.InDescendants | FindMode.Enabled | FindMode.Disabled ) )
{
if ( light != null )
{
lights.Add( light );
}
}
}
return lights.ToArray();
}
public static string GetSelectionSummary( UltimateLightManager[] lights, Func<UltimateLightManager, string> selector )
{
if ( lights == null || lights.Length == 0 || selector == null )
{
return string.Empty;
}
var values = lights
.Select( selector )
.Where( x => !string.IsNullOrWhiteSpace( x ) )
.Distinct( StringComparer.OrdinalIgnoreCase )
.ToArray();
return values.Length switch
{
0 => string.Empty,
1 => values[0],
_ => "plusieurs valeurs"
};
}
public static void ApplyDraftToLight( UltimateLightManagerBuilderDraft draft, UltimateLightManager light )
{
if ( draft == null || light == null )
{
return;
}
draft.ApplyToLight( light );
}
private static void ResetDraftLookSettings( UltimateLightManagerBuilderDraft draft )
{
var defaults = new UltimateLightManagerPresetData();
draft.LightColor = defaults.LightColor;
draft.SecondaryColor = defaults.SecondaryColor;
draft.Brightness = defaults.Brightness;
draft.VolumetricBoost = defaults.VolumetricBoost;
draft.CastShadows = defaults.CastShadows;
draft.EnableKelvin = defaults.EnableKelvin;
draft.KelvinTemperature = defaults.KelvinTemperature;
draft.EnableFire = defaults.EnableFire;
draft.FireSpeed = defaults.FireSpeed;
draft.FireIntensity = defaults.FireIntensity;
draft.FireChaos = defaults.FireChaos;
draft.EnableHorror = defaults.EnableHorror;
draft.MinFlickerDelay = defaults.MinFlickerDelay;
draft.MaxFlickerDelay = defaults.MaxFlickerDelay;
draft.DamageSeverity = defaults.DamageSeverity;
draft.EnableColorTransition = defaults.EnableColorTransition;
draft.ColorTransitionSpeed = defaults.ColorTransitionSpeed;
draft.EnablePulse = defaults.EnablePulse;
draft.PulseSpeed = defaults.PulseSpeed;
draft.PulseMin = defaults.PulseMin;
draft.EnableStrobe = defaults.EnableStrobe;
draft.StrobeSpeed = defaults.StrobeSpeed;
draft.StrobeDutyCycle = defaults.StrobeDutyCycle;
draft.AlarmColor = defaults.AlarmColor;
draft.MaxDistance = defaults.MaxDistance;
draft.ShadowMaxDistance = defaults.ShadowMaxDistance;
}
private static void SelectLightsInScene( SceneEditorSession session, Func<UltimateLightManager, bool> predicate )
{
using var scope = SceneEditorSession.Scope();
var lights = session.Scene
.GetAllComponents<UltimateLightManager>()
.Where( predicate )
.ToArray();
if ( lights.Length == 0 )
{
return;
}
EditorScene.Selection.Clear();
foreach ( var light in lights )
{
EditorScene.Selection.Add( light.GameObject );
}
}
private static GameObject GetSelectedParentGameObject()
{
return GetSelectedGameObjects().FirstOrDefault();
}
private static GameObject[] GetSelectedGameObjects()
{
var gameObjects = new HashSet<GameObject>();
foreach ( var go in EditorScene.Selection.OfType<GameObject>() )
{
if ( go != null && go is not Scene )
{
gameObjects.Add( go );
}
}
foreach ( var component in EditorScene.Selection.OfType<Component>() )
{
if ( component?.GameObject != null && component.GameObject is not Scene )
{
gameObjects.Add( component.GameObject );
}
}
return gameObjects.ToArray();
}
}