More import changes and more options

This commit is contained in:
Zeffuro
2025-12-22 05:42:36 +01:00
parent 5561305af8
commit c198663184
6 changed files with 174 additions and 21 deletions
@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Numerics; using System.Numerics;
using System.Text.Json.Serialization;
using KamiToolKit.Classes; using KamiToolKit.Classes;
namespace AetherBags.Configuration; namespace AetherBags.Configuration;
@@ -33,8 +34,14 @@ public class CategoryRuleSet
public List<uint> AllowedUiCategoryIds { get; set; } = new(); public List<uint> AllowedUiCategoryIds { get; set; } = new();
public List<int> AllowedRarities { get; set; } = new(); public List<int> AllowedRarities { get; set; } = new();
public RangeFilter<int> Level { get; set; } = new() { Enabled = false, Min = 0, Max = 200 };
public RangeFilter<int> ItemLevel { get; set; } = new() { Enabled = false, Min = 0, Max = 2000 }; public RangeFilter<int> ItemLevel { get; set; } = new() { Enabled = false, Min = 0, Max = 2000 };
public RangeFilter<uint> VendorPrice { get; set; } = new() { Enabled = false, Min = 0, Max = 9_999_999 }; public RangeFilter<uint> VendorPrice { get; set; } = new() { Enabled = false, Min = 0, Max = 9_999_999 };
public StateFilter Untradable { get; set; } = new();
public StateFilter Unique { get; set; } = new();
public StateFilter Collectable { get; set; } = new();
public StateFilter Dyeable { get; set; } = new();
public StateFilter Repairable { get; set; } = new();
} }
public class RangeFilter<T> where T : struct, IComparable<T> public class RangeFilter<T> where T : struct, IComparable<T>
@@ -42,4 +49,24 @@ public class RangeFilter<T> where T : struct, IComparable<T>
public bool Enabled { get; set; } public bool Enabled { get; set; }
public T Min { get; set; } public T Min { get; set; }
public T Max { get; set; } public T Max { get; set; }
}
public class StateFilter
{
public int State { get; set; } = 0;
public int Filter { get; set; } = 0;
[JsonIgnore]
public ToggleFilterState ToggleState
{
get => Enum.IsDefined(typeof(ToggleFilterState), State) ? (ToggleFilterState)State : ToggleFilterState.Ignored;
set => State = (int)value;
}
}
public enum ToggleFilterState
{
Ignored = 0,
Allow = 1,
Disallow = 2,
} }
@@ -3,13 +3,12 @@ using System.Numerics;
namespace AetherBags.Configuration.Import; namespace AetherBags.Configuration.Import;
// Possible Mapping: public sealed class SortaKindaImportFile
// Index -> Order {
// Color/Id/Name public List<SortaKindaCategory> Rules { get; set; } = new();
// AllowedItemNames -> AllowedItemNamePatterns
// AllowedItemTypes -> AllowedUiCategoryIds public object? MainInventory { get; set; }
// AllowedItemRarities -> AllowedRarities }
// ItemLevelFilter / VendorPriceFilter -> RangeFilter
public sealed class SortaKindaCategory public sealed class SortaKindaCategory
{ {
@@ -19,15 +18,38 @@ public sealed class SortaKindaCategory
public int Index { get; set; } public int Index { get; set; }
public List<string> AllowedItemNames { get; set; } = new(); public List<string> AllowedItemNames { get; set; } = new();
public List<AllowedNameRegexDto> AllowedNameRegexes { get; set; } = new();
// Common
public List<uint> AllowedItemTypes { get; set; } = new(); public List<uint> AllowedItemTypes { get; set; } = new();
public List<int> AllowedItemRarities { get; set; } = new(); public List<int> AllowedItemRarities { get; set; } = new();
public ExternalRangeFilterDto<int>? LevelFilter { get; set; }
public ExternalRangeFilterDto<int> ItemLevelFilter { get; set; } = new(); public ExternalRangeFilterDto<int> ItemLevelFilter { get; set; } = new();
public ExternalRangeFilterDto<uint> VendorPriceFilter { get; set; } = new(); public ExternalRangeFilterDto<uint> VendorPriceFilter { get; set; } = new();
public ExternalStateFilterDto? UntradableFilter { get; set; }
public ExternalStateFilterDto? UniqueFilter { get; set; }
public ExternalStateFilterDto? CollectableFilter { get; set; }
public ExternalStateFilterDto? DyeableFilter { get; set; }
public ExternalStateFilterDto? RepairableFilter { get; set; }
public int Direction { get; set; } public int Direction { get; set; }
public int FillMode { get; set; } public int FillMode { get; set; }
public int SortMode { get; set; } public int SortMode { get; set; }
public bool InclusiveAnd { get; set; }
}
public sealed class AllowedNameRegexDto
{
public string Text { get; set; } = string.Empty;
}
public sealed class ExternalStateFilterDto
{
public int State { get; set; }
public int Filter { get; set; }
} }
public sealed class ExternalRangeFilterDto<T> where T : struct public sealed class ExternalRangeFilterDto<T> where T : struct
@@ -52,7 +52,19 @@ public static class SortaKindaImportExport
return false; return false;
} }
var external = Util.DeserializeCompressed<SortaKindaCategory[]>(input.Trim(), ExternalJsonOptions); string trimmed = input.Trim();
SortaKindaCategory[]? external = null;
SortaKindaImportFile? file = Util.DeserializeCompressed<SortaKindaImportFile>(trimmed, ExternalJsonOptions);
if (file?.Rules is { Count: > 0 })
{
external = file.Rules.ToArray();
}
else
{
external = Util.DeserializeCompressed<SortaKindaCategory[]>(trimmed, ExternalJsonOptions);
}
if (external is null) if (external is null)
{ {
@@ -104,10 +116,15 @@ public static class SortaKindaImportExport
public static string ExportToJson(SystemConfiguration sourceConfig) public static string ExportToJson(SystemConfiguration sourceConfig)
{ {
var exported = sourceConfig.Categories.UserCategories var exported = new SortaKindaImportFile
.OrderBy(c => c.Order) {
.Select(MapToExternal) Rules = sourceConfig.Categories.UserCategories
.ToArray(); .OrderBy(c => c.Priority)
.Select(MapToExternal)
.ToList(),
// MainInventory = new { InventoryConfigs = new[] { new { } } }
};
return Util.SerializeCompressed(exported, ExternalJsonOptions); return Util.SerializeCompressed(exported, ExternalJsonOptions);
} }
@@ -122,14 +139,28 @@ public static class SortaKindaImportExport
Name = external.Name, Name = external.Name,
Description = string.Empty, Description = string.Empty,
Order = external.Index, Order = external.Index,
Priority = 100, Priority = external.Index,
Color = external.Color, Color = external.Color,
Rules = new CategoryRuleSet Rules = new CategoryRuleSet
{ {
AllowedItemIds = new List<uint>(), AllowedItemIds = new List<uint>(),
AllowedItemNamePatterns = external.AllowedItemNames?.ToList() ?? new List<string>(),
AllowedItemNamePatterns =
(external.AllowedItemNames ?? new List<string>())
.Concat((external.AllowedNameRegexes ?? new List<AllowedNameRegexDto>())
.Select(r => r.Text)
.Where(t => !string.IsNullOrWhiteSpace(t)))
.ToList(),
AllowedUiCategoryIds = external.AllowedItemTypes?.ToList() ?? new List<uint>(), AllowedUiCategoryIds = external.AllowedItemTypes?.ToList() ?? new List<uint>(),
AllowedRarities = external.AllowedItemRarities?.ToList() ?? new List<int>(), AllowedRarities = external.AllowedItemRarities?.ToList() ?? new List<int>(),
Level = new RangeFilter<int>
{
Enabled = external.LevelFilter?.Enable ?? false,
Min = external.LevelFilter?.MinValue ?? 0,
Max = external.LevelFilter?.MaxValue ?? 200,
},
ItemLevel = new RangeFilter<int> ItemLevel = new RangeFilter<int>
{ {
Enabled = external.ItemLevelFilter?.Enable ?? false, Enabled = external.ItemLevelFilter?.Enable ?? false,
@@ -141,7 +172,13 @@ public static class SortaKindaImportExport
Enabled = external.VendorPriceFilter?.Enable ?? false, Enabled = external.VendorPriceFilter?.Enable ?? false,
Min = external.VendorPriceFilter?.MinValue ?? 0u, Min = external.VendorPriceFilter?.MinValue ?? 0u,
Max = external.VendorPriceFilter?.MaxValue ?? 9_999_999u, Max = external.VendorPriceFilter?.MaxValue ?? 9_999_999u,
} },
Untradable = new StateFilter { State = external.UntradableFilter?.State ?? 0, Filter = external.UntradableFilter?.Filter ?? 0 },
Unique = new StateFilter { State = external.UniqueFilter?.State ?? 0, Filter = external.UniqueFilter?.Filter ?? 0 },
Collectable= new StateFilter { State = external.CollectableFilter?.State ?? 0,Filter = external.CollectableFilter?.Filter ?? 0 },
Dyeable = new StateFilter { State = external.DyeableFilter?.State ?? 0, Filter = external.DyeableFilter?.Filter ?? 0 },
Repairable = new StateFilter { State = external.RepairableFilter?.State ?? 0, Filter = external.RepairableFilter?.Filter ?? 0 },
} }
}; };
@@ -151,10 +188,26 @@ public static class SortaKindaImportExport
Color = internalCat.Color, Color = internalCat.Color,
Id = internalCat.Id, Id = internalCat.Id,
Name = internalCat.Name, Name = internalCat.Name,
Index = internalCat.Order, Index = internalCat.Priority,
AllowedItemNames = internalCat.Rules.AllowedItemNamePatterns?.ToList() ?? new List<string>(),
AllowedItemNames = new List<string>(),
AllowedNameRegexes =
(internalCat.Rules.AllowedItemNamePatterns ?? new List<string>())
.Where(s => !string.IsNullOrWhiteSpace(s))
.Select(s => new AllowedNameRegexDto { Text = s })
.ToList(),
AllowedItemTypes = internalCat.Rules.AllowedUiCategoryIds?.ToList() ?? new List<uint>(), AllowedItemTypes = internalCat.Rules.AllowedUiCategoryIds?.ToList() ?? new List<uint>(),
AllowedItemRarities = internalCat.Rules.AllowedRarities?.ToList() ?? new List<int>(), AllowedItemRarities = internalCat.Rules.AllowedRarities?.ToList() ?? new List<int>(),
LevelFilter = new ExternalRangeFilterDto<int>
{
Enable = internalCat.Rules.Level.Enabled,
Label = "Level Filter",
MinValue = internalCat.Rules.Level.Min,
MaxValue = internalCat.Rules.Level.Max
},
ItemLevelFilter = new ExternalRangeFilterDto<int> ItemLevelFilter = new ExternalRangeFilterDto<int>
{ {
Enable = internalCat.Rules.ItemLevel.Enabled, Enable = internalCat.Rules.ItemLevel.Enabled,
@@ -169,8 +222,16 @@ public static class SortaKindaImportExport
MinValue = internalCat.Rules.VendorPrice.Min, MinValue = internalCat.Rules.VendorPrice.Min,
MaxValue = internalCat.Rules.VendorPrice.Max MaxValue = internalCat.Rules.VendorPrice.Max
}, },
UntradableFilter = new ExternalStateFilterDto { State = internalCat.Rules.Untradable.State, Filter = internalCat.Rules.Untradable.Filter },
UniqueFilter = new ExternalStateFilterDto { State = internalCat.Rules.Unique.State, Filter = internalCat.Rules.Unique.Filter },
CollectableFilter= new ExternalStateFilterDto { State = internalCat.Rules.Collectable.State,Filter = internalCat.Rules.Collectable.Filter },
DyeableFilter = new ExternalStateFilterDto { State = internalCat.Rules.Dyeable.State, Filter = internalCat.Rules.Dyeable.Filter },
RepairableFilter = new ExternalStateFilterDto { State = internalCat.Rules.Repairable.State, Filter = internalCat.Rules.Repairable.Filter },
Direction = 0, Direction = 0,
FillMode = 0, FillMode = 0,
SortMode = 0 SortMode = 0,
InclusiveAnd = false,
}; };
} }
+22 -3
View File
@@ -56,6 +56,8 @@ public static unsafe class InventoryState
private static readonly List<CategorizedInventory> FilteredCategories = new(capacity: 256); private static readonly List<CategorizedInventory> FilteredCategories = new(capacity: 256);
private static readonly List<UserCategoryDefinition> UserCategoriesSortedScratch = new(capacity: 64);
private static readonly List<uint> RemoveKeysScratch = new(capacity: 256); private static readonly List<uint> RemoveKeysScratch = new(capacity: 256);
private const uint UserCategoryKeyFlag = 0x8000_0000; private const uint UserCategoryKeyFlag = 0x8000_0000;
@@ -149,9 +151,22 @@ public static unsafe class InventoryState
if (userCategoriesEnabled && userCategories.Count > 0) if (userCategoriesEnabled && userCategories.Count > 0)
{ {
for (int c = 0; c < userCategories.Count; c++) UserCategoriesSortedScratch.Clear();
UserCategoriesSortedScratch.AddRange(userCategories);
UserCategoriesSortedScratch.Sort((a, b) =>
{ {
UserCategoryDefinition category = userCategories[c]; int p = b.Priority.CompareTo(a.Priority);
if (p != 0) return p;
int o = a.Order.CompareTo(b.Order);
if (o != 0) return o;
return string.Compare(a.Id, b.Id, StringComparison.OrdinalIgnoreCase);
});
for (int c = 0; c < UserCategoriesSortedScratch.Count; c++)
{
UserCategoryDefinition category = UserCategoriesSortedScratch[c];
uint key = MakeUserCategoryKey(category.Order); uint key = MakeUserCategoryKey(category.Order);
if (!BucketsByKey.TryGetValue(key, out CategoryBucket? bucket)) if (!BucketsByKey.TryGetValue(key, out CategoryBucket? bucket))
@@ -182,11 +197,15 @@ public static unsafe class InventoryState
foreach (var itemKvp in ItemInfoByItemId) foreach (var itemKvp in ItemInfoByItemId)
{ {
ItemInfo item = itemKvp.Value; ItemInfo item = itemKvp.Value;
uint itemId = item.Item.ItemId;
if (claimedItemIds.Contains(itemId))
continue;
if (UserCategoryMatcher.Matches(item, category)) if (UserCategoryMatcher.Matches(item, category))
{ {
bucket.Items.Add(item); bucket.Items.Add(item);
claimedItemIds.Add(item.Item.ItemId); claimedItemIds.Add(itemId);
} }
} }
+6
View File
@@ -47,6 +47,12 @@ public sealed class ItemInfo : IEquatable<ItemInfo>
public RowRef<ItemUICategory> UiCategory => Row.ItemUICategory; public RowRef<ItemUICategory> UiCategory => Row.ItemUICategory;
public bool IsUntradable => Row.IsUntradable;
public bool IsUnique => Row.IsUnique;
public bool IsCollectable => Row.IsCollectable;
public bool IsDyeable => Row.DyeCount > 0;
public bool IsRepairable => Row.ItemRepair.RowId != 0;
private string Description => _description ??= Row.Description.ToString(); private string Description => _description ??= Row.Description.ToString();
public bool IsRegexMatch(string searchTerms) public bool IsRegexMatch(string searchTerms)
@@ -24,12 +24,21 @@ internal static class UserCategoryMatcher
if (rules.AllowedRarities.Count > 0 && !rules.AllowedRarities.Contains(item.Rarity)) if (rules.AllowedRarities.Count > 0 && !rules.AllowedRarities.Contains(item.Rarity))
return false; return false;
if (rules.Level.Enabled && !InRange(item.Level, rules.Level.Min, rules.Level.Max))
return false;
if (rules.ItemLevel.Enabled && !InRange(item.ItemLevel, rules.ItemLevel.Min, rules.ItemLevel.Max)) if (rules.ItemLevel.Enabled && !InRange(item.ItemLevel, rules.ItemLevel.Min, rules.ItemLevel.Max))
return false; return false;
if (rules.VendorPrice.Enabled && !InRange(item.VendorPrice, rules.VendorPrice.Min, rules.VendorPrice.Max)) if (rules.VendorPrice.Enabled && !InRange(item.VendorPrice, rules.VendorPrice.Min, rules.VendorPrice.Max))
return false; return false;
if (!MatchesToggle(rules.Untradable, item.IsUntradable)) return false;
if (!MatchesToggle(rules.Unique, item.IsUnique)) return false;
if (!MatchesToggle(rules.Collectable, item.IsCollectable)) return false;
if (!MatchesToggle(rules.Dyeable, item.IsDyeable)) return false;
if (!MatchesToggle(rules.Repairable, item.IsRepairable)) return false;
if (rules.AllowedItemNamePatterns.Count > 0) if (rules.AllowedItemNamePatterns.Count > 0)
{ {
bool any = false; bool any = false;
@@ -63,4 +72,13 @@ internal static class UserCategoryMatcher
private static bool InRange<T>(T value, T min, T max) where T : struct, IComparable<T> private static bool InRange<T>(T value, T min, T max) where T : struct, IComparable<T>
=> value.CompareTo(min) >= 0 && value.CompareTo(max) <= 0; => value.CompareTo(min) >= 0 && value.CompareTo(max) <= 0;
private static bool MatchesToggle(StateFilter filter, bool itemHasProperty)
=> filter.ToggleState switch
{
ToggleFilterState.Ignored => true,
ToggleFilterState.Allow => itemHasProperty,
ToggleFilterState.Disallow => !itemHasProperty,
_ => true
};
} }