Version: 1.0.0
Category: Modding
Scope: API Integration
Purpose: Document how cosmetic mods integrate with the game system and API
This protocol defines how cosmetic mods integrate with the Structs game system, specifically how cosmetic overrides are applied when querying struct types through the API.
System Context: This protocol covers the integration of cosmetics after they have been ingested into the system. Cosmetics are stored as Sets and Skins with hash-based identification. See Cosmetic System Overview for the complete architecture.
Note: During ingestion (Phase 2), cosmetic mods (Phase 1 format) are converted to Sets/Skins format with hash-based identification. This protocol covers the integration of Sets/Skins with the game system.
┌─────────────────────────────────────┐
│ Game Client / UI │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Web Application API │
│ (Cosmetic Mod Integration Layer) │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Consensus Network API │
│ (Base Struct Type Data) │
└─────────────────────────────────────┘
Consensus Network API (/structs/struct_type/{id}):
defaultCosmeticName, defaultCosmeticModelNumber)Web Application API (/api/cosmetic/class/{class}):
class field to link to struct typesIntegration Endpoint (/api/struct-type/{id}/full?class={class}):
id: Struct type ID (for base game data)class: Optional - struct type class (for cosmetic lookup)When multiple skins affect the same struct type class:
Note: Skins are linked to struct types via the class field (e.g., “Miner”, “Reactor”), not by struct type ID. The class field matches the on-chain struct type class name. Skins are identified by skinHash (SHA-256, 64-character hex), and sets are identified by setHash.
Text Fields (names, lore, descriptions):
Asset Fields (animations, icons, graphics):
Weapon/Ability Cosmetics:
Use Case: Display struct type in game UI
Workflow:
Example:
{
"workflow": "get-struct-type-with-cosmetics",
"steps": [
{
"step": 1,
"endpoint": "struct-type-by-id",
"api": "consensus",
"url": "/structs/struct_type/miner",
"description": "Get base struct type data"
},
{
"step": 2,
"endpoint": "cosmetic-class",
"api": "webapp",
"url": "/api/cosmetic/class/Miner?language=en&guildId=0-1",
"description": "Get cosmetic skin overrides for class 'Miner'"
},
{
"step": 3,
"action": "merge",
"description": "Merge base data with cosmetic overrides"
}
]
}
OR use integration endpoint:
{
"endpoint": "struct-type-with-cosmetics",
"api": "webapp",
"url": "/api/struct-type/1-11/full?class=Miner&language=en&guildId=0-1",
"description": "Get complete struct type with cosmetics (single call). Uses struct type ID for base data and class for cosmetic lookup."
}
Use Case: Display struct type list in game UI
Workflow:
Example:
{
"workflow": "list-struct-types-with-cosmetics",
"steps": [
{
"step": 1,
"endpoint": "struct-type-list",
"api": "consensus",
"url": "/structs/struct_type"
},
{
"step": 2,
"endpoint": "cosmetic-struct-type-list",
"api": "webapp",
"url": "/api/cosmetic/struct-types?language=en&guildId=0-1"
},
{
"step": 3,
"action": "merge-all",
"description": "Merge base data with cosmetic overrides for each struct type"
}
]
}
Use Case: Install and activate a cosmetic mod
Workflow:
Example:
{
"workflow": "install-cosmetic-mod",
"steps": [
{
"step": 1,
"endpoint": "cosmetic-mod-validate",
"api": "webapp",
"url": "/api/cosmetic-mods/validate",
"method": "POST",
"body": {
"file": "path/to/mod.zip"
}
},
{
"step": 2,
"endpoint": "cosmetic-mod-install",
"api": "webapp",
"url": "/api/cosmetic-mods/install",
"method": "POST",
"body": {
"file": "path/to/mod.zip",
"validate": true,
"activate": true
}
},
{
"step": 3,
"endpoint": "cosmetic-mod-get",
"api": "webapp",
"url": "/api/cosmetic-mods/{modId}",
"description": "Verify mod is installed and active"
}
]
}
Base Data (from consensus network):
{
"id": "miner",
"type": "Miner",
"defaultCosmeticName": "Miner"
}
Skin Override:
{
"class": "Miner",
"skinHash": "f1e2d3c4b5a6789012345678901234567890abcdef1234567890abcdef123456",
"name": {
"en": "Alpha Extractor"
}
}
Merged Result:
{
"id": "miner",
"type": "Miner",
"defaultCosmeticName": "Miner",
"cosmeticName": "Alpha Extractor"
}
Base Data:
{
"id": "miner",
"primaryWeapon": "drill"
}
Skin Override:
{
"class": "Miner",
"skinHash": "f1e2d3c4b5a6789012345678901234567890abcdef1234567890abcdef123456",
"weapons": [
{
"weaponType": "primary",
"names": {
"en": "Plasma Drill"
}
}
]
}
Merged Result:
{
"id": "miner",
"primaryWeapon": "drill",
"weaponCosmetics": {
"primary": {
"name": "Plasma Drill"
}
}
}
Base Data:
{
"id": "miner",
"defaultAnimation": "/assets/animations/miner-idle.json"
}
Skin Override:
{
"class": "Miner",
"skinHash": "f1e2d3c4b5a6789012345678901234567890abcdef1234567890abcdef123456",
"animations": {
"idle": "animations/miner-idle-custom.json"
}
}
Merged Result:
{
"id": "miner",
"defaultAnimation": "/assets/animations/miner-idle.json",
"cosmeticAnimations": {
"idle": "/mods/guild-alpha-miner-v1/animations/miner-idle-custom.json"
}
}
requested → en → defaultExample:
{
"request": {
"language": "es"
},
"mod": {
"names": {
"en": "Alpha Extractor",
"es": "Extractor Alpha"
}
},
"result": "Extractor Alpha" // Spanish from mod
}
Fallback Example:
{
"request": {
"language": "fr"
},
"mod": {
"names": {
"en": "Alpha Extractor"
}
},
"result": "Alpha Extractor" // English fallback from mod
}
Scenario: Skin referenced in cosmetic data doesn’t exist
Response:
{
"error": "COSMETIC_SKIN_NOT_FOUND",
"message": "Skin with hash 'f1e2d3c4b5a6789012345678901234567890abcdef1234567890abcdef123456' not found",
"skinHash": "f1e2d3c4b5a6789012345678901234567890abcdef1234567890abcdef123456",
"fallback": "Using default game assets"
}
Behavior: System falls back to default game assets
Scenario: Skin hash is invalid or doesn’t match content
Response:
{
"error": "COSMETIC_SKIN_INVALID_HASH",
"message": "Skin hash validation failed",
"details": {
"skinHash": "f1e2d3c4b5a6789012345678901234567890abcdef1234567890abcdef123456",
"issue": "Hash mismatch: calculated hash does not match provided hash"
}
}
Behavior: Skin is not loaded, system uses default assets
Scenario: Skin references struct type class that doesn’t exist
Response:
{
"error": "STRUCT_TYPE_CLASS_NOT_FOUND",
"message": "Struct type class 'InvalidClass' not found in game",
"class": "InvalidClass",
"skinHash": "f1e2d3c4b5a6789012345678901234567890abcdef1234567890abcdef123456"
}
Behavior: Skin override for that class is ignored
Recommendation: Cache merged struct type data
Cache Key: struct-type-{id}-{language}-{guildId}
TTL:
Recommendation: Use batch endpoints when querying multiple struct types
Example:
{
"endpoint": "/api/cosmetic/struct-types",
"description": "Get cosmetics for all struct types in one call"
}
Recommendation: Load cosmetic data only when needed
Pattern:
Before Integration:
During Integration:
technical/cosmetic-system-overview.md - Complete system architecturetechnical/cosmetic-sets-and-skins.md - Sets/Skins structuretechnical/cosmetic-hash-system.md - Hash-based identificationapi/cosmetic-mods.md - Complete API referenceschemas/cosmetic-set.md - Set schema (after ingestion)schemas/cosmetic-skin.md - Skin schema (after ingestion)schemas/cosmetic-mod.md - Mod file schema (Phase 1, before ingestion)protocols/cosmetic-mod-protocol.md - Mod protocolexamples/workflows/ - Integration examplesProtocol Version: 1.0.0 - January 2025