Files
MagentaDolphin b7f5343a73 feat: asset usage audit plugin
Editor tool for the LA and 3D departments: which assets each level uses,
which are used nowhere, and export of a chosen set.

Three modules. AssetUsageAuditCore holds the whole analysis and links no
UI and no editor-only asset pipeline, so it stays runnable from a
commandlet; AssetUsageAuditEditor holds the Slate panel and everything
that needs UnrealEd or AssetTools; AssetUsageAuditTests holds 152 specs.

Load-bearing decisions, each of which produces a wrong answer if undone:

- Dependency queries are always Package + NoRequirements, never Hard. The
  map-to-external-actor edges the OFPA gatherer emits carry Game|Build
  without Hard, so a Hard query drops all 16117 external actor packages
  in this project. There is deliberately no Hard constant in the code.
- Crossing into another map is allowed only from a level or its external
  actor package. Without that rule WP_Main reported 18136 assets, of
  which 9994 belonged to L_MainLevel, reached through the GameMode.
- The verdict has five states, never a bool. The registry cannot see
  FMOD events, DataTable rows or string-built paths; those are Unknown,
  and the tool never proposes a deletion.
- Copying .uasset files does not preserve references - they are stored as
  full package paths. Only the Migrate layout produces something Unreal
  can open; the others write a manifest so the graph can be rebuilt.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-03 17:07:59 +07:00

33 lines
1.3 KiB
C#

using UnrealBuildTool;
public class AssetUsageAuditCore : ModuleRules
{
public AssetUsageAuditCore(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
// INVARIANT: this module must stay free of UI and of the editor-only asset pipeline.
// Do NOT add: UnrealEd, AssetTools, ToolMenus, Slate, SlateCore, EditorSubsystem.
// AssetTools is editor-only transitively (it puts UnrealEd in PublicDependencyModuleNames),
// so pulling it in here would silently make the whole analysis undrivable from a commandlet.
PublicDependencyModuleNames.AddRange(new string[]
{
"Core",
"CoreUObject",
"AssetRegistry"
});
PrivateDependencyModuleNames.AddRange(new string[]
{
// Engine is a Runtime module and is available in commandlets, so it does not
// compromise the headless goal. It is needed for ULevel::GetExternalActorsPaths and
// ScanLevelAssets - the OFPA folder layout must never be string-built, because
// Content Bundles inject /CB/<Guid>/, External Data Layers inject /EDL/<UID>/, and
// plugins can register further roots through delegates.
"Engine",
"Json",
"Projects"
});
}
}