# 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<BlockType> 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<MyCustomAsset> 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<MyCustomAsset> 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
