Support recipes and item images from plugins

This commit is contained in:
Christof Petig 2023-10-19 23:56:19 +02:00
parent d690f25615
commit f73f52605f
4 changed files with 71 additions and 5 deletions

View File

@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- New Frost Gigas attacks & AI
- Allow plugins to add weapon and armor items
- New voxelised LoD shader effect
- Allow plugins to add recipes and item images
### Changed

View File

@ -1,6 +1,7 @@
//#![warn(clippy::pedantic)]
//! Load assets (images or voxel data) from files
use assets_manager::SharedBytes;
use dot_vox::DotVoxData;
use image::DynamicImage;
use lazy_static::lazy_static;
@ -120,6 +121,30 @@ pub trait AssetExt: Sized + Send + Sync + 'static {
fn get_or_insert(specifier: &str, default: Self) -> AssetHandle<Self>;
}
/// Extension to AssetExt to combine Ron files from filesystem and plugins
pub trait AssetCombined: AssetExt {
fn load_and_combine(specifier: &str) -> Result<AssetHandle<Self>, BoxedError>;
#[track_caller]
fn load_expect_combined(specifier: &str) -> AssetHandle<Self> {
// Avoid using `unwrap_or_else` to avoid breaking `#[track_caller]`
match Self::load_and_combine(specifier) {
Ok(handle) => handle,
Err(err) => {
panic!("Failed loading essential combined asset: {specifier} (error={err:?})")
},
}
}
}
/// Extension to AnyCache to combine Ron files from filesystem and plugins
pub trait CacheCombined<'a> {
fn load_and_combine<A: Compound + Concatenate>(
self,
id: &str,
) -> Result<assets_manager::Handle<'a, A>, BoxedError>;
}
/// Loads directory and all files in it
///
/// # Errors
@ -173,6 +198,32 @@ impl<T: Compound> AssetExt for T {
}
}
impl<'a> CacheCombined<'a> for AnyCache<'a> {
fn load_and_combine<A: Compound + Concatenate>(
self,
specifier: &str,
) -> Result<assets_manager::Handle<'a, A>, BoxedError> {
self.get_cached(specifier).map_or_else(
|| {
// only create this combined object if is not yet cached
let id_bytes = SharedBytes::from_slice(specifier.as_bytes());
// as it was created from UTF8 it needs to be valid UTF8
let id = SharedString::from_utf8(id_bytes).unwrap();
tracing::info!("combine {specifier}");
let data: Result<A, _> = ASSETS.combine(|cache: AnyCache| A::load(cache, &id));
data.map(|data| self.get_or_insert(specifier, data))
},
|obj| Ok(obj),
)
}
}
impl<T: Compound + Concatenate> AssetCombined for T {
fn load_and_combine(specifier: &str) -> Result<AssetHandle<Self>, BoxedError> {
ASSETS.as_any_cache().load_and_combine(specifier)
}
}
pub struct Image(pub Arc<DynamicImage>);
impl Image {

View File

@ -1,5 +1,5 @@
use crate::{
assets::{self, AssetExt, AssetHandle},
assets::{self, AssetExt, AssetHandle, CacheCombined, Concatenate},
comp::{
inventory::slot::{InvSlotId, Slot},
item::{
@ -504,6 +504,9 @@ impl assets::Asset for RawRecipeBook {
const EXTENSION: &'static str = "ron";
}
impl Concatenate for RawRecipeBook {
fn concatenate(self, b: Self) -> Self { RawRecipeBook(self.0.concatenate(b.0)) }
}
#[derive(Deserialize, Clone)]
struct ItemList(Vec<String>);
@ -513,6 +516,9 @@ impl assets::Asset for ItemList {
const EXTENSION: &'static str = "ron";
}
impl Concatenate for ItemList {
fn concatenate(self, b: Self) -> Self { ItemList(self.0.concatenate(b.0)) }
}
impl assets::Compound for RecipeBook {
fn load(
@ -531,7 +537,7 @@ impl assets::Compound for RecipeBook {
Ok((def, *amount, *is_mod_comp))
}
let raw = cache.load::<RawRecipeBook>(specifier)?.cloned();
let raw = cache.load_and_combine::<RawRecipeBook>(specifier)?.cloned();
let recipes = raw
.0
@ -596,6 +602,9 @@ impl assets::Asset for RawComponentRecipeBook {
const EXTENSION: &'static str = "ron";
}
impl Concatenate for RawComponentRecipeBook {
fn concatenate(self, b: Self) -> Self { RawComponentRecipeBook(self.0.concatenate(b.0)) }
}
#[derive(Clone, Debug, Serialize, Deserialize, Hash, Eq, PartialEq)]
pub struct ComponentKey {
@ -884,7 +893,9 @@ impl assets::Compound for ComponentRecipeBook {
})
}
let raw = cache.load::<RawComponentRecipeBook>(specifier)?.cloned();
let raw = cache
.load_and_combine::<RawComponentRecipeBook>(specifier)?
.cloned();
let recipes = raw
.0

View File

@ -1,6 +1,6 @@
use crate::ui::{Graphic, SampleStrat, Transform, Ui};
use common::{
assets::{self, AssetExt, AssetHandle, DotVoxAsset, ReloadWatcher},
assets::{self, AssetCombined, AssetExt, AssetHandle, Concatenate, DotVoxAsset, ReloadWatcher},
comp::item::item_key::ItemKey,
figure::Segment,
};
@ -62,6 +62,9 @@ impl assets::Asset for ItemImagesSpec {
const EXTENSION: &'static str = "ron";
}
impl Concatenate for ItemImagesSpec {
fn concatenate(self, b: Self) -> Self { ItemImagesSpec(self.0.concatenate(b.0)) }
}
// TODO: when there are more images don't load them all into memory
pub struct ItemImgs {
@ -73,7 +76,7 @@ pub struct ItemImgs {
impl ItemImgs {
pub fn new(ui: &mut Ui, not_found: Id) -> Self {
let manifest = ItemImagesSpec::load_expect("voxygen.item_image_manifest");
let manifest = ItemImagesSpec::load_expect_combined("voxygen.item_image_manifest");
let map = manifest
.read()
.0