Last active
September 9, 2020 14:10
-
-
Save colelawrence/43097f6bd1cadc15492c087732376d1d to your computer and use it in GitHub Desktop.
`shipyard_app` plugin for adding a "tracked" unique which is reset across updates.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//! A small change tracker to wrap around a unique so you can determine if the value changes between updates. | |
use crate::prelude::*; | |
use std::{fmt, ops::Deref, ops::DerefMut}; | |
pub struct TrackedUnique<T: ?Sized>(InnerTrackedState, T); | |
pub type TrackedUniqueView<'a, T> = UniqueView<'a, TrackedUnique<T>>; | |
pub type TrackedUniqueViewMut<'a, T> = UniqueViewMut<'a, TrackedUnique<T>>; | |
#[derive(PartialEq)] | |
enum InnerTrackedState { | |
New, | |
Modified, | |
NoChanges, | |
} | |
impl<T> TrackedUnique<T> { | |
pub fn new(value: T) -> Self { | |
TrackedUnique(InnerTrackedState::New, value) | |
} | |
pub fn reset_tracking(&mut self) { | |
self.0 = InnerTrackedState::NoChanges; | |
} | |
pub fn is_new_or_modified(&self) -> bool { | |
return self.0 != InnerTrackedState::NoChanges; | |
} | |
} | |
impl<T: ?Sized> TrackedUnique<T> {} | |
impl<T: ?Sized> Deref for TrackedUnique<T> { | |
type Target = T; | |
#[inline(always)] | |
fn deref(&self) -> &T { | |
&self.1 | |
} | |
} | |
impl<T: ?Sized> DerefMut for TrackedUnique<T> { | |
#[inline(always)] | |
fn deref_mut(&mut self) -> &mut T { | |
self.0 = InnerTrackedState::Modified; | |
&mut self.1 | |
} | |
} | |
impl<T: ?Sized> AsRef<T> for TrackedUnique<T> { | |
fn as_ref(&self) -> &T { | |
&**self | |
} | |
} | |
impl<T: ?Sized> AsMut<T> for TrackedUnique<T> { | |
fn as_mut(&mut self) -> &mut T { | |
&mut **self | |
} | |
} | |
impl<T: ?Sized + fmt::Display> fmt::Display for TrackedUnique<T> { | |
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
fmt::Display::fmt(&**self, f) | |
} | |
} | |
impl<T: ?Sized + fmt::Debug> fmt::Debug for TrackedUnique<T> { | |
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
fmt::Debug::fmt(&**self, f) | |
} | |
} | |
/// Add [TrackedUnique] of `T` and reset tracking at the end of every update. | |
#[derive(Default)] | |
pub struct TrackedUniquePlugin<T: Clone + Send + Sync + 'static>(T); | |
impl<T: Clone + Send + Sync + 'static> TrackedUniquePlugin<T> { | |
pub fn new(initial_value: T) -> Self { | |
TrackedUniquePlugin(initial_value) | |
} | |
} | |
impl<T: Clone + Send + Sync + 'static> Plugin for TrackedUniquePlugin<T> { | |
fn build(&self, app: &mut AppBuilder) { | |
app.add_unique(TrackedUnique::new(self.0.clone())) | |
.add_systems_to_stage(stage::LAST, |wb| { | |
wb.with_system(system!(clear_tracked_unique::<T>)); | |
}); | |
} | |
} | |
fn clear_tracked_unique<T>(mut uvm_tracked_unique_t: UniqueViewMut<TrackedUnique<T>>) { | |
uvm_tracked_unique_t.reset_tracking(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//! # Atom Display Plugin | |
//! | |
//! The [AtomDisplayPlugin] will add the [AtomDisplay] to all entities with [ecs::EcsAtomKind]. | |
//! | |
//! It uses the current [DisplayLanguage] to determine which language should be chosen | |
//! for displaying each atom. It will look up the [ecs::EcsAtomKind] info in the registry | |
//! to choose the most appropriate name for the atom kind for the language available. | |
use super::display_language_plugin::*; | |
use crate::prelude::*; | |
use storycore::registry::REGISTRY_LOOKUP; | |
/// Display text | |
/// | |
/// Example: `[slack]`, `[@Person]`, would all have an [AtomDisplay] with "slack", "Person" values respectively. | |
/// Token is written as "once" or "when" or in another language even | |
/// | |
/// 💠 Component (derived) for Atoms | |
#[derive(Clone, Debug, PartialEq)] | |
pub struct AtomDisplay(String); | |
impl AtomDisplay { | |
pub fn to_string(&self) -> String { | |
self.0.clone() | |
} | |
} | |
#[derive(Default)] | |
pub struct AtomDisplayPlugin(()); | |
impl Plugin for AtomDisplayPlugin { | |
fn build(&self, app: &mut AppBuilder) { | |
app.update_pack::<ecs::EcsAtomKind>("to refresh correct displays for AtomDisplay") | |
.depends_on_unique::<Tracked<DisplayLanguage>>( | |
"to choose the correct language to display text for Atoms with", | |
) | |
.add_systems_to_stage(stage::POST_UPDATE, |workload_builder| { | |
workload_builder.with_system(system!(atom_display_indexing)); | |
}); | |
} | |
} | |
fn atom_display_indexing( | |
tuv_display_language: TrackedUniqueView<DisplayLanguage>, | |
v_atom_kind: View<ecs::EcsAtomKind>, | |
mut vm_atom_display: ViewMut<AtomDisplay>, | |
) { | |
if tuv_display_language.is_new_or_modified() { | |
// applied language is out of date, so update all | |
trace!(lang = ?*tuv_display_language, "applied language is out of date, so update all atom displays"); | |
for (entity_id, updated_value) in v_atom_kind.iter().with_id() { | |
vm_atom_display.add_component_unchecked( | |
lookup_display(&updated_value, &tuv_display_language), | |
entity_id, | |
); | |
} | |
} else { | |
// only check changed atom kinds | |
// remove displays from deleted atom kinds | |
for (entity_id, _) in v_atom_kind.deleted() { | |
vm_atom_display.delete(*entity_id); | |
} | |
// update changed atom kinds | |
for (entity_id, updated_value) in v_atom_kind.inserted_or_modified().iter().with_id() { | |
vm_atom_display.add_component_unchecked( | |
lookup_display(&updated_value, &tuv_display_language), | |
entity_id, | |
); | |
} | |
} | |
} | |
/// NOTE: Consider how we'd use [DisplayLanguage] to propagate back up the "best" [AtomDisplay] info. | |
/// This might mean that [AtomDisplay] needs to have more granular information about the ordering depending | |
/// on language as well. | |
fn lookup_display(kind: &ecs::EcsAtomKind, _lang: &DisplayLanguage) -> AtomDisplay { | |
let found_opt: Option<String> = match kind { | |
ecs::EcsAtomKind::Service { | |
service_local_id: _, | |
service_registry_id, | |
} => REGISTRY_LOOKUP.get_service_display_name(&service_registry_id), | |
ecs::EcsAtomKind::ServiceAction { | |
action_registry_id, | |
depends_on_atom: _, | |
} => REGISTRY_LOOKUP.get_service_action_display_name(&action_registry_id), | |
ecs::EcsAtomKind::ServiceEvent { | |
depends_on_atom: _, | |
event_registry_id, | |
} => REGISTRY_LOOKUP.get_service_event_display_name(&event_registry_id), | |
ecs::EcsAtomKind::ServiceParam { | |
depends_on_atom: _, | |
field_registry_id, | |
field_value: _, | |
} => REGISTRY_LOOKUP.get_service_field_display_name(&field_registry_id), | |
ecs::EcsAtomKind::ValueConstant(constant) => Some(constant.display_text.clone()), | |
ecs::EcsAtomKind::ValueReference(_) | ecs::EcsAtomKind::ValueRefinement(_) => None, | |
}; | |
AtomDisplay(found_opt.unwrap_or_else(|| { | |
warn!(?kind, ?_lang, "TODO: need to actually look up the atom kind in the registry to get the display based on user language"); | |
format!("{:?}", kind) | |
})) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use crate::prelude::*; | |
/// Used as unique as well as a data type | |
#[derive(Clone, Debug, PartialEq)] | |
pub enum DisplayLanguage { | |
English, | |
} | |
impl Default for DisplayLanguage { | |
fn default() -> Self { | |
DisplayLanguage::English | |
} | |
} | |
#[derive(Default)] | |
pub struct DisplayLanguagePlugin { | |
initial_language: DisplayLanguage, | |
} | |
impl DisplayLanguagePlugin { | |
pub fn new_with_initial_language(initial_language: DisplayLanguage) -> Self { | |
DisplayLanguagePlugin { initial_language } | |
} | |
} | |
impl Plugin for DisplayLanguagePlugin { | |
fn build(&self, app: &mut AppBuilder) { | |
app.add_plugin(plugins::TrackedUniquePlugin::new( | |
self.initial_language.clone(), | |
)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment