Skip to content

Commit

Permalink
Start reworking plugin manager
Browse files Browse the repository at this point in the history
  • Loading branch information
Tides committed Dec 13, 2023
1 parent 6a671a7 commit fd841a5
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 20 deletions.
15 changes: 15 additions & 0 deletions Obsidian.API/Plugins/IPluginConfigurationManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Obsidian.API.Events;

namespace Obsidian.API.Plugins;
public interface IPluginConfigurationManager
{
public IPluginConfigurationManager MapCommands();
public IPluginConfigurationManager MapCommand(ContextDelegate<CommandContext> contextDelegate);

public IPluginConfigurationManager MapEvent<TEventArgs>(ContextDelegate<TEventArgs> contextDelegate, Priority priority = Priority.Low) where TEventArgs : BaseMinecraftEventArgs;
public IPluginConfigurationManager MapEvents();
}


//TODO better name maybe??
public delegate ValueTask ContextDelegate<TContext>(TContext context);
35 changes: 34 additions & 1 deletion Obsidian.API/Plugins/PluginBase.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.Extensions.DependencyInjection;
using Obsidian.API.Events;
using System.IO;

namespace Obsidian.API.Plugins;
Expand Down Expand Up @@ -28,7 +29,39 @@ public PluginBase()
/// Only services from the Server will be injected when this method is called. e.x (ILogger, IServerConfiguration).
/// Services registered through this method will be availiable/injected when <seealso cref="OnLoadAsync(IServer)"/> is called.
/// </remarks>
public virtual void Configure(IServiceCollection services) { }
public virtual void ConfigureServices(IServiceCollection services) { }

/// <summary>
/// Used for registering commands, events, blocks, items and entities.
/// </summary>
/// <param name="pluginConfiguration"></param>
/// <remarks>
/// Services from the Server will be injected when this method is called. e.x (ILogger, IServerConfiguration).
/// Services registered through this method will be availiable/injected when <seealso cref="OnLoadAsync(IServer)"/> is called.
/// </remarks>
public virtual void ConfigureRegistry(IPluginConfigurationManager pluginConfiguration)
{
//Will scan for command classes and register them for you
pluginConfiguration.MapCommands();

//Will scan for classes that inherit from MinecraftEventHandler
pluginConfiguration.MapEvents();

//Want to make a simple command?? Here you go
pluginConfiguration.MapCommand((CommandContext ctx) =>
{

return ValueTask.CompletedTask;
});

//Event doesn't need its own class? Here you go
pluginConfiguration.MapEvent((IncomingChatMessageEventArgs chat) =>
{

return ValueTask.CompletedTask;
});
}


/// <summary>
/// Called when the world has loaded and the server is joinable.
Expand Down
9 changes: 9 additions & 0 deletions Obsidian.API/_Enums/Priority.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Obsidian.API;

//TODO add more
public enum Priority
{
Low,

High
}
34 changes: 34 additions & 0 deletions Obsidian/Plugins/PluginConfigurationManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Microsoft.Extensions.DependencyInjection;
using Obsidian.API.Events;
using Obsidian.Plugins;

namespace Obsidian.API.Plugins;
public sealed class PluginConfigurationManager(PluginManager pluginManager) : IPluginConfigurationManager
{
private readonly PluginManager pluginManager = pluginManager;

public IPluginConfigurationManager MapCommands()
{

return this;
}

public IPluginConfigurationManager MapEvent<TEventArgs>(ContextDelegate<TEventArgs> contextDelegate, Priority priority = Priority.Low) where TEventArgs : BaseMinecraftEventArgs
{

return this;
}

public IPluginConfigurationManager MapCommand(ContextDelegate<CommandContext> contextDelegate)
{


return this;
}

public IPluginConfigurationManager MapEvents()
{

return this;
}
}
21 changes: 12 additions & 9 deletions Obsidian/Plugins/PluginManager.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Obsidian.API.Logging;
using Obsidian.API.Plugins;
using Obsidian.Commands.Framework;
using Obsidian.Events;
using Obsidian.Hosting;
Expand All @@ -26,8 +27,9 @@ public sealed class PluginManager
private readonly IServer server;

private readonly CommandHandler commands;

private IServiceCollection serviceCollection = new ServiceCollection();

private readonly PluginConfigurationManager pluginConfigurationManager;
private readonly IServiceCollection pluginServiceDescriptors = new ServiceCollection();

/// <summary>
/// List of all loaded plugins.
Expand Down Expand Up @@ -58,6 +60,7 @@ public PluginManager(IServiceProvider serverProvider, object eventSource, IServe
this.eventSource = eventSource;
this.commands = commands;
this.loggerProvider = new LoggerProvider(env.Configuration.LogLevel);
this.pluginConfigurationManager = new(this);

ConfigureInitialServices(env);

Expand All @@ -80,13 +83,13 @@ public PluginManager(IServiceProvider serverProvider, object eventSource, IServe

private void ConfigureInitialServices(IServerEnvironment env)
{
this.serviceCollection.AddLogging((builder) =>
this.pluginServiceDescriptors.AddLogging((builder) =>
{
builder.ClearProviders();
builder.AddProvider(this.loggerProvider);
builder.SetMinimumLevel(env.Configuration.LogLevel);
});
this.serviceCollection.AddSingleton<IServerConfiguration>(x => env.Configuration);
this.pluginServiceDescriptors.AddSingleton<IServerConfiguration>(x => env.Configuration);
}

/// <summary>
Expand Down Expand Up @@ -149,10 +152,10 @@ private void ConfigureInitialServices(IServerEnvironment env)
plugins.Add(pluginContainer);
}

pluginContainer.Plugin.Configure(serviceCollection);
pluginContainer.Plugin.ConfigureServices(this.pluginServiceDescriptors);

//TODO move this so this is called by the plugin and not the manager.
this.commands.RegisterCommands(pluginContainer);
//this.commands.RegisterCommands(pluginContainer);

pluginContainer.Loaded = true;
ExposePluginAsDependency(pluginContainer);
Expand Down Expand Up @@ -220,7 +223,7 @@ public async Task UnloadPluginAsync(PluginContainer pluginContainer)

public void ServerReady()
{
PluginServiceProvider ??= this.serviceCollection.BuildServiceProvider(true);
PluginServiceProvider ??= this.pluginServiceDescriptors.BuildServiceProvider(true);
foreach(var pluginContainer in this.plugins)
{
if (!pluginContainer.Loaded)
Expand Down Expand Up @@ -255,11 +258,11 @@ private void OnPluginSourceRenamed(string oldSource, string newSource)
renamedPlugin.Source = newSource;
}

private void OnPluginSourceDeleted(string path)
private async void OnPluginSourceDeleted(string path)
{
var deletedPlugin = plugins.FirstOrDefault(plugin => plugin.Source == path) ?? stagedPlugins.FirstOrDefault(plugin => plugin.Source == path);
if (deletedPlugin != null)
UnloadPluginAsync(deletedPlugin);
await UnloadPluginAsync(deletedPlugin);
}

private void StageRunning(PluginContainer plugin)
Expand Down
3 changes: 0 additions & 3 deletions Obsidian/Server.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,6 @@ public Server(
}
}

public void RegisterCommandClass<T>(PluginContainer plugin, T instance) =>
CommandsHandler.RegisterCommandClass<T>(plugin, instance);

public void RegisterArgumentHandler<T>(T parser) where T : BaseArgumentParser =>
CommandsHandler.AddArgumentParser(parser);

Expand Down
29 changes: 22 additions & 7 deletions SamplePlugin/SamplePlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,40 @@ public class SamplePlugin : PluginBase
// Dependencies will be injected automatically, if dependency class and field/property names match
// Plugins won't load until all their required dependencies are added
// Optional dependencies may be injected at any time, if at all
[Inject]
[Inject]
public ILogger<SamplePlugin> Logger { get; set; }

//You can register services here if you'd like
public override void Configure(IServiceCollection services) { }
//You can register services, commands and events here if you'd like
public override void ConfigureServices(IServiceCollection services) { }

//Called when the world has loaded and the server is ready for connections
public override ValueTask OnLoadAsync(IServer server)

//YOu can register commands, events and soon to be items, blocks entities
public override void ConfigureRegistry(IPluginConfigurationManager pluginConfiguration)
{
//Will scan for command classes and register them for you
pluginConfiguration.MapCommands();

//Will scan for classes that inherit from MinecraftEventHandler
server.MapEvents();
pluginConfiguration.MapEvents();

//Want to make a simple command?? Here you go
pluginConfiguration.MapCommand((CommandContext ctx) =>
{

return ValueTask.CompletedTask;
});

//Event doesn't need its own class? Here you go
server.MapEvent((IncomingChatMessageEventArgs chat) =>
pluginConfiguration.MapEvent((IncomingChatMessageEventArgs chat) =>
{

return ValueTask.CompletedTask;
});
}

//Called when the world has loaded and the server is ready for connections
public override ValueTask OnLoadAsync(IServer server)
{
Logger.LogInformation("§a{pluginName} §floaded! Hello §aEveryone§f!", Info.Name);
return ValueTask.CompletedTask;
}
Expand Down

0 comments on commit fd841a5

Please sign in to comment.