fix cash in multiplayer (#97)
* replicate it * use collision observer to simplify * pass entity of player that receives cash for a duplicate head
This commit is contained in:
@@ -54,7 +54,7 @@ fn on_head_collect(
|
||||
let (mut backpack, active_heads) = query.get_mut(entity)?;
|
||||
|
||||
if backpack.contains(head) || active_heads.contains(head) {
|
||||
cmds.trigger(CashCollectEvent);
|
||||
cmds.trigger(CashCollectEvent { entity });
|
||||
} else {
|
||||
backpack.insert(head, heads_db.as_ref());
|
||||
}
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
use crate::{GameState, global_observer, protocol::PlaySound, server_observer};
|
||||
use avian3d::prelude::Rotation;
|
||||
use crate::{
|
||||
GameState, global_observer,
|
||||
physics_layers::GameLayer,
|
||||
player::Player,
|
||||
protocol::{GltfSceneRoot, PlaySound, is_server},
|
||||
server_observer,
|
||||
tb_entities::CashSpawn,
|
||||
};
|
||||
use avian3d::prelude::*;
|
||||
use bevy::prelude::*;
|
||||
use bevy_replicon::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Component, Reflect, Default)]
|
||||
#[derive(Component, Reflect, Default, Deserialize, Serialize)]
|
||||
#[reflect(Component)]
|
||||
#[require(Transform)]
|
||||
pub struct Cash;
|
||||
@@ -17,28 +25,64 @@ pub struct CashInventory {
|
||||
pub cash: i32,
|
||||
}
|
||||
|
||||
#[derive(Event)]
|
||||
pub struct CashCollectEvent;
|
||||
|
||||
pub fn plugin(app: &mut App) {
|
||||
app.add_systems(Update, rotate.run_if(in_state(GameState::Playing)));
|
||||
|
||||
server_observer!(app, on_cash_collect);
|
||||
#[derive(EntityEvent)]
|
||||
pub struct CashCollectEvent {
|
||||
pub entity: Entity,
|
||||
}
|
||||
|
||||
fn on_cash_collect(
|
||||
_trigger: On<CashCollectEvent>,
|
||||
pub fn plugin(app: &mut App) {
|
||||
app.add_systems(OnEnter(GameState::Playing), setup.run_if(is_server));
|
||||
app.add_systems(Update, rotate.run_if(in_state(GameState::Playing)));
|
||||
|
||||
server_observer!(app, on_cash_collected);
|
||||
}
|
||||
|
||||
fn setup(mut commands: Commands, query: Query<Entity, With<CashSpawn>>) {
|
||||
for entity in query.iter() {
|
||||
commands
|
||||
.entity(entity)
|
||||
.insert((
|
||||
Name::new("cash"),
|
||||
GltfSceneRoot::Cash,
|
||||
Cash,
|
||||
Collider::cuboid(2., 3.0, 2.),
|
||||
CollisionLayers::new(GameLayer::CollectibleSensors, LayerMask::ALL),
|
||||
RigidBody::Kinematic,
|
||||
CollisionEventsEnabled,
|
||||
Sensor,
|
||||
Replicated,
|
||||
))
|
||||
.observe(on_cash_collision);
|
||||
}
|
||||
}
|
||||
|
||||
fn on_cash_collected(
|
||||
trigger: On<CashCollectEvent>,
|
||||
mut commands: Commands,
|
||||
mut cash: Single<&mut CashInventory>,
|
||||
mut query_player: Query<&mut CashInventory, With<Player>>,
|
||||
) {
|
||||
use bevy_replicon::prelude::{SendMode, ServerTriggerExt, ToClients};
|
||||
if let Ok(mut cash) = query_player.get_mut(trigger.entity) {
|
||||
commands.server_trigger(ToClients {
|
||||
mode: SendMode::Broadcast,
|
||||
message: PlaySound::CashCollect,
|
||||
});
|
||||
|
||||
commands.server_trigger(ToClients {
|
||||
mode: SendMode::Broadcast,
|
||||
message: PlaySound::CashCollect,
|
||||
});
|
||||
cash.cash += 100;
|
||||
}
|
||||
}
|
||||
|
||||
cash.cash += 100;
|
||||
fn on_cash_collision(
|
||||
trigger: On<CollisionStart>,
|
||||
mut commands: Commands,
|
||||
query_player: Query<&Player>,
|
||||
) {
|
||||
let collectable = trigger.event().collider1;
|
||||
let collider = trigger.event().collider2;
|
||||
|
||||
if query_player.contains(collider) {
|
||||
commands.trigger(CashCollectEvent { entity: collider });
|
||||
commands.entity(collectable).despawn();
|
||||
}
|
||||
}
|
||||
|
||||
fn rotate(time: Res<Time>, mut query: Query<&mut Rotation, With<Cash>>) {
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::{
|
||||
abilities::PlayerTriggerState,
|
||||
backpack::Backpack,
|
||||
camera::{CameraArmRotation, CameraTarget},
|
||||
cash::{Cash, CashCollectEvent, CashInventory},
|
||||
cash::CashInventory,
|
||||
character::{AnimatedCharacter, HedzCharacter},
|
||||
control::{Inputs, LocalInputs, controller_common::PlayerCharacterController},
|
||||
global_observer,
|
||||
@@ -16,7 +16,6 @@ use crate::{
|
||||
protocol::{ClientHeadChanged, OwnedByClient, PlaySound, PlayerId},
|
||||
tb_entities::SpawnPoint,
|
||||
};
|
||||
use avian3d::prelude::*;
|
||||
use bevy::{
|
||||
input::common_conditions::input_just_pressed,
|
||||
prelude::*,
|
||||
@@ -52,7 +51,6 @@ pub fn plugin(app: &mut App) {
|
||||
app.add_systems(
|
||||
Update,
|
||||
(
|
||||
collect_cash,
|
||||
setup_animations_marker_for_player,
|
||||
toggle_cursor_system.run_if(input_just_pressed(KeyCode::Escape)),
|
||||
)
|
||||
@@ -224,33 +222,6 @@ fn toggle_cursor_system(mut window: Single<&mut CursorOptions, With<PrimaryWindo
|
||||
toggle_grab_cursor(&mut window);
|
||||
}
|
||||
|
||||
fn collect_cash(
|
||||
mut commands: Commands,
|
||||
mut collision_message_reader: MessageReader<CollisionStart>,
|
||||
query_player: Query<&Player>,
|
||||
query_cash: Query<&Cash>,
|
||||
) {
|
||||
for CollisionStart {
|
||||
collider1: e1,
|
||||
collider2: e2,
|
||||
..
|
||||
} in collision_message_reader.read()
|
||||
{
|
||||
let collect = if query_player.contains(*e1) && query_cash.contains(*e2) {
|
||||
Some(*e2)
|
||||
} else if query_player.contains(*e2) && query_cash.contains(*e1) {
|
||||
Some(*e1)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(cash) = collect {
|
||||
commands.trigger(CashCollectEvent);
|
||||
commands.entity(cash).despawn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_animations_marker_for_player(
|
||||
mut commands: Commands,
|
||||
animation_handles: Query<Entity, Added<AnimationGraphHandle>>,
|
||||
|
||||
@@ -188,6 +188,7 @@ pub enum GltfSceneRoot {
|
||||
Projectile(String),
|
||||
HeadDrop(String),
|
||||
Key,
|
||||
Cash,
|
||||
}
|
||||
|
||||
pub fn spawn_gltf_scene_roots(
|
||||
@@ -219,6 +220,7 @@ pub fn spawn_gltf_scene_roots(
|
||||
get_scene(gltf, 0)
|
||||
}
|
||||
GltfSceneRoot::Key => assets.mesh_key.clone(),
|
||||
GltfSceneRoot::Cash => assets.mesh_cash.clone(),
|
||||
};
|
||||
|
||||
commands
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::{
|
||||
animation::AnimationFlags,
|
||||
backpack::{Backpack, BackpackSwapEvent},
|
||||
camera::{CameraArmRotation, CameraTarget},
|
||||
cash::CashInventory,
|
||||
cash::{Cash, CashInventory},
|
||||
character::{AnimatedCharacter, HedzCharacter},
|
||||
control::{
|
||||
CashHealPressed, ClientInputs, ControllerSettings, Inputs, SelectLeftPressed,
|
||||
@@ -106,6 +106,7 @@ pub fn plugin(app: &mut App) {
|
||||
.replicate::<SquishAnimation>()
|
||||
.replicate_once::<Transform>()
|
||||
.replicate_once::<SpawnTrail>()
|
||||
.replicate_once::<Cash>()
|
||||
.replicate_as::<Visibility, SerVisibility>();
|
||||
|
||||
app.replicate_once::<ThrownProjectile>()
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use crate::{
|
||||
GameState,
|
||||
cash::Cash,
|
||||
loading_assets::GameAssets,
|
||||
physics_layers::GameLayer,
|
||||
protocol::{
|
||||
@@ -152,30 +151,8 @@ impl EnemySpawn {
|
||||
|
||||
#[point_class(base(Transform), model({ "path": "models/cash.glb" }))]
|
||||
#[derive(Default)]
|
||||
#[component(on_add = Self::on_add)]
|
||||
pub struct CashSpawn {}
|
||||
|
||||
impl CashSpawn {
|
||||
fn on_add(mut world: DeferredWorld, HookContext { entity, .. }: HookContext) {
|
||||
let Some(assets) = world.get_resource::<GameAssets>() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let mesh = assets.mesh_cash.clone();
|
||||
|
||||
world.commands().entity(entity).insert((
|
||||
Name::new("cash"),
|
||||
SceneRoot(mesh),
|
||||
Cash,
|
||||
Collider::cuboid(2., 3.0, 2.),
|
||||
CollisionLayers::new(GameLayer::CollectibleSensors, LayerMask::ALL),
|
||||
RigidBody::Static,
|
||||
CollisionEventsEnabled,
|
||||
Sensor,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
#[point_class(base(Transform), model({ "path": "models/head_drop.glb" }))]
|
||||
#[derive(Default)]
|
||||
pub struct SecretHead {
|
||||
|
||||
Reference in New Issue
Block a user