207 lines
6.3 KiB
C#
207 lines
6.3 KiB
C#
using System.Collections;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using PkmnLib.Dynamic.ScriptHandling.Registry;
|
|
using PkmnLib.Static.Utils;
|
|
|
|
namespace PkmnLib.Dynamic.ScriptHandling;
|
|
|
|
/// <summary>
|
|
/// A script set is a collection of scripts that can be accessed by a key.
|
|
/// We can add, remove, and clear scripts from the set.
|
|
/// This is generally used for volatile scripts.
|
|
/// </summary>
|
|
public interface IScriptSet : IEnumerable<ScriptContainer>, IDeepCloneable
|
|
{
|
|
/// <summary>
|
|
/// Adds a script to the set. If the script with that name already exists in this set, this
|
|
/// makes that script stack instead. The return value here is that script.
|
|
/// If the script was blocked from being added, this will return null.
|
|
/// </summary>
|
|
/// <param name="script">The script to add.</param>
|
|
/// <param name="forceAdd">If true, the script cannot be blocked, and will always be added</param>
|
|
ScriptContainer? Add(Script script, bool forceAdd = false);
|
|
|
|
/// <summary>
|
|
/// Adds a script with a name to the set. If the script with that name already exists in this
|
|
/// set, this makes that script stack instead. The return value here is that script.
|
|
/// </summary>
|
|
ScriptContainer? StackOrAdd(StringKey scriptKey, Func<Script?> instantiation);
|
|
|
|
/// <summary>
|
|
/// Gets a script from the set using its unique name.
|
|
/// </summary>
|
|
ScriptContainer? Get(StringKey scriptKey);
|
|
|
|
/// <summary>
|
|
/// Tries to get a script from the set using its type.
|
|
/// </summary>
|
|
bool TryGet<T>([NotNullWhen(true)] out T? script) where T : Script;
|
|
|
|
/// <summary>
|
|
/// Gets a script from the set using its type.
|
|
/// </summary>
|
|
T? Get<T>() where T : Script;
|
|
|
|
/// <summary>
|
|
/// Removes a script from the set using its unique name.
|
|
/// </summary>
|
|
void Remove(StringKey scriptKey);
|
|
|
|
/// <summary>
|
|
/// Removes a script from the set using its type.
|
|
/// </summary>
|
|
void Remove<T>() where T : Script => Remove(ScriptUtils.ResolveName<T>());
|
|
|
|
/// <summary>
|
|
/// Clears all scripts from the set.
|
|
/// </summary>
|
|
void Clear();
|
|
|
|
/// <summary>
|
|
/// Checks if the set has a script with the given type.
|
|
/// </summary>
|
|
bool Contains<T>() where T : Script => Contains(ScriptUtils.ResolveName<T>());
|
|
|
|
/// <summary>
|
|
/// Checks if the set has a script with the given name.
|
|
/// </summary>
|
|
bool Contains(StringKey scriptKey);
|
|
|
|
/// <summary>
|
|
/// Gets a script from the set at a specific index.
|
|
/// </summary>
|
|
ScriptContainer At(int index);
|
|
|
|
/// <summary>
|
|
/// Gets the number of scripts in the set.
|
|
/// </summary>
|
|
int Count { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the names of all scripts in the set.
|
|
/// </summary>
|
|
IEnumerable<StringKey> GetScriptNames();
|
|
}
|
|
|
|
/// <inheritdoc cref="IScriptSet"/>
|
|
public class ScriptSet : IScriptSet
|
|
{
|
|
private readonly IScriptSource _source;
|
|
|
|
private readonly List<ScriptContainer> _scripts = [];
|
|
|
|
/// <inheritdoc cref="IScriptSet"/>
|
|
public ScriptSet(IScriptSource source)
|
|
{
|
|
_source = source;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public IEnumerator<ScriptContainer> GetEnumerator() => _scripts.GetEnumerator();
|
|
|
|
/// <inheritdoc />
|
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
|
|
/// <inheritdoc />
|
|
public ScriptContainer? Add(Script script, bool forceAdd = false)
|
|
{
|
|
if (!forceAdd)
|
|
{
|
|
var preventVolatileAdd = false;
|
|
_source.RunScriptHook(x => x.PreventVolatileAdd(_source, script, ref preventVolatileAdd));
|
|
if (preventVolatileAdd)
|
|
return null;
|
|
}
|
|
|
|
var existing = _scripts.FirstOrDefault(s => s.Script?.Name == script.Name);
|
|
if (existing != null)
|
|
{
|
|
if (existing.Script is IScriptStack stackable)
|
|
stackable.Stack();
|
|
return existing;
|
|
}
|
|
|
|
script.OnRemoveEvent += s => Remove(s.Name);
|
|
var container = new ScriptContainer(script);
|
|
_scripts.Add(container);
|
|
script.OnAddedToParent(_source);
|
|
return container;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public ScriptContainer? StackOrAdd(StringKey scriptKey, Func<Script?> instantiation)
|
|
{
|
|
var existing = _scripts.FirstOrDefault(s => s.Script?.Name == scriptKey);
|
|
if (existing != null)
|
|
{
|
|
if (existing.Script is IScriptStack stackable)
|
|
stackable.Stack();
|
|
return existing;
|
|
}
|
|
|
|
var script = instantiation();
|
|
if (script is null)
|
|
return null;
|
|
script.OnRemoveEvent += s => Remove(s.Name);
|
|
var container = new ScriptContainer(script);
|
|
_scripts.Add(container);
|
|
script.OnAddedToParent(_source);
|
|
return container;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public ScriptContainer? Get(StringKey scriptKey) => _scripts.FirstOrDefault(s => s.Script?.Name == scriptKey);
|
|
|
|
/// <inheritdoc />
|
|
public bool TryGet<T>([NotNullWhen(true)] out T? script) where T : Script
|
|
{
|
|
var scriptName = ScriptUtils.ResolveName<T>();
|
|
var container = _scripts.FirstOrDefault(sc => sc.Script?.Name == scriptName);
|
|
if (container?.Script is not T s)
|
|
{
|
|
script = null;
|
|
return false;
|
|
}
|
|
script = s;
|
|
return true;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public T? Get<T>() where T : Script => Get(ScriptUtils.ResolveName<T>())?.Script as T;
|
|
|
|
/// <inheritdoc />
|
|
public void Remove(StringKey scriptKey)
|
|
{
|
|
var script = _scripts.FirstOrDefault(s => s.Script?.Name == scriptKey);
|
|
if (script is null)
|
|
return;
|
|
script.Script?.OnRemove();
|
|
script.Clear();
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void Clear()
|
|
{
|
|
foreach (var script in _scripts)
|
|
{
|
|
if (!script.IsEmpty)
|
|
{
|
|
script.Script.OnRemove();
|
|
}
|
|
}
|
|
_scripts.Clear();
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public bool Contains(StringKey scriptKey) => _scripts.Any(s => s.Script?.Name == scriptKey);
|
|
|
|
/// <inheritdoc />
|
|
public ScriptContainer At(int index) => _scripts[index];
|
|
|
|
/// <inheritdoc />
|
|
public int Count => _scripts.Count;
|
|
|
|
/// <inheritdoc />
|
|
public IEnumerable<StringKey> GetScriptNames() =>
|
|
_scripts.Select(x => x.Script).WhereNotNull().Select(s => s.Name);
|
|
} |