implement auto-saving under reticles
This commit is contained in:
parent
4ba7e25510
commit
e0e64f7e24
2 changed files with 75 additions and 55 deletions
|
@ -324,34 +324,49 @@ impl SessionLoop {
|
||||||
wall::EventKind::Interact { interactions } => {
|
wall::EventKind::Interact { interactions } => {
|
||||||
let (done_tx, done_rx) = oneshot::channel();
|
let (done_tx, done_rx) = oneshot::channel();
|
||||||
|
|
||||||
if interactions
|
let chunks_to_modify: Vec<_> =
|
||||||
.iter()
|
chunks_to_modify(self.wall.settings(), interactions)
|
||||||
.any(|i| matches!(i, Interaction::SetBrush { .. }))
|
.into_iter()
|
||||||
{
|
.collect();
|
||||||
// SetBrush is an important event, so we wait for the render thread
|
match self.chunk_images.load(chunks_to_modify.clone()).await {
|
||||||
// to unload.
|
Ok(_) => {
|
||||||
_ = self
|
if interactions
|
||||||
.render_commands_tx
|
.iter()
|
||||||
.send(RenderCommand::Interact {
|
.any(|i| matches!(i, Interaction::SetBrush { .. }))
|
||||||
interactions: interactions.clone(),
|
{
|
||||||
done: done_tx,
|
// SetBrush is an important event, so we wait for the render thread
|
||||||
})
|
// to unload.
|
||||||
.await;
|
_ = self
|
||||||
} else {
|
.render_commands_tx
|
||||||
// If there is no SetBrush, there's no need to wait, so we fire events
|
.send(RenderCommand::Interact {
|
||||||
// blindly. If the thread's not okay with that... well, whatever.
|
interactions: interactions.clone(),
|
||||||
// That's your issue for making a really slow brush.
|
done: done_tx,
|
||||||
let send_result =
|
})
|
||||||
self.render_commands_tx.try_send(RenderCommand::Interact {
|
.await;
|
||||||
interactions: interactions.clone(),
|
} else {
|
||||||
done: done_tx,
|
// If there is no SetBrush, there's no need to wait, so we fire events
|
||||||
|
// blindly. If the thread's not okay with that... well, whatever.
|
||||||
|
// That's your issue for making a really slow brush.
|
||||||
|
let send_result =
|
||||||
|
self.render_commands_tx.try_send(RenderCommand::Interact {
|
||||||
|
interactions: interactions.clone(),
|
||||||
|
done: done_tx,
|
||||||
|
});
|
||||||
|
if send_result.is_err() {
|
||||||
|
info!(
|
||||||
|
?interactions,
|
||||||
|
"render thread is overloaded, dropping interaction request"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let auto_save = Arc::clone(&self.auto_save);
|
||||||
|
tokio::spawn(async move {
|
||||||
|
_ = done_rx.await;
|
||||||
|
auto_save.request(chunks_to_modify).await;
|
||||||
});
|
});
|
||||||
if send_result.is_err() {
|
|
||||||
info!(
|
|
||||||
?interactions,
|
|
||||||
"render thread is overloaded, dropping interaction request"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
Err(err) => error!(?err, "while loading chunks for render command"),
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Auto save. This'll need us to compute which chunks will be affected
|
// TODO: Auto save. This'll need us to compute which chunks will be affected
|
||||||
|
@ -501,12 +516,10 @@ impl SessionLoop {
|
||||||
|
|
||||||
Interaction::Dotter { from, to, num } => {
|
Interaction::Dotter { from, to, num } => {
|
||||||
if brush_ok {
|
if brush_ok {
|
||||||
if let Some(trampoline) =
|
if let Some(tramp) = jumpstart_trampoline(&mut haku, &mut trampoline) {
|
||||||
jumpstart_trampoline(&mut haku, &mut trampoline)
|
let cont = haku.cont(tramp);
|
||||||
{
|
|
||||||
let cont = haku.cont(trampoline);
|
|
||||||
if cont == Cont::Dotter {
|
if cont == Cont::Dotter {
|
||||||
_ = haku.dotter(trampoline, from, to, num);
|
_ = haku.dotter(tramp, from, to, num);
|
||||||
} else {
|
} else {
|
||||||
error!("received Dotter interaction when a {cont:?} continuation was next");
|
error!("received Dotter interaction when a {cont:?} continuation was next");
|
||||||
}
|
}
|
||||||
|
@ -562,6 +575,29 @@ fn render_area(wall_settings: &wall::Settings, interaction: &Interaction) -> Opt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn chunks_to_modify(
|
||||||
|
wall_settings: &wall::Settings,
|
||||||
|
interactions: &[Interaction],
|
||||||
|
) -> HashSet<ChunkPosition> {
|
||||||
|
let mut chunks = HashSet::new();
|
||||||
|
|
||||||
|
for interaction in interactions {
|
||||||
|
// NOTE: This is mostly a tentative overestimation, and can result in more chunks being
|
||||||
|
// marked as needing autosave than will be touched in reality.
|
||||||
|
// It's better to play safe in this case than lose data.
|
||||||
|
if let Some(render_area) = render_area(wall_settings, interaction) {
|
||||||
|
let top_left_chunk = wall_settings.chunk_at(render_area.top_left);
|
||||||
|
let bottom_right_chunk = wall_settings.chunk_at_ceil(render_area.bottom_right);
|
||||||
|
for chunk_y in top_left_chunk.y..bottom_right_chunk.y {
|
||||||
|
for chunk_x in top_left_chunk.x..bottom_right_chunk.x {
|
||||||
|
chunks.insert(ChunkPosition::new(chunk_x, chunk_y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chunks
|
||||||
|
}
|
||||||
fn jumpstart_trampoline<'a>(
|
fn jumpstart_trampoline<'a>(
|
||||||
haku: &mut Haku,
|
haku: &mut Haku,
|
||||||
trampoline: &'a mut Option<Trampoline>,
|
trampoline: &'a mut Option<Trampoline>,
|
||||||
|
@ -572,25 +608,6 @@ fn jumpstart_trampoline<'a>(
|
||||||
trampoline.as_mut()
|
trampoline.as_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn chunks_to_modify(wall: &Wall, points: &[Vec2]) -> HashSet<ChunkPosition> {
|
|
||||||
let mut chunks = HashSet::new();
|
|
||||||
for point in points {
|
|
||||||
let paint_area = wall.settings().paint_area as f32;
|
|
||||||
let left = point.x - paint_area / 2.0;
|
|
||||||
let top = point.y - paint_area / 2.0;
|
|
||||||
let top_left_chunk = wall.settings().chunk_at(Vec2::new(left, top));
|
|
||||||
let bottom_right_chunk = wall
|
|
||||||
.settings()
|
|
||||||
.chunk_at_ceil(Vec2::new(left + paint_area, top + paint_area));
|
|
||||||
for chunk_y in top_left_chunk.y..bottom_right_chunk.y {
|
|
||||||
for chunk_x in top_left_chunk.x..bottom_right_chunk.x {
|
|
||||||
chunks.insert(ChunkPosition::new(chunk_x, chunk_y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
chunks
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(skip(wall, haku, value))]
|
#[instrument(skip(wall, haku, value))]
|
||||||
fn draw_to_chunks(
|
fn draw_to_chunks(
|
||||||
wall: &Wall,
|
wall: &Wall,
|
||||||
|
|
|
@ -5,7 +5,7 @@ use tokio::{
|
||||||
sync::mpsc,
|
sync::mpsc,
|
||||||
time::{interval, MissedTickBehavior},
|
time::{interval, MissedTickBehavior},
|
||||||
};
|
};
|
||||||
use tracing::instrument;
|
use tracing::{info, instrument};
|
||||||
|
|
||||||
use super::{chunk_images::ChunkImages, ChunkPosition};
|
use super::{chunk_images::ChunkImages, ChunkPosition};
|
||||||
|
|
||||||
|
@ -77,9 +77,12 @@ impl AutoSaveLoop {
|
||||||
// NOTE: We don't care about actually using the images here -
|
// NOTE: We don't care about actually using the images here -
|
||||||
// the ChunkImages service writes them to the database by itself, and that's all our
|
// the ChunkImages service writes them to the database by itself, and that's all our
|
||||||
// request is for.
|
// request is for.
|
||||||
_ = self
|
if !self.unsaved_chunks.is_empty() {
|
||||||
.chunk_images
|
info!("saving chunks");
|
||||||
.encoded(self.unsaved_chunks.drain().collect())
|
_ = self
|
||||||
.await;
|
.chunk_images
|
||||||
|
.encoded(self.unsaved_chunks.drain().collect())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue