Begin work on outlining dynamic side

This commit is contained in:
2024-07-27 16:26:45 +02:00
parent 1b501dee7e
commit a251913ebd
44 changed files with 2150 additions and 19 deletions

View File

@@ -0,0 +1,23 @@
namespace PkmnLib.Dynamic.ScriptHandling.Registry;
/// <summary>
/// A plugin is a way to register scripts and other dynamic components to the script registry.
/// </summary>
public abstract class Plugin
{
/// <summary>
/// The name of the plugin. Mostly used for debugging purposes.
/// </summary>
public abstract string Name { get; }
/// <summary>
/// When the plugin should be loaded. Lower values are loaded first.
/// 0 should be reserved for the core battle scripts.
/// </summary>
public abstract uint LoadOrder { get; }
/// <summary>
/// Run the registration of the plugin when we're building the library.
/// </summary>
public abstract void Register(ScriptRegistry registry);
}

View File

@@ -0,0 +1,14 @@
namespace PkmnLib.Dynamic.ScriptHandling;
[AttributeUsage(AttributeTargets.Class)]
public class ScriptAttribute : Attribute
{
public ScriptCategory Category { get; }
public string Name { get; }
public ScriptAttribute(ScriptCategory category, string name)
{
Category = category;
Name = name;
}
}

View File

@@ -0,0 +1,56 @@
using System.Linq.Expressions;
using System.Reflection;
using PkmnLib.Dynamic.Libraries;
namespace PkmnLib.Dynamic.ScriptHandling;
public class ScriptRegistry
{
private Dictionary<(ScriptCategory category, string name), Func<Script>> _scriptTypes = new();
private IBattleStatCalculator? _battleStatCalculator;
private IDamageCalculator? _damageCalculator;
private IMiscLibrary? _miscLibrary;
public void RegisterAssemblyScripts(Assembly assembly)
{
var baseType = typeof(Script);
foreach (var type in assembly.GetTypes().Where(t => baseType.IsAssignableFrom(t)))
{
var attribute = type.GetCustomAttribute<ScriptAttribute>();
if (attribute == null)
continue;
RegisterScriptType(attribute.Category, attribute.Name, type);
}
}
public void RegisterScriptType(ScriptCategory category, string name, Type type)
{
if (name == null)
throw new ArgumentNullException(nameof(name));
if (type == null)
throw new ArgumentNullException(nameof(type));
var constructor = type.GetConstructor(Type.EmptyTypes);
if (constructor == null)
throw new ArgumentException("The type must have a parameterless constructor.");
// We create a lambda that creates a new instance of the script type.
// This is more performant than using Activator.CreateInstance.
_scriptTypes[(category, name)] = Expression.Lambda<Func<Script>>(Expression.New(constructor)).Compile();
}
public void RegisterBattleStatCalculator<T>(T battleStatCalculator)
where T : IBattleStatCalculator => _battleStatCalculator = battleStatCalculator;
public void RegisterDamageCalculator<T>(T damageCalculator)
where T : IDamageCalculator => _damageCalculator = damageCalculator;
public void RegisterMiscLibrary<T>(T miscLibrary) where T : IMiscLibrary
=> _miscLibrary = miscLibrary;
internal Dictionary<(ScriptCategory category, string name), Func<Script>> ScriptTypes => _scriptTypes;
internal IBattleStatCalculator? BattleStatCalculator => _battleStatCalculator;
internal IDamageCalculator? DamageCalculator => _damageCalculator;
internal IMiscLibrary? MiscLibrary => _miscLibrary;
}