Lots of crap
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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; }
|
||||
};
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user