mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added sentiments
This commit is contained in:
parent
d7ba4ecef7
commit
08338436ea
@ -5,7 +5,8 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
/// The limit on how many characters that a player can have
|
||||
pub const MAX_CHARACTERS_PER_PLAYER: usize = 8;
|
||||
pub type CharacterId = i64;
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||
pub struct CharacterId(pub i64);
|
||||
|
||||
pub const MAX_NAME_LENGTH: usize = 20;
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
pub mod faction;
|
||||
pub mod nature;
|
||||
pub mod npc;
|
||||
pub mod sentiment;
|
||||
pub mod site;
|
||||
|
||||
pub use self::{
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::{ai::Action, gen::name};
|
||||
use crate::{ai::Action, data::sentiment::Sentiments, gen::name};
|
||||
pub use common::rtsim::{NpcId, Profession};
|
||||
use common::{
|
||||
character::CharacterId,
|
||||
comp,
|
||||
grid::Grid,
|
||||
rtsim::{
|
||||
@ -91,7 +92,10 @@ pub struct Npc {
|
||||
pub faction: Option<FactionId>,
|
||||
pub riding: Option<Riding>,
|
||||
|
||||
#[serde(default)]
|
||||
pub personality: Personality,
|
||||
#[serde(default)]
|
||||
pub sentiments: Sentiments,
|
||||
|
||||
// Unpersisted state
|
||||
#[serde(skip)]
|
||||
@ -124,6 +128,7 @@ impl Clone for Npc {
|
||||
riding: self.riding.clone(),
|
||||
body: self.body,
|
||||
personality: self.personality,
|
||||
sentiments: self.sentiments.clone(),
|
||||
// Not persisted
|
||||
chunk_pos: None,
|
||||
current_site: Default::default(),
|
||||
@ -144,6 +149,7 @@ impl Npc {
|
||||
wpos,
|
||||
body,
|
||||
personality: Personality::default(),
|
||||
sentiments: Sentiments::default(),
|
||||
profession: None,
|
||||
home: None,
|
||||
faction: None,
|
||||
@ -274,7 +280,7 @@ pub struct Npcs {
|
||||
#[serde(skip, default = "construct_npc_grid")]
|
||||
pub npc_grid: Grid<GridCell>,
|
||||
#[serde(skip)]
|
||||
pub character_map: HashMap<Vec2<i32>, Vec<(common::character::CharacterId, Vec3<f32>)>>,
|
||||
pub character_map: HashMap<Vec2<i32>, Vec<(CharacterId, Vec3<f32>)>>,
|
||||
}
|
||||
|
||||
impl Default for Npcs {
|
||||
|
192
rtsim/src/data/sentiment.rs
Normal file
192
rtsim/src/data/sentiment.rs
Normal file
@ -0,0 +1,192 @@
|
||||
use common::{
|
||||
character::CharacterId,
|
||||
rtsim::{Actor, FactionId, NpcId},
|
||||
};
|
||||
use rand::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
// Factions have a larger 'social memory' than individual NPCs and so we allow
|
||||
// them to have more sentiments
|
||||
pub const FACTION_MAX_SENTIMENTS: usize = 1024;
|
||||
pub const NPC_MAX_SENTIMENTS: usize = 128;
|
||||
|
||||
/// The target that a sentiment is felt toward.
|
||||
// NOTE: More could be added to this! For example:
|
||||
// - Animal species (dislikes spiders?)
|
||||
// - Kind of food (likes meat?)
|
||||
// - Occupations (hatred of hunters or chefs?)
|
||||
// - Ideologies (dislikes democracy, likes monarchy?)
|
||||
// - etc.
|
||||
#[derive(Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum Target {
|
||||
Character(CharacterId),
|
||||
Npc(NpcId),
|
||||
Faction(FactionId),
|
||||
}
|
||||
|
||||
impl From<NpcId> for Target {
|
||||
fn from(npc: NpcId) -> Self { Self::Npc(npc) }
|
||||
}
|
||||
impl From<FactionId> for Target {
|
||||
fn from(faction: FactionId) -> Self { Self::Faction(faction) }
|
||||
}
|
||||
impl From<CharacterId> for Target {
|
||||
fn from(character: CharacterId) -> Self { Self::Character(character) }
|
||||
}
|
||||
impl From<Actor> for Target {
|
||||
fn from(actor: Actor) -> Self {
|
||||
match actor {
|
||||
Actor::Character(character) => Self::Character(character),
|
||||
Actor::Npc(npc) => Self::Npc(npc),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize)]
|
||||
pub struct Sentiments {
|
||||
#[serde(rename = "m")]
|
||||
map: HashMap<Target, Sentiment>,
|
||||
}
|
||||
|
||||
impl Sentiments {
|
||||
/// Return the sentiment that is felt toward the given target.
|
||||
pub fn toward(&self, target: impl Into<Target>) -> Sentiment {
|
||||
self.map.get(&target.into()).copied().unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn change_by(&mut self, target: impl Into<Target>, change: f32) {
|
||||
let target = target.into();
|
||||
self.map.entry(target).or_default().change_by(change);
|
||||
}
|
||||
|
||||
/// Progressively decay the sentiment back to a neutral sentiment.
|
||||
///
|
||||
/// Note that sentiment get decay gets slower the harsher the sentiment is.
|
||||
/// You can calculate the **average** number of ticks required for a
|
||||
/// sentiment to decay with the following formula:
|
||||
///
|
||||
/// ```
|
||||
/// ticks_until_neutrality = ((sentiment_value * 127 * 32) ^ 2) / 2
|
||||
/// ```
|
||||
///
|
||||
/// For example, a positive (see [`Sentiment::POSITIVE`]) sentiment has a
|
||||
/// value of `0.2`, so we get
|
||||
///
|
||||
/// ```
|
||||
/// ticks_until_neutrality = ((0.1 * 127 * 32) ^ 2) / 2 = ~82,580 ticks
|
||||
/// ```
|
||||
///
|
||||
/// Assuming a TPS of 30, that's ~46 minutes.
|
||||
///
|
||||
/// Some 'common' sentiment decay times are as follows:
|
||||
///
|
||||
/// - `POSITIVE`/`NEGATIVE`: ~46 minutes
|
||||
/// - `ALLY`/`RIVAL`: ~6.9 hours
|
||||
/// - `FRIEND`/`ENEMY`: ~27.5 hours
|
||||
/// - `HERO`/`VILLAIN`: ~48.9 hours
|
||||
pub fn decay(&mut self, rng: &mut impl Rng) {
|
||||
self.map.retain(|_, sentiment| {
|
||||
sentiment.decay(rng);
|
||||
// We can eliminate redundant sentiments that don't need remembering
|
||||
!sentiment.is_redundant()
|
||||
});
|
||||
}
|
||||
|
||||
/// Clean up sentiments to avoid them growing too large
|
||||
pub fn cleanup(&mut self, max_sentiments: usize) {
|
||||
if self.map.len() > max_sentiments {
|
||||
let mut sentiments = self.map
|
||||
.iter()
|
||||
// For each sentiment, calculate how valuable it is for us to remember.
|
||||
// For now, we just use the absolute value of the sentiment but later on we might want to favour
|
||||
// sentiments toward factions and other 'larger' groups over, say, sentiments toward players/other NPCs
|
||||
.map(|(tgt, sentiment)| (*tgt, sentiment.positivity.unsigned_abs()))
|
||||
.collect::<Vec<_>>();
|
||||
sentiments.sort_unstable_by_key(|(_, value)| *value);
|
||||
|
||||
// Remove the superfluous sentiments
|
||||
for (tgt, _) in &sentiments[0..self.map.len() - max_sentiments] {
|
||||
self.map.remove(tgt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default, Serialize, Deserialize)]
|
||||
pub struct Sentiment {
|
||||
/// How positive the sentiment is.
|
||||
///
|
||||
/// Using i8 to reduce on-disk memory footprint.
|
||||
/// Semantically, this value is -1 <= x <= 1.
|
||||
#[serde(rename = "p")]
|
||||
positivity: i8,
|
||||
}
|
||||
|
||||
impl Sentiment {
|
||||
/// Substantial positive sentiments: NPC may go out of their way to help
|
||||
/// actors associated with the target, greet them, etc.
|
||||
pub const ALLY: f32 = 0.3;
|
||||
/// Very negative sentiments: NPC may confront the actor, get aggressive
|
||||
/// with them, or even use force against them.
|
||||
pub const ENEMY: f32 = -0.6;
|
||||
/// Very positive sentiments: NPC may join the actor as a companion,
|
||||
/// encourage them to join their faction, etc.
|
||||
pub const FRIEND: f32 = 0.6;
|
||||
/// Extremely positive sentiments: NPC may switch sides to join the actor's
|
||||
/// faction, protect them at all costs, turn against friends for them,
|
||||
/// etc. Verging on cult-like behaviour.
|
||||
pub const HERO: f32 = 0.8;
|
||||
/// Minor negative sentiments: NPC might be less willing to provide
|
||||
/// information, give worse trade deals, etc.
|
||||
pub const NEGATIVE: f32 = -0.1;
|
||||
/// Minor positive sentiments: NPC might be more willing to provide
|
||||
/// information, give better trade deals, etc.
|
||||
pub const POSITIVE: f32 = 0.1;
|
||||
/// Substantial positive sentiments: NPC may reject attempts to trade or
|
||||
/// avoid actors associated with the target, insult them, but will not
|
||||
/// use physical force.
|
||||
pub const RIVAL: f32 = -0.3;
|
||||
/// Extremely negative sentiments: NPC may aggressively persue or hunt down
|
||||
/// the actor, organise others around them to do the same, and will
|
||||
/// generally try to harm the actor in any way they can.
|
||||
pub const VILLAIN: f32 = -0.8;
|
||||
|
||||
fn value(&self) -> f32 { self.positivity as f32 / 127.0 }
|
||||
|
||||
fn change_by(&mut self, change: f32) {
|
||||
// There's a bit of ceremony here for two reasons:
|
||||
// 1) Very small changes should not be rounded to 0
|
||||
// 2) Sentiment should never (over/under)flow
|
||||
if change != 0.0 {
|
||||
let abs = (change * 127.0).abs().clamp(1.0, 127.0) as i8;
|
||||
self.positivity = if change > 0.0 {
|
||||
self.positivity.saturating_add(abs)
|
||||
} else {
|
||||
self.positivity.saturating_sub(abs)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn decay(&mut self, rng: &mut impl Rng) {
|
||||
if self.positivity != 0 {
|
||||
// TODO: Make dt-independent so we can slow tick rates
|
||||
if rng.gen_range(0..self.positivity.unsigned_abs() as u32 * 1024) == 0 {
|
||||
self.positivity -= self.positivity.signum();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return `true` if the sentiment can be forgotten without changing
|
||||
/// anything (i.e: is entirely neutral, the default stance).
|
||||
fn is_redundant(&self) -> bool { self.positivity == 0 }
|
||||
|
||||
/// Returns `true` if the sentiment has reached the given threshold.
|
||||
pub fn is(&self, val: f32) -> bool {
|
||||
if val > 0.0 {
|
||||
self.value() >= val
|
||||
} else {
|
||||
self.value() <= val
|
||||
}
|
||||
}
|
||||
}
|
@ -139,7 +139,7 @@ pub fn load_character_data(
|
||||
)?;
|
||||
|
||||
let (body_data, character_data) = stmt.query_row(
|
||||
&[requesting_player_uuid.clone(), char_id.to_string()],
|
||||
&[requesting_player_uuid.clone(), char_id.0.to_string()],
|
||||
|row| {
|
||||
let character_data = Character {
|
||||
character_id: row.get(0)?,
|
||||
@ -168,7 +168,7 @@ pub fn load_character_data(
|
||||
warn!(
|
||||
"Error reading waypoint from database for character ID
|
||||
{}, error: {}",
|
||||
char_id, e
|
||||
char_id.0, e
|
||||
);
|
||||
(None, None)
|
||||
},
|
||||
@ -187,9 +187,9 @@ pub fn load_character_data(
|
||||
)?;
|
||||
|
||||
let skill_group_data = stmt
|
||||
.query_map(&[char_id], |row| {
|
||||
.query_map(&[char_id.0], |row| {
|
||||
Ok(SkillGroup {
|
||||
entity_id: char_id,
|
||||
entity_id: char_id.0,
|
||||
skill_group_kind: row.get(0)?,
|
||||
earned_exp: row.get(1)?,
|
||||
spent_exp: row.get(2)?,
|
||||
@ -212,7 +212,7 @@ pub fn load_character_data(
|
||||
)?;
|
||||
|
||||
let db_pets = stmt
|
||||
.query_map(&[char_id], |row| {
|
||||
.query_map(&[char_id.0], |row| {
|
||||
Ok(Pet {
|
||||
database_id: row.get(0)?,
|
||||
name: row.get(1)?,
|
||||
@ -240,7 +240,7 @@ pub fn load_character_data(
|
||||
} else {
|
||||
warn!(
|
||||
"Failed to deserialize pet_id: {} for character_id {}",
|
||||
db_pet.database_id, char_id
|
||||
db_pet.database_id, char_id.0
|
||||
);
|
||||
None
|
||||
}
|
||||
@ -254,9 +254,9 @@ pub fn load_character_data(
|
||||
WHERE entity_id = ?1",
|
||||
)?;
|
||||
|
||||
let ability_set_data = stmt.query_row(&[char_id], |row| {
|
||||
let ability_set_data = stmt.query_row(&[char_id.0], |row| {
|
||||
Ok(AbilitySets {
|
||||
entity_id: char_id,
|
||||
entity_id: char_id.0,
|
||||
ability_sets: row.get(0)?,
|
||||
})
|
||||
})?;
|
||||
@ -329,7 +329,7 @@ pub fn load_character_list(player_uuid_: &str, connection: &Connection) -> Chara
|
||||
FROM body
|
||||
WHERE body_id = ?1",
|
||||
)?;
|
||||
let db_body = stmt.query_row(&[char.id], |row| {
|
||||
let db_body = stmt.query_row(&[char.id.map(|c| c.0)], |row| {
|
||||
Ok(Body {
|
||||
body_id: row.get(0)?,
|
||||
variant: row.get(1)?,
|
||||
@ -342,7 +342,7 @@ pub fn load_character_list(player_uuid_: &str, connection: &Connection) -> Chara
|
||||
|
||||
let loadout_container_id = get_pseudo_container_id(
|
||||
connection,
|
||||
character_data.character_id,
|
||||
CharacterId(character_data.character_id),
|
||||
LOADOUT_PSEUDO_CONTAINER_POSITION,
|
||||
)?;
|
||||
|
||||
@ -470,7 +470,8 @@ pub fn create_character(
|
||||
])?;
|
||||
drop(stmt);
|
||||
|
||||
let db_skill_groups = convert_skill_groups_to_database(character_id, skill_set.skill_groups());
|
||||
let db_skill_groups =
|
||||
convert_skill_groups_to_database(CharacterId(character_id), skill_set.skill_groups());
|
||||
|
||||
let mut stmt = transaction.prepare_cached(
|
||||
"
|
||||
@ -495,7 +496,8 @@ pub fn create_character(
|
||||
}
|
||||
drop(stmt);
|
||||
|
||||
let ability_sets = convert_active_abilities_to_database(character_id, &active_abilities);
|
||||
let ability_sets =
|
||||
convert_active_abilities_to_database(CharacterId(character_id), &active_abilities);
|
||||
|
||||
let mut stmt = transaction.prepare_cached(
|
||||
"
|
||||
@ -547,7 +549,7 @@ pub fn create_character(
|
||||
}
|
||||
drop(stmt);
|
||||
|
||||
load_character_list(uuid, transaction).map(|list| (character_id, list))
|
||||
load_character_list(uuid, transaction).map(|list| (CharacterId(character_id), list))
|
||||
}
|
||||
|
||||
pub fn edit_character(
|
||||
@ -570,7 +572,7 @@ pub fn edit_character(
|
||||
warn!(
|
||||
"Character edit rejected due to failed validation - Character ID: {} \
|
||||
Alias: {}",
|
||||
character_id, character_alias
|
||||
character_id.0, character_alias
|
||||
);
|
||||
return Err(PersistenceError::CharacterDataError);
|
||||
} else {
|
||||
@ -587,14 +589,14 @@ pub fn edit_character(
|
||||
stmt.execute(&[
|
||||
&body_variant.to_string(),
|
||||
&body_data,
|
||||
&character_id as &dyn ToSql,
|
||||
&character_id.0 as &dyn ToSql,
|
||||
])?;
|
||||
drop(stmt);
|
||||
|
||||
let mut stmt =
|
||||
transaction.prepare_cached("UPDATE character SET alias = ?1 WHERE character_id = ?2")?;
|
||||
|
||||
stmt.execute(&[&character_alias, &character_id as &dyn ToSql])?;
|
||||
stmt.execute(&[&character_alias, &character_id.0 as &dyn ToSql])?;
|
||||
drop(stmt);
|
||||
|
||||
char_list.map(|list| (character_id, list))
|
||||
@ -616,10 +618,13 @@ pub fn delete_character(
|
||||
AND player_uuid = ?2",
|
||||
)?;
|
||||
|
||||
let result = stmt.query_row(&[&char_id as &dyn ToSql, &requesting_player_uuid], |row| {
|
||||
let result = stmt.query_row(
|
||||
&[&char_id.0 as &dyn ToSql, &requesting_player_uuid],
|
||||
|row| {
|
||||
let y: i64 = row.get(0)?;
|
||||
Ok(y)
|
||||
})?;
|
||||
},
|
||||
)?;
|
||||
drop(stmt);
|
||||
|
||||
if result != 1 {
|
||||
@ -636,7 +641,7 @@ pub fn delete_character(
|
||||
WHERE entity_id = ?1",
|
||||
)?;
|
||||
|
||||
stmt.execute(&[&char_id])?;
|
||||
stmt.execute(&[&char_id.0])?;
|
||||
drop(stmt);
|
||||
|
||||
let pet_ids = get_pet_ids(char_id, transaction)?
|
||||
@ -655,7 +660,7 @@ pub fn delete_character(
|
||||
WHERE entity_id = ?1",
|
||||
)?;
|
||||
|
||||
stmt.execute(&[&char_id])?;
|
||||
stmt.execute(&[&char_id.0])?;
|
||||
drop(stmt);
|
||||
|
||||
// Delete character
|
||||
@ -666,7 +671,7 @@ pub fn delete_character(
|
||||
WHERE character_id = ?1",
|
||||
)?;
|
||||
|
||||
stmt.execute(&[&char_id])?;
|
||||
stmt.execute(&[&char_id.0])?;
|
||||
drop(stmt);
|
||||
|
||||
// Delete body
|
||||
@ -677,7 +682,7 @@ pub fn delete_character(
|
||||
WHERE body_id = ?1",
|
||||
)?;
|
||||
|
||||
stmt.execute(&[&char_id])?;
|
||||
stmt.execute(&[&char_id.0])?;
|
||||
drop(stmt);
|
||||
|
||||
// Delete all items, recursively walking all containers starting from the
|
||||
@ -701,14 +706,14 @@ pub fn delete_character(
|
||||
WHERE EXISTS (SELECT 1 FROM parents WHERE parents.item_id = item.item_id)",
|
||||
)?;
|
||||
|
||||
let deleted_item_count = stmt.execute(&[&char_id])?;
|
||||
let deleted_item_count = stmt.execute(&[&char_id.0])?;
|
||||
drop(stmt);
|
||||
|
||||
if deleted_item_count < 3 {
|
||||
return Err(PersistenceError::OtherError(format!(
|
||||
"Error deleting from item table for char_id {} (expected at least 3 deletions, found \
|
||||
{})",
|
||||
char_id, deleted_item_count
|
||||
char_id.0, deleted_item_count
|
||||
)));
|
||||
}
|
||||
|
||||
@ -822,7 +827,7 @@ fn get_pseudo_container_id(
|
||||
#[allow(clippy::needless_question_mark)]
|
||||
let res = stmt.query_row(
|
||||
&[
|
||||
character_id.to_string(),
|
||||
character_id.0.to_string(),
|
||||
pseudo_container_position.to_string(),
|
||||
],
|
||||
|row| Ok(row.get(0)?),
|
||||
@ -850,7 +855,7 @@ fn update_pets(
|
||||
pets: Vec<PetPersistenceData>,
|
||||
transaction: &mut Transaction,
|
||||
) -> Result<(), PersistenceError> {
|
||||
debug!("Updating {} pets for character {}", pets.len(), char_id);
|
||||
debug!("Updating {} pets for character {}", pets.len(), char_id.0);
|
||||
|
||||
let db_pets = get_pet_ids(char_id, transaction)?;
|
||||
if !db_pets.is_empty() {
|
||||
@ -907,7 +912,7 @@ fn update_pets(
|
||||
VALUES (?1, ?2, ?3)",
|
||||
)?;
|
||||
|
||||
stmt.execute(&[&pet_entity_id as &dyn ToSql, &char_id, &stats.name])?;
|
||||
stmt.execute(&[&pet_entity_id as &dyn ToSql, &char_id.0, &stats.name])?;
|
||||
drop(stmt);
|
||||
|
||||
pet.get_database_id()
|
||||
@ -917,7 +922,10 @@ fn update_pets(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_pet_ids(char_id: i64, transaction: &mut Transaction) -> Result<Vec<i64>, PersistenceError> {
|
||||
fn get_pet_ids(
|
||||
char_id: CharacterId,
|
||||
transaction: &mut Transaction,
|
||||
) -> Result<Vec<i64>, PersistenceError> {
|
||||
#[rustfmt::skip]
|
||||
let mut stmt = transaction.prepare_cached("
|
||||
SELECT pet_id
|
||||
@ -927,7 +935,7 @@ fn get_pet_ids(char_id: i64, transaction: &mut Transaction) -> Result<Vec<i64>,
|
||||
|
||||
#[allow(clippy::needless_question_mark)]
|
||||
let db_pets = stmt
|
||||
.query_map(&[&char_id], |row| Ok(row.get(0)?))?
|
||||
.query_map(&[&char_id.0], |row| Ok(row.get(0)?))?
|
||||
.map(|x| x.unwrap())
|
||||
.collect::<Vec<i64>>();
|
||||
drop(stmt);
|
||||
@ -948,7 +956,10 @@ fn delete_pets(
|
||||
|
||||
let delete_count = stmt.execute(&[&pet_ids])?;
|
||||
drop(stmt);
|
||||
debug!("Deleted {} pets for character id {}", delete_count, char_id);
|
||||
debug!(
|
||||
"Deleted {} pets for character id {}",
|
||||
delete_count, char_id.0
|
||||
);
|
||||
|
||||
#[rustfmt::skip]
|
||||
let mut stmt = transaction.prepare_cached("
|
||||
@ -960,7 +971,7 @@ fn delete_pets(
|
||||
let delete_count = stmt.execute(&[&pet_ids])?;
|
||||
debug!(
|
||||
"Deleted {} pet bodies for character id {}",
|
||||
delete_count, char_id
|
||||
delete_count, char_id.0
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@ -996,7 +1007,7 @@ pub fn update(
|
||||
})?;
|
||||
|
||||
// Next, delete any slots we aren't upserting.
|
||||
trace!("Deleting items for character_id {}", char_id);
|
||||
trace!("Deleting items for character_id {}", char_id.0);
|
||||
let mut existing_item_ids: Vec<_> = vec![
|
||||
Value::from(pseudo_containers.inventory_container_id),
|
||||
Value::from(pseudo_containers.loadout_container_id),
|
||||
@ -1040,7 +1051,7 @@ pub fn update(
|
||||
trace!(
|
||||
"Upserting items {:?} for character_id {}",
|
||||
upserted_items,
|
||||
char_id
|
||||
char_id.0
|
||||
);
|
||||
|
||||
// When moving inventory items around, foreign key constraints on
|
||||
@ -1111,12 +1122,12 @@ pub fn update(
|
||||
",
|
||||
)?;
|
||||
|
||||
let waypoint_count = stmt.execute(&[&db_waypoint as &dyn ToSql, &char_id])?;
|
||||
let waypoint_count = stmt.execute(&[&db_waypoint as &dyn ToSql, &char_id.0])?;
|
||||
|
||||
if waypoint_count != 1 {
|
||||
return Err(PersistenceError::OtherError(format!(
|
||||
"Error updating character table for char_id {}",
|
||||
char_id
|
||||
char_id.0
|
||||
)));
|
||||
}
|
||||
|
||||
@ -1132,13 +1143,13 @@ pub fn update(
|
||||
|
||||
let ability_sets_count = stmt.execute(&[
|
||||
&ability_sets.ability_sets as &dyn ToSql,
|
||||
&char_id as &dyn ToSql,
|
||||
&char_id.0 as &dyn ToSql,
|
||||
])?;
|
||||
|
||||
if ability_sets_count != 1 {
|
||||
return Err(PersistenceError::OtherError(format!(
|
||||
"Error updating ability_set table for char_id {}",
|
||||
char_id,
|
||||
char_id.0,
|
||||
)));
|
||||
}
|
||||
|
||||
|
@ -608,7 +608,7 @@ pub fn convert_body_from_database(
|
||||
|
||||
pub fn convert_character_from_database(character: &Character) -> common::character::Character {
|
||||
common::character::Character {
|
||||
id: Some(character.character_id),
|
||||
id: Some(CharacterId(character.character_id)),
|
||||
alias: String::from(&character.alias),
|
||||
}
|
||||
}
|
||||
@ -704,7 +704,7 @@ pub fn convert_skill_groups_to_database<'a, I: Iterator<Item = &'a skillset::Ski
|
||||
skill_groups
|
||||
.into_iter()
|
||||
.map(|sg| SkillGroup {
|
||||
entity_id,
|
||||
entity_id: entity_id.0,
|
||||
skill_group_kind: json_models::skill_group_to_db_string(sg.skill_group_kind),
|
||||
earned_exp: i64::from(sg.earned_exp),
|
||||
spent_exp: i64::from(sg.spent_exp()),
|
||||
@ -724,7 +724,7 @@ pub fn convert_active_abilities_to_database(
|
||||
) -> AbilitySets {
|
||||
let ability_sets = json_models::active_abilities_to_db_model(active_abilities);
|
||||
AbilitySets {
|
||||
entity_id,
|
||||
entity_id: entity_id.0,
|
||||
ability_sets: serde_json::to_string(&ability_sets).unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ impl CharacterLoader {
|
||||
if result.is_err() {
|
||||
error!(
|
||||
?result,
|
||||
"Error loading character data for character_id: {}", character_id
|
||||
"Error loading character data for character_id: {}", character_id.0
|
||||
);
|
||||
}
|
||||
CharacterScreenResponseKind::CharacterData(Box::new(result))
|
||||
|
@ -242,7 +242,7 @@ impl CharacterUpdater {
|
||||
warn!(
|
||||
"Ignoring request to add pending logout update for character ID {} as there is a \
|
||||
disconnection of all clients in progress",
|
||||
update_data.0
|
||||
update_data.0.0
|
||||
);
|
||||
return;
|
||||
}
|
||||
@ -251,7 +251,7 @@ impl CharacterUpdater {
|
||||
warn!(
|
||||
"Ignoring request to add pending logout update for character ID {} as there is \
|
||||
already a pending delete for this character",
|
||||
update_data.0
|
||||
update_data.0.0
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user