This commit is contained in:
Mitchell Marino 2025-01-14 20:41:09 -06:00
parent 075ccc5a55
commit 7b727d797c
13 changed files with 2305 additions and 567 deletions

1356
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@ edition = "2021"
[dependencies]
avian3d = "0.1.2"
bevy = { version = "0.14.2", features = ["jpeg"] }
bevy = { version = "0.14", features = ["jpeg"] }
bevy_dolly = "0.0.4"
bevy_editor_pls = "0.10.0"
blenvy = "0.1.0-alpha.1"
@ -14,6 +14,8 @@ clap = { version = "4.5.20", features = ["derive"] }
lazy_static = "1.5.0"
lightyear = { version = "0.17.1", features = ["avian3d"] }
serde = { version = "1.0.213", features = ["derive"] }
bevy-steamworks = { version = "0.12", features = ["serde"] }
bevy_framepace = "0.17.0"
[profile.dev.package."*"]
opt-level = 3

Binary file not shown.

Binary file not shown.

View File

@ -1,10 +1,6 @@
(
assets:
[
("Player", File ( path: "blueprints/Player.glb" )),
("glasses.001", File ( path: "materials/glasses.001.glb" )),
("head.001", File ( path: "materials/head.001.glb" )),
("body.001", File ( path: "materials/body.001.glb" )),
("Hotel", File ( path: "blueprints/Hotel.glb" )),
("floor", File ( path: "materials/floor.glb" )),
]

File diff suppressed because it is too large Load Diff

1
launch.sh Executable file
View File

@ -0,0 +1 @@
cargo r || ~/rust/crooks/target/debug/crooks

View File

@ -2,11 +2,30 @@
use avian3d::{math::*, prelude::*};
use bevy::{ecs::query::Has, prelude::*, window::PrimaryWindow};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Debug, Hash, Resource)]
pub enum GameCursorMode {
#[default]
Locked,
Unlocked,
}
impl GameCursorMode {
#[must_use]
pub fn switch(self) -> Self {
match self {
GameCursorMode::Locked => GameCursorMode::Unlocked,
GameCursorMode::Unlocked => GameCursorMode::Locked,
}
}
}
pub struct CharacterControllerPlugin;
impl Plugin for CharacterControllerPlugin {
fn build(&self, app: &mut App) {
app.add_event::<MovementAction>()
app.insert_resource(GameCursorMode::default())
.add_event::<MovementAction>()
.add_systems(Update, set_cursor_vis)
.add_systems(
Update,
(
@ -105,6 +124,24 @@ impl MovementBundle {
}
}
fn set_cursor_vis(
buttons: Res<ButtonInput<MouseButton>>,
mut cursor_mode: ResMut<GameCursorMode>,
mut q_windows: Query<&mut Window, With<PrimaryWindow>>,
) {
let right_clicked = buttons.just_pressed(MouseButton::Right);
if right_clicked {
*cursor_mode = cursor_mode.switch();
}
if right_clicked || cursor_mode.is_changed() {
if let Ok(mut window) = q_windows.get_single_mut() {
window.cursor.visible = *cursor_mode == GameCursorMode::Unlocked;
}
}
}
impl Default for MovementBundle {
fn default() -> Self {
Self::new(30.0, 0.9, 7.0, PI * 0.45)
@ -146,9 +183,13 @@ impl CharacterControllerBundle {
}
fn cursor_input(
cursor_mode: Res<GameCursorMode>,
mut q_windows: Query<&mut Window, With<PrimaryWindow>>,
mut ew_movement: EventWriter<MovementAction>,
) {
if *cursor_mode == GameCursorMode::Unlocked {
return;
}
let mut window = q_windows.single_mut();
let window_center = window.size() / 2.;

View File

@ -1,14 +1,19 @@
use bevy::prelude::*;
use lightyear::prelude::ClientConnectEvent;
use lightyear::prelude::{client::ClientCommands, ClientConnectEvent};
pub struct MyClientPlugin;
impl Plugin for MyClientPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Update, handle_events);
app.add_systems(Startup, connect_to_server)
.add_systems(Update, handle_events);
}
}
pub fn connect_to_server(mut commands: Commands) {
commands.connect_client();
}
pub fn handle_events(
mut er_client_events: EventReader<ClientConnectEvent>,
// mut er_server_events: EventReader<ServerConnectEvent>,

View File

@ -1,5 +1,6 @@
use avian3d::prelude::PhysicsDebugPlugin;
use avian3d::PhysicsPlugins;
use bevy::log::LogPlugin;
use bevy::prelude::*;
use bevy_editor_pls::prelude::*;
use blenvy::BlenvyPlugin;
@ -20,6 +21,9 @@ lazy_static::lazy_static! {
};
}
const LOG_FILTER: &str = "wgpu=error,naga=warn,blenvy=warn";
// const LOG_FILTER: &str = "wgpu=error,naga=warn,blenvy=warn,lightyear=debug";
#[derive(Parser)]
#[command(version, about, long_about = None)]
pub struct Cli {
@ -40,25 +44,35 @@ fn main() {
#[cfg(feature = "client")]
let app = app
.add_plugins(DefaultPlugins)
// .add_plugins(SteamworksPlugin::init_app(480).unwrap())
.add_plugins(DefaultPlugins.set(LogPlugin {
filter: LOG_FILTER.to_string(),
level: bevy::log::Level::INFO,
custom_layer: |_| None,
}))
.add_plugins(lightyear::client::plugin::ClientPlugins::new(
shared_net::client_config(),
))
.add_plugins(EditorPlugin::default())
.add_plugins(bevy_framepace::FramepacePlugin)
.add_plugins(client::MyClientPlugin);
#[cfg(feature = "server")]
app.add_plugins(
DefaultPlugins.build(), // disable some plugins on the server
// .disable::<RenderPlugin>()
// .disable::<PbrPlugin>()
// .disable::<CorePipelinePlugin>()
// .disable::<ImagePlugin>()
// .disable::<TextPlugin>()
// .disable::<SpritePlugin>()
// .disable::<WindowPlugin>()
// .disable::<WinitPlugin>()
// .disable::<GizmoPlugin>()
DefaultPlugins.build().set(LogPlugin {
filter: LOG_FILTER.to_string(),
level: bevy::log::Level::INFO,
custom_layer: |_| None,
}), // disable some plugins on the server
// .disable::<RenderPlugin>()
// .disable::<PbrPlugin>()
// .disable::<CorePipelinePlugin>()
// .disable::<ImagePlugin>()
// .disable::<TextPlugin>()
// .disable::<SpritePlugin>()
// .disable::<WindowPlugin>()
// .disable::<WinitPlugin>()
// .disable::<GizmoPlugin>()
)
.add_plugins(lightyear::server::plugin::ServerPlugins::new(
shared_net::server_config(),
@ -73,7 +87,20 @@ fn main() {
CharacterControllerPlugin,
))
.add_plugins(protocol::ProtocolPlugin)
.add_plugins(BlenvyPlugin::default());
.add_plugins(BlenvyPlugin::default())
// .add_systems(Startup, steam_system);
;
app.run();
}
// fn steam_system(steam_client: Res<Client>) {
// for friend in steam_client.friends().get_friends(FriendFlags::IMMEDIATE) {
// println!(
// "Friend: {:?} - {}({:?})",
// friend.id(),
// friend.name(),
// friend.state()
// );
// }
// }

View File

@ -1,14 +1,19 @@
use bevy::prelude::*;
use lightyear::prelude::ServerConnectEvent;
use lightyear::prelude::{server::ServerCommands, ServerConnectEvent};
pub struct MyServerPlugin;
impl Plugin for MyServerPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Update, handle_events);
app.add_systems(Startup, start_server)
.add_systems(Update, handle_events);
}
}
pub fn start_server(mut commands: Commands) {
commands.start_server();
}
pub fn handle_events(mut er_server_events: EventReader<ServerConnectEvent>) {
for server_connect in er_server_events.read() {
println!("Server Connect: {:?}", server_connect);

View File

@ -1,9 +1,9 @@
use avian3d::{
math::{Scalar, Vector},
prelude::Collider,
prelude::{Collider, PhysicsSet},
};
use bevy::prelude::*;
use bevy_dolly::{prelude::Rig, system::Dolly};
use bevy_dolly::prelude::Rig;
use blenvy::{BlueprintInfo, GameWorldTag, HideUntilReady, SpawnBlueprint};
use crate::char_controller::CharacterControllerBundle;
@ -27,16 +27,22 @@ impl Plugin for SetupPlugin {
app.register_type::<Player>()
.register_type::<PlayerHead>()
.add_systems(Startup, setup)
// .add_systems(
// Update,
// (update_camera_rig, Dolly::<MainCamera>::update_active).chain(),
// )
.add_systems(
Update,
(update_camera_rig, Dolly::<MainCamera>::update_active),
)
// TODO: change to component hooks
.add_systems(Update, setup_player);
PostUpdate,
update_camera_location
.after(PhysicsSet::Sync)
.before(TransformSystem::TransformPropagate),
);
}
}
fn setup(mut commands: Commands) {
fn setup(world: &mut World) {
let mut commands = world.commands();
use bevy_dolly::prelude::*;
commands.spawn((
MainCamera, // The rig component tag
@ -45,9 +51,9 @@ fn setup(mut commands: Commands) {
// Adds a driver for rotation
.with(Rotation::new(Quat::IDENTITY))
// Interpolation when the translation is updated, also known as smoothing
.with(Smooth::new_position(0.3))
// .with(Smooth::new_position(0.03))
// Interpolation when the rotation is updated (updated via the YawPitch driver)
.with(Smooth::new_rotation(0.3))
// .with(Smooth::new_rotation(0.03))
// Moves the camera point out in the Z direction and uses the position as the pivot
// .with(Arm::new(Vec3::Z * 4.0))
.build(),
@ -92,23 +98,26 @@ fn setup(mut commands: Commands) {
HideUntilReady,
GameWorldTag,
));
}
fn setup_player(
mut commands: Commands,
q_player: Query<Entity, (With<Player>, Without<Collider>)>,
) {
let Ok(player_entity) = q_player.get_single() else {
return;
};
#[cfg(feature = "client")]
commands.spawn((
BlueprintInfo::from_path("blueprints/Player.glb"),
SpawnBlueprint,
HideUntilReady,
GameWorldTag,
));
commands.entity(player_entity).insert(
CharacterControllerBundle::new(
Collider::capsule_endpoints(1., Vec3::Y, Vec3::Y * 3.),
Vector::NEG_Y * 9.81 * 2.0,
)
.with_movement(30.0, 0.92, 7.0, (30.0 as Scalar).to_radians()),
);
world
.register_component_hooks::<Player>()
.on_add(|mut world, e, _| {
world.commands().entity(e).insert(
CharacterControllerBundle::new(
Collider::capsule_endpoints(1., Vec3::Y, Vec3::Y * 3.),
Vector::NEG_Y * 9.81 * 2.0,
)
.with_movement(30.0, 0.92, 7.0, (30.0 as Scalar).to_radians()),
);
});
}
fn update_camera_rig(
@ -129,3 +138,21 @@ fn update_camera_rig(
d_pos.position = pos;
}
}
fn update_camera_location(
q_player_head: Query<&GlobalTransform, (With<PlayerHead>, Without<Camera>)>,
mut q_camera: Query<&mut Transform, (With<Camera>, With<MainCamera>)>,
) {
let Ok(player_head_transform) = q_player_head.get_single() else {
warn!("No player head!");
return;
};
let Ok(mut camera_transform) = q_camera.get_single_mut() else {
warn!("No main camera!");
return;
};
let (_, rot, pos) = player_head_transform.to_scale_rotation_translation();
camera_transform.translation = pos;
camera_transform.rotation = rot;
}

View File

@ -6,17 +6,19 @@ use std::time::Duration;
pub const PRIVIATE_KEY: Key = [12; 32];
pub const FIXED_TIMESTEP_HZ: f64 = 64.0;
pub const REPLICATION_INTERVAL: Duration = Duration::from_millis(100);
pub const LOCAL_IP: &str = "127.0.0.1:7000";
pub const ANY_IP: &str = "0.0.0.0:0";
pub fn client_config() -> ClientConfig {
let auth = Authentication::Manual {
server_addr: "127.0.0.1:7000".parse().unwrap(),
server_addr: "127.0.0.1:7001".parse().unwrap(),
client_id: 2,
private_key: PRIVIATE_KEY,
protocol_id: 0,
};
let netcode_config = client::NetcodeConfig::default();
let io_config = client::IoConfig {
transport: client::ClientTransport::UdpSocket("127.0.0.1:7000".parse().unwrap()),
transport: client::ClientTransport::UdpSocket(ANY_IP.parse().unwrap()),
conditioner: None,
compression: CompressionConfig::default(),
};
@ -33,9 +35,13 @@ pub fn client_config() -> ClientConfig {
}
pub fn server_config() -> ServerConfig {
let netcode_config = server::NetcodeConfig::default();
let netcode_config = server::NetcodeConfig {
protocol_id: 0,
private_key: PRIVIATE_KEY,
..Default::default()
};
let io_config = server::IoConfig {
transport: server::ServerTransport::UdpSocket("127.0.0.1:7000".parse().unwrap()),
transport: server::ServerTransport::UdpSocket(LOCAL_IP.parse().unwrap()),
conditioner: None,
compression: CompressionConfig::default(),
};