#pragma once #include "CoreMinimal.h" #include "WingServer.h" #include "WingHandler.h" #include "WingUtils.h" #include "UObject/UObjectIterator.h" #include "Class_Search.generated.h" // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // ============================================================ // HandleListClasses — discover available UClasses // ============================================================ UCLASS() class UWing_Class_Search : public UObject, public IWingHandler { GENERATED_BODY() public: UPROPERTY(meta=(Optional, Description="Substring filter for class names")) FString Query; UPROPERTY(meta=(Optional, Description="Parent class name to restrict results to subclasses")) FString ParentClass; UPROPERTY(meta=(Optional, Description="Maximum number of results to return (1-500, default 100)")) int32 Limit = 100; virtual FString GetDescription() const override { return TEXT("Search for available UClasses by name substring and/or parent class. " "Returns class names, parent class, package, and flags."); } virtual void Handle() override { Limit = FMath::Clamp(Limit, 1, 500); UClass* ParentClassObj = nullptr; if (!ParentClass.IsEmpty()) { for (TObjectIterator It; It; ++It) { if (WingUtils::Identifies(ParentClass, *It)) { ParentClassObj = *It; break; } } if (!ParentClassObj) { UWingServer::Printf(TEXT("Error: Parent class '%s' not found\n"), *ParentClass); return; } } TArray Matches; int32 TotalMatched = 0; for (TObjectIterator It; It; ++It) { UClass* Class = *It; if (!Class) continue; if (Class->HasAnyClassFlags(CLASS_Deprecated | CLASS_NewerVersionExists)) continue; if (ParentClassObj && !Class->IsChildOf(ParentClassObj)) continue; FString ClassName = WingUtils::FormatName(Class); if (!Query.IsEmpty() && !ClassName.Contains(Query, ESearchCase::IgnoreCase)) continue; TotalMatched++; if (Matches.Num() < Limit) { Matches.Add(Class); } } UWingServer::Printf(TEXT("Found %d classes"), TotalMatched); if (TotalMatched > Limit) { UWingServer::Printf(TEXT(" (showing %d)"), Limit); } UWingServer::Print(TEXT("\n")); for (UClass* Class : Matches) { UWingServer::Printf(TEXT(" %s"), *WingUtils::FormatName(Class)); // Flags TStringBuilder<64> Flags; if (Class->HasAnyClassFlags(CLASS_Abstract)) Flags.Append(TEXT(" Abstract")); if (Class->HasAnyClassFlags(CLASS_Interface)) Flags.Append(TEXT(" Interface")); if (Class->HasAnyClassFlags(CLASS_MinimalAPI)) Flags.Append(TEXT(" MinimalAPI")); if (Class->ClassGeneratedBy) Flags.Append(TEXT(" Blueprint")); if (Flags.Len() > 0) { UWingServer::Printf(TEXT(" [%s]"), Flags.ToString() + 1); // skip leading space } if (Class->GetSuperClass()) { UWingServer::Printf(TEXT(" : %s"), *WingUtils::FormatName(Class->GetSuperClass())); } UWingServer::Print(TEXT("\n")); } } };