Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions MonkeyLoader/Components/Entity.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using MonkeyLoader.Meta.Tagging;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
Expand All @@ -12,14 +13,17 @@ namespace MonkeyLoader.Components
/// that <see cref="IComponent{TEntity}"/> instances can belong to.
/// </summary>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
public abstract class Entity<TEntity> : IEntity<TEntity>
public abstract class Entity<TEntity> : IEntity<TEntity>, ITaggable
where TEntity : Entity<TEntity>
{
/// <inheritdoc/>
public IComponentList<TEntity> Components { get; }

TEntity IEntity<TEntity>.Self => (TEntity)this;

/// <inheritdoc/>
public TagCollection Tags { get; } = [];

/// <summary>
/// Creates a new entity instance, using <c>this</c> as the
/// <see cref="IComponentList{TEntity}.Entity">Entity</see> for the
Expand Down
50 changes: 50 additions & 0 deletions MonkeyLoader/Configuration/ConfigAccessLevelTag.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using MonkeyLoader.Meta.Tagging;

namespace MonkeyLoader.Configuration
{
/// <summary>
/// Defines the possible access levels for config sections or their items.
/// </summary>
public enum ConfigAccessLevel
{
/// <summary>
/// The default level of access.<br/>
/// This config section or item should always be shown to users.
/// </summary>
Regular,

/// <summary>
/// Access for advanced users.<br/>
/// This config section or item should only be shown to advanced users.
/// </summary>
Advanced,

/// <summary>
/// Internal access of the mod only.<br/>
/// This config section or item should never be shown to users.
/// </summary>
Internal
}

/// <summary>
/// Defines the <see cref="ConfigAccessLevel"/> tag.
/// </summary>
/// <remarks>
/// This tag should be used for config sections or their items to define when or how they can be accessed.
/// </remarks>
public sealed class ConfigAccessLevelTag : DataTag<ConfigAccessLevel>
{
/// <inheritdoc/>
public override string Description => "Tags a config section or its items with an access level.";

/// <inheritdoc/>
public override string Id => nameof(ConfigAccessLevel);

/// <summary>
/// Creates a new instance of this tag with the given access <paramref name="level"/>.
/// </summary>
/// <param name="level">The access level to store.</param>
public ConfigAccessLevelTag(ConfigAccessLevel level) : base(level)
{ }
}
}
4 changes: 4 additions & 0 deletions MonkeyLoader/Configuration/ConfigKeyComponent.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using MonkeyLoader.Components;
using MonkeyLoader.Meta.Tagging;

namespace MonkeyLoader.Configuration
{
Expand All @@ -17,6 +18,9 @@ public static class ConfigKeyComponent
public static void Add<TKey>(this IEntity<TKey> configKey, IConfigKeyComponent<TKey> component)
where TKey : class, IDefiningConfigKey, IEntity<TKey>
=> configKey.Components.Add(component);

public static void Add(this IDefiningConfigKey configKey, ITag tag)
=> configKey.Tags.Add(tag);
}

/// <summary>
Expand Down
10 changes: 6 additions & 4 deletions MonkeyLoader/Configuration/DefiningConfigKey.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using System.Diagnostics.CodeAnalysis;
using MonkeyLoader.Meta;
using EnumerableToolkit;
using MonkeyLoader.Meta.Tagging;

namespace MonkeyLoader.Configuration
{
Expand Down Expand Up @@ -80,7 +81,7 @@ public bool HasChanges
public string Id => AsUntyped.Id;

/// <inheritdoc/>
public bool InternalAccessOnly { get; }
public bool InternalAccessOnly => (Tags[nameof(ConfigAccessLevel)].OfType<ConfigAccessLevelTag>().FirstOrDefault()?.Data ?? ConfigAccessLevel.Regular) is ConfigAccessLevel.Internal;

/// <inheritdoc/>
public bool IsDefiningKey => true;
Expand All @@ -89,10 +90,10 @@ public bool HasChanges

IIdentifiable INestedIdentifiable.Parent => Section;

/// <inheritdoc/>
/// <remarks>
/// Add a <see cref="IConfigKeyPriority">priority</see> component to this config key or set a value during initialization.
/// </remarks>
/// <inheritdoc/>
public int Priority
{
get => Components.TryGet<IConfigKeyPriority>(out var priorityComponent) ? priorityComponent.Priority : 0;
Expand Down Expand Up @@ -164,7 +165,8 @@ public DefiningConfigKey(string id, string? description = null, Func<T>? compute
if (valueValidator is not null)
Components.Add(new ConfigKeyValidator<T>(valueValidator));

InternalAccessOnly = internalAccessOnly;
if (internalAccessOnly)
Tags.Add(new ConfigAccessLevelTag(ConfigAccessLevel.Internal));

_canAlwaysHaveChanges = !ValueType.IsValueType
&& !(typeof(INotifyPropertyChanged).IsAssignableFrom(ValueType) || typeof(INotifyCollectionChanged).IsAssignableFrom(ValueType));
Expand Down Expand Up @@ -437,7 +439,7 @@ event ConfigKeyChangedEventHandler? IDefiningConfigKey.Changed
/// Defines the definition for a config item.
/// </summary>
public interface IDefiningConfigKey : ITypedConfigKey, IEntity<IDefiningConfigKey>,
INestedIdentifiable<ConfigSection>, IPrioritizable
INestedIdentifiable<ConfigSection>, IPrioritizable, ITaggable
{
/// <summary>
/// Gets the config this item belongs to.
Expand Down
5 changes: 3 additions & 2 deletions MonkeyLoader/Meta/IMonkey.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using HarmonyLib;
using MonkeyLoader.Configuration;
using MonkeyLoader.Logging;
using MonkeyLoader.Meta.Tagging;
using MonkeyLoader.Patching;
using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -35,7 +36,7 @@ public interface IEarlyMonkey : IMonkey
/// Defines the interface for all (<see cref="EarlyMonkey{TMonkey}">early</see>)
/// <see cref="Monkey{TMonkey}">monkeys</see>.
/// </summary>
public interface IMonkey : IRun, IShutdown, IComparable<IMonkey>, INestedIdentifiable<Mod>, IAuthorable
public interface IMonkey : IRun, IShutdown, IComparable<IMonkey>, INestedIdentifiable<Mod>, IAuthorable, ITaggable
{
/// <summary>
/// Gets the name of the assembly this monkey is defined in.
Expand Down Expand Up @@ -68,7 +69,7 @@ public interface IMonkey : IRun, IShutdown, IComparable<IMonkey>, INestedIdentif
public bool Enabled { get; set; }

/// <summary>
/// Gets the this monkey's <see cref="MonkeyTogglesConfigSection.GetToggle">toggle</see>
/// Gets the this monkey's <see cref="MonkeyTogglesConfigSection.GetToggle(IMonkey, Func{bool})">toggle</see>
/// if it <see cref="CanBeDisabled">can be disabled</see>.
/// </summary>
/// <value>The toggle config item if this monkey <see cref="CanBeDisabled">can be disabled</see>; otherwise, <c>null</c>.</value>
Expand Down
1 change: 0 additions & 1 deletion MonkeyLoader/Meta/Mod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ namespace MonkeyLoader.Meta
public abstract partial class Mod : IConfigOwner, IShutdown, ILoadedNuGetPackage, IComparable<Mod>,
INestedIdentifiableOwner<ConfigSection>, INestedIdentifiableOwner<IDefiningConfigKey>,
IIdentifiableOwner<Mod, IMonkey>, IIdentifiableOwner<Mod, IEarlyMonkey>, IAuthorable

{
/// <summary>
/// The file extension for mods' assemblies.
Expand Down
7 changes: 5 additions & 2 deletions MonkeyLoader/Meta/MonkeyTogglesConfigSection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace MonkeyLoader.Meta
/// </summary>
public sealed class MonkeyTogglesConfigSection : ExpandoConfigSection
{
private readonly Dictionary<IMonkey, IDefiningConfigKey<bool>> _togglesByMonkey = new();
private readonly Dictionary<IMonkey, IDefiningConfigKey<bool>> _togglesByMonkey = [];

/// <inheritdoc/>
public override string Description => "Contains toggles for the Monkeys of a mod which support disabling.";
Expand Down Expand Up @@ -44,8 +44,11 @@ internal MonkeyTogglesConfigSection(Mod mod)
public static ITypedConfigKey<bool> GetTemplateKey(IMonkey monkey)
=> new ConfigKey<bool>(monkey.Id);

/// <summary>
/// Gets or creates the toggle config item for the given (early) monkey.
/// </summary>
/// <remarks>
/// The default for toggles created with this method is <c>true</c>.
/// The default for toggles created with this method is always <c>true</c>.
/// </remarks>
/// <inheritdoc cref="GetToggle(IMonkey, Func{bool})"/>
public IDefiningConfigKey<bool> GetToggle(IMonkey monkey)
Expand Down
27 changes: 27 additions & 0 deletions MonkeyLoader/Meta/Tagging/DataTag.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace MonkeyLoader.Meta.Tagging
{
/// <summary>
/// Implements an abstract base class for any <see cref="IDataTag{T}"/>s.
/// </summary>
/// <typeparam name="T">The type of data associated with this tag type.</typeparam>
public abstract class DataTag<T> : Tag, IDataTag<T>
{
/// <inheritdoc/>
public T Data { get; }

object? IDataTag.Data => Data;

/// <summary>
/// Creates a new instance of this tag type storing the given <paramref name="data"/>.
/// </summary>
/// <param name="data">The data associated with this instance.</param>
protected DataTag(T data)
{
Data = data;
}

/// <inheritdoc/>
public override string ToString()
=> $"Data Tag: {Id} - {(Data is null ? "null" : Data.ToString())}";
}
}
38 changes: 38 additions & 0 deletions MonkeyLoader/Meta/Tagging/GenericTag.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;

namespace MonkeyLoader.Meta.Tagging
{
/// <summary>
/// Represents a generic tag that can have any <see cref="Id">Id</see> and <see cref="DataTag{T}.Data">Data</see>.
/// </summary>
/// <inheritdoc/>
public sealed class GenericTag<T> : DataTag<T>
{
private static readonly Dictionary<string, string> _descriptionsById = new(StringComparer.OrdinalIgnoreCase);

/// <inheritdoc/>
public override string Description { get; }

/// <inheritdoc/>
public override string Id { get; }

/// <summary>
/// Creates a new generic tag instance with the given <paramref name="id"/> and <paramref name="data"/>.
/// </summary>
/// <param name="id">The unique identifier of this type of tag.</param>
/// <param name="data">The data associated with this instance.</param>
public GenericTag(string id, T data) : base(data)
{
Id = id;

if (!_descriptionsById.TryGetValue(id, out var description))
{
description = $"GenericTag<{typeof(T).CompactDescription()}> with id: {id}";
_descriptionsById.Add(id.ToLower(), description);
}

Description = description;
}
}
}
24 changes: 24 additions & 0 deletions MonkeyLoader/Meta/Tagging/IDataTag.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace MonkeyLoader.Meta.Tagging
{
/// <summary>
/// Defines the non-generic interface for the data tags of <see cref="ITaggable"/>s.
/// </summary>
public interface IDataTag : ITag
{
/// <summary>
/// Gets the boxed data associated with this tag instance.
/// </summary>
public object? Data { get; }
}

/// <summary>
/// Defines the generic interface for the data tags of <see cref="ITaggable"/>s.
/// </summary>
public interface IDataTag<T> : IDataTag
{
/// <summary>
/// Gets the data associated with this tag instance.
/// </summary>
public new T Data { get; }
}
}
29 changes: 29 additions & 0 deletions MonkeyLoader/Meta/Tagging/ITag.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace MonkeyLoader.Meta.Tagging
{
/// <summary>
/// Defines the interface for the presence tags of <see cref="ITaggable"/>s.
/// </summary>
public interface ITag
{
/// <summary>
/// Gets the description for this type of tag.
/// </summary>
public string Description { get; }

/// <summary>
/// Gets the unique identifier of this type of tag.
/// </summary>
/// <remarks>
/// Case should be ignored when using this.
/// </remarks>
public string Id { get; }

/// <summary>
/// Gets the name for this type of tag.
/// </summary>
/// <remarks>
/// Implementations may default to the <see cref="Id">Id</see>.
/// </remarks>
public string Name { get; }
}
}
13 changes: 13 additions & 0 deletions MonkeyLoader/Meta/Tagging/ITaggable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace MonkeyLoader.Meta.Tagging
{
/// <summary>
/// Defines the interface for object that support tagging using <see cref="ITag"/>s.
/// </summary>
public interface ITaggable
{
/// <summary>
/// Gets the tags of this object.
/// </summary>
public TagCollection Tags { get; }
}
}
24 changes: 24 additions & 0 deletions MonkeyLoader/Meta/Tagging/Tag.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace MonkeyLoader.Meta.Tagging
{
/// <summary>
/// Implements an abstract base class for any <see cref="ITag"/>s.
/// </summary>
public abstract class Tag : ITag
{
/// <inheritdoc/>
public abstract string Description { get; }

/// <inheritdoc/>
public abstract string Id { get; }

/// <remarks>
/// <i>By default:</i> The <see cref="Id">Id</see> of this tag.
/// </remarks>
/// <inheritdoc/>
public virtual string Name => Id;

/// <inheritdoc/>
public override string ToString()
=> $"Presence Tag: {Id}";
}
}
Loading