Removed de-serialization failure tolerance to prevent player inventory/loadout wipes

This commit is contained in:
Ben Wallis 2020-07-06 22:06:03 +01:00
parent 921c8a81d6
commit 3ac18f73ea
2 changed files with 29 additions and 90 deletions

View File

@ -236,71 +236,33 @@ impl Drop for CharacterLoader {
fn load_character_data(player_uuid: &str, character_id: i32, db_dir: &str) -> CharacterDataResult { fn load_character_data(player_uuid: &str, character_id: i32, db_dir: &str) -> CharacterDataResult {
let connection = establish_connection(db_dir); let connection = establish_connection(db_dir);
let (character_data, body_data, stats_data, maybe_inventory, maybe_loadout) = let result = schema::character::dsl::character
schema::character::dsl::character .filter(schema::character::id.eq(character_id))
.filter(schema::character::id.eq(character_id)) .filter(schema::character::player_uuid.eq(player_uuid))
.filter(schema::character::player_uuid.eq(player_uuid)) .inner_join(schema::body::table)
.inner_join(schema::body::table) .inner_join(schema::stats::table)
.inner_join(schema::stats::table) .inner_join(schema::inventory::table)
.left_join(schema::inventory::table) .inner_join(schema::loadout::table)
.left_join(schema::loadout::table) .first::<(Character, Body, Stats, Inventory, Loadout)>(&connection);
.first::<(Character, Body, Stats, Option<Inventory>, Option<Loadout>)>(&connection)?;
Ok(( if let Ok((character_data, body_data, stats_data, inventory, loadout)) = result {
comp::Body::from(&body_data), Ok((
comp::Stats::from(StatsJoinData { comp::Body::from(&body_data),
alias: &character_data.alias, comp::Stats::from(StatsJoinData {
body: &comp::Body::from(&body_data), alias: &character_data.alias,
stats: &stats_data, body: &comp::Body::from(&body_data),
}), stats: &stats_data,
maybe_inventory.map_or_else( }),
|| { comp::Inventory::from(inventory),
// If no inventory record was found for the character, create it now comp::Loadout::from(&loadout),
let row = Inventory::from((character_data.id, comp::Inventory::default())); ))
} else {
if let Err(error) = diesel::insert_into(schema::inventory::table) error!(
.values(&row) ?result,
.execute(&connection) "Failed to load character data for character id {}", character_id
{ );
warn!( Err(Error::CharacterDataError)
"Failed to create an inventory record for character {}: {}", }
&character_data.id, error
)
}
comp::Inventory::default()
},
comp::Inventory::from,
),
maybe_loadout.map_or_else(
|| {
// Create if no record was found
let default_loadout = LoadoutBuilder::new()
.defaults()
.active_item(LoadoutBuilder::default_item_config_from_str(
character_data.tool.as_deref(),
))
.build();
let row = NewLoadout::from((character_data.id, &default_loadout));
if let Err(e) = diesel::insert_into(schema::loadout::table)
.values(&row)
.execute(&connection)
{
let char_id = character_data.id;
warn!(
?e,
?char_id,
"Failed to create an loadout record for character",
)
}
default_loadout
},
|data| comp::Loadout::from(&data),
),
))
} }
/// Loads a list of characters belonging to the player. This data is a small /// Loads a list of characters belonging to the player. This data is a small

View File

@ -2,7 +2,7 @@ extern crate serde_json;
use super::schema::{body, character, inventory, loadout, stats}; use super::schema::{body, character, inventory, loadout, stats};
use crate::comp; use crate::comp;
use common::{character::Character as CharacterData, LoadoutBuilder}; use common::character::Character as CharacterData;
use diesel::sql_types::Text; use diesel::sql_types::Text;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tracing::warn; use tracing::warn;
@ -212,14 +212,7 @@ where
bytes: Option<&<DB as diesel::backend::Backend>::RawValue>, bytes: Option<&<DB as diesel::backend::Backend>::RawValue>,
) -> diesel::deserialize::Result<Self> { ) -> diesel::deserialize::Result<Self> {
let t = String::from_sql(bytes)?; let t = String::from_sql(bytes)?;
serde_json::from_str(&t).map_err(Box::from)
match serde_json::from_str(&t) {
Ok(data) => Ok(Self(data)),
Err(e) => {
warn!(?e, "Failed to deserialise inventory data");
Ok(Self(comp::Inventory::default()))
},
}
} }
} }
@ -298,23 +291,7 @@ where
bytes: Option<&<DB as diesel::backend::Backend>::RawValue>, bytes: Option<&<DB as diesel::backend::Backend>::RawValue>,
) -> diesel::deserialize::Result<Self> { ) -> diesel::deserialize::Result<Self> {
let t = String::from_sql(bytes)?; let t = String::from_sql(bytes)?;
serde_json::from_str(&t).map_err(Box::from)
match serde_json::from_str(&t) {
Ok(data) => Ok(Self(data)),
Err(e) => {
warn!(?e, "Failed to deserialise loadout data");
// We don't have a weapon reference here, so we default to sword
let loadout = LoadoutBuilder::new()
.defaults()
.active_item(LoadoutBuilder::default_item_config_from_str(Some(
"common.items.weapons.sword.starter_sword",
)))
.build();
Ok(Self(loadout))
},
}
} }
} }