Skip to content

Commit

Permalink
chore: Unify concepts of Flag
Browse files Browse the repository at this point in the history
  • Loading branch information
lgrossi committed Apr 27, 2024
1 parent 378165e commit 59572ab
Show file tree
Hide file tree
Showing 21 changed files with 218 additions and 187 deletions.
17 changes: 12 additions & 5 deletions crates/ryot/src/plugins/game.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use bevy_app::{App, Last, Plugin, PostUpdate, Update};
use bevy_ecs::prelude::*;
use ryot_internal::prelude::*;
use std::marker::PhantomData;

pub struct GamePlugin;

Expand All @@ -25,15 +26,21 @@ impl Plugin for ElevationPlugin {
}
}

/// `TileFlagPlugin` provides the necessary system and resource setup for managing `TileFlags`
/// `NavigablePlugin` provides the necessary system and resource setup for managing `Navigable`
/// within the game world. It ensures that the flag cache is up-to-date and reflects the latest
/// flag state of the whole tile, per position. This avoids the need to iterate over each entity
/// within a tile to check its properties.
pub struct TileFlagPlugin;
pub struct NavigablePlugin<N: Navigable + Copy + Default + Component>(PhantomData<N>);

impl Plugin for TileFlagPlugin {
impl<N: Navigable + Copy + Default + Component> Default for NavigablePlugin<N> {
fn default() -> Self {
Self(PhantomData)
}
}

impl<N: Navigable + Copy + Default + Component> Plugin for NavigablePlugin<N> {
fn build(&self, app: &mut App) {
app.init_resource::<Cache<TilePosition, TileFlags>>()
.add_systems(PostUpdate, update_tile_flag_cache);
app.init_resource::<Cache<TilePosition, N>>()
.add_systems(PostUpdate, update_tile_flag_cache::<N>);
}
}
2 changes: 1 addition & 1 deletion crates/ryot/src/plugins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub mod prelude {
content_plugin,
plugins::{
content::{BaseContentPlugin, MetaContentPlugin, VisualContentPlugin},
game::{ElevationPlugin, GamePlugin, TileFlagPlugin},
game::{ElevationPlugin, GamePlugin, NavigablePlugin},
sprites::{RyotDrawingPlugin, RyotSpritePlugin},
},
};
Expand Down
File renamed without changes.
36 changes: 3 additions & 33 deletions crates/ryot_core/src/content/mod.rs
Original file line number Diff line number Diff line change
@@ -1,39 +1,9 @@
use crate::prelude::*;
use serde::{Deserialize, Serialize};

mod entity;
pub use entity::{ContentId, ContentType};
mod id;
pub use id::{ContentId, ContentType};

pub mod sprite;

mod state;
pub use state::{transition_to_ready, RyotContentState};

mod visual_element;
pub use visual_element::{VisualElement, VisualElements};

/// Ryot expects the sprite sheets to be cataloged in a JSON file. This file contains a list of
/// elements of type `SpriteSheet` that represents the sprite sheet information.
/// This struct is a default representation of this catalog file and ignores the other fields
/// that your JSON might have.
///
/// You can use your own json struct to represent the catalog file, as long as it implements
/// the Into<Option<SpriteSheet>> + Clone.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[cfg_attr(feature = "bevy", derive(bevy_reflect::TypePath))]
#[serde(tag = "type")]
pub enum ContentRecord {
#[serde(rename = "sprite")]
SpriteSheet(SpriteSheet),
#[serde(other, rename = "unknown")]
Unknown,
}

impl From<ContentRecord> for Option<SpriteSheet> {
fn from(content: ContentRecord) -> Self {
match content {
ContentRecord::SpriteSheet(sprite_sheet) => Some(sprite_sheet),
_ => None,
}
}
}
pub mod record;
14 changes: 14 additions & 0 deletions crates/ryot_core/src/content/record/category.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum Category {
Bottom,
Containers,
Corpses,
Decor,
Edges,
Ground,
#[default]
Miscellaneous,
Top,
Wearable,
Custom(i32),
}
70 changes: 70 additions & 0 deletions crates/ryot_core/src/content/record/flags.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use crate::prelude::Navigable;

/// Standard implementation of `Navigable` used within the Ryot framework.
///
/// `Flags` struct serves as the default data structure for encoding walkability and sight-blocking
/// attributes of game elements, particularly those defined in the content catalog. It is used as
/// a component in ECS to assign physical properties to visual elements like tiles and objects,
/// supporting straightforward integration with pathfinding and visibility checks.
///
/// # Attributes
/// * `is_walkable` - Indicates whether the element permits movement over it.
/// * `blocks_sight` - Determines if the element impedes vision.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "bevy", derive(bevy_ecs::prelude::Component))]
pub struct Flags {
pub is_walkable: bool,
pub blocks_sight: bool,
}

impl Default for Flags {
fn default() -> Self {
Flags {
is_walkable: true,
blocks_sight: false,
}
}
}

impl Flags {
pub fn new(is_walkable: bool, blocks_sight: bool) -> Self {
Flags {
is_walkable,
blocks_sight,
}
}

pub fn with_walkable(self, is_walkable: bool) -> Self {
Flags {
is_walkable,
..self
}
}

pub fn with_blocks_sight(self, blocks_sight: bool) -> Self {
Flags {
blocks_sight,
..self
}
}
}

impl Navigable for Flags {
fn is_walkable(&self) -> bool {
self.is_walkable
}

fn blocks_sight(&self) -> bool {
self.blocks_sight
}

fn append(mut self, navigable: &impl Navigable) -> Self {
self.is_walkable &= navigable.is_walkable();
self.blocks_sight |= navigable.blocks_sight();
self
}

fn is_default(&self) -> bool {
*self == Flags::default()
}
}
37 changes: 37 additions & 0 deletions crates/ryot_core/src/content/record/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use crate::prelude::*;
use serde::{Deserialize, Serialize};

mod category;
pub use category::Category;

mod flags;
pub use flags::Flags;

mod visual_element;
pub use visual_element::{VisualElement, VisualElements};

/// Ryot expects the sprite sheets to be cataloged in a JSON file. This file contains a list of
/// elements of type `SpriteSheet` that represents the sprite sheet information.
/// This struct is a default representation of this catalog file and ignores the other fields
/// that your JSON might have.
///
/// You can use your own json struct to represent the catalog file, as long as it implements
/// the Into<Option<SpriteSheet>> + Clone.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[cfg_attr(feature = "bevy", derive(bevy_reflect::TypePath))]
#[serde(tag = "type")]
pub enum ContentRecord {
#[serde(rename = "sprite")]
SpriteSheet(SpriteSheet),
#[serde(other, rename = "unknown")]
Unknown,
}

impl From<ContentRecord> for Option<SpriteSheet> {
fn from(content: ContentRecord) -> Self {
match content {
ContentRecord::SpriteSheet(sprite_sheet) => Some(sprite_sheet),
_ => None,
}
}
}
15 changes: 0 additions & 15 deletions crates/ryot_core/src/game/flags.rs

This file was deleted.

19 changes: 2 additions & 17 deletions crates/ryot_core/src/game/mod.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,5 @@
mod properties;
pub use properties::{Elevation, Properties};

mod flags;
pub use flags::Flags;

#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum Category {
Bottom,
Containers,
Corpses,
Decor,
Edges,
Ground,
#[default]
Miscellaneous,
Top,
Wearable,
Custom(i32),
}
mod navigable;
pub use navigable::Navigable;
46 changes: 46 additions & 0 deletions crates/ryot_core/src/game/navigable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/// Defines behavior for tiles or entities in terms of navigation and visibility within the Ryot framework.
///
/// This trait abstracts the walkability and sight-blocking properties to ensure compatibility with
/// generic systems such as pathfinding and ray-casting, facilitating their application across
/// different types of game environments and scenarios.
///
/// Implementing this trait allows for consistent behavior across various game elements, making
/// it integral to developing flexible and reusable game mechanics.
///
/// # Examples
///
/// Implementing `Navigable` for a custom tile type might look like this:
///
/// ```
/// use ryot_core::prelude::Navigable;
///
/// #[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
/// struct CustomTile {
/// walkable: bool,
/// sight_blocking: bool,
/// }
///
/// impl Navigable for CustomTile {
/// fn is_walkable(&self) -> bool {
/// self.walkable
/// }
///
/// fn blocks_sight(&self) -> bool {
/// self.sight_blocking
/// }
///
/// fn append(self, navigable: &impl Navigable) -> Self{
/// self
/// }
///
/// fn is_default(&self) -> bool {
/// true
/// }
/// }
/// ```
pub trait Navigable: Sync + Send + 'static {
fn is_walkable(&self) -> bool;
fn blocks_sight(&self) -> bool;
fn append(self, navigable: &impl Navigable) -> Self;
fn is_default(&self) -> bool;
}
5 changes: 3 additions & 2 deletions crates/ryot_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@ mod tests;
pub mod prelude {
pub use crate::{
content::{
record::{Category, ContentRecord, Flags, VisualElement, VisualElements},
sprite::{
layout::{SpriteLayout, SpriteLayoutIter, TextureAtlasLayouts},
sprite_sheet::{SpriteSheet, SpriteSheets},
Animation, FrameGroup, SpriteInfo,
},
ContentId, ContentRecord, ContentType, RyotContentState, VisualElement, VisualElements,
ContentId, ContentType, RyotContentState,
},
game::{Category, Elevation, Flags, Properties},
game::{Elevation, Navigable, Properties},
};

#[cfg(feature = "bevy")]
Expand Down
11 changes: 7 additions & 4 deletions crates/ryot_pathfinder/src/pathable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ use crate::prelude::PathFindingSystems;
use crate::systems::{handle_path_finding_tasks, trigger_path_finding_tasks};
use bevy_app::{App, Update};
use bevy_ecs::prelude::*;
use ryot_utils::Flag;
use ryot_core::prelude::Navigable;
use std::hash::Hash;
use std::time::Duration;

/// Represents an App that can add one or more `Pathable` to its systems.
/// Requires the `Cache<P, F>` resource to be initialized.
pub trait PathableApp {
fn add_pathable<P: Pathable + Component, F: Flag>(&mut self) -> &mut Self;
fn add_pathable<P: Pathable + Component, N: Navigable + Copy + Default>(&mut self)
-> &mut Self;
}

/// Represents an element that can be used in path finding calculations.
Expand All @@ -33,11 +34,13 @@ pub trait Pathable: Eq + Hash + Copy + Clone + Sync + Send + 'static {
}

impl PathableApp for App {
fn add_pathable<P: Pathable + Component, F: Flag>(&mut self) -> &mut Self {
fn add_pathable<P: Pathable + Component, N: Navigable + Copy + Default>(
&mut self,
) -> &mut Self {
self.add_systems(
Update,
(
trigger_path_finding_tasks::<P, F>.in_set(PathFindingSystems::TriggerTask),
trigger_path_finding_tasks::<P, N>.in_set(PathFindingSystems::TriggerTask),
handle_path_finding_tasks::<P>
.in_set(PathFindingSystems::ExecuteTask)
.after(PathFindingSystems::TriggerTask),
Expand Down
6 changes: 3 additions & 3 deletions crates/ryot_pathfinder/src/systems.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use crate::components::{Path, PathFindingQuery, PathFindingTask};
use crate::prelude::Pathable;
use bevy_ecs::prelude::*;
use bevy_tasks::*;
use ryot_core::prelude::Navigable;
use ryot_utils::prelude::*;
use ryot_utils::Flag;

/// Defines system sets for managing perspective calculation systems.
/// This enum categorizes systems related to perspective calculations, facilitating the organization
Expand All @@ -16,9 +16,9 @@ pub enum PathFindingSystems {

/// System that performs a path finding request query and starts a path finding
/// async task based on the request params.
pub(super) fn trigger_path_finding_tasks<P: Pathable + Component, F: Flag>(
pub(super) fn trigger_path_finding_tasks<P: Pathable + Component, N: Navigable + Copy + Default>(
mut commands: Commands,
tile_flags_cache: Res<Cache<P, F>>,
tile_flags_cache: Res<Cache<P, N>>,
q_path_finding_query: Query<(Entity, &P, &PathFindingQuery<P>), Changed<PathFindingQuery<P>>>,
) {
for (entity, from, query) in &q_path_finding_query {
Expand Down
5 changes: 3 additions & 2 deletions crates/ryot_ray_casting/src/systems.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use crate::prelude::*;
use bevy_ecs::prelude::*;
use itertools::Itertools;
use ryot_core::prelude::Navigable;
use ryot_tiled::prelude::*;
use ryot_utils::prelude::*;
use std::sync::mpsc;
Expand Down Expand Up @@ -40,8 +41,8 @@ pub fn update_intersection_cache<T: Trajectory>(
/// conditions (e.g., obstructions, visibility flags) and updates each entity's InterestPositions.
///
/// Run as part of [`PerspectiveSystems::CalculatePerspectives`].
pub fn process_perspectives<T: Trajectory, F: Flag>(
tile_flags_cache: Res<Cache<TilePosition, F>>,
pub fn process_perspectives<T: Trajectory, N: Navigable + Copy + Default>(
tile_flags_cache: Res<Cache<TilePosition, N>>,
intersection_cache: Res<Cache<RadialArea, Vec<Vec<TilePosition>>>>,
mut q_radial_areas: Query<(Entity, &T, &mut InterestPositions<T>)>,
) {
Expand Down
Loading

0 comments on commit 59572ab

Please sign in to comment.