mirror of
https://github.com/storytold/storyteller-bevy.git
synced 2026-10-21 07:55:55 +00:00
Scene storage backend integration (#51)
This PR adds Storyteller.ai API integration for saving and loading Storyteller Studio scenes to/from the backend. ### Known issues * The skybox is not currently stored in the serialized scene format
This commit is contained in:
+56
-8
@@ -13,7 +13,10 @@ use bevy::{
|
||||
scene::InstanceId,
|
||||
};
|
||||
|
||||
use space_editor::{prelude::PrefabMarker, space_prefab::component::SceneAutoChild};
|
||||
use space_editor::{
|
||||
prelude::{EditorEvent, EditorPrefabPath, PrefabMarker},
|
||||
space_prefab::component::SceneAutoChild,
|
||||
};
|
||||
#[cfg(feature = "wasm")]
|
||||
use wasm_bindgen::prelude::wasm_bindgen;
|
||||
use wgpu::{TextureDescriptor, TextureUsages};
|
||||
@@ -37,6 +40,7 @@ impl Plugin for ScenePlugin {
|
||||
app.insert_resource(ClearColor(Color::hsl(0.0, 0.0, 0.25)))
|
||||
.insert_resource(Msaa::Off)
|
||||
.add_state::<SceneState>()
|
||||
.add_event::<LoadLibraryObjectEvent>()
|
||||
.add_event::<LoadSceneEvent>()
|
||||
.add_systems(
|
||||
Startup,
|
||||
@@ -45,7 +49,10 @@ impl Plugin for ScenePlugin {
|
||||
initialiaze_headless.run_if(is_headless),
|
||||
),
|
||||
)
|
||||
.add_systems(Update, init_scene_loading.in_set(SceneSpawnerSystem))
|
||||
.add_systems(
|
||||
Update,
|
||||
(init_object_loading, init_scene_loading).in_set(SceneSpawnerSystem),
|
||||
)
|
||||
.add_systems(
|
||||
OnEnter(SceneState::Active),
|
||||
(
|
||||
@@ -78,7 +85,7 @@ impl Plugin for ScenePlugin {
|
||||
app.add_systems(
|
||||
Update,
|
||||
(
|
||||
wasm::dispatch_scene_request,
|
||||
wasm::dispatch_object_load_request,
|
||||
wasm::notify_state_changes
|
||||
.map(bevy::utils::error)
|
||||
.run_if(resource_changed::<State<SceneState>>()),
|
||||
@@ -172,6 +179,33 @@ fn auto_add_handle<T: Asset>(
|
||||
}
|
||||
}
|
||||
|
||||
/// Request the application to load a `gltf`/`glb` scene from the "bundled"
|
||||
/// asset library in `assets/gltf/`. Expects a filename including the extension.
|
||||
///
|
||||
/// ```ignore
|
||||
/// fn main() {
|
||||
/// App::new()
|
||||
/// .add_plugins((
|
||||
/// DefaultPlugins,
|
||||
/// CommonPlugins,
|
||||
/// ))
|
||||
/// .add_systems(Startup, load_mannequin)
|
||||
/// }
|
||||
///
|
||||
/// fn load_mannequin(mut ew_load_object: EventWriter<LoadLibraryObjectEvent>) {
|
||||
/// ew_load_object.send(LoadLibraryObjectEvent("Mannequin.gltf".into()));
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Event, Deref)]
|
||||
pub struct LoadLibraryObjectEvent(pub String);
|
||||
|
||||
/// Request the application to load a previously saved `*.scn.ron` dynamic scene
|
||||
/// file.
|
||||
///
|
||||
/// Expects a full, resolvable path to the file (e.g. `scenes/my-scene.scn.ron`
|
||||
/// for a local file saved under `studio/assets/scenes`, or
|
||||
/// `remote://<media_token>.scn.ron` for a scene saved to the Storyteller.ai
|
||||
/// backend).
|
||||
#[derive(Event, Deref)]
|
||||
pub struct LoadSceneEvent(pub String);
|
||||
|
||||
@@ -270,9 +304,9 @@ fn initialiaze_headless(
|
||||
));
|
||||
}
|
||||
|
||||
fn init_scene_loading(mut cmd: Commands, mut er: EventReader<LoadSceneEvent>) {
|
||||
fn init_object_loading(mut cmd: Commands, mut er: EventReader<LoadLibraryObjectEvent>) {
|
||||
if let Some(id) = er.read().last() {
|
||||
info!("Loading scene: {}", id.0);
|
||||
info!("Loading library asset: {}", id.0);
|
||||
cmd.spawn((
|
||||
SpatialBundle::default(),
|
||||
space_editor::prelude::GltfPrefab {
|
||||
@@ -285,6 +319,18 @@ fn init_scene_loading(mut cmd: Commands, mut er: EventReader<LoadSceneEvent>) {
|
||||
}
|
||||
}
|
||||
|
||||
fn init_scene_loading(
|
||||
mut er_load_scene: EventReader<LoadSceneEvent>,
|
||||
mut ew_editor: EventWriter<EditorEvent>,
|
||||
) {
|
||||
if let Some(scene_path) = er_load_scene.read().last() {
|
||||
info!("Loading scene: {}", scene_path.0);
|
||||
ew_editor.send(EditorEvent::Load(EditorPrefabPath::File(
|
||||
scene_path.0.clone(),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct NoMeshElement;
|
||||
|
||||
@@ -442,7 +488,7 @@ mod wasm {
|
||||
use bevy::{prelude::*, window::PrimaryWindow};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use super::{LoadSceneEvent, SceneState};
|
||||
use super::{LoadLibraryObjectEvent, SceneState};
|
||||
use crate::wasm::{self, StaticBuffer, WasmMessageBuffer};
|
||||
|
||||
static OBJECT_LOAD_REQUEST: WasmMessageBuffer<String> = WasmMessageBuffer::new();
|
||||
@@ -454,9 +500,11 @@ mod wasm {
|
||||
|
||||
// FIXME: Is it an object or a scene? Inconsistent terminology is
|
||||
// unnecessarily confusing
|
||||
pub(super) fn dispatch_scene_request(mut ew_load_scene: EventWriter<LoadSceneEvent>) {
|
||||
pub(super) fn dispatch_object_load_request(
|
||||
mut ew_load_scene: EventWriter<LoadLibraryObjectEvent>,
|
||||
) {
|
||||
if let Some(id) = OBJECT_LOAD_REQUEST.take_message() {
|
||||
ew_load_scene.send(LoadSceneEvent(id));
|
||||
ew_load_scene.send(LoadLibraryObjectEvent(id));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user