Skip to content

Parallel asset loading, file-signature cache, and invalid-file tracking#1

Closed
HectorMu wants to merge 6 commits into
mainfrom
feature/car-cache
Closed

Parallel asset loading, file-signature cache, and invalid-file tracking#1
HectorMu wants to merge 6 commits into
mainfrom
feature/car-cache

Conversation

@HectorMu

@HectorMu HectorMu commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

Replaces sequential asset-bundle scanning with parallel batched loading + a three-tier
invalid-file detection system (cache → magic bytes → LoadFromFile) to eliminate startup stalls.

Changes

Performance

  • Parallel loading: AssetBundle.LoadFromFile runs in batches of 4 via ThreadPool
  • File-signature cache: LastWriteTime + FileSize instead of SHA256 — cached files skip GetAllAssetNames() scan
  • Bundle unload: bundle.Unload(false) after processing each batch to free memory immediately
  • Material array fix: renderer.materials captured once per renderer instead of double-copied
  • Reflection cache: AssetBundleBridge resolves types once in static ctor instead of 247×
  • OrderBy restored: deterministic file ordering

Stall prevention

  • Invalid-file tracking: failed bundles are stored in cache by (path, signature) — never retried unless the file changes on disk
  • Magic-byte gate: reads first 8 bytes (UnityFS/UnityRaw/UnityWeb) before calling LoadFromFile — rejects non-bundles in microseconds
  • 30s timeout: WaitOne(30000) on batch — one hanging file can't stall the entire startup
  • Stale entry cleanup: deleted files removed from both Files and InvalidFiles

API improvements

  • Section + DictionaryExtensions: GetOrCreate(string, Func<T>) factory overload
  • ProfileCarColors: switched to factory overload, removed noisy logs
  • Plugin.cs: removed redundant second cache load

Build infra

  • Distance.CustomCar.csproj: all refs point to $(SolutionDir)libs\*, DistanceGameDir reads from env var
  • Publicize.ps1: assembly resolver for UnityEngine.dll, all members public, property publicization
  • .gitignore: libs/ excluded; README.md: build/deploy instructions
  • Tool.BuildTargets: conditional Centrifuge.Distance.dll copy

Tests

  • NUnit 2.6.4 test project: CarCacheTests (17), CarLoadBenchmarks (5), OptimizationTests (8)

HectorMu added 3 commits July 6, 2026 13:51
…ations

- CarCache: New file-signature based cache using LastWriteTime+FileSize instead of SHA256.
  Cached bundles skip the GetALLAssetNames() scan on subsequent launches.
  Stored at {modDir}\Settings\car_cache.json via JsonFx serialization.
- Parallel loading: AssetBundle.LoadFromFile runs in batches of 4 on the ThreadPool.
  Main thread processes loaded bundles (scan, LoadAsset, CreateCar).
- Bundle unload: bundle.Unload(false) after loading assets frees memory immediately.
- Material array fix: renderer.materials accessed once per renderer instead of 2x.
- REflection cache: AssetBundleBridge resolves kernel methods once in static ctor.
- Section/DictionaryExtensions: Added GetOrCreate(string, Func<T>) factory overload
  to avoid allocating default values when the key already exists.
- ProfileCarColors: Switched to factory overload; removed noisy Assigning logs.
- Plugin: Removed redundant second cache load (already done inside CreateCars).
- Stale entry cleanup: files deleted from disk are removed from the cache.
- Build infra: all external DLLs reference libs\*;
  DistanceGameDir reads from DISTANCE_GAME_DIR env var; publicizer script fixed.
- Added README with full build and deploy instructions.
- New NUnit test project with tests for CarCache, benchmarks, and optimization
  regression tests for Section/DictionaryExtensions factory overloads.
- Publicize.ps1: added assembly resolver to find UnityEngine.dll; made all
  members public instead of protected; added property getter/setter publicization.
- Fixed targets file: Conditional copy for Centrifuge.Distance.dll.
…rupted files

Changing batchDone.WaitOne() to WaitOne(30000) so a single hanging AssetBundle.LoadFromFile can't stall the entire startup. When a timeout occurs, incomplete results are marked with a TimeoutException and skipped in Phase 2.
…instantly

- CarCache.InvalidFiles: persists file path + signature for bundles that failed to load. IsFileInvalid() checks both path and signature so a replaced file gets re-tried.\n\n- HasValidBundleSignature(): reads first 8 bytes of each file before calling AssetBundle.LoadFromFile. Rejects non- UnityFS/UnityRaw/UnityWeb headers in microseconds instead of waiting for LoadFromFile to timeout.\n\n- LoadAssetsBundles pre-filter: computes signatures for all files first, then skips any that are in InvalidFiles with a matching signature. Logs the skip count.\n\n- LoadBundle now accepts a pre-computed signature and uses the magic-byte gate.\n\n- Phase 2 error handler calls MarkFileInvalid() so the file is never retried until it changes on disk.\n\n- Stale InvalidFiles entries (files that no longer exist on disk) are cleaned up after processing.\n\n- Combined: first run detects corrupt files at near-zero cost (8 bytes + FileInfo). Subsequent runs skip them before any I/O at all.
@HectorMu HectorMu self-assigned this Jul 6, 2026
@HectorMu HectorMu requested review from Californ1a and Tribow July 6, 2026 22:31
@Californ1a Californ1a requested review from REHERC and removed request for Californ1a July 6, 2026 22:46
@HectorMu HectorMu closed this Jul 6, 2026
@HectorMu HectorMu deleted the feature/car-cache branch July 6, 2026 23:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant