NYC
skills/smithery/ai/hytale-custom-assets

hytale-custom-assets

SKILL.md

Creating Custom Hytale Assets

Complete guide for creating and managing custom assets including models, textures, sounds, and particles.

When to use this skill

Use this skill when:

  • Creating asset packs for plugins
  • Adding custom textures and models
  • Configuring sounds and music
  • Creating particle effects
  • Setting up animations
  • Managing asset inheritance and tags

Asset System Architecture

Hytale uses a hierarchical asset system:

AssetPack
├── Server/          # Server-side assets
│   └── Content/     # Game content definitions
│       ├── BlockTypes/
│       ├── Items/
│       ├── Entities/
│       └── ...
└── Client/          # Client-side assets
    ├── Models/
    ├── Textures/
    ├── Sounds/
    ├── Particles/
    └── ...

Asset Pack Structure

my-plugin/
└── assets/
    ├── pack.json                    # Pack metadata
    ├── Server/
    │   └── Content/
    │       ├── BlockTypes/
    │       │   └── custom_block.blocktype
    │       ├── Items/
    │       │   └── custom_item.item
    │       ├── Entities/
    │       │   └── custom_entity.entity
    │       ├── Recipes/
    │       │   └── custom_recipe.recipe
    │       └── Sounds/
    │           └── custom_soundset.soundset
    └── Client/
        ├── Models/
        │   └── custom_model.model
        ├── Textures/
        │   ├── blocks/
        │   │   └── custom_block.png
        │   ├── items/
        │   │   └── custom_item.png
        │   └── entities/
        │       └── custom_entity.png
        ├── Sounds/
        │   └── custom/
        │       └── sound.ogg
        ├── Particles/
        │   └── custom_particle.particle
        └── Animations/
            └── custom_animation.animation

Pack Metadata

File: pack.json

{
  "Name": "MyPlugin Assets",
  "Id": "MyPlugin",
  "Version": "1.0.0",
  "Description": "Custom assets for MyPlugin",
  "Author": "Your Name",
  "Priority": 100,
  "Dependencies": ["Hytale:Core"]
}

Pack Properties

Property Type Description
Name String Display name
Id String Unique identifier
Version String Semantic version
Description String Pack description
Author String Creator name
Priority Integer Load order (higher = later)
Dependencies Array Required packs

Textures

Texture Formats

Format Use Case
PNG Standard textures (recommended)
TGA Textures with alpha
DDS Compressed textures

Block Textures

Location: Client/Textures/blocks/

custom_block.png          # All faces
custom_block_top.png      # Top face only
custom_block_side.png     # Side faces
custom_block_bottom.png   # Bottom face

Texture Size: 16x16, 32x32, 64x64 (power of 2)

Item Textures

Location: Client/Textures/items/

custom_item.png           # Inventory icon (32x32)
custom_item_held.png      # Held model texture

Entity Textures

Location: Client/Textures/entities/

custom_entity.png         # Main texture atlas
custom_entity_glow.png    # Emissive layer
custom_entity_normal.png  # Normal map

Models

Model Format

Hytale uses a custom JSON-based model format.

File: custom_model.model

{
  "Parent": "Hytale/Models/base_entity",
  "Textures": {
    "main": "MyPlugin/Textures/entities/custom_entity"
  },
  "Bones": [
    {
      "Name": "root",
      "Pivot": [0, 0, 0],
      "Children": [
        {
          "Name": "body",
          "Pivot": [0, 12, 0],
          "Cubes": [
            {
              "Origin": [-4, 0, -2],
              "Size": [8, 12, 4],
              "UV": [0, 0]
            }
          ],
          "Children": [
            {
              "Name": "head",
              "Pivot": [0, 24, 0],
              "Cubes": [
                {
                  "Origin": [-4, 0, -4],
                  "Size": [8, 8, 8],
                  "UV": [0, 16]
                }
              ]
            }
          ]
        }
      ]
    }
  ],
  "Animations": {
    "idle": "MyPlugin/Animations/custom_idle",
    "walk": "MyPlugin/Animations/custom_walk"
  }
}

Model Properties

Property Type Description
Parent String Parent model to inherit
Textures Object Texture bindings
Bones Array Bone hierarchy
Animations Object Animation bindings
Scale Float Overall scale
TextureSize Array Texture dimensions [W, H]

Bone Properties

Property Type Description
Name String Bone identifier
Pivot Array Rotation pivot point
Rotation Array Default rotation [X, Y, Z]
Cubes Array Geometry cubes
Children Array Child bones
Mirror Boolean Mirror UV horizontally

Cube Properties

Property Type Description
Origin Array Position offset
Size Array Dimensions [W, H, D]
UV Array Texture UV offset [U, V]
Inflate Float Expand cube size
Mirror Boolean Mirror this cube

Animations

File: custom_animation.animation

{
  "Length": 1.0,
  "Loop": true,
  "Bones": {
    "body": {
      "Rotation": {
        "0.0": [0, 0, 0],
        "0.5": [5, 0, 0],
        "1.0": [0, 0, 0]
      }
    },
    "leftArm": {
      "Rotation": {
        "0.0": [0, 0, 0],
        "0.25": [-30, 0, 0],
        "0.5": [0, 0, 0],
        "0.75": [30, 0, 0],
        "1.0": [0, 0, 0]
      }
    },
    "rightArm": {
      "Rotation": {
        "0.0": [0, 0, 0],
        "0.25": [30, 0, 0],
        "0.5": [0, 0, 0],
        "0.75": [-30, 0, 0],
        "1.0": [0, 0, 0]
      }
    }
  }
}

Animation Properties

Property Type Description
Length Float Duration in seconds
Loop Boolean Loop animation
Bones Object Per-bone keyframes

Keyframe Channels

Channel Type Description
Rotation Array Rotation [X, Y, Z] degrees
Position Array Position offset [X, Y, Z]
Scale Array Scale [X, Y, Z]

Sounds

Sound Formats

Format Use Case
OGG Music, ambient (recommended)
WAV Short sound effects

Sound Event

File: custom_sound.soundevent

{
  "Sounds": [
    {
      "Path": "MyPlugin/Sounds/custom/sound1",
      "Weight": 1.0
    },
    {
      "Path": "MyPlugin/Sounds/custom/sound2",
      "Weight": 0.5
    }
  ],
  "Volume": {
    "Min": 0.8,
    "Max": 1.0
  },
  "Pitch": {
    "Min": 0.9,
    "Max": 1.1
  },
  "Category": "Effects",
  "Subtitle": {
    "en-US": "Custom sound plays"
  }
}

Sound Set

File: custom_soundset.soundset

{
  "Sounds": {
    "break": "MyPlugin/SoundEvents/custom_break",
    "place": "MyPlugin/SoundEvents/custom_place",
    "step": "MyPlugin/SoundEvents/custom_step",
    "hit": "MyPlugin/SoundEvents/custom_hit"
  }
}

Block Sound Set

File: custom_blocksound.blocksound

{
  "Break": {
    "Sound": "MyPlugin/SoundEvents/metal_break",
    "Volume": 1.0,
    "Pitch": 1.0
  },
  "Place": {
    "Sound": "MyPlugin/SoundEvents/metal_place",
    "Volume": 1.0
  },
  "Step": {
    "Sound": "MyPlugin/SoundEvents/metal_step",
    "Volume": 0.5
  },
  "Fall": {
    "Sound": "MyPlugin/SoundEvents/metal_fall"
  }
}

Sound Categories

Category Description
Master All sounds
Music Background music
Effects Sound effects
Ambient Environmental sounds
Voice Voice/dialogue
UI Interface sounds
Weather Weather sounds

Particles

File: custom_particle.particle

{
  "Texture": "MyPlugin/Textures/particles/sparkle",
  "MaxParticles": 100,
  "EmissionRate": 10,
  "Lifetime": {
    "Min": 0.5,
    "Max": 1.5
  },
  "Size": {
    "Start": 0.2,
    "End": 0.0
  },
  "Color": {
    "Start": { "R": 1.0, "G": 0.8, "B": 0.2, "A": 1.0 },
    "End": { "R": 1.0, "G": 0.2, "B": 0.0, "A": 0.0 }
  },
  "Velocity": {
    "Min": [-0.5, 1.0, -0.5],
    "Max": [0.5, 2.0, 0.5]
  },
  "Gravity": -0.5,
  "Collision": false,
  "BlendMode": "Additive"
}

Particle Properties

Property Type Description
Texture String Particle texture
MaxParticles Integer Maximum active particles
EmissionRate Float Particles per second
Lifetime Range Particle lifespan
Size Range/Gradient Size over lifetime
Color Color/Gradient Color over lifetime
Velocity Range Initial velocity
Gravity Float Gravity effect
Collision Boolean Collide with blocks
BlendMode Enum Alpha, Additive, Multiply

Block Particle

File: custom_blockparticle.blockparticle

{
  "Break": {
    "Particle": "MyPlugin/Particles/shatter",
    "Count": 30
  },
  "Step": {
    "Particle": "MyPlugin/Particles/dust",
    "Count": 3
  },
  "Ambient": {
    "Particle": "MyPlugin/Particles/glow",
    "Rate": 1,
    "Radius": 0.5
  }
}

Trails

File: custom_trail.trail

{
  "Texture": "MyPlugin/Textures/trails/slash",
  "Width": 0.5,
  "Length": 10,
  "Lifetime": 0.3,
  "Color": {
    "Start": { "R": 1.0, "G": 1.0, "B": 1.0, "A": 1.0 },
    "End": { "R": 1.0, "G": 1.0, "B": 1.0, "A": 0.0 }
  },
  "BlendMode": "Additive",
  "AttachPoint": "weapon_tip"
}

Asset Inheritance

Assets can inherit from parents:

{
  "Parent": "Hytale:Stone",
  "DisplayName": { "en-US": "Enchanted Stone" },
  "LightLevel": 5
}

Inheritance Rules

  1. Child inherits all parent properties
  2. Child can override any property
  3. Nested objects merge (not replace)
  4. Arrays replace (not merge)

Asset Tags

Categorize assets with tags:

{
  "Tags": {
    "Category": ["Building", "Decorative"],
    "Material": ["Stone"],
    "Origin": ["Natural", "Cave"]
  }
}

Tag Queries

Used in spawning, loot tables, etc.:

{
  "Blocks": {
    "MatchAll": ["Material:Stone"],
    "MatchAny": ["Category:Natural", "Origin:Cave"],
    "Exclude": ["Category:Artificial"]
  }
}

Localization

File: lang/en-US.json

{
  "item.myPlugin.customItem.name": "Custom Item",
  "item.myPlugin.customItem.description": "A special custom item",
  "block.myPlugin.customBlock.name": "Custom Block",
  "entity.myPlugin.customEntity.name": "Custom Creature"
}

Localization Keys

Pattern Example
item.{plugin}.{id}.name item.myPlugin.sword.name
block.{plugin}.{id}.name block.myPlugin.ore.name
entity.{plugin}.{id}.name entity.myPlugin.mob.name
ui.{plugin}.{key} ui.myPlugin.menuTitle

Registering Assets in Plugin

@Override
protected void setup() {
    // Asset pack is auto-registered if manifest.json has:
    // "IncludesAssetPack": true
    
    // Listen for asset loading
    getEventRegistry().register(
        LoadedAssetsEvent.class,
        BlockType.class,
        this::onBlockTypesLoaded
    );
    
    getEventRegistry().register(
        LoadedAssetsEvent.class,
        Item.class,
        this::onItemsLoaded
    );
}

private void onBlockTypesLoaded(LoadedAssetsEvent<BlockType> event) {
    // Access loaded block types
    for (BlockType block : event.getLoadedAssets()) {
        getLogger().atInfo().log("Loaded block: %s", block.getId());
    }
}

Hot Reloading

Assets support hot-reload during development:

/reload assets

Listen for reload events:

getEventRegistry().register(
    AssetStoreMonitorEvent.class,
    this::onAssetReload
);

private void onAssetReload(AssetStoreMonitorEvent event) {
    if (event.getAssetStore().getAssetClass() == BlockType.class) {
        getLogger().atInfo().log("Block types reloaded");
        // Re-initialize dependent systems
    }
}

Custom Asset Store

Register entirely new asset types:

public class MyCustomAsset implements JsonAssetWithMap<String, DefaultAssetMap<String, MyCustomAsset>> {
    public static final AssetBuilderCodec<String, MyCustomAsset> CODEC = 
        AssetBuilderCodec.builder(MyCustomAsset.class, "MyCustomAsset")
            .appendRequired(Codec.STRING.fieldOf("Name"), MyCustomAsset::getName, (a, v) -> a.name = v)
            .appendOptional(Codec.INT.fieldOf("Value"), MyCustomAsset::getValue, (a, v) -> a.value = v, 0)
            .build();
    
    private String id;
    private String name;
    private int value;
    
    @Override
    public String getId() { return id; }
    public String getName() { return name; }
    public int getValue() { return value; }
}

// Register in plugin
@Override
protected void setup() {
    HytaleAssetStore<String, MyCustomAsset, DefaultAssetMap<String, MyCustomAsset>> store = 
        new HytaleAssetStore<>(
            MyCustomAsset.class,
            "MyCustomAssets",      // Directory name
            ".mycustomasset",      // File extension
            MyCustomAsset.CODEC,
            DefaultAssetMap::new
        );
    
    getAssetRegistry().register(store);
}

Troubleshooting

Textures Not Loading

  1. Check file path matches reference
  2. Verify PNG format and dimensions
  3. Ensure pack.json is valid
  4. Check console for loading errors

Models Not Displaying

  1. Verify model JSON syntax
  2. Check texture references exist
  3. Ensure bone hierarchy is valid
  4. Test with simpler model first

Sounds Not Playing

  1. Check OGG/WAV format compatibility
  2. Verify sound event references
  3. Check volume and category settings
  4. Ensure sound files exist at path

Asset Inheritance Not Working

  1. Verify Parent path is correct
  2. Check parent asset loads first
  3. Ensure pack dependencies are set

See references/asset-formats.md for detailed format specs. See references/texture-specs.md for texture requirements.

Weekly Installs
3
Repository
smithery/ai
First Seen
3 days ago
Installed on
codex3