Scripting - Enabled scripting (#638)

* Scripting - Simplified view model structure
* Scripting - Removed Layer and LayerProperty scripts
This commit is contained in:
Robert Beekman authored and GitHub committed 2021-07-04 11:45:32 +02:00
1 parent ee16d69fb3
commit 631d8de2c3
26 files changed
+278 -578

No files matched your search

@@ -0,0 +1,24 @@
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);
}
}
@@ -9,6 +9,7 @@ namespace Artemis.Core.ScriptingProviders
public class ScriptConfiguration : CorePropertyChanged, IStorageModel
{
private bool _hasChanges;
private bool _isSuspended;
private string _name;
private string? _pendingScriptContent;
private string? _scriptContent;
@@ -79,6 +80,16 @@ namespace Artemis.Core.ScriptingProviders
}
}
// 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" />
@@ -7,36 +7,10 @@ namespace Artemis.Core.ScriptingProviders
/// <summary>
/// Allows you to implement and register your own scripting provider.
/// </summary>
public abstract class ScriptingProvider<TGlobalScript, TProfileScript, TLayerScript, TPropertyScript> : ScriptingProvider
public abstract class ScriptingProvider<TGlobalScript, TProfileScript> : ScriptingProvider
where TGlobalScript : GlobalScript
where TProfileScript : ProfileScript
where TLayerScript : LayerScript
where TPropertyScript : PropertyScript
{
/// <summary>
/// Called when the UI needs a script editor for a <see cref="GlobalScript" />
/// </summary>
/// <param name="script">The script the editor must edit</param>
public abstract IScriptEditorViewModel CreateGlobalScriptEditor(TGlobalScript script);
/// <summary>
/// Called when the UI needs a script editor for a <see cref="ProfileScript" />
/// </summary>
/// <param name="script">The script the editor must edit</param>
public abstract IScriptEditorViewModel CreateProfileScriptEditor(TProfileScript script);
/// <summary>
/// Called when the UI needs a script editor for a <see cref="LayerScript" />
/// </summary>
/// <param name="script">The script the editor must edit</param>
public abstract IScriptEditorViewModel CreateLayerScriptScriptEditor(TLayerScript script);
/// <summary>
/// Called when the UI needs a script editor for a <see cref="PropertyScript" />
/// </summary>
/// <param name="script">The script the editor must edit</param>
public abstract IScriptEditorViewModel CreatePropertyScriptEditor(TPropertyScript script);
#region Overrides of PluginFeature
/// <inheritdoc />
@@ -52,69 +26,11 @@ namespace Artemis.Core.ScriptingProviders
#region Overrides of ScriptingProvider
/// <inheritdoc />
internal override Type GlobalScriptType => typeof(TGlobalScript);
/// <inheritdoc />
internal override Type ProfileScriptType => typeof(TProfileScript);
/// <inheritdoc />
internal override Type LayerScriptType => typeof(TLayerScript);
/// <inheritdoc />
internal override Type PropertyScriptType => typeof(TPropertyScript);
/// <summary>
/// Called when the UI needs a script editor for a <see cref="GlobalScript" />
/// </summary>
/// <param name="script">The script the editor must edit</param>
public override IScriptEditorViewModel CreateGlobalScriptEditor(GlobalScript script)
{
if (script == null) throw new ArgumentNullException(nameof(script));
if (script.GetType() != GlobalScriptType)
throw new ArtemisCoreException($"This scripting provider only supports global scripts of type {GlobalScriptType.Name}");
return CreateGlobalScriptEditor((TGlobalScript) script);
}
/// <summary>
/// Called when the UI needs a script editor for a <see cref="ProfileScript" />
/// </summary>
/// <param name="script">The script the editor must edit</param>
public override IScriptEditorViewModel CreateProfileScriptEditor(ProfileScript script)
{
if (script == null) throw new ArgumentNullException(nameof(script));
if (script.GetType() != ProfileScriptType)
throw new ArtemisCoreException($"This scripting provider only supports profile scripts of type {ProfileScriptType.Name}");
return CreateProfileScriptEditor((TProfileScript) script);
}
/// <summary>
/// Called when the UI needs a script editor for a <see cref="LayerScript" />
/// </summary>
/// <param name="script">The script the editor must edit</param>
public override IScriptEditorViewModel CreateLayerScriptScriptEditor(LayerScript script)
{
if (script == null) throw new ArgumentNullException(nameof(script));
if (script.GetType() != LayerScriptType)
throw new ArtemisCoreException($"This scripting provider only supports layer scripts of type {LayerScriptType.Name}");
return CreateLayerScriptScriptEditor((TLayerScript) script);
}
/// <summary>
/// Called when the UI needs a script editor for a <see cref="PropertyScript" />
/// </summary>
/// <param name="script">The script the editor must edit</param>
public override IScriptEditorViewModel CreatePropertyScriptEditor(PropertyScript script)
{
if (script == null) throw new ArgumentNullException(nameof(script));
if (script.GetType() != PropertyScriptType)
throw new ArtemisCoreException($"This scripting provider only supports property scripts of type {PropertyScriptType.Name}");
return CreatePropertyScriptEditor((TPropertyScript) script);
}
internal override Type GlobalScriptType => typeof(TGlobalScript);
#endregion
}
@@ -123,7 +39,7 @@ namespace Artemis.Core.ScriptingProviders
/// Allows you to implement and register your own scripting provider.
/// <para>
/// Note: You can't implement this, implement
/// <see cref="ScriptingProvider{TProfileScript,TLayerScript,TPropertyScript,TGlobalScript}" /> instead.
/// <see cref="ScriptingProvider{TGlobalScript, TProfileScript}" /> instead.
/// </para>
/// </summary>
public abstract class ScriptingProvider : PluginFeature
@@ -139,44 +55,13 @@ namespace Artemis.Core.ScriptingProviders
public ReadOnlyCollection<Script> Scripts => InternalScripts.AsReadOnly();
internal abstract Type GlobalScriptType { get; }
internal abstract Type PropertyScriptType { get; }
internal abstract Type LayerScriptType { get; }
internal abstract Type ProfileScriptType { get; }
internal List<Script> InternalScripts { get; } = new();
/// <summary>
/// Called when the UI needs a script editor for a <see cref="GlobalScript" />
/// Called when the UI needs a script editor for the specified <paramref name="scriptType" />
/// </summary>
/// <param name="script">The script the editor must edit</param>
public abstract IScriptEditorViewModel CreateGlobalScriptEditor(GlobalScript script);
/// <summary>
/// Called when the UI needs a script editor for a <see cref="ProfileScript" />
/// </summary>
/// <param name="script">The script the editor must edit</param>
public abstract IScriptEditorViewModel CreateProfileScriptEditor(ProfileScript script);
/// <summary>
/// Called when the UI needs a script editor for a <see cref="LayerScript" />
/// </summary>
/// <param name="script">The script the editor must edit</param>
public abstract IScriptEditorViewModel CreateLayerScriptScriptEditor(LayerScript script);
/// <summary>
/// Called when the UI needs a script editor for a <see cref="PropertyScript" />
/// </summary>
/// <param name="script">The script the editor must edit</param>
public abstract IScriptEditorViewModel CreatePropertyScriptEditor(PropertyScript script);
}
/// <summary>
/// Represents a view model containing a script editor
/// </summary>
public interface IScriptEditorViewModel
{
/// <summary>
/// Gets the script this editor is editing
/// </summary>
Script Script { get; }
/// <param name="scriptType">The type of script the editor will host</param>
public abstract IScriptEditorViewModel CreateScriptEditor(ScriptType scriptType);
}
}
@@ -32,6 +32,9 @@ namespace Artemis.Core.ScriptingProviders
#region Overrides of Script
/// <inheritdoc />
public override ScriptType ScriptType => ScriptType.Global;
/// <inheritdoc />
internal override void InternalCleanup()
{
@@ -1,74 +0,0 @@
using SkiaSharp;
namespace Artemis.Core.ScriptingProviders
{
/// <summary>
/// Represents a script bound to a specific <see cref="Layer" /> processed by a <see cref="ScriptingProvider" />.
/// </summary>
public abstract class LayerScript : Script
{
/// <inheritdoc />
protected LayerScript(Layer layer, ScriptConfiguration configuration) : base(configuration)
{
Layer = layer;
lock (Layer.Scripts)
{
Layer.Scripts.Add(this);
}
}
/// <summary>
/// Gets the layer this script is bound to
/// </summary>
public Layer Layer { get; internal set; }
/// <summary>
/// Called whenever the layer is about to update
/// </summary>
/// <param name="deltaTime">Seconds passed since last update</param>
public virtual void OnLayerUpdating(double deltaTime)
{
}
/// <summary>
/// Called whenever the layer has been updated
/// </summary>
/// <param name="deltaTime">Seconds passed since last update</param>
public virtual void OnLayerUpdated(double deltaTime)
{
}
/// <summary>
/// Called whenever the layer is about to render
/// </summary>
/// <param name="canvas">The layer canvas</param>
/// <param name="bounds">The area to be filled, covers the shape</param>
/// <param name="paint">The paint to be used to fill the shape</param>
public virtual void OnLayerRendering(SKCanvas canvas, SKRect bounds, SKPaint paint)
{
}
/// <summary>
/// Called whenever the layer has been rendered
/// </summary>
/// <param name="canvas">The layer canvas</param>
/// <param name="bounds">The area to be filled, covers the shape</param>
/// <param name="paint">The paint to be used to fill the shape</param>
public virtual void OnLayerRendered(SKCanvas canvas, SKRect bounds, SKPaint paint)
{
}
#region Overrides of Script
/// <inheritdoc />
internal override void InternalCleanup()
{
lock (Layer.Scripts)
{
Layer.Scripts.Remove(this);
}
}
#endregion
}
}
@@ -58,6 +58,9 @@ namespace Artemis.Core.ScriptingProviders
#region Overrides of Script
/// <inheritdoc />
public override ScriptType ScriptType => ScriptType.Profile;
/// <inheritdoc />
internal override void InternalCleanup()
{
@@ -1,53 +0,0 @@
namespace Artemis.Core.ScriptingProviders
{
/// <summary>
/// Represents a script bound to a specific <see cref="LayerProperty{T}" /> processed by a
/// <see cref="ScriptingProvider" />.
/// </summary>
public abstract class PropertyScript : Script
{
/// <inheritdoc />
protected PropertyScript(ILayerProperty layerProperty, ScriptConfiguration configuration) : base(configuration)
{
LayerProperty = layerProperty;
lock (LayerProperty.Scripts)
{
LayerProperty.Scripts.Add(this);
}
}
/// <summary>
/// Gets the layer property this script is bound to
/// </summary>
public ILayerProperty LayerProperty { get; }
/// <summary>
/// Called whenever the property is about to update
/// </summary>
/// <param name="deltaTime">Seconds passed since last update</param>
public virtual void OnPropertyUpdating(double deltaTime)
{
}
/// <summary>
/// Called whenever the property has been updated
/// </summary>
/// <param name="deltaTime">Seconds passed since last update</param>
public virtual void OnPropertyUpdated(double deltaTime)
{
}
#region Overrides of Script
/// <inheritdoc />
internal override void InternalCleanup()
{
lock (LayerProperty.Scripts)
{
LayerProperty.Scripts.Remove(this);
}
}
#endregion
}
}
@@ -39,6 +39,11 @@ namespace Artemis.Core.ScriptingProviders
/// </summary>
public ScriptConfiguration ScriptConfiguration { get; }
/// <summary>
/// Gets the script type of this script
/// </summary>
public abstract ScriptType ScriptType { get; }
#region Event handlers
private void ScriptConfigurationOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
@@ -71,7 +76,7 @@ namespace Artemis.Core.ScriptingProviders
ScriptConfiguration.PropertyChanged -= ScriptConfigurationOnPropertyChanged;
ScriptConfiguration.Script = null;
ScriptingProvider.InternalScripts.Remove(this);
// Can't trust those pesky plugin devs!
InternalCleanup();
@@ -100,4 +105,20 @@ namespace Artemis.Core.ScriptingProviders
#endregion
}
/// <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,
}
}