mirror of
https://github.com/griffi-gh/kubi.git
synced 2024-11-21 14:28:43 -06:00
Implement saving on the server-side
This commit is contained in:
parent
63e26e3a5b
commit
1b89756648
|
@ -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();
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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> {
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue