Create an early scripting engine #2
|
@ -319,12 +319,6 @@ version = "1.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "atomicell"
|
|
||||||
version = "0.1.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "157342dd84c64f16899b4b16c1fb2cce54b887990362aac3c590b3d13810890f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -690,42 +684,6 @@ version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "edict"
|
|
||||||
version = "0.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d85bf7cde5687ce04b093bfe183453fa12996b6bdfd2567a0262ebd621761d77"
|
|
||||||
dependencies = [
|
|
||||||
"atomicell",
|
|
||||||
"edict-proc",
|
|
||||||
"hashbrown 0.13.2",
|
|
||||||
"parking_lot",
|
|
||||||
"smallvec",
|
|
||||||
"tiny-fn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "edict-proc"
|
|
||||||
version = "0.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c94d80dc0f05250a9082bb9455bbf3d6c6c51db388b060df914aebcfb4a9b9f1"
|
|
||||||
dependencies = [
|
|
||||||
"edict-proc-lib",
|
|
||||||
"syn 2.0.48",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "edict-proc-lib"
|
|
||||||
version = "0.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "52d98f9931a4f71c7eb7d85cf4ef1271b27014625c85a65376a52c10ac4ffaea"
|
|
||||||
dependencies = [
|
|
||||||
"proc-easy",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.48",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.9.0"
|
version = "1.9.0"
|
||||||
|
@ -1149,15 +1107,6 @@ version = "0.12.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hashbrown"
|
|
||||||
version = "0.13.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
|
|
||||||
dependencies = [
|
|
||||||
"ahash",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.14.3"
|
version = "0.14.3"
|
||||||
|
@ -1504,8 +1453,10 @@ dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"lyra-ecs-derive",
|
"lyra-ecs-derive",
|
||||||
"lyra-math",
|
"lyra-math",
|
||||||
|
"paste",
|
||||||
"rand",
|
"rand",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
"unique",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1569,6 +1520,7 @@ dependencies = [
|
||||||
"lyra-ecs",
|
"lyra-ecs",
|
||||||
"lyra-math",
|
"lyra-math",
|
||||||
"lyra-reflect-derive",
|
"lyra-reflect-derive",
|
||||||
|
"lyra-resource",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1587,11 +1539,11 @@ dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64 0.21.5",
|
"base64 0.21.5",
|
||||||
"crossbeam",
|
"crossbeam",
|
||||||
"edict",
|
|
||||||
"glam",
|
"glam",
|
||||||
"gltf",
|
"gltf",
|
||||||
"image",
|
"image",
|
||||||
"infer",
|
"infer",
|
||||||
|
"lyra-ecs",
|
||||||
"mime",
|
"mime",
|
||||||
"notify",
|
"notify",
|
||||||
"notify-debouncer-full",
|
"notify-debouncer-full",
|
||||||
|
@ -2035,6 +1987,12 @@ dependencies = [
|
||||||
"windows-targets 0.48.5",
|
"windows-targets 0.48.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "paste"
|
||||||
|
version = "1.0.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.3.1"
|
version = "2.3.1"
|
||||||
|
@ -2125,17 +2083,6 @@ version = "0.2.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-easy"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ea59c637cd0e6b71ae18e589854e9de9b7cb17fefdbf2047e42bd38e24285b19"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.48",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-crate"
|
name = "proc-macro-crate"
|
||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
|
@ -2595,12 +2542,6 @@ dependencies = [
|
||||||
"time-core",
|
"time-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tiny-fn"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "af7b2c33e09916c65a15c92c1e583946052527e06102689ed11c6125f64fa8ba"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tiny-skia"
|
name = "tiny-skia"
|
||||||
version = "0.8.4"
|
version = "0.8.4"
|
||||||
|
@ -2747,6 +2688,12 @@ version = "0.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unique"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d360722e1f3884f5b14d332185f02ff111f771f0c76a313268fe6af1409aba96"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "urlencoding"
|
name = "urlencoding"
|
||||||
version = "2.1.3"
|
version = "2.1.3"
|
||||||
|
|
|
@ -37,7 +37,7 @@ pub struct DeltaTimePlugin;
|
||||||
|
|
||||||
impl Plugin for DeltaTimePlugin {
|
impl Plugin for DeltaTimePlugin {
|
||||||
fn setup(&self, game: &mut crate::game::Game) {
|
fn setup(&self, game: &mut crate::game::Game) {
|
||||||
game.world().add_resource(DeltaTime(0.0, None));
|
game.world_mut().add_resource(DeltaTime(0.0, None));
|
||||||
game.add_system_to_stage(GameStages::First, "delta_time", delta_time_system, &[]);
|
game.add_system_to_stage(GameStages::First, "delta_time", delta_time_system, &[]);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -78,6 +78,6 @@ pub struct EventsPlugin;
|
||||||
|
|
||||||
impl Plugin for EventsPlugin {
|
impl Plugin for EventsPlugin {
|
||||||
fn setup(&self, game: &mut crate::game::Game) {
|
fn setup(&self, game: &mut crate::game::Game) {
|
||||||
game.world().add_resource(EventQueue::new());
|
game.world_mut().add_resource(EventQueue::new());
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -246,11 +246,17 @@ impl Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the world of this game
|
/// Get the world of this game
|
||||||
pub fn world(&mut self) -> &mut World {
|
pub fn world_mut(&mut self) -> &mut World {
|
||||||
// world is always `Some`, so unwrapping is safe
|
// world is always `Some`, so unwrapping is safe
|
||||||
self.world.as_mut().unwrap()
|
self.world.as_mut().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the world of this game
|
||||||
|
pub fn world(&self) -> &World {
|
||||||
|
// world is always `Some`, so unwrapping is safe
|
||||||
|
self.world.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
/// Add a system to the ecs world
|
/// Add a system to the ecs world
|
||||||
pub fn with_system<S, A>(&mut self, name: &str, system: S, depends: &[&str]) -> &mut Self
|
pub fn with_system<S, A>(&mut self, name: &str, system: S, depends: &[&str]) -> &mut Self
|
||||||
where
|
where
|
||||||
|
|
|
@ -120,6 +120,10 @@ impl crate::ecs::system::System for InputSystem {
|
||||||
fn world_access(&self) -> lyra_ecs::Access {
|
fn world_access(&self) -> lyra_ecs::Access {
|
||||||
lyra_ecs::Access::Write
|
lyra_ecs::Access::Write
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn execute_deferred(&mut self, _: NonNull<World>) -> anyhow::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoSystem<()> for InputSystem {
|
impl IntoSystem<()> for InputSystem {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use lyra_ecs::Commands;
|
||||||
use lyra_resource::ResourceManager;
|
use lyra_resource::ResourceManager;
|
||||||
|
|
||||||
use crate::EventsPlugin;
|
use crate::EventsPlugin;
|
||||||
|
@ -98,7 +99,7 @@ pub struct ResourceManagerPlugin;
|
||||||
|
|
||||||
impl Plugin for ResourceManagerPlugin {
|
impl Plugin for ResourceManagerPlugin {
|
||||||
fn setup(&self, game: &mut Game) {
|
fn setup(&self, game: &mut Game) {
|
||||||
game.world().add_resource(ResourceManager::new());
|
game.world_mut().add_resource(ResourceManager::new());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -373,7 +373,7 @@ impl Plugin for WindowPlugin {
|
||||||
fn setup(&self, game: &mut crate::game::Game) {
|
fn setup(&self, game: &mut crate::game::Game) {
|
||||||
let window_options = WindowOptions::default();
|
let window_options = WindowOptions::default();
|
||||||
|
|
||||||
game.world().add_resource(Ct::new(window_options));
|
game.world_mut().add_resource(Ct::new(window_options));
|
||||||
game.with_system("window_updater", window_updater_system, &[]);
|
game.with_system("window_updater", window_updater_system, &[]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
use lyra_ecs::Component;
|
use lyra_ecs::Component;
|
||||||
|
use lyra_reflect::Reflect;
|
||||||
use lyra_resource::ResHandle;
|
use lyra_resource::ResHandle;
|
||||||
|
|
||||||
use crate::assets::Model;
|
use crate::assets::Model;
|
||||||
|
|
||||||
#[derive(Clone, Component)]
|
#[derive(Clone, Component, Reflect)]
|
||||||
pub struct ModelComponent(pub ResHandle<Model>);
|
pub struct ModelComponent(#[reflect(skip)] pub ResHandle<Model>);
|
||||||
|
|
||||||
impl From<ResHandle<Model>> for ModelComponent {
|
impl From<ResHandle<Model>> for ModelComponent {
|
||||||
fn from(value: ResHandle<Model>) -> Self {
|
fn from(value: ResHandle<Model>) -> Self {
|
||||||
|
|
|
@ -9,7 +9,9 @@ pub enum StagedExecutorError {
|
||||||
#[error("[stage={0}] could not find a system's dependency named `{1}`")]
|
#[error("[stage={0}] could not find a system's dependency named `{1}`")]
|
||||||
MissingSystem(String, String),
|
MissingSystem(String, String),
|
||||||
#[error("[stage={0}] system `{1}` returned with an error: `{2}`")]
|
#[error("[stage={0}] system `{1}` returned with an error: `{2}`")]
|
||||||
SystemError(String, String, anyhow::Error)
|
SystemError(String, String, anyhow::Error),
|
||||||
|
#[error("[stage={0}] a command returned with an error: `{1}`")]
|
||||||
|
CommandError(String, anyhow::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StagedExecutorError {
|
impl StagedExecutorError {
|
||||||
|
@ -17,6 +19,7 @@ impl StagedExecutorError {
|
||||||
match value {
|
match value {
|
||||||
GraphExecutorError::MissingSystem(s) => Self::MissingSystem(stage, s),
|
GraphExecutorError::MissingSystem(s) => Self::MissingSystem(stage, s),
|
||||||
GraphExecutorError::SystemError(s, e) => Self::SystemError(stage, s, e),
|
GraphExecutorError::SystemError(s, e) => Self::SystemError(stage, s, e),
|
||||||
|
GraphExecutorError::Command(e) => Self::CommandError(stage, e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,10 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
lyra-ecs = { path = "../lyra-ecs" }
|
||||||
anyhow = "1.0.75"
|
anyhow = "1.0.75"
|
||||||
base64 = "0.21.4"
|
base64 = "0.21.4"
|
||||||
crossbeam = { version = "0.8.4", features = [ "crossbeam-channel" ] }
|
crossbeam = { version = "0.8.4", features = [ "crossbeam-channel" ] }
|
||||||
edict = "0.5.0"
|
|
||||||
glam = "0.24.1"
|
glam = "0.24.1"
|
||||||
gltf = { version = "1.3.0", features = ["KHR_materials_pbrSpecularGlossiness", "KHR_materials_specular"] }
|
gltf = { version = "1.3.0", features = ["KHR_materials_pbrSpecularGlossiness", "KHR_materials_specular"] }
|
||||||
image = "0.24.7"
|
image = "0.24.7"
|
||||||
|
|
|
@ -16,7 +16,17 @@ pub use model::*;
|
||||||
pub mod material;
|
pub mod material;
|
||||||
pub use material::*;
|
pub use material::*;
|
||||||
|
|
||||||
|
pub mod world_ext;
|
||||||
|
pub use world_ext::*;
|
||||||
|
|
||||||
pub(crate) mod util;
|
pub(crate) mod util;
|
||||||
|
|
||||||
pub use crossbeam::channel as channel;
|
pub use crossbeam::channel as channel;
|
||||||
pub use notify;
|
pub use notify;
|
||||||
|
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
pub(crate) mod lyra_engine {
|
||||||
|
pub(crate) mod ecs {
|
||||||
|
pub use lyra_ecs::*;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::Material;
|
use crate::Material;
|
||||||
|
use crate::lyra_engine;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
@ -81,7 +82,7 @@ pub enum MeshVertexAttribute {
|
||||||
Other(String),
|
Other(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, edict::Component)]
|
#[derive(Clone, lyra_ecs::Component)]
|
||||||
pub struct Mesh {
|
pub struct Mesh {
|
||||||
pub uuid: uuid::Uuid,
|
pub uuid: uuid::Uuid,
|
||||||
pub attributes: HashMap<MeshVertexAttribute, VertexAttributeData>,
|
pub attributes: HashMap<MeshVertexAttribute, VertexAttributeData>,
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
use std::sync::{Arc, RwLock};
|
use std::{any::Any, sync::{Arc, RwLock}};
|
||||||
|
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use crate::ResourceStorage;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum ResourceState {
|
pub enum ResourceState {
|
||||||
Loading,
|
Loading,
|
||||||
|
@ -21,7 +23,7 @@ impl<'a, T> std::ops::Deref for ResourceDataRef<'a, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct Resource<T> {
|
pub struct Resource<T> {
|
||||||
path: String,
|
path: String,
|
||||||
pub(crate) data: Option<T>,
|
pub(crate) data: Option<T>,
|
||||||
pub(crate) version: usize,
|
pub(crate) version: usize,
|
||||||
|
@ -122,34 +124,51 @@ impl<T> ResHandle<T> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/* /// Get a reference to the data in the resource
|
|
||||||
///
|
impl<T: Send + Sync + 'static> ResourceStorage for ResHandle<T> {
|
||||||
/// # Panics
|
fn as_any(&self) -> &dyn Any {
|
||||||
/// Panics if the resource was not loaded yet.
|
self
|
||||||
pub fn data_ref(&self) -> &T {
|
}
|
||||||
self.data.as_ref()
|
|
||||||
.expect("Resource is not loaded yet (use try_data_ref, or wait until its loaded)!")
|
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||||
}
|
self
|
||||||
|
}
|
||||||
/// If the resource is loaded, returns `Some` reference to the data in the resource,
|
|
||||||
/// else it will return `None`
|
fn as_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
|
||||||
pub fn try_data_ref(&self) -> Option<&T> {
|
self.clone()
|
||||||
self.data.as_ref()
|
}
|
||||||
}
|
|
||||||
|
fn as_box_any(self: Box<Self>) -> Box<dyn Any + Send + Sync> {
|
||||||
/// Get a **mutable** reference to the data in the resource
|
self
|
||||||
///
|
}
|
||||||
/// # Panics
|
|
||||||
/// Panics if the resource was not loaded yet.
|
fn set_watched(&self, watched: bool) {
|
||||||
pub fn data_mut(&mut self) -> &mut T {
|
let mut w = self.data.write().unwrap();
|
||||||
self.data.as_mut()
|
w.is_watched = watched;
|
||||||
.expect("Resource is not loaded yet (use try_data_ref, or wait until its loaded)!")
|
}
|
||||||
}
|
|
||||||
|
fn path(&self) -> String {
|
||||||
/// If the resource is loaded, returns `Some` **mutable** reference to the data in the resource,
|
self.path()
|
||||||
/// else it will return `None`
|
}
|
||||||
pub fn try_data_mut(&mut self) -> Option<&mut T> {
|
|
||||||
self.data.as_mut()
|
fn version(&self) -> usize {
|
||||||
} */
|
self.version()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn state(&self) -> ResourceState {
|
||||||
|
self.state()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn uuid(&self) -> Uuid {
|
||||||
|
self.uuid()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_watched(&self) -> bool {
|
||||||
|
self.is_watched()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_loaded(&self) -> bool {
|
||||||
|
self.is_loaded()
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -4,39 +4,27 @@ use crossbeam::channel::Receiver;
|
||||||
use notify::{Watcher, RecommendedWatcher};
|
use notify::{Watcher, RecommendedWatcher};
|
||||||
use notify_debouncer_full::{DebouncedEvent, FileIdMap};
|
use notify_debouncer_full::{DebouncedEvent, FileIdMap};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::{resource::ResHandle, loader::{ResourceLoader, LoaderError, image::ImageLoader, model::ModelLoader}};
|
use crate::{loader::{image::ImageLoader, model::ModelLoader, LoaderError, ResourceLoader}, resource::ResHandle, ResourceState};
|
||||||
|
|
||||||
|
/// A trait for type erased storage of a resource.
|
||||||
|
/// Implemented for [`ResHandle<T>`]
|
||||||
pub trait ResourceStorage: Send + Sync + Any + 'static {
|
pub trait ResourceStorage: Send + Sync + Any + 'static {
|
||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||||
fn as_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
|
fn as_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
|
||||||
fn as_box_any(self: Box<Self>) -> Box<dyn Any + Send + Sync>;
|
fn as_box_any(self: Box<Self>) -> Box<dyn Any + Send + Sync>;
|
||||||
|
/// Do not set a resource to watched if it is not actually watched.
|
||||||
|
/// This is used internally.
|
||||||
fn set_watched(&self, watched: bool);
|
fn set_watched(&self, watched: bool);
|
||||||
}
|
|
||||||
|
|
||||||
/// Implements this trait for anything that fits the type bounds
|
fn path(&self) -> String;
|
||||||
impl<T: Send + Sync + 'static> ResourceStorage for ResHandle<T> {
|
fn version(&self) -> usize;
|
||||||
fn as_any(&self) -> &dyn Any {
|
fn state(&self) -> ResourceState;
|
||||||
self
|
fn uuid(&self) -> Uuid;
|
||||||
}
|
fn is_watched(&self) -> bool;
|
||||||
|
fn is_loaded(&self) -> bool;
|
||||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
|
|
||||||
self.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_box_any(self: Box<Self>) -> Box<dyn Any + Send + Sync> {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_watched(&self, watched: bool) {
|
|
||||||
let mut w = self.data.write().unwrap();
|
|
||||||
w.is_watched = watched;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
|
@ -131,6 +119,35 @@ impl ResourceManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request a resource without downcasting to a ResHandle<T>.
|
||||||
|
/// Whenever you're ready to downcast, you can do so like this:
|
||||||
|
/// ```compile_fail
|
||||||
|
/// let arc_any = res_arc.as_arc_any();
|
||||||
|
/// let res: Arc<ResHandle<T>> = res.downcast::<ResHandle<T>>().expect("Failure to downcast resource");
|
||||||
|
/// ```
|
||||||
|
pub fn request_raw(&mut self, path: &str) -> Result<Arc<dyn ResourceStorage>, RequestError> {
|
||||||
|
match self.resources.get(&path.to_string()) {
|
||||||
|
Some(res) => {
|
||||||
|
Ok(res.clone())
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
if let Some(loader) = self.loaders.iter()
|
||||||
|
.find(|l| l.does_support_file(path)) {
|
||||||
|
|
||||||
|
// Load the resource and store it
|
||||||
|
let loader = Arc::clone(loader); // stop borrowing from self
|
||||||
|
let res = loader.load(self, path)?;
|
||||||
|
let res: Arc<dyn ResourceStorage> = Arc::from(res);
|
||||||
|
self.resources.insert(path.to_string(), res.clone());
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
} else {
|
||||||
|
Err(RequestError::UnsupportedFileExtension(path.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Store bytes in the manager. If there is already an entry with the same identifier it will be updated.
|
/// Store bytes in the manager. If there is already an entry with the same identifier it will be updated.
|
||||||
///
|
///
|
||||||
/// Panics: If there is already an entry with the same `ident`, and the entry is not bytes, this function will panic.
|
/// Panics: If there is already an entry with the same `ident`, and the entry is not bytes, this function will panic.
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
use std::any::Any;
|
||||||
|
|
||||||
|
use crossbeam::channel::Receiver;
|
||||||
|
use lyra_ecs::World;
|
||||||
|
use notify_debouncer_full::DebouncedEvent;
|
||||||
|
|
||||||
|
use crate::{RequestError, ResHandle, ResourceLoader, ResourceManager};
|
||||||
|
|
||||||
|
pub trait WorldAssetExt {
|
||||||
|
/// Register a resource loader with the resource manager.
|
||||||
|
fn register_res_loader<L>(&mut self)
|
||||||
|
where
|
||||||
|
L: ResourceLoader + Default + 'static;
|
||||||
|
|
||||||
|
/// Request a resource from the resource manager.
|
||||||
|
fn request_res<T>(&mut self, path: &str) -> Result<ResHandle<T>, RequestError>
|
||||||
|
where
|
||||||
|
T: Send + Sync + Any + 'static;
|
||||||
|
|
||||||
|
/// Start watching a resource for changes. Returns a crossbeam channel that can be used to listen for events.
|
||||||
|
fn watch_res(&mut self, path: &str, recursive: bool) -> notify::Result<Receiver<Result<Vec<DebouncedEvent>, Vec<notify::Error>>>>;
|
||||||
|
|
||||||
|
/// Stop watching a resource for changes.
|
||||||
|
fn stop_watching_res(&mut self, path: &str) -> notify::Result<()>;
|
||||||
|
|
||||||
|
/// Try to retrieve a crossbeam channel for a path that is currently watched. Returns None if the path is not watched
|
||||||
|
fn res_watcher_recv(&self, path: &str) -> Option<Receiver<Result<Vec<DebouncedEvent>, Vec<notify::Error>>>>;
|
||||||
|
|
||||||
|
/// Reload a resource. The data will be updated in the handle. This is not
|
||||||
|
/// automatically triggered if the resource is being watched.
|
||||||
|
fn reload_res<T>(&mut self, resource: ResHandle<T>) -> Result<(), RequestError>
|
||||||
|
where
|
||||||
|
T: Send + Sync + Any + 'static;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WorldAssetExt for World {
|
||||||
|
fn register_res_loader<L>(&mut self)
|
||||||
|
where
|
||||||
|
L: ResourceLoader + Default + 'static
|
||||||
|
{
|
||||||
|
let mut man = self.get_resource_or_default::<ResourceManager>();
|
||||||
|
man.register_loader::<L>();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_res<T>(&mut self, path: &str) -> Result<ResHandle<T>, RequestError>
|
||||||
|
where
|
||||||
|
T: Send + Sync + Any + 'static
|
||||||
|
{
|
||||||
|
let mut man = self.get_resource_or_default::<ResourceManager>();
|
||||||
|
man.request(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn watch_res(&mut self, path: &str, recursive: bool) -> notify::Result<Receiver<Result<Vec<DebouncedEvent>, Vec<notify::Error>>>> {
|
||||||
|
let mut man = self.get_resource_or_default::<ResourceManager>();
|
||||||
|
man.watch(path, recursive)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stop_watching_res(&mut self, path: &str) -> notify::Result<()> {
|
||||||
|
let mut man = self.get_resource_or_default::<ResourceManager>();
|
||||||
|
man.stop_watching(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn res_watcher_recv(&self, path: &str) -> Option<Receiver<Result<Vec<DebouncedEvent>, Vec<notify::Error>>>> {
|
||||||
|
let man = self.get_resource::<ResourceManager>();
|
||||||
|
man.watcher_event_recv(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reload_res<T>(&mut self, resource: ResHandle<T>) -> Result<(), RequestError>
|
||||||
|
where
|
||||||
|
T: Send + Sync + Any + 'static
|
||||||
|
{
|
||||||
|
let mut man = self.get_resource_or_default::<ResourceManager>();
|
||||||
|
man.reload(resource)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue