
← Back
3.5.26
Asset Bundle Dependencies: Building a Hierarchical Asset Management System
How we cut manual work and download sizes with a hierarchical system

ByLior Orenbach
Senior Backend Engineer

How we cut manual work and download sizes with a hierarchical system

Background
Asset bundles are a core part of how Papaya Gaming delivers visual content to players. They package images, fonts, buttons, and other UI elements that define the look and feel of tournaments, liveops, and other in-game experiences. Each bundle is versioned, published through an internal backoffice tool (Optimus), and served to clients via CDN.
Until recently, every asset bundle was a standalone entity. There was no formal relationship between bundles — each one was created, configured, and published independently.
The Problem
When the art department needed to customize asset bundles for seasonal events, like Valentine's Day, Christmas, black
friday, etc. The process was manual and repetitive. A single search for "Valentine's" in Optimus returned dozens of
bundles. For each one, artists had to:
This created three compounding issues:
Evaluating Alternatives
The core requirement was clear: allow asset bundles to share common assets without duplication, while preserving backwards compatibility with the existing system. We considered two approaches:
1. Flat shared asset pools: A global pool of shared assets that any bundle could reference. This would solve duplication but offered no structure — any bundle could reference anything, making it difficult to reason about completeness and consistency.
2. Typed dependency hierarchy: A structured three-tier system where bundles can only reference specific types of other bundles, enforcing a directed, acyclic relationship. This approach offered both deduplication and structural guarantees.
We chose the typed hierarchy for its ability to prevent circular dependencies by design and for providing a clear mental model for the art and operations teams.
Solution Architecture
The dependency system introduces three asset bundle types:
Design Decisions
A practical example: for a Valentine's event, the art team creates one Resource bundle containing all shared currency and game mode icons, one Base bundle per asset bundle kind containing the common layout and logic references, and individual Skin bundles for each specific variant. Updating the shared icons requires changing only the Resource bundle — the change propagates to all dependent bases and skins automatically.
Implementation Details
Database Changes
Asset bundles are stored in a document database (not MySQL). The schema changes were minimal:
Asset Bundle Collection - added a single field:
1 dependencyType: "skin" | "base" | "resource"Asset Bundle Package - added a dependsOnVersions field:
1 dependsOnVersions: string[] // e.g., ["packId@1.0", "packId@2.1"]Dependencies are defined per version, using the same versioning schema already in place ( packId@major.minor ). This means dependencies can evolve across versions — a new version of a skin can reference a different base than the previous version.
Dependency Resolution
The existing API exposed a function
1 getUrl(assetBundlePackId: string, context: IApiContext): stringthat accepted an asset bundle ID and returned a single CDN URL. We preserved this function for backwards compatibility and introduced a new function alongside it:
1 getDownloadableAssetBundle(packId: string, context: AssetBundleContext): DownloadableAssetBundle[]This function accepts a skin pack ID and recursively resolves all dependencies:
The resolution reuses the version-selection logic extracted from the original getURL implementation, applied recursively at each level of the hierarchy.
API Changes
The existing assetBundleUrl field on liveop and tournament objects in response to the client remains unchanged.For backwards compatibility a new field was added alongside it to carry the full downloadable asset bundle payload, an array of objects, each with URL, metadata, and dependency type. The client receives a flat array (not a tree structure), but each entry is annotated with its type, allowing the client to handle caching and rendering appropriately.
A conditional check prevents unnecessary overhead: if an asset bundle has no dependencies, the new field is omitted entirely.
Optimus UI Changes
Three additions were made to the backoffice (Optimus) interface:
Validation
All existing validations continue to run (completeness checks, PapayaKit version compatibility, game ID verification). On top of these, new dependency-specific validations enforce:
A review workflow ensures that newly uploaded assets are not immediately visible to players. Artists can use a cheat code to preview new assets in the client before publishing to production.
Results
Trade-offs and Lessons Learned
Lior Orenbach is a backend developer at Papaya Gaming, working on the asset management and content delivery systems.