diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml new file mode 100644 index 000000000..a3a584083 --- /dev/null +++ b/.github/workflows/website.yml @@ -0,0 +1,120 @@ +name: Website + +on: + push: + branches: + - master + pull_request: + +env: + RUSTFLAGS: -Cdebuginfo=0 + CARGO_TERM_COLOR: always + CARGO_INCREMENTAL: 0 + RUST_BACKTRACE: 1 + +jobs: + Tutorials: + name: Doc Tutorials + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + sparse-checkout: docs/tutorials + + - name: Build Books + uses: taiki-e/install-action@v2 + with: + tool: mdbook@0.4.37 + + - run: mdbook build docs/tutorials --dest-dir ${GITHUB_WORKSPACE}/public/docs/tutorials + + - uses: actions/upload-artifact@v4 + with: + name: Doc Tutorials + path: public/docs/tutorials + + Rust-API: + name: Doc Rust API + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + override: true + components: rust-docs + + - name: Build API Doc + env: + FEATURES: parallel serde derive uuid_entity storage-event-control + run: cargo doc --all --features "${FEATURES}" # --no-deps + + - uses: actions/upload-artifact@v4 + with: + name: Doc Rust API + path: | + target/doc + + Website: + name: Doc Website + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + sparse-checkout: | + docs/website + + - name: Find Base Url + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # Use the API to retrieve the github pages url and set an environment variable containing the value. + run: echo "GITHUB_PAGES_URL=$(gh api "repos/$GITHUB_REPOSITORY/pages" --jq '.html_url')" >> $GITHUB_ENV + + - uses: taiki-e/install-action@v2 + with: + tool: zola@0.18.0 + + - run: zola build --base-url $GITHUB_PAGES_URL + working-directory: docs/website + + - uses: actions/upload-artifact@v4 + with: + name: Doc Zola + path: docs/website/public + + Deploy: + name: Deploy + runs-on: ubuntu-latest + needs: [ Tutorials, Rust-API, Website ] + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + if: github.event_name != 'pull_request' + steps: + - uses: actions/download-artifact@v4 + with: + name: Doc Tutorials + path: public/docs/tutorials + + - uses: actions/download-artifact@v4 + with: + name: Doc Rust API + path: public/docs/api + + - uses: actions/download-artifact@v4 + with: + name: Doc Zola + path: public + + - uses: actions/upload-pages-artifact@v3 + with: + path: public + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/Cargo.toml b/Cargo.toml index e58ed3fff..0ec6fa375 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,8 +5,8 @@ description = """ Specs is an Entity-Component-System library written in Rust. """ documentation = "https://docs.rs/specs/" -repository = "https://github.com/slide-rs/specs" -homepage = "https://specs.amethyst.rs" +repository = "https://github.com/amethyst/specs" +homepage = "https://amethyst.github.io/specs" readme = "README.md" keywords = ["gamedev", "ecs", "entity", "component"] categories = ["concurrency", "game-engines"] @@ -20,7 +20,7 @@ rust-version = "1.70.0" autobenches = false [dependencies] -ahash = "0.7.6" +ahash = "0.8.6" crossbeam-queue = "0.3" hibitset = { version = "0.6.4", default-features = false } log = "0.4.8" @@ -49,9 +49,9 @@ shred-derive = ["shred/shred-derive"] features = ["parallel", "serde", "shred-derive", "specs-derive", "uuid_entity", "storage-event-control"] [dev-dependencies] -nalgebra = "0.31" +nalgebra = "0.32" criterion = "0.3.1" -ron = "0.7.1" +ron = "0.8.1" rand = "0.8" serde_json = "1.0.48" shred = { version = "0.16.0", default-features = false, features = ["shred-derive"] } diff --git a/README.md b/README.md index a5caf0a4b..3abb272e8 100644 --- a/README.md +++ b/README.md @@ -2,26 +2,22 @@ > **S**pecs **P**arallel **ECS** -[![Build Status][bi]][bl] [![Crates.io][ci]][cl] [![Gitter][gi]][gl] ![MIT/Apache][li] [![Docs.rs][di]][dl] [![Code coverage][coi]][cov] ![LoC][lo] +[![Build Status][bi]][bl] [![Crates.io][ci]][cl] [![Gitter][gi]][gl] ![MIT/Apache][li] [![Docs.rs][di]][dl] -[bi]: https://travis-ci.org/amethyst/specs.svg?branch=master -[bl]: https://travis-ci.org/amethyst/specs +[bi]: https://github.com/amethyst/specs/actions/workflows/ci.yml/badge.svg?branch=master +[bl]: https://github.com/amethyst/specs/actions/workflows/ci.yml [ci]: https://img.shields.io/crates/v/specs.svg [cl]: https://crates.io/crates/specs/ +[gi]: https://badges.gitter.im/slide-rs/specs.svg +[gl]: https://gitter.im/slide-rs/specs + [li]: https://img.shields.io/crates/l/specs.svg?maxAge=2592000 [di]: https://docs.rs/specs/badge.svg [dl]: https://docs.rs/specs/ -[gi]: https://badges.gitter.im/slide-rs/specs.svg -[gl]: https://gitter.im/slide-rs/specs - -[coi]: https://img.shields.io/codecov/c/gitlab/torkleyy/specs/master.svg -[cov]: https://codecov.io/gl/torkleyy/specs/branch/master - -[lo]: https://tokei.rs/b1/github/slide-rs/specs?category=code Specs is an Entity-Component System written in Rust. Unlike most other ECS libraries out there, it provides @@ -39,7 +35,7 @@ Minimum Rust version: 1.70 ## [Link to the book][book] -[book]: https://specs.amethyst.rs/docs/tutorials/ +[book]: https://amethyst.github.io/specs/docs/tutorials/ ## Example @@ -118,10 +114,10 @@ Please look into [the examples directory](examples) for more. | crate | version | |----------|------------------------------------------------------------------------------------------------| -| hibitset | [![hibitset](https://img.shields.io/crates/v/hibitset.svg)](https://crates.rs/crates/hibitset) | -| rayon | [![rayon](https://img.shields.io/crates/v/rayon.svg)](https://crates.rs/crates/rayon) | -| shred | [![shred](https://img.shields.io/crates/v/shred.svg)](https://crates.rs/crates/shred) | -| shrev | [![shrev](https://img.shields.io/crates/v/shrev.svg)](https://crates.rs/crates/shrev) | +| hibitset | [![hibitset](https://img.shields.io/crates/v/hibitset.svg)](https://crates.io/crates/hibitset) | +| rayon | [![rayon](https://img.shields.io/crates/v/rayon.svg)](https://crates.io/crates/rayon) | +| shred | [![shred](https://img.shields.io/crates/v/shred.svg)](https://crates.io/crates/shred) | +| shrev | [![shrev](https://img.shields.io/crates/v/shrev.svg)](https://crates.io/crates/shrev) | ## Contribution diff --git a/codecov.yml b/codecov.yml deleted file mode 100644 index e1a331547..000000000 --- a/codecov.yml +++ /dev/null @@ -1,26 +0,0 @@ -codecov: - notify: - require_ci_to_pass: yes - -coverage: - precision: 2 - round: down - # range: "70...100" - - status: - project: yes - patch: yes - changes: no - -parsers: - gcov: - branch_detection: - conditional: yes - loop: yes - method: no - macro: no - -comment: - layout: "header, diff" - behavior: default - require_changes: no diff --git a/docs/reference/book.toml b/docs/reference/book.toml deleted file mode 100644 index 094303ccb..000000000 --- a/docs/reference/book.toml +++ /dev/null @@ -1,5 +0,0 @@ -[book] -authors = ["Thomas Schaller"] -multilingual = false -src = "src" -title = "Specs reference" diff --git a/docs/reference/src/01_system.md b/docs/reference/src/01_system.md deleted file mode 100644 index f44ce8afb..000000000 --- a/docs/reference/src/01_system.md +++ /dev/null @@ -1,4 +0,0 @@ -# System - - - diff --git a/docs/reference/src/SUMMARY.md b/docs/reference/src/SUMMARY.md deleted file mode 100644 index ab94c79ec..000000000 --- a/docs/reference/src/SUMMARY.md +++ /dev/null @@ -1,5 +0,0 @@ -# Summary - -- [Introduction](./intro.md) -- [1. System](./01_system.md) - diff --git a/docs/reference/src/intro.md b/docs/reference/src/intro.md deleted file mode 100644 index 7dc485678..000000000 --- a/docs/reference/src/intro.md +++ /dev/null @@ -1,7 +0,0 @@ -# Specs Parallel ECS - -This is the reference for Specs, a Rust Entity Component System library. - -If you're looking for tutorials instead, there's a book for that -[here](../tutorials/), too. - diff --git a/docs/tutorials/src/01_intro.md b/docs/tutorials/src/01_intro.md index e2982554b..fa4d1db3e 100644 --- a/docs/tutorials/src/01_intro.md +++ b/docs/tutorials/src/01_intro.md @@ -15,10 +15,6 @@ Additional documentation is available on `docs.rs`: * [API documentation for Specs](https://docs.rs/specs) -There also is a reference-style documentation available here: - -* [Specs reference](../reference/) - You don't yet know what an ECS is all about? The next section is for you! In case you already know what an ECS is, just skip it. diff --git a/docs/tutorials/src/02_hello_world.md b/docs/tutorials/src/02_hello_world.md index d27864d12..90a776d02 100644 --- a/docs/tutorials/src/02_hello_world.md +++ b/docs/tutorials/src/02_hello_world.md @@ -84,10 +84,25 @@ struct Velocity { If the `#[storage(...)]` attribute is omitted, the given component will be stored in a `DenseVecStorage` by default. But for this example, we are explicitly asking for these components to be kept in a `VecStorage` instead (see -the later [storages chapter][sc] for more details). But before we move on, we +the later [storages chapter][sc] for more details). + +`#[storage(VecStorage)]` assumes `` as the default type parameter for the storage. +More complex type parameters can be specified explicitly: + +```rust,ignore +#[derive(Component, Debug)] +#[storage(FlaggedStorage>)] +pub struct Data { + [..] +} +``` +(see the later [`FlaggedStorage` and modification events chapter][tc] for more details on `FlaggedStorage`) + +But before we move on, we need to create a world in which to store all of our components. [sc]: ./05_storages.html +[tc]: ./12_tracked.html ## The `World` diff --git a/docs/tutorials/src/12_tracked.md b/docs/tutorials/src/12_tracked.md index 5e88b0405..f47965fd9 100644 --- a/docs/tutorials/src/12_tracked.md +++ b/docs/tutorials/src/12_tracked.md @@ -1,7 +1,7 @@ # `FlaggedStorage` and modification events In most games you will have many entities, but from frame to frame there will -usually be components that will only need to updated when something related is +usually be components that will only need to be updated when something related is modified. To avoid a lot of unnecessary computation when updating components it diff --git a/docs/website/config.toml b/docs/website/config.toml index e54d05c94..1ba785f72 100644 --- a/docs/website/config.toml +++ b/docs/website/config.toml @@ -1,5 +1,5 @@ -# The URL the site will be built for -base_url = "https://slide-rs.github.io/" +# Should be supplied with --base-url +base_url = "/" title = "Specs" description = "Specs Parallel ECS, a Rust library for parallel data processing using the Entity Component System pattern" @@ -8,10 +8,13 @@ theme = "hyde" # Whether to automatically compile all Sass files in the sass directory compile_sass = true +[markdown] # Whether to do syntax highlighting # Theme can be customised by setting the `highlight_theme` variable to a theme supported by Zola highlight_code = true +highlight_theme = "inspired-github" + # Whether to build a search index to be used later on by a JavaScript library build_search_index = true @@ -19,8 +22,7 @@ taxonomies = [] [extra] hyde_links = [ - {url = "/", name = "Home"}, + {url = ".", name = "Home"}, {url = "docs", name = "Docs"}, - {url = "https://github.com/slide-rs/specs", name = "GitHub"}, -# {url = "about", name = "About"}, + {absolut_url = "https://github.com/amethyst/specs", name = "GitHub"}, ] diff --git a/docs/website/content/_index.md b/docs/website/content/_index.md index ff6d02b7f..f0da41e78 100644 --- a/docs/website/content/_index.md +++ b/docs/website/content/_index.md @@ -1,5 +1,101 @@ +++ -paginate_by = 5 -sort_by = "date" +title = "Specs" +template = "section-nodate.html" +++ +> **S**pecs **P**arallel **ECS** + +Specs is an Entity-Component System written in Rust. +Unlike most other ECS libraries out there, it provides + +* easy parallelism +* high flexibility + * contains 5 different storages for components, which can be extended by the user + * its types are mostly not coupled, so you can easily write some part yourself and + still use Specs + * `System`s may read from and write to components and resources, can depend on each + other and you can use barriers to force several stages in system execution +* high performance for real-world applications + +## [Link to the book][book] + +[book]: docs/tutorials/ + +## Example + +```rust +use specs::prelude::*; + +// A component contains data +// which is associated with an entity. +#[derive(Debug)] +struct Vel(f32); + +impl Component for Vel { + type Storage = VecStorage; +} + +#[derive(Debug)] +struct Pos(f32); + +impl Component for Pos { + type Storage = VecStorage; +} + +struct SysA; + +impl<'a> System<'a> for SysA { + // These are the resources required for execution. + // You can also define a struct and `#[derive(SystemData)]`, + // see the `full` example. + type SystemData = (WriteStorage<'a, Pos>, ReadStorage<'a, Vel>); + + fn run(&mut self, (mut pos, vel): Self::SystemData) { + // The `.join()` combines multiple component storages, + // so we get access to all entities which have + // both a position and a velocity. + for (pos, vel) in (&mut pos, &vel).join() { + pos.0 += vel.0; + } + } +} + +fn main() { + // The `World` is our + // container for components + // and other resources. + let mut world = World::new(); + world.register::(); + world.register::(); + + // An entity may or may not contain some component. + + world.create_entity().with(Vel(2.0)).with(Pos(0.0)).build(); + world.create_entity().with(Vel(4.0)).with(Pos(1.6)).build(); + world.create_entity().with(Vel(1.5)).with(Pos(5.4)).build(); + + // This entity does not have `Vel`, so it won't be dispatched. + world.create_entity().with(Pos(2.0)).build(); + + // This builds a dispatcher. + // The third parameter of `with` specifies + // logical dependencies on other systems. + // Since we only have one, we don't depend on anything. + // See the `full` example for dependencies. + let mut dispatcher = DispatcherBuilder::new() + .with(SysA, "sys_a", &[]).build(); + // This will call the `setup` function of every system. + // In this example this has no effect + // since we already registered our components. + dispatcher.setup(&mut world); + + // This dispatches all the systems in parallel (but blocking). + dispatcher.dispatch(&mut world); +} +``` + +## Contribution + +Contribution is very welcome! If you didn't contribute before, +just filter for issues with "easy" or "good first issue" label. +Please note that your contributions are assumed to be dual-licensed under Apache-2.0/MIT. \ No newline at end of file diff --git a/docs/website/content/pages/about.md b/docs/website/content/pages/about.md deleted file mode 100644 index 813b0ea01..000000000 --- a/docs/website/content/pages/about.md +++ /dev/null @@ -1,8 +0,0 @@ -+++ -title = "About" -path = "about" -template = "page-nodate.html" -+++ - -This site is about Specs. - diff --git a/docs/website/content/pages/docs.md b/docs/website/content/pages/docs.md index 234bf940a..5ebc2b0aa 100644 --- a/docs/website/content/pages/docs.md +++ b/docs/website/content/pages/docs.md @@ -13,7 +13,3 @@ template = "page-nodate.html" * [Tutorials for master](tutorials/) -## Reference - -* [Specs reference for master](reference/) - diff --git a/docs/website/content/specs-0.15.md b/docs/website/content/specs-0.15.md deleted file mode 100644 index 1c26d9bcf..000000000 --- a/docs/website/content/specs-0.15.md +++ /dev/null @@ -1,10 +0,0 @@ -+++ -title = "Specs 0.15 released" -date = 2019-05-04 -draft = true -+++ - -Specs 0.15 finally released! - -Test - diff --git a/docs/website/themes/hyde/templates/index.html b/docs/website/themes/hyde/templates/index.html index f96dc11b9..5b9873840 100644 --- a/docs/website/themes/hyde/templates/index.html +++ b/docs/website/themes/hyde/templates/index.html @@ -39,7 +39,11 @@ diff --git a/docs/website/themes/hyde/templates/page.html b/docs/website/themes/hyde/templates/page.html deleted file mode 100644 index 35acc9731..000000000 --- a/docs/website/themes/hyde/templates/page.html +++ /dev/null @@ -1,10 +0,0 @@ -{% extends "index.html" %} - -{% block content %} -
-

{{ page.title }}

- - {{ page.content | safe }} -
-{% endblock content %} - diff --git a/docs/website/themes/hyde/templates/section-nodate.html b/docs/website/themes/hyde/templates/section-nodate.html new file mode 100644 index 000000000..0b12a948b --- /dev/null +++ b/docs/website/themes/hyde/templates/section-nodate.html @@ -0,0 +1,9 @@ +{% extends "index.html" %} + +{% block content %} +
+

{{ section.title }}

+ {{ section.content | safe }} +
+{% endblock content %} + diff --git a/netlify.toml b/netlify.toml deleted file mode 100644 index 511434346..000000000 --- a/netlify.toml +++ /dev/null @@ -1,8 +0,0 @@ -[build] -publish = "public" -command = "BASE_URL=\"https://specs.netlify.com\" ./scripts/build-netlify.sh" - -[build.environment] - -[context.deploy-preview] -command = "BASE_URL=${DEPLOY_PRIME_URL} ./scripts/build-netlify.sh" diff --git a/scripts/build-netlify.sh b/scripts/build-netlify.sh deleted file mode 100755 index 8c1c2de88..000000000 --- a/scripts/build-netlify.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/sh - -set -e - -WORKING_DIR=$(pwd) - -# Install everything -mkdir bin -cd bin -install_tar_gz() { - curl -sL "$1" | tar zxv -} - -echo "Installing dependencies..." - -install_tar_gz https://github.com/getzola/zola/releases/download/v0.6.0/zola-v0.6.0-x86_64-unknown-linux-gnu.tar.gz -install_tar_gz https://github.com/rust-lang-nursery/mdBook/releases/download/v0.2.1/mdbook-v0.2.1-x86_64-unknown-linux-gnu.tar.gz -BIN_DIR=$(pwd) - -curl https://sh.rustup.rs -sSf | sh -s - --default-toolchain nightly -y -. ~/.cargo/env - -# Build website -echo "Building website..." - -cd "${WORKING_DIR}"/docs/website -"${BIN_DIR}"/zola build --base-url "${BASE_URL}" -o "${WORKING_DIR}/public" - -# Build reference + tutorials -build_book() { - cd "${WORKING_DIR}"/docs/$1 - "${BIN_DIR}"/mdbook build -d "${WORKING_DIR}/public/docs/$1" -} - -echo "Building books..." - -build_book reference -build_book tutorials - -# Build API docs -FEATURES="parallel serde derive uuid_entity" - -echo "Building Rust API docs..." -cd "${WORKING_DIR}" -cargo doc --all --features "${FEATURES}" || cargo doc --all --features "${FEATURES}" --no-deps -cp -R target/doc "${WORKING_DIR}/public/docs/api" - -echo "Done!" diff --git a/scripts/kcov.sh b/scripts/kcov.sh deleted file mode 100755 index 8b45eac4d..000000000 --- a/scripts/kcov.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh - -docker rm -f mykcov1 - -# Run image (non-blocking) -docker run -dt --security-opt seccomp=unconfined --name mykcov1 --entrypoint /bin/sh registry.gitlab.com/torkleyy/docker-cargo-kcov || exit 1 - -#docker cp Cargo.lock mykcov1:/volume -docker cp Cargo.toml mykcov1:/volume -docker cp src/ mykcov1:/volume -docker cp tests/ mykcov1:/volume -docker cp specs-derive/ mykcov1:/volume -docker cp examples/ mykcov1:/volume -docker cp benches/ mykcov1:/volume - -docker exec -t mykcov1 /bin/sh -c "cargo check --all" || echo "Failed to generate rustc meta" -docker exec -t mykcov1 /bin/sh -c "cargo kcov --all" || echo "Failed generating report" - -rm -R cov -mkdir -p cov -docker cp mykcov1:/volume/target/cov ./ - -# Force remove image -docker rm -f mykcov1 diff --git a/specs-derive/src/lib.rs b/specs-derive/src/lib.rs index 5a73e83f7..139f4c9ee 100644 --- a/specs-derive/src/lib.rs +++ b/specs-derive/src/lib.rs @@ -15,7 +15,7 @@ extern crate syn; use proc_macro::TokenStream; use syn::{ parse::{Parse, ParseStream, Result}, - DeriveInput, Path, + DeriveInput, Path, PathArguments, }; mod impl_saveload; @@ -28,7 +28,17 @@ mod impl_saveload; /// use specs::storage::VecStorage; /// /// #[derive(Component, Debug)] -/// #[storage(VecStorage)] // This line is optional, defaults to `DenseVecStorage` +/// #[storage(VecStorage)] // This line is optional, defaults to `DenseVecStorage` +/// struct Pos(f32, f32, f32); +/// ``` +/// +/// When the type parameter is `` it can be omitted i.e.: +/// +///```rust,ignore +/// use specs::storage::VecStorage; +/// +/// #[derive(Component, Debug)] +/// #[storage(VecStorage)] // Equals to #[storage(VecStorage)] /// struct Pos(f32, f32, f32); /// ``` #[proc_macro_derive(Component, attributes(storage))] @@ -68,9 +78,14 @@ fn impl_component(ast: &DeriveInput) -> proc_macro2::TokenStream { }) .unwrap_or_else(|| parse_quote!(DenseVecStorage)); + let additional_generics = match storage.segments.last().unwrap().arguments { + PathArguments::AngleBracketed(_) => quote!(), + _ => quote!(), + }; + quote! { impl #impl_generics Component for #name #ty_generics #where_clause { - type Storage = #storage; + type Storage = #storage #additional_generics; } } }