#![warn(clippy::pedantic)] // Be annoying, and disable specific irritating lints if needed
#![deny(
clippy::allow_attributes_without_reason,
clippy::assertions_on_result_states
)]
#![warn(clippy::if_then_some_else_none)]
#![allow(clippy::type_complexity, reason = "Bevy makes this a nightmare")]
#![allow(clippy::needless_pass_by_value, reason = "Bevy makes this a nightmare")]
#![allow(
clippy::cast_precision_loss,
clippy::cast_possible_truncation,
clippy::cast_sign_loss,
reason = "We cast ints to floats a lot"
)]
#![allow(clippy::missing_panics_doc, reason = "Gamedev! We panic a lot")]
#![allow(clippy::too_many_arguments, reason = "Le Bevy:tm:")]
#![allow(
clippy::too_many_lines,
reason = "With the three of us, this is impossible"
)]
pub mod attachment;
pub mod client;
pub mod client_plugins;
pub mod config;
pub mod ecs;
#[cfg(all(not(target_arch = "wasm32"), feature = "particle_editor"))]
pub mod particle_editor;
pub mod particles;
#[cfg(all(not(target_arch = "wasm32"), feature = "native"))]
pub mod server;
#[cfg(all(not(target_arch = "wasm32"), feature = "native"))]
pub mod server_plugins;
pub mod shared_plugins;
pub mod physics;
pub mod prelude;
#[cfg(target_arch = "wasm32")]
pub mod wasm_entrypoint;
#[cfg(target_arch = "wasm32")]
pub use wasm_entrypoint::*;
use bevy::log::{tracing_subscriber, LogPlugin};
use crate::prelude::*;
use clap::Parser;
use crate::client_plugins::ClientPluginGroup;
#[cfg(not(target_arch = "wasm32"))]
use crate::server_plugins::ServerPluginGroup;
use std::net::SocketAddr;
use std::process::exit;
use std::str::FromStr;
use std::time::Duration;
use bevy::app::ScheduleRunnerPlugin;
use bevy::diagnostic::FrameCountPlugin;
use bevy::state::app::StatesPlugin;
use bevy::time::TimePlugin;
use bevy::ui::UiPlugin;
use tracing_subscriber::EnvFilter;
use tracing_subscriber::filter::Directive;
use tracing_subscriber::util::SubscriberInitExt;
use crate::shared_plugins::SharedPluginGroup;
#[derive(Parser, Debug, Clone)]
#[command(version, about)]
enum Cli {
Client {
#[arg(short, long)]
server: String,
#[arg(long, action)]
hotpatching_enabled: bool,
},
#[cfg(not(target_arch = "wasm32"))]
Server {
#[arg(short = 'b', long)]
bind: SocketAddr,
#[arg(short = 'r', long)]
tick_rate: f32,
#[arg(short = 'C', long)]
max_clients: usize,
#[arg(long, action)]
with_client: bool,
#[arg(long, action)]
hotpatching_enabled: bool
},
#[cfg(all(not(target_arch = "wasm32"), feature = "particle_editor"))]
ParticleEditor {},
}
fn run(cli: Cli) -> AppExit {
let mut app = App::new();
match cli {
Cli::Client { server, hotpatching_enabled } => {
if hotpatching_enabled {
warn!("-+-+-+-+-+-+- Starting with hotpatching enabled -+-+-+-+-+-+-");
warn!("This can result in segfaults and inconsistent behavior! If there is weirdness, try disabling it.");
warn!("-+-+-+-+-+-+- Starting with hotpatching enabled -+-+-+-+-+-+-");
}
app.add_plugins(
DefaultPlugins.build()
.disable::<LogPlugin>()
.disable::<UiPlugin>()
);
app.add_plugins(ClientPluginGroup { server: Some(server) });
app.add_plugins(SharedPluginGroup);
}
#[cfg(not(target_arch = "wasm32"))]
Cli::Server {
bind,
tick_rate,
max_clients,
hotpatching_enabled,
with_client
} => {
if hotpatching_enabled {
warn!("-+-+-+-+-+-+- Starting with hotpatching enabled -+-+-+-+-+-+-");
warn!("This can result in segfaults and inconsistent behavior! If there is weirdness, try disabling it.");
warn!("-+-+-+-+-+-+- Starting with hotpatching enabled -+-+-+-+-+-+-");
}
if cfg!(target_family = "wasm") {
eprintln!("the server cannot run on webassembly");
exit(1);
}
if with_client {
app.add_plugins(
DefaultPlugins.build()
.disable::<LogPlugin>()
.disable::<UiPlugin>()
);
app.add_plugins(|app: &mut App| {
app.add_systems(Startup, crate::server::player::join::ls_magically_invent_player);
});
} else {
app
.add_plugins(AssetPlugin::default())
.add_plugins(StatesPlugin)
.add_plugins(TaskPoolPlugin::default())
.add_plugins(FrameCountPlugin)
.add_plugins(TimePlugin)
.add_plugins(ScheduleRunnerPlugin::run_loop(Duration::from_secs_f32(
1.0 / tick_rate,
)));
}
app.add_plugins(SharedPluginGroup);
let mut pg = ServerPluginGroup {
bind,
tick_rate,
max_clients,
}.build();
if with_client {
pg = pg.add_group(ClientPluginGroup {
server: None
});
}
app.add_plugins(pg);
}
#[cfg(all(not(target_arch = "wasm32"), feature = "particle_editor"))]
Cli::ParticleEditor {} => {
app.add_plugins(crate::particle_editor::particle_editor_plugin);
}
}
app.run()
}
#[cfg(feature = "wasm")]
fn main() {
// noop
}
#[cfg(feature = "native")]
fn main() -> AppExit {
let cli = Cli::parse();
tracing_subscriber::fmt()
.with_env_filter(
EnvFilter::from_default_env().add_directive(Directive::from_str("naga=error").unwrap()),
)
.finish()
.init();
#[cfg(feature = "native")] {
ctrlc::set_handler(|| {
info!("caught ^C, ciao!");
exit(0);
}).unwrap();
}
run(cli)
}