Remove stringbuilder parameter for handlers

This commit is contained in:
2026-03-13 23:41:59 -04:00
parent 7cfe73eca8
commit 2ffc493e91
76 changed files with 539 additions and 467 deletions

View File

@@ -260,57 +260,17 @@ TStatId UMCPServer::GetStatId() const
FString UMCPServer::HandleRequest(const FString& Line)
{
// Turn the request string into a JSON tree.
TSharedPtr<FJsonObject> Request;
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Line);
FJsonSerializer::Deserialize(Reader, Request);
if (!Request.IsValid())
{
return TEXT("Request is not valid JSON");
}
// Extract the command from the request.
FString Command;
if (!Request->TryGetStringField(TEXT("command"), Command))
{
return TEXT("Request does not contain 'command' parameter");
}
Request->RemoveField(TEXT("command"));
// Find the handler UClass for the specified command.
UClass** HandlerClass = MCPHandlerRegistry.Find(Command);
if (!HandlerClass)
{
return FString::Printf(TEXT("Unknown command: %s"), *Command);
}
// Make an object of the handler class.
TStrongObjectPtr<UObject> HandlerObj(NewObject<UObject>(GetTransientPackage(), *HandlerClass));
IMCPHandler* Handler = Cast<IMCPHandler>(HandlerObj.Get());
// Populate the handler object with the request parameters.
HandlerOutput.Reset();
if (!MCPUtils::PopulateFromJson(HandlerObj->GetClass(), HandlerObj.Get(), &*Request))
{
HandlerOutput.Append(TEXT("\nUsage:\n"));
MCPUtils::FormatCommandHelp(*HandlerClass, HandlerOutput);
FString Result = HandlerOutput.ToString();
HandlerOutput.Reset();
return Result;
}
// Invoke the handler with log capture.
LogCapture.CapturedErrors.Empty();
LogCapture.bEnabled = true;
HandlerOutput.Reset();
Handler->Handle(HandlerOutput);
TryCallHandler(Line);
Notifier.SendNotifications();
LogCapture.bEnabled = false;
for (const FString& Msg : LogCapture.CapturedErrors)
{
HandlerOutput.Append(TEXT("LOG: "));
HandlerOutput.Append(Msg);
HandlerOutput.Append(TEXT("\n"));
UMCPServer::Printf(TEXT("UE_LOG: %s\n"), *Msg);
}
LogCapture.CapturedErrors.Empty();
FString Result = HandlerOutput.ToString();
@@ -322,6 +282,51 @@ FString UMCPServer::HandleRequest(const FString& Line)
return Result;
}
void UMCPServer::TryCallHandler(const FString &Line)
{
// Turn the request string into a JSON tree.
TSharedPtr<FJsonObject> Request;
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Line);
FJsonSerializer::Deserialize(Reader, Request);
if (!Request.IsValid())
{
UMCPServer::Printf(TEXT("Request is not valid JSON"));
return;
}
// Extract the command from the request.
FString Command;
if (!Request->TryGetStringField(TEXT("command"), Command))
{
UMCPServer::Printf(TEXT("Request does not contain 'command' parameter"));
return;
}
Request->RemoveField(TEXT("command"));
// Find the handler UClass for the specified command.
UClass** HandlerClass = MCPHandlerRegistry.Find(Command);
if (!HandlerClass)
{
UMCPServer::Printf(TEXT("Unknown command: %s"), *Command);
return;
}
// Make an object of the handler class.
TStrongObjectPtr<UObject> HandlerObj(NewObject<UObject>(GetTransientPackage(), *HandlerClass));
IMCPHandler* Handler = Cast<IMCPHandler>(HandlerObj.Get());
// Populate the handler object with the request parameters.
if (!MCPUtils::PopulateFromJson(HandlerObj->GetClass(), HandlerObj.Get(), &*Request))
{
UMCPServer::Printf(TEXT("\nUsage:\n\n"));
MCPUtils::FormatCommandHelp(*HandlerClass);
return;
}
// Invoke the handler.
Handler->Handle();
}
// ============================================================
// Connection Maintenance
// ============================================================

View File

@@ -813,7 +813,7 @@ bool MCPUtils::ParseMaterialParameterAssociation(const FString& Str, EMaterialPa
return true;
}
void MCPUtils::FormatMaterialParameter(FStringBuilderBase& Result, const FMaterialParameterInfo& Info, const FMaterialParameterMetadata& Meta)
void MCPUtils::FormatMaterialParameter(const FMaterialParameterInfo& Info, const FMaterialParameterMetadata& Meta)
{
// Association prefix for layer/blend parameters.
FString Prefix;
@@ -825,35 +825,35 @@ void MCPUtils::FormatMaterialParameter(FStringBuilderBase& Result, const FMateri
switch (Meta.Value.Type)
{
case EMaterialParameterType::Scalar:
Result.Appendf(TEXT(" %sScalar \"%s\" = %g\n"), *Prefix, *Info.Name.ToString(), Meta.Value.AsScalar());
UMCPServer::Printf(TEXT(" %sScalar \"%s\" = %g\n"), *Prefix, *Info.Name.ToString(), Meta.Value.AsScalar());
break;
case EMaterialParameterType::Vector:
{
FLinearColor C = Meta.Value.AsLinearColor();
Result.Appendf(TEXT(" %sVector \"%s\" = (R=%.3f, G=%.3f, B=%.3f, A=%.3f)\n"),
UMCPServer::Printf(TEXT(" %sVector \"%s\" = (R=%.3f, G=%.3f, B=%.3f, A=%.3f)\n"),
*Prefix, *Info.Name.ToString(), C.R, C.G, C.B, C.A);
break;
}
case EMaterialParameterType::DoubleVector:
{
FVector4d V = Meta.Value.AsVector4d();
Result.Appendf(TEXT(" %sDoubleVector \"%s\" = (%.3f, %.3f, %.3f, %.3f)\n"),
UMCPServer::Printf(TEXT(" %sDoubleVector \"%s\" = (%.3f, %.3f, %.3f, %.3f)\n"),
*Prefix, *Info.Name.ToString(), V.X, V.Y, V.Z, V.W);
break;
}
case EMaterialParameterType::Texture:
{
UTexture* Tex = Cast<UTexture>(Meta.Value.AsTextureObject());
Result.Appendf(TEXT(" %sTexture \"%s\" = %s\n"),
UMCPServer::Printf(TEXT(" %sTexture \"%s\" = %s\n"),
*Prefix, *Info.Name.ToString(), Tex ? *MCPUtils::FormatName(Tex) : TEXT("None"));
break;
}
case EMaterialParameterType::StaticSwitch:
Result.Appendf(TEXT(" %sStaticSwitch \"%s\" = %s\n"),
UMCPServer::Printf(TEXT(" %sStaticSwitch \"%s\" = %s\n"),
*Prefix, *Info.Name.ToString(), Meta.Value.AsStaticSwitch() ? TEXT("true") : TEXT("false"));
break;
default:
Result.Appendf(TEXT(" %sType%d \"%s\"\n"), *Prefix, (int)Meta.Value.Type, *Info.Name.ToString());
UMCPServer::Printf(TEXT(" %sType%d \"%s\"\n"), *Prefix, (int)Meta.Value.Type, *Info.Name.ToString());
break;
}
}
@@ -1398,29 +1398,29 @@ TArray<FProperty*> MCPUtils::SearchProperties(UObject* Obj, const FString& Query
// FormatCommandHelp — verbose description of one handler command
// ============================================================
void MCPUtils::FormatCommandHelp(UClass* HandlerClass, FStringBuilderBase& Result)
void MCPUtils::FormatCommandHelp(UClass* HandlerClass)
{
const IMCPHandler* Handler = Cast<IMCPHandler>(HandlerClass->GetDefaultObject());
if (!Handler) return;
FString ToolName = GetHandlerName(HandlerClass);
Result.Append(TEXT("\n"));
Result.Append(WrapText(Handler->GetDescription(), 80, TEXT("// ")));
Result.Append(TEXT("\n"));
UMCPServer::Print(TEXT("\n"));
UMCPServer::Print(WrapText(Handler->GetDescription(), 80, TEXT("// ")));
UMCPServer::Print(TEXT("\n"));
// Command signature line
Result.Append(ToolName);
Result.Append(TEXT("("));
UMCPServer::Print(ToolName);
UMCPServer::Print(TEXT("("));
bool bFirst = true;
for (TFieldIterator<FProperty> PropIt(HandlerClass, EFieldIterationFlags::None); PropIt; ++PropIt)
{
if (!bFirst) Result.Append(TEXT(","));
if (!bFirst) UMCPServer::Print(TEXT(","));
bFirst = false;
if (PropIt->HasMetaData(TEXT("Optional"))) Result.Append(TEXT("?"));
Result.Append(PropertyNameToJsonKey(PropIt->GetName()));
if (PropIt->HasMetaData(TEXT("Optional"))) UMCPServer::Print(TEXT("?"));
UMCPServer::Print(PropertyNameToJsonKey(PropIt->GetName()));
}
Result.Append(TEXT(")\n"));
UMCPServer::Print(TEXT(")\n"));
// parameter details
for (TFieldIterator<FProperty> PropIt(HandlerClass, EFieldIterationFlags::None); PropIt; ++PropIt)
@@ -1431,10 +1431,10 @@ void MCPUtils::FormatCommandHelp(UClass* HandlerClass, FStringBuilderBase& Resul
bool bOptional = Prop->HasMetaData(TEXT("Optional"));
const FString& Desc = Prop->GetMetaData(TEXT("Description"));
Result.Appendf(TEXT(" %s %s%s"),
UMCPServer::Printf(TEXT(" %s %s%s"),
*Type, *Name, bOptional ? TEXT(" (optional)") : TEXT(""));
if (!Desc.IsEmpty())
Result.Appendf(TEXT(" — %s"), *Desc);
Result.Append(TEXT("\n"));
UMCPServer::Printf(TEXT(" — %s"), *Desc);
UMCPServer::Print(TEXT("\n"));
}
}