436 lines
9.9 KiB
Markdown
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
|