Added persistence for skill trees.

This commit is contained in:
Sam 2020-12-13 11:21:51 -06:00
parent cc60ca58be
commit 69be3a3d93
6 changed files with 180 additions and 10 deletions

View File

@ -7,8 +7,8 @@ use common::{
resources::DeltaTime, resources::DeltaTime,
span, span,
}; };
use hashbrown::HashSet;
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage}; use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage};
use std::collections::HashSet;
const ENERGY_REGEN_ACCEL: f32 = 10.0; const ENERGY_REGEN_ACCEL: f32 = 10.0;

View File

@ -28,9 +28,9 @@ use common_net::{
}; };
use common_sys::state::BlockChange; use common_sys::state::BlockChange;
use comp::item::Reagent; use comp::item::Reagent;
use hashbrown::HashSet;
use rand::prelude::*; use rand::prelude::*;
use specs::{join::Join, saveload::MarkerAllocator, Entity as EcsEntity, WorldExt}; use specs::{join::Join, saveload::MarkerAllocator, Entity as EcsEntity, WorldExt};
use std::collections::HashSet;
use tracing::error; use tracing::error;
use vek::Vec3; use vek::Vec3;

View File

@ -15,6 +15,7 @@ use crate::{
convert_body_from_database, convert_body_to_database_json, convert_body_from_database, convert_body_to_database_json,
convert_character_from_database, convert_inventory_from_database_items, convert_character_from_database, convert_inventory_from_database_items,
convert_items_to_database_items, convert_loadout_from_database_items, convert_items_to_database_items, convert_loadout_from_database_items,
convert_skill_groups_to_database, convert_skills_to_database,
convert_stats_from_database, convert_stats_to_database, convert_stats_from_database, convert_stats_to_database,
convert_waypoint_from_database_json, convert_waypoint_from_database_json,
}, },
@ -58,7 +59,9 @@ pub fn load_character_data(
char_id: CharacterId, char_id: CharacterId,
connection: VelorenTransaction, connection: VelorenTransaction,
) -> CharacterDataResult { ) -> CharacterDataResult {
use schema::{body::dsl::*, character::dsl::*, item::dsl::*}; use schema::{
body::dsl::*, character::dsl::*, item::dsl::*, skill_group::dsl::*,
};
let character_containers = get_pseudo_containers(connection, char_id)?; let character_containers = get_pseudo_containers(connection, char_id)?;
@ -100,9 +103,22 @@ pub fn load_character_data(
}, },
}); });
let skill_data = schema::skill::dsl::skill
.filter(schema::skill::dsl::character_id.eq(char_id))
.load::<Skill>(&*connection)?;
let skill_group_data = skill_group
.filter(schema::skill_group::dsl::character_id.eq(char_id))
.load::<SkillGroup>(&*connection)?;
Ok(( Ok((
convert_body_from_database(&char_body)?, convert_body_from_database(&char_body)?,
convert_stats_from_database(&stats_data, character_data.alias), convert_stats_from_database(
&stats_data,
character_data.alias,
&skill_data,
&skill_group_data,
),
convert_inventory_from_database_items(&inventory_items, &loadout_items)?, convert_inventory_from_database_items(&inventory_items, &loadout_items)?,
char_waypoint, char_waypoint,
)) ))
@ -172,7 +188,7 @@ pub fn create_character(
check_character_limit(uuid, connection)?; check_character_limit(uuid, connection)?;
use schema::{body, character}; use schema::{body, character, skill_group};
let (body, stats, inventory, waypoint) = persisted_components; let (body, stats, inventory, waypoint) = persisted_components;
@ -218,6 +234,8 @@ pub fn create_character(
))); )));
} }
let skill_set = stats.skill_set.clone();
// Insert stats record // Insert stats record
let db_stats = convert_stats_to_database(character_id, &stats, &waypoint)?; let db_stats = convert_stats_to_database(character_id, &stats, &waypoint)?;
let stats_count = diesel::insert_into(schema::stats::table) let stats_count = diesel::insert_into(schema::stats::table)
@ -266,6 +284,18 @@ pub fn create_character(
))); )));
} }
let db_skill_groups = convert_skill_groups_to_database(character_id, skill_set.skill_groups);
let skill_groups_count = diesel::insert_into(skill_group::table)
.values(&db_skill_groups)
.execute(&*connection)?;
if skill_groups_count != 1 {
return Err(Error::OtherError(format!(
"Error inserting into skill_group table for char_id {}",
character_id
)));
}
// Insert default inventory and loadout item records // Insert default inventory and loadout item records
let mut inserts = Vec::new(); let mut inserts = Vec::new();
@ -305,7 +335,9 @@ pub fn delete_character(
char_id: CharacterId, char_id: CharacterId,
connection: VelorenTransaction, connection: VelorenTransaction,
) -> CharacterListResult { ) -> CharacterListResult {
use schema::{body::dsl::*, character::dsl::*, stats::dsl::*}; use schema::{
body::dsl::*, character::dsl::*, skill::dsl::*, skill_group::dsl::*, stats::dsl::*,
};
// Load the character to delete - ensures that the requesting player // Load the character to delete - ensures that the requesting player
// owns the character // owns the character
@ -317,6 +349,13 @@ pub fn delete_character(
) )
.first::<Character>(&*connection)?; .first::<Character>(&*connection)?;
// Delete skills
diesel::delete(skill_group.filter(schema::skill_group::dsl::character_id.eq(char_id)))
.execute(&*connection)?;
diesel::delete(skill.filter(schema::skill::dsl::character_id.eq(char_id)))
.execute(&*connection)?;
// Delete character // Delete character
let character_count = diesel::delete( let character_count = diesel::delete(
character character
@ -529,7 +568,7 @@ pub fn update(
char_waypoint: Option<comp::Waypoint>, char_waypoint: Option<comp::Waypoint>,
connection: VelorenTransaction, connection: VelorenTransaction,
) -> Result<Vec<Arc<common::comp::item::ItemId>>, Error> { ) -> Result<Vec<Arc<common::comp::item::ItemId>>, Error> {
use super::schema::item::dsl::*; use super::schema::{item::dsl::*, skill_group::dsl::*};
let pseudo_containers = get_pseudo_containers(connection, char_id)?; let pseudo_containers = get_pseudo_containers(connection, char_id)?;
@ -591,6 +630,20 @@ pub fn update(
} }
} }
let char_skill_set = char_stats.skill_set.clone();
let db_skill_groups = convert_skill_groups_to_database(char_id, char_skill_set.skill_groups);
diesel::replace_into(skill_group)
.values(&db_skill_groups)
.execute(&*connection)?;
let db_skills = convert_skills_to_database(char_id, char_skill_set.skills);
diesel::replace_into(schema::skill::dsl::skill)
.values(&db_skills)
.execute(&*connection)?;
let db_stats = convert_stats_to_database(char_id, &char_stats, &char_waypoint)?; let db_stats = convert_stats_to_database(char_id, &char_stats, &char_waypoint)?;
let stats_count = let stats_count =
diesel::update(schema::stats::dsl::stats.filter(schema::stats::dsl::stats_id.eq(char_id))) diesel::update(schema::stats::dsl::stats.filter(schema::stats::dsl::stats_id.eq(char_id)))

View File

@ -1,6 +1,6 @@
use crate::persistence::{ use crate::persistence::{
character::EntityId, character::EntityId,
models::{Body, Character, Item, Stats}, models::{Body, Character, Item, Skill, SkillGroup, Stats},
}; };
use crate::persistence::{ use crate::persistence::{
@ -15,11 +15,13 @@ use common::{
loadout_builder::LoadoutBuilder, loadout_builder::LoadoutBuilder,
slot::InvSlotId, slot::InvSlotId,
}, },
skills,
Body as CompBody, Waypoint, *, Body as CompBody, Waypoint, *,
}, },
resources::Time, resources::Time,
}; };
use core::{convert::TryFrom, num::NonZeroU64}; use core::{convert::TryFrom, num::NonZeroU64};
use hashbrown::HashMap;
use itertools::{Either, Itertools}; use itertools::{Either, Itertools};
use std::sync::Arc; use std::sync::Arc;
@ -342,7 +344,12 @@ pub fn convert_character_from_database(character: &Character) -> common::charact
} }
} }
pub fn convert_stats_from_database(stats: &Stats, alias: String) -> common::comp::Stats { pub fn convert_stats_from_database(
stats: &Stats,
alias: String,
skills: &[Skill],
skill_groups: &[SkillGroup],
) -> common::comp::Stats {
let mut new_stats = common::comp::Stats::empty(); let mut new_stats = common::comp::Stats::empty();
new_stats.name = alias; new_stats.name = alias;
new_stats.level.set_level(stats.level as u32); new_stats.level.set_level(stats.level as u32);
@ -356,6 +363,10 @@ pub fn convert_stats_from_database(stats: &Stats, alias: String) -> common::comp
new_stats.endurance = stats.endurance as u32; new_stats.endurance = stats.endurance as u32;
new_stats.fitness = stats.fitness as u32; new_stats.fitness = stats.fitness as u32;
new_stats.willpower = stats.willpower as u32; new_stats.willpower = stats.willpower as u32;
new_stats.skill_set = skills::SkillSet {
skill_groups: convert_skill_groups_from_database(skill_groups),
skills: convert_skills_from_database(skills),
};
new_stats new_stats
} }
@ -369,3 +380,72 @@ fn get_item_from_asset(item_definition_id: &str) -> Result<common::comp::Item, E
)) ))
}) })
} }
fn convert_skill_groups_from_database(skill_groups: &[SkillGroup]) -> Vec<skills::SkillGroup> {
let mut new_skill_groups = Vec::new();
for skill_group in skill_groups.iter() {
let skill_group_type =
serde_json::de::from_str::<skills::SkillGroupType>(&skill_group.skill_group_type)
.map_err(|err| {
Error::ConversionError(format!(
"Error de-serializing skill group: {} err: {}",
skill_group.skill_group_type, err
))
})
.unwrap();
let new_skill_group = skills::SkillGroup {
skill_group_type,
exp: skill_group.exp as u16,
available_sp: skill_group.available_sp as u16,
};
new_skill_groups.push(new_skill_group);
}
new_skill_groups
}
fn convert_skills_from_database(skills: &[Skill]) -> HashMap<skills::Skill, skills::Level> {
let mut new_skills = HashMap::new();
for skill in skills.iter() {
let new_skill = serde_json::de::from_str::<skills::Skill>(&skill.skill_type)
.map_err(|err| {
Error::ConversionError(format!(
"Error de-serializing skill: {} err: {}",
skill.skill_type, err
))
})
.unwrap();
new_skills.insert(new_skill, skill.level.map(|l| l as u16));
}
new_skills
}
pub fn convert_skill_groups_to_database(
character_id: CharacterId,
skill_groups: Vec<skills::SkillGroup>,
) -> Vec<SkillGroup> {
let db_skill_groups: Vec<_> = skill_groups
.into_iter()
.map(|sg| SkillGroup {
character_id,
skill_group_type: serde_json::to_string(&sg.skill_group_type).unwrap(),
exp: sg.exp as i32,
available_sp: sg.available_sp as i32,
})
.collect();
db_skill_groups
}
pub fn convert_skills_to_database(
character_id: CharacterId,
skills: HashMap<skills::Skill, skills::Level>,
) -> Vec<Skill> {
let db_skills: Vec<_> = skills
.iter()
.map(|(s, l)| Skill {
character_id,
skill_type: serde_json::to_string(&s).unwrap(),
level: l.map(|l| l as i32),
})
.collect();
db_skills
}

View File

@ -1,6 +1,6 @@
extern crate serde_json; extern crate serde_json;
use super::schema::{body, character, entity, item, stats}; use super::schema::{body, character, entity, item, skill, skill_group, stats};
#[derive(Debug, Insertable, PartialEq)] #[derive(Debug, Insertable, PartialEq)]
#[table_name = "entity"] #[table_name = "entity"]
@ -57,3 +57,22 @@ pub struct Body {
pub variant: String, pub variant: String,
pub body_data: String, pub body_data: String,
} }
#[derive(Associations, Identifiable, Insertable, Queryable, Debug)]
#[primary_key(character_id, skill_type)]
#[table_name = "skill"]
pub struct Skill {
pub character_id: i64,
pub skill_type: String,
pub level: Option<i32>,
}
#[derive(Associations, Identifiable, Insertable, Queryable, Debug)]
#[primary_key(character_id, skill_group_type)]
#[table_name = "skill_group"]
pub struct SkillGroup {
pub character_id: i64,
pub skill_group_type: String,
pub exp: i32,
pub available_sp: i32,
}

View File

@ -42,6 +42,24 @@ table! {
} }
} }
table! {
skill (character_id, skill_type) {
character_id -> BigInt,
#[sql_name = "skill"]
skill_type -> Text,
level -> Nullable<Integer>,
}
}
table! {
skill_group (character_id, skill_group_type) {
character_id -> BigInt,
skill_group_type -> Text,
exp -> Integer,
available_sp -> Integer,
}
}
joinable!(character -> body (character_id)); joinable!(character -> body (character_id));
joinable!(character -> stats (character_id)); joinable!(character -> stats (character_id));