Lots of crap

This commit is contained in:
2026-03-13 03:30:14 -04:00
parent a3247b451e
commit 303c3fb03a
9 changed files with 107 additions and 84 deletions

Binary file not shown.

View File

@@ -45,9 +45,6 @@ public:
// Returns true if the blueprint compiled cleanly (no errors).
static bool CompileAndReport(UBlueprint* BP, FStringBuilderBase& Out)
{
FLogCaptureOutputDevice LogCapture;
GLog->AddOutputDevice(&LogCapture);
EBlueprintCompileOptions CompileOpts =
EBlueprintCompileOptions::SkipSave |
EBlueprintCompileOptions::SkipGarbageCollection |
@@ -55,8 +52,6 @@ public:
FKismetEditorUtilities::CompileBlueprint(BP, CompileOpts, nullptr);
GLog->RemoveOutputDevice(&LogCapture);
int32 ErrorCount = 0;
int32 WarningCount = 0;
@@ -74,18 +69,6 @@ public:
*Node->ErrorMsg);
}
// Collect log-captured errors/warnings
for (const FString& Msg : LogCapture.CapturedErrors)
{
ErrorCount++;
Out.Appendf(TEXT(" ERROR: (log) %s\n"), *Msg);
}
for (const FString& Msg : LogCapture.CapturedWarnings)
{
WarningCount++;
Out.Appendf(TEXT(" WARNING: (log) %s\n"), *Msg);
}
FString StatusStr = MCPUtils::EnumToString((EBlueprintStatus)BP->Status, TEXT("BS_"));
bool bIsValid = (BP->Status == BS_UpToDate) && (ErrorCount == 0);

View File

@@ -2,10 +2,9 @@
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPAssetFinder.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
#include "Materials/Material.h"
#include "MaterialDomain.h"
#include "Material_Compile.generated.h"
@@ -30,27 +29,25 @@ public:
virtual void Handle(FStringBuilderBase& Result) override
{
// Load material
MCPAssets<UMaterial> Assets;
if (!Assets.Exact(Material).Errors(Result).ENone().ETwo().Load()) return;
UMaterial* MaterialObj = Assets.Object();
MCPFetcher F(Result);
UMaterial* MaterialObj = F.Asset(Material).Cast<UMaterial>();
if (!MaterialObj) return;
// Force recompile by triggering PreEdit/PostEdit
TArray<UObject*> Chain = { MaterialObj };
MCPUtils::PreEdit(Chain);
MCPUtils::PostEdit(Chain);
// Force recompile
MaterialObj->ForceRecompileForRendering();
// Check for compilation errors via FMaterialResource on current platform
TArray<FString> Errors;
// Wait for compilation to finish, then check for errors
FMaterialResource* Resource = MaterialObj->GetMaterialResource(GMaxRHIFeatureLevel);
TArray<FString> Errors;
if (Resource)
{
Resource->FinishCompilation();
Errors = Resource->GetCompileErrors();
}
if (Errors.IsEmpty())
{
Result.Appendf(TEXT("%s compiled successfully.\n"), *MCPUtils::FormatName(MaterialObj));
Result.Append(TEXT("WARNING: Error detection is not working. GetCompileErrors() returns empty even when shader compilation fails. Do not trust this result.\n"));
}
else
{

View File

@@ -0,0 +1,34 @@
#pragma once
#include "CoreMinimal.h"
class FLogCaptureOutputDevice : public FOutputDevice
{
public:
TArray<FString> CapturedErrors;
bool bEnabled = true;
void Install() { GLog->AddOutputDevice(this); }
void Uninstall() { GLog->RemoveOutputDevice(this); }
// If the device is marked 'CanBeUsedOnMultipleThreads,'
// then UE_LOG will call Serialize from the current
// thread, otherwise, it will call Serialize from the
// logging thread. Without this, we wouldn't be able to
// tell whether an error is coming from the game thread.
virtual bool CanBeUsedOnMultipleThreads() const override { return true; }
virtual void Serialize(const TCHAR* V, ELogVerbosity::Type Verbosity, const FName& Category) override
{
// Only capture messages from the game thread.
// Other threads generate noise we don't care about.
if (!IsInGameThread() || !bEnabled) return;
if (Verbosity == ELogVerbosity::Warning ||
Verbosity == ELogVerbosity::Error ||
Verbosity == ELogVerbosity::Fatal)
{
CapturedErrors.Add(FString(V));
}
}
};

View File

@@ -0,0 +1,24 @@
#include "MCPProperty.h"
#include "MCPUtils.h"
MCPProperty::MCPProperty(FProperty* InProp, void* Container)
: Prop(InProp), ValuePtr(InProp ? InProp->ContainerPtrToValuePtr<void>(Container) : nullptr) {}
FString MCPProperty::GetText() const
{
FString Result;
Prop->ExportTextItem_Direct(Result, ValuePtr, nullptr, nullptr, PPF_None);
return Result;
}
bool MCPProperty::SetText(const FString& Value, MCPErrorCallback Error)
{
const TCHAR* ImportResult = Prop->ImportText_Direct(*Value, ValuePtr, nullptr, PPF_None);
if (!ImportResult)
{
Error.SetError(FString::Printf(TEXT("Failed to parse '%s' for property '%s' (type: %s)"),
*Value, *MCPUtils::FormatName(Prop), *Prop->GetCPPType()));
return false;
}
return true;
}

View File

@@ -1,5 +1,6 @@
#include "MCPServer.h"
#include "MCPHandler.h"
#include "LogCapture.h"
#include "MCPUtils.h"
#include "MCPAssetFinder.h"
#include "UObject/StrongObjectPtr.h"
@@ -151,6 +152,8 @@ void UMCPServer::Initialize(FSubsystemCollectionBase& Collection)
}
BuildMCPHandlerRegistry();
LogCapture.bEnabled = false;
LogCapture.Install();
bRunning = true;
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: MCP server listening on tcp://localhost:%d"), Port);
}
@@ -204,6 +207,7 @@ void UMCPServer::Deinitialize()
ListenSocket = nullptr;
}
LogCapture.Uninstall();
bRunning = false;
bShuttingDown = false;
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Server stopped."));
@@ -294,9 +298,19 @@ FString UMCPServer::HandleRequest(const FString& Line)
return PopulateError.ToString();
}
// Invoke the handler.
// Invoke the handler with log capture.
LogCapture.CapturedErrors.Empty();
LogCapture.bEnabled = true;
TStringBuilder<32768> TextResult;
Handler->Handle(TextResult);
LogCapture.bEnabled = false;
for (const FString& Msg : LogCapture.CapturedErrors)
{
TextResult.Append(TEXT("LOG: "));
TextResult.Append(Msg);
TextResult.Append(TEXT("\n"));
}
LogCapture.CapturedErrors.Empty();
FString Result = TextResult.ToString();
for (int32 i = 0; i < Result.Len(); ++i)
{

View File

@@ -0,0 +1,21 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPUtils.h"
// A resolved property: the FProperty descriptor plus a pointer to
// the value's storage. operator-> forwards to the FProperty.
struct MCPProperty
{
FProperty* Prop = nullptr;
void* ValuePtr = nullptr;
MCPProperty() = default;
MCPProperty(FProperty* InProp, void* Container);
FString GetText() const;
bool SetText(const FString& Value, MCPErrorCallback Error = nullptr);
explicit operator bool() const { return Prop != nullptr; }
FProperty* operator->() const { return Prop; }
};

View File

@@ -7,6 +7,7 @@
#include "Async/Future.h"
#include "Dom/JsonObject.h"
#include "MCPUtils.h"
#include "LogCapture.h"
#include "MCPServer.generated.h"
class FSocket;
@@ -52,6 +53,7 @@ public:
private:
// ----- Tool dispatch -----
FLogCaptureOutputDevice LogCapture; // installed once at startup, enabled per-request
TMap<FString, UClass*> MCPHandlerRegistry; // tool name -> UMCPHandler subclass
void BuildMCPHandlerRegistry();

View File

@@ -30,58 +30,6 @@ class UEnum;
struct FMemberReference;
struct FBPVariableDescription;
// ----- Log capture -----
class FLogCaptureOutputDevice : public FOutputDevice
{
public:
TArray<FString> CapturedErrors;
TArray<FString> CapturedWarnings;
virtual void Serialize(const TCHAR* V, ELogVerbosity::Type Verbosity, const FName& Category) override
{
FString Msg(V);
if (Verbosity == ELogVerbosity::Error || Verbosity == ELogVerbosity::Fatal)
{
CapturedErrors.Add(Msg);
return;
}
if (Verbosity == ELogVerbosity::Warning)
{
if (!Msg.Contains(TEXT("BlueprintMCP:")))
{
CapturedWarnings.Add(Msg);
}
return;
}
static const TCHAR* ErrorPatterns[] = {
TEXT("Can't connect pins"),
TEXT("Fixed up function"),
TEXT("is not compatible with"),
TEXT("could not find a pin"),
TEXT("has an invalid"),
TEXT("orphaned pin"),
TEXT("is deprecated"),
TEXT("does not implement"),
TEXT("Missing function"),
TEXT("Unable to find"),
TEXT("Failed to resolve"),
};
for (const TCHAR* Pattern : ErrorPatterns)
{
if (Msg.Contains(Pattern))
{
CapturedWarnings.Add(Msg);
return;
}
}
}
};
// ----- Error callback -----
struct MCPErrorCallback