mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'christof/hot-reload-fix' into 'master'
Fix hot reloading for plugin combined manifests See merge request veloren/veloren!4280
This commit is contained in:
commit
eaba303670
@ -2,7 +2,6 @@
|
||||
//! Load assets (images or voxel data) from files
|
||||
|
||||
#[cfg(feature = "plugins")]
|
||||
use assets_manager::SharedBytes;
|
||||
use dot_vox::DotVoxData;
|
||||
use image::DynamicImage;
|
||||
use lazy_static::lazy_static;
|
||||
@ -122,19 +121,37 @@ pub trait AssetExt: Sized + Send + Sync + 'static {
|
||||
}
|
||||
|
||||
/// Extension to AssetExt to combine Ron files from filesystem and plugins
|
||||
#[cfg(feature = "plugins")]
|
||||
pub trait AssetCombined: AssetExt {
|
||||
fn load_and_combine(specifier: &str) -> Result<AssetHandle<Self>, BoxedError>;
|
||||
fn load_and_combine(
|
||||
reloading_cache: AnyCache<'static>,
|
||||
specifier: &str,
|
||||
) -> Result<AssetHandle<Self>, Error>;
|
||||
|
||||
/// Load combined table without hot-reload support
|
||||
fn load_and_combine_static(specifier: &str) -> Result<AssetHandle<Self>, Error> {
|
||||
Self::load_and_combine(ASSETS.non_reloading_cache(), specifier)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn load_expect_combined(specifier: &str) -> AssetHandle<Self> {
|
||||
fn load_expect_combined(
|
||||
reloading_cache: AnyCache<'static>,
|
||||
specifier: &str,
|
||||
) -> AssetHandle<Self> {
|
||||
// Avoid using `unwrap_or_else` to avoid breaking `#[track_caller]`
|
||||
match Self::load_and_combine(specifier) {
|
||||
match Self::load_and_combine(reloading_cache, specifier) {
|
||||
Ok(handle) => handle,
|
||||
Err(err) => {
|
||||
panic!("Failed loading essential combined asset: {specifier} (error={err:?})")
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Load combined table without hot-reload support, panic on error
|
||||
#[track_caller]
|
||||
fn load_expect_combined_static(specifier: &str) -> AssetHandle<Self> {
|
||||
Self::load_expect_combined(ASSETS.non_reloading_cache(), specifier)
|
||||
}
|
||||
}
|
||||
|
||||
/// Extension to AnyCache to combine Ron files from filesystem and plugins
|
||||
@ -142,7 +159,7 @@ pub trait CacheCombined<'a> {
|
||||
fn load_and_combine<A: Compound + Concatenate>(
|
||||
self,
|
||||
id: &str,
|
||||
) -> Result<&'a assets_manager::Handle<A>, BoxedError>;
|
||||
) -> Result<&'a assets_manager::Handle<A>, Error>;
|
||||
}
|
||||
|
||||
/// Loads directory and all files in it
|
||||
@ -172,32 +189,28 @@ impl<'a> CacheCombined<'a> for AnyCache<'a> {
|
||||
fn load_and_combine<A: Compound + Concatenate>(
|
||||
self,
|
||||
specifier: &str,
|
||||
) -> Result<&'a assets_manager::Handle<A>, BoxedError> {
|
||||
) -> Result<&'a assets_manager::Handle<A>, Error> {
|
||||
#[cfg(feature = "plugins")]
|
||||
{
|
||||
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))
|
||||
},
|
||||
Ok,
|
||||
)
|
||||
tracing::info!("combine {specifier}");
|
||||
let data: Result<A, _> =
|
||||
ASSETS.combine(self, |cache: AnyCache| cache.load_owned::<A>(specifier));
|
||||
data.map(|data| self.get_or_insert(specifier, data))
|
||||
}
|
||||
#[cfg(not(feature = "plugins"))]
|
||||
{
|
||||
Ok(self.load(specifier)?)
|
||||
self.load(specifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "plugins")]
|
||||
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)
|
||||
fn load_and_combine(
|
||||
reloading_cache: AnyCache<'static>,
|
||||
specifier: &str,
|
||||
) -> Result<AssetHandle<Self>, Error> {
|
||||
reloading_cache.load_and_combine(specifier)
|
||||
}
|
||||
}
|
||||
|
||||
@ -223,9 +236,11 @@ impl Asset for Image {
|
||||
const EXTENSIONS: &'static [&'static str] = &["png", "jpg"];
|
||||
}
|
||||
|
||||
#[cfg(feature = "plugins")]
|
||||
pub struct DotVoxAsset(pub DotVoxData);
|
||||
|
||||
pub struct DotVoxLoader;
|
||||
#[cfg(feature = "plugins")]
|
||||
impl Loader<DotVoxAsset> for DotVoxLoader {
|
||||
fn load(content: Cow<[u8]>, _: &str) -> Result<DotVoxAsset, BoxedError> {
|
||||
let data = dot_vox::load_bytes(&content).map_err(|err| err.to_owned())?;
|
||||
@ -233,6 +248,7 @@ impl Loader<DotVoxAsset> for DotVoxLoader {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "plugins")]
|
||||
impl Asset for DotVoxAsset {
|
||||
type Loader = DotVoxLoader;
|
||||
|
||||
@ -294,10 +310,14 @@ impl<T> Compound for MultiRon<T>
|
||||
where
|
||||
T: for<'de> serde::Deserialize<'de> + Send + Sync + 'static + Concatenate,
|
||||
{
|
||||
fn load(_cache: AnyCache, id: &SharedString) -> Result<Self, BoxedError> {
|
||||
// the passed cache registers with hot reloading
|
||||
fn load(reloading_cache: AnyCache, id: &SharedString) -> Result<Self, BoxedError> {
|
||||
ASSETS
|
||||
.combine(|cache: AnyCache| <Ron<T> as Compound>::load(cache, id).map(|r| r.0))
|
||||
.combine(reloading_cache, |cache: AnyCache| {
|
||||
cache.load_owned::<Ron<T>>(id).map(|ron| ron.into_inner())
|
||||
})
|
||||
.map(MultiRon)
|
||||
.map_err(Into::<BoxedError>::into)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,9 +4,10 @@ use crate::Concatenate;
|
||||
|
||||
use super::{fs::FileSystem, ASSETS_PATH};
|
||||
use assets_manager::{
|
||||
asset::DirLoadable,
|
||||
hot_reloading::EventSender,
|
||||
source::{FileContent, Source, Tar},
|
||||
AnyCache, AssetCache, BoxedError,
|
||||
AnyCache, AssetCache, BoxedError, Compound, Storable,
|
||||
};
|
||||
|
||||
struct PluginEntry {
|
||||
@ -131,18 +132,27 @@ impl CombinedCache {
|
||||
CombinedSource::new().map(|combined_source| Self(AssetCache::with_source(combined_source)))
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
// Provide a cache to the "combine_static" functions as they omit
|
||||
// wrapping in a Compound (which enables hot-reload)
|
||||
pub(crate) fn non_reloading_cache(&self) -> AnyCache<'_> {
|
||||
self.0.raw_source().fs.as_any_cache()
|
||||
}
|
||||
|
||||
/// Combine objects from filesystem and plugins
|
||||
pub fn combine<T: Concatenate>(
|
||||
&self,
|
||||
mut load_from: impl FnMut(AnyCache) -> Result<T, BoxedError>,
|
||||
) -> Result<T, BoxedError> {
|
||||
let mut result = load_from(self.0.raw_source().fs.as_any_cache());
|
||||
// this cache registers with hot reloading
|
||||
reloading_cache: AnyCache,
|
||||
mut load_from: impl FnMut(AnyCache) -> Result<T, assets_manager::Error>,
|
||||
) -> Result<T, assets_manager::Error> {
|
||||
let mut result = load_from(reloading_cache);
|
||||
// Report a severe error from the filesystem asset even if later overwritten by
|
||||
// an Ok value from a plugin
|
||||
if let Err(ref fs_error) = result {
|
||||
match fs_error
|
||||
.source()
|
||||
.and_then(|error_source| error_source.downcast_ref::<std::io::Error>())
|
||||
.reason()
|
||||
.downcast_ref::<std::io::Error>()
|
||||
.map(|io_error| io_error.kind())
|
||||
{
|
||||
Some(std::io::ErrorKind::NotFound) => (),
|
||||
@ -161,8 +171,8 @@ impl CombinedCache {
|
||||
// Report any error other than NotFound
|
||||
Err(plugin_error) => {
|
||||
match plugin_error
|
||||
.source()
|
||||
.and_then(|error_source| error_source.downcast_ref::<std::io::Error>())
|
||||
.reason()
|
||||
.downcast_ref::<std::io::Error>()
|
||||
.map(|io_error| io_error.kind())
|
||||
{
|
||||
Some(std::io::ErrorKind::NotFound) => (),
|
||||
@ -190,11 +200,36 @@ impl CombinedCache {
|
||||
.push(PluginEntry { path, cache });
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Delegate all cache operations directly to the contained cache object
|
||||
impl std::ops::Deref for CombinedCache {
|
||||
type Target = AssetCache<CombinedSource>;
|
||||
// Just forward these methods to the cache
|
||||
#[inline]
|
||||
#[cfg(feature = "hot-reloading")]
|
||||
pub fn enhance_hot_reloading(&'static self) { self.0.enhance_hot_reloading(); }
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.0 }
|
||||
#[inline]
|
||||
pub fn load_rec_dir<A: DirLoadable>(
|
||||
&self,
|
||||
id: &str,
|
||||
) -> Result<&assets_manager::Handle<assets_manager::RecursiveDirectory<A>>, assets_manager::Error>
|
||||
{
|
||||
self.0.load_rec_dir(id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn load<A: Compound>(
|
||||
&self,
|
||||
id: &str,
|
||||
) -> Result<&assets_manager::Handle<A>, assets_manager::Error> {
|
||||
self.0.load(id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_or_insert<A: Storable>(&self, id: &str, a: A) -> &assets_manager::Handle<A> {
|
||||
self.0.get_or_insert(id, a)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn load_owned<A: Compound>(&self, id: &str) -> Result<A, assets_manager::Error> {
|
||||
self.0.load_owned(id)
|
||||
}
|
||||
}
|
||||
|
@ -242,7 +242,7 @@ lazy_static! {
|
||||
};
|
||||
|
||||
pub static ref KITS: Vec<String> = {
|
||||
let mut kits = if let Ok(kits) = KitManifest::load_and_combine(KIT_MANIFEST_PATH) {
|
||||
let mut kits = if let Ok(kits) = KitManifest::load_and_combine_static(KIT_MANIFEST_PATH) {
|
||||
let mut kits = kits.read().0.keys().cloned().collect::<Vec<String>>();
|
||||
kits.sort();
|
||||
kits
|
||||
@ -255,7 +255,7 @@ lazy_static! {
|
||||
};
|
||||
|
||||
static ref PRESETS: HashMap<String, Vec<(Skill, u8)>> = {
|
||||
if let Ok(presets) = SkillPresetManifest::load_and_combine(PRESET_MANIFEST_PATH) {
|
||||
if let Ok(presets) = SkillPresetManifest::load_and_combine_static(PRESET_MANIFEST_PATH) {
|
||||
presets.read().0.clone()
|
||||
} else {
|
||||
warn!("Error while loading presets");
|
||||
@ -1324,12 +1324,12 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_loading_skill_presets() {
|
||||
SkillPresetManifest::load_expect_combined(PRESET_MANIFEST_PATH);
|
||||
SkillPresetManifest::load_expect_combined_static(PRESET_MANIFEST_PATH);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_load_kits() {
|
||||
let kits = KitManifest::load_expect_combined(KIT_MANIFEST_PATH).read();
|
||||
let kits = KitManifest::load_expect_combined_static(KIT_MANIFEST_PATH).read();
|
||||
let mut rng = rand::thread_rng();
|
||||
for kit in kits.0.values() {
|
||||
for (item_id, _) in kit.iter() {
|
||||
|
@ -282,7 +282,7 @@ impl Concatenate for ResourceExperienceManifest {
|
||||
|
||||
lazy_static! {
|
||||
static ref RESOURCE_EXPERIENCE_MANIFEST: assets::AssetHandle<ResourceExperienceManifest> =
|
||||
assets::AssetCombined::load_expect_combined(
|
||||
assets::AssetCombined::load_expect_combined_static(
|
||||
"server.manifests.resource_experience_manifest"
|
||||
);
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ pub struct ItemImgs {
|
||||
|
||||
impl ItemImgs {
|
||||
pub fn new(ui: &mut Ui, not_found: Id) -> Self {
|
||||
let manifest = ItemImagesSpec::load_expect_combined("voxygen.item_image_manifest");
|
||||
let manifest = ItemImagesSpec::load_expect_combined_static("voxygen.item_image_manifest");
|
||||
let map = manifest
|
||||
.read()
|
||||
.0
|
||||
|
Loading…
Reference in New Issue
Block a user