Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions src/client/chat/systems.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,21 +55,23 @@ pub fn chat_state_transition_system(
mut chat_state: ResMut<chat_resources::ChatState>,
) {
let current_state_value = current_state.get();
let mut next_state_value = current_state_value.clone();

if *current_state_value == GameState::WaitingForServer || *current_state_value == GameState::LoadingSpawnArea {
// TODO: Introduce Chatting Substate
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be implemented in a follow up PR alongside a rework of events

return;
}

if keyboard_input.just_pressed(KeyCode::KeyT) {
info!("Focusing chat via KeyT");
if *current_state_value == GameState::Playing {
chat_state.just_focused = true;
next_state_value = GameState::Chatting;
next_state.set(GameState::Chatting);
}
}
if keyboard_input.just_pressed(KeyCode::Escape) && *current_state_value == GameState::Chatting {
info!("Unfocusing chat via Escape");
next_state_value = GameState::Playing;
next_state.set(GameState::Playing);
}

next_state.set(next_state_value);
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one was annoying to catch. it wasn't possible to transition from WorldLoading to Playing.

  1. world loading check system sets next state to Playing after realizing that the world is loaded
  2. same tick, this system overrides the next state with the current state
  3. world never enters playing

}

pub fn process_chat_input_system(
Expand Down
4 changes: 2 additions & 2 deletions src/client/collider/systems.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ use terrain_util::client_block::block_properties;
use crate::prelude::*;

static COLLIDER_GRID_SIZE: u32 = 4;
static COLLIDER_RESTING_POSITION: Vec3 = Vec3::ZERO;
static COLLIDER_RESTING_POSITION: Vec3 = Vec3::MIN;
static COLLIDER_CUBOID_WIDTH: f32 = 1.0;

pub fn setup_coliders_system(mut commands: Commands) {
let collider_range = 0..COLLIDER_GRID_SIZE;

commands.spawn((
Collider::cuboid(256.0, 1.0, 256.0),
Transform::from_xyz(0.0, 0.0, 0.0),
Transform::from_translation(COLLIDER_RESTING_POSITION),
));

for x in collider_range.clone() {
Expand Down
3 changes: 2 additions & 1 deletion src/client/gui/systems.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ pub fn handle_debug_state_transition_system(
) {
if key_input.just_pressed(KeyCode::Tab) {
match *current_state.get() {
GameState::WaitingForServer => {}
GameState::LoadingSpawnArea => {},
GameState::WaitingForServer => {},
GameState::Playing => next_state.set(GameState::Debugging),
GameState::Chatting => next_state.set(GameState::Debugging),
GameState::Debugging => next_state.set(GameState::Playing),
Expand Down
9 changes: 2 additions & 7 deletions src/client/networking/systems.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ pub fn receive_message_system(
#[cfg(feature = "chat")] mut single_chat_events: ResMut<
Messages<chat_events::SingleChatSendEvent>,
>,
mut spawn_area_loaded: ResMut<terrain_resources::SpawnAreaLoaded>,
mut exit_events: MessageWriter<AppExit>,
mut next_state: ResMut<NextState<GameState>>,
) {
Expand All @@ -40,7 +39,8 @@ pub fn receive_message_system(
}
NetworkingMessage::PlayerAccept(player_state) => {
commands.insert_resource(player_resources::LocalPlayerSpawnState(player_state));
next_state.set(GameState::Playing);
commands.insert_resource(terrain_resources::SpawnArea{ origin: player_state.position.as_ivec3() });
next_state.set(GameState::LoadingSpawnArea);
}
NetworkingMessage::PlayerJoin(username) => {
player_spawn_events.write(remote_player_events::RemotePlayerSpawnedEvent {
Expand Down Expand Up @@ -102,11 +102,6 @@ pub fn receive_message_system(
chunk_manager.insert_chunk(chunk);
chunk_mesh_events
.write(terrain_events::ChunkMeshUpdateEvent { chunk_position });

if chunk_position.eq(&IVec3::ZERO) {
info!("Spawn area loaded.");
spawn_area_loaded.0 = true;
}
}
}
NetworkingMessage::PlayerSync(event) => {
Expand Down
12 changes: 4 additions & 8 deletions src/client/player/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,20 @@ impl Plugin for PlayerPlugin {
app.insert_resource(player_resources::PlayerSpawned(false));
app.insert_resource(player_resources::LastPlayerPosition::new());
app.add_systems(
Startup,
OnExit(GameState::LoadingSpawnArea),
(
player_systems::setup_highlight_cube_system,
player_systems::setup_player_camera,
),
);
app.add_systems(
Update,
(player_systems::setup_controller_on_area_ready_system,)
.run_if(terrain_resources::SpawnAreaLoaded::is_loaded)
.run_if(player_resources::PlayerSpawned::is_not_spawned),
player_systems::setup_controller_on_area_ready_system
).chain(),
);
app.add_systems(
Update,
(
player_systems::handle_controller_movement_system,
player_systems::handle_player_collider_events_system,
)
.run_if(terrain_resources::SpawnAreaLoaded::is_loaded) // TODO: doublecheck
.run_if(player_resources::PlayerSpawned::is_spawned),
);
app.add_systems(
Expand Down
16 changes: 14 additions & 2 deletions src/client/player/resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ impl BlockSelection {
}

#[derive(Resource)]
pub struct LastPlayerPosition(pub Vec3);
pub struct LastPlayerPosition(pub IVec3);

impl Default for LastPlayerPosition {
fn default() -> Self {
Expand All @@ -45,7 +45,19 @@ impl Default for LastPlayerPosition {

impl LastPlayerPosition {
pub fn new() -> Self {
Self(Vec3::ZERO)
Self(IVec3::ZERO)
}

pub fn chunk_position(&self) -> IVec3 {
Self::chunk_pos(self.0)
}

pub fn has_same_chunk_position_as(&self, other_world_position: IVec3) -> bool {
Self::chunk_pos(self.0) == Self::chunk_pos(other_world_position)
}

fn chunk_pos(world_pos: IVec3) -> IVec3 {
ChunkManager::world_position_to_chunk_position(world_pos)
}
}

Expand Down
24 changes: 20 additions & 4 deletions src/client/player/systems/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,31 @@ pub fn handle_controller_movement_system(
query: Query<(Entity, &FpsControllerInput, &Transform)>,
mut last_position: ResMut<player_resources::LastPlayerPosition>,
mut collider_events: MessageWriter<collider_events::ColliderUpdateEvent>,
mut terrain_events: MessageWriter<terrain_events::RerequestChunks>,
) {
for (_entity, _input, transform) in &mut query.iter() {
let controller_position = transform.translation;
if last_position.0.floor() != controller_position.floor() {
let controller_position: IVec3 = transform.translation.as_ivec3();

if last_position.0 != controller_position {
collider_events.write(collider_events::ColliderUpdateEvent {
grid_center_position: controller_position.floor().into(),
grid_center_position: [
// TODO: refactor colliders to use integers over floats
controller_position.x as f32,
controller_position.y as f32,
controller_position.z as f32,
],
});

if !last_position.has_same_chunk_position_as(controller_position) {
info!("Player moved out of chunk, rerequesting chunks for: {controller_position}");
terrain_events.write(terrain_events::RerequestChunks {
center_chunk_position: ChunkManager::world_position_to_chunk_position(
controller_position,
),
});
}
}
last_position.0 = controller_position.floor();
last_position.0 = controller_position;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/client/player/systems/selection.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::prelude::*;

const RAY_DIST: f32 = 20.0;
const HIGHLIGHT_CUBE_ORIGIN: Vec3 = Vec3::new(0.0, 2.0, 0.0);
const HIGHLIGHT_CUBE_ORIGIN: Vec3 = Vec3::MIN;

pub fn setup_highlight_cube_system(
mut commands: Commands,
Expand Down
4 changes: 3 additions & 1 deletion src/client/states.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use bevy::prelude::States;

#[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
#[derive(States, Debug, Clone, PartialEq, Eq, Hash, Default)]
pub enum GameState {
#[default]
WaitingForServer,
LoadingSpawnArea,
Chatting,
Debugging,
Playing,
Expand Down
10 changes: 10 additions & 0 deletions src/client/terrain/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ pub struct ChunkMeshUpdateEvent {
pub chunk_position: IVec3,
}

#[derive(Message)]
pub struct RerequestChunks {
pub center_chunk_position: IVec3,
}

#[derive(Message)]
pub struct RequestChunkBatch {
pub positions: Vec<IVec3>,
}

#[derive(Message)]
pub struct BlockUpdateEvent {
pub position: IVec3,
Expand Down
19 changes: 15 additions & 4 deletions src/client/terrain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@ impl Plugin for TerrainPlugin {
app.insert_resource(resources::RenderMaterials::new());
app.insert_resource(resources::MesherTasks::default());
app.insert_resource(resources::ChunkEntityMap::default());
app.insert_resource(resources::RequestedChunks::default());
app.insert_resource(resources::LastChunkRequestOrigin::default());
app.add_message::<terrain_events::BlockUpdateEvent>();
app.add_message::<terrain_events::ChunkMeshUpdateEvent>();
app.add_message::<terrain_events::WorldRegenerateEvent>();
app.add_message::<terrain_events::RerequestChunks>();
app.add_message::<terrain_events::RequestChunkBatch>();
app.add_systems(Startup, terrain_systems::prepare_mesher_materials_system);
#[cfg(feature = "skip_terrain")]
{
Expand All @@ -30,12 +34,13 @@ impl Plugin for TerrainPlugin {
app.insert_resource(terrain_resources::SpawnAreaLoaded(false));

app.add_systems(
OnExit(GameState::WaitingForServer),
terrain_systems::prepare_spawn_area_system,
OnEnter(GameState::LoadingSpawnArea),
terrain_systems::generate_world_system,
);
app.add_systems(
OnExit(GameState::WaitingForServer),
terrain_systems::generate_world_system,
Update,
(terrain_systems::check_if_spawn_area_is_loaded_system)
.run_if(in_state(GameState::LoadingSpawnArea)),
);
app.add_systems(
Update,
Expand All @@ -46,6 +51,12 @@ impl Plugin for TerrainPlugin {
terrain_systems::handle_terrain_regeneration_events_system,
);
app.add_systems(Update, terrain_systems::handle_chunk_tasks_system);
app.add_systems(Update, terrain_systems::handle_chunk_rerequests_system);
app.add_systems(
Update,
terrain_systems::handle_chunk_request_chunk_batch_event_system,
);
app.add_systems(Update, terrain_systems::cleanup_chunk_entities_system);
}
}
}
32 changes: 32 additions & 0 deletions src/client/terrain/resources.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::{collections::{HashSet, hash_map::ExtractIf}, option::Iter};

use bevy::tasks::Task;

use crate::prelude::*;
Expand All @@ -11,6 +13,15 @@ impl SpawnAreaLoaded {
}
}

#[derive(Resource, Default)]
pub struct RequestedChunks {
pub previous_chunks: HashSet<IVec3>,
}
#[derive(Resource, Default)]
pub struct LastChunkRequestOrigin {
pub position: IVec3
}

#[derive(Eq, Hash, Clone, PartialEq)]
pub enum MeshType {
Solid,
Expand Down Expand Up @@ -38,14 +49,35 @@ pub struct ChunkEntityMap {
map: HashMap<IVec3, Vec<Entity>>,
}

#[derive(Resource, Default)]
pub struct SpawnArea {
pub origin: IVec3
}

impl ChunkEntityMap {
pub fn count(&self) -> usize {
return self.map.iter().count()
}

pub fn add(&mut self, chunk_position: IVec3, entity: Entity) {
self.map.entry(chunk_position).or_default().push(entity);
}

pub fn remove(&mut self, chunk_position: IVec3) -> Option<Vec<Entity>> {
self.map.remove(&chunk_position)
}

pub fn extract_within_distance(&mut self, origin: &IVec3, distance: &IVec3) -> Vec<(IVec3, Vec<Entity>)> {
let extracted: HashMap<IVec3, Vec<Entity>> = self.map.extract_if(|k, _v| {
(k.x - origin.x) > distance.x
|| (k.y - origin.y) > distance.y
|| (k.z - origin.z) > distance.z
}).collect();

extracted.into_iter().map(|(key, entities)| {
(key, entities)
}).collect()
}
}

#[derive(Resource)]
Expand Down
Loading
Loading