Core - Removed scripting providers

Meta - Updated packages
This commit is contained in:
Robert committed 2024-11-14 14:09:51 +01:00
1 parent 7691af95b9
commit 37f973b093
30 files changed
+35 -1441

No files matched your search

+3 -94
View File
@@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Artemis.Core.ScriptingProviders;
using Artemis.Storage.Entities.Profile;
using SkiaSharp;
@@ -14,15 +12,10 @@ namespace Artemis.Core;
public sealed class Profile : ProfileElement
{
private readonly object _lock = new();
private readonly ObservableCollection<ScriptConfiguration> _scriptConfigurations;
private readonly ObservableCollection<ProfileScript> _scripts;
private bool _isFreshImport;
internal Profile(ProfileConfiguration configuration, ProfileEntity profileEntity) : base(null!)
{
_scripts = new ObservableCollection<ProfileScript>();
_scriptConfigurations = new ObservableCollection<ScriptConfiguration>();
Opacity = 0d;
ShouldDisplay = true;
Configuration = configuration;
@@ -31,8 +24,6 @@ public sealed class Profile : ProfileElement
EntityId = profileEntity.Id;
Exceptions = new List<Exception>();
Scripts = new ReadOnlyObservableCollection<ProfileScript>(_scripts);
ScriptConfigurations = new ReadOnlyObservableCollection<ScriptConfiguration>(_scriptConfigurations);
Load();
}
@@ -41,17 +32,7 @@ public sealed class Profile : ProfileElement
/// Gets the profile configuration of this profile
/// </summary>
public ProfileConfiguration Configuration { get; }
/// <summary>
/// Gets a collection of all active scripts assigned to this profile
/// </summary>
public ReadOnlyObservableCollection<ProfileScript> Scripts { get; }
/// <summary>
/// Gets a collection of all script configurations assigned to this profile
/// </summary>
public ReadOnlyObservableCollection<ScriptConfiguration> ScriptConfigurations { get; }
/// <summary>
/// Gets or sets a boolean indicating whether this profile is freshly imported i.e. no changes have been made to it
/// since import
@@ -85,15 +66,9 @@ public sealed class Profile : ProfileElement
if (Disposed)
throw new ObjectDisposedException("Profile");
foreach (ProfileScript profileScript in Scripts)
profileScript.OnProfileUpdating(deltaTime);
foreach (ProfileElement profileElement in Children)
profileElement.Update(deltaTime);
foreach (ProfileScript profileScript in Scripts)
profileScript.OnProfileUpdated(deltaTime);
const double OPACITY_PER_SECOND = 1;
if (ShouldDisplay && Opacity < 1)
@@ -111,9 +86,6 @@ public sealed class Profile : ProfileElement
if (Disposed)
throw new ObjectDisposedException("Profile");
foreach (ProfileScript profileScript in Scripts)
profileScript.OnProfileRendering(canvas, canvas.LocalClipBounds);
SKPaint? opacityPaint = null;
bool applyOpacityLayer = Configuration.FadeInAndOut && Opacity < 1;
@@ -133,9 +105,6 @@ public sealed class Profile : ProfileElement
opacityPaint?.Dispose();
}
foreach (ProfileScript profileScript in Scripts)
profileScript.OnProfileRendered(canvas, canvas.LocalClipBounds);
if (!Exceptions.Any())
return;
@@ -174,7 +143,7 @@ public sealed class Profile : ProfileElement
/// <inheritdoc />
public override IEnumerable<PluginFeature> GetFeatureDependencies()
{
return GetRootFolder().GetFeatureDependencies().Concat(Scripts.Select(c => c.ScriptingProvider));
return GetRootFolder().GetFeatureDependencies();
}
/// <summary>
@@ -205,10 +174,7 @@ public sealed class Profile : ProfileElement
{
if (!disposing)
return;
while (Scripts.Count > 0)
RemoveScript(Scripts[0]);
foreach (ProfileElement profileElement in Children)
profileElement.Dispose();
ChildrenList.Clear();
@@ -238,61 +204,11 @@ public sealed class Profile : ProfileElement
AddChild(new Folder(this, this, rootFolder));
}
while (_scriptConfigurations.Any())
RemoveScriptConfiguration(_scriptConfigurations[0]);
foreach (ScriptConfiguration scriptConfiguration in ProfileEntity.ScriptConfigurations.Select(e => new ScriptConfiguration(e)))
AddScriptConfiguration(scriptConfiguration);
// Load node scripts last since they may rely on the profile structure being in place
foreach (RenderProfileElement renderProfileElement in GetAllRenderElements())
renderProfileElement.LoadNodeScript();
}
/// <summary>
/// Removes a script configuration from the profile, if the configuration has an active script it is also removed.
/// </summary>
internal void RemoveScriptConfiguration(ScriptConfiguration scriptConfiguration)
{
if (!_scriptConfigurations.Contains(scriptConfiguration))
return;
Script? script = scriptConfiguration.Script;
if (script != null)
RemoveScript((ProfileScript) script);
_scriptConfigurations.Remove(scriptConfiguration);
}
/// <summary>
/// Adds a script configuration to the profile but does not instantiate it's script.
/// </summary>
internal void AddScriptConfiguration(ScriptConfiguration scriptConfiguration)
{
if (!_scriptConfigurations.Contains(scriptConfiguration))
_scriptConfigurations.Add(scriptConfiguration);
}
/// <summary>
/// Adds a script that has a script configuration belonging to this profile.
/// </summary>
internal void AddScript(ProfileScript script)
{
if (!_scriptConfigurations.Contains(script.ScriptConfiguration))
throw new ArtemisCoreException("Cannot add a script to a profile whose script configuration doesn't belong to the same profile.");
if (!_scripts.Contains(script))
_scripts.Add(script);
}
/// <summary>
/// Removes a script from the profile and disposes it.
/// </summary>
internal void RemoveScript(ProfileScript script)
{
_scripts.Remove(script);
script.Dispose();
}
internal override void Save()
{
if (Disposed)
@@ -310,12 +226,5 @@ public sealed class Profile : ProfileElement
ProfileEntity.Layers.Clear();
ProfileEntity.Layers.AddRange(GetAllLayers().Select(f => f.LayerEntity));
ProfileEntity.ScriptConfigurations.Clear();
foreach (ScriptConfiguration scriptConfiguration in ScriptConfigurations)
{
scriptConfiguration.Save();
ProfileEntity.ScriptConfigurations.Add(scriptConfiguration.Entity);
}
}
}
@@ -1,23 +0,0 @@
namespace Artemis.Core.ScriptingProviders;
/// <summary>
/// Represents a view model containing a script editor
/// </summary>
public interface IScriptEditorViewModel
{
/// <summary>
/// Gets the script type this view model was created for
/// </summary>
ScriptType ScriptType { get; }
/// <summary>
/// Gets the script this editor is editing
/// </summary>
Script? Script { get; }
/// <summary>
/// Called whenever the view model must display a different script
/// </summary>
/// <param name="script">The script to display or <see langword="null" /> if no script is to be displayed</param>
void ChangeScript(Script? script);
}
@@ -1,163 +0,0 @@
using System;
using Artemis.Storage.Entities.General;
namespace Artemis.Core.ScriptingProviders;
/// <summary>
/// Represents the configuration of a script
/// </summary>
public class ScriptConfiguration : CorePropertyChanged, IStorageModel
{
private bool _hasChanges;
private bool _isSuspended;
private string _name;
private string? _pendingScriptContent;
private string? _scriptContent;
private string _scriptingProviderId;
/// <summary>
/// Creates a new instance of the <see cref="ScriptConfiguration" /> class
/// </summary>
public ScriptConfiguration(ScriptingProvider provider, string name, ScriptType scriptType)
{
_scriptingProviderId = provider.Id;
_name = name;
Entity = new ScriptConfigurationEntity();
PendingScriptContent = provider.GetDefaultScriptContent(scriptType);
ScriptContent = PendingScriptContent;
}
internal ScriptConfiguration(ScriptConfigurationEntity entity)
{
_scriptingProviderId = null!;
_name = null!;
Entity = entity;
Load();
}
/// <summary>
/// Gets or sets the ID of the scripting provider
/// </summary>
public string ScriptingProviderId
{
get => _scriptingProviderId;
set => SetAndNotify(ref _scriptingProviderId, value);
}
/// <summary>
/// Gets or sets the name of the script
/// </summary>
public string Name
{
get => _name;
set => SetAndNotify(ref _name, value);
}
/// <summary>
/// Gets or sets the script's content
/// </summary>
public string? ScriptContent
{
get => _scriptContent;
private set
{
if (!SetAndNotify(ref _scriptContent, value)) return;
OnScriptContentChanged();
}
}
/// <summary>
/// Gets or sets the pending changes to the script's content
/// </summary>
public string? PendingScriptContent
{
get => _pendingScriptContent;
set
{
if (string.IsNullOrWhiteSpace(value))
value = null;
if (!SetAndNotify(ref _pendingScriptContent, value)) return;
HasChanges = ScriptContent != PendingScriptContent;
}
}
// TODO: Implement suspension
/// <summary>
/// [NYI] Gets or sets a boolean indicating whether this configuration is suspended
/// </summary>
public bool IsSuspended
{
get => _isSuspended;
set => SetAndNotify(ref _isSuspended, value);
}
/// <summary>
/// Gets or sets a boolean indicating whether this configuration has pending changes to it's
/// <see cref="ScriptContent" />
/// </summary>
public bool HasChanges
{
get => _hasChanges;
set => SetAndNotify(ref _hasChanges, value);
}
/// <summary>
/// If active, gets the script
/// </summary>
public Script? Script { get; internal set; }
internal ScriptConfigurationEntity Entity { get; }
/// <summary>
/// Applies the <see cref="PendingScriptContent" /> to the <see cref="ScriptContent" />
/// </summary>
public void ApplyPendingChanges()
{
ScriptContent = PendingScriptContent;
HasChanges = false;
}
/// <summary>
/// Discards the <see cref="PendingScriptContent" />
/// </summary>
public void DiscardPendingChanges()
{
PendingScriptContent = ScriptContent;
HasChanges = false;
}
/// <summary>
/// Occurs whenever the contents of the script have changed
/// </summary>
public event EventHandler? ScriptContentChanged;
/// <summary>
/// Invokes the <see cref="ScriptContentChanged" /> event
/// </summary>
protected virtual void OnScriptContentChanged()
{
ScriptContentChanged?.Invoke(this, EventArgs.Empty);
}
#region Implementation of IStorageModel
/// <inheritdoc />
public void Load()
{
ScriptingProviderId = Entity.ScriptingProviderId;
ScriptContent = Entity.ScriptContent;
PendingScriptContent = Entity.ScriptContent;
Name = Entity.Name;
}
/// <inheritdoc />
public void Save()
{
Entity.ScriptingProviderId = ScriptingProviderId;
Entity.ScriptContent = ScriptContent;
Entity.Name = Name;
}
#endregion
}
@@ -1,80 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace Artemis.Core.ScriptingProviders;
/// <summary>
/// Allows you to implement and register your own scripting provider.
/// </summary>
public abstract class ScriptingProvider<TGlobalScript, TProfileScript> : ScriptingProvider
where TGlobalScript : GlobalScript
where TProfileScript : ProfileScript
{
#region Overrides of PluginFeature
/// <inheritdoc />
internal override void InternalDisable()
{
base.InternalDisable();
while (Scripts.Count > 0)
Scripts[0].Dispose();
}
#endregion
#region Overrides of ScriptingProvider
/// <inheritdoc />
internal override Type ProfileScriptType => typeof(TProfileScript);
/// <inheritdoc />
internal override Type GlobalScriptType => typeof(TGlobalScript);
#endregion
}
/// <summary>
/// Allows you to implement and register your own scripting provider.
/// <para>
/// Note: You can't implement this, implement
/// <see cref="ScriptingProvider{TGlobalScript, TProfileScript}" /> instead.
/// </para>
/// </summary>
public abstract class ScriptingProvider : PluginFeature
{
/// <summary>
/// The base constructor of the <see cref="ScriptingProvider" /> class
/// </summary>
protected ScriptingProvider()
{
Scripts = new ReadOnlyCollection<Script>(InternalScripts);
}
/// <summary>
/// Gets the name of the scripting language this provider provides
/// </summary>
public abstract string LanguageName { get; }
/// <summary>
/// Gets a list of all active scripts belonging to this scripting provider
/// </summary>
public ReadOnlyCollection<Script> Scripts { get; }
internal abstract Type GlobalScriptType { get; }
internal abstract Type ProfileScriptType { get; }
internal List<Script> InternalScripts { get; } = new();
/// <summary>
/// Called when the UI needs a script editor for the specified <paramref name="scriptType" />
/// </summary>
/// <param name="scriptType">The type of script the editor will host</param>
public abstract IScriptEditorViewModel CreateScriptEditor(ScriptType scriptType);
/// <summary>
/// Called when a script for a certain type needs default content.
/// </summary>
/// <param name="scriptType">The type of script the default content is for.</param>
public abstract string GetDefaultScriptContent(ScriptType scriptType);
}
@@ -1,45 +0,0 @@
using Artemis.Core.Services;
namespace Artemis.Core.ScriptingProviders;
/// <summary>
/// Represents a script running globally
/// </summary>
public abstract class GlobalScript : Script
{
/// <inheritdoc />
protected GlobalScript(ScriptConfiguration configuration) : base(configuration)
{
}
internal ScriptingService? ScriptingService { get; set; }
/// <summary>
/// Called whenever the Artemis Core is about to update
/// </summary>
/// <param name="deltaTime">Seconds passed since last update</param>
public virtual void OnCoreUpdating(double deltaTime)
{
}
/// <summary>
/// Called whenever the Artemis Core has been updated
/// </summary>
/// <param name="deltaTime">Seconds passed since last update</param>
public virtual void OnCoreUpdated(double deltaTime)
{
}
#region Overrides of Script
/// <inheritdoc />
public override ScriptType ScriptType => ScriptType.Global;
/// <inheritdoc />
internal override void InternalCleanup()
{
ScriptingService?.RemoveScript(ScriptConfiguration);
}
#endregion
}
@@ -1,67 +0,0 @@
using SkiaSharp;
namespace Artemis.Core.ScriptingProviders;
/// <summary>
/// Represents a script bound to a specific <see cref="Profile" /> processed by a <see cref="ScriptingProvider" />.
/// </summary>
public abstract class ProfileScript : Script
{
/// <inheritdoc />
protected ProfileScript(Profile profile, ScriptConfiguration configuration) : base(configuration)
{
Profile = profile;
}
/// <summary>
/// Gets the profile this script is bound to
/// </summary>
public Profile Profile { get; }
/// <summary>
/// Called whenever the profile is about to update
/// </summary>
/// <param name="deltaTime">Seconds passed since last update</param>
public virtual void OnProfileUpdating(double deltaTime)
{
}
/// <summary>
/// Called whenever the profile has been updated
/// </summary>
/// <param name="deltaTime">Seconds passed since last update</param>
public virtual void OnProfileUpdated(double deltaTime)
{
}
/// <summary>
/// Called whenever the profile is about to render
/// </summary>
/// <param name="canvas">The profile canvas</param>
/// <param name="bounds">The area to be filled, covers the entire canvas</param>
public virtual void OnProfileRendering(SKCanvas canvas, SKRect bounds)
{
}
/// <summary>
/// Called whenever the profile has been rendered
/// </summary>
/// <param name="canvas">The profile canvas</param>
/// <param name="bounds">The area to be filled, covers the entire canvas</param>
public virtual void OnProfileRendered(SKCanvas canvas, SKRect bounds)
{
}
#region Overrides of Script
/// <inheritdoc />
public override ScriptType ScriptType => ScriptType.Profile;
/// <inheritdoc />
internal override void InternalCleanup()
{
Profile.RemoveScript(this);
}
#endregion
}
@@ -1,114 +0,0 @@
using System;
using System.ComponentModel;
namespace Artemis.Core.ScriptingProviders;
/// <summary>
/// Represents a script processed by a <see cref="ScriptingProviders.ScriptingProvider" />.
/// </summary>
public abstract class Script : CorePropertyChanged, IDisposable
{
private bool _disposed;
private ScriptingProvider _scriptingProvider = null!;
/// <summary>
/// The base constructor of any script
/// </summary>
/// <param name="configuration">The script configuration this script belongs to</param>
protected Script(ScriptConfiguration configuration)
{
if (configuration.Script != null)
throw new ArtemisCoreException("The provided script configuration already has an active script");
ScriptConfiguration = configuration;
ScriptConfiguration.PropertyChanged += ScriptConfigurationOnPropertyChanged;
}
/// <summary>
/// Gets the scripting provider this script belongs to
/// </summary>
public ScriptingProvider ScriptingProvider
{
get => _scriptingProvider;
internal set => SetAndNotify(ref _scriptingProvider, value);
}
/// <summary>
/// Gets the script configuration this script belongs to
/// </summary>
public ScriptConfiguration ScriptConfiguration { get; }
/// <summary>
/// Gets the script type of this script
/// </summary>
public abstract ScriptType ScriptType { get; }
/// <summary>
/// Occurs when the contents of the script have changed
/// </summary>
public event EventHandler? ScriptContentChanged;
/// <summary>
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
/// </summary>
/// <param name="disposing">
/// <see langword="true" /> to release both managed and unmanaged resources;
/// <see langword="false" /> to release only unmanaged resources.
/// </param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
}
}
/// <summary>
/// Invokes the <see cref="ScriptContentChanged" /> event
/// </summary>
protected virtual void OnScriptContentChanged()
{
ScriptContentChanged?.Invoke(this, EventArgs.Empty);
}
internal abstract void InternalCleanup();
private void ScriptConfigurationOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(ScriptConfiguration.ScriptContent))
OnScriptContentChanged();
}
/// <inheritdoc />
public void Dispose()
{
if (_disposed)
return;
_disposed = true;
ScriptConfiguration.PropertyChanged -= ScriptConfigurationOnPropertyChanged;
ScriptConfiguration.Script = null;
ScriptingProvider.InternalScripts.Remove(this);
// Can't trust those pesky plugin devs!
InternalCleanup();
Dispose(true);
GC.SuppressFinalize(this);
}
}
/// <summary>
/// Represents a type of script
/// </summary>
public enum ScriptType
{
/// <summary>
/// A global script that's always active
/// </summary>
Global,
/// <summary>
/// A script tied to a <see cref="Profile" />
/// </summary>
Profile
}
+1 -10
View File
@@ -1,4 +1,3 @@
using Artemis.Core.ScriptingProviders;
using Artemis.Core.Services.Core;
using SkiaSharp;
@@ -7,22 +6,17 @@ namespace Artemis.Core.Services;
internal class CoreRenderer : IRenderer
{
private readonly IModuleService _moduleService;
private readonly IScriptingService _scriptingService;
private readonly IProfileService _profileService;
public CoreRenderer(IModuleService moduleService, IScriptingService scriptingService, IProfileService profileService)
public CoreRenderer(IModuleService moduleService, IProfileService profileService)
{
_moduleService = moduleService;
_scriptingService = scriptingService;
_profileService = profileService;
}
/// <inheritdoc />
public void Render(SKCanvas canvas, double delta)
{
foreach (GlobalScript scriptingServiceGlobalScript in _scriptingService.GlobalScripts)
scriptingServiceGlobalScript.OnCoreUpdating(delta);
_moduleService.UpdateActiveModules(delta);
if (!_profileService.ProfileRenderingDisabled)
@@ -30,9 +24,6 @@ internal class CoreRenderer : IRenderer
_profileService.UpdateProfiles(delta);
_profileService.RenderProfiles(canvas);
}
foreach (GlobalScript scriptingServiceGlobalScript in _scriptingService.GlobalScripts)
scriptingServiceGlobalScript.OnCoreUpdated(delta);
}
/// <inheritdoc />
-6
View File
@@ -1,17 +1,12 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using Artemis.Core.DryIoc.Factories;
using Artemis.Core.ScriptingProviders;
using Artemis.Storage;
using DryIoc;
using HidSharp;
using RGB.NET.Core;
using Serilog;
using Serilog.Events;
using SkiaSharp;
namespace Artemis.Core.Services;
@@ -33,7 +28,6 @@ internal class CoreService : ICoreService
IPluginManagementService pluginManagementService,
IProfileService profileService,
IModuleService moduleService,
IScriptingService scriptingService,
IRenderService renderService)
{
Constants.CorePlugin.Container = container;
@@ -1,46 +0,0 @@
using System.Collections.ObjectModel;
using Artemis.Core.ScriptingProviders;
namespace Artemis.Core.Services;
/// <summary>
/// A service that allows you to manage various types of <see cref="NodeScript" /> instances
/// </summary>
public interface IScriptingService : IArtemisService
{
/// <summary>
/// Gets a list of all available scripting providers
/// </summary>
ReadOnlyCollection<ScriptingProvider> ScriptingProviders { get; }
/// <summary>
/// Gets a list of all currently active global scripts
/// </summary>
ReadOnlyCollection<GlobalScript> GlobalScripts { get; }
/// <summary>
/// Adds a script by the provided script configuration to the provided profile and instantiates it.
/// </summary>
/// <param name="scriptConfiguration">The script configuration whose script to add.</param>
/// <param name="profile">The profile to add the script to.</param>
ProfileScript AddScript(ScriptConfiguration scriptConfiguration, Profile profile);
/// <summary>
/// Removes a script by the provided script configuration from the provided profile and disposes it.
/// </summary>
/// <param name="scriptConfiguration">The script configuration whose script to remove.</param>
/// <param name="profile">The profile to remove the script from.</param>
void RemoveScript(ScriptConfiguration scriptConfiguration, Profile profile);
/// <summary>
/// Adds a script by the provided script configuration to the global collection and instantiates it.
/// </summary>
/// <param name="scriptConfiguration">The script configuration whose script to add.</param>
GlobalScript AddScript(ScriptConfiguration scriptConfiguration);
/// <summary>
/// Removes a script by the provided script configuration from the global collection and disposes it.
/// </summary>
/// <param name="scriptConfiguration">The script configuration whose script to remove.</param>
void RemoveScript(ScriptConfiguration scriptConfiguration);
}
@@ -1,165 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Artemis.Core.ScriptingProviders;
namespace Artemis.Core.Services;
internal class ScriptingService : IScriptingService
{
private readonly List<GlobalScript> _globalScripts;
private readonly IPluginManagementService _pluginManagementService;
private readonly IProfileService _profileService;
private readonly List<ScriptingProvider> _scriptingProviders;
public ScriptingService(IPluginManagementService pluginManagementService, IProfileService profileService)
{
_pluginManagementService = pluginManagementService;
_profileService = profileService;
_pluginManagementService.PluginFeatureEnabled += PluginManagementServiceOnPluginFeatureToggled;
_pluginManagementService.PluginFeatureDisabled += PluginManagementServiceOnPluginFeatureToggled;
_scriptingProviders = _pluginManagementService.GetFeaturesOfType<ScriptingProvider>();
_globalScripts = new List<GlobalScript>();
ScriptingProviders = new ReadOnlyCollection<ScriptingProvider>(_scriptingProviders);
GlobalScripts = new ReadOnlyCollection<GlobalScript>(_globalScripts);
// No need to sub to Deactivated, scripts will deactivate themselves
profileService.ProfileActivated += ProfileServiceOnProfileActivated;
foreach (ProfileCategory profileCategory in _profileService.ProfileCategories)
{
foreach (ProfileConfiguration profileConfiguration in profileCategory.ProfileConfigurations)
{
if (profileConfiguration.Profile != null)
InitializeProfileScripts(profileConfiguration.Profile);
}
}
}
private GlobalScript CreateScriptInstance(ScriptConfiguration scriptConfiguration)
{
GlobalScript? script = null;
try
{
if (scriptConfiguration.Script != null)
throw new ArtemisCoreException("The provided script configuration already has an active script");
ScriptingProvider? provider = _scriptingProviders.FirstOrDefault(p => p.Id == scriptConfiguration.ScriptingProviderId);
if (provider == null)
throw new ArtemisCoreException($"Can't create script instance as there is no matching scripting provider found for the script ({scriptConfiguration.ScriptingProviderId}).");
script = (GlobalScript) provider.Plugin.Resolve(provider.GlobalScriptType, scriptConfiguration);
script.ScriptingProvider = provider;
script.ScriptingService = this;
scriptConfiguration.Script = script;
provider.InternalScripts.Add(script);
return script;
}
catch (Exception e)
{
script?.Dispose();
throw new ArtemisCoreException("Failed to initialize global script", e);
}
}
private ProfileScript CreateScriptInstance(ScriptConfiguration scriptConfiguration, Profile profile)
{
ProfileScript? script = null;
try
{
if (scriptConfiguration.Script != null)
throw new ArtemisCoreException("The provided script configuration already has an active script");
ScriptingProvider? provider = _scriptingProviders.FirstOrDefault(p => p.Id == scriptConfiguration.ScriptingProviderId);
if (provider == null)
throw new ArtemisCoreException($"Can't create script instance as there is no matching scripting provider found for the script ({scriptConfiguration.ScriptingProviderId}).");
script = (ProfileScript) provider.Plugin.Resolve(provider.ProfileScriptType, profile, scriptConfiguration);
script.ScriptingProvider = provider;
scriptConfiguration.Script = script;
provider.InternalScripts.Add(script);
lock (profile)
{
profile.AddScript(script);
}
return script;
}
catch (Exception e)
{
// If something went wrong but the script was created, clean up as best we can
if (script != null)
{
if (profile.Scripts.Contains(script))
profile.RemoveScript(script);
else
script.Dispose();
}
throw new ArtemisCoreException("Failed to initialize profile script", e);
}
}
private void InitializeProfileScripts(Profile profile)
{
// Initialize the scripts on the profile
foreach (ScriptConfiguration scriptConfiguration in profile.ScriptConfigurations.Where(c => c.Script == null && _scriptingProviders.Any(p => p.Id == c.ScriptingProviderId)))
CreateScriptInstance(scriptConfiguration, profile);
}
private void PluginManagementServiceOnPluginFeatureToggled(object? sender, PluginFeatureEventArgs e)
{
_scriptingProviders.Clear();
_scriptingProviders.AddRange(_pluginManagementService.GetFeaturesOfType<ScriptingProvider>());
foreach (ProfileCategory profileCategory in _profileService.ProfileCategories)
{
foreach (ProfileConfiguration profileConfiguration in profileCategory.ProfileConfigurations)
{
if (profileConfiguration.Profile != null)
InitializeProfileScripts(profileConfiguration.Profile);
}
}
}
private void ProfileServiceOnProfileActivated(object? sender, ProfileConfigurationEventArgs e)
{
if (e.ProfileConfiguration.Profile != null)
InitializeProfileScripts(e.ProfileConfiguration.Profile);
}
/// <inheritdoc />
public ReadOnlyCollection<ScriptingProvider> ScriptingProviders { get; }
/// <inheritdoc />
public ReadOnlyCollection<GlobalScript> GlobalScripts { get; }
/// <inheritdoc />
public ProfileScript AddScript(ScriptConfiguration scriptConfiguration, Profile profile)
{
profile.AddScriptConfiguration(scriptConfiguration);
return CreateScriptInstance(scriptConfiguration, profile);
}
/// <inheritdoc />
public void RemoveScript(ScriptConfiguration scriptConfiguration, Profile profile)
{
profile.RemoveScriptConfiguration(scriptConfiguration);
}
/// <inheritdoc />
public GlobalScript AddScript(ScriptConfiguration scriptConfiguration)
{
throw new NotImplementedException("Global scripts are not yet implemented.");
}
/// <inheritdoc />
public void RemoveScript(ScriptConfiguration scriptConfiguration)
{
throw new NotImplementedException("Global scripts are not yet implemented.");
}
}