mirror of
https://github.com/eliasstepanik/voxel-simulation.git
synced 2026-01-11 05:48:29 +00:00
Fixed Commit History
This commit is contained in:
parent
befbfb8935
commit
9074854ce9
@ -10,13 +10,12 @@ build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
bevy = { version = "0.15.1", features = ["jpeg", "trace_tracy", "trace_tracy_memory"] }
|
||||
bevy_egui = "0.31.1"
|
||||
bevy_egui = "0.33.0"
|
||||
bevy_asset = "0.15.0"
|
||||
bevy-inspector-egui = "0.28.0"
|
||||
bevy_reflect = "0.15.0"
|
||||
bevy_render = "0.15.0"
|
||||
bevy_window = "0.15.0"
|
||||
egui_dock = "0.14.0"
|
||||
egui_tiles = "0.12.0"
|
||||
spacetimedb-sdk = "1.0"
|
||||
hex = "0.4"
|
||||
random_word = { version = "0.5.0", features = ["en"] }
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
[server]
|
||||
host = "http://100.85.241.101:3000"
|
||||
host = "http://localhost:3000"
|
||||
database = "network-game"
|
||||
|
||||
[movement]
|
||||
|
||||
@ -1,76 +1,16 @@
|
||||
use crate::helper::debug_gizmos::debug_gizmos;
|
||||
use crate::helper::egui_dock::{
|
||||
reset_camera_viewport, set_camera_viewport, set_gizmo_mode, show_ui_system, UiState,
|
||||
};
|
||||
use bevy::prelude::*;
|
||||
use crate::helper::*;
|
||||
use bevy_egui::EguiSet;
|
||||
use bevy_render::extract_resource::ExtractResourcePlugin;
|
||||
use spacetimedb_sdk::{credentials, DbContext, Error, Event, Identity, Status, Table, TableWithPrimaryKey};
|
||||
use crate::plugins::network::systems::database::setup_database;
|
||||
use crate::module_bindings::DbConnection;
|
||||
|
||||
pub struct AppPlugin;
|
||||
|
||||
#[derive(Resource, Debug)]
|
||||
pub struct InspectorVisible(pub bool);
|
||||
|
||||
impl Default for InspectorVisible {
|
||||
fn default() -> Self {
|
||||
InspectorVisible(false)
|
||||
}
|
||||
}
|
||||
impl Plugin for AppPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.insert_resource(UiState::new());
|
||||
app.insert_resource(InspectorVisible(true));
|
||||
app.add_plugins(crate::plugins::ui::ui_plugin::UiPlugin);
|
||||
app.add_plugins(crate::plugins::environment::environment_plugin::EnvironmentPlugin);
|
||||
app.add_plugins(crate::plugins::network::network_plugin::NetworkPlugin);
|
||||
//app.add_plugins(crate::plugins::network::network_plugin::NetworkPlugin);
|
||||
app.add_plugins(crate::plugins::input::input_plugin::InputPlugin);
|
||||
|
||||
app.add_systems(Update, (debug_gizmos, toggle_ui_system));
|
||||
app.add_systems(
|
||||
PostUpdate,
|
||||
show_ui_system
|
||||
.before(EguiSet::ProcessOutput)
|
||||
.before(bevy_egui::systems::end_pass_system)
|
||||
.before(TransformSystem::TransformPropagate)
|
||||
.run_if(should_display_inspector),
|
||||
);
|
||||
app.add_systems(
|
||||
PostUpdate,
|
||||
(
|
||||
set_camera_viewport
|
||||
.after(show_ui_system)
|
||||
.run_if(should_display_inspector),
|
||||
reset_camera_viewport
|
||||
.run_if(should_not_display_inspector)
|
||||
.after(set_camera_viewport),
|
||||
),
|
||||
);
|
||||
app.add_systems(Update, set_gizmo_mode);
|
||||
app.add_systems(Update, (debug_gizmos));
|
||||
app.register_type::<Option<Handle<Image>>>();
|
||||
app.register_type::<AlphaMode>();
|
||||
}
|
||||
}
|
||||
|
||||
fn toggle_ui_system(
|
||||
keyboard_input: Res<ButtonInput<KeyCode>>,
|
||||
mut inspector_visible: ResMut<InspectorVisible>,
|
||||
) {
|
||||
// =======================
|
||||
// 6) Hide Inspector
|
||||
// =======================
|
||||
if keyboard_input.just_pressed(KeyCode::F1) {
|
||||
inspector_visible.0 = !inspector_visible.0
|
||||
}
|
||||
}
|
||||
|
||||
fn should_display_inspector(inspector_visible: Res<InspectorVisible>) -> bool {
|
||||
inspector_visible.0
|
||||
}
|
||||
|
||||
fn should_not_display_inspector(inspector_visible: Res<InspectorVisible>) -> bool {
|
||||
!inspector_visible.0
|
||||
}
|
||||
|
||||
@ -1,342 +0,0 @@
|
||||
use bevy::prelude::*;
|
||||
use bevy_asset::{ReflectAsset, UntypedAssetId};
|
||||
use bevy_egui::{egui, EguiContext};
|
||||
use bevy_inspector_egui::bevy_inspector::hierarchy::{hierarchy_ui, SelectedEntities};
|
||||
use bevy_inspector_egui::bevy_inspector::{
|
||||
self, ui_for_entities_shared_components, ui_for_entity_with_children,
|
||||
};
|
||||
use bevy_reflect::TypeRegistry;
|
||||
use bevy_render::camera::{CameraProjection, Viewport};
|
||||
use bevy_window::{PrimaryWindow, Window};
|
||||
use egui_dock::{DockArea, DockState, NodeIndex, Style};
|
||||
use std::any::TypeId;
|
||||
|
||||
#[cfg(egui_dock_gizmo)]
|
||||
use transform_gizmo_egui::GizmoMode;
|
||||
|
||||
/// Placeholder type if gizmo is disabled.
|
||||
#[cfg(not(egui_dock_gizmo))]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct GizmoMode;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct MainCamera;
|
||||
|
||||
pub fn show_ui_system(world: &mut World) {
|
||||
let Ok(egui_context) = world
|
||||
.query_filtered::<&mut EguiContext, With<PrimaryWindow>>()
|
||||
.get_single(world)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let mut egui_context = egui_context.clone();
|
||||
|
||||
world.resource_scope::<UiState, _>(|world, mut ui_state| {
|
||||
ui_state.ui(world, egui_context.get_mut())
|
||||
});
|
||||
}
|
||||
|
||||
// make camera only render to view not obpub structed by UI
|
||||
pub fn set_camera_viewport(
|
||||
ui_state: Res<UiState>,
|
||||
primary_window: Query<&mut Window, With<PrimaryWindow>>,
|
||||
egui_settings: Query<&bevy_egui::EguiSettings>,
|
||||
mut cameras: Query<&mut Camera, With<MainCamera>>,
|
||||
) {
|
||||
let mut cam = cameras.single_mut();
|
||||
|
||||
let Ok(window) = primary_window.get_single() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let scale_factor = window.scale_factor() * egui_settings.single().scale_factor;
|
||||
|
||||
let viewport_pos = ui_state.viewport_rect.left_top().to_vec2() * scale_factor;
|
||||
let viewport_size = ui_state.viewport_rect.size() * scale_factor;
|
||||
|
||||
let physical_position = UVec2::new(viewport_pos.x as u32, viewport_pos.y as u32);
|
||||
let physical_size = UVec2::new(viewport_size.x as u32, viewport_size.y as u32);
|
||||
|
||||
// The desired viewport rectangle at its offset in "physical pixel space"
|
||||
let rect = physical_position + physical_size;
|
||||
|
||||
let window_size = window.physical_size();
|
||||
// wgpu will panic if trying to set a viewport rect which has coordinates extending
|
||||
// past the size of the render target, i.e. the physical window in our case.
|
||||
// Typically this shouldn't happen- but during init and resizing etc. edge cases might occur.
|
||||
// Simply do nothing in those cases.
|
||||
if rect.x <= window_size.x && rect.y <= window_size.y {
|
||||
cam.viewport = Some(Viewport {
|
||||
physical_position,
|
||||
physical_size,
|
||||
depth: 0.0..1.0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset_camera_viewport(mut cameras: Query<&mut Camera, With<MainCamera>>) {
|
||||
if let Ok(mut cam) = cameras.get_single_mut() {
|
||||
cam.viewport = None; // Reset the viewport to its default state
|
||||
}
|
||||
}
|
||||
pub fn set_gizmo_mode(input: Res<ButtonInput<KeyCode>>, mut ui_state: ResMut<UiState>) {
|
||||
#[cfg(egui_dock_gizmo)]
|
||||
let keybinds = [
|
||||
(KeyCode::KeyR, GizmoMode::Rotate),
|
||||
(KeyCode::KeyT, GizmoMode::Translate),
|
||||
(KeyCode::KeyS, GizmoMode::Scale),
|
||||
];
|
||||
#[cfg(not(egui_dock_gizmo))]
|
||||
let keybinds = [];
|
||||
for (key, mode) in keybinds {
|
||||
if input.just_pressed(key) {
|
||||
ui_state.gizmo_mode = mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub enum InspectorSelection {
|
||||
Entities,
|
||||
Resource(TypeId, String),
|
||||
Asset(TypeId, String, UntypedAssetId),
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct UiState {
|
||||
state: DockState<EguiWindow>,
|
||||
viewport_rect: egui::Rect,
|
||||
selected_entities: SelectedEntities,
|
||||
selection: InspectorSelection,
|
||||
gizmo_mode: GizmoMode,
|
||||
}
|
||||
|
||||
impl UiState {
|
||||
pub fn new() -> Self {
|
||||
let mut state = DockState::new(vec![EguiWindow::GameView]);
|
||||
let tree = state.main_surface_mut();
|
||||
let [game, _inspector] =
|
||||
tree.split_right(NodeIndex::root(), 0.75, vec![EguiWindow::Inspector]);
|
||||
let [game, _hierarchy] = tree.split_left(game, 0.2, vec![EguiWindow::Hierarchy]);
|
||||
let [_game, _bottom] =
|
||||
tree.split_below(game, 0.8, vec![EguiWindow::Resources, EguiWindow::Assets]);
|
||||
|
||||
Self {
|
||||
state,
|
||||
selected_entities: SelectedEntities::default(),
|
||||
selection: InspectorSelection::Entities,
|
||||
viewport_rect: egui::Rect::NOTHING,
|
||||
#[cfg(egui_dock_gizmo)]
|
||||
gizmo_mode: GizmoMode::Translate,
|
||||
#[cfg(not(egui_dock_gizmo))]
|
||||
gizmo_mode: GizmoMode,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ui(&mut self, world: &mut World, ctx: &mut egui::Context) {
|
||||
let mut tab_viewer = TabViewer {
|
||||
world,
|
||||
viewport_rect: &mut self.viewport_rect,
|
||||
selected_entities: &mut self.selected_entities,
|
||||
selection: &mut self.selection,
|
||||
gizmo_mode: self.gizmo_mode,
|
||||
};
|
||||
DockArea::new(&mut self.state)
|
||||
.style(Style::from_egui(ctx.style().as_ref()))
|
||||
.show(ctx, &mut tab_viewer);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum EguiWindow {
|
||||
GameView,
|
||||
Hierarchy,
|
||||
Resources,
|
||||
Assets,
|
||||
Inspector,
|
||||
}
|
||||
|
||||
pub struct TabViewer<'a> {
|
||||
world: &'a mut World,
|
||||
selected_entities: &'a mut SelectedEntities,
|
||||
selection: &'a mut InspectorSelection,
|
||||
viewport_rect: &'a mut egui::Rect,
|
||||
gizmo_mode: GizmoMode,
|
||||
}
|
||||
|
||||
impl egui_dock::TabViewer for TabViewer<'_> {
|
||||
type Tab = EguiWindow;
|
||||
|
||||
fn ui(&mut self, ui: &mut egui_dock::egui::Ui, window: &mut Self::Tab) {
|
||||
let type_registry = self.world.resource::<AppTypeRegistry>().0.clone();
|
||||
let type_registry = type_registry.read();
|
||||
|
||||
match window {
|
||||
EguiWindow::GameView => {
|
||||
*self.viewport_rect = ui.clip_rect();
|
||||
|
||||
draw_gizmo(ui, self.world, self.selected_entities, self.gizmo_mode);
|
||||
}
|
||||
EguiWindow::Hierarchy => {
|
||||
let selected = hierarchy_ui(self.world, ui, self.selected_entities);
|
||||
if selected {
|
||||
*self.selection = InspectorSelection::Entities;
|
||||
}
|
||||
}
|
||||
EguiWindow::Resources => select_resource(ui, &type_registry, self.selection),
|
||||
EguiWindow::Assets => select_asset(ui, &type_registry, self.world, self.selection),
|
||||
EguiWindow::Inspector => match *self.selection {
|
||||
InspectorSelection::Entities => match self.selected_entities.as_slice() {
|
||||
&[entity] => ui_for_entity_with_children(self.world, entity, ui),
|
||||
entities => ui_for_entities_shared_components(self.world, entities, ui),
|
||||
},
|
||||
InspectorSelection::Resource(type_id, ref name) => {
|
||||
ui.label(name);
|
||||
bevy_inspector::by_type_id::ui_for_resource(
|
||||
self.world,
|
||||
type_id,
|
||||
ui,
|
||||
name,
|
||||
&type_registry,
|
||||
)
|
||||
}
|
||||
InspectorSelection::Asset(type_id, ref name, handle) => {
|
||||
ui.label(name);
|
||||
bevy_inspector::by_type_id::ui_for_asset(
|
||||
self.world,
|
||||
type_id,
|
||||
handle,
|
||||
ui,
|
||||
&type_registry,
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn title(&mut self, window: &mut Self::Tab) -> egui_dock::egui::WidgetText {
|
||||
format!("{window:?}").into()
|
||||
}
|
||||
|
||||
fn clear_background(&self, window: &Self::Tab) -> bool {
|
||||
!matches!(window, EguiWindow::GameView)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn draw_gizmo(
|
||||
ui: &mut egui::Ui,
|
||||
world: &mut World,
|
||||
selected_entities: &SelectedEntities,
|
||||
gizmo_mode: GizmoMode,
|
||||
) {
|
||||
let (cam_transform, projection) = world
|
||||
.query_filtered::<(&GlobalTransform, &Projection), With<MainCamera>>()
|
||||
.single(world);
|
||||
let view_matrix = Mat4::from(cam_transform.affine().inverse());
|
||||
let projection_matrix = projection.get_clip_from_view();
|
||||
|
||||
if selected_entities.len() != 1 {
|
||||
#[allow(clippy::needless_return)]
|
||||
return;
|
||||
}
|
||||
|
||||
/*for selected in selected_entities.iter() {
|
||||
let Some(transform) = world.get::<Transform>(selected) else {
|
||||
continue;
|
||||
};
|
||||
let model_matrix = transform.compute_matrix();
|
||||
|
||||
let mut gizmo = Gizmo::new(GizmoConfig {
|
||||
view_matrix: view_matrix.into(),
|
||||
projection_matrix: projection_matrix.into(),
|
||||
orientation: GizmoOrientation::Local,
|
||||
modes: EnumSet::from(gizmo_mode),
|
||||
..Default::default()
|
||||
});
|
||||
let Some([result]) = gizmo
|
||||
.interact(ui, model_matrix.into())
|
||||
.map(|(_, res)| res.as_slice())
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let mut transform = world.get_mut::<Transform>(selected).unwrap();
|
||||
transform = Transform {
|
||||
translation: Vec3::from(<[f64; 3]>::from(result.translation)),
|
||||
rotation: Quat::from_array(<[f64; 4]>::from(result.rotation)),
|
||||
scale: Vec3::from(<[f64; 3]>::from(result.scale)),
|
||||
};
|
||||
}*/
|
||||
}
|
||||
|
||||
pub fn select_resource(
|
||||
ui: &mut egui::Ui,
|
||||
type_registry: &TypeRegistry,
|
||||
selection: &mut InspectorSelection,
|
||||
) {
|
||||
let mut resources: Vec<_> = type_registry
|
||||
.iter()
|
||||
.filter(|registration| registration.data::<ReflectResource>().is_some())
|
||||
.map(|registration| {
|
||||
(
|
||||
registration.type_info().type_path_table().short_path(),
|
||||
registration.type_id(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
resources.sort_by(|(name_a, _), (name_b, _)| name_a.cmp(name_b));
|
||||
|
||||
for (resource_name, type_id) in resources {
|
||||
let selected = match *selection {
|
||||
InspectorSelection::Resource(selected, _) => selected == type_id,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if ui.selectable_label(selected, resource_name).clicked() {
|
||||
*selection = InspectorSelection::Resource(type_id, resource_name.to_string());
|
||||
}
|
||||
debug!("{}", resource_name);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn select_asset(
|
||||
ui: &mut egui::Ui,
|
||||
type_registry: &TypeRegistry,
|
||||
world: &World,
|
||||
selection: &mut InspectorSelection,
|
||||
) {
|
||||
let mut assets: Vec<_> = type_registry
|
||||
.iter()
|
||||
.filter_map(|registration| {
|
||||
let reflect_asset = registration.data::<ReflectAsset>()?;
|
||||
Some((
|
||||
registration.type_info().type_path_table().short_path(),
|
||||
registration.type_id(),
|
||||
reflect_asset,
|
||||
))
|
||||
})
|
||||
.collect();
|
||||
assets.sort_by(|(name_a, ..), (name_b, ..)| name_a.cmp(name_b));
|
||||
|
||||
for (asset_name, asset_type_id, reflect_asset) in assets {
|
||||
let handles: Vec<_> = reflect_asset.ids(world).collect();
|
||||
|
||||
ui.collapsing(format!("{asset_name} ({})", handles.len()), |ui| {
|
||||
for handle in handles {
|
||||
let selected = match *selection {
|
||||
InspectorSelection::Asset(_, _, selected_id) => selected_id == handle,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if ui
|
||||
.selectable_label(selected, format!("{:?}", handle))
|
||||
.clicked()
|
||||
{
|
||||
*selection =
|
||||
InspectorSelection::Asset(asset_type_id, asset_name.to_string(), handle);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,3 @@
|
||||
pub mod debug_gizmos;
|
||||
pub mod egui_dock;
|
||||
pub mod vector_helper;
|
||||
pub mod math;
|
||||
|
||||
@ -13,7 +13,6 @@ use bevy::render::settings::{Backends, RenderCreation, WgpuSettings};
|
||||
use bevy::render::RenderPlugin;
|
||||
use bevy::DefaultPlugins;
|
||||
use bevy_egui::EguiPlugin;
|
||||
use bevy_inspector_egui::DefaultInspectorConfigPlugin;
|
||||
use bevy_window::{PresentMode, Window, WindowPlugin};
|
||||
use toml;
|
||||
use crate::config::Config;
|
||||
@ -42,7 +41,6 @@ fn main() {
|
||||
|
||||
app.add_plugins(AppPlugin);
|
||||
app.add_plugins(EguiPlugin);
|
||||
app.add_plugins(DefaultInspectorConfigPlugin);
|
||||
|
||||
|
||||
|
||||
|
||||
@ -5,7 +5,9 @@ impl Plugin for EnvironmentPlugin {
|
||||
|
||||
app.add_systems(
|
||||
Startup,
|
||||
(crate::plugins::environment::systems::camera_system::setup),
|
||||
(crate::plugins::environment::systems::environment_system::setup, crate::plugins::environment::systems::camera_system::setup ),
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use crate::helper::egui_dock::MainCamera;
|
||||
|
||||
use bevy::input::mouse::{MouseMotion, MouseWheel};
|
||||
use bevy::math::Vec3;
|
||||
use bevy::prelude::*;
|
||||
@ -39,7 +39,6 @@ pub fn setup(mut commands: Commands,) {
|
||||
near: 0.0001,
|
||||
..default()
|
||||
}),
|
||||
MainCamera,
|
||||
CameraController::default(),
|
||||
Exposure::from_physical_camera(PhysicalCameraParameters {
|
||||
aperture_f_stops: 1.0,
|
||||
|
||||
@ -2,10 +2,31 @@
|
||||
use bevy::prelude::*;
|
||||
|
||||
|
||||
pub fn setup(mut commands: Commands) {
|
||||
|
||||
pub(crate) fn setup(
|
||||
mut commands : Commands,
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
) {
|
||||
|
||||
// 2) directional light
|
||||
commands.spawn(DirectionalLightBundle {
|
||||
transform: Transform::from_rotation(Quat::from_euler(
|
||||
EulerRot::XYZ,
|
||||
-std::f32::consts::FRAC_PI_4,
|
||||
std::f32::consts::FRAC_PI_4,
|
||||
0.0,
|
||||
)),
|
||||
directional_light: DirectionalLight {
|
||||
shadows_enabled: true,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
pub fn update(time: Res<Time>,) {
|
||||
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
|
||||
use bevy::app::{App, Plugin, PreUpdate, Startup};
|
||||
use bevy::prelude::{IntoSystemConfigs, Update};
|
||||
use crate::plugins::input::systems::console::{console_system, toggle_console, ConsoleState};
|
||||
|
||||
pub struct InputPlugin;
|
||||
impl Plugin for InputPlugin {
|
||||
@ -11,10 +12,14 @@ impl Plugin for InputPlugin {
|
||||
crate::plugins::input::systems::console::console_system,
|
||||
crate::plugins::input::systems::flight::flight_systems,
|
||||
crate::plugins::input::systems::ui::ui_system,
|
||||
crate::plugins::input::systems::network::network_system,
|
||||
//crate::plugins::input::systems::network::network_system,
|
||||
crate::plugins::input::systems::movement::movement_system,
|
||||
|
||||
),
|
||||
|
||||
);
|
||||
|
||||
_app.insert_resource(ConsoleState::default());
|
||||
_app.add_systems(Update, (toggle_console, console_system));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,23 +1,63 @@
|
||||
use bevy::app::AppExit;
|
||||
use bevy::input::ButtonInput;
|
||||
use bevy::input::mouse::{MouseMotion, MouseWheel};
|
||||
use bevy::prelude::{EventReader, EventWriter, KeyCode, Query, Res, ResMut, Time, Transform};
|
||||
use bevy::prelude::{EventReader, EventWriter, KeyCode, Query, Res, ResMut, Resource, Time, Transform};
|
||||
use bevy_egui::{egui, EguiContexts};
|
||||
use bevy_window::Window;
|
||||
use crate::plugins::environment::systems::camera_system::CameraController;
|
||||
use crate::plugins::network::systems::database::DbConnectionResource;
|
||||
|
||||
pub fn console_system(
|
||||
time: Res<Time>,
|
||||
keyboard_input: Res<ButtonInput<KeyCode>>, /*
|
||||
mouse_button_input: Res<ButtonInput<MouseButton>>,*/
|
||||
mut mouse_motion_events: EventReader<MouseMotion>,
|
||||
mut mouse_wheel_events: EventReader<MouseWheel>,
|
||||
mut windows: Query<&mut Window>,
|
||||
mut query: Query<(&mut Transform, &mut CameraController)>,
|
||||
mut app_exit_events: EventWriter<AppExit>,
|
||||
mut ctx: ResMut<DbConnectionResource>,
|
||||
mut ctxs: EguiContexts,
|
||||
mut state: ResMut<ConsoleState>,
|
||||
) {
|
||||
let mut window = windows.single_mut();
|
||||
let (mut transform, mut controller) = query.single_mut();
|
||||
if !state.open { return; }
|
||||
|
||||
egui::Window::new("Console")
|
||||
.resizable(true)
|
||||
.vscroll(true)
|
||||
.show(ctxs.ctx_mut(), |ui| {
|
||||
// Output
|
||||
for line in &state.output {
|
||||
ui.label(line);
|
||||
}
|
||||
|
||||
// Input line
|
||||
let resp = ui.text_edit_singleline(&mut state.input);
|
||||
if resp.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter)) {
|
||||
let cmd = state.input.trim().to_string();
|
||||
if !cmd.is_empty() {
|
||||
state.history.push(cmd.clone());
|
||||
handle_command(&cmd, &mut state.output);
|
||||
state.input.clear();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
/// Press ` to open / close
|
||||
pub fn toggle_console(
|
||||
mut state: ResMut<ConsoleState>,
|
||||
keys: Res<ButtonInput<KeyCode>>,
|
||||
) {
|
||||
if keys.just_pressed(KeyCode::KeyC) {
|
||||
state.open = !state.open;
|
||||
}
|
||||
}
|
||||
|
||||
/// Add your own commands here.
|
||||
/// For demo purposes we just echo the input.
|
||||
fn handle_command(cmd: &str, out: &mut Vec<String>) {
|
||||
match cmd.trim() {
|
||||
"help" => out.push("Available: help, clear, echo …".into()),
|
||||
"clear" => out.clear(),
|
||||
_ => out.push(format!("> {cmd}")),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Resource, Default)]
|
||||
pub struct ConsoleState {
|
||||
pub open: bool,
|
||||
pub input: String,
|
||||
pub history: Vec<String>,
|
||||
pub output: Vec<String>,
|
||||
}
|
||||
@ -5,7 +5,8 @@ use bevy::math::{Quat, Vec3};
|
||||
use bevy::prelude::{EventReader, EventWriter, KeyCode, Query, Res, ResMut, Time, Transform};
|
||||
use bevy_window::{CursorGrabMode, Window};
|
||||
use random_word::Lang;
|
||||
use crate::module_bindings::{set_name, set_position, spawn_entity, DbTransform, DbVector3, DbVector4};
|
||||
use spacetimedb_sdk::DbContext;
|
||||
use crate::module_bindings::{set_name, set_position, spawn_entity, DbTransform, DbVector3, DbVector4, PlayerTableAccess};
|
||||
use crate::plugins::environment::systems::camera_system::CameraController;
|
||||
use crate::plugins::network::systems::database::DbConnectionResource;
|
||||
|
||||
@ -19,8 +20,9 @@ pub fn flight_systems(
|
||||
mut windows: Query<&mut Window>,
|
||||
mut query: Query<(&mut Transform, &mut CameraController)>,
|
||||
mut app_exit_events: EventWriter<AppExit>,
|
||||
mut ctx: ResMut<DbConnectionResource>,
|
||||
//mut ctx: ResMut<DbConnectionResource>,
|
||||
) {
|
||||
|
||||
let mut window = windows.single_mut();
|
||||
let (mut transform, mut controller) = query.single_mut();
|
||||
|
||||
@ -98,11 +100,12 @@ pub fn flight_systems(
|
||||
let distance = controller.speed as f64 * delta_seconds;
|
||||
transform.translation += direction * distance as f32;
|
||||
|
||||
ctx.0.reducers.set_position(DbVector3{
|
||||
/*ctx.0.reducers.set_position(DbVector3{
|
||||
x: transform.translation.x,
|
||||
y: transform.translation.y,
|
||||
z: transform.translation.z,
|
||||
}).expect("TODO: panic message");
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,22 +1,5 @@
|
||||
use bevy::app::AppExit;
|
||||
use bevy::input::ButtonInput;
|
||||
use bevy::input::mouse::{MouseMotion, MouseWheel};
|
||||
use bevy::prelude::{EventReader, EventWriter, KeyCode, Query, Res, ResMut, Time, Transform};
|
||||
use bevy_window::Window;
|
||||
use crate::plugins::environment::systems::camera_system::CameraController;
|
||||
use crate::plugins::network::systems::database::DbConnectionResource;
|
||||
|
||||
|
||||
///TODO
|
||||
pub fn movement_system(
|
||||
time: Res<Time>,
|
||||
keyboard_input: Res<ButtonInput<KeyCode>>, /*
|
||||
mouse_button_input: Res<ButtonInput<MouseButton>>,*/
|
||||
mut mouse_motion_events: EventReader<MouseMotion>,
|
||||
mut mouse_wheel_events: EventReader<MouseWheel>,
|
||||
mut windows: Query<&mut Window>,
|
||||
mut query: Query<(&mut Transform, &mut CameraController)>,
|
||||
mut app_exit_events: EventWriter<AppExit>,
|
||||
mut ctx: ResMut<DbConnectionResource>,
|
||||
) {
|
||||
}
|
||||
@ -3,16 +3,18 @@ use bevy::input::ButtonInput;
|
||||
use bevy::math::{EulerRot, Quat};
|
||||
use bevy::prelude::{KeyCode, Res, ResMut,};
|
||||
use random_word::Lang;
|
||||
use crate::module_bindings::{set_name, spawn_entity, DbTransform, DbVector3, DbVector4};
|
||||
use crate::module_bindings::{set_name, spawn_entity, spawn_rigidbody_entity, DbTransform, DbVector3, DbVector4, EntityType};
|
||||
use crate::plugins::network::systems::database::DbConnectionResource;
|
||||
|
||||
pub fn network_system(
|
||||
keyboard_input: Res<ButtonInput<KeyCode>>,
|
||||
ctx: ResMut<DbConnectionResource>,
|
||||
) {
|
||||
let word = random_word::get(Lang::En);
|
||||
|
||||
|
||||
if keyboard_input.just_pressed(KeyCode::KeyQ) {
|
||||
let word = random_word::get(Lang::En);
|
||||
|
||||
ctx.0.reducers.set_name(word.to_string()).unwrap();
|
||||
}
|
||||
if keyboard_input.just_pressed(KeyCode::KeyE) {
|
||||
@ -20,7 +22,7 @@ pub fn network_system(
|
||||
let rand_rotation = crate::helper::vector_helper::random_vec3(0.0, 10.0);
|
||||
let rand_rotation = Quat::from_euler(EulerRot::XYZ,rand_rotation.x,rand_rotation.y,rand_rotation.z).normalize();
|
||||
let rand_scale = crate::helper::vector_helper::random_vec3(0.1, 1.0);
|
||||
ctx.0.reducers.spawn_entity(DbTransform{
|
||||
ctx.0.reducers.spawn_rigidbody_entity(DbTransform{
|
||||
position: DbVector3{
|
||||
x: rand_position.x,
|
||||
y: rand_position.y,
|
||||
@ -40,7 +42,9 @@ pub fn network_system(
|
||||
y: rand_scale.x,
|
||||
z: rand_scale.x,
|
||||
},
|
||||
}).unwrap();
|
||||
},
|
||||
EntityType::Cube,
|
||||
DbVector3{ x:0.0, y:0.0, z:0.0}, 5.0, false).unwrap();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -3,4 +3,3 @@ pub mod environment;
|
||||
pub mod ui;
|
||||
pub mod network;
|
||||
pub mod input;
|
||||
|
||||
|
||||
@ -10,11 +10,6 @@ use crate::plugins::network::systems::callbacks::*;
|
||||
use crate::plugins::network::systems::connection::*;
|
||||
use crate::plugins::network::systems::subscriptions::*;
|
||||
|
||||
/// The URI of the SpacetimeDB instance hosting our chat module.
|
||||
const HOST: &str = "http://100.85.241.101:3000";
|
||||
|
||||
/// The database name we chose when we published our module.
|
||||
const DB_NAME: &str = "network-game";
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct DbConnectionResource(pub(crate) DbConnection);
|
||||
@ -65,5 +60,5 @@ fn subscribe_to_tables(ctx: &DbConnection) {
|
||||
ctx.subscription_builder()
|
||||
.on_applied(on_sub_applied)
|
||||
.on_error(on_sub_error)
|
||||
.subscribe(["SELECT * FROM player", "SELECT * FROM entity"]);
|
||||
.subscribe(["SELECT * FROM player", "SELECT * FROM entity", "SELECT * FROM rigidbody"]);
|
||||
}
|
||||
@ -6,9 +6,9 @@ use bevy::prelude::{default, info, Bundle, Commands, Component, Cuboid, DespawnR
|
||||
use bevy_asset::Assets;
|
||||
use bevy_reflect::Reflect;
|
||||
use bevy_render::mesh::Mesh3d;
|
||||
use spacetimedb_sdk::Table;
|
||||
use spacetimedb_sdk::{DbContext, Table};
|
||||
use crate::helper::math::RoundTo;
|
||||
use crate::module_bindings::{DbTransform, DbVector3, EntityTableAccess, EntityType};
|
||||
use crate::module_bindings::{DbTransform, DbVector3, EntityTableAccess, EntityType, PlayerTableAccess};
|
||||
use crate::plugins::network::systems::database::DbConnectionResource;
|
||||
|
||||
#[derive(Component)]
|
||||
@ -44,6 +44,10 @@ pub fn sync_entities_system(
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
) {
|
||||
|
||||
let identity = db_resource.0.identity();
|
||||
let player = db_resource.0.db.player().identity().find(&identity);
|
||||
|
||||
// --- 1) Collect DB entities and build a set of IDs ---
|
||||
let db_entities = db_resource.0.db.entity();
|
||||
let db_ids: HashSet<u32> = db_entities.iter().map(|e| e.entity_id).collect();
|
||||
@ -51,6 +55,10 @@ pub fn sync_entities_system(
|
||||
// --- 2) For each DB entity, update or spawn in ECS ---
|
||||
for db_entity in db_entities.iter() {
|
||||
|
||||
if db_entity.entity_id == player.clone().unwrap().entity_id {
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to find a matching ECS entity by entity_id
|
||||
if let Some((_, mut transform, mut global, mut dto)) =
|
||||
query.iter_mut().find(|(_, _, _, dto)| dto.entity_id == db_entity.entity_id)
|
||||
@ -81,6 +89,9 @@ pub fn sync_entities_system(
|
||||
EntityType::Custom => todo!(),
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
let new_tf = Transform::from(db_entity.transform.clone());
|
||||
|
||||
commands.spawn((
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
mod types;
|
||||
|
||||
use spacetimedb::{reducer, ReducerContext, Table};
|
||||
use std::time::Duration;
|
||||
use spacetimedb::{reducer, ReducerContext, ScheduleAt, Table, TimeDuration, Timestamp};
|
||||
use crate::types::entity::{entity, entity__TableHandle, Entity, EntityType};
|
||||
use crate::types::player::{player, player__TableHandle, Player};
|
||||
use crate::types::rigidbody::physics_step;
|
||||
use crate::types::types::{DBVector4, DbTransform, DbVector3};
|
||||
|
||||
#[spacetimedb::table(name = config, public)]
|
||||
@ -78,5 +80,24 @@ pub fn init(ctx: &ReducerContext) -> Result<(), String> {
|
||||
ctx.db.config().try_insert(Config {
|
||||
id: 0,
|
||||
})?;
|
||||
|
||||
|
||||
ctx.db.physics_timer().try_insert(PhysicsTimer {
|
||||
scheduled_id: 0,
|
||||
scheduled_at: ScheduleAt::Interval(Duration::from_millis(50).into()),
|
||||
last_update_ts: ctx.timestamp,
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[spacetimedb::table(name = physics_timer, scheduled(physics_step))]
|
||||
struct PhysicsTimer {
|
||||
#[primary_key]
|
||||
#[auto_inc]
|
||||
scheduled_id: u64,
|
||||
scheduled_at: ScheduleAt,
|
||||
last_update_ts: Timestamp,
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
pub mod types;
|
||||
pub mod player;
|
||||
pub mod entity;
|
||||
pub mod rigidbody;
|
||||
103
server/src/types/rigidbody.rs
Normal file
103
server/src/types/rigidbody.rs
Normal file
@ -0,0 +1,103 @@
|
||||
use std::time::Duration;
|
||||
use spacetimedb::{ReducerContext, Table, TimeDuration, Timestamp};
|
||||
use crate::{physics_timer, PhysicsTimer};
|
||||
use crate::types::entity::{entity, Entity, EntityType};
|
||||
use crate::types::types::{DbTransform, DbVector3};
|
||||
|
||||
#[spacetimedb::table(name = rigidbody, public)]
|
||||
#[derive(Debug, Clone, )]
|
||||
pub struct Rigidbody {
|
||||
#[auto_inc]
|
||||
#[primary_key]
|
||||
pub rigidbody_id: u32,
|
||||
|
||||
#[index(btree)]
|
||||
pub entity_id: u32,
|
||||
|
||||
|
||||
pub velocity: DbVector3,
|
||||
pub force: DbVector3,
|
||||
pub mass: f32,
|
||||
|
||||
pub is_fixed: bool,
|
||||
}
|
||||
|
||||
#[spacetimedb::reducer]
|
||||
pub fn spawn_rigidbody_entity(
|
||||
ctx: &ReducerContext,
|
||||
transform: DbTransform,
|
||||
entity_type: EntityType,
|
||||
velocity: DbVector3,
|
||||
mass: f32,
|
||||
is_fixed: bool,
|
||||
) -> Result<(), String> {
|
||||
// 1. insert a new Entity row
|
||||
let inserted_entity: Entity = ctx
|
||||
.db
|
||||
.entity()
|
||||
.insert(Entity {
|
||||
entity_id: 0,
|
||||
transform,
|
||||
entity_type,
|
||||
});
|
||||
|
||||
// 2. insert its corresponding Rigidbody row
|
||||
ctx.db
|
||||
.rigidbody()
|
||||
.insert(Rigidbody {
|
||||
rigidbody_id: 0,
|
||||
entity_id: inserted_entity.entity_id,
|
||||
velocity,
|
||||
force: DbVector3::zero(),
|
||||
mass,
|
||||
is_fixed,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[spacetimedb::reducer]
|
||||
pub fn physics_step(ctx: &ReducerContext, mut timer: PhysicsTimer) -> Result<(), String> {
|
||||
let now = ctx.timestamp;
|
||||
let delta = now
|
||||
.time_duration_since(timer.last_update_ts)
|
||||
.unwrap_or(TimeDuration::from(Duration::from_millis(50)));
|
||||
let dt = delta.to_duration().unwrap().as_secs_f32();
|
||||
|
||||
// update timer state
|
||||
timer.last_update_ts = now;
|
||||
ctx.db.physics_timer().scheduled_id().update(timer);
|
||||
|
||||
// constant gravity
|
||||
let gravity = DbVector3::new(0.0, -9.81, 0.0);
|
||||
|
||||
// process all rigidbodies
|
||||
let bodies: Vec<Rigidbody> = ctx.db.rigidbody().iter().collect();
|
||||
for mut rb in bodies {
|
||||
if rb.is_fixed {
|
||||
continue;
|
||||
}
|
||||
|
||||
// apply gravity to force
|
||||
rb.force.add(&gravity.mul_scalar(rb.mass));
|
||||
|
||||
// integrate velocity
|
||||
let inv_mass = 1.0 / rb.mass;
|
||||
let accel = rb.force.mul_scalar(inv_mass);
|
||||
rb.velocity.add(&accel.mul_scalar(dt));
|
||||
|
||||
// update corresponding entity position
|
||||
if let Some(mut ent) = ctx.db.entity().iter().find(|e| e.entity_id == rb.entity_id){
|
||||
ent.transform.position.add(&rb.velocity.mul_scalar(dt));
|
||||
ctx.db.entity().entity_id().update(ent);
|
||||
}
|
||||
|
||||
// reset force and write back
|
||||
rb.force = DbVector3::zero();
|
||||
ctx.db.rigidbody().rigidbody_id().update(rb);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -7,7 +7,22 @@ pub struct DbVector3 {
|
||||
pub z: f32,
|
||||
}
|
||||
|
||||
|
||||
impl DbVector3 {
|
||||
pub(crate) fn new(x: f32, y: f32, z: f32) -> DbVector3 {
|
||||
DbVector3 { x, y, z }
|
||||
}
|
||||
pub(crate) fn zero() -> DbVector3 {
|
||||
DbVector3::new(0.0, 0.0, 0.0)
|
||||
}
|
||||
pub(crate) fn add(&mut self, other: &DbVector3) {
|
||||
self.x += other.x;
|
||||
self.y += other.y;
|
||||
self.z += other.z;
|
||||
}
|
||||
pub(crate) fn mul_scalar(&self, s: f32) -> DbVector3 {
|
||||
DbVector3::new(self.x * s, self.y * s, self.z * s)
|
||||
}
|
||||
}
|
||||
#[derive(SpacetimeType, Clone, Debug)]
|
||||
pub struct DBVector4 {
|
||||
pub x: f32,
|
||||
|
||||
2
start_server.sh
Normal file
2
start_server.sh
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
spacetime start
|
||||
Loading…
x
Reference in New Issue
Block a user