diff --git a/ASS.Pages/ASS.Pages.csproj b/ASS.Pages/ASS.Pages.csproj new file mode 100644 index 0000000..449c458 --- /dev/null +++ b/ASS.Pages/ASS.Pages.csproj @@ -0,0 +1,40 @@ + + + + + Library + ASS.Pages + LabAPI;Exiled + + + + ASS.Pages-LabAPI + + + + ASS.Pages-Exiled + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ASS.Pages/Config.cs b/ASS.Pages/Config.cs new file mode 100644 index 0000000..9b180c9 --- /dev/null +++ b/ASS.Pages/Config.cs @@ -0,0 +1,17 @@ +namespace ASS.Pages +{ + #if EXILED + using Exiled.API.Interfaces; + + public class Config : IConfig + #elif LABAPI + public class Config + #endif + { + #if EXILED + public bool IsEnabled { get; set; } = true; + #endif + + public bool Debug { get; set; } + } +} \ No newline at end of file diff --git a/ASS.Pages/Features/ASSPage.cs b/ASS.Pages/Features/ASSPage.cs new file mode 100644 index 0000000..313031a --- /dev/null +++ b/ASS.Pages/Features/ASSPage.cs @@ -0,0 +1,16 @@ +namespace ASS.Pages.Features +{ + using System; + using System.Collections.Generic; + using ASS.Features.Interfaces; + using LabApi.Features.Wrappers; + + public class ASSPage : IASSObject + { + public List? Children { get; set; } + + public Predicate? Viewers { get; set; } + + public int Priority { get; set; } + } +} \ No newline at end of file diff --git a/ASS.Pages/Main.cs b/ASS.Pages/Main.cs new file mode 100644 index 0000000..5b85874 --- /dev/null +++ b/ASS.Pages/Main.cs @@ -0,0 +1,58 @@ +namespace ASS.Pages +{ + using System; + + using LabApi.Features; + using LabApi.Loader.Features.Plugins; + + #if EXILED + public class Main : Exiled.API.Features.Plugin + #elif LABAPI + public class Main : Plugin + #endif + { + public override string Name => "ASS.Pages"; + + public override string Author => "@Someone"; + + public override Version Version { get; } = new(1, 0, 0); + + #if EXILED + public override string Prefix => "ASS_Pages"; + #elif LABAPI + public override string Description => "Adds pages to ASS"; + + public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion); + #endif + + #if EXILED + public override void OnEnabled() + { + Enabled(); + } + + public override void OnDisabled() + { + Disabled(); + } + #elif LABAPI + public override void Enable() + { + Enabled(); + } + + public override void Disable() + { + Disabled(); + } + #endif + + private void Enabled() + { + } + + private void Disabled() + { + } + } +} \ No newline at end of file diff --git a/ASS.sln b/ASS.sln index d3d738d..1d058fa 100644 --- a/ASS.sln +++ b/ASS.sln @@ -4,6 +4,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ASS", "ASS\ASS.csproj", "{5 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ASS.Example", "ASS.Example\ASS.Example.csproj", "{537BC30F-80F8-4A91-9D24-25E23B7BA28B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ASS.Pages", "ASS.Pages\ASS.Pages.csproj", "{2E38C870-CAFF-4B9D-A539-23E87DF283EE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution LabAPI|Any CPU = LabAPI|Any CPU @@ -18,5 +20,9 @@ Global {537BC30F-80F8-4A91-9D24-25E23B7BA28B}.LabAPI|Any CPU.Build.0 = LabAPI|Any CPU {537BC30F-80F8-4A91-9D24-25E23B7BA28B}.Exiled|Any CPU.ActiveCfg = Exiled|Any CPU {537BC30F-80F8-4A91-9D24-25E23B7BA28B}.Exiled|Any CPU.Build.0 = Exiled|Any CPU + {2E38C870-CAFF-4B9D-A539-23E87DF283EE}.LabAPI|Any CPU.ActiveCfg = LabAPI|Any CPU + {2E38C870-CAFF-4B9D-A539-23E87DF283EE}.LabAPI|Any CPU.Build.0 = LabAPI|Any CPU + {2E38C870-CAFF-4B9D-A539-23E87DF283EE}.Exiled|Any CPU.ActiveCfg = Exiled|Any CPU + {2E38C870-CAFF-4B9D-A539-23E87DF283EE}.Exiled|Any CPU.Build.0 = Exiled|Any CPU EndGlobalSection EndGlobal diff --git a/ASS/Features/ASSExtensions.cs b/ASS/Features/ASSExtensions.cs new file mode 100644 index 0000000..0a0a4be --- /dev/null +++ b/ASS/Features/ASSExtensions.cs @@ -0,0 +1,73 @@ +namespace ASS.Features +{ + using System; + using System.Collections.Generic; + using System.Linq; + using ASS.Features.Interfaces; + using ASS.Features.Settings; + using LabApi.Features.Wrappers; + using NorthwoodLib.Pools; + + public static class ASSExtensions + { + public static List GetAllSettings(this IASSObject assObject) + { + List settings = []; + List previousObjects = ListPool.Shared.Rent(); + InternalGetAllSettings(assObject, settings, previousObjects); + ListPool.Shared.Return(previousObjects); + return settings; + } + + public static List GetViewableSettingsOrdered(this IASSObject assObject, Player? viewer) + { + if (viewer == null) + return []; + List settings = []; + List previousGroups = ListPool.Shared.Rent(); + InternalGetViewableSettingsOrdered(assObject, settings, previousGroups, viewer); + ListPool.Shared.Return(previousGroups); + return settings; + } + + private static void InternalGetAllSettings(IASSObject assObject, List current, List previousObjects) + { + if (assObject is ISettingsObject settings) + current.AddRange(settings.Settings); + + if (assObject.Children == null) + return; + previousObjects.Add(assObject); + foreach (IASSObject group in assObject.Children) + { + if (previousObjects.Contains(group)) + throw new InvalidOperationException("ASS objects cannot reference themselves within their children."); + InternalGetAllSettings(group, current, previousObjects); + } + + previousObjects.Remove(assObject); + } + + private static void InternalGetViewableSettingsOrdered(IASSObject assObject, List current, List previousChildren, Player viewer) + { + if (assObject is ISettingsObject settingsObject) + { + if (assObject.Viewers == null || assObject.Viewers(viewer)) + current.AddRange(settingsObject.Settings); + } + + if (assObject.Children == null) + return; + previousChildren.Add(assObject); + foreach (IASSObject obj in assObject.Children.Where(obj => (obj.Viewers?.Invoke(viewer) ?? true)).OrderByDescending(group => group.Priority)) + { + if (previousChildren.Contains(obj)) + throw new InvalidOperationException("ASS objects cannot reference themselves within their children."); + + InternalGetViewableSettingsOrdered(obj, current, previousChildren, viewer); + } + + previousChildren.Remove(assObject); + } + } +} \ No newline at end of file diff --git a/ASS/Features/ASSNetworking.cs b/ASS/Features/ASSNetworking.cs index 224c9c5..0a5bff9 100644 --- a/ASS/Features/ASSNetworking.cs +++ b/ASS/Features/ASSNetworking.cs @@ -9,6 +9,7 @@ namespace ASS.Features using ASS.Events.EventArgs; using ASS.Events.Handlers; using ASS.Features.Collections; + using ASS.Features.Interfaces; using ASS.Features.MirrorUtils; using ASS.Features.MirrorUtils.Messages; using ASS.Features.Settings; @@ -38,9 +39,9 @@ public static class ASSNetworking /// public static Dictionary ReceivedSettings { get; } = new(); - public static List Groups { get; } = []; + public static List Objects { get; } = []; - public static IEnumerable Settings { get; } = Groups.SelectMany(group => group.GetAllSettings()); + public static IEnumerable Settings { get; } = Objects.SelectMany(obj => obj.GetAllSettings()); public static Dictionary Versions { get; } = new(); @@ -66,7 +67,7 @@ public static class ASSNetworking /// /// Useful if you want to force only a certain group or 2 to be visible to a player (like a setting controlling what settings you can see, then the group of settings you're looking at). /// - public static Dictionary PlayerOverrides { get; } = new(); + public static Dictionary PlayerOverrides { get; } = new(); public static bool TryGetSetting(Player player, int id, [NotNullWhen(true)] out T? value) where T : ASSBase @@ -160,10 +161,10 @@ public static void SendSSSIncludingASS(Player player, ServerSpecificSettingBase[ } } - public static void RegisterGroups(IEnumerable groups, IEnumerable? toUpdate = null) + public static void RegisterObjects(IEnumerable groups, IEnumerable? toUpdate = null) { groups = groups.Where(group => group != null); - Groups.AddRange(groups); + Objects.AddRange(groups); if (toUpdate is null) return; @@ -175,7 +176,7 @@ public static void RegisterGroups(IEnumerable groups, IEnumerable groups, IEnumerable? toUpdate = null) { groups = groups.Where(group => group != null); - Groups.RemoveAll(groups.Contains); + Objects.RemoveAll(groups.Contains); if (toUpdate is null) return; @@ -238,18 +239,18 @@ internal static void SendByFilter(Func filter) internal static IEnumerable GetRegisteredSorted(Player player) { - IEnumerable groups; + IEnumerable objects; - if (PlayerOverrides.TryGetValue(player, out ASSGroup[] groupArray)) + if (PlayerOverrides.TryGetValue(player, out IASSObject[] objArray)) { - groups = groupArray; + objects = objArray; } else { - groups = Groups; + objects = Objects; } - return groups.OrderByDescending(group => group.Priority).SelectMany(group => group.GetViewableSettingsOrdered(player)); + return objects.OrderByDescending(obj => obj.Priority).SelectMany(obj => obj.GetViewableSettingsOrdered(player)); } internal static void ProcessResponseMessage(NetworkConnectionToClient conn, SSSClientResponse message) diff --git a/ASS/Features/Collections/ASSGroup.cs b/ASS/Features/Collections/ASSGroup.cs index 3b64d62..8df5e22 100644 --- a/ASS/Features/Collections/ASSGroup.cs +++ b/ASS/Features/Collections/ASSGroup.cs @@ -3,21 +3,19 @@ namespace ASS.Features.Collections using System; using System.Collections.Generic; using System.Linq; - + using ASS.Features.Interfaces; using ASS.Features.Settings; - using LabApi.Features.Wrappers; - using NorthwoodLib.Pools; - public class ASSGroup + public class ASSGroup : IASSObject, ISettingsObject { - public ASSGroup(IEnumerable settings, int priority = 0, Predicate? viewers = null, IEnumerable? subGroups = null) + public ASSGroup(IEnumerable settings, int priority = 0, Predicate? viewers = null, IEnumerable? subGroups = null) { Settings = settings.ToList(); Priority = priority; Viewers = viewers; - SubGroups = subGroups?.ToList(); + Children = subGroups?.ToList(); } public List Settings { get; set; } @@ -26,59 +24,6 @@ public ASSGroup(IEnumerable settings, int priority = 0, Predicate? Viewers { get; set; } - public List? SubGroups { get; set; } - - public List GetAllSettings() - { - List settings = []; - List previousGroups = ListPool.Shared.Rent(); - InternalGetAllSettings(settings, previousGroups); - ListPool.Shared.Return(previousGroups); - return settings; - } - - public List GetViewableSettingsOrdered(Player? viewer) - { - if (viewer == null) - return []; - List settings = []; - List previousGroups = ListPool.Shared.Rent(); - InternalGetViewableSettingsOrdered(settings, previousGroups, viewer); - ListPool.Shared.Return(previousGroups); - return settings; - } - - private void InternalGetAllSettings(List current, List previousGroups) - { - current.AddRange(Settings); - if (SubGroups == null) - return; - previousGroups.Add(this); - foreach (ASSGroup group in SubGroups) - { - if (previousGroups.Contains(group)) - throw new InvalidOperationException("ASSGroups cannot reference themselves within subgroups."); - group.InternalGetAllSettings(current, previousGroups); - } - - previousGroups.Remove(this); - } - - private void InternalGetViewableSettingsOrdered(List current, List previousGroups, Player viewer) - { - if (Viewers == null || Viewers(viewer)) - current.AddRange(Settings); - if (SubGroups == null) - return; - previousGroups.Add(this); - foreach (ASSGroup group in SubGroups.Where(group => group.Viewers == null || group.Viewers(viewer)).OrderByDescending(group => group.Priority)) - { - if (previousGroups.Contains(group)) - throw new InvalidOperationException("ASSGroups cannot reference themselves within subgroups."); - group.InternalGetViewableSettingsOrdered(current, previousGroups, viewer); - } - - previousGroups.Remove(this); - } + public List? Children { get; set; } } } \ No newline at end of file diff --git a/ASS/Features/Collections/AbstractMenu.cs b/ASS/Features/Collections/AbstractMenu.cs index 0efd274..362fc0b 100644 --- a/ASS/Features/Collections/AbstractMenu.cs +++ b/ASS/Features/Collections/AbstractMenu.cs @@ -12,7 +12,7 @@ public void Add(Player player) { Groups[player] = Generate(player); - ASSNetworking.RegisterGroups([Groups[player]], [player]); + ASSNetworking.RegisterObjects([Groups[player]], [player]); } public void Update(Player player, bool registerChange = true, bool ignoreDefaultResponses = false, bool onlyGroupsResponses = false) @@ -25,7 +25,7 @@ public void Update(Player player, bool registerChange = true, bool ignoreDefault group.Settings = newGroup.Settings; group.Priority = newGroup.Priority; group.Viewers = newGroup.Viewers; - group.SubGroups = newGroup.SubGroups; + group.Children = newGroup.Children; ASSNetworking.SendToPlayerFull(player, true, registerChange, false, ignoreDefaultResponses || onlyGroupsResponses, onlyGroupsResponses ? group.GetAllSettings().ToArray() : null); } diff --git a/ASS/Features/Collections/PlayerMenu.cs b/ASS/Features/Collections/PlayerMenu.cs index a885800..0e5d7c5 100644 --- a/ASS/Features/Collections/PlayerMenu.cs +++ b/ASS/Features/Collections/PlayerMenu.cs @@ -15,7 +15,7 @@ public PlayerMenu(GroupUpdateHandler generator, Player owner, bool updateOwner = Current = generator(owner); - ASSNetworking.RegisterGroups([Current], updateOwner ? [owner] : []); + ASSNetworking.RegisterObjects([Current], updateOwner ? [owner] : []); } [Obsolete("Use constructor with \"updateOwner\" instead.")] @@ -79,7 +79,7 @@ public void Update(bool registerChange = true, bool ignoreDefaultResponses = fal Current.Settings = newGroup.Settings; Current.Priority = newGroup.Priority; Current.Viewers = newGroup.Viewers; - Current.SubGroups = newGroup.SubGroups; + Current.Children = newGroup.Children; ASSNetworking.SendToPlayerFull(Owner, true, registerChange, false, ignoreDefaultResponses || onlyGroupsResponses, onlyGroupsResponses ? Current.GetAllSettings().ToArray() : null); } diff --git a/ASS/Features/Interfaces/IASSObject.cs b/ASS/Features/Interfaces/IASSObject.cs new file mode 100644 index 0000000..0d3bd58 --- /dev/null +++ b/ASS/Features/Interfaces/IASSObject.cs @@ -0,0 +1,18 @@ +namespace ASS.Features.Interfaces +{ + using System; + using System.Collections.Generic; + using System.Linq; + using ASS.Features.Settings; + using LabApi.Features.Wrappers; + using NorthwoodLib.Pools; + + public interface IASSObject + { + public List? Children { get; set; } + + public Predicate? Viewers { get; set; } + + public int Priority { get; set; } + } +} \ No newline at end of file diff --git a/ASS/Features/Interfaces/ISettingsObject.cs b/ASS/Features/Interfaces/ISettingsObject.cs new file mode 100644 index 0000000..1558b20 --- /dev/null +++ b/ASS/Features/Interfaces/ISettingsObject.cs @@ -0,0 +1,10 @@ +namespace ASS.Features.Interfaces +{ + using System.Collections.Generic; + using ASS.Features.Settings; + + public interface ISettingsObject + { + public List Settings { get; set; } + } +} \ No newline at end of file