diff --git a/src/common/state.rs b/src/common/state.rs index ad99308ef22e5e9494775c37aecf8f2aa16b8e00..a644fad9f3b067d61eb08f2e0806756f7ba657aa 100644 --- a/src/common/state.rs +++ b/src/common/state.rs @@ -37,7 +37,7 @@ pub struct Changeset<C: blockchain::Config> { #[derive(Event)] pub struct BlockchainEvent<C: blockchain::Config> { - changeset: Changeset<C>, + pub changeset: Changeset<C>, } #[derive(Clone)] diff --git a/src/main.rs b/src/main.rs index bb0ee8418f91e4ea0447413ccbd673d3d5965808..c714698c78953c388a9e3c7970c2c180bb761934 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,29 +14,9 @@ use bevy::{ window::WindowMode, }; use bevy_atmosphere::prelude::*; -//use bevy_easings::*; -use bevy_egui::{egui, EguiContext, EguiPlugin}; -use bevy_mod_picking::{ - events::Pointer, - prelude::*, - selection::{Deselect, Select}, -}; -use bevy_polyline::prelude::*; -use chrono::{TimeZone, Utc}; use clap::Parser; -use dashmap::DashMap; -use enterpolation::{Curve, Generator as _}; -use epaint::textures::TextureOptions; -use num_traits::AsPrimitive; -use palette::{convert::IntoColorUnclamped, IntoColor}; -use rand::distributions::Distribution; -use rayon::iter::ParallelIterator; -use sha2::Digest; -use smooth_bevy_cameras::{ - controllers::orbit::{OrbitCameraBundle, OrbitCameraController, OrbitCameraPlugin}, - LookTransform, LookTransformPlugin, -}; -use std::{fmt::Debug, io::Write, marker::PhantomData}; +use smooth_bevy_cameras::{controllers::orbit::{OrbitCameraBundle, OrbitCameraController, OrbitCameraPlugin}, LookTransformPlugin}; +use std::{fmt::Debug, marker::PhantomData}; #[derive(Clone, Debug, Eq, Hash, PartialEq, SystemSet)] enum Set { @@ -72,12 +52,20 @@ impl< App::new() .add_event::<state::BlockchainEvent<C>>() .init_resource::<offchain::OffchainData<C>>() + .insert_resource(plugins::bc_reader::BcReaderRes { + reader: Box::new(bc_reader), + _p: Default::default(), + }) .add_plugins(( DefaultPlugins, - plugins::wotgraph::WotGraphPlugin::<C, 3>::default(), - plugins::bc_reader::BcReaderPlugin::new(Box::new(bc_reader)), + AtmospherePlugin, + LookTransformPlugin, + OrbitCameraPlugin::default(), + plugins::wotgraph::WotGraphPlugin::<C>::default(), + plugins::bc_reader::BcReaderPlugin::<C>::default(), )) .add_systems(Startup, Self::setup) + .add_systems(Update, Self::keyboard_event_system) .configure_sets(Update, Set::UpdatePositions) .configure_sets(PreUpdate, Set::UpdateState) .run(); @@ -94,9 +82,9 @@ impl< commands .spawn(OrbitCameraBundle::new( OrbitCameraController::default(), - Vec3::new(0.0, -100.0, 0.0), + Vec3::new(-100.0, -100.0, -100.0), Vec3::new(0.0, 0.0, 0.0), - Vec3::new(0.0, 0.0, 1.0), + Vec3::Y, )) .insert(Camera3dBundle::default()) .insert(AtmosphereCamera::default()); @@ -105,6 +93,7 @@ impl< fn keyboard_event_system( mut keyboard_input_events: EventReader<KeyboardInput>, mut windows: Query<&mut Window>, + mut bc_reader_cmd_event_writer: EventWriter<plugins::bc_reader::BcReaderCmdEvent>, ) { for event in keyboard_input_events.read() { match event { @@ -118,21 +107,26 @@ impl< state: ButtonState::Pressed, .. } => { - if ui_state.target_block_number < bc_reader.available_blocks() - 1 { - ui_state.target_block_number += 1; - } + bc_reader_cmd_event_writer.send(plugins::bc_reader::BcReaderCmdEvent::ApplyOne); } KeyboardInput { key_code: KeyCode::NumpadSubtract, state: ButtonState::Pressed, .. } => { - if ui_state.target_block_number > 0 { - ui_state.target_block_number -= 1; - } + bc_reader_cmd_event_writer + .send(plugins::bc_reader::BcReaderCmdEvent::RevertOne); } _ => {} } } } + + fn toggle_fullscreen(windows: &mut Query<&mut Window>) { + let mut window = windows.single_mut(); + window.mode = match window.mode { + WindowMode::Windowed => WindowMode::Fullscreen, + _ => WindowMode::Windowed, + }; + } } diff --git a/src/plugins/bc_reader.rs b/src/plugins/bc_reader.rs index ea2e8ff452a9a57a8784c0d9e1b4a18538bb5044..85e2a83ed4f2be8fb036e89947676d56842599bc 100644 --- a/src/plugins/bc_reader.rs +++ b/src/plugins/bc_reader.rs @@ -1,22 +1,66 @@ -use crate::{bc_reader, common::*}; +use crate::{ + bc_reader::{self, BcReader as _}, + common::*, +}; use bevy::prelude::*; use std::marker::PhantomData; +#[derive(Resource)] +pub struct BcReaderRes<C: blockchain::Config> { + pub reader: Box<dyn bc_reader::BcReader<C>>, + pub _p: PhantomData<C>, +} + +#[derive(Event)] +pub enum BcReaderCmdEvent { + ApplyOne, + RevertOne, +} + +#[derive(Default)] pub struct BcReaderPlugin<C: blockchain::Config> { - reader: Box<dyn bc_reader::BcReader<C>>, + //reader: Box<dyn bc_reader::BcReader<C>>, _p: PhantomData<C>, } -impl<C: 'static + blockchain::Config + Send + Sync> BcReaderPlugin<C> { - pub fn new(reader: Box<dyn bc_reader::BcReader<C>>) -> Self { - Self { - reader, - _p: Default::default(), - } +// impl<C: 'static + blockchain::Config + Send + Sync> BcReaderPlugin<C> { +// pub fn new(reader: Box<dyn bc_reader::BcReader<C>>) -> Self { +// Self { +// reader, +// _p: Default::default(), +// } +// } +// } + +impl<C: 'static + blockchain::Config + Send + Sync> Plugin for BcReaderPlugin<C> { + fn build(&self, app: &mut App) { + app.add_event::<BcReaderCmdEvent>() + .add_systems(Update, cmd_event_listener::<C>); } } -impl<C: 'static + blockchain::Config + Send + Sync> Plugin for BcReaderPlugin<C> { - fn build(&self, app: &mut App) {} +fn cmd_event_listener<C: 'static + blockchain::Config + Send + Sync>( + mut cmd_event_reader: EventReader<BcReaderCmdEvent>, + mut blockchain_event_writer: EventWriter<state::BlockchainEvent<C>>, + mut bc_reader: ResMut<BcReaderRes<C>>, +) { + for event in cmd_event_reader.read() { + match event { + BcReaderCmdEvent::ApplyOne => { + if let Some(changeset) = bc_reader.as_mut().reader.apply_one() { + blockchain_event_writer.send(state::BlockchainEvent { + changeset + }); + } + } + BcReaderCmdEvent::RevertOne => { + if let Some(changeset) = bc_reader.as_mut().reader.revert_one() { + blockchain_event_writer.send(state::BlockchainEvent { + changeset + }); + } + } + } + } } diff --git a/src/plugins/wotgraph.rs b/src/plugins/wotgraph.rs index 7d0b01182394f1278e3a32d3c707a36c21e1c9db..25b55abfe27a1c78038d4cbf57eb6fbf6130cdcf 100644 --- a/src/plugins/wotgraph.rs +++ b/src/plugins/wotgraph.rs @@ -4,13 +4,14 @@ use bevy::prelude::*; use num_traits::Zero; use std::marker::PhantomData; -pub type Layout<const N: usize> = forceatlas2::Layout< - f32, - 3, - forceatlas2::EdgeBTreeMap<f32, IdtyId>, - forceatlas2::NodeHashMap<f32, 3, IdtyId>, - IdtyId, ->; +#[derive(Default, Resource)] +pub struct LayoutRes(pub forceatlas2::Layout< +f32, +3, +forceatlas2::EdgeBTreeMap<f32, IdtyId>, +forceatlas2::NodeHashMap<f32, 3, IdtyId>, +IdtyId, +>); #[derive(Bundle)] struct IdtyNodeBundle { @@ -18,72 +19,82 @@ struct IdtyNodeBundle { pbr: PbrBundle, } -pub struct WotGraphPlugin<C, const N: usize> { - layout: Layout<N>, +#[derive(Default)] +pub struct WotGraphPlugin<C> { _p: PhantomData<C>, } -impl<C> Default for WotGraphPlugin<C, 3> { - fn default() -> Self { - Self { - layout: Layout::default(), - _p: Default::default(), - } - } -} - -impl<C: 'static + blockchain::Config + Send + Sync, const N: usize> Plugin - for WotGraphPlugin<C, N> +impl<C: 'static + blockchain::Config + Send + Sync> Plugin + for WotGraphPlugin<C> { - fn build(&self, app: &mut App) {} + fn build(&self, app: &mut App) { + app.insert_resource(LayoutRes::default()) + .add_systems(Update, (Self::blockchain_event_listener, Self::iterate_layout, Self::update_positions)); + } } -impl<C: blockchain::Config, const N: usize> WotGraphPlugin<C, N> { - fn update_graph( - &mut self, - changeset: &state::Changeset<C>, +impl<C: 'static + blockchain::Config> WotGraphPlugin<C> { + fn blockchain_event_listener( + mut blockchain_event_reader: EventReader<state::BlockchainEvent<C>>, + mut layout: ResMut<LayoutRes>, mut commands: Commands, mut meshes: ResMut<Assets<Mesh>>, mut materials: ResMut<Assets<StandardMaterial>>, ) { - let mut rng = rand::thread_rng(); - for cert in changeset.removed_certs.iter() { - let cert = cert.value(); - self.layout.edges.remove(&(cert.issuer, cert.receiver)); - } - for idty in changeset.removed_idties.iter() { - self.layout.nodes.remove(idty.key()); - } - for idty in changeset.new_idties.iter() { - let pos = forceatlas2::sample_unit_cube(&mut rng); - self.layout.nodes.insert( - *idty.key(), - forceatlas2::Node { - pos, - speed: Zero::zero(), - old_speed: Zero::zero(), - size: 1.0, - mass: 1.0, - }, - ); - let mesh = meshes.add(Sphere::new(1.0).mesh().ico(3).unwrap()); - commands.spawn(IdtyNodeBundle { - pbr: PbrBundle { - transform: Transform { - translation: pos.0.into(), - scale: Vec3::splat(1.0), + for event in blockchain_event_reader.read() { + let mut rng = rand::thread_rng(); + for cert in event.changeset.removed_certs.iter() { + let cert = cert.value(); + layout.0.edges.remove(&(cert.issuer, cert.receiver)); + } + for idty in event.changeset.removed_idties.iter() { + layout.0.nodes.remove(idty.key()); + } + for idty in event.changeset.new_idties.iter() { + let pos = forceatlas2::sample_unit_cube(&mut rng); + layout.0.nodes.insert( + *idty.key(), + forceatlas2::Node { + pos, + speed: Zero::zero(), + old_speed: Zero::zero(), + size: 1.0, + mass: 1.0, + }, + ); + let mesh = meshes.add(Sphere::new(1.0).mesh().ico(3).unwrap()); + commands.spawn(IdtyNodeBundle { + pbr: PbrBundle { + transform: Transform { + translation: pos.0.into(), + scale: Vec3::splat(1.0), + ..default() + }, + mesh: mesh.clone(), + material: materials.add(Color::rgb(1.0, 1.0, 1.0)), ..default() }, - mesh: mesh.clone(), - material: materials.add(Color::rgb(1.0, 1.0, 1.0)), - ..default() - }, - idty_id: *idty.key(), - }); - } - for cert in changeset.new_certs.iter() { - let cert = cert.value(); - self.layout.edges.insert((cert.issuer, cert.receiver), 1.0); + idty_id: *idty.key(), + }); + } + for cert in event.changeset.new_certs.iter() { + let cert = cert.value(); + layout.0.edges.insert((cert.issuer, cert.receiver), 1.0); + } } } + + fn iterate_layout( + mut layout: ResMut<LayoutRes>,) { + layout.0.iteration(); + } + + fn update_positions( + mut layout: ResMut<LayoutRes>, + mut query_idty: Query<(&IdtyId, &mut Transform)>, + ) { + for (idty_id, mut idty_pos) in query_idty.iter_mut() { + idty_pos.translation = layout.0.nodes[idty_id].pos.0.into(); + } + } }