Skip to content

Latest commit

 

History

History
136 lines (95 loc) · 5.6 KB

File metadata and controls

136 lines (95 loc) · 5.6 KB

Application Layer

← Home


Overview

The Application layer orchestrates analysis, owns the ViewModel, and provides pure-function engines for filtering and diffing. It has no IMGUI code and no file I/O — all persistence delegates to the Storage folder, and build-report/dependency reading delegates to Analysis.


AnalysisCoordinator

Editor/Application/AnalysisCoordinator.cs

The central static coordinator. One instance per Editor session (reset on domain reload).

Public API

Method / Property Description
RunAnalysis() Start real analysis from Library/LastBuild.buildreport
RunDemo() Load the synthetic demo snapshot
ApplyFilter() Re-apply current FilterState to the active snapshot
SelectNode(node) Set vm.SelectedNode and publish
ComputeDiff(a, b) Run DiffEngine.Compute(a, b) and store result
ReloadSnapshots() Call SessionManager.Reload(), refresh vm.Snapshots, and — if there's no active snapshot — restore the most recent one as vm.ActiveSnapshot so the Overview/Dependencies tabs don't go blank after every domain reload
ClearLogs() Empty vm.Logs and publish
CurrentViewModel Returns the current AnalysisViewModel reference
OnViewModelUpdated event Action<AnalysisViewModel> — fired after every state mutation

Log(level, message) exists but is private — it appends a LogEntry to vm.Logs without publishing on its own; the surrounding Transition()/SetFailed() call handles that. It's not part of the coordinator's public surface.

Analysis Phase Sequence

RunAnalysis()
  ClearLogs()
  Log(Info, "Analysis started.")
  Transition(LoadingReport, "Loading build report…", 0.05)

    BuildReportAdapter.Load()
    → error: SetFailed()

  Log(Info, "Loaded N assets.")
  Transition(WalkingDependencies, "Scanning dependencies…", 0.30)

    AssetDatabaseWalker.BuildDependencyGraph(nodes)
    → error: SetFailed()

  Log(Info, "Dependency graph built successfully.")
  FinalizeSnapshot(nodes, graph, platform, productName)
    Transition(SavingSnapshot, "Saving snapshot…", 0.88)
    BuildSnapshot created
    SessionManager.AddSnapshot(snapshot)
    Log(Info, "Snapshot saved.")
    ApplySmartDefaultFilterIfPristine(nodes)
      → only if FilterState is still untouched this session, and one category
        crosses the dominance threshold: excludes it, Log(Info, "...")
    FilterEngine.Apply(nodes, FilterState)
    Log(Info, "Analysis complete — N assets, X MB compressed.")
    Transition(Complete, "Analysis complete.", 1.0)

AnalysisState Enum

State IsAnalyzing Description
Idle false No analysis has run this session
LoadingReport true Reading BuildReport
WalkingDependencies true Running AssetDatabase traversal
SavingSnapshot true Writing to disk
Complete false Finished successfully
Failed false Stopped with an error

SessionManager

Editor/Application/SessionManager.cs

Thin wrapper over SnapshotStore that maintains an in-memory list sorted newest-first.

Method Description
Reload() Calls SnapshotStore.LoadAll(), which fully deserialises every .blsnapshot file referenced by the index — not just summaries
AddSnapshot(snapshot) Persists via SnapshotStore.Save(); inserts at index 0; Save() enforces the retention limit internally
Snapshots IReadOnlyList<BuildSnapshot> — current in-memory list

FilterEngine

Editor/Application/FilterEngine.cs

public static List<AssetNode> Apply(
    IReadOnlyList<AssetNode> nodes,
    FilterState filter)

Applies the type mask, a min/max compressed-size range, and a scene-name substring filter in a single pass, then sorts the result via SortEngine. Returns a new list — never mutates input. Called by AnalysisCoordinator.ApplyFilter() after any filter state change.

public static AssetType? FindDominantCategoryToExcludeByDefault(
    IReadOnlyList<AssetNode> nodes)

Pure function, no dependency on FilterState or any mutable state — given a node list, returns the one AssetType that should start unchecked in the default view because it makes up 90% or more of total compressed size, provided at least two other categories still have non-zero data of their own; returns null otherwise. At most one category can ever cross 90%, since shares sum to 100%, so there's never an ambiguous choice between candidates. The caller (AnalysisCoordinator.ApplySmartDefaultFilterIfPristine) is responsible for deciding when to act on this — specifically, only against a FilterState that hasn't been touched yet this session — this function itself has no opinion on that and will happily return an answer against any node list regardless of the caller's filter state.


DiffEngine

Editor/Application/DiffEngine.cs

public static BuildDiff Compute(BuildSnapshot snapshotA, BuildSnapshot snapshotB)

Compares by GUID using two dictionary lookups (one per snapshot):

  1. GUIDs in B but not A → Added
  2. GUIDs in A but not B → Removed
  3. GUIDs in both where CompressedBytes differs at all → Changed

There is no minimum-delta threshold — a one-byte difference is enough to land an asset in Changed. Results in each list are sorted by size (or by |SizeDelta| for Changed), largest first.


Related