Load and insert a characters achievement list after completion of their body/stats/inventory data.

This commit is contained in:
Shane Handley
2020-07-05 06:53:15 +10:00
parent e7c47e1d38
commit fb8590fac7
11 changed files with 59 additions and 32 deletions

View File

@ -992,16 +992,15 @@ impl Client {
self.view_distance = Some(vd);
frontend_events.push(Event::SetViewDistance(vd));
},
ServerMsg::AchievementDataUpdate(achievements) => {
// TODO should this happen? Can't you just save it
// against the entity on the server and it will et
// synced?
ServerMsg::CharacterAchievementDataLoaded(achievement_list) => {
self.state.write_component(self.entity, achievement_list);
},
ServerMsg::AchievementDataError(error) => {
ServerMsg::CharacterAchievementDataError(error) => {
// TODO handle somehow
},
ServerMsg::AchievementCompletion => {
tracing::info!("Completed achievement");
ServerMsg::AchievementCompletion(achievement) => {
// TODO handle in UI
tracing::info!(?achievement, "Completed achievement");
},
}
}

View File

@ -88,8 +88,12 @@ impl Achievement {
}
}
/// The achievement List assigned to all players. This holds a list of
/// achievements where the player has made some progress towards completion.
/// Each character is assigned an achievement list, which holds information
/// about which achievements that the player has made some progress on, or
/// completed.
///
/// This minimises storage of data per-character, and can be merged with a full
/// achievement list
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct AchievementList(Vec<Achievement>);
@ -97,6 +101,10 @@ impl Default for AchievementList {
fn default() -> AchievementList { AchievementList(Vec::new()) }
}
impl AchievementList {
pub fn from(data: Vec<Achievement>) -> Self { Self(data) }
}
impl Component for AchievementList {
type Storage = FlaggedStorage<Self, IDVStorage<Self>>;
}

View File

@ -60,7 +60,7 @@ pub enum ServerEvent {
},
UpdateCharacterData {
entity: EcsEntity,
components: (comp::Body, comp::Stats, comp::Inventory, comp::Loadout),
components: (i32, comp::Body, comp::Stats, comp::Inventory, comp::Loadout),
},
ExitIngame {
entity: EcsEntity,

View File

@ -61,11 +61,11 @@ pub enum ServerMsg {
},
/// A list of achievements which the character has fully or partially
/// completed
AchievementDataUpdate(Vec<comp::Achievement>),
CharacterAchievementDataLoaded(comp::AchievementList),
/// An error occurred while loading character achievements
AchievementDataError(String),
CharacterAchievementDataError(String),
/// The client has completed an achievement
AchievementCompletion,
AchievementCompletion(comp::AchievementItem),
/// An error occurred while loading character data
CharacterDataLoadError(String),
/// A list of characters belonging to the a authenticated player was sent

View File

@ -1,9 +1,12 @@
[
(
title: "Collect 5 Apples",
action: CollectItemKind(Consumable(
kind: Apple
)),
action: CollectConsumable(Apple),
target: 5
),
(
title: "Collect 7 Apples",
action: CollectConsumable(Apple),
target: 7
)
]

View File

@ -16,7 +16,7 @@ pub fn handle_initialize_character(server: &mut Server, entity: EcsEntity, chara
pub fn handle_loaded_character_data(
server: &mut Server,
entity: EcsEntity,
loaded_components: (comp::Body, comp::Stats, comp::Inventory, comp::Loadout),
loaded_components: (i32, comp::Body, comp::Stats, comp::Inventory, comp::Loadout),
) {
server
.state

View File

@ -486,10 +486,14 @@ impl Server {
entity,
result,
)) => match result {
Ok(achievement_data) => self
.notify_client(entity, ServerMsg::AchievementDataUpdate(achievement_data)),
Err(error) => self
.notify_client(entity, ServerMsg::AchievementDataError(error.to_string())),
Ok(achievement_data) => self.notify_client(
entity,
ServerMsg::CharacterAchievementDataLoaded(achievement_data),
),
Err(error) => self.notify_client(
entity,
ServerMsg::CharacterAchievementDataError(error.to_string()),
),
},
});

View File

@ -29,7 +29,7 @@ enum AchievementLoaderRequestKind {
},
}
type LoadCharacterAchievementsResult = (specs::Entity, Result<Vec<comp::Achievement>, Error>);
type LoadCharacterAchievementsResult = (specs::Entity, Result<comp::AchievementList, Error>);
/// Wrapper for results
#[derive(Debug)]
@ -100,15 +100,17 @@ impl Drop for AchievementLoader {
fn load_character_achievement_list(
character_id: i32,
db_dir: &str,
) -> Result<Vec<comp::Achievement>, Error> {
) -> Result<comp::AchievementList, Error> {
let character_achievements = schema::character_achievement::dsl::character_achievement
.filter(schema::character_achievement::character_id.eq(character_id))
.load::<CharacterAchievement>(&establish_connection(db_dir))?;
Ok(character_achievements
.iter()
.map(comp::Achievement::from)
.collect::<Vec<comp::Achievement>>())
Ok(comp::AchievementList::from(
character_achievements
.iter()
.map(comp::Achievement::from)
.collect::<Vec<comp::Achievement>>(),
))
}
pub fn sync(db_dir: &str) -> Result<Vec<AchievementModel>, Error> {

View File

@ -49,7 +49,7 @@ enum CharacterLoaderRequestKind {
}
/// A tuple of the components that are persisted to the DB for each character
pub type PersistedComponents = (comp::Body, comp::Stats, comp::Inventory, comp::Loadout);
pub type PersistedComponents = (i32, comp::Body, comp::Stats, comp::Inventory, comp::Loadout);
type CharacterListResult = Result<Vec<CharacterItem>, Error>;
type CharacterDataResult = Result<PersistedComponents, Error>;
@ -236,6 +236,7 @@ impl Drop for CharacterLoader {
fn load_character_data(player_uuid: &str, character_id: i32, db_dir: &str) -> CharacterDataResult {
let connection = establish_connection(db_dir);
<<<<<<< HEAD
let result = schema::character::dsl::character
.filter(schema::character::id.eq(character_id))
.filter(schema::character::player_uuid.eq(player_uuid))

View File

@ -1,6 +1,9 @@
use crate::{
client::Client, persistence::character::PersistedComponents, settings::ServerSettings,
sys::sentinel::DeletedEntities, SpawnPoint,
client::Client,
persistence::{achievement::AchievementLoader, character::PersistedComponents},
settings::ServerSettings,
sys::sentinel::DeletedEntities,
SpawnPoint,
};
use common::{
comp,
@ -208,7 +211,14 @@ impl StateExt for State {
}
fn update_character_data(&mut self, entity: EcsEntity, components: PersistedComponents) {
let (body, stats, inventory, loadout) = components;
let (character_id, body, stats, inventory, loadout) = components;
// Now that data essential for loading into the world has returned, kick of a
// request for supplemental game data, such as achievements
self.ecs()
.read_resource::<AchievementLoader>()
.load_character_achievement_list(entity, character_id);
// Make sure physics are accepted.
self.write_component(entity, comp::ForceUpdate);

View File

@ -37,7 +37,7 @@ impl<'a> System<'a> for Sys {
.process_achievement(Achievement::from(achievement), ach_update.event())
== true
{
client.notify(ServerMsg::AchievementCompletion);
client.notify(ServerMsg::AchievementCompletion(achievement_item));
}
}
});