Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [Unreleased]

### Fixed

- **Material sampler discovery now uses the supported API on each engine version.** The material and generic-asset index paths share one compatibility boundary that calls `UMaterialExpressionTextureBase` on UE 5.7 and `MaterialExpressionUtils` on UE 5.8+, removing both sampler deprecation warnings without duplicating version branches.

## [0.22.0] - 2026-08-01

### Internal
Expand Down
1 change: 1 addition & 0 deletions Docs/specs/SPEC_MonolithCore.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@

| Symbol | Header | Responsibility |
|--------|--------|---------------|
| `MonolithMaterialSamplerCompat::GetSamplerTypeForTexture` | `MonolithMaterialSamplerCompat.h` (header-only inline) | Single UE 5.7/5.8 compatibility boundary for recommended material sampler selection. UE 5.7 routes to `UMaterialExpressionTextureBase`; UE 5.8+ routes to `MaterialExpressionUtils`, so consumers never call a deprecated engine API directly. |
| `MonolithPinTypeGrammar::{TryParsePinType, ParsePinTypeFromString, PinTypeToString, ContainerPrefix, ResolveEnumByNameOrPath}` | `MonolithPinTypeGrammar.h` (header-only inline) | The single implementation of the MCP-friendly pin-type token grammar and its inverse — `bool` / `int` / `struct:Vector` / `enum:ESlateVisibility` / `array:object:StaticMesh` / `map:string:int` and so on. It previously existed twice (MonolithBlueprint + MonolithUI) and the copies drifted, which is what shipped enum widget variables that compiled to `int` (issue #115). `TryParsePinType` is the preferred entry point: it fails **by token** — an `object:` / `class:` / `struct:` / `enum:` / `softobject:` / `softclass:` sub-object that does not resolve, an unknown base token, or a bad container value type is a hard `false` with a caller-facing reason, and `Out` is left untouched. `ParsePinTypeFromString` keeps the historical best-effort shape (bool fallback, null sub-object) for un-migrated call sites. **Linkage invariant:** MonolithCore does not link `BlueprintGraph`, so this header is inline-only and must NEVER be included from a MonolithCore `.cpp` (or a MonolithCore test) — the `UEdGraphSchema_K2::PC_*` constants are dllimport'd from `BlueprintGraph` and referencing them from a MonolithCore translation unit is an LNK2019. Same pattern, and same reason, as `MonolithPropertyAccessReader.h` and `MonolithAnimNodeBindingReader.h`. The modules that do link `BlueprintGraph` and may include it from a `.cpp`: MonolithAI, MonolithAnimation, MonolithBlueprint, MonolithComboGraph, MonolithGAS, MonolithIndex, MonolithLevelSequence, MonolithLogicDriver, MonolithUI. |
| `MonolithCore::ValidatePackagePath(const FString&)` | `MonolithPackagePathValidator.h` (inline) | Wraps `FPackageName::IsValidLongPackageName` with an empty-string-on-success / error-msg-on-failure contract. Rejects empty input, double-slash (`//Game/...`), missing `/Game/` root, trailing slash, illegal chars. Added `dv.367` after a fatal `UObjectGlobals.cpp:1012` ensure from a malformed `//Game/...` JSON payload reaching `CreatePackage`. Routing is incremental and module-keyed. Current owners: MonolithUI (`HandleCreateWidgetBlueprint`, the original crash site), MonolithAI (`MonolithAIInternal::GetOrCreatePackage`), MonolithGAS (`MonolithGASInternal::GetOrCreatePackage`); MonolithBlueprint, MonolithMaterial and MonolithNiagara are being wired now. Grep the Source tree for `ValidatePackagePath` for the current owner list rather than trusting a count here. |

Expand Down
2 changes: 1 addition & 1 deletion Docs/specs/SPEC_MonolithIndex.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
| `FGameplayTagIndexer` | GameplayTag containers — tag hierarchies and references |
| `FConfigIndexer` | Config/INI files — sections, keys, values across config hierarchy |
| `FCppIndexer` | C++ source files — classes, functions, includes (project-level source) |
| `FGenericAssetIndexer` | StaticMesh, SkeletalMesh, Texture2D, SoundWave, etc. — metadata nodes |
| `FGenericAssetIndexer` | StaticMesh, SkeletalMesh, Texture2D, SoundWave, etc. — metadata nodes. Texture `recommended_sampler_type` uses the shared `MonolithMaterialSamplerCompat` UE 5.7/5.8 boundary. |
| `FDependencyIndexer` | Hard + Soft package dependencies (runs after all other indexers) |
| `FMonolithIndexNotification` | Slate notification bar with throbber + percentage |

Expand Down
2 changes: 1 addition & 1 deletion Docs/specs/SPEC_MonolithMaterial.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
| Class | Responsibility |
|-------|---------------|
| `FMonolithMaterialModule` | Registers 63 material actions |
| `FMonolithMaterialActions` | Static handlers + helpers for loading materials and serializing expressions |
| `FMonolithMaterialActions` | Static handlers + helpers for loading materials and serializing expressions. Texture metadata routes sampler recommendation through the shared `MonolithMaterialSamplerCompat` UE 5.7/5.8 boundary. |

### Actions (63 — namespace: "material")

Expand Down
37 changes: 37 additions & 0 deletions Docs/testing/2026-08-04-ue58-material-sampler-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# UE 5.8 Material Sampler API Verification

**Date:** 2026-08-04
**Scope:** `MonolithCore`, `MonolithIndex`, and `MonolithMaterial`
**Related:** issue #121

---

## 1. Regression

UE 5.8 deprecates `UMaterialExpressionTextureBase::GetSamplerTypeForTexture` in favor of `MaterialExpressionUtils::GetSamplerTypeForTexture`. UE 5.7 does not expose the replacement header, so an unconditional migration would break the supported compile floor. The deprecated call existed in both texture metadata consumers.

## 2. Compatibility contract

| Engine | Routed API |
|---|---|
| UE 5.7 | `UMaterialExpressionTextureBase::GetSamplerTypeForTexture` |
| UE 5.8+ | `MaterialExpressionUtils::GetSamplerTypeForTexture` |

Both consumers call `MonolithMaterialSamplerCompat::GetSamplerTypeForTexture`; the engine-version boundary is defined once in `Source/MonolithCore/Public/MonolithMaterialSamplerCompat.h`.

## 3. Verification

| Gate | Expected result | Result |
|---|---|---|
| Repository diff audit | One compatibility boundary and two migrated consumers | Pass — `git diff --check` returned no errors |
| UE 5.7 plugin package build | Editor plugin compiles with the legacy API path | Pass — 434/434 actions, UAT exit 0 |
| UE 5.8 plugin package build | Editor plugin compiles without either sampler deprecation warning | Pass — 434/434 actions, UAT exit 0, zero matching sampler C4996 warnings |

Both builds compiled `GenericAssetIndexer.cpp` and `MonolithMaterialActions.cpp` as individual actions. Engine roots were resolved from validation-host `.uproject` `EngineAssociation` values through `Build/BatchFiles/Script/ResolveUnrealEngine.ps1`. UAT logs were redirected to external evidence paths:

- `D:\P4\MonolithValidation20260804\02-ue58-material-sampler\Logs\UE57`
- `D:\P4\MonolithValidation20260804\02-ue58-material-sampler\Logs\UE58`

The authoritative command shape was `RunUAT BuildPlugin -NoTargetPlatforms -Rocket`. An earlier UE 5.7 run also completed all 434 compile actions, but its final UAT log flush failed because the system drive was full; the redirected-log exit-0 run above supersedes it.

Issue #121 contains other engine deprecations that are intentionally outside this single-concern change.
31 changes: 31 additions & 0 deletions Source/MonolithCore/Public/MonolithMaterialSamplerCompat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#pragma once

#include "Runtime/Launch/Resources/Version.h"

#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 8
#include "Materials/MaterialExpressionUtils.h"
#else
#include "Materials/MaterialExpressionTextureBase.h"
#endif

class UTexture;

namespace MonolithMaterialSamplerCompat
{
#if WITH_EDITOR
/**
* Return Unreal's recommended sampler type without exposing engine-version API
* drift to each material or index consumer.
*/
FORCEINLINE EMaterialSamplerType GetSamplerTypeForTexture(
const UTexture* Texture,
bool bForceNoVirtualTexture = false)
{
#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 8
return MaterialExpressionUtils::GetSamplerTypeForTexture(Texture, bForceNoVirtualTexture);
#else
return UMaterialExpressionTextureBase::GetSamplerTypeForTexture(Texture, bForceNoVirtualTexture);
#endif
}
#endif
}
4 changes: 2 additions & 2 deletions Source/MonolithIndex/Private/Indexers/GenericAssetIndexer.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#include "Indexers/GenericAssetIndexer.h"
#include "MonolithMaterialSamplerCompat.h"
#include "Engine/StaticMesh.h"
#include "Engine/SkeletalMesh.h"
#include "Engine/Texture2D.h"
#include "Materials/MaterialExpressionTextureBase.h"
#include "Sound/SoundWave.h"
#include "Sound/SoundCue.h"
#include "PhysicsEngine/PhysicsAsset.h"
Expand Down Expand Up @@ -79,7 +79,7 @@ bool FGenericAssetIndexer::IndexAsset(const FAssetData& AssetData, UObject* Load
Props->SetBoolField(TEXT("compression_no_alpha"), Tex->CompressionNoAlpha != 0);
#endif
// Recommended sampler type for material use
EMaterialSamplerType SamplerType = UMaterialExpressionTextureBase::GetSamplerTypeForTexture(Tex);
const EMaterialSamplerType SamplerType = MonolithMaterialSamplerCompat::GetSamplerTypeForTexture(Tex);
UEnum* SamplerEnum = StaticEnum<EMaterialSamplerType>();
if (SamplerEnum)
{
Expand Down
3 changes: 2 additions & 1 deletion Source/MonolithMaterial/Private/MonolithMaterialActions.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "MonolithMaterialActions.h"
#include "MonolithMaterialSamplerCompat.h"
#include "MonolithToolRegistry.h"
#include "MonolithParamSchema.h"
#include "MonolithPackagePathValidator.h"
Expand Down Expand Up @@ -9344,7 +9345,7 @@ static void PopulateTextureMetadata(UTexture* Tex, const TSharedPtr<FJsonObject>
#endif

// Recommended sampler type for material usage
EMaterialSamplerType SamplerType = UMaterialExpressionTextureBase::GetSamplerTypeForTexture(Tex);
const EMaterialSamplerType SamplerType = MonolithMaterialSamplerCompat::GetSamplerTypeForTexture(Tex);
UEnum* SamplerEnum = StaticEnum<EMaterialSamplerType>();
if (SamplerEnum)
{
Expand Down