Bundle Verification Window
The Bundle Verification Window is a Unity Editor tool that lets mod authors configure, verify, and build asset bundles for EnhancedPrefabLoader. It is accessed from the Unity menu bar via Assets > Build AssetBundles with Verification.
Overview
The window provides a GUI for editing all data that goes into a bundle's JSON descriptor. When you build, it exports two files per bundle:
.catalog.json— Editor working file. Uses Unity'sJsonUtilityformat (list-based weights). This file is loaded when you reopen the window so your editor state roundtrips cleanly..json— Game-facing bundle descriptor consumed by EPL Core (Newtonsoft.Json). Items use dictionary-format weight fields (NormalWeights,GodWeights,SlotWeights). All other sections go throughJsonUtility.ToJsonon the catalog object.
On open, the editor tries .catalog.json first, then falls back to .json with automatic migration of old-format weight fields.
Bundle Settings
At the top of each bundle tab you'll find global bundle settings:
| Field | Description |
|---|---|
| Bundle Name | Display name for the bundle. Shown in-game where applicable. |
| Bundle ID | Stable unique identifier used for save data keying. Auto-generated as {name}_{guid} on first open. Read-only in the editor. |
| Auto Compress Textures | When enabled, the build step automatically configures texture import settings for all textures in the bundle. |
| Max Texture Size | Maximum texture resolution. Options: 2048, 1024, 512, 256. Default: 1024. |
| Texture Compression | Compression format. DXT5 (standard, high quality) or BC7 (highest quality, newer GPUs). |
Sections
The window organizes bundle content into collapsible sections. Each section has an "Add New" button at the bottom.
Custom Shops
Custom shops allow mods to add new stores accessible via the in-game phone. Each shop needs a set of sprites for its phone app and web store appearance.
| Field | Description |
|---|---|
| Phone App Id | Unique identifier. Must match the folder name in the Phone Overhaul App directory. |
| App Display Name | Name shown under the app icon on the phone. |
| App Icon | Sprite name for the phone app icon (no file extension). |
| App Inner BG Image | Sprite name for the app's inner background. |
| App Outer BG Image | Sprite name for the app's outer background. |
| Site Logo | Sprite name for the store header logo. |
| Site Header | Sprite name for the store header banner. |
| Site Background | Sprite name for the store background. |
Card Expansions
Card expansions define a set of cards with shared properties like rarities, foil behavior, and pricing strategy.
| Field | Description |
|---|---|
| Card Expansion Name | Display name shown in-game menus and selection screens. |
| Expansion Type | Globally unique internal identifier. Does not appear in game UI. |
| Menu Category | Groups this expansion under a category in selection screens. |
| Has Foils | When enabled, every card in the set has both foil and non-foil variants. |
| Foil Chance | Probability (0-1) that a drawn card is foil. Only shown when Has Foils is enabled. Leave at 0 to use the default of 0.025 (1-in-40). |
| Card Price Strategy | How card market prices are calculated. Default uses border type as the primary driver with rarity as a modifier. RarityDriven uses rarity as the base with border and foil as light multipliers. |
Price Generation Multipliers
After selecting a Card Price Strategy, per-strategy tuning fields appear. These control how border type and foil status affect the generated market price.
Default strategy fields:
| Field | Default | Description |
|---|---|---|
| Border Multiplier Base | 3.15 | Price is multiplied by this value raised to the power of the border type index (Base=0, FirstEdition=1, … FullArt=5). Higher values widen the gap between border tiers. |
| Foil Multiplier | 2.9 | Foil cards have their price multiplied by this value. |
RarityDriven strategy fields:
| Field | Default | Description |
|---|---|---|
| Floor | 4.0 | Minimum base price before any rarity stepping is applied. |
| Step Size | 1026 | Price increase per rarity tier. Each rarity index adds this amount to the base price. |
| Border Multiplier Base | 1.15 | Price is multiplied by this value raised to the power of the border type index. Lower than the Default strategy because rarity is the primary price driver. |
| Foil Multiplier | 1.4 | Foil cards have their price multiplied by this value. Lower than the Default strategy since rarity already accounts for most of the price. |
These multipliers are expansion-scoped — all packs that reference the expansion share the same price generation parameters.
| Card Back Texture | Texture name for the card back sprite. Must be unique across the bundle. | | Foil Mask | Texture name for the expansion's foil mask. Determines where foil appears on cards. |
Play Card Materials
An optional list of material asset names from the bundle to use as card texture sheets on play tables. When customers sit down to play at a table, the game randomly picks a card texture set — if any expansion provides play card materials, that expansion's materials may be selected. Both CPU players at a table always use materials from the same expansion.
If no expansion provides play card materials, the base game's built-in card textures are used. A config option (PlayTable > DisableBaseGamePlayCards) allows players to exclude base game textures from the pool, forcing mod expansion textures to be used instead (ignored if no mod textures are available).
Add/remove material name entries with the list controls. Material names must match assets included in the bundle.
Rarities
A list of rarity names for the expansion (e.g., "Common", "Rare", "Ultra Rare"). These are referenced by cards and by pack generation weight tables. Add/remove rarities with the list controls.
Cards
Each card in the expansion has the following fields:
| Field | Description |
|---|---|
| Name | Display name of the card. |
| Element Type | The card's element. Only affects day-to-day price fluctuations. Dropdown sourced from EElementIndex. |
| Border Type | Affects initial price generation. Base generates the lowest prices, FullArt the highest. Dropdown sourced from ECardBorderType. |
| Rarity | Dropdown populated from the parent expansion's rarity list. |
| Sprite | Sprite name for the card image. Must be unique across the bundle. |
| Is Guaranteed Foil | Only shown when the expansion does not have random foils. Forces this card to always be foil. |
| Foil Mask | Per-card foil mask override. Falls back to the expansion's foil mask if empty. |
| Card Back | Per-card card back override. Falls back to the expansion's card back if empty. |
Each card also displays a Calculated Pricing preview showing the min/max price range based on the expansion's Card Price Strategy. If the expansion has foils, both Normal and Foil price ranges are shown.
Items
Items cover everything sold in shops: standalone products, booster packs, booster boxes, and bulk boxes.
Common Fields
| Field | Description |
|---|---|
| Name | Display name of the item. |
| Phone App Id | Links this item to a custom shop by its App ID. |
| Category | Shop category. Dropdown sourced from EItemCategory. |
| Sprite | Sprite name for store/box/price tag display. Must be unique across the bundle. |
| Item Type | Globally unique identifier for this item across all bundles. |
TCG Item Types
When the item category is TCG, three mutually exclusive toggles become available:
- Is Bulk Box — A bulk card box. Automatically sets mesh to
BulkBox_TetramonBase. - Is Booster Box — A card box that spawns packs when opened. Automatically sets mesh to
BasicCardBox. - Is Booster Pack — A card pack that spawns cards when opened. Automatically sets mesh to
BasicCardPack.
Box Type Settings
For non-bulk-box items, two toggles control which shipping box variants exist for the item:
| Field | Description |
|---|---|
| Has Small Box | Enables a small shipping box variant for this item. |
| Has Big Box | Enables a big shipping box variant for this item. |
At least one must be enabled. If neither is set in the descriptor, HasSmallBox defaults to true.
Each enabled box type shows a collapsible settings section with per-box configuration:
| Field | Description |
|---|---|
| License Price | Cost to unlock this item in this box variant. |
| License Level | Player level required to unlock this box variant. |
| Hide Until Unlocked | Shows a question mark sprite/name until the player purchases the license for this box variant. |
| Ignore Double Image | Prevents duplicate image rendering for this box variant. |
These fields are independent per box type — a small box and big box for the same item can have different license prices, level requirements, and visibility settings.
Backwards compatibility: Existing descriptors using the old
IsBigBox,LicensePrice,LicenseLevelRequirement,HideTillUnlocked, andIgnoreDoubleImagefields are automatically mapped to the big box settings. No descriptor changes are required for bundles that only use big boxes.
Shop Category Flags (non-TCG, non-box/pack)
| Field | Description |
|---|---|
| Add to Accessory Store | Lists the item in the accessory shop. |
| Add to Figurine Store | Lists the item in the figurine shop. |
| Add to Board Game Store | Lists the item in the board game shop. |
| Is Spray Can | Marks the item as a spray can. |
Price Settings
| Field | Description |
|---|---|
| Follow Item Price | Copies base cost and market price percentages from another item. Dropdown sourced from EItemType. Select None to set prices manually. |
| Auto Set Box Price | Only for booster boxes when Follow Item Price is None. Sets price to 8x the spawned pack's price. |
| Base Cost | Per-item base cost. Hidden when Follow Item Price is set or Auto Set Box Price is enabled. |
| Min Market Price % | Minimum market price as a percentage of base cost. Default: 1.0. |
| Max Market Price % | Maximum market price as a percentage of base cost. Default: 1.2. |
Price Affected By
A list of EPriceChangeType values that influence this item's market price fluctuations. Add/remove entries with the list controls.
Item Configuration
| Field | Description |
|---|---|
| Material | Material name for the item mesh. Not required for card boxes. |
| Material List | Multiple materials. If set, takes precedence over the single Material field. For packs/boxes, a random material is chosen from this list. |
| Uses Base Game Mesh | When enabled, uses an existing game mesh instead of a custom one. |
| Item Mesh To Use | Dropdown sourced from EItemType. Only shown when Uses Base Game Mesh is enabled. |
| Mesh | Custom mesh name. Only shown when Uses Base Game Mesh is disabled. |
| Is Tall Item | Marks the item as tall for shelf placement. |
| In Box Y Offset / Scale | Positioning adjustments when the item is inside a box. |
| Collider Offset / Scale | Physics collider position and size. |
| Item Dimensions | Visual dimensions of the item mesh. |
Booster Box Configuration
Only shown for booster boxes:
| Field | Description |
|---|---|
| Spawns Packs | Dropdown of all booster pack items in the bundle. Selects which pack type this box produces. |
Booster Pack Configuration
Only shown for booster packs:
| Field | Description |
|---|---|
| Card Expansion | Dropdown showing expansion Name (falls back to Expansion Type if Name is empty). Stores the Expansion Type value. |
| Can Have Duplicates | Allows duplicate cards within a single pack. |
| Can Have God Packs | Enables god pack generation for this pack type. |
| God Pack Chance | Probability of a god pack. Value is N / X (e.g., 1/5000 = 0.0002). Only shown when god packs are enabled. |
| Pack Generation Strategy | How cards are selected for the pack. See below. |
| Pack Type | Globally unique identifier. Required but does not appear in game UI. |
Pack Generation Strategies
AllRandom — Cards are selected completely at random. No weight configuration needed.
AllRandomWeighted — All cards drawn from a shared rarity weight table. Displays a Normal Weights table with one row per rarity and a weight column.
Guaranteed — Each of the 7 pack slots has its own independent rarity weight table. Displays a 2D grid with rarities as rows and Slot1-Slot7 as columns. All 7 slots are always present.
When Can Have God Packs is enabled, an additional God Pack Weights table appears. All cards in a god pack are foil.
Weight tables automatically sync their rarity entries to match the linked card expansion's rarity list.
Bulk Box Configuration
Only shown for bulk boxes:
| Field | Description |
|---|---|
| Use Custom Min Value | When disabled, select a box type from a preset dropdown. When enabled, enter a raw value. |
| Box Type | Preset dropdown: White (0), Yellow (100), Pink (200), Red (400), Green (1200). |
| Min Value | Raw minimum card value. Only shown when Use Custom Min Value is enabled. |
| Card Expansion | The expansion this bulk box draws cards from. |
Prefabs & Decos
Prefabs cover furniture, deco objects, deco textures, and UI prefabs.
| Field | Description |
|---|---|
| Name | Display name. |
| Prefab Name | Asset bundle prefab name. Not shown in-game. |
| Is UI Prefab | When enabled, hides all other fields and shows UI-specific options. |
UI Prefab Mode
| Field | Description |
|---|---|
| Instantiate In Title | Places the prefab as a child of the title scene's Canvas. |
| Instantiate In Start | Places the prefab as a child of the start scene's Canvas. |
Standard Prefab Mode
| Field | Description |
|---|---|
| Sprite | Sprite name for store display. Must be unique across the bundle. |
| Price | Purchase price in-game. |
| Level Requirement | Player level required to purchase. |
Two mutually exclusive groups of toggles determine the prefab type:
Object Group (Furniture / Deco Objects):
- Is Deco Object — A decorative object (statue, sign, etc.).
- Is Furniture — A DIY Shop furniture item.
Texture Group (Deco Textures):
- Is Wall Texture — A wall texture in the Deco store.
- Is Floor Texture — A floor texture in the Deco store.
- Is Ceiling Texture — A ceiling texture in the Deco store.
Only one group can be active at a time. Selecting a toggle from one group hides the other group's toggles.
Deco Object Fields
| Field | Description |
|---|---|
| Deco Bonus | Decoration bonus value. |
| Deco Object | Globally unique identifier. Does not appear in game UI. |
| Deco Type | Dropdown sourced from EDecoType. |
Furniture Fields
| Field | Description |
|---|---|
| Deco Bonus | Decoration bonus value. |
| Description | Text description of the furniture item. |
| Object Type | Globally unique identifier. Does not appear in game UI. |
Both object types also support Video Clips — a list of named video clip entries with a clip name and player name.
Texture Fields
| Field | Description |
|---|---|
| Texture | Main texture name. |
| Roughness Map | Roughness texture name. |
| Normal Map | Normal map texture name. |
| Smoothness | Smoothness value for the material. |
| Color | Tint color for the texture. |
Assemblies
If the bundle directory contains .dll files, they are automatically detected and listed here. Assembly names are editable but typically auto-populated.
Building
- Open the window via Assets > Build AssetBundles with Verification.
- Select a bundle from the dropdown at the top.
- Check Include in Build for each bundle you want to export.
- Fill in or verify all fields.
- Click Build Selected Bundles.
The build process:
- Writes both
.catalog.jsonand.jsonfiles toAssets/AssetBundles/<bundle-path>/. - If Auto Compress Textures is enabled, configures texture import settings:
- Card sprites get Kaiser mipmap filtering enabled.
- Non-card textures have mipmaps disabled.
- All textures are set to the configured max size and compression format.
- Normal maps are always compressed with DXT5.
- Builds the Unity asset bundle with chunk-based compression.
File Format Details
Catalog JSON (.catalog.json)
Used internally by the editor for roundtripping. Weights are stored as lists:
{
"Name": "My Bundle",
"BundleId": "my_bundle_abc123",
"Items": [
{
"NormalWeights": [
{ "Rarity": "Common", "Weight": 1.0 },
{ "Rarity": "Rare", "Weight": 0.5 }
],
"SlotWeights": [
{
"Slot": 1,
"Weights": [
{ "Rarity": "Common", "Weight": 1.0 }
]
}
]
}
]
}
Bundle Descriptor (.json)
Consumed by EPL Core. Items use dictionary-format weights. Big box fields use the original JSON keys for backwards compatibility; small box fields use prefixed keys:
{
"Name": "My Bundle",
"BundleId": "my_bundle_abc123",
"Items": [
{
"IsBigBox": true,
"LicensePrice": 500,
"LicenseLevelRequirement": 3,
"HideTillUnlocked": true,
"IgnoreDoubleImage": false,
"HasSmallBox": true,
"SmallBoxLicensePrice": 100,
"SmallBoxLicenseLevelRequirement": 1,
"SmallBoxHideTillUnlocked": false,
"SmallBoxIgnoreDoubleImage": false,
"NormalWeights": { "Common": 1.0, "Rare": 0.5 },
"GodWeights": { "Common": 0.1, "Rare": 1.0 },
"SlotWeights": {
"Slot1": { "Common": 1.0, "Rare": 0.2 },
"Slot2": { "Common": 0.5, "Rare": 1.0 }
}
}
]
}
Note:
IsBigBox,LicensePrice,LicenseLevelRequirement,HideTillUnlocked, andIgnoreDoubleImageare the JSON keys for big box settings. These names are preserved for backwards compatibility with existing descriptors. TheBigBoxprefix is used on the C# property names but not in the JSON output.
The custom JSON builder is necessary because Unity's JsonUtility cannot serialize Dictionary<K,V>. Non-item sections use JsonUtility.ToJson directly.
Migration
When opening a bundle that only has an old-format .json file (no .catalog.json), the editor automatically migrates item weight fields:
GenerationWeights[].NormalWeightis converted toNormalWeightsdictionary entries.GenerationWeights[].GodPackWeightis converted toGodWeightsdictionary entries.GenerationWeights[].GuaranteedSlotsis distributed intoSlotWeights: for each entry, itsNormalWeightis written into everyPackSlotwhose bit is set in the legacyGuaranteedSlotsflag. An entry withGuaranteedSlots = 7(Slot1|Slot2|Slot3) adds that rarity with itsNormalWeightto the weight tables for slots 1, 2, and 3.
The migrated data is saved to .catalog.json on the next build.
Box Type Migration
Old descriptors using IsBigBox and the shared LicensePrice, LicenseLevelRequirement, HideTillUnlocked, and IgnoreDoubleImage fields are automatically mapped to the big box settings via [JsonProperty] attributes. No descriptor changes are required.
If neither IsBigBox (mapped to HasBigBox) nor HasSmallBox is set, HasSmallBox defaults to true during sanitization.
Save data migration: existing saves with a single IsUnlocked field are automatically read as IsBigBoxUnlocked. A new IsSmallBoxUnlocked field defaults to false, meaning players may need to re-purchase small box licenses after upgrading.