From 4744106b0d9c9efb5b7e73ea46b00fb9502b78cf Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Mon, 6 Feb 2023 16:15:52 -0800 Subject: [PATCH 01/28] WIP dependency manager --- src/Interface/Tabs/DependencyManager.as | 89 +++++++++++++++++++++++++ src/Interface/Tabs/Search.as | 20 +++++- src/Interface/Window.as | 1 + 3 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 src/Interface/Tabs/DependencyManager.as diff --git a/src/Interface/Tabs/DependencyManager.as b/src/Interface/Tabs/DependencyManager.as new file mode 100644 index 0000000..a80476f --- /dev/null +++ b/src/Interface/Tabs/DependencyManager.as @@ -0,0 +1,89 @@ +class DependencyManagerTab : Tab +{ + + string GetLabel() override { return "Dependencies"; } + + vec4 GetColor() override { return vec4(0, 0.6f, 0.2f, 1); } + + void RenderEmpty() + { + } + + void Render() override + { + + Meta::Plugin@[] loaded = Meta::AllPlugins(); + for (uint i = 0; i < loaded.Length; i++) { + Meta::Plugin@ v = loaded[i]; + + if (v.Dependencies.Length == 0 && v.OptionalDependencies.Length == 0) { + continue; + } else { + string[] inChain; + DepLeaf(v, inChain, true, false); + } + } + } + + void DepLeaf(Meta::Plugin@ plugin, string[]@ inChain, bool topLevel, bool isOptional) + { + if (plugin.Dependencies.Length == 0 && plugin.OptionalDependencies.Length == 0) { + _DepLeafNoChilds(plugin, isOptional); + return; + } + + int flags = topLevel ? UI::TreeNodeFlags::DefaultOpen : UI::TreeNodeFlags::None; + if (UI::TreeNode(_GetPluginTitleString(plugin, isOptional), flags)) { + if (inChain.Find(plugin.ID) >= 0) { + UI::TreeAdvanceToLabelPos(); + UI::Text("Circular dependency detected..."); + UI::TreePop(); + return; + } + inChain.InsertLast(plugin.ID); + + for (uint i = 0; i < plugin.Dependencies.Length; i++) { + _DepLeaf(plugin.Dependencies[i], inChain, false); + } + for (uint i = 0; i < plugin.OptionalDependencies.Length; i++) { + _DepLeaf(plugin.OptionalDependencies[i], inChain, true); + } + UI::TreePop(); + } + } + + void _DepLeafNoChilds(Meta::Plugin@ plugin, bool isOptional) + { + UI::TreeAdvanceToLabelPos(); + UI::Text(_GetPluginTitleString(plugin, isOptional)); + } + + string _GetPluginTitleString(Meta::Plugin@ plugin, bool isOptional) { + string name = plugin.Name; + if (isOptional) { + name = "\\$666" + name; + } + name += " by " + plugin.Author + " (v" + plugin.Version + ")"; + return name; + } + + void _DepLeaf(const string &in dep, string[]@ inChain, bool isOptional) + { + Meta::Plugin@ child = Meta::GetPluginFromID(dep); + if (child !is null) { + DepLeaf(child, inChain, false, isOptional); + } else { + string name = dep; + if (isOptional) { + name = "\\$666" + name; + } + UI::TreeAdvanceToLabelPos(); + UI::Text(name + " \\$f00(not installed)\\$z"); + UI::SameLine(); + if (UI::Button("Info###"+dep, vec2(0, UI::GetTextLineHeight()))) { + // todo: is there a better way to do this? search by ident instead of siteID would be gr8 + g_window.AddTab(SearchTab(dep), true); + } + } + } +} diff --git a/src/Interface/Tabs/Search.as b/src/Interface/Tabs/Search.as index 779c3c2..4021dba 100644 --- a/src/Interface/Tabs/Search.as +++ b/src/Interface/Tabs/Search.as @@ -1,9 +1,27 @@ class SearchTab : PluginListTab { string m_search; + bool m_closable = false; uint64 m_typingStart; - string GetLabel() override { return Icons::Search + " Search###Search"; } + SearchTab() {} + SearchTab(const string &in ident) + { + m_search = ident; + m_closable = true; + StartRequest(); + } + + bool CanClose() override { return m_closable; } + + string GetLabel() override + { + if (m_closable) { + return Icons::Search + " " + m_search + "###Search"; + } else { + return Icons::Search + " Search###Search"; + } + } void GetRequestParams(dictionary@ params) override { diff --git a/src/Interface/Window.as b/src/Interface/Window.as index 03a8a6e..2f2d466 100644 --- a/src/Interface/Window.as +++ b/src/Interface/Window.as @@ -9,6 +9,7 @@ class Window Window() { AddTab(UpdatesTab()); + AddTab(DependencyManagerTab()); AddTab(InstalledTab()); AddTab(FeaturedTab()); From 385b099cd36cce20636358fea108d13040a07304 Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Mon, 6 Feb 2023 20:48:02 -0800 Subject: [PATCH 02/28] pull plugin list on startup to get ident <=> siteid conversion --- src/Interface/Tabs/DependencyManager.as | 12 ++++++++++-- src/Interface/Tabs/Search.as | 20 +------------------- src/Utils/API.as | 22 ++++++++++++++++++++++ src/main.as | 5 +++++ 4 files changed, 38 insertions(+), 21 deletions(-) diff --git a/src/Interface/Tabs/DependencyManager.as b/src/Interface/Tabs/DependencyManager.as index a80476f..b5bcf80 100644 --- a/src/Interface/Tabs/DependencyManager.as +++ b/src/Interface/Tabs/DependencyManager.as @@ -81,9 +81,17 @@ class DependencyManagerTab : Tab UI::Text(name + " \\$f00(not installed)\\$z"); UI::SameLine(); if (UI::Button("Info###"+dep, vec2(0, UI::GetTextLineHeight()))) { - // todo: is there a better way to do this? search by ident instead of siteID would be gr8 - g_window.AddTab(SearchTab(dep), true); + g_window.AddTab(PluginTab(PluginIdentToSiteID(dep)), true); } } } + + int PluginIdentToSiteID(const string &in ident) { + for (uint i = 0; i < g_cachedAPIPluginList.Length; i++) { + if (g_cachedAPIPluginList[i]["identifier"] == ident) { + return g_cachedAPIPluginList[i]["id"]; + } + } + return -1; + } } diff --git a/src/Interface/Tabs/Search.as b/src/Interface/Tabs/Search.as index 4021dba..779c3c2 100644 --- a/src/Interface/Tabs/Search.as +++ b/src/Interface/Tabs/Search.as @@ -1,27 +1,9 @@ class SearchTab : PluginListTab { string m_search; - bool m_closable = false; uint64 m_typingStart; - SearchTab() {} - SearchTab(const string &in ident) - { - m_search = ident; - m_closable = true; - StartRequest(); - } - - bool CanClose() override { return m_closable; } - - string GetLabel() override - { - if (m_closable) { - return Icons::Search + " " + m_search + "###Search"; - } else { - return Icons::Search + " Search###Search"; - } - } + string GetLabel() override { return Icons::Search + " Search###Search"; } void GetRequestParams(dictionary@ params) override { diff --git a/src/Utils/API.as b/src/Utils/API.as index b91f33b..a2d2e6f 100644 --- a/src/Utils/API.as +++ b/src/Utils/API.as @@ -24,4 +24,26 @@ namespace API } return Json::Parse(req.String()); } + + Json::Value@[] GetPluginListAsync() { + uint pages = 1; + + Json::Value@[] plugs; + + for (uint i = 0; i < pages; i++) { + Json::Value req = GetAsync("plugins?page=" + i); + + if (pages == 1 && req["pages"] != 1) { + pages = req["pages"]; + } + + for (uint ii = 0; ii < req["items"].Length; ii++) { + plugs.InsertLast(req["items"][ii]); + } + + // nap a bit so we dont wreck the Openplanet API... + sleep(500); + } + return plugs; + } } diff --git a/src/main.as b/src/main.as index 5384c89..7db8e83 100644 --- a/src/main.as +++ b/src/main.as @@ -1,4 +1,5 @@ UI::Font@ g_fontHeader; +Json::Value@[] g_cachedAPIPluginList; void Main() { @@ -11,11 +12,15 @@ void Main() // Start checking for updates immediately CheckForUpdatesAsyncStartUp(); + // load a list of plugins from the API for later use... + g_cachedAPIPluginList = API::GetPluginListAsync(); + // Every 30 minutes, check for updates again while (true) { sleep(30 * 60 * 1000); if (Setting_AutoCheckUpdates) { CheckForUpdatesAsync(); + g_cachedAPIPluginList = API::GetPluginListAsync(); } } } From 863efabae15c80be5641b87e725b23f307e07ba1 Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Mon, 6 Feb 2023 21:04:04 -0800 Subject: [PATCH 03/28] clean up dependency view --- src/Interface/Tabs/DependencyManager.as | 31 ++++++++++++++++++------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/Interface/Tabs/DependencyManager.as b/src/Interface/Tabs/DependencyManager.as index b5bcf80..a7f4876 100644 --- a/src/Interface/Tabs/DependencyManager.as +++ b/src/Interface/Tabs/DependencyManager.as @@ -28,12 +28,12 @@ class DependencyManagerTab : Tab void DepLeaf(Meta::Plugin@ plugin, string[]@ inChain, bool topLevel, bool isOptional) { if (plugin.Dependencies.Length == 0 && plugin.OptionalDependencies.Length == 0) { - _DepLeafNoChilds(plugin, isOptional); + _DepLeafNoChilds(plugin, isOptional, topLevel); return; } int flags = topLevel ? UI::TreeNodeFlags::DefaultOpen : UI::TreeNodeFlags::None; - if (UI::TreeNode(_GetPluginTitleString(plugin, isOptional), flags)) { + if (UI::TreeNode(_GetPluginTitleString(plugin, isOptional, topLevel), flags)) { if (inChain.Find(plugin.ID) >= 0) { UI::TreeAdvanceToLabelPos(); UI::Text("Circular dependency detected..."); @@ -52,18 +52,21 @@ class DependencyManagerTab : Tab } } - void _DepLeafNoChilds(Meta::Plugin@ plugin, bool isOptional) + void _DepLeafNoChilds(Meta::Plugin@ plugin, bool isOptional, bool isTopLevel) { UI::TreeAdvanceToLabelPos(); - UI::Text(_GetPluginTitleString(plugin, isOptional)); + UI::Text(_GetPluginTitleString(plugin, isOptional, isTopLevel)); } - string _GetPluginTitleString(Meta::Plugin@ plugin, bool isOptional) { + string _GetPluginTitleString(Meta::Plugin@ plugin, bool isOptional, bool isTopLevel) { string name = plugin.Name; if (isOptional) { name = "\\$666" + name; } - name += " by " + plugin.Author + " (v" + plugin.Version + ")"; + name += " \\$999by " + plugin.Author; + if (isTopLevel) { + name += " (v" + plugin.Version + " installed)"; + } return name; } @@ -74,14 +77,26 @@ class DependencyManagerTab : Tab DepLeaf(child, inChain, false, isOptional); } else { string name = dep; + int siteID = PluginIdentToSiteID(dep); if (isOptional) { name = "\\$666" + name; } UI::TreeAdvanceToLabelPos(); UI::Text(name + " \\$f00(not installed)\\$z"); UI::SameLine(); - if (UI::Button("Info###"+dep, vec2(0, UI::GetTextLineHeight()))) { - g_window.AddTab(PluginTab(PluginIdentToSiteID(dep)), true); + if (siteID == -1) { // could not find in api cache + if (UI::ColoredButton(Icons::ExclamationTriangle, 0.f)) { + OpenBrowserURL("https://openplanet.dev/plugin/"+dep); + } + if (UI::IsItemHovered()) { + UI::BeginTooltip(); + UI::Text("Plugin identifier not found. Click to search on Openplanet.dev."); + UI::EndTooltip(); + } + } else { + if (UI::Button(Icons::InfoCircle + "###"+dep, vec2(0, UI::GetTextLineHeight()))) { + g_window.AddTab(PluginTab(siteID), true); + } } } } From 196dd69ef868b1da9945d372e3f443b5692d7425 Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Mon, 6 Feb 2023 21:42:33 -0800 Subject: [PATCH 04/28] store directly in the object instead of making a middleman --- src/Utils/API.as | 8 +++----- src/main.as | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Utils/API.as b/src/Utils/API.as index a2d2e6f..867275f 100644 --- a/src/Utils/API.as +++ b/src/Utils/API.as @@ -25,10 +25,9 @@ namespace API return Json::Parse(req.String()); } - Json::Value@[] GetPluginListAsync() { + void GetPluginListAsync() { uint pages = 1; - - Json::Value@[] plugs; + g_cachedAPIPluginList.Resize(0); for (uint i = 0; i < pages; i++) { Json::Value req = GetAsync("plugins?page=" + i); @@ -38,12 +37,11 @@ namespace API } for (uint ii = 0; ii < req["items"].Length; ii++) { - plugs.InsertLast(req["items"][ii]); + g_cachedAPIPluginList.InsertLast(req["items"][ii]); } // nap a bit so we dont wreck the Openplanet API... sleep(500); } - return plugs; } } diff --git a/src/main.as b/src/main.as index 7db8e83..c8743d7 100644 --- a/src/main.as +++ b/src/main.as @@ -13,14 +13,14 @@ void Main() CheckForUpdatesAsyncStartUp(); // load a list of plugins from the API for later use... - g_cachedAPIPluginList = API::GetPluginListAsync(); + API::GetPluginListAsync(); // Every 30 minutes, check for updates again while (true) { sleep(30 * 60 * 1000); if (Setting_AutoCheckUpdates) { CheckForUpdatesAsync(); - g_cachedAPIPluginList = API::GetPluginListAsync(); + API::GetPluginListAsync(); } } } From 094ec9dc148372c9fab6710a4996133a56b3b5c7 Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Mon, 6 Feb 2023 21:42:45 -0800 Subject: [PATCH 05/28] better formatting --- src/Interface/Tabs/DependencyManager.as | 61 +++++++++++++++++-------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/src/Interface/Tabs/DependencyManager.as b/src/Interface/Tabs/DependencyManager.as index a7f4876..20c924f 100644 --- a/src/Interface/Tabs/DependencyManager.as +++ b/src/Interface/Tabs/DependencyManager.as @@ -1,6 +1,11 @@ class DependencyManagerTab : Tab { + string COLOR_RI = "\\$z"; + string COLOR_OI = "\\$666"; + string COLOR_RN = "\\$f00"; + string COLOR_ON = "\\$f88"; + string GetLabel() override { return "Dependencies"; } vec4 GetColor() override { return vec4(0, 0.6f, 0.2f, 1); } @@ -12,6 +17,15 @@ class DependencyManagerTab : Tab void Render() override { + UI::Text(COLOR_RI + "Required dependency "); + UI::SameLine(); + UI::Text(COLOR_OI + "Optional dependency "); + UI::SameLine(); + UI::Text(COLOR_RN + "Required dependency (not installed) "); + UI::SameLine(); + UI::Text(COLOR_ON + "Optional dependency (not installed) "); + UI::Separator(); + Meta::Plugin@[] loaded = Meta::AllPlugins(); for (uint i = 0; i < loaded.Length; i++) { Meta::Plugin@ v = loaded[i]; @@ -32,8 +46,9 @@ class DependencyManagerTab : Tab return; } + string nameColorTag = isOptional ? COLOR_OI : COLOR_RI; int flags = topLevel ? UI::TreeNodeFlags::DefaultOpen : UI::TreeNodeFlags::None; - if (UI::TreeNode(_GetPluginTitleString(plugin, isOptional, topLevel), flags)) { + if (UI::TreeNode(nameColorTag + GetPluginTitleString(plugin, topLevel), flags)) { if (inChain.Find(plugin.ID) >= 0) { UI::TreeAdvanceToLabelPos(); UI::Text("Circular dependency detected..."); @@ -54,37 +69,40 @@ class DependencyManagerTab : Tab void _DepLeafNoChilds(Meta::Plugin@ plugin, bool isOptional, bool isTopLevel) { + string nameColorTag = isOptional ? COLOR_OI : COLOR_RI; UI::TreeAdvanceToLabelPos(); - UI::Text(_GetPluginTitleString(plugin, isOptional, isTopLevel)); + UI::Text(nameColorTag + GetPluginTitleString(plugin, isTopLevel)); } - string _GetPluginTitleString(Meta::Plugin@ plugin, bool isOptional, bool isTopLevel) { - string name = plugin.Name; - if (isOptional) { - name = "\\$666" + name; - } - name += " \\$999by " + plugin.Author; + string GetPluginTitleString(Meta::Plugin@ plugin, bool isTopLevel) { + string name = _GetPluginTitleString(plugin.Name, plugin.Author); if (isTopLevel) { name += " (v" + plugin.Version + " installed)"; } return name; } + string GetPluginTitleString(Json::Value@ plugin) { + return _GetPluginTitleString(plugin["name"], plugin["author"]); + } + + string _GetPluginTitleString(const string &in pluginName, const string &in author) { + return pluginName + " \\$999by " + author; + } + void _DepLeaf(const string &in dep, string[]@ inChain, bool isOptional) { Meta::Plugin@ child = Meta::GetPluginFromID(dep); if (child !is null) { DepLeaf(child, inChain, false, isOptional); } else { - string name = dep; - int siteID = PluginIdentToSiteID(dep); - if (isOptional) { - name = "\\$666" + name; - } + int APIcacheRef = PluginIdentToSiteIDRef(dep); + + string nameColorTag = isOptional ? COLOR_ON : COLOR_RN; UI::TreeAdvanceToLabelPos(); - UI::Text(name + " \\$f00(not installed)\\$z"); - UI::SameLine(); - if (siteID == -1) { // could not find in api cache + if (APIcacheRef == -1) { // could not find in api cache + UI::Text(nameColorTag + dep + "\\$z"); + UI::SameLine(); if (UI::ColoredButton(Icons::ExclamationTriangle, 0.f)) { OpenBrowserURL("https://openplanet.dev/plugin/"+dep); } @@ -94,17 +112,20 @@ class DependencyManagerTab : Tab UI::EndTooltip(); } } else { - if (UI::Button(Icons::InfoCircle + "###"+dep, vec2(0, UI::GetTextLineHeight()))) { - g_window.AddTab(PluginTab(siteID), true); + Json::Value apiRet = g_cachedAPIPluginList[APIcacheRef]; + UI::Text(nameColorTag + GetPluginTitleString(apiRet) + "\\$z"); + UI::SameLine(); + if (UI::Button(Icons::InfoCircle + "###"+dep)) { + g_window.AddTab(PluginTab(g_cachedAPIPluginList[APIcacheRef]['id']), true); } } } } - int PluginIdentToSiteID(const string &in ident) { + int PluginIdentToSiteIDRef(const string &in ident) { for (uint i = 0; i < g_cachedAPIPluginList.Length; i++) { if (g_cachedAPIPluginList[i]["identifier"] == ident) { - return g_cachedAPIPluginList[i]["id"]; + return i; } } return -1; From be91ba84451fa9f3488d5896508551718037a5ba Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Mon, 6 Feb 2023 21:58:36 -0800 Subject: [PATCH 06/28] make it more accessible --- src/Interface/Tabs/DependencyManager.as | 15 ++++++++++----- src/Settings.as | 3 +++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/Interface/Tabs/DependencyManager.as b/src/Interface/Tabs/DependencyManager.as index 20c924f..5bb6687 100644 --- a/src/Interface/Tabs/DependencyManager.as +++ b/src/Interface/Tabs/DependencyManager.as @@ -1,10 +1,9 @@ class DependencyManagerTab : Tab { - - string COLOR_RI = "\\$z"; - string COLOR_OI = "\\$666"; - string COLOR_RN = "\\$f00"; - string COLOR_ON = "\\$f88"; + string COLOR_RI = Icons::CheckCircle; + string COLOR_OI = Icons::CheckCircleO; + string COLOR_RN = Icons::Circle; + string COLOR_ON = Icons::CircleO; string GetLabel() override { return "Dependencies"; } @@ -16,6 +15,12 @@ class DependencyManagerTab : Tab void Render() override { + if (!Setting_ColorblindDependencies) { + COLOR_RI = "\\$z" + COLOR_RI; + COLOR_OI = "\\$666" + COLOR_OI; + COLOR_RN = "\\$f00" + COLOR_RN; + COLOR_ON = "\\$f88" + COLOR_ON; + } UI::Text(COLOR_RI + "Required dependency "); UI::SameLine(); diff --git a/src/Settings.as b/src/Settings.as index 9ffd0be..7950582 100644 --- a/src/Settings.as +++ b/src/Settings.as @@ -7,6 +7,9 @@ bool Setting_ColoredUsernames = true; [Setting category="Interface" name="Plugins per row" min=1 max=10] int Setting_PluginsPerRow = 3; +[Setting category="Interface" name="Disable colored statuses in Dependency view"] +bool Setting_ColorblindDependencies = false; + [Setting category="Advanced" name="Base URL" description="Only change if you know what you're doing!"] string Setting_BaseURL = "https://openplanet.dev/"; From 37a5eaed136d7bbf6f5965aebaa23dd9ec52933e Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Mon, 6 Feb 2023 22:27:42 -0800 Subject: [PATCH 07/28] make the legend suck less --- src/Interface/Tabs/DependencyManager.as | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/Interface/Tabs/DependencyManager.as b/src/Interface/Tabs/DependencyManager.as index 5bb6687..a053fc0 100644 --- a/src/Interface/Tabs/DependencyManager.as +++ b/src/Interface/Tabs/DependencyManager.as @@ -22,14 +22,20 @@ class DependencyManagerTab : Tab COLOR_ON = "\\$f88" + COLOR_ON; } - UI::Text(COLOR_RI + "Required dependency "); - UI::SameLine(); - UI::Text(COLOR_OI + "Optional dependency "); - UI::SameLine(); - UI::Text(COLOR_RN + "Required dependency (not installed) "); - UI::SameLine(); - UI::Text(COLOR_ON + "Optional dependency (not installed) "); - UI::Separator(); + if (UI::BeginTable("legend", 2, UI::TableFlags::SizingStretchSame)) { + UI::TableNextRow(); + UI::TableNextColumn(); + UI::Text(COLOR_RI + "Required dependency"); + UI::TableNextColumn(); + UI::Text(COLOR_OI + "Optional dependency"); + UI::TableNextRow(); + UI::TableNextColumn(); + UI::Text(COLOR_RN + "Required dependency (not installed)"); + UI::TableNextColumn(); + UI::Text(COLOR_ON + "Optional dependency (not installed)"); + UI::EndTable(); + UI::Separator(); + } Meta::Plugin@[] loaded = Meta::AllPlugins(); for (uint i = 0; i < loaded.Length; i++) { From b5c9c58140c959d45b9e9b5b8fb9dbaead6703cb Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Tue, 7 Feb 2023 20:47:45 -0800 Subject: [PATCH 08/28] refactor dependency code to make it less fucking miserable --- src/Interface/Tabs/DependencyManager.as | 156 ++++++++++++------------ src/Utils/DependencyLeaf.as | 93 ++++++++++++++ 2 files changed, 169 insertions(+), 80 deletions(-) create mode 100644 src/Utils/DependencyLeaf.as diff --git a/src/Interface/Tabs/DependencyManager.as b/src/Interface/Tabs/DependencyManager.as index a053fc0..c2ca284 100644 --- a/src/Interface/Tabs/DependencyManager.as +++ b/src/Interface/Tabs/DependencyManager.as @@ -5,6 +5,11 @@ class DependencyManagerTab : Tab string COLOR_RN = Icons::Circle; string COLOR_ON = Icons::CircleO; + uint DEPTH_LIMIT = 5; + + DepLeaf@[] seen; // used to prevent infinite loops + DepLeaf@[] tree; + string GetLabel() override { return "Dependencies"; } vec4 GetColor() override { return vec4(0, 0.6f, 0.2f, 1); } @@ -15,6 +20,10 @@ class DependencyManagerTab : Tab void Render() override { + if (tree.Length == 0) { + LoadDependencyTree(); + } + if (!Setting_ColorblindDependencies) { COLOR_RI = "\\$z" + COLOR_RI; COLOR_OI = "\\$666" + COLOR_OI; @@ -34,111 +43,98 @@ class DependencyManagerTab : Tab UI::TableNextColumn(); UI::Text(COLOR_ON + "Optional dependency (not installed)"); UI::EndTable(); + if (UI::Button("Rescan dependencies")) { + LoadDependencyTree(); + return; + } UI::Separator(); } - Meta::Plugin@[] loaded = Meta::AllPlugins(); - for (uint i = 0; i < loaded.Length; i++) { - Meta::Plugin@ v = loaded[i]; - - if (v.Dependencies.Length == 0 && v.OptionalDependencies.Length == 0) { - continue; - } else { - string[] inChain; - DepLeaf(v, inChain, true, false); - } + for (uint i = 0; i < tree.Length; i++) { + DrawPluginLeaf(tree[i], 0, true); } } - void DepLeaf(Meta::Plugin@ plugin, string[]@ inChain, bool topLevel, bool isOptional) + void DrawPluginLeaf(DepLeaf@ plugin, uint depth, bool required) { - if (plugin.Dependencies.Length == 0 && plugin.OptionalDependencies.Length == 0) { - _DepLeafNoChilds(plugin, isOptional, topLevel); - return; - } + string colorTag; - string nameColorTag = isOptional ? COLOR_OI : COLOR_RI; - int flags = topLevel ? UI::TreeNodeFlags::DefaultOpen : UI::TreeNodeFlags::None; - if (UI::TreeNode(nameColorTag + GetPluginTitleString(plugin, topLevel), flags)) { - if (inChain.Find(plugin.ID) >= 0) { + if (plugin.m_plugin !is null) { // plugin is installed + colorTag = required ? COLOR_RI : COLOR_OI; + string pluginText = InstalledPluginString(plugin); + // don't go too deep + if (depth > DEPTH_LIMIT) { UI::TreeAdvanceToLabelPos(); - UI::Text("Circular dependency detected..."); - UI::TreePop(); - return; + UI::Text(colorTag + pluginText); + } else { + if (UI::TreeNode(colorTag + pluginText, UI::TreeNodeFlags::Leaf)) { + for (uint i = 0; i < plugin.m_requiredChilds.Length; i++) { + DrawPluginLeaf(plugin.m_requiredChilds[i], depth+1, true); + } + for (uint i = 0; i < plugin.m_optionalChilds.Length; i++) { + DrawPluginLeaf(plugin.m_optionalChilds[i], depth+1, false); + } + UI::TreePop(); + } } - inChain.InsertLast(plugin.ID); - for (uint i = 0; i < plugin.Dependencies.Length; i++) { - _DepLeaf(plugin.Dependencies[i], inChain, false); + } else if (plugin.m_apiObj !is null) { // we have openplanet.dev deets + colorTag = required ? COLOR_RN : COLOR_ON; + UI::TreeAdvanceToLabelPos(); + UI::Text(colorTag + NotInstalledPluginString(plugin) + "\\$z"); + UI::SameLine(); + if (UI::Button(Icons::InfoCircle + "###" + plugin.m_ident)) { + g_window.AddTab(PluginTab(plugin.m_siteID), true); } - for (uint i = 0; i < plugin.OptionalDependencies.Length; i++) { - _DepLeaf(plugin.OptionalDependencies[i], inChain, true); + } else { // we got no fukken clue + colorTag = required ? COLOR_RN : COLOR_ON; + UI::TreeAdvanceToLabelPos(); + UI::Text(colorTag + MysteryPluginString(plugin) + "\\$z"); + UI::SameLine(); + if (UI::ColoredButton(Icons::ExclamationTriangle, 0.f)) { + OpenBrowserURL("https://openplanet.dev/plugin/"+plugin.m_ident); + } + if (UI::IsItemHovered()) { + UI::BeginTooltip(); + UI::Text("Plugin identifier not found. Click to search on Openplanet.dev."); + UI::EndTooltip(); } - UI::TreePop(); } } - void _DepLeafNoChilds(Meta::Plugin@ plugin, bool isOptional, bool isTopLevel) - { - string nameColorTag = isOptional ? COLOR_OI : COLOR_RI; - UI::TreeAdvanceToLabelPos(); - UI::Text(nameColorTag + GetPluginTitleString(plugin, isTopLevel)); + string InstalledPluginString(DepLeaf@ plugin) { + return plugin.m_name + + " \\$999by " + plugin.m_author + + " \\$666(v" + plugin.m_plugin.Version + " installed)"; } - string GetPluginTitleString(Meta::Plugin@ plugin, bool isTopLevel) { - string name = _GetPluginTitleString(plugin.Name, plugin.Author); - if (isTopLevel) { - name += " (v" + plugin.Version + " installed)"; - } - return name; + string NotInstalledPluginString(DepLeaf@ plugin) { + return plugin.m_name + + " \\$999by " + plugin.m_author; } - string GetPluginTitleString(Json::Value@ plugin) { - return _GetPluginTitleString(plugin["name"], plugin["author"]); + string MysteryPluginString(DepLeaf@ plugin) { + return plugin.m_ident; } - string _GetPluginTitleString(const string &in pluginName, const string &in author) { - return pluginName + " \\$999by " + author; - } + void LoadDependencyTree() { + trace("Reloading dependency tree..."); + seen.Resize(0); + tree.Resize(0); - void _DepLeaf(const string &in dep, string[]@ inChain, bool isOptional) - { - Meta::Plugin@ child = Meta::GetPluginFromID(dep); - if (child !is null) { - DepLeaf(child, inChain, false, isOptional); - } else { - int APIcacheRef = PluginIdentToSiteIDRef(dep); - - string nameColorTag = isOptional ? COLOR_ON : COLOR_RN; - UI::TreeAdvanceToLabelPos(); - if (APIcacheRef == -1) { // could not find in api cache - UI::Text(nameColorTag + dep + "\\$z"); - UI::SameLine(); - if (UI::ColoredButton(Icons::ExclamationTriangle, 0.f)) { - OpenBrowserURL("https://openplanet.dev/plugin/"+dep); - } - if (UI::IsItemHovered()) { - UI::BeginTooltip(); - UI::Text("Plugin identifier not found. Click to search on Openplanet.dev."); - UI::EndTooltip(); - } - } else { - Json::Value apiRet = g_cachedAPIPluginList[APIcacheRef]; - UI::Text(nameColorTag + GetPluginTitleString(apiRet) + "\\$z"); - UI::SameLine(); - if (UI::Button(Icons::InfoCircle + "###"+dep)) { - g_window.AddTab(PluginTab(g_cachedAPIPluginList[APIcacheRef]['id']), true); - } - } + // first let's populate our top-levels + Meta::Plugin@[] loaded = Meta::AllPlugins(); + for (uint i = 0; i < loaded.Length; i++) { + Meta::Plugin@ v = loaded[i]; + DepLeaf x = DepLeaf(loaded[i]); + tree.InsertLast(x); + seen.InsertLast(x); } - } - int PluginIdentToSiteIDRef(const string &in ident) { - for (uint i = 0; i < g_cachedAPIPluginList.Length; i++) { - if (g_cachedAPIPluginList[i]["identifier"] == ident) { - return i; - } + // now iterate through and add dependencies + for (uint i = 0; i < tree.Length; i++) { + tree[i].PopulateChilds(seen); } - return -1; + trace("Scanned " + seen.Length + " plugins."); } } diff --git a/src/Utils/DependencyLeaf.as b/src/Utils/DependencyLeaf.as new file mode 100644 index 0000000..4d043ec --- /dev/null +++ b/src/Utils/DependencyLeaf.as @@ -0,0 +1,93 @@ +class DepLeaf { + Json::Value@ m_apiObj; + Meta::Plugin@ m_plugin; + + string m_ident; + int m_siteID; + + string m_name; + string m_author; + string m_version; + + DepLeaf@[] m_requiredChilds; + DepLeaf@[] m_optionalChilds; + + DepLeaf() {} + + DepLeaf(Json::Value@ req) + { + @m_apiObj = req; + + m_ident = req["identifier"]; + m_siteID = req["id"]; + m_name = req["name"]; + m_author = req["author"]; + } + + DepLeaf(Meta::Plugin@ plug) + { + @m_plugin = plug; + + m_ident = plug.ID; + m_siteID = plug.SiteID; + m_name = plug.Name; + m_author = plug.Author; + m_version = plug.Version; + } + + void PopulateChilds(DepLeaf@[]@ seen) + { + if (m_plugin is null) { + return; + } + + _PopulateChilds(seen, m_plugin.Dependencies, m_requiredChilds); + _PopulateChilds(seen, m_plugin.OptionalDependencies, m_optionalChilds); + } + + void _PopulateChilds(DepLeaf@[]@ seen, string[]@ deps, DepLeaf@[]@ childsArray) + { + for (uint i = 0; i < deps.Length; i++) { + int seenID = GetSeenID(deps[i], seen); + if (seenID >= 0) { + // we've already seen this plugin, so just add a reference to the array and fuck off + childsArray.InsertLast(seen[seenID]); + return; + } + + // all installed plugins are already "seen" so we gotta get from API + int APIcacheRef = PluginIdentToSiteIDRef(deps[i]); + DepLeaf x; + if (APIcacheRef == -1) { // could not find in api cache + x.m_ident = deps[i]; + } else { + Json::Value apiRet = g_cachedAPIPluginList[APIcacheRef]; + x = DepLeaf(apiRet); + } + seen.InsertLast(x); + childsArray.InsertLast(x); + x.PopulateChilds(seen); + } + } + + int PluginIdentToSiteIDRef(const string &in ident) + { + for (uint i = 0; i < g_cachedAPIPluginList.Length; i++) { + if (g_cachedAPIPluginList[i]["identifier"] == ident) { + return i; + } + } + return -1; + } + + int GetSeenID(const string &in ident, DepLeaf@[]@ seen) + { + for (uint i = 0; i < seen.Length; i++) { + if (seen[i].m_ident == ident) { + return i; + } + } + return -1; + } + +} From e4a5c2073a337feb6f2e35f6ffead771c3d1c786 Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Tue, 7 Feb 2023 20:54:53 -0800 Subject: [PATCH 09/28] dont do leaf, its hiding THE PROBLEM --- src/Interface/Tabs/DependencyManager.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Interface/Tabs/DependencyManager.as b/src/Interface/Tabs/DependencyManager.as index c2ca284..21160e3 100644 --- a/src/Interface/Tabs/DependencyManager.as +++ b/src/Interface/Tabs/DependencyManager.as @@ -67,7 +67,7 @@ class DependencyManagerTab : Tab UI::TreeAdvanceToLabelPos(); UI::Text(colorTag + pluginText); } else { - if (UI::TreeNode(colorTag + pluginText, UI::TreeNodeFlags::Leaf)) { + if (UI::TreeNode(colorTag + pluginText)) { for (uint i = 0; i < plugin.m_requiredChilds.Length; i++) { DrawPluginLeaf(plugin.m_requiredChilds[i], depth+1, true); } From 1d08bf9d11c0b860ff3e1cd00cee71fa30f748cc Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Tue, 7 Feb 2023 21:30:18 -0800 Subject: [PATCH 10/28] why do i keep doing this --- src/Utils/DependencyLeaf.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Utils/DependencyLeaf.as b/src/Utils/DependencyLeaf.as index 4d043ec..6060ad4 100644 --- a/src/Utils/DependencyLeaf.as +++ b/src/Utils/DependencyLeaf.as @@ -52,7 +52,7 @@ class DepLeaf { if (seenID >= 0) { // we've already seen this plugin, so just add a reference to the array and fuck off childsArray.InsertLast(seen[seenID]); - return; + continue; } // all installed plugins are already "seen" so we gotta get from API From 6333a5ae30457872a748c417f89f990173c958c5 Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Tue, 7 Feb 2023 21:31:45 -0800 Subject: [PATCH 11/28] nicer formatting, only show plugins with dependencies --- src/Interface/Tabs/DependencyManager.as | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Interface/Tabs/DependencyManager.as b/src/Interface/Tabs/DependencyManager.as index 21160e3..f0269b8 100644 --- a/src/Interface/Tabs/DependencyManager.as +++ b/src/Interface/Tabs/DependencyManager.as @@ -10,6 +10,8 @@ class DependencyManagerTab : Tab DepLeaf@[] seen; // used to prevent infinite loops DepLeaf@[] tree; + bool showAllPlugins = false; + string GetLabel() override { return "Dependencies"; } vec4 GetColor() override { return vec4(0, 0.6f, 0.2f, 1); } @@ -47,6 +49,13 @@ class DependencyManagerTab : Tab LoadDependencyTree(); return; } + UI::SameLine(); + showAllPlugins = UI::Checkbox("List all plugins", showAllPlugins); + if (UI::IsItemHovered()) { + UI::BeginTooltip(); + UI::Text("If unchecked, only plugins with dependencies are listed"); + UI::EndTooltip(); + } UI::Separator(); } @@ -66,8 +75,21 @@ class DependencyManagerTab : Tab if (depth > DEPTH_LIMIT) { UI::TreeAdvanceToLabelPos(); UI::Text(colorTag + pluginText); + return; } else { - if (UI::TreeNode(colorTag + pluginText)) { + int numChilds = plugin.m_requiredChilds.Length + plugin.m_optionalChilds.Length; + int flags = (numChilds == 0) ? UI::TreeNodeFlags::Leaf : UI::TreeNodeFlags::None; + if (depth == 0) { + flags |= UI::TreeNodeFlags::DefaultOpen; + if (!showAllPlugins && numChilds == 0) { + return; + } + } + if (UI::TreeNode(colorTag + pluginText+"###"+plugin.m_ident, flags)) { + if (numChilds == 0 && depth == 0) { + UI::TreeAdvanceToLabelPos(); + UI::Text("\\$666No dependencies"); + } for (uint i = 0; i < plugin.m_requiredChilds.Length; i++) { DrawPluginLeaf(plugin.m_requiredChilds[i], depth+1, true); } From 092662be660fb5a82096eae6febe1502427cc708 Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Tue, 7 Feb 2023 21:50:57 -0800 Subject: [PATCH 12/28] openplanet doesnt need to parse an infinite chain of color codes, actually. --- src/Interface/Tabs/DependencyManager.as | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/Interface/Tabs/DependencyManager.as b/src/Interface/Tabs/DependencyManager.as index f0269b8..071e436 100644 --- a/src/Interface/Tabs/DependencyManager.as +++ b/src/Interface/Tabs/DependencyManager.as @@ -12,6 +12,16 @@ class DependencyManagerTab : Tab bool showAllPlugins = false; + DependencyManagerTab() + { + if (!Setting_ColorblindDependencies) { + COLOR_RI = "\\$z" + COLOR_RI; + COLOR_OI = "\\$666" + COLOR_OI; + COLOR_RN = "\\$f00" + COLOR_RN; + COLOR_ON = "\\$666" + COLOR_ON; + } + } + string GetLabel() override { return "Dependencies"; } vec4 GetColor() override { return vec4(0, 0.6f, 0.2f, 1); } @@ -26,13 +36,6 @@ class DependencyManagerTab : Tab LoadDependencyTree(); } - if (!Setting_ColorblindDependencies) { - COLOR_RI = "\\$z" + COLOR_RI; - COLOR_OI = "\\$666" + COLOR_OI; - COLOR_RN = "\\$f00" + COLOR_RN; - COLOR_ON = "\\$f88" + COLOR_ON; - } - if (UI::BeginTable("legend", 2, UI::TableFlags::SizingStretchSame)) { UI::TableNextRow(); UI::TableNextColumn(); From f238ea54a00191e7dabfe8c2e6289be677103e67 Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Tue, 7 Feb 2023 22:05:45 -0800 Subject: [PATCH 13/28] pretty up the tab color --- src/Interface/Tabs/DependencyManager.as | 4 ++-- src/Interface/Window.as | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Interface/Tabs/DependencyManager.as b/src/Interface/Tabs/DependencyManager.as index 071e436..7ab4fba 100644 --- a/src/Interface/Tabs/DependencyManager.as +++ b/src/Interface/Tabs/DependencyManager.as @@ -22,9 +22,9 @@ class DependencyManagerTab : Tab } } - string GetLabel() override { return "Dependencies"; } + string GetLabel() override { return Icons::CheckSquareO + " Dependencies"; } - vec4 GetColor() override { return vec4(0, 0.6f, 0.2f, 1); } + vec4 GetColor() override { return vec4(0.6f, 0.6f, 0.f, 1); } void RenderEmpty() { diff --git a/src/Interface/Window.as b/src/Interface/Window.as index 2f2d466..06a43b0 100644 --- a/src/Interface/Window.as +++ b/src/Interface/Window.as @@ -9,8 +9,8 @@ class Window Window() { AddTab(UpdatesTab()); - AddTab(DependencyManagerTab()); AddTab(InstalledTab()); + AddTab(DependencyManagerTab()); AddTab(FeaturedTab()); AddTab(PopularTab()); From a967f0fe415cfe7552f3a649dd5b75b4f2cb10f2 Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Tue, 7 Feb 2023 22:09:41 -0800 Subject: [PATCH 14/28] formatting --- src/Interface/Tabs/DependencyManager.as | 12 ++++++++---- src/Utils/API.as | 3 ++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Interface/Tabs/DependencyManager.as b/src/Interface/Tabs/DependencyManager.as index 7ab4fba..2c1b881 100644 --- a/src/Interface/Tabs/DependencyManager.as +++ b/src/Interface/Tabs/DependencyManager.as @@ -127,22 +127,26 @@ class DependencyManagerTab : Tab } } - string InstalledPluginString(DepLeaf@ plugin) { + string InstalledPluginString(DepLeaf@ plugin) + { return plugin.m_name + " \\$999by " + plugin.m_author + " \\$666(v" + plugin.m_plugin.Version + " installed)"; } - string NotInstalledPluginString(DepLeaf@ plugin) { + string NotInstalledPluginString(DepLeaf@ plugin) + { return plugin.m_name + " \\$999by " + plugin.m_author; } - string MysteryPluginString(DepLeaf@ plugin) { + string MysteryPluginString(DepLeaf@ plugin) + { return plugin.m_ident; } - void LoadDependencyTree() { + void LoadDependencyTree() + { trace("Reloading dependency tree..."); seen.Resize(0); tree.Resize(0); diff --git a/src/Utils/API.as b/src/Utils/API.as index 867275f..001cf7d 100644 --- a/src/Utils/API.as +++ b/src/Utils/API.as @@ -25,7 +25,8 @@ namespace API return Json::Parse(req.String()); } - void GetPluginListAsync() { + void GetPluginListAsync() + { uint pages = 1; g_cachedAPIPluginList.Resize(0); From 3cd5fed7c1b37f8aace9affc83904359581e7f9e Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Tue, 7 Feb 2023 22:26:43 -0800 Subject: [PATCH 15/28] i hate IDs i hate IDs --- src/Interface/Tabs/DependencyManager.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Interface/Tabs/DependencyManager.as b/src/Interface/Tabs/DependencyManager.as index 2c1b881..fbbbe8a 100644 --- a/src/Interface/Tabs/DependencyManager.as +++ b/src/Interface/Tabs/DependencyManager.as @@ -116,7 +116,7 @@ class DependencyManagerTab : Tab UI::TreeAdvanceToLabelPos(); UI::Text(colorTag + MysteryPluginString(plugin) + "\\$z"); UI::SameLine(); - if (UI::ColoredButton(Icons::ExclamationTriangle, 0.f)) { + if (UI::ColoredButton(Icons::ExclamationTriangle+ "###" + plugin.m_ident, 0.f)) { OpenBrowserURL("https://openplanet.dev/plugin/"+plugin.m_ident); } if (UI::IsItemHovered()) { From 8f49d59d8559d3e519e7ed243a761dcdba668673 Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Wed, 8 Feb 2023 09:53:35 -0800 Subject: [PATCH 16/28] differentiate top-level and bundled plugins --- src/Interface/Tabs/DependencyManager.as | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Interface/Tabs/DependencyManager.as b/src/Interface/Tabs/DependencyManager.as index fbbbe8a..692db29 100644 --- a/src/Interface/Tabs/DependencyManager.as +++ b/src/Interface/Tabs/DependencyManager.as @@ -72,12 +72,20 @@ class DependencyManagerTab : Tab string colorTag; if (plugin.m_plugin !is null) { // plugin is installed - colorTag = required ? COLOR_RI : COLOR_OI; - string pluginText = InstalledPluginString(plugin); + if (depth > 0) { + colorTag = required ? COLOR_RI : COLOR_OI; + } + string pluginText; + // check if it's an openplanet bundled plugin... + if (plugin.m_plugin.Source == Meta::PluginSource::ApplicationFolder) { + pluginText = "\\$f39" + Icons::Heartbeat + "\\$z" + plugin.m_name + " \\$666(built-in)"; + } else { + pluginText = colorTag + InstalledPluginString(plugin); + } // don't go too deep if (depth > DEPTH_LIMIT) { UI::TreeAdvanceToLabelPos(); - UI::Text(colorTag + pluginText); + UI::Text(pluginText); return; } else { int numChilds = plugin.m_requiredChilds.Length + plugin.m_optionalChilds.Length; @@ -88,7 +96,7 @@ class DependencyManagerTab : Tab return; } } - if (UI::TreeNode(colorTag + pluginText+"###"+plugin.m_ident, flags)) { + if (UI::TreeNode(pluginText+"###"+plugin.m_ident, flags)) { if (numChilds == 0 && depth == 0) { UI::TreeAdvanceToLabelPos(); UI::Text("\\$666No dependencies"); From 53255f3af2bd289c68db8f6cb4d09f92dafbdcdf Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Wed, 8 Feb 2023 09:58:07 -0800 Subject: [PATCH 17/28] formatting --- src/Utils/DependencyLeaf.as | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Utils/DependencyLeaf.as b/src/Utils/DependencyLeaf.as index 6060ad4..3750987 100644 --- a/src/Utils/DependencyLeaf.as +++ b/src/Utils/DependencyLeaf.as @@ -89,5 +89,4 @@ class DepLeaf { } return -1; } - } From bef7df62398c4e10a720fe7aa979a8347732236e Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Wed, 8 Feb 2023 13:46:20 -0800 Subject: [PATCH 18/28] lose the v --- src/Interface/Tabs/DependencyManager.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Interface/Tabs/DependencyManager.as b/src/Interface/Tabs/DependencyManager.as index 692db29..b2a5dad 100644 --- a/src/Interface/Tabs/DependencyManager.as +++ b/src/Interface/Tabs/DependencyManager.as @@ -139,7 +139,7 @@ class DependencyManagerTab : Tab { return plugin.m_name + " \\$999by " + plugin.m_author + - " \\$666(v" + plugin.m_plugin.Version + " installed)"; + " \\$666(" + plugin.m_plugin.Version + " installed)"; } string NotInstalledPluginString(DepLeaf@ plugin) From f101ceedb285bfb9b23c8862625424e30ab98600 Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Wed, 8 Feb 2023 13:57:36 -0800 Subject: [PATCH 19/28] whitespace --- src/Interface/Tabs/DependencyManager.as | 4 +- src/Utils/DependencyLeaf.as | 116 ++++++++++++------------ 2 files changed, 60 insertions(+), 60 deletions(-) diff --git a/src/Interface/Tabs/DependencyManager.as b/src/Interface/Tabs/DependencyManager.as index b2a5dad..3fcd1b0 100644 --- a/src/Interface/Tabs/DependencyManager.as +++ b/src/Interface/Tabs/DependencyManager.as @@ -138,14 +138,14 @@ class DependencyManagerTab : Tab string InstalledPluginString(DepLeaf@ plugin) { return plugin.m_name + - " \\$999by " + plugin.m_author + + " \\$999by " + plugin.m_author + " \\$666(" + plugin.m_plugin.Version + " installed)"; } string NotInstalledPluginString(DepLeaf@ plugin) { return plugin.m_name + - " \\$999by " + plugin.m_author; + " \\$999by " + plugin.m_author; } string MysteryPluginString(DepLeaf@ plugin) diff --git a/src/Utils/DependencyLeaf.as b/src/Utils/DependencyLeaf.as index 3750987..b3bf94a 100644 --- a/src/Utils/DependencyLeaf.as +++ b/src/Utils/DependencyLeaf.as @@ -2,76 +2,76 @@ class DepLeaf { Json::Value@ m_apiObj; Meta::Plugin@ m_plugin; - string m_ident; - int m_siteID; + string m_ident; + int m_siteID; - string m_name; - string m_author; - string m_version; + string m_name; + string m_author; + string m_version; DepLeaf@[] m_requiredChilds; DepLeaf@[] m_optionalChilds; - DepLeaf() {} + DepLeaf() {} - DepLeaf(Json::Value@ req) - { - @m_apiObj = req; + DepLeaf(Json::Value@ req) + { + @m_apiObj = req; - m_ident = req["identifier"]; - m_siteID = req["id"]; - m_name = req["name"]; - m_author = req["author"]; - } + m_ident = req["identifier"]; + m_siteID = req["id"]; + m_name = req["name"]; + m_author = req["author"]; + } - DepLeaf(Meta::Plugin@ plug) - { - @m_plugin = plug; + DepLeaf(Meta::Plugin@ plug) + { + @m_plugin = plug; - m_ident = plug.ID; - m_siteID = plug.SiteID; - m_name = plug.Name; - m_author = plug.Author; - m_version = plug.Version; - } + m_ident = plug.ID; + m_siteID = plug.SiteID; + m_name = plug.Name; + m_author = plug.Author; + m_version = plug.Version; + } - void PopulateChilds(DepLeaf@[]@ seen) - { - if (m_plugin is null) { - return; - } + void PopulateChilds(DepLeaf@[]@ seen) + { + if (m_plugin is null) { + return; + } - _PopulateChilds(seen, m_plugin.Dependencies, m_requiredChilds); - _PopulateChilds(seen, m_plugin.OptionalDependencies, m_optionalChilds); - } + _PopulateChilds(seen, m_plugin.Dependencies, m_requiredChilds); + _PopulateChilds(seen, m_plugin.OptionalDependencies, m_optionalChilds); + } - void _PopulateChilds(DepLeaf@[]@ seen, string[]@ deps, DepLeaf@[]@ childsArray) - { - for (uint i = 0; i < deps.Length; i++) { - int seenID = GetSeenID(deps[i], seen); - if (seenID >= 0) { - // we've already seen this plugin, so just add a reference to the array and fuck off - childsArray.InsertLast(seen[seenID]); - continue; - } + void _PopulateChilds(DepLeaf@[]@ seen, string[]@ deps, DepLeaf@[]@ childsArray) + { + for (uint i = 0; i < deps.Length; i++) { + int seenID = GetSeenID(deps[i], seen); + if (seenID >= 0) { + // we've already seen this plugin, so just add a reference to the array and fuck off + childsArray.InsertLast(seen[seenID]); + continue; + } - // all installed plugins are already "seen" so we gotta get from API - int APIcacheRef = PluginIdentToSiteIDRef(deps[i]); - DepLeaf x; - if (APIcacheRef == -1) { // could not find in api cache - x.m_ident = deps[i]; - } else { - Json::Value apiRet = g_cachedAPIPluginList[APIcacheRef]; - x = DepLeaf(apiRet); - } - seen.InsertLast(x); - childsArray.InsertLast(x); - x.PopulateChilds(seen); - } - } + // all installed plugins are already "seen" so we gotta get from API + int APIcacheRef = PluginIdentToSiteIDRef(deps[i]); + DepLeaf x; + if (APIcacheRef == -1) { // could not find in api cache + x.m_ident = deps[i]; + } else { + Json::Value apiRet = g_cachedAPIPluginList[APIcacheRef]; + x = DepLeaf(apiRet); + } + seen.InsertLast(x); + childsArray.InsertLast(x); + x.PopulateChilds(seen); + } + } - int PluginIdentToSiteIDRef(const string &in ident) - { + int PluginIdentToSiteIDRef(const string &in ident) + { for (uint i = 0; i < g_cachedAPIPluginList.Length; i++) { if (g_cachedAPIPluginList[i]["identifier"] == ident) { return i; @@ -80,8 +80,8 @@ class DepLeaf { return -1; } - int GetSeenID(const string &in ident, DepLeaf@[]@ seen) - { + int GetSeenID(const string &in ident, DepLeaf@[]@ seen) + { for (uint i = 0; i < seen.Length; i++) { if (seen[i].m_ident == ident) { return i; From 0870562642b295d822357dcfeee5a2e7c9dcdb8f Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Wed, 8 Feb 2023 14:06:03 -0800 Subject: [PATCH 20/28] missing dependency helper funcs --- src/Interface/Tabs/DependencyManager.as | 20 ++++++++++++++++++++ src/Utils/DependencyLeaf.as | 20 ++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/Interface/Tabs/DependencyManager.as b/src/Interface/Tabs/DependencyManager.as index 3fcd1b0..a7c7c62 100644 --- a/src/Interface/Tabs/DependencyManager.as +++ b/src/Interface/Tabs/DependencyManager.as @@ -174,4 +174,24 @@ class DependencyManagerTab : Tab } trace("Scanned " + seen.Length + " plugins."); } + + bool isMissingRequirements() + { + for (uint i = 0; i < tree.Length; i++) { + if (tree[i].isMissingRequirements()) { + return true; + } + } + return false; + } + + bool isMissingOptionals() + { + for (uint i = 0; i < tree.Length; i++) { + if (tree[i].isMissingOptionals()) { + return true; + } + } + return false; + } } diff --git a/src/Utils/DependencyLeaf.as b/src/Utils/DependencyLeaf.as index b3bf94a..880d425 100644 --- a/src/Utils/DependencyLeaf.as +++ b/src/Utils/DependencyLeaf.as @@ -89,4 +89,24 @@ class DepLeaf { } return -1; } + + bool isMissingRequirements() + { + for (uint i = 0; i < m_requiredChilds.Length; i++) { + if (m_requiredChilds[i].m_plugin is null) { + return true; + } + } + return false; + } + + bool isMissingOptionals() + { + for (uint i = 0; i < m_optionalChilds.Length; i++) { + if (m_optionalChilds[i].m_plugin is null) { + return true; + } + } + return false; + } } From 1823755f81526b69e6384a82b44ef28af9f1c66d Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Wed, 8 Feb 2023 15:01:59 -0800 Subject: [PATCH 21/28] make DependencyManager its own window rather than a tab --- src/Interface/{Tabs => }/DependencyManager.as | 77 ++++++++++--------- src/Interface/Window.as | 1 - src/MenuMain.as | 14 +++- src/main.as | 5 ++ 4 files changed, 58 insertions(+), 39 deletions(-) rename src/Interface/{Tabs => }/DependencyManager.as (76%) diff --git a/src/Interface/Tabs/DependencyManager.as b/src/Interface/DependencyManager.as similarity index 76% rename from src/Interface/Tabs/DependencyManager.as rename to src/Interface/DependencyManager.as index a7c7c62..53537e8 100644 --- a/src/Interface/Tabs/DependencyManager.as +++ b/src/Interface/DependencyManager.as @@ -1,4 +1,4 @@ -class DependencyManagerTab : Tab +class DependencyManager { string COLOR_RI = Icons::CheckCircle; string COLOR_OI = Icons::CheckCircleO; @@ -11,8 +11,9 @@ class DependencyManagerTab : Tab DepLeaf@[] tree; bool showAllPlugins = false; + bool m_visible = false; - DependencyManagerTab() + DependencyManager() { if (!Setting_ColorblindDependencies) { COLOR_RI = "\\$z" + COLOR_RI; @@ -22,49 +23,48 @@ class DependencyManagerTab : Tab } } - string GetLabel() override { return Icons::CheckSquareO + " Dependencies"; } - - vec4 GetColor() override { return vec4(0.6f, 0.6f, 0.f, 1); } - - void RenderEmpty() - { - } - - void Render() override + void Render() { - if (tree.Length == 0) { - LoadDependencyTree(); + if (!m_visible) { + return; } - if (UI::BeginTable("legend", 2, UI::TableFlags::SizingStretchSame)) { - UI::TableNextRow(); - UI::TableNextColumn(); - UI::Text(COLOR_RI + "Required dependency"); - UI::TableNextColumn(); - UI::Text(COLOR_OI + "Optional dependency"); - UI::TableNextRow(); - UI::TableNextColumn(); - UI::Text(COLOR_RN + "Required dependency (not installed)"); - UI::TableNextColumn(); - UI::Text(COLOR_ON + "Optional dependency (not installed)"); - UI::EndTable(); - if (UI::Button("Rescan dependencies")) { + UI::SetNextWindowSize(800, 500); + if (UI::Begin(Icons::CheckSquareO + " Dependency Auditor###PluginManagerDepAudit", m_visible)) { + if (tree.Length == 0) { LoadDependencyTree(); - return; } - UI::SameLine(); - showAllPlugins = UI::Checkbox("List all plugins", showAllPlugins); - if (UI::IsItemHovered()) { - UI::BeginTooltip(); - UI::Text("If unchecked, only plugins with dependencies are listed"); - UI::EndTooltip(); + + if (UI::BeginTable("legend", 2, UI::TableFlags::SizingStretchSame)) { + UI::TableNextRow(); + UI::TableNextColumn(); + UI::Text(COLOR_RI + "Required dependency"); + UI::TableNextColumn(); + UI::Text(COLOR_OI + "Optional dependency"); + UI::TableNextRow(); + UI::TableNextColumn(); + UI::Text(COLOR_RN + "Required dependency (not installed)"); + UI::TableNextColumn(); + UI::Text(COLOR_ON + "Optional dependency (not installed)"); + UI::EndTable(); + if (UI::Button("Rescan dependencies")) { + LoadDependencyTree(); + } + UI::SameLine(); + showAllPlugins = UI::Checkbox("List all plugins", showAllPlugins); + if (UI::IsItemHovered()) { + UI::BeginTooltip(); + UI::Text("If unchecked, only plugins with dependencies are listed"); + UI::EndTooltip(); + } + UI::Separator(); } - UI::Separator(); - } - for (uint i = 0; i < tree.Length; i++) { - DrawPluginLeaf(tree[i], 0, true); + for (uint i = 0; i < tree.Length; i++) { + DrawPluginLeaf(tree[i], 0, true); + } } + UI::End(); } void DrawPluginLeaf(DepLeaf@ plugin, uint depth, bool required) @@ -117,6 +117,7 @@ class DependencyManagerTab : Tab UI::Text(colorTag + NotInstalledPluginString(plugin) + "\\$z"); UI::SameLine(); if (UI::Button(Icons::InfoCircle + "###" + plugin.m_ident)) { + g_window.m_visible = true; g_window.AddTab(PluginTab(plugin.m_siteID), true); } } else { // we got no fukken clue @@ -195,3 +196,5 @@ class DependencyManagerTab : Tab return false; } } + +DependencyManager g_dependencyManager; diff --git a/src/Interface/Window.as b/src/Interface/Window.as index 06a43b0..03a8a6e 100644 --- a/src/Interface/Window.as +++ b/src/Interface/Window.as @@ -10,7 +10,6 @@ class Window { AddTab(UpdatesTab()); AddTab(InstalledTab()); - AddTab(DependencyManagerTab()); AddTab(FeaturedTab()); AddTab(PopularTab()); diff --git a/src/MenuMain.as b/src/MenuMain.as index eb9206e..f0fe735 100644 --- a/src/MenuMain.as +++ b/src/MenuMain.as @@ -1,7 +1,9 @@ void RenderMenuMain() { string menuText; - if (g_availableUpdates.Length > 0) { + if (g_dependencyManager.isMissingRequirements()) { + menuText = "\\$f33" + Icons::ExclamationTriangle; + } else if (g_availableUpdates.Length > 0) { menuText = "\\$f77" + Icons::ArrowCircleUp + " " + g_availableUpdates.Length; } else { menuText = Icons::ShoppingCart; @@ -13,6 +15,16 @@ void RenderMenuMain() g_window.m_visible = !g_window.m_visible; } + string depManText; + if (g_dependencyManager.isMissingRequirements()) { + depManText = "\\$f33" + Icons::ExclamationTriangle + "\\$z Audit missing requirements"; + } else { + depManText = "\\$z" + Icons::CheckSquareO + " Open dependency auditor"; + } + if (UI::MenuItem(depManText, "", g_dependencyManager.m_visible)) { + g_dependencyManager.m_visible = !g_dependencyManager.m_visible; + } + if (UI::MenuItem(Icons::Refresh + " Check for updates")) { // When manually checking for updates, we synchronize the cache as well PluginCache::Sync(); diff --git a/src/main.as b/src/main.as index 2656df8..85db059 100644 --- a/src/main.as +++ b/src/main.as @@ -14,6 +14,9 @@ void Main() // Start checking for updates immediately CheckForUpdatesAsyncStartUp(); + // check for missing dependencies + g_dependencyManager.LoadDependencyTree(); + // load a list of plugins from the API for later use... API::GetPluginListAsync(); @@ -23,6 +26,7 @@ void Main() if (Setting_AutoCheckUpdates) { CheckForUpdatesAsync(); API::GetPluginListAsync(); + g_dependencyManager.LoadDependencyTree(); } } } @@ -30,4 +34,5 @@ void Main() void RenderInterface() { g_window.Render(); + g_dependencyManager.Render(); } From bb79aec3246816115ecaba2b7c68a03a8c8271e1 Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Sun, 11 Jun 2023 10:43:22 -0700 Subject: [PATCH 22/28] use better website api --- src/Interface/DependencyManager.as | 11 ++++++++-- src/Utils/API.as | 33 +++++++++++++++++++----------- src/Utils/DependencyLeaf.as | 11 ++++++++++ src/main.as | 4 ---- 4 files changed, 41 insertions(+), 18 deletions(-) diff --git a/src/Interface/DependencyManager.as b/src/Interface/DependencyManager.as index 53537e8..68162fa 100644 --- a/src/Interface/DependencyManager.as +++ b/src/Interface/DependencyManager.as @@ -9,6 +9,7 @@ class DependencyManager DepLeaf@[] seen; // used to prevent infinite loops DepLeaf@[] tree; + string[] missing; bool showAllPlugins = false; bool m_visible = false; @@ -125,7 +126,7 @@ class DependencyManager UI::TreeAdvanceToLabelPos(); UI::Text(colorTag + MysteryPluginString(plugin) + "\\$z"); UI::SameLine(); - if (UI::ColoredButton(Icons::ExclamationTriangle+ "###" + plugin.m_ident, 0.f)) { + if (UI::RedButton(Icons::ExclamationTriangle+ "###" + plugin.m_ident)) { OpenBrowserURL("https://openplanet.dev/plugin/"+plugin.m_ident); } if (UI::IsItemHovered()) { @@ -154,11 +155,12 @@ class DependencyManager return plugin.m_ident; } - void LoadDependencyTree() + void LoadDependencyTree(bool retryMissing = true) { trace("Reloading dependency tree..."); seen.Resize(0); tree.Resize(0); + missing.Resize(0); // first let's populate our top-levels Meta::Plugin@[] loaded = Meta::AllPlugins(); @@ -174,6 +176,11 @@ class DependencyManager tree[i].PopulateChilds(seen); } trace("Scanned " + seen.Length + " plugins."); + + if (retryMissing) { // avoid infinite loop + API::GetPluginListAsync(missing); + LoadDependencyTree(false); + } } bool isMissingRequirements() diff --git a/src/Utils/API.as b/src/Utils/API.as index 001cf7d..7f5e235 100644 --- a/src/Utils/API.as +++ b/src/Utils/API.as @@ -25,24 +25,33 @@ namespace API return Json::Parse(req.String()); } - void GetPluginListAsync() + void GetPluginListAsync(string[] missing) { uint pages = 1; - g_cachedAPIPluginList.Resize(0); - for (uint i = 0; i < pages; i++) { - Json::Value req = GetAsync("plugins?page=" + i); + string fetchMissing = string::Join(missing, ','); + if (fetchMissing.Length > 0) { + for (uint i = 0; i < pages; i++) { + Json::Value req = GetAsync("plugins?idents=" + fetchMissing + "&page=" + i); - if (pages == 1 && req["pages"] != 1) { - pages = req["pages"]; - } + if (pages == 1 && req["pages"] != 1) { + pages = req["pages"]; + } - for (uint ii = 0; ii < req["items"].Length; ii++) { - g_cachedAPIPluginList.InsertLast(req["items"][ii]); - } + for (uint ii = 0; ii < req["items"].Length; ii++) { + // kill any existing values + for (uint iii = 0; iii < g_cachedAPIPluginList.Length; iii++) { // how deep can we go + if (string(g_cachedAPIPluginList[iii]['identifier']) == string(req["items"][ii]['identifier'])) { + g_cachedAPIPluginList.RemoveAt(iii); + } + } - // nap a bit so we dont wreck the Openplanet API... - sleep(500); + g_cachedAPIPluginList.InsertLast(req["items"][ii]); + } + + // nap a bit so we dont wreck the Openplanet API... + sleep(500); + } } } } diff --git a/src/Utils/DependencyLeaf.as b/src/Utils/DependencyLeaf.as index 880d425..29337cb 100644 --- a/src/Utils/DependencyLeaf.as +++ b/src/Utils/DependencyLeaf.as @@ -59,6 +59,7 @@ class DepLeaf { int APIcacheRef = PluginIdentToSiteIDRef(deps[i]); DepLeaf x; if (APIcacheRef == -1) { // could not find in api cache + addMissingIdent(deps[i]); x.m_ident = deps[i]; } else { Json::Value apiRet = g_cachedAPIPluginList[APIcacheRef]; @@ -80,6 +81,16 @@ class DepLeaf { return -1; } + void addMissingIdent(const string &in ident) + { + for (uint i = 0; i < g_dependencyManager.missing.Length; i++) { + if (g_dependencyManager.missing[i] == ident) { + return; + } + } + g_dependencyManager.missing.InsertLast(ident); + } + int GetSeenID(const string &in ident, DepLeaf@[]@ seen) { for (uint i = 0; i < seen.Length; i++) { diff --git a/src/main.as b/src/main.as index 85db059..f3ce16a 100644 --- a/src/main.as +++ b/src/main.as @@ -17,15 +17,11 @@ void Main() // check for missing dependencies g_dependencyManager.LoadDependencyTree(); - // load a list of plugins from the API for later use... - API::GetPluginListAsync(); - // Every 30 minutes, check for updates again while (true) { sleep(30 * 60 * 1000); if (Setting_AutoCheckUpdates) { CheckForUpdatesAsync(); - API::GetPluginListAsync(); g_dependencyManager.LoadDependencyTree(); } } From 18b8b47b0cf05b9cde9a050cfac82c177130c8cb Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Sun, 11 Jun 2023 12:03:19 -0700 Subject: [PATCH 23/28] show deps on plugin tab --- src/Interface/Tabs/Plugin.as | 98 ++++++++++++++++++++++++++++++++++++ src/Utils/API.as | 28 +++++++++++ src/Utils/PluginInfo.as | 61 +++++++++++++++++++--- 3 files changed, 181 insertions(+), 6 deletions(-) diff --git a/src/Interface/Tabs/Plugin.as b/src/Interface/Tabs/Plugin.as index b452ca4..ece6cd5 100644 --- a/src/Interface/Tabs/Plugin.as +++ b/src/Interface/Tabs/Plugin.as @@ -2,6 +2,7 @@ class PluginTab : Tab { Net::HttpRequest@ m_requestMain; Net::HttpRequest@ m_requestChangelog; + Net::HttpRequest@ m_requestDependencies; bool m_error = false; string m_errorMessage; @@ -61,6 +62,15 @@ class PluginTab : Tab } } + void CheckRequestDependencies() + { + // If there's a request, check if it has finished + if (m_requestDependencies !is null && m_requestDependencies.Finished()) { + API::GetPluginListPost(m_requestDependencies); + @m_requestDependencies = null; + } + } + void CheckRequestChangelog() { // If there's a request, check if it has finished @@ -88,6 +98,10 @@ class PluginTab : Tab void HandleResponse(const Json::Value &in js) { @m_plugin = PluginInfo(js); + string[] missingDeps = m_plugin.GetMissingDeps(); + if (missingDeps.Length > 0) { + @m_requestDependencies = API::GetPluginList(missingDeps); + } } void HandleErrorResponse(const string &in message, int code) @@ -212,12 +226,66 @@ class PluginTab : Tab } } + void RenderDependency(const string &in dep) + { + // is the plugin installed? + auto plug = Meta::GetPluginFromID(dep); + if (plug !is null) { + if (plug.Source == Meta::PluginSource::ApplicationFolder) { // openplanet bundled + UI::Text("\\$f39" + Icons::Heartbeat + "\\$z" + plug.Name + " \\$666(built-in)"); + } else { + UI::Text(plug.Name + " \\$666(installed)"); + if (UI::IsItemClicked()) { + g_window.AddTab(PluginTab(plug.SiteID), true); + } + if (UI::IsItemHovered()) { + UI::SetMouseCursor(UI::MouseCursor::Hand); + UI::BeginTooltip(); + UI::Text(plug.Name + " \\$999by " + plug.Author + " \\$666(" + plug.Version + " installed)"); + UI::Text("Click to open this plugin in a new tab."); + UI::EndTooltip(); + } + } + } else { + // plugin not installed, let's see what info we have on it... + Json::Value@ js; + for (uint i = 0; i < g_cachedAPIPluginList.Length; i++) { + if (string(g_cachedAPIPluginList[i]['identifier']).ToLower() == dep.ToLower()) { + @js = g_cachedAPIPluginList[i]; + } + } + if (js !is null) { + // not installed but we have info + PluginInfo x(js); + + UI::Text("\\$999"+x.m_name); + if (UI::IsItemClicked()) { + g_window.AddTab(PluginTab(x.m_siteID), true); + } + if (UI::IsItemHovered()) { + UI::SetMouseCursor(UI::MouseCursor::Hand); + UI::BeginTooltip(); + UI::Text(x.m_name + " \\$999by " + x.m_author); + UI::Text("Click to open this plugin in a new tab."); + UI::EndTooltip(); + } + + } else { + // no fukken clue + UI::Text("Unknown plugin '"+dep+"'"); + } + + } + + } + void Render() override { float scale = UI::GetScale(); CheckRequestMain(); CheckRequestChangelog(); + CheckRequestDependencies(); if (m_requestMain !is null) { UI::Text("Loading plugin.."); @@ -271,6 +339,36 @@ class PluginTab : Tab OpenBrowserURL(m_plugin.m_donateURL); } + if (m_plugin.m_dep_req.Length + m_plugin.m_dep_opt.Length > 0) { + UI::Separator(); + if (m_plugin.m_dep_req.Length > 0) { + if (UI::TreeNode("Required dependencies:", UI::TreeNodeFlags::DefaultOpen)) { + if (UI::IsItemHovered()) { + UI::BeginTooltip(); + UI::Text("This plugin will not work without all of these plugins installed"); + UI::EndTooltip(); + } + for (uint i = 0; i < m_plugin.m_dep_req.Length; i++) { + RenderDependency(m_plugin.m_dep_req[i]); + } + UI::TreePop(); + } + } + if (m_plugin.m_dep_opt.Length > 0) { + if (UI::TreeNode("Optional dependencies:", UI::TreeNodeFlags::DefaultOpen)) { + if (UI::IsItemHovered()) { + UI::BeginTooltip(); + UI::Text("This plugin provides enhanced functionality if these plugins are installed"); + UI::EndTooltip(); + } + for (uint i = 0; i < m_plugin.m_dep_opt.Length; i++) { + RenderDependency(m_plugin.m_dep_opt[i]); + } + UI::TreePop(); + } + } + } + UI::EndChild(); // Right side of the window diff --git a/src/Utils/API.as b/src/Utils/API.as index 7f5e235..8467b5b 100644 --- a/src/Utils/API.as +++ b/src/Utils/API.as @@ -54,4 +54,32 @@ namespace API } } } + + /** + * special version of GetPluginListAsync for use in Render contexts + * + * only supports a single page, but its only use case is in PluginTab + * and if there's enough deps to cause pagination you can fuck right off. + */ + Net::HttpRequest@ GetPluginList(string[] missing) + { + string fetchMissing = string::Join(missing, ','); + Net::HttpRequest@ req = Get("plugins?idents=" + fetchMissing); + return req; + } + + void GetPluginListPost(Net::HttpRequest@ request) + { + Json::Value req = Json::Parse(request.String()); + for (uint ii = 0; ii < req["items"].Length; ii++) { + // kill any existing values + for (uint iii = 0; iii < g_cachedAPIPluginList.Length; iii++) { // how deep can we go + if (string(g_cachedAPIPluginList[iii]['identifier']) == string(req["items"][ii]['identifier'])) { + g_cachedAPIPluginList.RemoveAt(iii); + } + } + + g_cachedAPIPluginList.InsertLast(req["items"][ii]); + } + } } diff --git a/src/Utils/PluginInfo.as b/src/Utils/PluginInfo.as index 270edbf..f284d02 100644 --- a/src/Utils/PluginInfo.as +++ b/src/Utils/PluginInfo.as @@ -28,6 +28,11 @@ class PluginInfo array m_tags; array m_changelogs; + array m_dep_req; + array m_dep_opt; + + Json::Value@ m_dep_info; + bool m_isInstalled; Net::HttpRequest@ m_changelogRequest; @@ -50,12 +55,24 @@ class PluginInfo m_description = js["description"]; } - if (js.HasKey("links")) { - auto jsLinks = js["links"]; - m_donateURL = jsLinks["donate"].GetType() == Json::Type::String ? jsLinks["donate"] : ""; // setting to null instead of "" crashes openplanet compiler - m_sourceURL = jsLinks["source"].GetType() == Json::Type::String ? jsLinks["source"] : ""; - m_issuesURL = jsLinks["issues"].GetType() == Json::Type::String ? jsLinks["issues"] : ""; - } + if (js.HasKey("links")) { + auto jsLinks = js["links"]; + m_donateURL = jsLinks["donate"].GetType() == Json::Type::String ? jsLinks["donate"] : ""; // setting to null instead of "" crashes openplanet compiler + m_sourceURL = jsLinks["source"].GetType() == Json::Type::String ? jsLinks["source"] : ""; + m_issuesURL = jsLinks["issues"].GetType() == Json::Type::String ? jsLinks["issues"] : ""; + } + + if (js.HasKey("dependencies") && js["dependencies"].GetType() == Json::Type::Array) { + for (uint i = 0; i < js["dependencies"].Length; i++) { + m_dep_req.InsertLast(js["dependencies"][i]); + } + } + + if (js.HasKey("optional_dependencies") && js["optional_dependencies"].GetType() == Json::Type::Array) { + for (uint i = 0; i < js["optional_dependencies"].Length; i++) { + m_dep_opt.InsertLast(js["optional_dependencies"][i]); + } + } m_filesize = js["filesize"]; m_signed = js["signed"]; @@ -121,6 +138,38 @@ class PluginInfo } } + void LoadDependencyInfo() + { + string[] missingDeps = GetMissingDeps(); + if (missingDeps.Length > 0) { + API::GetPluginListAsync(missingDeps); + } + } + + string[] GetMissingDeps() + { + string[] missingDeps; + for (uint i = 0; i < m_dep_req.Length; i++) { + if (Meta::GetPluginFromID(m_dep_req[i]) is null) { + // not installed, let's see if it's in the dep manager list + if (g_dependencyManager.missing.Find(m_dep_req[i]) < 0) { + missingDeps.InsertLast(m_dep_req[i]); + } + } + } + + // copy paste for optionals + for (uint i = 0; i < m_dep_opt.Length; i++) { + if (Meta::GetPluginFromID(m_dep_opt[i]) is null) { + // not installed, let's see if it's in the dep manager list + if (g_dependencyManager.missing.Find(m_dep_opt[i]) < 0) { + missingDeps.InsertLast(m_dep_opt[i]); + } + } + } + return missingDeps; + } + void LoadChangelog() { @m_changelogRequest = API::Get("plugin/" + m_siteID + "/versions"); From 2cc69eeda5ce18a10df8bae640227c34bab98f4d Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Sun, 11 Jun 2023 12:34:05 -0700 Subject: [PATCH 24/28] install required deps alongside plugin --- src/Interface/Tabs/Plugin.as | 59 ++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 9 deletions(-) diff --git a/src/Interface/Tabs/Plugin.as b/src/Interface/Tabs/Plugin.as index ece6cd5..2d38f6d 100644 --- a/src/Interface/Tabs/Plugin.as +++ b/src/Interface/Tabs/Plugin.as @@ -135,15 +135,43 @@ class PluginTab : Tab return true; } + bool HasMissingRequirements() + { + if (m_plugin.m_dep_req.Length == 0) return false; + + for (uint i = 0; i < m_plugin.m_dep_req.Length; i++) { + auto plug = Meta::GetPluginFromID(m_plugin.m_dep_req[i]); + if (plug is null) return true; + } + return false; + } + void InstallAsync() { m_updating = true; + // install any required dependents first + string[] missingDeps = m_plugin.GetMissingDeps(); + for (uint i = 0; i < missingDeps.Length; i++) { + PluginInfo@ dep = getCachedPluginInfo(missingDeps[i]); + + if (dep is null) { + error("Unable to find required plugin info: " + missingDeps[i]); + continue; + } + + PluginInstallAsync(dep.m_siteID, dep.m_id, dep.m_version); + } + PluginInstallAsync(m_plugin.m_siteID, m_plugin.m_id, m_plugin.m_version); m_plugin.m_downloads++; m_plugin.CheckIfInstalled(); m_updating = false; + + if (missingDeps.Length > 0) { + @m_requestDependencies = API::GetPluginList(missingDeps); + } } void UpdateAsync() @@ -209,6 +237,11 @@ class PluginTab : Tab if (UI::GreenButton(Icons::Download + " Install")) { startnew(CoroutineFunc(InstallAsync)); } + if (UI::IsItemHovered() && HasMissingRequirements()) { + UI::BeginTooltip(); + UI::Text("Note: this will also install any missing required dependencies listed below."); + UI::EndTooltip(); + } return; } @@ -248,16 +281,9 @@ class PluginTab : Tab } } else { // plugin not installed, let's see what info we have on it... - Json::Value@ js; - for (uint i = 0; i < g_cachedAPIPluginList.Length; i++) { - if (string(g_cachedAPIPluginList[i]['identifier']).ToLower() == dep.ToLower()) { - @js = g_cachedAPIPluginList[i]; - } - } - if (js !is null) { + PluginInfo@ x = getCachedPluginInfo(dep); + if (x !is null) { // not installed but we have info - PluginInfo x(js); - UI::Text("\\$999"+x.m_name); if (UI::IsItemClicked()) { g_window.AddTab(PluginTab(x.m_siteID), true); @@ -276,7 +302,22 @@ class PluginTab : Tab } } + } + PluginInfo@ getCachedPluginInfo(const string &in ident) + { + Json::Value@ js; + for (uint i = 0; i < g_cachedAPIPluginList.Length; i++) { + if (string(g_cachedAPIPluginList[i]['identifier']).ToLower() == ident.ToLower()) { + @js = g_cachedAPIPluginList[i]; + } + } + if (js !is null) { + // not installed but we have info + return PluginInfo(js); + } else { + return null; + } } void Render() override From b77577edd5bb44c60021cf36f5aa627a3a187073 Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Sun, 11 Jun 2023 12:48:34 -0700 Subject: [PATCH 25/28] remove dep auditor stuff --- src/Interface/DependencyManager.as | 207 ----------------------------- src/MenuMain.as | 14 +- src/Utils/DependencyLeaf.as | 123 ----------------- src/Utils/PluginInfo.as | 10 +- src/main.as | 5 - 5 files changed, 3 insertions(+), 356 deletions(-) delete mode 100644 src/Interface/DependencyManager.as delete mode 100644 src/Utils/DependencyLeaf.as diff --git a/src/Interface/DependencyManager.as b/src/Interface/DependencyManager.as deleted file mode 100644 index 68162fa..0000000 --- a/src/Interface/DependencyManager.as +++ /dev/null @@ -1,207 +0,0 @@ -class DependencyManager -{ - string COLOR_RI = Icons::CheckCircle; - string COLOR_OI = Icons::CheckCircleO; - string COLOR_RN = Icons::Circle; - string COLOR_ON = Icons::CircleO; - - uint DEPTH_LIMIT = 5; - - DepLeaf@[] seen; // used to prevent infinite loops - DepLeaf@[] tree; - string[] missing; - - bool showAllPlugins = false; - bool m_visible = false; - - DependencyManager() - { - if (!Setting_ColorblindDependencies) { - COLOR_RI = "\\$z" + COLOR_RI; - COLOR_OI = "\\$666" + COLOR_OI; - COLOR_RN = "\\$f00" + COLOR_RN; - COLOR_ON = "\\$666" + COLOR_ON; - } - } - - void Render() - { - if (!m_visible) { - return; - } - - UI::SetNextWindowSize(800, 500); - if (UI::Begin(Icons::CheckSquareO + " Dependency Auditor###PluginManagerDepAudit", m_visible)) { - if (tree.Length == 0) { - LoadDependencyTree(); - } - - if (UI::BeginTable("legend", 2, UI::TableFlags::SizingStretchSame)) { - UI::TableNextRow(); - UI::TableNextColumn(); - UI::Text(COLOR_RI + "Required dependency"); - UI::TableNextColumn(); - UI::Text(COLOR_OI + "Optional dependency"); - UI::TableNextRow(); - UI::TableNextColumn(); - UI::Text(COLOR_RN + "Required dependency (not installed)"); - UI::TableNextColumn(); - UI::Text(COLOR_ON + "Optional dependency (not installed)"); - UI::EndTable(); - if (UI::Button("Rescan dependencies")) { - LoadDependencyTree(); - } - UI::SameLine(); - showAllPlugins = UI::Checkbox("List all plugins", showAllPlugins); - if (UI::IsItemHovered()) { - UI::BeginTooltip(); - UI::Text("If unchecked, only plugins with dependencies are listed"); - UI::EndTooltip(); - } - UI::Separator(); - } - - for (uint i = 0; i < tree.Length; i++) { - DrawPluginLeaf(tree[i], 0, true); - } - } - UI::End(); - } - - void DrawPluginLeaf(DepLeaf@ plugin, uint depth, bool required) - { - string colorTag; - - if (plugin.m_plugin !is null) { // plugin is installed - if (depth > 0) { - colorTag = required ? COLOR_RI : COLOR_OI; - } - string pluginText; - // check if it's an openplanet bundled plugin... - if (plugin.m_plugin.Source == Meta::PluginSource::ApplicationFolder) { - pluginText = "\\$f39" + Icons::Heartbeat + "\\$z" + plugin.m_name + " \\$666(built-in)"; - } else { - pluginText = colorTag + InstalledPluginString(plugin); - } - // don't go too deep - if (depth > DEPTH_LIMIT) { - UI::TreeAdvanceToLabelPos(); - UI::Text(pluginText); - return; - } else { - int numChilds = plugin.m_requiredChilds.Length + plugin.m_optionalChilds.Length; - int flags = (numChilds == 0) ? UI::TreeNodeFlags::Leaf : UI::TreeNodeFlags::None; - if (depth == 0) { - flags |= UI::TreeNodeFlags::DefaultOpen; - if (!showAllPlugins && numChilds == 0) { - return; - } - } - if (UI::TreeNode(pluginText+"###"+plugin.m_ident, flags)) { - if (numChilds == 0 && depth == 0) { - UI::TreeAdvanceToLabelPos(); - UI::Text("\\$666No dependencies"); - } - for (uint i = 0; i < plugin.m_requiredChilds.Length; i++) { - DrawPluginLeaf(plugin.m_requiredChilds[i], depth+1, true); - } - for (uint i = 0; i < plugin.m_optionalChilds.Length; i++) { - DrawPluginLeaf(plugin.m_optionalChilds[i], depth+1, false); - } - UI::TreePop(); - } - } - - } else if (plugin.m_apiObj !is null) { // we have openplanet.dev deets - colorTag = required ? COLOR_RN : COLOR_ON; - UI::TreeAdvanceToLabelPos(); - UI::Text(colorTag + NotInstalledPluginString(plugin) + "\\$z"); - UI::SameLine(); - if (UI::Button(Icons::InfoCircle + "###" + plugin.m_ident)) { - g_window.m_visible = true; - g_window.AddTab(PluginTab(plugin.m_siteID), true); - } - } else { // we got no fukken clue - colorTag = required ? COLOR_RN : COLOR_ON; - UI::TreeAdvanceToLabelPos(); - UI::Text(colorTag + MysteryPluginString(plugin) + "\\$z"); - UI::SameLine(); - if (UI::RedButton(Icons::ExclamationTriangle+ "###" + plugin.m_ident)) { - OpenBrowserURL("https://openplanet.dev/plugin/"+plugin.m_ident); - } - if (UI::IsItemHovered()) { - UI::BeginTooltip(); - UI::Text("Plugin identifier not found. Click to search on Openplanet.dev."); - UI::EndTooltip(); - } - } - } - - string InstalledPluginString(DepLeaf@ plugin) - { - return plugin.m_name + - " \\$999by " + plugin.m_author + - " \\$666(" + plugin.m_plugin.Version + " installed)"; - } - - string NotInstalledPluginString(DepLeaf@ plugin) - { - return plugin.m_name + - " \\$999by " + plugin.m_author; - } - - string MysteryPluginString(DepLeaf@ plugin) - { - return plugin.m_ident; - } - - void LoadDependencyTree(bool retryMissing = true) - { - trace("Reloading dependency tree..."); - seen.Resize(0); - tree.Resize(0); - missing.Resize(0); - - // first let's populate our top-levels - Meta::Plugin@[] loaded = Meta::AllPlugins(); - for (uint i = 0; i < loaded.Length; i++) { - Meta::Plugin@ v = loaded[i]; - DepLeaf x = DepLeaf(loaded[i]); - tree.InsertLast(x); - seen.InsertLast(x); - } - - // now iterate through and add dependencies - for (uint i = 0; i < tree.Length; i++) { - tree[i].PopulateChilds(seen); - } - trace("Scanned " + seen.Length + " plugins."); - - if (retryMissing) { // avoid infinite loop - API::GetPluginListAsync(missing); - LoadDependencyTree(false); - } - } - - bool isMissingRequirements() - { - for (uint i = 0; i < tree.Length; i++) { - if (tree[i].isMissingRequirements()) { - return true; - } - } - return false; - } - - bool isMissingOptionals() - { - for (uint i = 0; i < tree.Length; i++) { - if (tree[i].isMissingOptionals()) { - return true; - } - } - return false; - } -} - -DependencyManager g_dependencyManager; diff --git a/src/MenuMain.as b/src/MenuMain.as index f0fe735..eb9206e 100644 --- a/src/MenuMain.as +++ b/src/MenuMain.as @@ -1,9 +1,7 @@ void RenderMenuMain() { string menuText; - if (g_dependencyManager.isMissingRequirements()) { - menuText = "\\$f33" + Icons::ExclamationTriangle; - } else if (g_availableUpdates.Length > 0) { + if (g_availableUpdates.Length > 0) { menuText = "\\$f77" + Icons::ArrowCircleUp + " " + g_availableUpdates.Length; } else { menuText = Icons::ShoppingCart; @@ -15,16 +13,6 @@ void RenderMenuMain() g_window.m_visible = !g_window.m_visible; } - string depManText; - if (g_dependencyManager.isMissingRequirements()) { - depManText = "\\$f33" + Icons::ExclamationTriangle + "\\$z Audit missing requirements"; - } else { - depManText = "\\$z" + Icons::CheckSquareO + " Open dependency auditor"; - } - if (UI::MenuItem(depManText, "", g_dependencyManager.m_visible)) { - g_dependencyManager.m_visible = !g_dependencyManager.m_visible; - } - if (UI::MenuItem(Icons::Refresh + " Check for updates")) { // When manually checking for updates, we synchronize the cache as well PluginCache::Sync(); diff --git a/src/Utils/DependencyLeaf.as b/src/Utils/DependencyLeaf.as deleted file mode 100644 index 29337cb..0000000 --- a/src/Utils/DependencyLeaf.as +++ /dev/null @@ -1,123 +0,0 @@ -class DepLeaf { - Json::Value@ m_apiObj; - Meta::Plugin@ m_plugin; - - string m_ident; - int m_siteID; - - string m_name; - string m_author; - string m_version; - - DepLeaf@[] m_requiredChilds; - DepLeaf@[] m_optionalChilds; - - DepLeaf() {} - - DepLeaf(Json::Value@ req) - { - @m_apiObj = req; - - m_ident = req["identifier"]; - m_siteID = req["id"]; - m_name = req["name"]; - m_author = req["author"]; - } - - DepLeaf(Meta::Plugin@ plug) - { - @m_plugin = plug; - - m_ident = plug.ID; - m_siteID = plug.SiteID; - m_name = plug.Name; - m_author = plug.Author; - m_version = plug.Version; - } - - void PopulateChilds(DepLeaf@[]@ seen) - { - if (m_plugin is null) { - return; - } - - _PopulateChilds(seen, m_plugin.Dependencies, m_requiredChilds); - _PopulateChilds(seen, m_plugin.OptionalDependencies, m_optionalChilds); - } - - void _PopulateChilds(DepLeaf@[]@ seen, string[]@ deps, DepLeaf@[]@ childsArray) - { - for (uint i = 0; i < deps.Length; i++) { - int seenID = GetSeenID(deps[i], seen); - if (seenID >= 0) { - // we've already seen this plugin, so just add a reference to the array and fuck off - childsArray.InsertLast(seen[seenID]); - continue; - } - - // all installed plugins are already "seen" so we gotta get from API - int APIcacheRef = PluginIdentToSiteIDRef(deps[i]); - DepLeaf x; - if (APIcacheRef == -1) { // could not find in api cache - addMissingIdent(deps[i]); - x.m_ident = deps[i]; - } else { - Json::Value apiRet = g_cachedAPIPluginList[APIcacheRef]; - x = DepLeaf(apiRet); - } - seen.InsertLast(x); - childsArray.InsertLast(x); - x.PopulateChilds(seen); - } - } - - int PluginIdentToSiteIDRef(const string &in ident) - { - for (uint i = 0; i < g_cachedAPIPluginList.Length; i++) { - if (g_cachedAPIPluginList[i]["identifier"] == ident) { - return i; - } - } - return -1; - } - - void addMissingIdent(const string &in ident) - { - for (uint i = 0; i < g_dependencyManager.missing.Length; i++) { - if (g_dependencyManager.missing[i] == ident) { - return; - } - } - g_dependencyManager.missing.InsertLast(ident); - } - - int GetSeenID(const string &in ident, DepLeaf@[]@ seen) - { - for (uint i = 0; i < seen.Length; i++) { - if (seen[i].m_ident == ident) { - return i; - } - } - return -1; - } - - bool isMissingRequirements() - { - for (uint i = 0; i < m_requiredChilds.Length; i++) { - if (m_requiredChilds[i].m_plugin is null) { - return true; - } - } - return false; - } - - bool isMissingOptionals() - { - for (uint i = 0; i < m_optionalChilds.Length; i++) { - if (m_optionalChilds[i].m_plugin is null) { - return true; - } - } - return false; - } -} diff --git a/src/Utils/PluginInfo.as b/src/Utils/PluginInfo.as index f284d02..056dbe6 100644 --- a/src/Utils/PluginInfo.as +++ b/src/Utils/PluginInfo.as @@ -151,20 +151,14 @@ class PluginInfo string[] missingDeps; for (uint i = 0; i < m_dep_req.Length; i++) { if (Meta::GetPluginFromID(m_dep_req[i]) is null) { - // not installed, let's see if it's in the dep manager list - if (g_dependencyManager.missing.Find(m_dep_req[i]) < 0) { - missingDeps.InsertLast(m_dep_req[i]); - } + missingDeps.InsertLast(m_dep_req[i]); } } // copy paste for optionals for (uint i = 0; i < m_dep_opt.Length; i++) { if (Meta::GetPluginFromID(m_dep_opt[i]) is null) { - // not installed, let's see if it's in the dep manager list - if (g_dependencyManager.missing.Find(m_dep_opt[i]) < 0) { - missingDeps.InsertLast(m_dep_opt[i]); - } + missingDeps.InsertLast(m_dep_opt[i]); } } return missingDeps; diff --git a/src/main.as b/src/main.as index f3ce16a..988b30a 100644 --- a/src/main.as +++ b/src/main.as @@ -14,15 +14,11 @@ void Main() // Start checking for updates immediately CheckForUpdatesAsyncStartUp(); - // check for missing dependencies - g_dependencyManager.LoadDependencyTree(); - // Every 30 minutes, check for updates again while (true) { sleep(30 * 60 * 1000); if (Setting_AutoCheckUpdates) { CheckForUpdatesAsync(); - g_dependencyManager.LoadDependencyTree(); } } } @@ -30,5 +26,4 @@ void Main() void RenderInterface() { g_window.Render(); - g_dependencyManager.Render(); } From c50c2bced14e0516745d4f3c2332ea0602ec08ee Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Sun, 11 Jun 2023 13:13:43 -0700 Subject: [PATCH 26/28] move getCachedPluginInfo to API ns --- src/Interface/Tabs/Plugin.as | 20 ++------------------ src/Utils/API.as | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Interface/Tabs/Plugin.as b/src/Interface/Tabs/Plugin.as index 2d38f6d..7a02a7a 100644 --- a/src/Interface/Tabs/Plugin.as +++ b/src/Interface/Tabs/Plugin.as @@ -153,7 +153,7 @@ class PluginTab : Tab // install any required dependents first string[] missingDeps = m_plugin.GetMissingDeps(); for (uint i = 0; i < missingDeps.Length; i++) { - PluginInfo@ dep = getCachedPluginInfo(missingDeps[i]); + PluginInfo@ dep = API::getCachedPluginInfo(missingDeps[i]); if (dep is null) { error("Unable to find required plugin info: " + missingDeps[i]); @@ -281,7 +281,7 @@ class PluginTab : Tab } } else { // plugin not installed, let's see what info we have on it... - PluginInfo@ x = getCachedPluginInfo(dep); + PluginInfo@ x = API::getCachedPluginInfo(dep); if (x !is null) { // not installed but we have info UI::Text("\\$999"+x.m_name); @@ -304,22 +304,6 @@ class PluginTab : Tab } } - PluginInfo@ getCachedPluginInfo(const string &in ident) - { - Json::Value@ js; - for (uint i = 0; i < g_cachedAPIPluginList.Length; i++) { - if (string(g_cachedAPIPluginList[i]['identifier']).ToLower() == ident.ToLower()) { - @js = g_cachedAPIPluginList[i]; - } - } - if (js !is null) { - // not installed but we have info - return PluginInfo(js); - } else { - return null; - } - } - void Render() override { float scale = UI::GetScale(); diff --git a/src/Utils/API.as b/src/Utils/API.as index 8467b5b..83555ee 100644 --- a/src/Utils/API.as +++ b/src/Utils/API.as @@ -82,4 +82,20 @@ namespace API g_cachedAPIPluginList.InsertLast(req["items"][ii]); } } + + PluginInfo@ getCachedPluginInfo(const string &in ident) + { + Json::Value@ js; + for (uint i = 0; i < g_cachedAPIPluginList.Length; i++) { + if (string(g_cachedAPIPluginList[i]['identifier']).ToLower() == ident.ToLower()) { + @js = g_cachedAPIPluginList[i]; + } + } + if (js !is null) { + // not installed but we have info + return PluginInfo(js); + } else { + return null; + } + } } From 9a036db88c88a7a09a2500a23e22d216f068e1f2 Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Sun, 11 Jun 2023 13:20:56 -0700 Subject: [PATCH 27/28] install missing deps on update --- src/Update.as | 12 ++++++++++++ src/UpdateCheck.as | 28 ++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/Update.as b/src/Update.as index 715babf..cabe2d2 100644 --- a/src/Update.as +++ b/src/Update.as @@ -60,6 +60,18 @@ void PluginUpdateAsync(ref@ update) return; } + // install any unmet dependencies + for (uint i = 0; i < au.m_requirements.Length; i++) { + auto plug = Meta::GetPluginFromID(au.m_requirements[i]); + if (plug is null) { + PluginInfo@ dep = API::getCachedPluginInfo(au.m_requirements[i]); + if (dep is null) { + error("Unable to find required plugin info: " + au.m_requirements[i]); + continue; + } + PluginInstallAsync(dep.m_siteID, dep.m_id, dep.m_version); + } + } // If the plugin is currently loaded auto installedPlugin = Meta::GetPluginFromSiteID(au.m_siteID); if (installedPlugin !is null) { diff --git a/src/UpdateCheck.as b/src/UpdateCheck.as index 2eb7fb2..b0b2fb4 100644 --- a/src/UpdateCheck.as +++ b/src/UpdateCheck.as @@ -5,6 +5,18 @@ class AvailableUpdate string m_identifier; string m_oldVersion; string m_newVersion; + string[] m_requirements; + + bool HasMissingRequirements() + { + if (m_requirements.Length == 0) return false; + + for (uint i = 0; i < m_requirements.Length; i++) { + auto plug = Meta::GetPluginFromID(m_requirements[i]); + if (plug is null) return true; + } + return false; + } } array g_availableUpdates; @@ -65,6 +77,8 @@ void CheckForUpdatesAsync() return; } + string[] needDepInfo; + // Go through returned list of versions for (uint i = 0; i < js.Length; i++) { auto jsVersion = js[i]; @@ -97,9 +111,23 @@ void CheckForUpdatesAsync() au.m_identifier = siteIdentifier; au.m_oldVersion = info.m_version.ToString(); au.m_newVersion = siteVersion; + + if (jsVersion["required_dependencies"] == Json::Type::Array) { + for (uint d = 0; d < jsVersion["required_dependencies"].Length; d++) { + au.m_requirements.InsertLast(jsVersion["required_dependencies"][d]); + if (API::getCachedPluginInfo(jsVersion["required_dependencies"][d]) is null) { + needDepInfo.InsertLast(jsVersion["required_dependencies"][d]); + } + } + } + g_availableUpdates.InsertLast(au); } + if (needDepInfo.Length > 0) { + API::GetPluginListAsync(needDepInfo); + } + if (g_availableUpdates.Length == 0) { trace("No plugin updates found!"); } From 458d0bd57d719c8d27d504f51d58bde0e42454b9 Mon Sep 17 00:00:00 2001 From: Keira Dueck Date: Sun, 11 Jun 2023 13:22:02 -0700 Subject: [PATCH 28/28] remove unused setting --- src/Settings.as | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Settings.as b/src/Settings.as index 9217e0d..9b596e9 100644 --- a/src/Settings.as +++ b/src/Settings.as @@ -7,9 +7,6 @@ bool Setting_ColoredUsernames = true; [Setting category="Interface" name="Plugins per row" min=1 max=10] int Setting_PluginsPerRow = 3; -[Setting category="Interface" name="Disable colored statuses in Dependency view"] -bool Setting_ColorblindDependencies = false; - [Setting category="Interface" name="Display changelog when hovering over updatable plugins."] bool Setting_ChangelogTooltips = true;