# Asset System The Hytale asset system manages game assets including blocks, items, models, sounds, particles, and more. This guide covers how to work with assets and create custom content. ## Overview Assets are defined in JSON files and loaded by the `AssetStore`. The server provides a type-safe asset system with: - JSON-based asset definitions - Codec-based serialization - Asset type registration - Asset pack support for mods ## Asset Store ### Accessing Assets ```java // Get the asset store AssetStore store = HytaleAssetStore.get(); // Get a specific asset by ID BlockType block = store.get(BlockType.class, "stone"); ItemType item = store.get(ItemType.class, "sword"); // Get all assets of a type Collection allBlocks = store.getAll(BlockType.class); ``` ### Asset Loading Assets are loaded from: 1. Core game assets 2. Plugin asset packs (when `IncludesAssetPack: true` in manifest) ## Asset Types The server supports many built-in asset types located in `server/core/asset/type/`: | Asset Type | Description | |------------|-------------| | `BlockType` | Block definitions (stone, dirt, etc.) | | `ItemType` | Item definitions | | `ModelAsset` | 3D model definitions | | `SoundEvent` | Sound effect definitions | | `ParticleAsset` | Particle system definitions | | `WeatherAsset` | Weather type definitions | | `EnvironmentAsset` | Environment settings | | `FluidAsset` | Fluid definitions | | `EntityEffect` | Entity effect definitions | | `BiomeAsset` | Biome definitions | | `StructureAsset` | Structure/prefab definitions | ## Blocks ### Block Type Definition Block types are defined in JSON: ```json { "id": "mymod:custom_block", "name": "Custom Block", "model": "mymod:models/custom_block", "hardness": 2.0, "resistance": 6.0, "drops": ["mymod:custom_block"], "sounds": { "break": "block.stone.break", "place": "block.stone.place", "step": "block.stone.step" }, "properties": { "transparent": false, "solid": true, "flammable": false } } ``` ### Block States Blocks can have multiple states (orientations, variations): ```java // Get block state BlockState state = BlockStates.get("stone"); // Create state with properties BlockState orientedBlock = BlockStates.get("log", Map.of( "axis", "y" )); // Check block properties boolean isSolid = state.isSolid(); boolean isTransparent = state.isTransparent(); ``` ### Registering Block States ```java @Override protected void setup() { getBlockStateRegistry().register("custom_block", CustomBlockState.class); } ``` ## Items ### Item Type Definition ```json { "id": "mymod:custom_sword", "name": "Custom Sword", "model": "mymod:models/custom_sword", "maxStackSize": 1, "durability": 500, "itemType": "weapon", "damage": 7.0, "attackSpeed": 1.6, "enchantable": true } ``` ### Working with Items ```java // Get item type ItemType swordType = store.get(ItemType.class, "mymod:custom_sword"); // Create item stack ItemStack stack = new ItemStack(swordType, 1); // Set item data stack.setDurability(400); stack.setCustomName("Legendary Sword"); // Add to inventory player.getInventory().addItem(stack); ``` ## Models ### Model Asset Definition ```json { "id": "mymod:models/custom_block", "type": "block", "textures": { "all": "mymod:textures/custom_block" }, "elements": [ { "from": [0, 0, 0], "to": [16, 16, 16], "faces": { "north": {"texture": "#all"}, "south": {"texture": "#all"}, "east": {"texture": "#all"}, "west": {"texture": "#all"}, "up": {"texture": "#all"}, "down": {"texture": "#all"} } } ] } ``` ## Sounds ### Sound Event Definition ```json { "id": "mymod:custom_sound", "sounds": [ { "name": "mymod:sounds/custom1", "volume": 1.0, "pitch": 1.0, "weight": 1 }, { "name": "mymod:sounds/custom2", "volume": 0.8, "pitch": 1.2, "weight": 1 } ], "category": "block" } ``` ### Playing Sounds ```java // Get sound event SoundEvent sound = store.get(SoundEvent.class, "mymod:custom_sound"); // Play at position world.playSound(sound, position, volume, pitch); // Play to specific player player.playSound(sound, volume, pitch); // Play to all nearby players world.playSoundNearby(sound, position, radius, volume, pitch); ``` ## Particles ### Particle Asset Definition ```json { "id": "mymod:custom_particle", "texture": "mymod:textures/particles/custom", "lifetime": 20, "scale": 1.0, "gravity": 0.04, "color": [1.0, 1.0, 1.0, 1.0], "fadeOut": true } ``` ### Spawning Particles ```java // Get particle asset ParticleAsset particle = store.get(ParticleAsset.class, "mymod:custom_particle"); // Spawn particles world.spawnParticle(particle, position, count, spreadX, spreadY, spreadZ, speed); // Spawn for specific player player.spawnParticle(particle, position, count); ``` ## Custom Asset Types ### Defining a Custom Asset Type ```java public class MyCustomAsset { public static final Codec CODEC = BuilderCodec.of(MyCustomAsset::new) .with("id", Codec.STRING, a -> a.id) .with("value", Codec.INTEGER, a -> a.value, 0) .with("enabled", Codec.BOOLEAN, a -> a.enabled, true) .build(); private final String id; private final int value; private final boolean enabled; public MyCustomAsset(String id, int value, boolean enabled) { this.id = id; this.value = value; this.enabled = enabled; } public String getId() { return id; } public int getValue() { return value; } public boolean isEnabled() { return enabled; } } ``` ### Registering Custom Asset Types ```java @Override protected void setup() { getAssetRegistry().register(MyCustomAsset.class, MyCustomAsset.CODEC); } ``` ### Using Custom Assets ```java @Override protected void start() { AssetStore store = HytaleAssetStore.get(); // Get all custom assets Collection assets = store.getAll(MyCustomAsset.class); for (MyCustomAsset asset : assets) { if (asset.isEnabled()) { processAsset(asset); } } } ``` ## Asset Packs ### Creating an Asset Pack 1. Set `IncludesAssetPack: true` in your `manifest.json` 2. Create an `assets/` directory in your JAR 3. Organize assets following Hytale's structure: ``` assets/ ├── mymod/ │ ├── blocks/ │ │ └── custom_block.json │ ├── items/ │ │ └── custom_item.json │ ├── models/ │ │ ├── block/ │ │ │ └── custom_block.json │ │ └── item/ │ │ └── custom_item.json │ ├── textures/ │ │ ├── blocks/ │ │ │ └── custom_block.png │ │ └── items/ │ │ └── custom_item.png │ └── sounds/ │ └── custom_sound.ogg ``` ### Asset Namespacing Assets are namespaced by plugin ID: ``` {group}:{name} -> mymod:custom_block ``` Reference assets using their full namespaced ID to avoid conflicts. ## Entity Assets ### Entity Type Definition Entities can have associated assets: ```json { "id": "mymod:custom_mob", "name": "Custom Mob", "model": "mymod:models/entity/custom_mob", "textures": { "default": "mymod:textures/entity/custom_mob" }, "animations": { "idle": "mymod:animations/custom_mob_idle", "walk": "mymod:animations/custom_mob_walk", "attack": "mymod:animations/custom_mob_attack" }, "sounds": { "hurt": "mymod:entity.custom_mob.hurt", "death": "mymod:entity.custom_mob.death", "ambient": "mymod:entity.custom_mob.ambient" }, "attributes": { "maxHealth": 20.0, "movementSpeed": 0.3, "attackDamage": 4.0 } } ``` ## Weather Assets ### Weather Definition ```json { "id": "mymod:custom_weather", "name": "Custom Weather", "particles": "mymod:weather_particle", "skyColor": [0.5, 0.5, 0.7], "fogColor": [0.6, 0.6, 0.8], "lightLevel": 0.7, "sounds": { "ambient": "mymod:weather.custom.ambient" } } ``` ## Environment Assets ### Environment Definition ```json { "id": "mymod:custom_environment", "skybox": "mymod:textures/skybox/custom", "ambientLight": 0.4, "sunLight": 1.0, "fogDensity": 0.02, "music": "mymod:music/custom_ambient" } ``` ## Best Practices 1. **Use namespaces** - Always prefix asset IDs with your mod namespace 2. **Follow conventions** - Use lowercase, underscores for asset IDs 3. **Optimize textures** - Use appropriate resolutions and compression 4. **Provide fallbacks** - Handle missing assets gracefully 5. **Document assets** - Comment complex asset definitions 6. **Test loading** - Verify all assets load correctly 7. **Version assets** - Track asset changes with mod versions 8. **Reuse when possible** - Reference existing assets instead of duplicating ## Troubleshooting ### Asset Not Found ```java // Check if asset exists if (store.has(MyAsset.class, "mymod:asset_id")) { MyAsset asset = store.get(MyAsset.class, "mymod:asset_id"); } ``` ### Asset Loading Errors - Check JSON syntax - Verify codec definitions match JSON structure - Ensure all referenced assets (textures, models) exist - Check namespace spelling ### Asset Pack Not Loading - Verify `IncludesAssetPack: true` in manifest - Check asset directory structure - Ensure JAR file includes assets