use bevy::diagnostic::{
Diagnostic, DiagnosticPath, Diagnostics, EntityCountDiagnosticsPlugin,
FrameTimeDiagnosticsPlugin, RegisterDiagnostic, SystemInformationDiagnosticsPlugin,
};
use bevy::prelude::*;
use bevy::time::TimerMode;
use bevy_fleet::{FleetConfig, FleetEvent, FleetPlugin, forward_serialized_events};
use serde::Serialize;
const PLAYER_SCORE: DiagnosticPath = DiagnosticPath::const_new("game/player_score");
const PLAYER_LEVEL: DiagnosticPath = DiagnosticPath::const_new("game/player_level");
fn main() {
let fleet_config = FleetConfig {
app_id: "advanced-example".to_string(),
aggregation_url: "http://127.0.0.1:4318".to_string(),
enabled: true,
publish_interval_secs: 10,
..Default::default()
};
let mut app = App::new();
app.insert_resource(fleet_config.clone());
app.add_plugins(DefaultPlugins)
.add_plugins(EntityCountDiagnosticsPlugin::default())
.add_plugins(FrameTimeDiagnosticsPlugin::default())
.add_plugins(SystemInformationDiagnosticsPlugin::default())
.add_plugins(FleetPlugin {
config: fleet_config,
})
.register_diagnostic(Diagnostic::new(PLAYER_SCORE))
.register_diagnostic(Diagnostic::new(PLAYER_LEVEL))
.add_message::<ItemPickupEvent>()
.add_systems(Startup, setup)
.add_systems(
Update,
(
track_player_events,
emit_item_pickups,
forward_serialized_events::<ItemPickupEvent>,
update_game_diagnostics,
panic_after_delay,
),
);
app.run();
}
#[derive(Component)]
struct Player {
score: u32,
level: u32,
}
#[derive(Clone, Event, Serialize, Message)]
struct ItemPickupEvent {
item: String,
quantity: u32,
player_level: u32,
}
#[derive(Resource)]
struct EventTimers {
status: Timer,
pickup: Timer,
}
#[derive(Resource)]
struct PanicTimer(Timer);
fn setup(mut commands: Commands) {
commands.spawn(Player { score: 0, level: 1 });
commands.insert_resource(EventTimers {
status: Timer::from_seconds(5.0, TimerMode::Repeating),
pickup: Timer::from_seconds(7.0, TimerMode::Repeating),
});
commands.insert_resource(PanicTimer(Timer::from_seconds(30.0, TimerMode::Once)));
}
fn track_player_events(
mut events: MessageWriter<FleetEvent>,
query: Query<&Player>,
time: Res<Time>,
mut timers: ResMut<EventTimers>,
) {
if timers.status.tick(time.delta()).just_finished() {
for player in query.iter() {
let event = FleetEvent::new("player_status")
.with_data("score", player.score.to_string())
.with_data("level", player.level.to_string());
events.write(event);
}
}
}
fn emit_item_pickups(
mut events: MessageWriter<ItemPickupEvent>,
query: Query<&Player>,
time: Res<Time>,
mut timers: ResMut<EventTimers>,
) {
if timers.pickup.tick(time.delta()).just_finished() {
for player in query.iter() {
events.write(ItemPickupEvent {
item: "health_potion".to_string(),
quantity: 1,
player_level: player.level,
});
}
}
}
fn update_game_diagnostics(mut diagnostics: Diagnostics, query: Query<&Player>) {
for player in query.iter() {
diagnostics.add_measurement(&PLAYER_SCORE, || player.score as f64);
diagnostics.add_measurement(&PLAYER_LEVEL, || player.level as f64);
}
}
fn panic_after_delay(mut timer: ResMut<PanicTimer>, time: Res<Time>) {
if timer.0.tick(time.delta()).just_finished() {
panic!("Intentional panic after 30s to verify Fleet export");
}
}