#pragma once #include "CoreMinimal.h" #include "MCPHandler.h" #include "MCPAssets.h" #include "MCPUtils.h" #include "Materials/Material.h" #include "Materials/MaterialExpression.h" #include "Materials/MaterialExpressionScalarParameter.h" #include "Materials/MaterialExpressionVectorParameter.h" #include "Materials/MaterialExpressionTextureSampleParameter2D.h" #include "Materials/MaterialExpressionStaticSwitchParameter.h" #include "UMCPHandler_SearchWithinMaterials.generated.h" // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- UCLASS(meta=(Group="Unclassified")) class UMCPHandler_SearchWithinMaterials : public UObject, public IMCPHandler { GENERATED_BODY() public: UPROPERTY(meta=(Description="Search query string to match against material names, expression classes, and parameter names")) FString Query; UPROPERTY(meta=(Optional, Description="Maximum number of results to return (default 50, max 200)")) int32 MaxResults = 50; virtual FString GetDescription() const override { return TEXT("Search across all materials for matching material names, expression types, and parameter names."); } virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override { FString DecodedQuery = MCPUtils::UrlDecode(Query); MaxResults = FMath::Clamp(MaxResults, 1, 200); int32 Count = 0; MCPAssets AllMaterials; AllMaterials.Load(); for (UMaterial* MaterialObj : AllMaterials.Objects()) { if (Count >= MaxResults) break; if (!MaterialObj) continue; FString MatName = MCPUtils::FormatName(MaterialObj); // Check material name bool bNameMatch = MatName.Contains(DecodedQuery, ESearchCase::IgnoreCase); if (bNameMatch) { Result.Appendf(TEXT("material %s\n"), *MatName); Count++; } // Search expressions for (UMaterialExpression* Expr : MaterialObj->GetExpressions()) { if (!Expr || Count >= MaxResults) continue; FString ExprName = MCPUtils::FormatName(Expr); FString ExprClass = Expr->GetClass()->GetName(); FString ExprDesc = Expr->GetDescription(); // Check parameter name FString ParamName; if (auto* SP = Cast(Expr)) ParamName = SP->ParameterName.ToString(); else if (auto* VP = Cast(Expr)) ParamName = VP->ParameterName.ToString(); else if (auto* TP = Cast(Expr)) ParamName = TP->ParameterName.ToString(); else if (auto* SSP = Cast(Expr)) ParamName = SSP->ParameterName.ToString(); bool bExprMatch = ExprDesc.Contains(DecodedQuery, ESearchCase::IgnoreCase) || ExprClass.Contains(DecodedQuery, ESearchCase::IgnoreCase) || (!ParamName.IsEmpty() && ParamName.Contains(DecodedQuery, ESearchCase::IgnoreCase)); if (!bExprMatch) continue; Result.Appendf(TEXT("expression %s in %s (%s)"), *ExprName, *MatName, *ExprClass); if (!ParamName.IsEmpty()) Result.Appendf(TEXT(" param=%s"), *ParamName); Result.Append(TEXT("\n")); Count++; } } if (Count == 0) { Result.Append(TEXT("No matches found.\n")); } else if (Count >= MaxResults) { Result.Appendf(TEXT("WARNING: Reached limit of %d results. Specify MaxResults to raise it.\n"), MaxResults); } } };