Implement saving on the server-side

This commit is contained in:
griffi-gh 2024-09-11 11:28:37 +02:00
parent 63e26e3a5b
commit 1b89756648
7 changed files with 79 additions and 27 deletions

View file

@ -50,7 +50,7 @@ pub fn sync_client_positions(
};
//log movement (annoying duh)
log::debug!("dbg: player moved id: {} coords: {} quat: {}", message.client_id, position, direction);
// log::debug!("dbg: player moved id: {} coords: {} quat: {}", message.client_id, position, direction);
//Apply position to server-side client
let mut trans = (&mut transforms).get(message.entity_id).unwrap();

View file

@ -1,6 +1,6 @@
use shipyard::{IntoWorkload, Workload, WorkloadModificator, World};
use shipyard::{IntoWorkload, SystemModificator, Workload, WorkloadModificator, World};
use std::{thread, time::Duration};
use kubi_shared::fixed_timestamp::init_fixed_timestamp_storage;
use kubi_shared::fixed_timestamp::{FixedTimestamp, init_fixed_timestamp_storage};
mod util;
mod config;
@ -13,7 +13,7 @@ use config::read_config;
use server::{bind_server, update_server, log_server_errors};
use client::{init_client_maps, on_client_disconnect, sync_client_positions};
use auth::authenticate_players;
use world::{update_world, init_world};
use world::{init_world, save::save_modified, update_world};
fn initialize() -> Workload {
(
@ -34,7 +34,10 @@ fn update() -> Workload {
update_world,
sync_client_positions,
on_client_disconnect,
).into_workload()
).into_workload(),
save_modified
.into_workload()
.make_fixed(10000, 0),
).into_sequential_workload()
}

View file

@ -250,7 +250,11 @@ fn process_block_queue(
let Some(blocks) = &mut chunk.blocks else {
return true
};
blocks[block_position.x as usize][block_position.y as usize][block_position.z as usize] = item.block_type;
let block = &mut blocks[block_position.x as usize][block_position.y as usize][block_position.z as usize];
if item.block_type != *block {
*block = item.block_type;
chunk.data_modified = true;
}
false
});
if initial_len != queue.queue.len() {

View file

@ -16,13 +16,16 @@ pub struct Chunk {
pub state: ChunkState,
pub blocks: Option<BlockData>,
pub subscriptions: HashSet<ClientId, BuildNoHashHasher<ClientId>>,
pub data_modified: bool,
}
impl Chunk {
pub fn new() -> Self {
Self {
state: ChunkState::Nothing,
blocks: None,
subscriptions: HashSet::with_capacity_and_hasher(4, BuildNoHashHasher::default()),
data_modified: false,
}
}
}

View file

@ -1,7 +1,10 @@
use kubi_shared::data::{io_thread::IOThreadManager, open_local_save_file};
use shipyard::{AllStoragesView, UniqueView};
use shipyard::{AllStoragesView, UniqueView, UniqueViewMut};
use crate::config::ConfigTable;
use super::{
tasks::{ChunkTask, ChunkTaskManager},
ChunkManager,
};
pub fn init_save_file(storages: &AllStoragesView) -> Option<IOThreadManager> {
let config = storages.borrow::<UniqueView<ConfigTable>>().unwrap();
@ -14,3 +17,27 @@ pub fn init_save_file(storages: &AllStoragesView) -> Option<IOThreadManager> {
None
}
}
pub fn save_modified(
mut chunks: UniqueViewMut<ChunkManager>,
ctm: UniqueView<ChunkTaskManager>,
) {
log::info!("Saving...");
let mut amount_saved = 0;
for (position, chunk) in chunks.chunks.iter_mut() {
if chunk.data_modified {
let Some(data) = chunk.blocks.clone() else {
continue
};
ctm.run(ChunkTask::SaveChunk {
position: *position,
data: data,
});
chunk.data_modified = false;
amount_saved += 1;
}
}
if amount_saved > 0 {
log::info!("Queued {} chunks for saving", amount_saved);
}
}

View file

@ -12,7 +12,11 @@ pub enum ChunkTask {
LoadChunk {
position: IVec3,
seed: u64,
}
},
SaveChunk {
position: IVec3,
data: BlockData,
},
}
pub enum ChunkTaskResponse {
@ -40,27 +44,35 @@ impl ChunkTaskManager {
}
pub fn run(&self, task: ChunkTask) {
// 1. Check if the chunk exists in the save file
#[allow(irrefutable_let_patterns)]
if let ChunkTask::LoadChunk { position, .. } = &task {
if let Some(iota) = &self.iota {
if iota.chunk_exists(*position) {
iota.send(IOCommand::LoadChunk { position: *position });
match task {
ChunkTask::LoadChunk { position: chunk_position, seed } => {
// 1. Check if the chunk exists in the save file
if let ChunkTask::LoadChunk { position, .. } = &task {
if let Some(iota) = &self.iota {
if iota.chunk_exists(*position) {
iota.send(IOCommand::LoadChunk { position: *position });
return
}
}
}
}
}
// 2. Generate the chunk if it doesn't exist
let sender = self.channel.0.clone();
self.pool.spawn(move || {
sender.send(match task {
ChunkTask::LoadChunk { position: chunk_position, seed } => {
//unwrap is fine because abort is not possible
let (blocks, queue) = generate_world(chunk_position, seed, None).unwrap();
ChunkTaskResponse::ChunkLoaded { chunk_position, blocks, queue }
// 2. Generate the chunk if it doesn't exist
let sender = self.channel.0.clone();
self.pool.spawn(move || {
sender.send({
//unwrap is fine because abort is not possible
let (blocks, queue) = generate_world(chunk_position, seed, None).unwrap();
ChunkTaskResponse::ChunkLoaded { chunk_position, blocks, queue }
}).unwrap()
});
},
ChunkTask::SaveChunk { position, data } => {
// Save the chunk to the save file
if let Some(iota) = &self.iota {
iota.send(IOCommand::SaveChunk { position, data });
}
}).unwrap()
})
},
}
}
pub fn receive(&self) -> Option<ChunkTaskResponse> {

View file

@ -22,6 +22,9 @@ pub fn apply_queued_blocks(
if event.soft && *block != Block::Air {
return false
}
if event.block_type == *block {
return false
}
*block = event.block_type;
//mark chunk as dirty
let (chunk_pos, block_pos) = ChunkStorage::to_chunk_coords(event.position);