From c8675eaf45dc40243762b913446a00ba7e838076 Mon Sep 17 00:00:00 2001 From: Sam Date: Sun, 14 Nov 2021 13:32:37 -0500 Subject: [PATCH] Added hash value to decide if we should invalidate persited skills and allow a respec. --- Cargo.lock | 48 +++++++++++++++++++ common/Cargo.toml | 2 + common/src/comp/inventory/item/tool.rs | 2 +- common/src/comp/skillset/mod.rs | 27 +++++++++-- common/src/comp/skillset/skills.rs | 24 +++++----- .../src/persistence/character/conversions.rs | 19 ++++++-- 6 files changed, 100 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ffd6f77b0c..d55b8d2787 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -428,6 +428,15 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array 0.14.4", +] + [[package]] name = "bstr" version = "0.2.17" @@ -962,6 +971,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "cpufeatures" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +dependencies = [ + "libc", +] + [[package]] name = "cranelift-bforest" version = "0.74.0" @@ -1381,6 +1399,15 @@ version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2c9736e15e7df1638a7f6eee92a6511615c738246a052af5ba86f039b65aede" +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.4", +] + [[package]] name = "directories-next" version = "2.0.0" @@ -3804,6 +3831,12 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + [[package]] name = "openssl-probe" version = "0.1.4" @@ -5122,6 +5155,19 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" +[[package]] +name = "sha2" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" +dependencies = [ + "block-buffer", + "cfg-if 1.0.0", + "cpufeatures", + "digest", + "opaque-debug", +] + [[package]] name = "shaderc" version = "0.6.3" @@ -6145,6 +6191,7 @@ name = "veloren-common" version = "0.10.0" dependencies = [ "approx 0.4.0", + "bincode", "bitflags", "chrono", "chrono-tz", @@ -6170,6 +6217,7 @@ dependencies = [ "roots", "serde", "serde_repr", + "sha2", "slab", "slotmap 1.0.6", "specs", diff --git a/common/Cargo.toml b/common/Cargo.toml index 8e5977d4bf..1dc4a059e1 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -29,6 +29,8 @@ enum-iterator = "0.7" vek = { version = "=0.14.1", features = ["serde"] } chrono = "0.4" chrono-tz = "0.6" +sha2 = "0.9.8" +bincode = "1.3.1" # Strum strum = { version = "0.23", features = ["derive"] } diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index e7d64afe5d..f47cd1eff0 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -12,7 +12,7 @@ use std::{ time::Duration, }; -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Ord, PartialOrd)] pub enum ToolKind { // weapons Sword, diff --git a/common/src/comp/skillset/mod.rs b/common/src/comp/skillset/mod.rs index 68333d4342..e895586c6e 100644 --- a/common/src/comp/skillset/mod.rs +++ b/common/src/comp/skillset/mod.rs @@ -5,18 +5,20 @@ use crate::{ skills::{GeneralSkill, Skill}, }, }; -use hashbrown::{HashMap, HashSet}; +use bincode; +use hashbrown::HashMap; use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; use specs::{Component, DerefFlaggedStorage}; use specs_idvs::IdvStorage; -use std::hash::Hash; +use std::{collections::BTreeSet, hash::Hash}; use tracing::{trace, warn}; pub mod skills; #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct SkillTreeMap(HashMap>); +pub struct SkillTreeMap(HashMap>); impl Asset for SkillTreeMap { type Loader = assets::RonLoader; @@ -25,7 +27,7 @@ impl Asset for SkillTreeMap { } pub struct SkillGroupDef { - pub skills: HashSet, + pub skills: BTreeSet, pub total_skill_point_cost: u16, } @@ -94,9 +96,24 @@ lazy_static! { "common.skill_trees.skill_prerequisites", ).0 }; + pub static ref SKILL_GROUP_HASHES: HashMap> = { + let map = SkillTreeMap::load_expect_cloned( + "common.skill_trees.skills_skill-groups_manifest", + ).0; + let mut hashes = HashMap::new(); + for (skill_group_kind, skills) in map.iter() { + let mut hasher = Sha256::new(); + let bincode_input: Vec<_> = skills.iter().map(|skill| (*skill, skill.max_level())).collect(); + let hash_input = bincode::serialize(&bincode_input).unwrap_or_default(); + hasher.update(hash_input); + let hash_result = hasher.finalize(); + hashes.insert(*skill_group_kind, hash_result.iter().copied().collect()); + } + hashes + }; } -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize, Ord, PartialOrd)] pub enum SkillGroupKind { General, Weapon(ToolKind), diff --git a/common/src/comp/skillset/skills.rs b/common/src/comp/skillset/skills.rs index df863cc2ea..ba86636917 100644 --- a/common/src/comp/skillset/skills.rs +++ b/common/src/comp/skillset/skills.rs @@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize}; /// handled by dedicated ECS systems. // NOTE: if skill does use some constant, add it to corresponding // SkillTree Modifiers below. -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize, Ord, PartialOrd)] pub enum Skill { General(GeneralSkill), Sword(SwordSkill), @@ -26,7 +26,7 @@ pub enum Skill { UnlockGroup(SkillGroupKind), } -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize, Ord, PartialOrd)] pub enum SwordSkill { // Sword passives InterruptingAttacks, @@ -50,7 +50,7 @@ pub enum SwordSkill { SSpins, } -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize, Ord, PartialOrd)] pub enum AxeSkill { // Double strike upgrades DsCombo, @@ -71,7 +71,7 @@ pub enum AxeSkill { LDistance, } -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize, Ord, PartialOrd)] pub enum HammerSkill { // Single strike upgrades SsKnockback, @@ -92,7 +92,7 @@ pub enum HammerSkill { LRange, } -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize, Ord, PartialOrd)] pub enum BowSkill { // Passives ProjSpeed, @@ -114,7 +114,7 @@ pub enum BowSkill { SSpread, } -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize, Ord, PartialOrd)] pub enum StaffSkill { // Basic ranged upgrades BDamage, @@ -133,7 +133,7 @@ pub enum StaffSkill { SCost, } -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize, Ord, PartialOrd)] pub enum SceptreSkill { // Lifesteal beam upgrades LDamage, @@ -153,31 +153,31 @@ pub enum SceptreSkill { ACost, } -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize, Ord, PartialOrd)] pub enum GeneralSkill { HealthIncrease, EnergyIncrease, } -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize, Ord, PartialOrd)] pub enum RollSkill { Cost, Strength, Duration, } -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize, Ord, PartialOrd)] pub enum ClimbSkill { Cost, Speed, } -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize, Ord, PartialOrd)] pub enum SwimSkill { Speed, } -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize, Ord, PartialOrd)] pub enum MiningSkill { Speed, OreGain, diff --git a/server/src/persistence/character/conversions.rs b/server/src/persistence/character/conversions.rs index a6f8e28030..fd4df48bff 100644 --- a/server/src/persistence/character/conversions.rs +++ b/server/src/persistence/character/conversions.rs @@ -547,9 +547,17 @@ fn convert_skill_groups_from_database( while new_skill_group.earn_skill_point().is_ok() {} new_skill_groups.push(new_skill_group); - let mut new_skills = - serde_json::from_str::>(&skill_group.skills).unwrap_or_default(); - skills.append(&mut new_skills); + // If the hash stored of the skill group is the same as the current hash of the + // skill group, don't invalidate skills + if serde_json::from_str::>(&skill_group.hash_val) + .ok() + .as_ref() + == skillset::SKILL_GROUP_HASHES.get(&skill_group_kind) + { + let mut new_skills = + serde_json::from_str::>(&skill_group.skills).unwrap_or_default(); + skills.append(&mut new_skills); + } } (new_skill_groups, skills) } @@ -566,7 +574,10 @@ pub fn convert_skill_groups_to_database( earned_exp: sg.earned_exp as i32, // If fails to convert, just forces a respec on next login skills: serde_json::to_string(&sg.ordered_skills).unwrap_or_else(|_| "".to_string()), - hash_val: "".to_string(), + hash_val: serde_json::to_string( + &skillset::SKILL_GROUP_HASHES.get(&sg.skill_group_kind), + ) + .unwrap_or_else(|_| "".to_string()), }) .collect() }