Cutscene + Items + Target sync (#64)
This commit is contained in:
@@ -13,13 +13,14 @@ use crate::{
|
|||||||
use avian3d::prelude::*;
|
use avian3d::prelude::*;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use marker::MarkerEvent;
|
use marker::MarkerEvent;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
#[derive(Component, Reflect, Default, Deref)]
|
#[derive(Component, Reflect, Default, Deref, PartialEq, Serialize, Deserialize)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
pub struct AimTarget(pub Option<Entity>);
|
pub struct AimTarget(pub Option<Entity>);
|
||||||
|
|
||||||
#[derive(Component, Reflect)]
|
#[derive(Component, Reflect, PartialEq, Serialize, Deserialize)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
#[require(AimTarget)]
|
#[require(AimTarget)]
|
||||||
pub struct AimState {
|
pub struct AimState {
|
||||||
@@ -39,6 +40,9 @@ impl Default for AimState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
|
app.register_type::<AimState>();
|
||||||
|
app.register_type::<AimTarget>();
|
||||||
|
|
||||||
app.add_plugins(target_ui::plugin);
|
app.add_plugins(target_ui::plugin);
|
||||||
app.add_plugins(marker::plugin);
|
app.add_plugins(marker::plugin);
|
||||||
|
|
||||||
@@ -71,20 +75,20 @@ fn update_player_aim(
|
|||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
potential_targets: Query<(Entity, &Transform), With<Hitpoints>>,
|
potential_targets: Query<(Entity, &Transform), With<Hitpoints>>,
|
||||||
player_rot: Query<(&Transform, &GlobalTransform), With<PlayerBodyMesh>>,
|
player_rot: Query<(&Transform, &GlobalTransform), With<PlayerBodyMesh>>,
|
||||||
mut player_aim: Query<(Entity, &AimState, &mut AimTarget), With<Player>>,
|
mut player_aim: Query<(Entity, &AimState, &mut AimTarget, &Children), With<Player>>,
|
||||||
spatial_query: SpatialQuery,
|
spatial_query: SpatialQuery,
|
||||||
) {
|
) {
|
||||||
let Some((player, state, mut aim_target)) = player_aim.iter_mut().next() else {
|
for (player, state, mut aim_target, children) in player_aim.iter_mut() {
|
||||||
return;
|
assert_eq!(
|
||||||
};
|
children.len(),
|
||||||
|
1,
|
||||||
|
"expected player to have one direct child"
|
||||||
|
);
|
||||||
|
|
||||||
let Some((player_pos, player_forward)) = player_rot
|
let (player_pos, player_forward) = player_rot
|
||||||
.iter()
|
.get(*children.first().unwrap())
|
||||||
.next()
|
|
||||||
.map(|(t, global)| (global.translation(), t.forward()))
|
.map(|(t, global)| (global.translation(), t.forward()))
|
||||||
else {
|
.unwrap();
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut new_target = None;
|
let mut new_target = None;
|
||||||
let mut target_distance = f32::MAX;
|
let mut target_distance = f32::MAX;
|
||||||
@@ -132,6 +136,7 @@ fn update_player_aim(
|
|||||||
aim_target.0 = new_target;
|
aim_target.0 = new_target;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn update_npc_aim(
|
fn update_npc_aim(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
|
|||||||
@@ -6,8 +6,9 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_trenchbroom::prelude::*;
|
use bevy_trenchbroom::prelude::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Event, Debug)]
|
#[derive(Clone, Debug, Event, Serialize, Deserialize)]
|
||||||
pub struct StartCutscene(pub String);
|
pub struct StartCutscene(pub String);
|
||||||
|
|
||||||
#[derive(Resource, Debug, Default)]
|
#[derive(Resource, Debug, Default)]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
GameState, billboards::Billboard, global_observer, heads_database::HeadsDatabase,
|
GameState, billboards::Billboard, global_observer, heads_database::HeadsDatabase,
|
||||||
loading_assets::HeadDropAssets, physics_layers::GameLayer, player::Player, sounds::PlaySound,
|
physics_layers::GameLayer, player::Player, protocol::GltfSceneRoot, sounds::PlaySound,
|
||||||
squish_animation::SquishAnimation, tb_entities::SecretHead,
|
squish_animation::SquishAnimation, tb_entities::SecretHead,
|
||||||
};
|
};
|
||||||
use avian3d::prelude::*;
|
use avian3d::prelude::*;
|
||||||
@@ -8,6 +8,8 @@ use bevy::{
|
|||||||
ecs::{relationship::RelatedSpawner, spawn::SpawnWith},
|
ecs::{relationship::RelatedSpawner, spawn::SpawnWith},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
#[cfg(feature = "server")]
|
||||||
|
use lightyear::prelude::{NetworkTarget, Replicate};
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
#[derive(Event, Reflect)]
|
#[derive(Event, Reflect)]
|
||||||
@@ -77,9 +79,7 @@ fn spawn(mut commands: Commands, query: Query<(Entity, &GlobalTransform, &Secret
|
|||||||
fn on_head_drop(
|
fn on_head_drop(
|
||||||
trigger: Trigger<HeadDrops>,
|
trigger: Trigger<HeadDrops>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
assets: Res<HeadDropAssets>,
|
|
||||||
heads_db: Res<HeadsDatabase>,
|
heads_db: Res<HeadsDatabase>,
|
||||||
gltf_assets: Res<Assets<Gltf>>,
|
|
||||||
time: Res<Time>,
|
time: Res<Time>,
|
||||||
) -> Result<(), BevyError> {
|
) -> Result<(), BevyError> {
|
||||||
let drop = trigger.event();
|
let drop = trigger.event();
|
||||||
@@ -91,13 +91,7 @@ fn on_head_drop(
|
|||||||
commands.trigger(PlaySound::HeadDrop);
|
commands.trigger(PlaySound::HeadDrop);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ability = format!("{:?}.glb", heads_db.head_stats(drop.head_id).ability).to_lowercase();
|
let mesh_addr = format!("{:?}", heads_db.head_stats(drop.head_id).ability).to_lowercase();
|
||||||
let mesh = if let Some(handle) = assets.meshes.get(ability.as_str()) {
|
|
||||||
gltf_assets.get(handle)
|
|
||||||
} else {
|
|
||||||
gltf_assets.get(&assets.meshes["none.glb"])
|
|
||||||
}
|
|
||||||
.ok_or("asset not found")?;
|
|
||||||
|
|
||||||
commands
|
commands
|
||||||
.spawn((
|
.spawn((
|
||||||
@@ -128,6 +122,8 @@ fn on_head_drop(
|
|||||||
.observe(on_collect_head);
|
.observe(on_collect_head);
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
|
#[cfg(feature = "server")]
|
||||||
|
Replicate::to_clients(NetworkTarget::All),
|
||||||
))
|
))
|
||||||
.insert_if(
|
.insert_if(
|
||||||
ExternalImpulse::new(spawn_dir * 180.).with_persistence(false),
|
ExternalImpulse::new(spawn_dir * 180.).with_persistence(false),
|
||||||
@@ -136,7 +132,7 @@ fn on_head_drop(
|
|||||||
.with_child((
|
.with_child((
|
||||||
Billboard::All,
|
Billboard::All,
|
||||||
SquishAnimation(2.6),
|
SquishAnimation(2.6),
|
||||||
SceneRoot(mesh.scenes[0].clone()),
|
GltfSceneRoot::HeadDrop(mesh_addr),
|
||||||
));
|
));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use crate::{
|
|||||||
sounds::PlaySound,
|
sounds::PlaySound,
|
||||||
};
|
};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Event, Reflect)]
|
#[derive(Event, Reflect)]
|
||||||
pub struct Kill;
|
pub struct Kill;
|
||||||
@@ -14,7 +15,7 @@ pub struct Hit {
|
|||||||
pub damage: u32,
|
pub damage: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component, Reflect, Debug, Clone, Copy)]
|
#[derive(Component, Reflect, Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Hitpoints {
|
pub struct Hitpoints {
|
||||||
max: u32,
|
max: u32,
|
||||||
current: u32,
|
current: u32,
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
billboards::Billboard, global_observer, loading_assets::GameAssets, physics_layers::GameLayer,
|
billboards::Billboard, global_observer, physics_layers::GameLayer, player::Player,
|
||||||
player::Player, sounds::PlaySound, squish_animation::SquishAnimation,
|
protocol::GltfSceneRoot, sounds::PlaySound, squish_animation::SquishAnimation,
|
||||||
};
|
};
|
||||||
use avian3d::prelude::*;
|
use avian3d::prelude::*;
|
||||||
use bevy::{
|
use bevy::{
|
||||||
ecs::{relationship::RelatedSpawner, spawn::SpawnWith},
|
ecs::{relationship::RelatedSpawner, spawn::SpawnWith},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
#[cfg(feature = "server")]
|
||||||
|
use lightyear::prelude::{NetworkTarget, Replicate};
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
#[derive(Event, Reflect)]
|
#[derive(Event, Reflect)]
|
||||||
@@ -23,7 +25,7 @@ pub fn plugin(app: &mut App) {
|
|||||||
global_observer!(app, on_spawn_key);
|
global_observer!(app, on_spawn_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_spawn_key(trigger: Trigger<KeySpawn>, mut commands: Commands, assets: Res<GameAssets>) {
|
fn on_spawn_key(trigger: Trigger<KeySpawn>, mut commands: Commands) {
|
||||||
let KeySpawn(position, id) = trigger.event();
|
let KeySpawn(position, id) = trigger.event();
|
||||||
|
|
||||||
let id = id.clone();
|
let id = id.clone();
|
||||||
@@ -42,11 +44,7 @@ fn on_spawn_key(trigger: Trigger<KeySpawn>, mut commands: Commands, assets: Res<
|
|||||||
CollisionLayers::new(GameLayer::CollectiblePhysics, GameLayer::Level),
|
CollisionLayers::new(GameLayer::CollectiblePhysics, GameLayer::Level),
|
||||||
Restitution::new(0.6),
|
Restitution::new(0.6),
|
||||||
Children::spawn((
|
Children::spawn((
|
||||||
Spawn((
|
Spawn((Billboard::All, SquishAnimation(2.6), GltfSceneRoot::Key)),
|
||||||
Billboard::All,
|
|
||||||
SquishAnimation(2.6),
|
|
||||||
SceneRoot(assets.mesh_key.clone()),
|
|
||||||
)),
|
|
||||||
SpawnWith(|parent: &mut RelatedSpawner<ChildOf>| {
|
SpawnWith(|parent: &mut RelatedSpawner<ChildOf>| {
|
||||||
parent
|
parent
|
||||||
.spawn((
|
.spawn((
|
||||||
@@ -59,6 +57,8 @@ fn on_spawn_key(trigger: Trigger<KeySpawn>, mut commands: Commands, assets: Res<
|
|||||||
.observe(on_collect_key);
|
.observe(on_collect_key);
|
||||||
}),
|
}),
|
||||||
)),
|
)),
|
||||||
|
#[cfg(feature = "server")]
|
||||||
|
Replicate::to_clients(NetworkTarget::All),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +1,25 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
GameState,
|
GameState, character::Character, global_observer, loading_assets::GameAssets,
|
||||||
|
utils::billboards::Billboard,
|
||||||
|
};
|
||||||
|
#[cfg(feature = "server")]
|
||||||
|
use crate::{
|
||||||
ai::Ai,
|
ai::Ai,
|
||||||
character::{AnimatedCharacter, Character},
|
character::AnimatedCharacter,
|
||||||
global_observer,
|
|
||||||
head::ActiveHead,
|
head::ActiveHead,
|
||||||
head_drop::HeadDrops,
|
head_drop::HeadDrops,
|
||||||
heads::{ActiveHeads, HEAD_COUNT, HeadState},
|
heads::{ActiveHeads, HEAD_COUNT, HeadState},
|
||||||
heads_database::HeadsDatabase,
|
heads_database::HeadsDatabase,
|
||||||
hitpoints::{Hitpoints, Kill},
|
hitpoints::{Hitpoints, Kill},
|
||||||
keys::KeySpawn,
|
keys::KeySpawn,
|
||||||
loading_assets::GameAssets,
|
|
||||||
sounds::PlaySound,
|
sounds::PlaySound,
|
||||||
tb_entities::EnemySpawn,
|
tb_entities::EnemySpawn,
|
||||||
utils::billboards::Billboard,
|
|
||||||
};
|
};
|
||||||
use bevy::{pbr::NotShadowCaster, prelude::*};
|
use bevy::{pbr::NotShadowCaster, prelude::*};
|
||||||
use lightyear::prelude::Disconnected;
|
|
||||||
#[cfg(feature = "client")]
|
|
||||||
use lightyear::prelude::{Client, Connected};
|
|
||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
use lightyear::prelude::{NetworkTarget, Replicate};
|
use lightyear::prelude::{NetworkTarget, Replicate};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
#[cfg(feature = "server")]
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Component, Reflect, PartialEq, Serialize, Deserialize)]
|
#[derive(Component, Reflect, PartialEq, Serialize, Deserialize)]
|
||||||
@@ -38,67 +37,44 @@ struct NpcSpawning {
|
|||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
pub struct SpawningBeam(pub f32);
|
pub struct SpawningBeam(pub f32);
|
||||||
|
|
||||||
|
#[cfg(feature = "server")]
|
||||||
#[derive(Event)]
|
#[derive(Event)]
|
||||||
struct OnCheckSpawns {
|
struct OnCheckSpawns;
|
||||||
on_client: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Event)]
|
#[derive(Event)]
|
||||||
pub struct SpawnCharacter(pub Vec3);
|
pub struct SpawnCharacter(pub Vec3);
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
app.init_resource::<NpcSpawning>();
|
app.init_resource::<NpcSpawning>();
|
||||||
|
#[cfg(feature = "server")]
|
||||||
app.add_systems(FixedUpdate, setup.run_if(in_state(GameState::Playing)));
|
app.add_systems(FixedUpdate, setup.run_if(in_state(GameState::Playing)));
|
||||||
app.add_systems(Update, update_beams.run_if(in_state(GameState::Playing)));
|
app.add_systems(Update, update_beams.run_if(in_state(GameState::Playing)));
|
||||||
|
|
||||||
|
#[cfg(feature = "server")]
|
||||||
global_observer!(app, on_spawn_check);
|
global_observer!(app, on_spawn_check);
|
||||||
global_observer!(app, on_spawn);
|
global_observer!(app, on_spawn);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup(
|
#[cfg(feature = "server")]
|
||||||
mut commands: Commands,
|
fn setup(mut commands: Commands, mut spawned: Local<bool>) {
|
||||||
#[cfg(feature = "client")] client: Query<
|
|
||||||
(Option<&Connected>, Option<&Disconnected>),
|
|
||||||
With<Client>,
|
|
||||||
>,
|
|
||||||
mut spawned: Local<bool>,
|
|
||||||
) {
|
|
||||||
if *spawned {
|
if *spawned {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
commands.init_resource::<NpcSpawning>();
|
||||||
|
commands.trigger(OnCheckSpawns);
|
||||||
|
|
||||||
|
*spawned = true;
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
{
|
|
||||||
commands.init_resource::<NpcSpawning>();
|
|
||||||
commands.trigger(OnCheckSpawns { on_client: false });
|
|
||||||
|
|
||||||
*spawned = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "client")]
|
|
||||||
if let Ok((connected, disconnected)) = client.single()
|
|
||||||
&& (connected.is_some() || disconnected.is_some())
|
|
||||||
{
|
|
||||||
commands.init_resource::<NpcSpawning>();
|
|
||||||
commands.trigger(OnCheckSpawns {
|
|
||||||
on_client: disconnected.is_some(),
|
|
||||||
});
|
|
||||||
|
|
||||||
*spawned = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_spawn_check(
|
fn on_spawn_check(
|
||||||
trigger: Trigger<OnCheckSpawns>,
|
_trigger: Trigger<OnCheckSpawns>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
query: Query<(Entity, &EnemySpawn, &Transform), Without<Npc>>,
|
query: Query<(Entity, &EnemySpawn, &Transform), Without<Npc>>,
|
||||||
heads_db: Res<HeadsDatabase>,
|
heads_db: Res<HeadsDatabase>,
|
||||||
spawning: Res<NpcSpawning>,
|
spawning: Res<NpcSpawning>,
|
||||||
) {
|
) {
|
||||||
if cfg!(not(feature = "server")) && !trigger.event().on_client {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: move into HeadsDatabase
|
//TODO: move into HeadsDatabase
|
||||||
let mut names: HashMap<String, usize> = HashMap::default();
|
let mut names: HashMap<String, usize> = HashMap::default();
|
||||||
for i in 0..HEAD_COUNT {
|
for i in 0..HEAD_COUNT {
|
||||||
@@ -126,6 +102,8 @@ fn on_spawn_check(
|
|||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
]),
|
]),
|
||||||
|
#[cfg(feature = "server")]
|
||||||
|
Replicate::to_clients(NetworkTarget::All),
|
||||||
))
|
))
|
||||||
.insert_if(Ai, || !spawn.disable_ai)
|
.insert_if(Ai, || !spawn.disable_ai)
|
||||||
.with_child((Name::from("body-rig"), AnimatedCharacter::new(id)))
|
.with_child((Name::from("body-rig"), AnimatedCharacter::new(id)))
|
||||||
@@ -138,9 +116,9 @@ fn on_spawn_check(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "server")]
|
||||||
fn on_kill(
|
fn on_kill(
|
||||||
trigger: Trigger<Kill>,
|
trigger: Trigger<Kill>,
|
||||||
disconnected: Option<Single<&Disconnected>>,
|
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
query: Query<(&Transform, &EnemySpawn, &ActiveHead)>,
|
query: Query<(&Transform, &EnemySpawn, &ActiveHead)>,
|
||||||
) {
|
) {
|
||||||
@@ -155,9 +133,7 @@ fn on_kill(
|
|||||||
}
|
}
|
||||||
|
|
||||||
commands.trigger(HeadDrops::new(transform.translation, head.0));
|
commands.trigger(HeadDrops::new(transform.translation, head.0));
|
||||||
commands.trigger(OnCheckSpawns {
|
commands.trigger(OnCheckSpawns);
|
||||||
on_client: cfg!(feature = "server") || disconnected.is_some(),
|
|
||||||
});
|
|
||||||
|
|
||||||
commands.entity(trigger.target()).despawn();
|
commands.entity(trigger.target()).despawn();
|
||||||
|
|
||||||
|
|||||||
@@ -9,10 +9,12 @@ use crate::{
|
|||||||
controller_common::{MovementSpeedFactor, PlayerCharacterController},
|
controller_common::{MovementSpeedFactor, PlayerCharacterController},
|
||||||
controls::ControllerSettings,
|
controls::ControllerSettings,
|
||||||
},
|
},
|
||||||
|
cutscene::StartCutscene,
|
||||||
global_observer,
|
global_observer,
|
||||||
head::ActiveHead,
|
head::ActiveHead,
|
||||||
heads::ActiveHeads,
|
heads::ActiveHeads,
|
||||||
loading_assets::GameAssets,
|
hitpoints::Hitpoints,
|
||||||
|
loading_assets::{GameAssets, HeadDropAssets},
|
||||||
player::{Player, PlayerBodyMesh},
|
player::{Player, PlayerBodyMesh},
|
||||||
utils::triggers::TriggerAppExt,
|
utils::triggers::TriggerAppExt,
|
||||||
};
|
};
|
||||||
@@ -57,6 +59,7 @@ pub fn plugin(app: &mut App) {
|
|||||||
app.register_component::<Grounding>();
|
app.register_component::<Grounding>();
|
||||||
app.register_component::<GroundingConfig>();
|
app.register_component::<GroundingConfig>();
|
||||||
app.register_component::<GroundingState>();
|
app.register_component::<GroundingState>();
|
||||||
|
app.register_component::<Hitpoints>();
|
||||||
app.register_component::<KinematicVelocity>();
|
app.register_component::<KinematicVelocity>();
|
||||||
app.register_component::<LinearVelocity>();
|
app.register_component::<LinearVelocity>();
|
||||||
app.register_component::<MoveInput>();
|
app.register_component::<MoveInput>();
|
||||||
@@ -84,6 +87,7 @@ pub fn plugin(app: &mut App) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.replicate_trigger::<BuildExplosionSprite, ActionsChannel>();
|
app.replicate_trigger::<BuildExplosionSprite, ActionsChannel>();
|
||||||
|
app.replicate_trigger::<StartCutscene, ActionsChannel>();
|
||||||
|
|
||||||
global_observer!(app, spawn_gltf_scene_roots);
|
global_observer!(app, spawn_gltf_scene_roots);
|
||||||
}
|
}
|
||||||
@@ -96,26 +100,40 @@ fn transform_should_rollback(this: &Transform, that: &Transform) -> bool {
|
|||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
pub enum GltfSceneRoot {
|
pub enum GltfSceneRoot {
|
||||||
Projectile(String),
|
Projectile(String),
|
||||||
|
HeadDrop(String),
|
||||||
|
Key,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_gltf_scene_roots(
|
fn spawn_gltf_scene_roots(
|
||||||
trigger: Trigger<OnAdd, GltfSceneRoot>,
|
trigger: Trigger<OnAdd, GltfSceneRoot>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
gltf_roots: Query<&GltfSceneRoot>,
|
gltf_roots: Query<&GltfSceneRoot>,
|
||||||
|
head_drop_assets: Res<HeadDropAssets>,
|
||||||
assets: Res<GameAssets>,
|
assets: Res<GameAssets>,
|
||||||
gltfs: Res<Assets<Gltf>>,
|
gltfs: Res<Assets<Gltf>>,
|
||||||
) -> Result {
|
) -> Result {
|
||||||
let root = gltf_roots.get(trigger.target())?;
|
let root = gltf_roots.get(trigger.target())?;
|
||||||
|
|
||||||
let (gltf, index) = match root {
|
let get_scene = |gltf: Handle<Gltf>, index: usize| {
|
||||||
GltfSceneRoot::Projectile(addr) => (
|
let gltf = gltfs.get(&gltf).unwrap();
|
||||||
|
gltf.scenes[index].clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
let scene = match root {
|
||||||
|
GltfSceneRoot::Projectile(addr) => get_scene(
|
||||||
assets.projectiles[format!("{addr}.glb").as_str()].clone(),
|
assets.projectiles[format!("{addr}.glb").as_str()].clone(),
|
||||||
0,
|
0,
|
||||||
),
|
),
|
||||||
|
GltfSceneRoot::HeadDrop(addr) => {
|
||||||
|
let gltf = head_drop_assets
|
||||||
|
.meshes
|
||||||
|
.get(format!("{addr}.glb").as_str())
|
||||||
|
.cloned();
|
||||||
|
let gltf = gltf.unwrap_or_else(|| head_drop_assets.meshes["none.glb"].clone());
|
||||||
|
get_scene(gltf, 0)
|
||||||
|
}
|
||||||
|
GltfSceneRoot::Key => assets.mesh_key.clone(),
|
||||||
};
|
};
|
||||||
let gltf = gltfs.get(&gltf).unwrap();
|
|
||||||
|
|
||||||
let scene = gltf.scenes[index].clone();
|
|
||||||
|
|
||||||
commands.entity(trigger.target()).insert(SceneRoot(scene));
|
commands.entity(trigger.target()).insert(SceneRoot(scene));
|
||||||
|
|
||||||
|
|||||||
5
justfile
5
justfile
@@ -15,8 +15,9 @@ run *args:
|
|||||||
server:
|
server:
|
||||||
RUST_BACKTRACE=1 cargo r {{server_args}}
|
RUST_BACKTRACE=1 cargo r {{server_args}}
|
||||||
|
|
||||||
dbg:
|
dbg *args:
|
||||||
RUST_BACKTRACE=1 cargo r {{client_args}},dbg
|
cargo b {{server_args}},dbg
|
||||||
|
RUST_BACKTRACE=1 cargo r {{client_args}},dbg -- {{args}}
|
||||||
|
|
||||||
dbg-server:
|
dbg-server:
|
||||||
RUST_BACKTRACE=1 cargo r {{server_args}},dbg
|
RUST_BACKTRACE=1 cargo r {{server_args}},dbg
|
||||||
|
|||||||
Reference in New Issue
Block a user