diff --git a/Penumbra/API/ModsController.cs b/Penumbra/API/ModsController.cs new file mode 100644 index 00000000..4d3d0cc2 --- /dev/null +++ b/Penumbra/API/ModsController.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using System.Linq; +using EmbedIO; +using EmbedIO.Routing; +using EmbedIO.WebApi; + +namespace Penumbra.API +{ + public class ModsController : WebApiController + { + private readonly Plugin _plugin; + + public ModsController( Plugin plugin ) + { + _plugin = plugin; + } + + [Route( HttpVerbs.Get, "/mods" )] + public object GetMods() + { + return _plugin.ModManager.Mods.ModSettings.Select( x => new + { + x.Enabled, + x.Priority, + x.FolderName, + x.Mod.Meta, + BasePath = x.Mod.ModBasePath.FullName, + Files = x.Mod.ModFiles.Select( x => x.FullName ) + } ); + } + + [Route( HttpVerbs.Get, "/files" )] + public object CreateMod() + { + return _plugin.ModManager.ResolvedFiles.ToDictionary( + o => o.Key, + o => o.Value.FullName + ); + } + } +} \ No newline at end of file diff --git a/Penumbra/Configuration.cs b/Penumbra/Configuration.cs index 7a7d50b2..0641f286 100644 --- a/Penumbra/Configuration.cs +++ b/Penumbra/Configuration.cs @@ -16,6 +16,8 @@ namespace Penumbra public bool DisableFileSystemNotifications { get; set; } = false; + public bool EnableHttpApi { get; set; } = false; + public string CurrentCollection { get; set; } = @"D:/ffxiv/fs_mods/"; public List< string > ModCollections { get; set; } = new(); diff --git a/Penumbra/Mods/ModManager.cs b/Penumbra/Mods/ModManager.cs index dc19677b..14a2c0d1 100644 --- a/Penumbra/Mods/ModManager.cs +++ b/Penumbra/Mods/ModManager.cs @@ -7,6 +7,7 @@ namespace Penumbra.Mods { public class ModManager : IDisposable { + private readonly Plugin _plugin; public readonly Dictionary< string, FileInfo > ResolvedFiles = new(); public readonly Dictionary< string, string > SwappedFiles = new(); @@ -14,6 +15,11 @@ namespace Penumbra.Mods private DirectoryInfo _basePath; + public ModManager( Plugin plugin ) + { + _plugin = plugin; + } + public void DiscoverMods() { if( _basePath == null ) @@ -92,6 +98,9 @@ namespace Penumbra.Mods Mods.Save(); CalculateEffectiveFileList(); + + // Needed to reload body textures with mods + _plugin.GameUtils.ReloadPlayerResources(); } public void CalculateEffectiveFileList() diff --git a/Penumbra/Penumbra.csproj b/Penumbra/Penumbra.csproj index 5d64ff8a..c1d746af 100644 --- a/Penumbra/Penumbra.csproj +++ b/Penumbra/Penumbra.csproj @@ -56,6 +56,7 @@ + diff --git a/Penumbra/Plugin.cs b/Penumbra/Plugin.cs index 44d9d4ed..2c0d101b 100644 --- a/Penumbra/Plugin.cs +++ b/Penumbra/Plugin.cs @@ -1,5 +1,9 @@ using Dalamud.Game.Command; using Dalamud.Plugin; +using EmbedIO; +using EmbedIO.Actions; +using EmbedIO.WebApi; +using Penumbra.API; using Penumbra.Game; using Penumbra.Mods; using Penumbra.UI; @@ -13,7 +17,7 @@ namespace Penumbra private const string CommandName = "/penumbra"; public DalamudPluginInterface PluginInterface { get; set; } - + public Configuration Configuration { get; set; } public ResourceLoader ResourceLoader { get; set; } @@ -26,18 +30,18 @@ namespace Penumbra public string PluginDebugTitleStr { get; private set; } - public bool ImportInProgress => SettingsInterface?.IsImportRunning ?? true; + private WebServer _webServer; public void Initialize( DalamudPluginInterface pluginInterface ) { PluginInterface = pluginInterface; - + Configuration = PluginInterface.GetPluginConfig() as Configuration ?? new Configuration(); Configuration.Initialize( PluginInterface ); GameUtils = new GameUtils( PluginInterface ); - ModManager = new ModManager(); + ModManager = new ModManager( this ); ModManager.DiscoverMods( Configuration.CurrentCollection ); ResourceLoader = new ResourceLoader( this ); @@ -50,13 +54,39 @@ namespace Penumbra ResourceLoader.Init(); ResourceLoader.Enable(); - // Needed to reload body textures with mods - GameUtils.ReloadPlayerResources(); - SettingsInterface = new SettingsInterface( this ); PluginInterface.UiBuilder.OnBuildUi += SettingsInterface.Draw; PluginDebugTitleStr = $"{Name} - Debug Build"; + + if( Configuration.EnableHttpApi ) + { + CreateWebServer(); + } + } + + public void CreateWebServer() + { + var prefix = "http://localhost:45800/"; + + ShutdownWebServer(); + + _webServer = new WebServer( o => o + .WithUrlPrefix( prefix ) + .WithMode( HttpListenerMode.EmbedIO ) ) + .WithCors( prefix ) + .WithWebApi( "/api", m => m + .WithController( () => new ModsController( this ) ) ); + + _webServer.StateChanged += ( s, e ) => PluginLog.Information( $"WebServer New State - {e.NewState}" ); + + _webServer.RunAsync(); + } + + public void ShutdownWebServer() + { + _webServer?.Dispose(); + _webServer = null; } public void Dispose() @@ -69,6 +99,8 @@ namespace Penumbra PluginInterface.Dispose(); ResourceLoader.Dispose(); + + ShutdownWebServer(); } private void OnCommand( string command, string rawArgs ) @@ -94,4 +126,4 @@ namespace Penumbra SettingsInterface.Visible = !SettingsInterface.Visible; } } -} +} \ No newline at end of file diff --git a/Penumbra/UI/SettingsInterface.cs b/Penumbra/UI/SettingsInterface.cs index 01db3657..88b4242f 100644 --- a/Penumbra/UI/SettingsInterface.cs +++ b/Penumbra/UI/SettingsInterface.cs @@ -299,6 +299,22 @@ namespace Penumbra.UI dirty = true; } + var http = _plugin.Configuration.EnableHttpApi; + if( ImGui.Checkbox( "Enable HTTP API", ref http ) ) + { + if( http ) + { + _plugin.CreateWebServer(); + } + else + { + _plugin.ShutdownWebServer(); + } + + _plugin.Configuration.EnableHttpApi = http; + dirty = true; + } + if( ImGui.Button( "Reload Player Resource" ) ) { _plugin.GameUtils.ReloadPlayerResources();