Skip to content

Commit

Permalink
Initial Catalog Search Implementation
Browse files Browse the repository at this point in the history
- Search individual categories and inventory. Supports build/buy
- Currently only indexes builtin objects by OBJD name.
- Supports tags from catalog xml, index by CTSS for CC.
  • Loading branch information
riperiperi committed Oct 3, 2022
1 parent 0f712a9 commit 345492a
Show file tree
Hide file tree
Showing 14 changed files with 324 additions and 15 deletions.
1 change: 1 addition & 0 deletions TSOClient/tso.client/FSO.Client.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@
<Compile Include="UI\Panels\EODs\UIGameshowBuzzerPlayerEOD.cs" />
<Compile Include="UI\Panels\EODs\UIGameshowBuzzerEOD.cs" />
<Compile Include="UI\Panels\UIAbstractCatalogMode.cs" />
<Compile Include="UI\Panels\UICatalogSearchPanel.cs" />
<Compile Include="UI\Panels\Upgrades\UIUpgradeItem.cs" />
<Compile Include="UI\Panels\Upgrades\UIUpgradeList.cs" />
<Compile Include="UI\Panels\Upgrades\UIUpgradeThermo.cs" />
Expand Down
97 changes: 90 additions & 7 deletions TSOClient/tso.client/UI/Controls/Catalog/UICatalog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
using FSO.SimAntics.Model;
using FSO.Content.Interfaces;
using FSO.Client.UI.Panels;
using System.Text.RegularExpressions;

namespace FSO.Client.UI.Controls.Catalog
{
Expand Down Expand Up @@ -125,7 +126,7 @@ private static void AddFloors()
for (int i = 0; i < floors.Count; i++)
{
var floor = (FloorReference)floors[i];
sbyte category = (sbyte)((floor.ID >= 65534)?5:9);
sbyte category = (sbyte)((floor.ID >= 65534) ? 5 : 9);
_Catalog[category].Insert(0, new UICatalogElement
{
Item = new ObjectCatalogItem()
Expand Down Expand Up @@ -276,9 +277,12 @@ private static void AddTerrainTools()

public int PageSize { get; set; }
public List<UICatalogElement> Selected;
public List<UICatalogElement> Filtered;
private UICatalogItem[] CatalogItems;
private Dictionary<uint, Texture2D> IconCache;

private string SearchTerm;

public UICatalog(int pageSize)
{
IconCache = new Dictionary<uint, Texture2D>();
Expand All @@ -292,13 +296,91 @@ public void SetActive(int selection, bool active) {

public void SetCategory(List<UICatalogElement> select) {
Selected = select;
FilterSelected();
SetPage(0);
}

private void AddMatchScore(string name, Regex search, ref int score)
{
if (name == null) return;

var allMatches = search.Matches(name);

foreach (Match match in allMatches)
{
int matchScore = 4;

if (match.Index == 0 || char.IsWhiteSpace(name[match.Index - 1]))
{
matchScore *= 2;
}

if (match.Index + match.Value.Length == name.Length || char.IsWhiteSpace(name[match.Index + match.Value.Length]))
{
matchScore *= 3;
}

score += matchScore;
}
}

private int GetScore(UICatalogElement elem)
{
ref var item = ref elem.Item;

string name = item.Name.ToLowerInvariant();
string catalogName = item.CatalogName?.ToLowerInvariant();
string tags = item.Tags?.ToLowerInvariant();

string[] termWords = SearchTerm.ToLowerInvariant().Split(' ');

int score = 0;

foreach (string word in termWords)
{
var search = new Regex(".*" + Regex.Escape(word) + ".*");

AddMatchScore(name, search, ref score);
AddMatchScore(catalogName, search, ref score);
AddMatchScore(tags, search, ref score);
}

return score;
}

public void FilterSelected()
{
if (SearchTerm != null && Selected != null)
{
Filtered = Selected
.Select(elem => new Tuple<UICatalogElement, int>(elem, GetScore(elem)))
.Where(tuple => tuple.Item2 > 0)
.OrderByDescending(tuple => tuple.Item2)
.Select(tuple => tuple.Item1)
.ToList();
}
else
{
Filtered = Selected;
}
}

public void SetSearchTerm(string term)
{
if (term == "") term = null;

if (SearchTerm != term)
{
SearchTerm = term;
FilterSelected();
SetPage(0);
}
}

public int TotalPages()
{
if (Selected == null) return 0;
return ((Selected.Count-1) / PageSize)+1;
if (Filtered == null) return 0;
return ((Filtered.Count - 1) / PageSize) + 1;
}

public int GetPage()
Expand All @@ -316,12 +398,13 @@ public void SetPage(int page) {
}

int index = page*PageSize;
if (Selected == null) return;
CatalogItems = new UICatalogItem[Math.Min(PageSize, Math.Max(Selected.Count-index, 0))];
if (Filtered == null) return;
CatalogItems = new UICatalogItem[Math.Min(PageSize, Math.Max(Filtered.Count - index, 0))];
int halfPage = PageSize / 2;

for (int i=0; i<CatalogItems.Length; i++) {
var sel = Selected[index++];
for (int i=0; i<CatalogItems.Length; i++)
{
var sel = Filtered[index++];
var elem = new UICatalogItem(false);
if (sel.Item.GUID == uint.MaxValue) elem.Visible = false;
elem.Index = index-1;
Expand Down
39 changes: 37 additions & 2 deletions TSOClient/tso.client/UI/Panels/UIAbstractCatalogMode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ public abstract class UIAbstractCatalogPanel : UICachedContainer

protected Dictionary<uint, byte> UpgradeLevelMemory = new Dictionary<uint, byte>();

protected UIButton SearchButton;
protected UICatalogSearchPanel SearchPanel;

protected bool UseSmall;
public UIAbstractCatalogPanel(string mode, UILotControl lotController)
{
Expand Down Expand Up @@ -83,8 +86,28 @@ public UIAbstractCatalogPanel(string mode, UILotControl lotController)
ObjLimitLabel.Size = new Microsoft.Xna.Framework.Vector2(200, 0);
ObjLimitLabel.Alignment = TextAlignment.Center;
DynamicOverlay.Add(ObjLimitLabel);

var ui = Content.Content.Get().CustomUI;
var gd = GameFacade.GraphicsDevice;

SearchPanel = new UICatalogSearchPanel(this);
SearchPanel.XOffset = Background.Width - 259;
SearchPanel.OnUpdate += SearchUpdated;

SearchButton = new UIButton(ui.Get("cat_search.png").Get(gd));
SearchButton.Y = 8;
SearchButton.X = Background.Width - (6 + 13);
SearchButton.OnButtonClick += (UIElement btn) => { SearchButton.Selected = SearchPanel.Toggle(); };
this.Add(SearchButton);
}


private void SearchUpdated(string term)
{
Catalog.SetSearchTerm(term);
SetPage(0);
Invalidate();
}

private void HolderBeforeRelease(UIObjectSelection holding, UpdateState state)
{
// remember the upgrade level between entering the catalog
Expand Down Expand Up @@ -143,6 +166,9 @@ public override void Removed()
Holder.ClearSelected();
QueryPanel.Active = false;
}

SearchPanel.Parent?.Remove(SearchPanel);

base.Removed();
}

Expand Down Expand Up @@ -217,7 +243,7 @@ protected virtual void Catalog_OnSelectionChange(int selection)
}
}
Holder.ClearSelected();
var item = CurrentCategory[selection];
var item = Catalog.Filtered[selection];

if (LotController.ActiveEntity != null && item.CalcPrice > LotController.ActiveEntity.TSOState.Budget.Value)
{
Expand Down Expand Up @@ -274,5 +300,14 @@ protected virtual void Catalog_OnSelectionChange(int selection)
OldSelection = selection;
}

public override void Update(UpdateState state)
{
if (SearchPanel.Parent == null)
{
SearchPanel.SetParent(this.Parent);
}

base.Update(state);
}
}
}
5 changes: 4 additions & 1 deletion TSOClient/tso.client/UI/Panels/UIBuildMode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,15 +139,18 @@ public override void InitCategoryMap()

public override void SetPage(int page)
{
int total = Catalog.TotalPages();

bool noPrev = (page == 0);
PreviousPageButton.Disabled = noPrev;

bool noNext = (page + 1 == Catalog.TotalPages());
bool noNext = (page + 1 == total);
NextPageButton.Disabled = noNext;

Catalog.SetPage(page);
if (OldSelection != -1) Catalog.SetActive(OldSelection, true);

SubtoolsSlider.MaxValue = total - 1;
SubtoolsSlider.Value = page;
}

Expand Down
8 changes: 7 additions & 1 deletion TSOClient/tso.client/UI/Panels/UIBuyMode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -261,19 +261,25 @@ override protected void Catalog_OnSelectionChange(int selection)

public override void SetPage(int page)
{
int total = Catalog.TotalPages();

bool noPrev = (page == 0);
ProductCatalogPreviousPageButton.Disabled = noPrev;
InventoryCatalogRoommatePreviousPageButton.Disabled = noPrev;
InventoryCatalogVisitorPreviousPageButton.Disabled = noPrev;

bool noNext = (page + 1 == Catalog.TotalPages());
bool noNext = (page + 1 == total);
ProductCatalogNextPageButton.Disabled = noNext;
InventoryCatalogRoommateNextPageButton.Disabled = noNext;
InventoryCatalogVisitorNextPageButton.Disabled = noNext;

Catalog.SetPage(page);
if (OldSelection != -1) Catalog.SetActive(OldSelection, true);

ProductCatalogSlider.MaxValue = total - 1;
InventoryCatalogRoommateSlider.MaxValue = total - 1;
InventoryCatalogVisitorSlider.MaxValue = total - 1;

ProductCatalogSlider.Value = page;
InventoryCatalogRoommateSlider.Value = page;
InventoryCatalogVisitorSlider.Value = page;
Expand Down
Loading

0 comments on commit 345492a

Please sign in to comment.