diff --git a/IPA.Loader/IPA.Loader.csproj b/IPA.Loader/IPA.Loader.csproj
index 33fa27fe..cd5b9ac6 100644
--- a/IPA.Loader/IPA.Loader.csproj
+++ b/IPA.Loader/IPA.Loader.csproj
@@ -62,6 +62,7 @@
+
diff --git a/IPA.Loader/Loader/Features/AddInFeature.cs b/IPA.Loader/Loader/Features/AddInFeature.cs
new file mode 100644
index 00000000..47cc9294
--- /dev/null
+++ b/IPA.Loader/Loader/Features/AddInFeature.cs
@@ -0,0 +1,21 @@
+namespace IPA.Loader.Features
+{
+ internal class AddInFeature : Feature
+ {
+ private PluginLoader.PluginMetadata selfMeta;
+
+ public override bool Initialize(PluginLoader.PluginMetadata meta, string[] parameters)
+ {
+ selfMeta = meta;
+
+ RequireLoaded(meta);
+
+ return true;
+ }
+
+ public override bool BeforeLoad(PluginLoader.PluginMetadata plugin)
+ {
+ return plugin != selfMeta;
+ }
+ }
+}
diff --git a/IPA.Loader/Loader/Features/DefineFeature.cs b/IPA.Loader/Loader/Features/DefineFeature.cs
index c2b30511..15fffad0 100644
--- a/IPA.Loader/Loader/Features/DefineFeature.cs
+++ b/IPA.Loader/Loader/Features/DefineFeature.cs
@@ -7,6 +7,8 @@ namespace IPA.Loader.Features
{
public static bool NewFeature = true;
+ internal override bool StoreOnPlugin => false;
+
public override bool Initialize(PluginLoader.PluginMetadata meta, string[] parameters)
{ // parameters should be (name, fully qualified type)
if (parameters.Length != 2)
diff --git a/IPA.Loader/Loader/Features/Feature.cs b/IPA.Loader/Loader/Features/Feature.cs
index 7f707732..ec84ec20 100644
--- a/IPA.Loader/Loader/Features/Feature.cs
+++ b/IPA.Loader/Loader/Features/Feature.cs
@@ -25,6 +25,14 @@ namespace IPA.Loader.Features
/// if the feature is valid for the plugin, otherwise
public abstract bool Initialize(PluginLoader.PluginMetadata meta, string[] parameters);
+ ///
+ /// Evaluates the Feature for use in conditional meta-Features. This should be re-calculated on every call, unless it can be proven to not change.
+ ///
+ /// This will be called on every feature that returns from
+ ///
+ /// the truthiness of the Feature.
+ public virtual bool Evaluate() => true;
+
///
/// The message to be logged when the feature is not valid for a plugin.
/// This should also be set whenever either or returns false.
@@ -61,11 +69,15 @@ namespace IPA.Loader.Features
/// the plugin to ensure is loaded.
protected void RequireLoaded(PluginLoader.PluginMetadata plugin) => PluginLoader.Load(plugin);
+ internal virtual bool StoreOnPlugin => true;
+
private static readonly Dictionary featureTypes = new Dictionary
{
{ "define-feature", typeof(DefineFeature) }
};
+ internal static bool HasFeature(string name) => featureTypes.ContainsKey(name);
+
internal static bool RegisterFeature(string name, Type type)
{
if (!typeof(Feature).IsAssignableFrom(type))
@@ -103,7 +115,7 @@ namespace IPA.Loader.Features
var parameters = new List();
bool escape = false;
- bool readingParams = false;
+ int parens = 0;
bool removeWhitespace = true;
foreach (var chr in featureString)
{
@@ -119,18 +131,20 @@ namespace IPA.Loader.Features
case '\\':
escape = true;
break;
- case '(' when !readingParams:
+ case '(':
+ parens++;
+ if (parens != 1) goto default;
removeWhitespace = true;
- readingParams = true;
name = builder.ToString();
builder.Clear();
break;
- case ')' when readingParams:
- readingParams = false;
+ case ')':
+ parens--;
+ if (parens != 0) goto default;
goto case ',';
case ',':
+ if (parens > 1) goto default;
parameters.Add(builder.ToString());
- if (!readingParams) break;
builder.Clear();
removeWhitespace = true;
break;
@@ -149,7 +163,7 @@ namespace IPA.Loader.Features
parsed = new FeatureParse(name, parameters.ToArray());
- if (readingParams)
+ if (parens != 0)
{
failException = new Exception("Malformed feature definition");
return false;
diff --git a/IPA.Loader/Loader/Features/PrintFeature.cs b/IPA.Loader/Loader/Features/PrintFeature.cs
index 52b03316..401a8e6f 100644
--- a/IPA.Loader/Loader/Features/PrintFeature.cs
+++ b/IPA.Loader/Loader/Features/PrintFeature.cs
@@ -11,4 +11,22 @@ namespace IPA.Loader.Features
return true;
}
}
+
+ internal class DebugFeature : Feature
+ {
+ public override bool Initialize(PluginLoader.PluginMetadata meta, string[] parameters)
+ {
+ Logger.features.Debug($"{meta.Name}: {string.Join(" ", parameters)}");
+ return true;
+ }
+ }
+
+ internal class WarnFeature : Feature
+ {
+ public override bool Initialize(PluginLoader.PluginMetadata meta, string[] parameters)
+ {
+ Logger.features.Debug($"{meta.Name}: {string.Join(" ", parameters)}");
+ return true;
+ }
+ }
}
diff --git a/IPA.Loader/Loader/PluginLoader.cs b/IPA.Loader/Loader/PluginLoader.cs
index 57e58dc6..62baf403 100644
--- a/IPA.Loader/Loader/PluginLoader.cs
+++ b/IPA.Loader/Loader/PluginLoader.cs
@@ -322,9 +322,9 @@ namespace IPA.Loader
feature.Item2.Value = parsed;
else if (success)
{
- if (valid)
+ if (valid && featureObj.StoreOnPlugin)
plugin.Item1.InternalFeatures.Add(featureObj);
- else
+ else if (!valid)
Logger.features.Warn(
$"Feature not valid on {plugin.Item1.Name}: {featureObj.InvalidMessage}");
plugin.Item2.RemoveAt(i--);
@@ -336,6 +336,10 @@ namespace IPA.Loader
plugin.Item2.RemoveAt(i--);
}
}
+
+ foreach (var plugin in PluginsMetadata)
+ foreach (var feature in plugin.Features)
+ feature.Evaluate();
}
foreach (var plugin in parsedFeatures)
diff --git a/IPA.Loader/Loader/manifest.json b/IPA.Loader/Loader/manifest.json
index 029b5189..26c2f1da 100644
--- a/IPA.Loader/Loader/manifest.json
+++ b/IPA.Loader/Loader/manifest.json
@@ -8,7 +8,10 @@
"version": "3.12.0",
"features": [
"define-feature(print, IPA.Loader.Features.PrintFeature)",
+ "define-feature(debug, IPA.Loader.Features.DebugFeature)",
+ "define-feature(warn, IPA.Loader.Features.WarnFeature)",
"define-feature(no-update, IPA.Loader.Features.NoUpdateFeature)",
+ "define-feature(add-in, IPA.Loader.Features.AddInFeature)",
"print(YO! Howz it goin\\, its ya boi desinc here)"
]
}
\ No newline at end of file