Files
hytale-server/docs/08-asset-system.md

436 lines
9.9 KiB
Markdown

# 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