Nodes - Added type color registration system

Nodes - Generate (stable) type colors for undefined types
This commit is contained in:
Robert committed 2021-08-19 11:40:50 +02:00
1 parent 5675d1895b
commit b8077ca589
12 files changed
+297 -147

No files matched your search

@@ -16,7 +16,7 @@ namespace Artemis.Core
/// <returns>The RGB.NET color</returns>
public static Color ToRgbColor(this SKColor color)
{
return new(color.Alpha, color.Red, color.Green, color.Blue);
return new Color(color.Alpha, color.Red, color.Green, color.Blue);
}
/// <summary>
@@ -49,7 +49,7 @@ namespace Artemis.Core
/// <returns>The sum of the two colors</returns>
public static SKColor Sum(this SKColor a, SKColor b)
{
return new(
return new SKColor(
ClampToByte(a.Red + b.Red),
ClampToByte(a.Green + b.Green),
ClampToByte(a.Blue + b.Blue),
@@ -57,6 +57,19 @@ namespace Artemis.Core
);
}
/// <summary>
/// Darkens the color by the specified amount
/// </summary>
/// <param name="c">The color to darken</param>
/// <param name="amount">The brightness of the new color</param>
/// <returns>The darkened color</returns>
public static SKColor Darken(this SKColor c, float amount)
{
c.ToHsl(out float h, out float s, out float l);
l *= 1f - amount;
return SKColor.FromHsl(h, s, l);
}
private static byte ClampToByte(float value)
{
return (byte) Math.Clamp(value, 0, 255);
+39 -11
View File
@@ -4,24 +4,19 @@ using System.Reflection;
using Artemis.Storage.Entities.Profile.Nodes;
using Ninject;
using Ninject.Parameters;
using SkiaSharp;
namespace Artemis.Core.Services
{
internal class NodeService : INodeService
{
private readonly IKernel _kernel;
#region Constants
private static readonly Type TYPE_NODE = typeof(INode);
#endregion
#region Properties & Fields
public IEnumerable<NodeData> AvailableNodes => NodeTypeStore.GetAll();
#endregion
private readonly IKernel _kernel;
#region Constructors
@@ -32,8 +27,20 @@ namespace Artemis.Core.Services
#endregion
#region Properties & Fields
public IEnumerable<NodeData> AvailableNodes => NodeTypeStore.GetAll();
#endregion
#region Methods
/// <inheritdoc />
public TypeColorRegistration? GetTypeColor(Type type)
{
return NodeTypeStore.GetColor(type);
}
public NodeTypeRegistration RegisterNodeType(Plugin plugin, Type nodeType)
{
if (plugin == null) throw new ArgumentNullException(nameof(plugin));
@@ -46,10 +53,18 @@ namespace Artemis.Core.Services
string description = nodeAttribute?.Description ?? string.Empty;
string category = nodeAttribute?.Category ?? string.Empty;
NodeData nodeData = new(plugin, nodeType, name, description, category, (e) => CreateNode(e, nodeType));
NodeData nodeData = new(plugin, nodeType, name, description, category, e => CreateNode(e, nodeType));
return NodeTypeStore.Add(nodeData);
}
public TypeColorRegistration RegisterTypeColor(Plugin plugin, Type type, SKColor color)
{
if (plugin == null) throw new ArgumentNullException(nameof(plugin));
if (type == null) throw new ArgumentNullException(nameof(type));
return NodeTypeStore.AddColor(type, color, plugin);
}
private INode CreateNode(NodeEntity? entity, Type nodeType)
{
INode node = _kernel.Get(nodeType) as INode ?? throw new InvalidOperationException($"Node {nodeType} is not an INode");
@@ -72,20 +87,33 @@ namespace Artemis.Core.Services
}
/// <summary>
/// A service that provides access to the node system
/// A service that provides access to the node system
/// </summary>
public interface INodeService : IArtemisService
{
/// <summary>
/// Gets all available nodes
/// Gets all available nodes
/// </summary>
IEnumerable<NodeData> AvailableNodes { get; }
/// <summary>
/// Initializes a node of the provided <paramref name="nodeType"/>
/// Gets the best matching registration for the provided type
/// </summary>
TypeColorRegistration? GetTypeColor(Type type);
/// <summary>
/// Registers a node of the provided <paramref name="nodeType" />
/// </summary>
/// <param name="plugin">The plugin the node belongs to</param>
/// <param name="nodeType">The type of node to initialize</param>
NodeTypeRegistration RegisterNodeType(Plugin plugin, Type nodeType);
/// <summary>
/// Registers a type with a provided color for use in the node editor
/// </summary>
/// <param name="plugin">The plugin making the registration</param>
/// <param name="type">The type to associate the color with</param>
/// <param name="color">The color to display</param>
TypeColorRegistration RegisterTypeColor(Plugin plugin, Type type, SKColor color);
}
}
+50 -11
View File
@@ -1,12 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SkiaSharp;
namespace Artemis.Core
{
internal class NodeTypeStore
{
private static readonly List<NodeTypeRegistration> Registrations = new();
private static readonly List<TypeColorRegistration> ColorRegistrations = new();
public static NodeTypeRegistration Add(NodeData nodeData)
{
@@ -19,7 +21,7 @@ namespace Artemis.Core
if (Registrations.Any(r => r.NodeData == nodeData))
throw new ArtemisCoreException($"Data binding modifier type store already contains modifier '{nodeData.Name}'");
typeRegistration = new NodeTypeRegistration(nodeData, nodeData.Plugin) { IsInStore = true };
typeRegistration = new NodeTypeRegistration(nodeData, nodeData.Plugin) {IsInStore = true};
Registrations.Add(typeRegistration);
}
@@ -32,7 +34,7 @@ namespace Artemis.Core
lock (Registrations)
{
if (!Registrations.Contains(typeRegistration))
throw new ArtemisCoreException($"Data binding modifier type store does not contain modifier type '{typeRegistration.NodeData.Name}'");
throw new ArtemisCoreException($"Node type store does not contain modifier type '{typeRegistration.NodeData.Name}'");
Registrations.Remove(typeRegistration);
typeRegistration.IsInStore = false;
@@ -57,6 +59,51 @@ namespace Artemis.Core
}
}
public static Plugin? GetPlugin(INode node)
{
lock (Registrations)
{
return Registrations.FirstOrDefault(r => r.Plugin.GetType().Assembly == node.GetType().Assembly)?.Plugin;
}
}
public static TypeColorRegistration AddColor(Type type, SKColor color, Plugin plugin)
{
TypeColorRegistration typeColorRegistration;
lock (ColorRegistrations)
{
if (ColorRegistrations.Any(r => r.Type == type))
throw new ArtemisCoreException($"Node color store already contains a color for '{type.Name}'");
typeColorRegistration = new TypeColorRegistration(type, color, plugin) {IsInStore = true};
ColorRegistrations.Add(typeColorRegistration);
}
return typeColorRegistration;
}
public static void RemoveColor(TypeColorRegistration typeColorRegistration)
{
lock (ColorRegistrations)
{
if (!ColorRegistrations.Contains(typeColorRegistration))
throw new ArtemisCoreException($"Node color store does not contain modifier type '{typeColorRegistration.Type.Name}'");
ColorRegistrations.Remove(typeColorRegistration);
typeColorRegistration.IsInStore = false;
}
}
public static TypeColorRegistration? GetColor(Type type)
{
lock (ColorRegistrations)
{
return ColorRegistrations
.OrderByDescending(r => r.Type.ScoreCastability(type))
.FirstOrDefault(r => r.Type.ScoreCastability(type) > 0);
}
}
#region Events
public static event EventHandler<NodeTypeStoreEvent>? NodeTypeAdded;
@@ -73,13 +120,5 @@ namespace Artemis.Core
}
#endregion
public static Plugin? GetPlugin(INode node)
{
lock (Registrations)
{
return Registrations.FirstOrDefault(r => r.Plugin.GetType().Assembly == node.GetType().Assembly)?.Plugin;
}
}
}
}
}
@@ -1,9 +1,10 @@
using System;
using SkiaSharp;
namespace Artemis.Core
{
/// <summary>
/// Represents a registration for a type of <see cref="INode"/>
/// Represents a registration for a type of <see cref="INode" />
/// </summary>
public class NodeTypeRegistration
{
@@ -15,13 +16,16 @@ namespace Artemis.Core
Plugin.Disabled += OnDisabled;
}
/// <summary>
/// Gets the node data that was registered
/// </summary>
public NodeData NodeData { get; }
/// <summary>
/// Gets the plugin the node is associated with
/// </summary>
public Plugin Plugin { get; }
/// <summary>
/// Gets a boolean indicating whether the registration is in the internal Core store
/// </summary>
@@ -34,4 +38,51 @@ namespace Artemis.Core
NodeTypeStore.Remove(this);
}
}
/// <summary>
/// Represents a registration for a <see cref="SKColor" /> to associate with a certain <see cref="System.Type" />
/// </summary>
public class TypeColorRegistration
{
internal TypeColorRegistration(Type type, SKColor color, Plugin plugin)
{
Type = type;
Color = color;
Plugin = plugin;
Plugin.Disabled += OnDisabled;
}
/// <summary>
/// Gets the type
/// </summary>
public Type Type { get; }
/// <summary>
/// Gets the color
/// </summary>
public SKColor Color { get; }
/// <summary>
/// Gets a darkened tone of the <see cref="Color" />
/// </summary>
public SKColor DarkenedColor => Color.Darken(0.35f);
/// <summary>
/// Gets the plugin type color is associated with
/// </summary>
public Plugin Plugin { get; }
/// <summary>
/// Gets a boolean indicating whether the registration is in the internal Core store
/// </summary>
public bool IsInStore { get; internal set; }
private void OnDisabled(object? sender, EventArgs e)
{
Plugin.Disabled -= OnDisabled;
if (IsInStore)
NodeTypeStore.RemoveColor(this);
}
}
}