mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Gather all characters stats in the system, build one big query, rather than per-character queries.
This commit is contained in:
parent
7c6c9f4302
commit
0a6f9b860d
@ -108,7 +108,7 @@ impl Server {
|
||||
state
|
||||
.ecs_mut()
|
||||
.insert(sys::StatsPersistenceScheduler::every(Duration::from_secs(
|
||||
5,
|
||||
60,
|
||||
)));
|
||||
|
||||
// Server-only components
|
||||
|
@ -1,7 +1,7 @@
|
||||
CREATE TABLE "stats" (
|
||||
character_id INT NOT NULL PRIMARY KEY,
|
||||
"level" INT NOT NULL DEFAULT 1,
|
||||
"exp" INT NOT NULL DEFAULT 0,
|
||||
exp INT NOT NULL DEFAULT 0,
|
||||
endurance INT NOT NULL DEFAULT 0,
|
||||
fitness INT NOT NULL DEFAULT 0,
|
||||
willpower INT NOT NULL DEFAULT 0,
|
||||
|
@ -4,7 +4,7 @@ use std::fmt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
// The player has alredy reached the max character limit
|
||||
// The player has already reached the max character limit
|
||||
CharacterLimitReached,
|
||||
// An error occured when performing a database action
|
||||
DatabaseError(diesel::result::Error),
|
||||
|
@ -73,7 +73,7 @@ impl From<&Body> for comp::Body {
|
||||
}
|
||||
|
||||
/// `Stats` represents the stats for a character
|
||||
#[derive(Associations, Identifiable, Queryable, Debug, Insertable)]
|
||||
#[derive(Associations, AsChangeset, Identifiable, Queryable, Debug, Insertable)]
|
||||
#[belongs_to(Character)]
|
||||
#[primary_key(character_id)]
|
||||
#[table_name = "stats"]
|
||||
@ -110,9 +110,9 @@ impl From<StatsJoinData<'_>> for comp::Stats {
|
||||
#[primary_key(character_id)]
|
||||
#[table_name = "stats"]
|
||||
pub struct StatsUpdate {
|
||||
pub level: Option<i32>,
|
||||
pub exp: Option<i32>,
|
||||
pub endurance: Option<i32>,
|
||||
pub fitness: Option<i32>,
|
||||
pub willpower: Option<i32>,
|
||||
pub level: i32,
|
||||
pub exp: i32,
|
||||
pub endurance: i32,
|
||||
pub fitness: i32,
|
||||
pub willpower: i32,
|
||||
}
|
||||
|
@ -1,33 +1,83 @@
|
||||
extern crate diesel;
|
||||
|
||||
use super::{establish_connection, models::StatsUpdate, schema};
|
||||
use super::establish_connection;
|
||||
use crate::comp;
|
||||
use diesel::prelude::*;
|
||||
|
||||
pub fn update(
|
||||
character_id: i32,
|
||||
level: Option<i32>,
|
||||
exp: Option<i32>,
|
||||
endurance: Option<i32>,
|
||||
fitness: Option<i32>,
|
||||
willpower: Option<i32>,
|
||||
) {
|
||||
use schema::stats;
|
||||
|
||||
match diesel::update(stats::table)
|
||||
.set(&StatsUpdate {
|
||||
level,
|
||||
exp,
|
||||
endurance,
|
||||
fitness,
|
||||
willpower,
|
||||
})
|
||||
.execute(&establish_connection())
|
||||
{
|
||||
Err(error) => log::warn!(
|
||||
"Failed to update stats for player with character_id: {:?}: {:?}",
|
||||
character_id,
|
||||
error
|
||||
),
|
||||
/// Update DB rows for stats given a Vec of (character_id, Stats) tuples
|
||||
pub fn update(data: Vec<(i32, &comp::Stats)>) {
|
||||
match establish_connection().execute(&build_query(data)) {
|
||||
Err(diesel_error) => log::warn!("Error updating stats: {:?}", diesel_error),
|
||||
_ => {},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Takes a Vec of (character_id, Stats) tuples and builds an SQL UPDATE query
|
||||
/// Since there is apprently no sensible way to update > 1 row using diesel, we
|
||||
/// just construct the raw SQL
|
||||
fn build_query(data: Vec<(i32, &comp::Stats)>) -> String {
|
||||
data.iter()
|
||||
.map(|(character_id, stats)| {
|
||||
String::from(format!(
|
||||
"UPDATE stats SET level = {}, exp = {}, endurance = {}, fitness = {}, willpower = \
|
||||
{} WHERE character_id = {};",
|
||||
stats.level.level() as i32,
|
||||
stats.exp.current() as i32,
|
||||
stats.endurance as i32,
|
||||
stats.fitness as i32,
|
||||
stats.willpower as i32,
|
||||
*character_id as i32
|
||||
))
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
.join(" ")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn builds_query_for_multiple_characters() {
|
||||
let mut stats_one = comp::Stats::new(
|
||||
String::from("One"),
|
||||
comp::Body::Humanoid(comp::humanoid::Body::random()),
|
||||
);
|
||||
|
||||
stats_one.endurance = 1;
|
||||
stats_one.fitness = 1;
|
||||
stats_one.willpower = 1;
|
||||
|
||||
let mut stats_two = comp::Stats::new(
|
||||
String::from("Two"),
|
||||
comp::Body::Humanoid(comp::humanoid::Body::random()),
|
||||
);
|
||||
|
||||
stats_two.endurance = 2;
|
||||
stats_two.fitness = 2;
|
||||
stats_two.willpower = 2;
|
||||
|
||||
let mut stats_three = comp::Stats::new(
|
||||
String::from("Three"),
|
||||
comp::Body::Humanoid(comp::humanoid::Body::random()),
|
||||
);
|
||||
|
||||
stats_three.endurance = 3;
|
||||
stats_three.fitness = 3;
|
||||
stats_three.willpower = 3;
|
||||
|
||||
let data = vec![
|
||||
(1_i32, &stats_one),
|
||||
(2_i32, &stats_two),
|
||||
(3_i32, &stats_three),
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
build_query(data),
|
||||
"UPDATE stats SET level = 1, exp = 0, endurance = 1, fitness = 1, willpower = 1 WHERE \
|
||||
character_id = 1; UPDATE stats SET level = 1, exp = 0, endurance = 2, fitness = 2, \
|
||||
willpower = 2 WHERE character_id = 2; UPDATE stats SET level = 1, exp = 0, endurance \
|
||||
= 3, fitness = 3, willpower = 3 WHERE character_id = 3;"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -13,17 +13,19 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
fn run(&mut self, (players, player_stats, mut scheduler): Self::SystemData) {
|
||||
if scheduler.should_run() {
|
||||
for (player, stats) in (&players, &player_stats).join() {
|
||||
if let Some(character_id) = player.character_id {
|
||||
stats::update(
|
||||
character_id,
|
||||
Some(stats.level.level() as i32),
|
||||
Some(stats.exp.current() as i32),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
let updates: Vec<(i32, &Stats)> = (&players, &player_stats)
|
||||
.join()
|
||||
.filter_map(|(player, stats)| {
|
||||
if let Some(character_id) = player.character_id {
|
||||
Some((character_id, stats))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if !updates.is_empty() {
|
||||
stats::update(updates);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user