mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
Remove Bytes, FromBytes, Labels, EntityLabels. Document rest of bevy_core and enable warning on missing docs. (#3521)
This PR is part of the issue #3492. # Objective - Clean up dead code in `bevy_core`. - Add and update the `bevy_core` documentation to achieve a 100% documentation coverage. - Add the #![warn(missing_docs)] lint to keep the documentation coverage for the future. # Solution - Remove unused `Bytes`, `FromBytes`, `Labels`, and `EntityLabels` types and associated systems. - Made several types private that really only have use as internal types, mostly pertaining to fixed timestep execution. - Add and update the bevy_core documentation. - Add the #![warn(missing_docs)] lint. # Open Questions Should more of the internal states of `FixedTimestep` be public? Seems mostly to be an implementation detail unless someone really needs that fixed timestep state.
This commit is contained in:
parent
363bdf78dc
commit
dc8fefe27f
12 changed files with 80 additions and 484 deletions
|
@ -1,103 +0,0 @@
|
|||
pub use bevy_derive::Bytes;
|
||||
|
||||
// NOTE: we can reexport common traits and methods from bytemuck to avoid requiring dependency most of
|
||||
// the time, but unfortunately we can't use derive macros that way due to hardcoded path in generated code.
|
||||
pub use bytemuck::{bytes_of, cast_slice, Pod, Zeroable};
|
||||
|
||||
// FIXME: `Bytes` trait doesn't specify the expected encoding format,
|
||||
// which means types that implement it have to know what format is expected
|
||||
// and can only implement one encoding at a time.
|
||||
// TODO: Remove `Bytes` and `FromBytes` in favour of `crevice` crate.
|
||||
|
||||
/// Converts the implementing type to bytes by writing them to a given buffer
|
||||
pub trait Bytes {
|
||||
/// Converts the implementing type to bytes by writing them to a given buffer
|
||||
fn write_bytes(&self, buffer: &mut [u8]);
|
||||
|
||||
/// The number of bytes that will be written when calling `write_bytes`
|
||||
fn byte_len(&self) -> usize;
|
||||
}
|
||||
|
||||
impl<T> Bytes for T
|
||||
where
|
||||
T: Pod,
|
||||
{
|
||||
fn write_bytes(&self, buffer: &mut [u8]) {
|
||||
buffer[0..self.byte_len()].copy_from_slice(bytes_of(self))
|
||||
}
|
||||
|
||||
fn byte_len(&self) -> usize {
|
||||
std::mem::size_of::<Self>()
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a byte array to `Self`
|
||||
pub trait FromBytes {
|
||||
/// Converts a byte array to `Self`
|
||||
fn from_bytes(bytes: &[u8]) -> Self;
|
||||
}
|
||||
|
||||
impl<T> FromBytes for T
|
||||
where
|
||||
T: Pod,
|
||||
{
|
||||
fn from_bytes(bytes: &[u8]) -> Self {
|
||||
assert_eq!(
|
||||
bytes.len(),
|
||||
std::mem::size_of::<T>(),
|
||||
"Cannot convert byte slice `&[u8]` to type `{}`. They are not the same size.",
|
||||
std::any::type_name::<T>()
|
||||
);
|
||||
unsafe { bytes.as_ptr().cast::<T>().read_unaligned() }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::{Bytes, FromBytes};
|
||||
use bevy_math::{Mat4, Vec2, Vec3, Vec4};
|
||||
|
||||
fn test_round_trip<T: Bytes + FromBytes + std::fmt::Debug + PartialEq>(value: T) {
|
||||
let mut bytes = vec![0; value.byte_len()];
|
||||
value.write_bytes(&mut bytes);
|
||||
let result = T::from_bytes(&bytes);
|
||||
assert_eq!(value, result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_u32_bytes_round_trip() {
|
||||
test_round_trip(123u32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f64_bytes_round_trip() {
|
||||
test_round_trip(123f64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vec2_round_trip() {
|
||||
test_round_trip(Vec2::new(1.0, 2.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vec3_round_trip() {
|
||||
test_round_trip(Vec3::new(1.0, 2.0, 3.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vec4_round_trip() {
|
||||
test_round_trip(Vec4::new(1.0, 2.0, 3.0, 4.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mat4_round_trip() {
|
||||
test_round_trip(Mat4::IDENTITY);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_array_round_trip() {
|
||||
test_round_trip([-10i32; 1024]);
|
||||
test_round_trip([Vec2::ZERO, Vec2::ONE, Vec2::Y, Vec2::X]);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
use crate::bytes_of;
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
hash::{Hash, Hasher},
|
||||
|
@ -42,12 +41,12 @@ impl Hash for FloatOrd {
|
|||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
if self.0.is_nan() {
|
||||
// Ensure all NaN representations hash to the same value
|
||||
state.write(bytes_of(&f32::NAN))
|
||||
state.write(bytemuck::bytes_of(&f32::NAN))
|
||||
} else if self.0 == 0.0 {
|
||||
// Ensure both zeroes hash to the same value
|
||||
state.write(bytes_of(&0.0f32))
|
||||
state.write(bytemuck::bytes_of(&0.0f32))
|
||||
} else {
|
||||
state.write(bytes_of(&self.0));
|
||||
state.write(bytemuck::bytes_of(&self.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,256 +0,0 @@
|
|||
use bevy_ecs::{
|
||||
component::Component,
|
||||
entity::Entity,
|
||||
query::Changed,
|
||||
reflect::ReflectComponent,
|
||||
system::{Query, RemovedComponents, ResMut},
|
||||
};
|
||||
use bevy_reflect::Reflect;
|
||||
use bevy_utils::{HashMap, HashSet};
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
fmt::Debug,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
|
||||
/// A collection of labels
|
||||
#[derive(Component, Default, Reflect)]
|
||||
#[reflect(Component)]
|
||||
pub struct Labels {
|
||||
labels: HashSet<Cow<'static, str>>,
|
||||
}
|
||||
|
||||
impl Debug for Labels {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let mut list = f.debug_list();
|
||||
for label in self.iter() {
|
||||
list.entry(&label);
|
||||
}
|
||||
|
||||
list.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, L: Into<Cow<'static, str>>> From<T> for Labels
|
||||
where
|
||||
T: IntoIterator<Item = L>,
|
||||
{
|
||||
fn from(value: T) -> Self {
|
||||
let mut labels = HashSet::default();
|
||||
for label in value {
|
||||
labels.insert(label.into());
|
||||
}
|
||||
Self { labels }
|
||||
}
|
||||
}
|
||||
|
||||
impl Labels {
|
||||
pub fn contains<T: Into<Cow<'static, str>>>(&self, label: T) -> bool {
|
||||
self.labels.contains(&label.into())
|
||||
}
|
||||
|
||||
pub fn insert<T: Into<Cow<'static, str>>>(&mut self, label: T) {
|
||||
self.labels.insert(label.into());
|
||||
}
|
||||
|
||||
pub fn remove<T: Into<Cow<'static, str>>>(&mut self, label: T) {
|
||||
self.labels.remove(&label.into());
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = &str> {
|
||||
self.labels.iter().map(|label| label.deref())
|
||||
}
|
||||
}
|
||||
|
||||
/// Maintains a mapping from [Entity](bevy_ecs::prelude::Entity) ids to entity labels and entity
|
||||
/// labels to [Entities](bevy_ecs::prelude::Entity).
|
||||
#[derive(Debug, Default)]
|
||||
pub struct EntityLabels {
|
||||
label_entities: HashMap<Cow<'static, str>, Vec<Entity>>,
|
||||
entity_labels: HashMap<Entity, HashSet<Cow<'static, str>>>,
|
||||
}
|
||||
|
||||
impl EntityLabels {
|
||||
pub fn get(&self, label: &str) -> &[Entity] {
|
||||
self.label_entities
|
||||
.get(label)
|
||||
.map(|entities| entities.as_slice())
|
||||
.unwrap_or(&[])
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn entity_labels_system(
|
||||
mut entity_labels: ResMut<EntityLabels>,
|
||||
removed_labels: RemovedComponents<Labels>,
|
||||
query: Query<(Entity, &Labels), Changed<Labels>>,
|
||||
) {
|
||||
let entity_labels = entity_labels.deref_mut();
|
||||
|
||||
for entity in removed_labels.iter() {
|
||||
if let Some(labels) = entity_labels.entity_labels.get(&entity) {
|
||||
for label in labels.iter() {
|
||||
if let Some(entities) = entity_labels.label_entities.get_mut(label) {
|
||||
entities.retain(|e| *e != entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (entity, labels) in query.iter() {
|
||||
let current_labels = entity_labels
|
||||
.entity_labels
|
||||
.entry(entity)
|
||||
.or_insert_with(HashSet::default);
|
||||
|
||||
for removed_label in current_labels.difference(&labels.labels) {
|
||||
if let Some(entities) = entity_labels.label_entities.get_mut(removed_label) {
|
||||
entities.retain(|e| *e != entity);
|
||||
}
|
||||
}
|
||||
|
||||
for added_label in labels.labels.difference(current_labels) {
|
||||
entity_labels
|
||||
.label_entities
|
||||
.entry(added_label.clone())
|
||||
.or_insert_with(Vec::new)
|
||||
.push(entity);
|
||||
}
|
||||
|
||||
*current_labels = labels.labels.clone();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use bevy_ecs::{
|
||||
schedule::{Schedule, Stage, SystemStage},
|
||||
world::World,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
fn setup() -> (World, Schedule) {
|
||||
let mut world = World::new();
|
||||
world.insert_resource(EntityLabels::default());
|
||||
let mut schedule = Schedule::default();
|
||||
schedule.add_stage("test", SystemStage::single_threaded());
|
||||
schedule.add_system_to_stage("test", entity_labels_system);
|
||||
(world, schedule)
|
||||
}
|
||||
|
||||
fn holy_cow() -> Labels {
|
||||
Labels::from(["holy", "cow"].iter().cloned())
|
||||
}
|
||||
|
||||
fn holy_shamoni() -> Labels {
|
||||
Labels::from(["holy", "shamoni"].iter().cloned())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn adds_spawned_entity() {
|
||||
let (mut world, mut schedule) = setup();
|
||||
|
||||
let e1 = world.spawn().insert(holy_cow()).id();
|
||||
schedule.run(&mut world);
|
||||
|
||||
let entity_labels = world.get_resource::<EntityLabels>().unwrap();
|
||||
assert_eq!(entity_labels.get("holy"), &[e1], "holy");
|
||||
assert_eq!(entity_labels.get("cow"), &[e1], "cow");
|
||||
assert_eq!(entity_labels.get("shalau"), &[], "shalau");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_labels() {
|
||||
let (mut world, mut schedule) = setup();
|
||||
let e1 = world.spawn().insert(holy_cow()).id();
|
||||
schedule.run(&mut world);
|
||||
|
||||
world.get_mut::<Labels>(e1).unwrap().insert("shalau");
|
||||
schedule.run(&mut world);
|
||||
|
||||
let entity_labels = world.get_resource::<EntityLabels>().unwrap();
|
||||
assert_eq!(entity_labels.get("holy"), &[e1], "holy");
|
||||
assert_eq!(entity_labels.get("cow"), &[e1], "cow");
|
||||
assert_eq!(entity_labels.get("shalau"), &[e1], "shalau");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remove_labels() {
|
||||
let (mut world, mut schedule) = setup();
|
||||
let e1 = world.spawn().insert(holy_cow()).id();
|
||||
schedule.run(&mut world);
|
||||
|
||||
world.get_mut::<Labels>(e1).unwrap().remove("holy");
|
||||
schedule.run(&mut world);
|
||||
|
||||
let entity_labels = world.get_resource::<EntityLabels>().unwrap();
|
||||
assert_eq!(entity_labels.get("holy"), &[], "holy");
|
||||
assert_eq!(entity_labels.get("cow"), &[e1], "cow");
|
||||
assert_eq!(entity_labels.get("shalau"), &[], "shalau");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn removes_despawned_entity() {
|
||||
let (mut world, mut schedule) = setup();
|
||||
let e1 = world.spawn().insert(holy_cow()).id();
|
||||
schedule.run(&mut world);
|
||||
|
||||
assert!(world.despawn(e1));
|
||||
schedule.run(&mut world);
|
||||
|
||||
let entity_labels = world.get_resource::<EntityLabels>().unwrap();
|
||||
assert_eq!(entity_labels.get("holy"), &[], "holy");
|
||||
assert_eq!(entity_labels.get("cow"), &[], "cow");
|
||||
assert_eq!(entity_labels.get("shalau"), &[], "shalau");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn removes_labels_when_component_removed() {
|
||||
let (mut world, mut schedule) = setup();
|
||||
let e1 = world.spawn().insert(holy_cow()).id();
|
||||
schedule.run(&mut world);
|
||||
|
||||
world.entity_mut(e1).remove::<Labels>().unwrap();
|
||||
schedule.run(&mut world);
|
||||
|
||||
let entity_labels = world.get_resource::<EntityLabels>().unwrap();
|
||||
assert_eq!(entity_labels.get("holy"), &[], "holy");
|
||||
assert_eq!(entity_labels.get("cow"), &[], "cow");
|
||||
assert_eq!(entity_labels.get("shalau"), &[], "shalau");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn adds_another_spawned_entity() {
|
||||
let (mut world, mut schedule) = setup();
|
||||
let e1 = world.spawn().insert(holy_cow()).id();
|
||||
schedule.run(&mut world);
|
||||
|
||||
let e2 = world.spawn().insert(holy_shamoni()).id();
|
||||
schedule.run(&mut world);
|
||||
|
||||
let entity_labels = world.get_resource::<EntityLabels>().unwrap();
|
||||
assert_eq!(entity_labels.get("holy"), &[e1, e2], "holy");
|
||||
assert_eq!(entity_labels.get("cow"), &[e1], "cow");
|
||||
assert_eq!(entity_labels.get("shamoni"), &[e2], "shamoni");
|
||||
assert_eq!(entity_labels.get("shalau"), &[], "shalau");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn removes_despawned_entity_but_leaves_other() {
|
||||
let (mut world, mut schedule) = setup();
|
||||
let e1 = world.spawn().insert(holy_cow()).id();
|
||||
schedule.run(&mut world);
|
||||
|
||||
let e2 = world.spawn().insert(holy_shamoni()).id();
|
||||
schedule.run(&mut world);
|
||||
|
||||
assert!(world.despawn(e1));
|
||||
schedule.run(&mut world);
|
||||
|
||||
let entity_labels = world.get_resource::<EntityLabels>().unwrap();
|
||||
assert_eq!(entity_labels.get("holy"), &[e2], "holy");
|
||||
assert_eq!(entity_labels.get("cow"), &[], "cow");
|
||||
assert_eq!(entity_labels.get("shamoni"), &[e2], "shamoni");
|
||||
assert_eq!(entity_labels.get("shalau"), &[], "shalau");
|
||||
}
|
||||
}
|
|
@ -1,20 +1,21 @@
|
|||
mod bytes;
|
||||
#![warn(missing_docs)]
|
||||
//! This crate provides core functionality for Bevy Engine.
|
||||
|
||||
mod float_ord;
|
||||
mod label;
|
||||
mod name;
|
||||
mod task_pool_options;
|
||||
mod time;
|
||||
|
||||
pub use bytes::*;
|
||||
pub use bytemuck::{bytes_of, cast_slice, Pod, Zeroable};
|
||||
pub use float_ord::*;
|
||||
pub use label::*;
|
||||
pub use name::*;
|
||||
pub use task_pool_options::DefaultTaskPoolOptions;
|
||||
pub use time::*;
|
||||
|
||||
pub mod prelude {
|
||||
//! The Bevy Core Prelude.
|
||||
#[doc(hidden)]
|
||||
pub use crate::{DefaultTaskPoolOptions, EntityLabels, Labels, Name, Time, Timer};
|
||||
pub use crate::{DefaultTaskPoolOptions, Name, Time, Timer};
|
||||
}
|
||||
|
||||
use bevy_app::prelude::*;
|
||||
|
@ -30,6 +31,7 @@ use std::ops::Range;
|
|||
#[derive(Default)]
|
||||
pub struct CorePlugin;
|
||||
|
||||
/// A `SystemLabel` enum for ordering systems relative to core Bevy systems.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Hash, SystemLabel)]
|
||||
pub enum CoreSystem {
|
||||
/// Updates the elapsed time. Any system that interacts with [Time] component should run after
|
||||
|
@ -47,13 +49,11 @@ impl Plugin for CorePlugin {
|
|||
.create_default_pools(&mut app.world);
|
||||
|
||||
app.init_resource::<Time>()
|
||||
.init_resource::<EntityLabels>()
|
||||
.init_resource::<FixedTimesteps>()
|
||||
.register_type::<HashSet<String>>()
|
||||
.register_type::<Option<String>>()
|
||||
.register_type::<Entity>()
|
||||
.register_type::<Name>()
|
||||
.register_type::<Labels>()
|
||||
.register_type::<Range<f32>>()
|
||||
.register_type::<Timer>()
|
||||
// time system is added as an "exclusive system" to ensure it runs before other systems
|
||||
|
@ -61,9 +61,7 @@ impl Plugin for CorePlugin {
|
|||
.add_system_to_stage(
|
||||
CoreStage::First,
|
||||
time_system.exclusive_system().label(CoreSystem::Time),
|
||||
)
|
||||
.add_startup_system_to_stage(StartupStage::PostStartup, entity_labels_system)
|
||||
.add_system_to_stage(CoreStage::PostUpdate, entity_labels_system);
|
||||
);
|
||||
|
||||
register_rust_types(app);
|
||||
register_math_types(app);
|
||||
|
|
|
@ -8,6 +8,11 @@ use std::{
|
|||
};
|
||||
|
||||
/// Component used to identify an entity. Stores a hash for faster comparisons
|
||||
/// The hash is eagerly re-computed upon each update to the name.
|
||||
///
|
||||
/// [`Name`] should not be treated as a globally unique identifier for entities,
|
||||
/// as multiple entities can have the same name. [`bevy_ecs::entity::Entity`] should be
|
||||
/// used instead as the default unique identifier.
|
||||
#[derive(Component, Debug, Clone, Reflect)]
|
||||
#[reflect(Component)]
|
||||
pub struct Name {
|
||||
|
@ -22,6 +27,9 @@ impl Default for Name {
|
|||
}
|
||||
|
||||
impl Name {
|
||||
/// Creates a new [`Name`] from any string-like type.
|
||||
///
|
||||
/// The internal hash will be computed immediately.
|
||||
pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
|
||||
let name = name.into();
|
||||
let mut name = Name { name, hash: 0 };
|
||||
|
@ -29,17 +37,25 @@ impl Name {
|
|||
name
|
||||
}
|
||||
|
||||
/// Sets the entity's name.
|
||||
///
|
||||
/// The internal hash will be re-computed.
|
||||
#[inline(always)]
|
||||
pub fn set(&mut self, name: impl Into<Cow<'static, str>>) {
|
||||
*self = Name::new(name);
|
||||
}
|
||||
|
||||
/// Updates the name of the entity in place.
|
||||
///
|
||||
/// This will allocate a new string if the name was previously
|
||||
/// created from a borrow.
|
||||
#[inline(always)]
|
||||
pub fn mutate<F: FnOnce(&mut String)>(&mut self, f: F) {
|
||||
f(self.name.to_mut());
|
||||
self.update_hash();
|
||||
}
|
||||
|
||||
/// Gets the name of the entity as a `&str`.
|
||||
#[inline(always)]
|
||||
pub fn as_str(&self) -> &str {
|
||||
&self.name
|
||||
|
|
|
@ -10,45 +10,66 @@ use bevy_ecs::{
|
|||
use bevy_utils::HashMap;
|
||||
use std::borrow::Cow;
|
||||
|
||||
/// The internal state of each [`FixedTimestep`].
|
||||
#[derive(Debug)]
|
||||
pub struct FixedTimestepState {
|
||||
pub step: f64,
|
||||
pub accumulator: f64,
|
||||
step: f64,
|
||||
accumulator: f64,
|
||||
}
|
||||
|
||||
impl FixedTimestepState {
|
||||
/// The amount of time each step takes
|
||||
/// The amount of time each step takes.
|
||||
pub fn step(&self) -> f64 {
|
||||
self.step
|
||||
}
|
||||
|
||||
/// The number of steps made in a second
|
||||
/// The number of steps made in a second.
|
||||
pub fn steps_per_second(&self) -> f64 {
|
||||
1.0 / self.step
|
||||
}
|
||||
|
||||
/// The amount of time (in seconds) left over from the last step
|
||||
/// The amount of time (in seconds) left over from the last step.
|
||||
pub fn accumulator(&self) -> f64 {
|
||||
self.accumulator
|
||||
}
|
||||
|
||||
/// The percentage of "step" stored inside the accumulator. Calculated as accumulator / step
|
||||
/// The percentage of "step" stored inside the accumulator. Calculated as accumulator / step.
|
||||
pub fn overstep_percentage(&self) -> f64 {
|
||||
self.accumulator / self.step
|
||||
}
|
||||
}
|
||||
|
||||
/// A global resource that tracks the individual [`FixedTimestepState`]s
|
||||
/// for every labeled [`FixedTimestep`].
|
||||
#[derive(Default)]
|
||||
pub struct FixedTimesteps {
|
||||
fixed_timesteps: HashMap<String, FixedTimestepState>,
|
||||
}
|
||||
|
||||
impl FixedTimesteps {
|
||||
/// Gets the [`FixedTimestepState`] for a given label.
|
||||
pub fn get(&self, name: &str) -> Option<&FixedTimestepState> {
|
||||
self.fixed_timesteps.get(name)
|
||||
}
|
||||
}
|
||||
|
||||
/// A system run criteria that enables systems or stages to run at a fixed timestep between executions.
|
||||
///
|
||||
/// This does not guarentee that the time elapsed between executions is exactly the provided
|
||||
/// fixed timestep, but will guarentee that the execution will run multiple times per game tick
|
||||
/// until the number of repetitions is as expected.
|
||||
///
|
||||
/// For example, a system with a fixed timestep run criteria of 120 times per second will run
|
||||
/// two times during a ~16.667ms frame, once during a ~8.333ms frame, and once every two frames
|
||||
/// with ~4.167ms frames. However, the same criteria may not result in exactly 8.333ms passing
|
||||
/// between each execution.
|
||||
///
|
||||
/// When using this run criteria, it is advised not to rely on [`Time::delta`] or any of it's
|
||||
/// variants for game simulation, but rather use the constant time delta used to initialize the
|
||||
/// [`FixedTimestep`] instead.
|
||||
///
|
||||
/// For more fine tuned information about the execution status of a given fixed timestep,
|
||||
/// use the [`FixedTimesteps`] resource.
|
||||
pub struct FixedTimestep {
|
||||
state: LocalFixedTimestepState,
|
||||
internal_system: Box<dyn System<In = (), Out = ShouldRun>>,
|
||||
|
@ -64,6 +85,7 @@ impl Default for FixedTimestep {
|
|||
}
|
||||
|
||||
impl FixedTimestep {
|
||||
/// Creates a [`FixedTimestep`] that ticks once every `step` seconds.
|
||||
pub fn step(step: f64) -> Self {
|
||||
Self {
|
||||
state: LocalFixedTimestepState {
|
||||
|
@ -74,6 +96,7 @@ impl FixedTimestep {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a [`FixedTimestep`] that ticks once every `rate` times per second.
|
||||
pub fn steps_per_second(rate: f64) -> Self {
|
||||
Self {
|
||||
state: LocalFixedTimestepState {
|
||||
|
@ -84,6 +107,8 @@ impl FixedTimestep {
|
|||
}
|
||||
}
|
||||
|
||||
/// Sets the label for the timestep. Setting a label allows a timestep
|
||||
/// to be observed by the global [`FixedTimesteps`] resource.
|
||||
pub fn with_label(mut self, label: &str) -> Self {
|
||||
self.state.label = Some(label.to_string());
|
||||
self
|
||||
|
@ -106,7 +131,7 @@ impl FixedTimestep {
|
|||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct LocalFixedTimestepState {
|
||||
struct LocalFixedTimestepState {
|
||||
label: Option<String>, // TODO: consider making this a TypedLabel
|
||||
step: f64,
|
||||
accumulator: f64,
|
||||
|
|
|
@ -55,11 +55,30 @@ impl Stopwatch {
|
|||
/// stopwatch.tick(Duration::from_secs(1));
|
||||
/// assert_eq!(stopwatch.elapsed(), Duration::from_secs(1));
|
||||
/// ```
|
||||
///
|
||||
/// # See Also
|
||||
///
|
||||
/// [`elapsed_secs`](Stopwatch::elapsed) - if a `f32` value is desirable instead.
|
||||
#[inline]
|
||||
pub fn elapsed(&self) -> Duration {
|
||||
self.elapsed
|
||||
}
|
||||
|
||||
/// Returns the elapsed time since the last [`reset`](Stopwatch::reset)
|
||||
/// of the stopwatch, in seconds.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # use bevy_core::*;
|
||||
/// use std::time::Duration;
|
||||
/// let mut stopwatch = Stopwatch::new();
|
||||
/// stopwatch.tick(Duration::from_secs(1));
|
||||
/// assert_eq!(stopwatch.elapsed_secs(), 1.0);
|
||||
/// ```
|
||||
///
|
||||
/// # See Also
|
||||
///
|
||||
/// [`elapsed`](Stopwatch::elapsed) - if a `Duration` is desirable instead.
|
||||
#[inline]
|
||||
pub fn elapsed_secs(&self) -> f32 {
|
||||
self.elapsed().as_secs_f32()
|
||||
|
|
|
@ -28,9 +28,9 @@ impl Default for Time {
|
|||
}
|
||||
|
||||
impl Time {
|
||||
/// Updates the internal time measurements.
|
||||
pub fn update(&mut self) {
|
||||
let now = Instant::now();
|
||||
self.update_with_instant(now);
|
||||
self.update_with_instant(Instant::now());
|
||||
}
|
||||
|
||||
pub(crate) fn update_with_instant(&mut self, instant: Instant) {
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
use bevy_macro_utils::BevyManifest;
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Fields};
|
||||
|
||||
pub fn derive_bytes(input: TokenStream) -> TokenStream {
|
||||
let ast = parse_macro_input!(input as DeriveInput);
|
||||
let fields = match &ast.data {
|
||||
Data::Struct(DataStruct {
|
||||
fields: Fields::Named(fields),
|
||||
..
|
||||
}) => &fields.named,
|
||||
_ => panic!("Expected a struct with named fields."),
|
||||
};
|
||||
|
||||
let bevy_core_path = BevyManifest::default().get_path(crate::modules::BEVY_CORE);
|
||||
|
||||
let fields = fields
|
||||
.iter()
|
||||
.map(|field| field.ident.as_ref().unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let struct_name = &ast.ident;
|
||||
let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
|
||||
|
||||
TokenStream::from(quote! {
|
||||
impl #impl_generics #bevy_core_path::Bytes for #struct_name #ty_generics #where_clause {
|
||||
fn write_bytes(&self, buffer: &mut [u8]) {
|
||||
let mut offset: usize = 0;
|
||||
#(let byte_len = self.#fields.byte_len();
|
||||
self.#fields.write_bytes(&mut buffer[offset..(offset + byte_len)]);
|
||||
offset += byte_len;)*
|
||||
}
|
||||
fn byte_len(&self) -> usize {
|
||||
let mut byte_len: usize = 0;
|
||||
#(byte_len += self.#fields.byte_len();)*
|
||||
byte_len
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
|
@ -2,7 +2,6 @@ extern crate proc_macro;
|
|||
|
||||
mod app_plugin;
|
||||
mod bevy_main;
|
||||
mod bytes;
|
||||
mod enum_variant_meta;
|
||||
mod modules;
|
||||
|
||||
|
@ -10,12 +9,6 @@ use bevy_macro_utils::{derive_label, BevyManifest};
|
|||
use proc_macro::TokenStream;
|
||||
use quote::format_ident;
|
||||
|
||||
/// Derives the Bytes trait. Each field must also implements Bytes or this will fail.
|
||||
#[proc_macro_derive(Bytes)]
|
||||
pub fn derive_bytes(input: TokenStream) -> TokenStream {
|
||||
bytes::derive_bytes(input)
|
||||
}
|
||||
|
||||
/// Generates a dynamic plugin entry point function for the given `Plugin` type.
|
||||
#[proc_macro_derive(DynamicPlugin)]
|
||||
pub fn derive_dynamic_plugin(input: TokenStream) -> TokenStream {
|
||||
|
|
|
@ -1,2 +1 @@
|
|||
pub const BEVY_CORE: &str = "bevy_core";
|
||||
pub const BEVY_UTILS: &str = "bevy_utils";
|
||||
|
|
|
@ -3,7 +3,6 @@ mod colorspace;
|
|||
pub use colorspace::*;
|
||||
|
||||
use crate::color::{HslRepresentation, SrgbColorSpace};
|
||||
use bevy_core::Bytes;
|
||||
use bevy_math::{Vec3, Vec4};
|
||||
use bevy_reflect::{FromReflect, Reflect, ReflectDeserialize};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -1035,58 +1034,6 @@ impl MulAssign<[f32; 3]> for Color {
|
|||
}
|
||||
}
|
||||
|
||||
impl Bytes for Color {
|
||||
fn write_bytes(&self, buffer: &mut [u8]) {
|
||||
match *self {
|
||||
Color::Rgba {
|
||||
red,
|
||||
green,
|
||||
blue,
|
||||
alpha,
|
||||
} => {
|
||||
red.nonlinear_to_linear_srgb().write_bytes(buffer);
|
||||
green
|
||||
.nonlinear_to_linear_srgb()
|
||||
.write_bytes(&mut buffer[std::mem::size_of::<f32>()..]);
|
||||
blue.nonlinear_to_linear_srgb()
|
||||
.write_bytes(&mut buffer[2 * std::mem::size_of::<f32>()..]);
|
||||
alpha.write_bytes(&mut buffer[3 * std::mem::size_of::<f32>()..]);
|
||||
}
|
||||
Color::RgbaLinear {
|
||||
red,
|
||||
green,
|
||||
blue,
|
||||
alpha,
|
||||
} => {
|
||||
red.write_bytes(buffer);
|
||||
green.write_bytes(&mut buffer[std::mem::size_of::<f32>()..]);
|
||||
blue.write_bytes(&mut buffer[2 * std::mem::size_of::<f32>()..]);
|
||||
alpha.write_bytes(&mut buffer[3 * std::mem::size_of::<f32>()..]);
|
||||
}
|
||||
Color::Hsla {
|
||||
hue,
|
||||
saturation,
|
||||
lightness,
|
||||
alpha,
|
||||
} => {
|
||||
let [red, green, blue] =
|
||||
HslRepresentation::hsl_to_nonlinear_srgb(hue, saturation, lightness);
|
||||
red.nonlinear_to_linear_srgb().write_bytes(buffer);
|
||||
green
|
||||
.nonlinear_to_linear_srgb()
|
||||
.write_bytes(&mut buffer[std::mem::size_of::<f32>()..]);
|
||||
blue.nonlinear_to_linear_srgb()
|
||||
.write_bytes(&mut buffer[std::mem::size_of::<f32>() * 2..]);
|
||||
alpha.write_bytes(&mut buffer[std::mem::size_of::<f32>() * 3..]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn byte_len(&self) -> usize {
|
||||
std::mem::size_of::<f32>() * 4
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum HexColorError {
|
||||
Length,
|
||||
|
|
Loading…
Reference in a new issue