Skip to content

Commit

Permalink
docs: update README and TODO comments. (#174)
Browse files Browse the repository at this point in the history
  • Loading branch information
zicklag committed Aug 22, 2023
1 parent a0cea1d commit db6560f
Show file tree
Hide file tree
Showing 18 changed files with 116 additions and 43 deletions.
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

51 changes: 35 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,22 @@

[![Documentation](https://img.shields.io/badge/documentation-fishfolk.org-green.svg?labelColor=1e1c24&color=f3ee7a)](https://fishfolk.org/bones/overview/introduction/)
[![Crates.io](https://img.shields.io/crates/v/bones_lib?labelColor=1e1c24)](https://crates.io/crates/bones_lib)
[![docs.rs](https://img.shields.io/docsrs/bones_lib?label=API%20Docs&labelColor=1e1c24)](https://docs.rs/bones_lib)
[![docs.rs](https://img.shields.io/docsrs/bones_framework?label=API%20Docs&labelColor=1e1c24)](https://docs.rs/bones_framework)
[![Main Branch Docs](https://img.shields.io/badge/API_Docs-Main_Branch-blue?labelColor=1e1c24&color=red)](https://fishfolk.github.io/bones/rustdoc/bones_framework/index.html)
[![License](https://img.shields.io/badge/License-MIT%20or%20Apache%202-green.svg?label=license&labelColor=1e1c24&color=34925e)](./LICENSE)
[![Discord](https://img.shields.io/badge/chat-on%20discord-green.svg?logo=discord&logoColor=fff&labelColor=1e1c24&color=8d5b3f)](https://discord.gg/4smxjcheE5)
[![Discord](https://img.shields.io/badge/chat-on%20discord-green.svg?logo=discord&logoColor=fff&labelColor=1e1c24&color=8d5b3f)][Discord]

A work-in-progress, opinionated game meta-engine built on [Bevy].
A work-in-progress, simple, and easy-to-use game engine that can be rendered with [Bevy].

Under development for future use in the [Jumpy] game, and possibly other FishFolk games.
Used in the [Jumpy] game, and will possibly be used in other FishFolk games in the future.

Check out [Fishfolk.org] for more documentation and tutorials.

[fishfolk.org]: https://fishfolk.org
[bevy]: https://bevyengine.org
[jumpy]: https://github.com/fishfolk/jumpy
[discord]: https://discord.gg/4smxjcheE5
[revolt]: https://weird.dev/invite/ZagXxrS4

## Overview

Expand All @@ -24,31 +27,47 @@ Bones is designed around a simple, custom Entity Component System ( ECS ), desig

- **Determinism:** Bones ECS is deterministic by default, making it easier to get a re-producible and predictable gameplay.
- **Snapshot/Restore:** The Bones ECS world can be trivially snapshot and restored.
- **Modding/Scripting ( future ):** Bones ECS is simple enough that we can feasibly provide a C API for integration with other languages and scripting.
- **Modding/Scripting ( work-in-progress ):** Bones ECS is built on our [`bones_schema`] system, which allows for runtime reflection and the ability to interact with data types defined outside of Rust.

[`bones_schema`]: https://fishfolk.github.io/bones/rustdoc/bones_schema/index.html

Determinism and Snapshot/Restore are also key features for getting excellent **network play** with the rollback networking model, while requiring no changes to the core game loop implementation.

### Game Core
### Bones Lib

The [`bones_lib`] contains the [`bones_ecs`] and the [`bones_asset`] system. It defines the concept of a [`Game`] which contains all of your game logic and data in a collection of [`Session`]s that each have their own ECS [`World`].

Bones lib has no rendering components or even math types, it is only concerned with organizing your game logic and assets.

[`bones_lib`]: https://fishfolk.github.io/bones/rustdoc/bones_lib/index.html
[`bones_ecs`]: https://fishfolk.github.io/bones/rustdoc/bones_ecs/index.html
[`bones_asset`]: https://fishfolk.github.io/bones/rustdoc/bones_asset/index.html
[`Game`]: https://fishfolk.github.io/bones/rustdoc/bones_lib/struct.Game.html
[`Session`]: https://fishfolk.github.io/bones/rustdoc/bones_lib/struct.Session.html
[`World`]: https://fishfolk.github.io/bones/rustdoc/bones_lib/ecs/struct.World.html

### Bones Framework

Using `bones_lib`, which includes `bones_ecs` and other useful utilities, you write your "game core".
On top of [`bones_lib`] there is the [`bones_framework`], which defines the rendering components and math types. Right now [`bones_framework`] is focused only on 2D rendering. 3D is not a priority for us now, but there is no technical limitation preventing community developed 3D rendering components either on top of [`bones_lib`] directly or as an extension to the [`bones_framework`].

This game core is mostly isolated from anything outside of the ECS world. This is important so that the entire game core can be snapshot/restored.
[`bones_framework`]: https://fishfolk.github.io/bones/rustdoc/bones_framework/index.html

This means that to collect input, you must read those inputs from an ECS resource, and to render sprites, map tiles, etc., you must create entities with specific components that tell Bones how to render them.
### Bones Bevy Renderer

### Bevy Renderer
A game created with the [`bones_framework`] is renderer agnostic. This allows us to create rendering integrations with other engines. Our official integration is with the [Bevy] engine. The [`bones_bevy_renderer`] allows you to create a Bevy `App` for rendering a [`bones_framework`] game.

Once you have your game core, you can render the core in a Bevy game using the `bones_bevy_renderer` crate.
This also allows you to create custom extensions to the Bevy renderer, if you need a bones integration with a feature not supported out-of-the-box in the [`bones_framework`].

This lets you utilize the power and plugin ecosystem of Bevy to interact with rendering, input, etc. while keeping your core game deterministic, snapshot-able, and moddable.
[`bones_bevy_renderer`]: https://fishfolk.github.io/bones/rustdoc/bones_bevy_renderer/index.html

You are also free to create your own rendering components that you synchronize with Bevy to support any custom rendering/audio use-cases, etc.
## Contributing

> **Note:** Bones ECS as well as `bones_lib` can technically be used without Bevy. Right now we are focusing on Bevy, and support for alternative uses may not be well polished/complete yet, but it's still within the realm of possibility to render Bones cores with any framework you want.
If you would like to contribute, feel free to reach out on our [Discord] or [Revolt] server to ask questions!

### Bones App ( Future )
We also use [TODO Issue][tdi] to automatically create issues from all of our `TODO` comments in code. You can check out the [todo issue list][tdil] to see if there's any thing you'd like to take a hack at.

As we get a feel for how things fit together with the use of Bones in [Jumpy], we hope to be able to create a standardized game runner around Bones game cores. This would allow the Bones app to handle common things like localization, asset loading, input mapping, settings menu, networking, etc., allowing you to focus on writing what makes your game unique.
[tdi]: https://github.com/DerJuulsn/todo-issue
[tdil]: https://github.com/fishfolk/bones/issues?q=is%3Aissue+is%3Aopen+label%3Acode%3Atodo

## Similar Projects

Expand Down
8 changes: 4 additions & 4 deletions framework_crates/bones_asset/src/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ impl FileAssetIo {
}
_ => (),
},
// TODO: Log `bones_asset` errors with tracing.
//
// Also see the unwrap_or_else line below, which needs an error log.
// TODO: Log asset errors with tracing.
// We should use the [`tracing`](https://docs.rs/tracing/latest/tracing/) crate
// to log an error message here instead of using `eprintln!()`.
Err(e) => eprintln!("watch error: {e:?}"),
}
})
Expand All @@ -96,7 +96,7 @@ impl FileAssetIo {
})
.map_err(|e| {
eprintln!("watch error: {e:?}");
// See todo above: log error message.
// TODO: Log asset errors with tracing.
})
.ok();
}
Expand Down
17 changes: 12 additions & 5 deletions framework_crates/bones_asset/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,11 @@ impl AssetServer {
id: meta.id,
version: meta.version,
game_version: meta.game_version,
// TODO: load & import schemas that are defined in asset packs.
// TODO: Load & import schemas that are defined in asset packs.
// This is medium-sized effort. The idea is that asset packs shoudl be able to
// create YAML files that describe a `SchemaData`. This schema data should get
// registered with a file extension name, just like a Rust metadata asset does
// so that that schema can be used to load assets.
schemas: default(),
import_schemas: default(),
root: root_handle,
Expand All @@ -230,7 +234,7 @@ impl AssetServer {
match self.load_asset_forced(loc.as_ref()) {
Ok(handle) => handle_change(self, handle),
Err(_) => {
// TODO: Handle/log asset error.
// TODO: Log asset errors with tracing.
continue;
}
};
Expand Down Expand Up @@ -742,7 +746,10 @@ mod metadata {
type Value = ();

fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
// TODO: write a really nice error message for this.
// TODO: Write very verbose error messages for metadata asset deserializers.
// The schema describes the type that we are trying to deserialize, so we should
// use that information to format a nice-to-read error message that documents
// what data it's expecting.
write!(
formatter,
"asset metadata matching the schema: {:#?}",
Expand Down Expand Up @@ -820,7 +827,7 @@ mod metadata {
type Value = ();

fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
// TODO: write a really nice error message for this.
// TODO: Write very verbose error messages for metadata asset deserializers.
write!(
formatter,
"asset metadata matching the schema: {:#?}",
Expand Down Expand Up @@ -863,7 +870,7 @@ mod metadata {
type Value = ();

fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
// TODO: write a really nice error message for this.
// TODO: Write very verbose error messages for metadata asset deserializers.
write!(
formatter,
"asset metadata matching the schema: {:#?}",
Expand Down
2 changes: 2 additions & 0 deletions framework_crates/bones_bevy_renderer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ pub struct BonesData {

impl BonesBevyRenderer {
// TODO: Create a better builder pattern struct for `BonesBevyRenderer`.
// We want to use a nice builder-pattern struct for `BonesBevyRenderer` so that it is easier
// to set options like the `pixel_art` flag or the `game_version`.
/// Create a new [`BonesBevyRenderer`] for the provided game.
pub fn new(game: bones::Game) -> Self {
BonesBevyRenderer {
Expand Down
1 change: 0 additions & 1 deletion framework_crates/bones_ecs/src/components/typed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ impl<T: HasSchema> ComponentStore<T> {
}

// TODO: Replace ComponentStore functions with non-validating ones.
//
// Right now functions like `insert`, `get`, and `get_mut` use the checked and panicing versions
// of the `untyped` functions. These functions do an extra check to see that the schema matches,
// but we've already validated that in the construction of the `ComponentStore`, so we should
Expand Down
9 changes: 8 additions & 1 deletion framework_crates/bones_ecs/src/components/untyped.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,14 @@ impl UntypedComponentStore {
fn allocate_enough(&mut self, until: usize) {
if self.storage.capacity() <= until {
self.storage
// TODO: Determine a better policy for resizing component storage.
// TODO: Determine a better policy for resizing and pre-allocating component storage.
// Right now we double the size of the storage every time we run out. It seems like we
// might be able to come up with a smarter policy. On top of that we should
// be able to create a type data for components ( see
// `bones_framework::metadata_asset()` for example ) that lets you customize the resize
// and also pre-allocation strategy for the component. Right now we don't pre-allocate
// any memory, but that could be useful for components that know there will be a lot of
// them, such as bullets.
.resize((until + 1) * 2)
.unwrap();
}
Expand Down
4 changes: 3 additions & 1 deletion framework_crates/bones_ecs/src/entities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ pub trait QueryItem {
}

// TODO: Implement optional component query iterators.

// We don't have the ability to do `entities.iter_with(Option<&my_comp>)`, but we should
// be able to implement a `QueryItem` for that so that you can iterate over entities that
// _might_ have a component.
impl<'a, 'q, T: HasSchema> QueryItem for &'a Comp<'q, T> {
type Iter = ComponentBitsetIterator<'a, T>;
fn apply_bitset(&self, bitset: &mut BitSetVec) {
Expand Down
6 changes: 5 additions & 1 deletion framework_crates/bones_ecs/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ use std::error::Error;

/// The types of errors used throughout the ECS.
// TODO: Re-evaluate `EcsError` variants.
// Some of them may not be used anymore.
// Some these error variants may not be used anymore. Also, I think most of the times
// that we return `EcsError`, there is only one possible error that could occur for that function.
// If that is the case in all situations, we should consider breaking each error type into it's
// own struct, so that we aren't returning an enum with a bunch of errors that will never happen
// for each function call.
#[derive(Debug, thiserror::Error)]
pub enum EcsError {
/// A resource was not initialized in the [`World`][crate::World] but the
Expand Down
4 changes: 3 additions & 1 deletion framework_crates/bones_ecs/src/stage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ pub struct SystemStages {
impl std::fmt::Debug for SystemStages {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SystemStages")
// TODO: add list of stages to the debug render for `SystemStages`.
// TODO: Add list of stages to the debug render for `SystemStages`.
// We can at least list the names of each stage for `SystemStages` debug
// implementation.
.finish()
}
}
Expand Down
3 changes: 3 additions & 0 deletions framework_crates/bones_framework/src/input/gamepad.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
//! Gamepad input resource.
// TODO: implement gamepad input in bones framework.
// We don't have any gamepad imput implementation right now. We should probably
// copy Bevy's strategy for the most part, just like we did with the keyboard and
// mouse modules.
1 change: 0 additions & 1 deletion framework_crates/bones_framework/src/localization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ impl LocalizationAsset {
};

// TODO: Log localization formatting errors.
//
// We need to find a way to log the errors without allocating every time we format:
// https://github.com/projectfluent/fluent-rs/issues/323.
b.format_pattern(value, None, &mut vec![])
Expand Down
5 changes: 4 additions & 1 deletion framework_crates/bones_framework/src/render/camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ use crate::prelude::*;
///
/// The entity must also have a [`Transform`] component for the camera to render anything.
#[derive(Clone, Copy, Debug, HasSchema)]
#[schema(opaque)] // TODO: make repr(C) when `Option`s are supported.
#[schema(opaque)]
// TODO: make repr(C) when `Option`s are supported.
// We don't have `Option` support in `bones_schema` right now.
// Once we do, we can make this type `#[repr(C)]` instead of `#[schema(opaque)]`.
pub struct Camera {
/// The height of the camera in in-game pixels.
///
Expand Down
14 changes: 14 additions & 0 deletions framework_crates/bones_schema/macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,20 @@ pub fn derive_has_schema(input: TokenStream) -> TokenStream {
default_fn: #default_fn,
drop_fn: Some(<Self as #schema_mod::raw_fns::RawDrop>::raw_drop),
// TODO: Allow deriving `hash_fn` and `eq_fn` for `HasSchema`.
// We need to come up with a strategy for deriving the `Hash` and `Eq`
// functions. There are a couple ways of thinking about this. If the
// struct is #[repr(C)] and all of it's fields implement hash and eq,
// then we can automatically implement hash and EQ using all of the
// field's implementations, without having to have the rust struct
// actually implement either. On the other hand, we could have the rust
// struct be required to derive hash and/or eq, and then we just use the
// `RawHash` and `RawEq` traits to get the functions. I think that's
// probably the right direction, but we need to come up with an
// attribute syntax to tell the derive macro to use the Hash and Eq
// rust implmentations. Bevy used `#[reflect(Hash)]`, and we already
// have `#[schema(no_default)]` so maybe we just add a couple flags like
// `#[schema(hash, eq)]` if you want to use the Rust structs
// `Hash` and `Eq` impls.
eq_fn: None,
hash_fn: None,
kind: #schema_mod::SchemaKind::Primitive(#schema_mod::Primitive::Opaque {
Expand Down
12 changes: 7 additions & 5 deletions framework_crates/bones_schema/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,9 @@ impl Schema {
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
// TODO: Add name fields to `SchemaData`.
//
// We may want to to have both "full" names and "short" names.
// We may want to to have both "full" names and "short" names. We have to think about whether or not
// we want to have some sort of a module path type or just make the full name include the module
// path in whatever way it wants to.
pub struct SchemaData {
/// The kind of schema.
pub kind: SchemaKind,
Expand Down Expand Up @@ -262,9 +263,10 @@ pub struct StructFieldInfo {
/// The schema of the field.
pub schema: &'static Schema,
// TODO: Investigate adding attribute info to `StructFieldInfo`.
//
// This would allow custom type datas to read and respond to custom attributes on fields as
// well.
// It could be very useful if the derive macro could capture custom attribute data for struct
// fields and put it into the schema data. This would allow type data implementations that
// implement `FromType` to have access to custom attributes that could be used to modify various
// behavior, without requiring a new macro.
}

/// A type of primitive.
Expand Down
8 changes: 7 additions & 1 deletion framework_crates/bones_schema/src/std_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,11 @@ mod impl_glam {
clone_fn: Some(<Self as RawClone>::raw_clone),
drop_fn: Some(<Self as RawDrop>::raw_drop),
default_fn: Some(<Self as RawDefault>::raw_default),
// TODO: Implement hash and eq for `Quat`.
// TODO: Get the schema `hash_fn` and `eq_fn` for the `Quat` type.
// Quats don't implement hash and eq by default because of floating point number
// issues, so we'll have to use a workaround like `CustomRawFns` below to create
// valid implementations of Hash and Eq over the floating points inside the
// Quat.
hash_fn: None,
eq_fn: None,
type_data: Default::default(),
Expand Down Expand Up @@ -190,6 +194,8 @@ mod impl_glam {
schema_impl_glam_vecs!(F64, f64, DVec);

// TODO: Implement `HasSchema` for glam matrix types.
// We need to implement `HasSchema` for the matrix types, just like we did with the vector
// types.

macro_rules! custom_fns_impl_bvec {
($ty:ident) => {
Expand Down
Loading

0 comments on commit db6560f

Please sign in to comment.