Custom Asset

(Rodrigo Oliveira) #1

Hey I’m creating a script type of asset, but I think I’m missing something.

formats.rs

use amethyst_assets::*;
use amethyst_error::Error;

use serde::{Deserialize, Serialize};


#[derive(Clone, Debug)]
pub struct ScriptData(pub Vec<u8>);
amethyst_assets::register_format_type!(ScriptData);

#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)]
pub struct LuaFormat;
amethyst_assets::register_format!("lua", LuaFormat as ScriptData);

impl Format<ScriptData> for LuaFormat {
    fn name(&self) -> &'static str {
        "lua"
    }

    fn import_simple(&self, bytes: Vec<u8>) -> Result<ScriptData, Error> {
        Ok(ScriptData(bytes))
    }
}


asset.rs

//! Provides structures used to load script files.
//!
use amethyst_assets::{
    Asset, AssetStorage, Handle, Loader, ProcessableAsset, ProcessingState,
};
use amethyst_core::ecs::prelude::VecStorage;
use amethyst_error::Error;

use std::string::FromUtf8Error;

use crate::formats::ScriptData;

// Hold a reference to a script asset loaded
pub type ScriptHandle = Handle<Script>;

#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct Script {
    pub bytes: Vec<u8>,
}

impl Script {
    pub fn to_string(self) -> Result<String, std::string::FromUtf8Error> {
        match String::from_utf8(self.bytes) {
            Ok(utf8_str) => Ok(String::from(utf8_str)),
            Err(error) => Err(error)
        }
    }
}

impl Asset for Script {
    const NAME: &'static str = "script::Script";

    type Data = ScriptData;
    type HandleStorage = VecStorage<ScriptHandle>;

}

impl ProcessableAsset for Script {
    fn process(data: ScriptData) -> Result<ProcessingState<Script>, Error> {
        Ok(ProcessingState::Loaded(Script { bytes: data.0 }))
    }
}

main.rs

fn load_script(world: &mut World) -> Handle<ScriptAsset> {

    let loader = world.read_resource::<Loader>();
    let script_storage = world.read_resource::<AssetStorage<ScriptAsset>>();
    
    loader.load(
        "scripts/lua/pong.lua",
        LuaFormat::default(),
        (),
        &script_storage,
    )
}

#[derive(Default)]
pub struct Pong;

impl SimpleState for Pong {
    fn on_start(&mut self, data: StateData<'_, GameData<'_, '_>>) {
        let world = data.world;        
        let script_handle = load_script(world);
        
        let storage = data.world.read_resource::<AssetStorage<ScriptAsset>>();
        for sh in [&script_handle].iter() {
            if let Some(s) = sh.as_ref().and_then(|sh| storage.get(sh)){
                println!("{}", s.clone().to_string().unwrap());
            }else{
                println!("nothing");
            }
        }

This always print “nothing” but the script is in the path. Am I missing something here?

1 Like
(Azriel Hoh) #2

Heya, gotta change at least one thing, maybe two:

  1. loader.load(..) will return immediately with the Handle (which you can store), but the actual asset will not be loaded until the State::update function is run (specifically state_data.game_data.update(&mut state_data.world)). It may take a few State::update calls to load the asset, since it loads it asynchronously with a thread pool.
  2. Make sure you’ve got Processor::<ScriptData>::new() as a system in main.rsgame_data.with(Processor::<ScriptData>>new(), "script_data_processor", &[]).
(Rodrigo Oliveira) #3

Thank you, placing

let storage = data.world.read_resource::<AssetStorage<ScriptAsset>>();
        for sh in [&script_handle].iter() {
            if let Some(s) = sh.as_ref().and_then(|sh| storage.get(sh)){
                println!("{}", s.clone().to_string().unwrap());
            }else{
                println!("nothing");
            }
        }

in update function and calling data.data.update(&mut data.world) worked!