MI stuff is now workign

This commit is contained in:
2026-03-12 16:54:22 -04:00
parent 73b5d67b96
commit c7fb52a775
9 changed files with 245 additions and 387 deletions

View File

@@ -0,0 +1,80 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
#include "Materials/MaterialInstanceConstant.h"
#include "MaterialTypes.h"
#include "MaterialInstance_ClearParameter.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS()
class UMCP_MaterialInstance_ClearParameter : public UObject, public IMCPHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Description="Material Instance path"))
FString Path;
UPROPERTY(meta=(Description="Parameter name to clear"))
FString Parameter;
UPROPERTY(meta=(Description="Parameter association: 'Global', 'Layer', or 'Blend'. Default: 'Global'", Optional))
FString ParameterAssociation = TEXT("Global");
UPROPERTY(meta=(Description="Layer/blend index (0-based). Only used when ParameterAssociation is 'Layer' or 'Blend'", Optional))
int32 ParameterLayer = INDEX_NONE;
virtual FString GetDescription() const override
{
return TEXT("Remove a parameter override from a Material Instance, reverting it to the parent material's value.");
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{
MCPFetcher F(Result);
UMaterialInstanceConstant* MI = F.Asset(Path).Cast<UMaterialInstanceConstant>();
if (!MI) return;
// Parse the association string.
EMaterialParameterAssociation Association;
if (!MCPUtils::ParseMaterialParameterAssociation(ParameterAssociation, Association, Result))
return;
FMaterialParameterInfo ParamID(*Parameter, Association, ParameterLayer);
// Remove the override from all parameter arrays.
auto RemoveFrom = [&](auto& Arr) {
return Arr.RemoveAll([&](auto& Entry) { return Entry.ParameterInfo == ParamID; });
};
F.PreEdit();
int32 Removed = 0;
Removed += RemoveFrom(MI->ScalarParameterValues);
Removed += RemoveFrom(MI->VectorParameterValues);
Removed += RemoveFrom(MI->DoubleVectorParameterValues);
Removed += RemoveFrom(MI->TextureParameterValues);
Removed += RemoveFrom(MI->TextureCollectionParameterValues);
Removed += RemoveFrom(MI->RuntimeVirtualTextureParameterValues);
Removed += RemoveFrom(MI->SparseVolumeTextureParameterValues);
Removed += RemoveFrom(MI->FontParameterValues);
F.PostEdit();
if (Removed == 0)
{
Result.Appendf(TEXT("No override found for parameter '%s' (association=%s layer=%d) on %s"),
*Parameter, *ParameterAssociation, ParameterLayer, *MCPUtils::FormatName(MI));
return;
}
MCPUtils::SaveGenericPackage(MI);
Result.Appendf(TEXT("Cleared override for '%s' on %s\n"),
*Parameter, *MCPUtils::FormatName(MI));
}
};

View File

@@ -2,16 +2,10 @@
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPAssetFinder.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
#include "Materials/Material.h"
#include "Materials/MaterialInterface.h"
#include "Materials/MaterialInstanceConstant.h"
#include "Materials/MaterialExpressionScalarParameter.h"
#include "Materials/MaterialExpressionVectorParameter.h"
#include "Materials/MaterialExpressionTextureSampleParameter2D.h"
#include "Materials/MaterialExpressionStaticSwitchParameter.h"
#include "Engine/Texture.h"
#include "MaterialTypes.h"
#include "MaterialInstance_DumpParameters.generated.h"
@@ -25,144 +19,38 @@ class UMCP_MaterialInstance_DumpParameters : public UObject, public IMCPHandler
GENERATED_BODY()
public:
UPROPERTY(meta=(Description="Material Instance name or path to inspect"))
FString MaterialInstance;
UPROPERTY(meta=(Description="Material Instance path"))
FString Path;
virtual FString GetDescription() const override
{
return TEXT("List all parameters on a Material Instance, including overridden and inherited parameters.");
return TEXT("List all parameters on a Material Instance, showing current values and which are overridden.");
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{
MCPAssets<UMaterialInstanceConstant> Assets;
if (!Assets.Exact(MaterialInstance).Errors(Result).ENone().ETwo().Load()) return;
UMaterialInstanceConstant* MI = Assets.Object();
MCPFetcher F(Result);
UMaterialInstanceConstant* MI = F.Asset(Path).Cast<UMaterialInstanceConstant>();
if (!MI) return;
Result.Appendf(TEXT("MaterialInstance: %s\n"), *MCPUtils::FormatName(MI));
auto AllParams = MCPUtils::GetMaterialParameters(MI);
// Parent chain
if (MI->Parent)
{
Result.Append(TEXT("Parent chain:"));
UMaterialInterface* Current = MI->Parent;
while (Current)
{
if (UMaterial* Mat = Cast<UMaterial>(Current))
{
Result.Appendf(TEXT(" %s"), *MCPUtils::FormatName(Mat));
break;
}
if (UMaterialInstance* ParentMI = Cast<UMaterialInstance>(Current))
{
Result.Appendf(TEXT(" %s ->"), *MCPUtils::FormatName(ParentMI));
UMaterialInstanceConstant* ParentMIC = Cast<UMaterialInstanceConstant>(Current);
Current = ParentMIC ? ParentMIC->Parent : nullptr;
}
else
{
Result.Appendf(TEXT(" %s"), *Current->GetPathName());
break;
}
}
Result.Append(TEXT("\n"));
}
// Collect names of overridden parameters for filtering inherited ones
TSet<FString> OverriddenScalars, OverriddenVectors, OverriddenTextures, OverriddenStaticSwitches;
for (const FScalarParameterValue& P : MI->ScalarParameterValues)
OverriddenScalars.Add(P.ParameterInfo.Name.ToString());
for (const FVectorParameterValue& P : MI->VectorParameterValues)
OverriddenVectors.Add(P.ParameterInfo.Name.ToString());
for (const FTextureParameterValue& P : MI->TextureParameterValues)
OverriddenTextures.Add(P.ParameterInfo.Name.ToString());
{
FStaticParameterSet SP;
MI->GetStaticParameterValues(SP);
for (const FStaticSwitchParameter& P : SP.StaticSwitchParameters)
if (P.bOverride)
OverriddenStaticSwitches.Add(P.ParameterInfo.Name.ToString());
}
// Overridden parameters
// Overridden parameters first.
bool bHasOverrides = false;
auto EnsureOverrideHeader = [&]() {
for (auto& [Info, Meta] : AllParams)
{
if (!Meta.bOverride) continue;
if (!bHasOverrides) { Result.Append(TEXT("\nOverridden Parameters:\n")); bHasOverrides = true; }
};
for (const FScalarParameterValue& P : MI->ScalarParameterValues)
{
EnsureOverrideHeader();
Result.Appendf(TEXT(" Scalar \"%s\" = %g\n"), *P.ParameterInfo.Name.ToString(), P.ParameterValue);
}
for (const FVectorParameterValue& P : MI->VectorParameterValues)
{
EnsureOverrideHeader();
Result.Appendf(TEXT(" Vector \"%s\" = (%.3f, %.3f, %.3f, %.3f)\n"),
*P.ParameterInfo.Name.ToString(),
P.ParameterValue.R, P.ParameterValue.G, P.ParameterValue.B, P.ParameterValue.A);
}
for (const FTextureParameterValue& P : MI->TextureParameterValues)
{
EnsureOverrideHeader();
Result.Appendf(TEXT(" Texture \"%s\" = %s\n"),
*P.ParameterInfo.Name.ToString(),
P.ParameterValue ? *MCPUtils::FormatName(P.ParameterValue) : TEXT("None"));
}
{
FStaticParameterSet StaticParams;
MI->GetStaticParameterValues(StaticParams);
for (const FStaticSwitchParameter& P : StaticParams.StaticSwitchParameters)
{
if (!P.bOverride) continue;
EnsureOverrideHeader();
Result.Appendf(TEXT(" StaticSwitch \"%s\" = %s\n"),
*P.ParameterInfo.Name.ToString(), P.Value ? TEXT("true") : TEXT("false"));
}
MCPUtils::FormatMaterialParameter(Result, Info, Meta);
}
// Inherited (non-overridden) parameters from the base material
UMaterial* BaseMat = MI->GetMaterial();
if (!BaseMat) return;
// Inherited (non-overridden) parameters.
bool bHasInherited = false;
auto EnsureInheritedHeader = [&]() {
if (!bHasInherited) { Result.Append(TEXT("\nInherited Parameters (not overridden):\n")); bHasInherited = true; }
};
for (UMaterialExpression* Expr : BaseMat->GetExpressions())
for (auto& [Info, Meta] : AllParams)
{
if (!Expr) continue;
if (auto* SP = Cast<UMaterialExpressionScalarParameter>(Expr))
{
if (OverriddenScalars.Contains(SP->ParameterName.ToString())) continue;
EnsureInheritedHeader();
Result.Appendf(TEXT(" Scalar \"%s\" default=%g\n"), *SP->ParameterName.ToString(), SP->DefaultValue);
}
else if (auto* VP = Cast<UMaterialExpressionVectorParameter>(Expr))
{
if (OverriddenVectors.Contains(VP->ParameterName.ToString())) continue;
EnsureInheritedHeader();
Result.Appendf(TEXT(" Vector \"%s\" default=(%.3f, %.3f, %.3f, %.3f)\n"),
*VP->ParameterName.ToString(),
VP->DefaultValue.R, VP->DefaultValue.G, VP->DefaultValue.B, VP->DefaultValue.A);
}
else if (auto* TP = Cast<UMaterialExpressionTextureSampleParameter2D>(Expr))
{
if (OverriddenTextures.Contains(TP->ParameterName.ToString())) continue;
EnsureInheritedHeader();
Result.Appendf(TEXT(" Texture \"%s\" default=%s\n"),
*TP->ParameterName.ToString(),
TP->Texture ? *MCPUtils::FormatName(TP->Texture) : TEXT("None"));
}
else if (auto* SSP = Cast<UMaterialExpressionStaticSwitchParameter>(Expr))
{
if (OverriddenStaticSwitches.Contains(SSP->ParameterName.ToString())) continue;
EnsureInheritedHeader();
Result.Appendf(TEXT(" StaticSwitch \"%s\" default=%s\n"),
*SSP->ParameterName.ToString(), SSP->DefaultValue ? TEXT("true") : TEXT("false"));
}
if (Meta.bOverride) continue;
if (!bHasInherited) { Result.Append(TEXT("\nInherited Parameters (not overridden):\n")); bHasInherited = true; }
MCPUtils::FormatMaterialParameter(Result, Info, Meta);
}
}
};

View File

@@ -5,6 +5,7 @@
#include "MCPFetcher.h"
#include "MCPUtils.h"
#include "Materials/MaterialInstanceConstant.h"
#include "MaterialTypes.h"
#include "Misc/DefaultValueHelper.h"
#include "MaterialInstance_SetParameter.generated.h"
@@ -25,6 +26,12 @@ public:
UPROPERTY(meta=(Description="Parameter name to set"))
FString Parameter;
UPROPERTY(meta=(Description="Parameter association: 'Global', 'Layer', or 'Blend'. Default: 'Global'", Optional))
FString ParameterAssociation = TEXT("Global");
UPROPERTY(meta=(Description="Layer/blend index (0-based). Only used when ParameterAssociation is 'Layer' or 'Blend'", Optional))
int32 ParameterLayer = INDEX_NONE;
UPROPERTY(meta=(Description="Value to set (uses Unreal text format, e.g. '0.5' for scalar, '(R=1,G=0,B=0,A=1)' for vector)"))
FString Value;
@@ -39,38 +46,30 @@ public:
UMaterialInstanceConstant* MI = F.Asset(Path).Cast<UMaterialInstanceConstant>();
if (!MI) return;
auto Parameters = MCPUtils::MaterialParameters(MI);
// Parse the association string.
EMaterialParameterAssociation Association;
if (!MCPUtils::ParseMaterialParameterAssociation(ParameterAssociation, Association, Result))
return;
// Find a parameter with a matching name.
FName Name(*Parameter);
MCPMaterialParameter* Found = nullptr;
int MatchCount = 0;
for (auto& P : Parameters)
// Build the parameter ID to look up.
FMaterialParameterInfo ParamID(*Parameter, Association, ParameterLayer);
// Find it in the material's parameter map.
auto AllParams = MCPUtils::GetMaterialParameters(MI);
FMaterialParameterMetadata* Found = AllParams.Find(ParamID);
if (!Found)
{
if (P.Name == Name)
{
MatchCount++;
Found = &P;
}
}
if (MatchCount > 1)
{
Result.Appendf(TEXT("More than one parameter named '%s'"), *Parameter);
Result.Appendf(TEXT("No parameter named '%s' with association=%s layer=%d"),
*Parameter, *ParameterAssociation, ParameterLayer);
return;
}
if (MatchCount == 0)
{
Result.Appendf(TEXT("No parameter named '%s'"), *Parameter);
return;
}
if (Found->Metadata.PrimitiveDataIndex != INDEX_NONE)
if (Found->PrimitiveDataIndex != INDEX_NONE)
{
Result.Appendf(TEXT("Parameter '%s' uses custom primitive data and cannot be set on a material instance"), *Parameter);
return;
}
FMaterialParameterInfo Info(*Parameter);
EMaterialParameterType Type = Found->Metadata.Value.Type;
EMaterialParameterType Type = Found->Value.Type;
F.PreEdit();
switch (Type)
@@ -83,7 +82,7 @@ public:
Result.Appendf(TEXT("Failed to parse '%s' as a float"), *Value);
return;
}
MI->SetScalarParameterValueEditorOnly(Info, ScalarValue);
MI->SetScalarParameterValueEditorOnly(ParamID, ScalarValue);
break;
}
case EMaterialParameterType::Vector:
@@ -94,11 +93,11 @@ public:
Result.Appendf(TEXT("Failed to parse '%s' as a color/vector (expected format: '(R=1,G=0,B=0,A=1)')"), *Value);
return;
}
MI->SetVectorParameterValueEditorOnly(Info, Color);
MI->SetVectorParameterValueEditorOnly(ParamID, Color);
break;
}
default:
Result.Appendf(TEXT("Unsupported parameter type for '%s'"), *Parameter);
Result.Appendf(TEXT("Parameters of type %d (see EMaterialParameterType) are not implemented"), (int)Type);
return;
}
F.PostEdit();

View File

@@ -0,0 +1,43 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
#include "Materials/Material.h"
#include "MaterialTypes.h"
#include "Material_DumpParameters.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS()
class UMCP_Material_DumpParameters : public UObject, public IMCPHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Description="Material path"))
FString Path;
virtual FString GetDescription() const override
{
return TEXT("List all parameters on a Material, showing their default values.");
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{
MCPFetcher F(Result);
UMaterial* Mat = F.Asset(Path).Cast<UMaterial>();
if (!Mat) return;
auto AllParams = MCPUtils::GetMaterialParameters(Mat);
for (auto& [Info, Meta] : AllParams)
{
MCPUtils::FormatMaterialParameter(Result, Info, Meta);
}
}
};

View File

@@ -1,206 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPAssetFinder.h"
#include "MCPUtils.h"
#include "Materials/Material.h"
#include "Materials/MaterialInterface.h"
#include "Materials/MaterialInstanceConstant.h"
#include "Materials/MaterialExpressionScalarParameter.h"
#include "Materials/MaterialExpressionVectorParameter.h"
#include "Materials/MaterialExpressionTextureSampleParameter2D.h"
#include "Materials/MaterialExpressionStaticSwitchParameter.h"
#include "Engine/Texture.h"
#include "Material_SetInstanceParameter.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS()
class UMCP_Material_SetInstanceParameter : public UObject, public IMCPHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Description="Material Instance name or path"))
FString MaterialInstance;
UPROPERTY(meta=(Description="Parameter name to set"))
FString ParameterName;
UPROPERTY(meta=(Description="Value to set (number for scalar, object with r/g/b/a for vector, string path for texture, bool for staticSwitch)"))
FMCPJsonObject Value;
UPROPERTY(meta=(Optional, Description="Parameter type: scalar, vector, texture, staticSwitch. Auto-detected from parent if omitted."))
FString Type;
UPROPERTY(meta=(Optional, Description="If true, validate without applying changes"))
bool DryRun = false;
virtual FString GetDescription() const override
{
return TEXT("Set a parameter override on a Material Instance. "
"Supports scalar, vector, texture, and static switch parameter types.");
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{
if (!Json->HasField(TEXT("value")))
{
Result.Append(TEXT("ERROR: Missing required field: value\n"));
return;
}
// Load the Material Instance
MCPAssets<UMaterialInstanceConstant> Assets;
if (!Assets.Exact(MaterialInstance).Errors(Result).ENone().ETwo().Load()) return;
UMaterialInstanceConstant* MI = Assets.Object();
// Determine the parameter type -- explicit or auto-detect from parent
FString TypeStr = Type;
if (TypeStr.IsEmpty())
TypeStr = AutoDetectType(MI);
if (TypeStr.IsEmpty())
{
Result.Appendf(TEXT("ERROR: Could not determine parameter type for '%s'. Specify the 'type' field explicitly (scalar, vector, texture, staticSwitch).\n"),
*ParameterName);
return;
}
FMaterialParameterInfo ParamInfo(*ParameterName);
FString NewValueDescription;
if (TypeStr.Equals(TEXT("scalar"), ESearchCase::IgnoreCase))
{
double FloatValue = Json->GetNumberField(TEXT("value"));
if (!DryRun)
MI->SetScalarParameterValueEditorOnly(ParamInfo, (float)FloatValue);
NewValueDescription = FString::Printf(TEXT("%g"), FloatValue);
}
else if (TypeStr.Equals(TEXT("vector"), ESearchCase::IgnoreCase))
{
const TSharedPtr<FJsonObject>* ValueObj = nullptr;
if (!Json->TryGetObjectField(TEXT("value"), ValueObj) || !ValueObj || !(*ValueObj).IsValid())
{
Result.Append(TEXT("ERROR: For vector parameters, 'value' must be an object with r, g, b (and optional a) fields.\n"));
return;
}
double R = (*ValueObj)->GetNumberField(TEXT("r"));
double G = (*ValueObj)->GetNumberField(TEXT("g"));
double B = (*ValueObj)->GetNumberField(TEXT("b"));
double A = (*ValueObj)->HasField(TEXT("a")) ? (*ValueObj)->GetNumberField(TEXT("a")) : 1.0;
FLinearColor Color((float)R, (float)G, (float)B, (float)A);
if (!DryRun)
MI->SetVectorParameterValueEditorOnly(ParamInfo, Color);
NewValueDescription = FString::Printf(TEXT("(%.3f, %.3f, %.3f, %.3f)"), R, G, B, A);
}
else if (TypeStr.Equals(TEXT("texture"), ESearchCase::IgnoreCase))
{
FString TexturePath = Json->GetStringField(TEXT("value"));
if (TexturePath.IsEmpty())
{
Result.Append(TEXT("ERROR: For texture parameters, 'value' must be a texture asset path string.\n"));
return;
}
MCPAssets<UTexture> TexAssets;
if (!TexAssets.Exact(TexturePath).AllContent().Errors(Result).ENone().ETwo().Load()) return;
UTexture* TextureObj = TexAssets.Object();
if (!DryRun)
MI->SetTextureParameterValueEditorOnly(ParamInfo, TextureObj);
NewValueDescription = MCPUtils::FormatName(TextureObj);
}
else if (TypeStr.Equals(TEXT("staticSwitch"), ESearchCase::IgnoreCase))
{
bool bSwitchValue = Json->GetBoolField(TEXT("value"));
if (!DryRun)
{
FStaticParameterSet StaticParams;
MI->GetStaticParameterValues(StaticParams);
bool bFound = false;
for (FStaticSwitchParameter& Param : StaticParams.StaticSwitchParameters)
{
if (Param.ParameterInfo.Name == FName(*ParameterName))
{
Param.Value = bSwitchValue;
Param.bOverride = true;
bFound = true;
break;
}
}
if (!bFound)
{
FStaticSwitchParameter NewParam;
NewParam.ParameterInfo.Name = FName(*ParameterName);
NewParam.Value = bSwitchValue;
NewParam.bOverride = true;
StaticParams.StaticSwitchParameters.Add(NewParam);
}
MI->UpdateStaticPermutation(StaticParams);
}
NewValueDescription = bSwitchValue ? TEXT("true") : TEXT("false");
}
else
{
Result.Appendf(TEXT("ERROR: Unknown parameter type '%s'. Valid types: scalar, vector, texture, staticSwitch\n"), *TypeStr);
return;
}
if (!DryRun)
{
MCPUtils::PreEdit({MI});
MCPUtils::PostEdit({MI});
MCPUtils::SaveGenericPackage(MI);
}
if (DryRun)
Result.Appendf(TEXT("[DRY RUN] Would set %s \"%s\" = %s on %s\n"), *TypeStr, *ParameterName, *NewValueDescription, *MCPUtils::FormatName(MI));
else
Result.Appendf(TEXT("Set %s \"%s\" = %s on %s\n"), *TypeStr, *ParameterName, *NewValueDescription, *MCPUtils::FormatName(MI));
}
private:
// Auto-detect parameter type by examining the base material's expressions.
FString AutoDetectType(UMaterialInstanceConstant* MI)
{
UMaterial* BaseMat = MI->GetMaterial();
if (!BaseMat) return FString();
for (UMaterialExpression* Expr : BaseMat->GetExpressions())
{
if (!Expr) continue;
if (auto* SP = Cast<UMaterialExpressionScalarParameter>(Expr))
{
if (SP->ParameterName.ToString() == ParameterName)
return TEXT("scalar");
}
else if (auto* VP = Cast<UMaterialExpressionVectorParameter>(Expr))
{
if (VP->ParameterName.ToString() == ParameterName)
return TEXT("vector");
}
else if (auto* TP = Cast<UMaterialExpressionTextureSampleParameter2D>(Expr))
{
if (TP->ParameterName.ToString() == ParameterName)
return TEXT("texture");
}
else if (auto* SSP = Cast<UMaterialExpressionStaticSwitchParameter>(Expr))
{
if (SSP->ParameterName.ToString() == ParameterName)
return TEXT("staticSwitch");
}
}
return FString();
}
};

View File

@@ -1150,21 +1150,79 @@ void MCPUtils::PostEdit(const TArray<UObject*>& Objects)
GEditor->RedrawAllViewports();
}
TArray<MCPMaterialParameter> MCPUtils::MaterialParameters(UMaterialInstanceConstant *MI)
TMap<FMaterialParameterInfo, FMaterialParameterMetadata> MCPUtils::GetMaterialParameters(UMaterialInterface* Material)
{
TArray<MCPMaterialParameter> Results;
UMaterial* BaseMat = MI->GetMaterial();
if (!BaseMat) return Results;
for (UMaterialExpression* Expr : BaseMat->GetExpressions())
TMap<FMaterialParameterInfo, FMaterialParameterMetadata> Result;
if (!Material) return Result;
TMap<FMaterialParameterInfo, FMaterialParameterMetadata> Temp;
for (int32 i = 0; i < (int32)EMaterialParameterType::NumRuntime; i++)
{
if (!Expr || !Expr->bIsParameterExpression) continue;
MCPMaterialParameter P;
P.Name = Expr->GetParameterName();
if (P.Name.IsNone()) continue;
if (!Expr->GetParameterValue(P.Metadata)) continue;
Results.Add(P);
Material->GetAllParametersOfType((EMaterialParameterType)i, Temp);
Result.Append(Temp);
}
return Result;
}
bool MCPUtils::ParseMaterialParameterAssociation(const FString& Str, EMaterialParameterAssociation& OutAssociation, MCPErrorCallback Error)
{
if (Str.Equals(TEXT("Global"), ESearchCase::IgnoreCase))
OutAssociation = GlobalParameter;
else if (Str.Equals(TEXT("Layer"), ESearchCase::IgnoreCase))
OutAssociation = LayerParameter;
else if (Str.Equals(TEXT("Blend"), ESearchCase::IgnoreCase))
OutAssociation = BlendParameter;
else
{
Error.SetError(FString::Printf(TEXT("Invalid ParameterAssociation '%s' (expected 'Global', 'Layer', or 'Blend')"), *Str));
return false;
}
return true;
}
void MCPUtils::FormatMaterialParameter(FStringBuilderBase& Result, const FMaterialParameterInfo& Info, const FMaterialParameterMetadata& Meta)
{
// Association prefix for layer/blend parameters.
FString Prefix;
if (Info.Association == LayerParameter)
Prefix = FString::Printf(TEXT("[Layer %d] "), Info.Index);
else if (Info.Association == BlendParameter)
Prefix = FString::Printf(TEXT("[Blend %d] "), Info.Index);
switch (Meta.Value.Type)
{
case EMaterialParameterType::Scalar:
Result.Appendf(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"),
*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"),
*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"),
*Prefix, *Info.Name.ToString(), Tex ? *MCPUtils::FormatName(Tex) : TEXT("None"));
break;
}
case EMaterialParameterType::StaticSwitch:
Result.Appendf(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());
break;
}
return Results;
}
bool MCPUtils::SaveMaterialPackage(UMaterial* Material)

View File

@@ -98,12 +98,6 @@ struct MCPErrorCallback
void SetError(const FString& Msg) const { Func(Msg); }
};
struct MCPMaterialParameter
{
FName Name;
FMaterialParameterMetadata Metadata;
};
// Stateless utility functions used by MCP handlers and the MCP server.
// This is effectively a namespace — all methods are static.
class MCPUtils
@@ -285,8 +279,10 @@ public:
static void PreEdit(const TArray<UObject*>& Objects);
static void PostEdit(const TArray<UObject*>& Objects);
// ----- Material Instance -----
static TArray<MCPMaterialParameter> MaterialParameters(UMaterialInstanceConstant *MI);
// ----- Material Parameters -----
static TMap<FMaterialParameterInfo, FMaterialParameterMetadata> GetMaterialParameters(UMaterialInterface* Material);
static bool ParseMaterialParameterAssociation(const FString& Str, EMaterialParameterAssociation& OutAssociation, MCPErrorCallback Error = nullptr);
static void FormatMaterialParameter(FStringBuilderBase& Result, const FMaterialParameterInfo& Info, const FMaterialParameterMetadata& Meta);
// ----- Editable template -----
// Given an object, returns the appropriate template object for generic