Merge remote-tracking branch 'origin/feat/inport-props' into feat/craft-discovery

# Conflicts:
#	Assets/External/Animated PBR Chest Demo/Materials/WoodChest.mat
#	Packages/com.distantlands.cozy.core/Content/Integration/Import for BiRP.unitypackage.meta
#	Packages/com.distantlands.cozy.core/Content/Integration/Import for HDRP.unitypackage.meta
#	Packages/com.distantlands.cozy.core/Content/Integration/Import for URP.unitypackage.meta
This commit is contained in:
2026-07-25 19:42:26 +02:00
954 changed files with 999772 additions and 26193 deletions
@@ -31,6 +31,7 @@ namespace Ashwild.EditorTools
#region Constants
private const string UssPath = "Assets/GAME/Script/Editor/Database/AshwildDatabase.uss";
private const string AllTypesLabel = "All Types";
#endregion
@@ -38,6 +39,7 @@ namespace Ashwild.EditorTools
private Tab activeTab = Tab.Items;
private string searchFilter = string.Empty;
private string itemTypeFilter = AllTypesLabel;
private readonly List<Object> sourceItems = new List<Object>();
private Object selectedAsset;
@@ -51,6 +53,7 @@ namespace Ashwild.EditorTools
private Button itemsTab;
private Button recipesTab;
private Button buildablesTab;
private PopupField<string> typeFilterField;
#endregion
@@ -106,7 +109,8 @@ namespace Ashwild.EditorTools
#region Toolbar
/// <summary>
/// Builds the top toolbar: the two family tabs, a search field, and the database rebuild action.
/// Builds the top toolbar: the three family tabs and the database rebuild action. The search
/// field and type filter live in the left-pane header, directly above the list they filter.
/// </summary>
private VisualElement BuildToolbar()
{
@@ -124,15 +128,6 @@ namespace Ashwild.EditorTools
spacer.AddToClassList("ash-toolbar-spacer");
toolbar.Add(spacer);
ToolbarSearchField search = new ToolbarSearchField();
search.AddToClassList("ash-search");
search.RegisterValueChangedCallback(evt =>
{
searchFilter = evt.newValue ?? string.Empty;
RefreshList();
});
toolbar.Add(search);
Button rebuild = new Button(ItemDatabaseBuilder.Rebuild) { text = "Rebuild DB" };
rebuild.AddToClassList("ash-btn");
rebuild.tooltip = "Re-scan every ItemData and rewrite the network ItemDatabase.";
@@ -175,6 +170,8 @@ namespace Ashwild.EditorTools
recipesTab.EnableInClassList("ash-tab--active", tab == Tab.Recipes);
buildablesTab.EnableInClassList("ash-tab--active", tab == Tab.Buildables);
UpdateTypeFilterVisibility();
selectedAsset = null;
RefreshList();
ShowSelection();
@@ -185,13 +182,16 @@ namespace Ashwild.EditorTools
#region Left Pane
/// <summary>
/// Builds the left pane: a styled list of the active family plus a footer "New" button.
/// Builds the left pane: a filter header (search + item-type filter), a styled list of the
/// active family, and a footer "New" button.
/// </summary>
private VisualElement BuildLeftPane()
{
VisualElement left = new VisualElement();
left.AddToClassList("ash-left");
left.Add(BuildListHeader());
listView = new ListView(sourceItems)
{
fixedItemHeight = 48,
@@ -214,6 +214,58 @@ namespace Ashwild.EditorTools
return left;
}
/// <summary>
/// Builds the header sitting above the list: a search field that filters by name across every
/// family, and an item-type dropdown that narrows the item list to a single type. The type
/// filter is only meaningful for items, so it is hidden on the Recipes and Buildables tabs.
/// </summary>
private VisualElement BuildListHeader()
{
VisualElement header = new VisualElement();
header.AddToClassList("ash-listheader");
ToolbarSearchField search = new ToolbarSearchField();
search.AddToClassList("ash-listsearch");
search.RegisterValueChangedCallback(evt =>
{
searchFilter = evt.newValue ?? string.Empty;
RefreshList();
});
header.Add(search);
List<string> typeChoices = new List<string> { AllTypesLabel };
typeChoices.AddRange(System.Enum.GetNames(typeof(ItemType)));
typeFilterField = new PopupField<string>(typeChoices, 0);
typeFilterField.AddToClassList("ash-typefilter");
typeFilterField.tooltip = "Show only items of the selected type.";
typeFilterField.RegisterValueChangedCallback(evt =>
{
itemTypeFilter = evt.newValue ?? AllTypesLabel;
RefreshList();
});
header.Add(typeFilterField);
return header;
}
/// <summary>
/// Shows the item-type dropdown only on the Items tab and resets it to "all" when leaving, so a
/// stale type filter never silently narrows a list it cannot apply to.
/// </summary>
private void UpdateTypeFilterVisibility()
{
if (typeFilterField == null) return;
bool showForItems = activeTab == Tab.Items;
typeFilterField.style.display = showForItems ? DisplayStyle.Flex : DisplayStyle.None;
if (!showForItems)
{
itemTypeFilter = AllTypesLabel;
typeFilterField.SetValueWithoutNotify(AllTypesLabel);
}
}
/// <summary>
/// Builds the reusable visual for a single list row (icon, name, type tag).
/// </summary>
@@ -251,6 +303,7 @@ namespace Ashwild.EditorTools
{
ItemData item => AshwildUI.TypeColor(item.ItemType),
BuildableData => AshwildUI.BuildableColor,
CraftingRecipe recipe when recipe.RequiredStation != CraftingStationType.None => AshwildUI.StationColor,
_ => new Color(0.5f, 0.52f, 0.58f)
};
@@ -421,6 +474,9 @@ namespace Ashwild.EditorTools
if (!string.IsNullOrEmpty(searchFilter)
&& AssetDisplayName(asset).IndexOf(searchFilter, System.StringComparison.OrdinalIgnoreCase) < 0)
continue;
if (activeTab == Tab.Items && itemTypeFilter != AllTypesLabel
&& asset is ItemData item && item.ItemType.ToString() != itemTypeFilter)
continue;
sourceItems.Add(asset);
}
@@ -465,12 +521,15 @@ namespace Ashwild.EditorTools
}
/// <summary>
/// The short type tag shown on the right of a list row (item type, or "Recipe").
/// The short type tag shown on the right of a list row. A recipe reports the station it is
/// crafted on rather than a flat "Recipe", so scanning the list tells which recipes are bench-
/// locked; hand recipes (station None) keep reading "Recipe".
/// </summary>
private static string AssetTag(Object asset)
{
if (asset is ItemData item) return item.ItemType.ToString();
if (asset is CraftingRecipe) return "Recipe";
if (asset is CraftingRecipe recipe)
return recipe.RequiredStation == CraftingStationType.None ? "Recipe" : recipe.RequiredStation.ToString();
if (asset is BuildableData) return "Buildable";
return string.Empty;
}