MI stuff is now workign
This commit is contained in:
@@ -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));
|
||||
}
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user