diff --git a/assets/voxygen/i18n/pt_BR.ron b/assets/voxygen/i18n/pt_BR.ron index 7ae905fc49..91a2ef4b90 100644 --- a/assets/voxygen/i18n/pt_BR.ron +++ b/assets/voxygen/i18n/pt_BR.ron @@ -242,7 +242,7 @@ Aproveite a sua estadia no Mundo de Veloren."#, "hud.settings.maximum_fps": "FPS máximo", "hud.settings.fov": "Campo de visão(graus)", "hud.settings.gamma": "Gama", - "hud.settings.antialiasing_mode": Modo de antialiasing", + "hud.settings.antialiasing_mode": "Modo de antialiasing", "hud.settings.cloud_rendering_mode": "Modo de Renderização das Nuvens", "hud.settings.fluid_rendering_mode": "Modo de Renderização dos Fluidos", "hud.settings.fluid_rendering_mode.cheap": "Barato", diff --git a/server/src/events/player.rs b/server/src/events/player.rs index 8c14b647de..3494988f8e 100644 --- a/server/src/events/player.rs +++ b/server/src/events/player.rs @@ -42,7 +42,6 @@ pub fn handle_exit_ingame(server: &mut Server, entity: EcsEntity) { } pub fn handle_client_disconnect(server: &mut Server, entity: EcsEntity) -> Event { - let db_dir = &server.server_settings.persistence_db_dir.clone(); let state = server.state_mut(); // Tell other clients to remove from player list @@ -73,12 +72,13 @@ pub fn handle_client_disconnect(server: &mut Server, entity: EcsEntity) -> Event } // Sync the player's character data to the database - if let (Some(player), Some(stats)) = ( + if let (Some(player), Some(stats), updater) = ( state.read_storage::().get(entity), state.read_storage::().get(entity), + state.ecs().read_resource::(), ) { if let Some(character_id) = player.character_id { - persistence::stats::update_item(character_id, stats, db_dir); + updater.update(character_id, stats); } } diff --git a/server/src/lib.rs b/server/src/lib.rs index ebe55fa292..10fdb50740 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -94,6 +94,12 @@ impl Server { .insert(AuthProvider::new(settings.auth_server_address.clone())); state.ecs_mut().insert(Tick(0)); state.ecs_mut().insert(ChunkGenerator::new()); + state.ecs_mut().insert(persistence::stats::Updater::new( + settings.persistence_db_dir.clone(), + )); + state.ecs_mut().insert(crate::settings::PersistenceDBDir( + settings.persistence_db_dir.clone(), + )); // System timers for performance monitoring state.ecs_mut().insert(sys::EntitySyncTimer::default()); @@ -117,9 +123,6 @@ impl Server { // Server-only components state.ecs_mut().register::(); state.ecs_mut().register::(); - state.ecs_mut().insert(crate::settings::PersistenceDBDir( - settings.persistence_db_dir.clone(), - )); #[cfg(feature = "worldgen")] let world = World::generate(settings.world_seed, WorldOpts { diff --git a/server/src/persistence/stats.rs b/server/src/persistence/stats.rs index 57a66bfdab..52aecea414 100644 --- a/server/src/persistence/stats.rs +++ b/server/src/persistence/stats.rs @@ -2,12 +2,13 @@ extern crate diesel; use super::{establish_connection, models::StatsUpdate, schema}; use crate::comp; +use crossbeam::channel; use diesel::prelude::*; -fn update(character_id: i32, stats: &comp::Stats, connection: &SqliteConnection) { +fn update(character_id: i32, stats: &StatsUpdate, connection: &SqliteConnection) { if let Err(error) = diesel::update(schema::stats::table.filter(schema::stats::character_id.eq(character_id))) - .set(&StatsUpdate::from(stats)) + .set(stats) .execute(connection) { log::warn!( @@ -18,12 +19,58 @@ fn update(character_id: i32, stats: &comp::Stats, connection: &SqliteConnection) } } -pub fn update_item(character_id: i32, stats: &comp::Stats, db_dir: &str) { - update(character_id, stats, &establish_connection(db_dir)); -} - -pub fn batch_update<'a>(updates: impl Iterator, db_dir: &str) { +fn batch_update(updates: impl Iterator, db_dir: &str) { let connection = establish_connection(db_dir); + if let Err(err) = connection.transaction::<_, diesel::result::Error, _>(|| { + updates.for_each(|(character_id, stats_update)| { + update(character_id, &stats_update, &connection) + }); - updates.for_each(|(character_id, stats)| update(character_id, stats, &connection)); + Ok(()) + }) { + log::error!("Error during stats batch update transaction: {:?}", err); + } +} + +pub struct Updater { + update_tx: Option>>, + handle: Option>, +} +impl Updater { + pub fn new(db_dir: String) -> Self { + let (update_tx, update_rx) = channel::unbounded::>(); + let handle = std::thread::spawn(move || { + while let Ok(updates) = update_rx.recv() { + batch_update(updates.into_iter(), &db_dir); + } + }); + + Self { + update_tx: Some(update_tx), + handle: Some(handle), + } + } + + pub fn batch_update<'a>(&self, updates: impl Iterator) { + let updates = updates + .map(|(id, stats)| (id, StatsUpdate::from(stats))) + .collect(); + + if let Err(err) = self.update_tx.as_ref().unwrap().send(updates) { + log::error!("Could not send stats updates: {:?}", err); + } + } + + pub fn update(&self, character_id: i32, stats: &comp::Stats) { + self.batch_update(std::iter::once((character_id, stats))); + } +} + +impl Drop for Updater { + fn drop(&mut self) { + drop(self.update_tx.take()); + if let Err(err) = self.handle.take().unwrap().join() { + log::error!("Error from joining stats update thread: {:?}", err); + } + } } diff --git a/server/src/sys/persistence/stats.rs b/server/src/sys/persistence/stats.rs index 88d6d3f542..af3c63153f 100644 --- a/server/src/sys/persistence/stats.rs +++ b/server/src/sys/persistence/stats.rs @@ -1,6 +1,5 @@ use crate::{ persistence::stats, - settings::PersistenceDBDir, sys::{SysScheduler, SysTimer}, }; use common::comp::{Player, Stats}; @@ -12,25 +11,22 @@ impl<'a> System<'a> for Sys { type SystemData = ( ReadStorage<'a, Player>, ReadStorage<'a, Stats>, - ReadExpect<'a, PersistenceDBDir>, + ReadExpect<'a, stats::Updater>, Write<'a, SysScheduler>, Write<'a, SysTimer>, ); fn run( &mut self, - (players, player_stats, persistence_db_dir, mut scheduler, mut timer): Self::SystemData, + (players, player_stats, updater, mut scheduler, mut timer): Self::SystemData, ) { if scheduler.should_run() { timer.start(); - - stats::batch_update( + updater.batch_update( (&players, &player_stats) .join() .filter_map(|(player, stats)| player.character_id.map(|id| (id, stats))), - &persistence_db_dir.0, ); - timer.end(); } }