2 Commits
Author SHA1 Message Date
mitchell f8b5107c92 shells 2026-02-09 15:35:37 -06:00
mitchell dbb87c3930 networking shell 2026-02-02 15:31:39 -06:00
9 changed files with 310 additions and 647 deletions
Generated
+146 -621
View File
File diff suppressed because it is too large Load Diff
+7 -1
View File
@@ -3,7 +3,13 @@ name = "time_travel"
version = "0.1.0" version = "0.1.0"
edition = "2024" edition = "2024"
[features]
default = ["client", "server"]
client = []
server = []
[dependencies] [dependencies]
avian2d = "0.5.0" avian2d = "0.5.0"
bevy = "0.18.0" bevy = "0.18.0"
bevy_egui = "0.39.1" clap = { version = "4.5.56", features = ["derive"] }
+27
View File
@@ -0,0 +1,27 @@
use clap::{Parser, Subcommand};
#[derive(Parser, Debug)]
#[command(author, version, about)]
pub struct Cli {
#[command(subcommand)]
pub mode: Option<Mode>,
}
#[derive(Subcommand, Debug, Default)]
pub enum Mode {
/// Run a headless server (no rendering)
#[cfg(feature = "server")]
#[cfg_attr(all(feature = "server", not(feature = "client")), default)]
Headless,
/// Run a server that renders
#[cfg(feature = "server")]
Server,
/// Run the client application
#[cfg(feature = "client")]
#[cfg_attr(all(feature = "client", not(feature = "server")), default)]
Client,
/// Run both client and server in one process
#[cfg(all(feature = "client", feature = "server"))]
#[cfg_attr(all(feature = "client", feature = "server"), default)]
Host,
}
+62 -25
View File
@@ -1,29 +1,75 @@
use crate::avian::{CharacterControllerBundle, CharacterControllerPlugin}; use crate::{
avian::{CharacterControllerBundle, CharacterControllerPlugin},
cli::Cli,
};
use avian2d::{ use avian2d::{
PhysicsPlugins, PhysicsPlugins,
math::Vector, math::Vector,
prelude::{Collider, Gravity, RigidBody}, prelude::{Collider, Gravity, RigidBody},
}; };
use bevy::{camera::ScalingMode, color::palettes::css::GREEN, prelude::*}; use bevy::{camera::ScalingMode, color::palettes::css::GREEN, prelude::*};
use bevy_egui::{EguiContexts, EguiPlugin, EguiPrimaryContextPass, egui}; use clap::Parser;
pub mod avian; pub mod avian;
pub mod cli;
pub mod net;
fn main() { fn main() {
App::new() let cli = match Cli::try_parse() {
.add_plugins(( Ok(cli) => cli,
DefaultPlugins, Err(err) => {
EguiPlugin::default(), err.print().expect("failed to print clap error");
// Add physics plugins and specify a units-per-meter scaling factor, 1 meter = 20 pixels. std::process::exit(1);
// The unit allows the engine to tune its parameters for the scale of the world, improving stability. }
PhysicsPlugins::default().with_length_unit(20.0), };
CharacterControllerPlugin,
)) #[cfg(all(feature = "client", not(feature = "server")))]
.add_systems(Startup, setup) let mode = cli.mode.unwrap_or(cli::Mode::Client);
.add_systems(Update, debug_border) #[cfg(all(feature = "server", not(feature = "client")))]
.add_systems(EguiPrimaryContextPass, connection_ui) let mode = cli.mode.unwrap_or(cli::Mode::Server);
.insert_resource(Gravity(Vector::ZERO)) #[cfg(all(feature = "client", feature = "server"))]
.run(); let mode = cli.mode.unwrap_or(cli::Mode::Host);
#[cfg(all(not(feature = "client"), not(feature = "server")))]
panic!("You must enable either the client or server feature");
let mut app = App::new();
match mode {
#[cfg(feature = "server")]
cli::Mode::Headless => {
app.add_plugins((MinimalPlugins, net::server::GameServerPlugin));
}
#[cfg(feature = "server")]
cli::Mode::Server => {
app.add_plugins((DefaultPlugins, net::server::GameServerPlugin));
}
#[cfg(feature = "client")]
cli::Mode::Client => {
app.add_plugins((DefaultPlugins, net::client::GameClientPlugin));
}
#[cfg(all(feature = "client", feature = "server"))]
cli::Mode::Host => {
app.add_plugins((
DefaultPlugins,
net::server::GameServerPlugin,
net::client::GameClientPlugin,
));
}
}
app.add_plugins((
// Add physics plugins and specify a units-per-meter scaling factor, 1 meter = 20 pixels.
// The unit allows the engine to tune its parameters for the scale of the world, improving stability.
PhysicsPlugins::default().with_length_unit(20.0),
CharacterControllerPlugin,
))
.add_systems(Startup, setup)
.add_systems(Update, debug_border)
.insert_resource(Gravity(Vector::ZERO))
.run();
} }
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) { fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
@@ -57,12 +103,3 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
fn debug_border(mut gizmos: Gizmos) { fn debug_border(mut gizmos: Gizmos) {
gizmos.rect_2d(Isometry2d::IDENTITY, Vec2::new(1920., 1080.), GREEN); gizmos.rect_2d(Isometry2d::IDENTITY, Vec2::new(1920., 1080.), GREEN);
} }
fn connection_ui(mut contexts: EguiContexts) -> Result {
let mut text = String::from("hello");
egui::Window::new("Connection").show(contexts.ctx_mut()?, |ui| {
ui.label("connection:");
ui.text_edit_singleline(&mut text)
});
Ok(())
}
+18
View File
@@ -0,0 +1,18 @@
use bevy::prelude::*;
pub struct GameClientPlugin;
impl Plugin for GameClientPlugin {
fn build(&self, app: &mut App) {
// app.add_systems(
// FixedPreUpdate,
// // Inputs have to be buffered in the WriteClientInputs set
// buffer_input.in_set(InputSystems::WriteClientInputs),
// );
// app.add_systems(FixedUpdate, player_movement);
// app.add_systems(Update, receive_message1);
// app.add_observer(handle_predicted_spawn);
// app.add_observer(handle_interpolated_spawn);
}
}
+6
View File
@@ -0,0 +1,6 @@
#[cfg(feature = "client")]
pub mod client;
pub mod protocol;
#[cfg(feature = "server")]
pub mod server;
pub mod shared;
+30
View File
@@ -0,0 +1,30 @@
use bevy::prelude::*;
#[derive(Clone)]
pub struct ProtocolPlugin;
impl Plugin for ProtocolPlugin {
fn build(&self, app: &mut App) {
// messages
app.register_message::<Message1>()
.add_direction(NetworkDirection::ServerToClient);
// inputs
app.add_plugins(input::native::InputPlugin::<Inputs>::default());
// components
app.register_component::<PlayerId>();
app.register_component::<PlayerPosition>()
.add_prediction()
.add_linear_interpolation();
app.register_component::<PlayerColor>();
// channels
app.add_channel::<Channel1>(ChannelSettings {
mode: ChannelMode::OrderedReliable(ReliableSettings::default()),
..default()
})
.add_direction(NetworkDirection::ServerToClient);
}
}
+13
View File
@@ -0,0 +1,13 @@
use bevy::prelude::*;
pub struct GameServerPlugin;
impl Plugin for GameServerPlugin {
fn build(&self, app: &mut App) {
// // the physics/FixedUpdates systems that consume inputs should be run in this set.
// app.add_systems(FixedUpdate, movement);
// app.add_observer(handle_new_client);
// app.add_observer(handle_connected);
// app.add_systems(Update, send_message);
}
}
+1
View File
@@ -0,0 +1 @@