kaka.farm

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit 4c68edc30236b0e5de36b6a42852a35c82fddcfa
parent d8fe85ca5359e0342ac0ccdf658a2059b58526d2
Author: Yuval Langer <yuval.langer@gmail.com>
Date:   Wed, 12 Jun 2019 15:36:38 +0300

Add cobalt blog.

Diffstat:
M.gitignore | 1+
Acobalt/_cobalt.yml | 7+++++++
Acobalt/_defaults/pages.md | 10++++++++++
Acobalt/_defaults/posts.md | 10++++++++++
Acobalt/_layouts/default.liquid | 13+++++++++++++
Acobalt/index.md | 10++++++++++
Acobalt/posts/making-quicksilver-and-friends-play-nice-with-wasm32.md | 192+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 243 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -5,3 +5,4 @@ public/ output/ pelican_base_configuration.pyc __pycache__ +*~ diff --git a/cobalt/_cobalt.yml b/cobalt/_cobalt.yml @@ -0,0 +1,7 @@ + +site: + title: cobalt blog + description: Blog Posts Go Here + base_url: http://kaka.farm +posts: + rss: rss.xml diff --git a/cobalt/_defaults/pages.md b/cobalt/_defaults/pages.md @@ -0,0 +1,10 @@ +--- +layout: default.liquid +--- +## Blog! + +{% for post in collections.posts.pages %} +#### {{post.title}} + +[{{ post.title }}]({{ post.permalink }}) +{% endfor %} diff --git a/cobalt/_defaults/posts.md b/cobalt/_defaults/posts.md @@ -0,0 +1,10 @@ +--- +layout: default.liquid + +title: First Post +is_draft: true +--- + +# This is our first Post! + +Welcome to the first post ever on cobalt.rs! diff --git a/cobalt/_layouts/default.liquid b/cobalt/_layouts/default.liquid @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>{{ page.title }}</title> + </head> + <body> + <div> + <h2>{{ page.title }}</h2> + {{ page.content }} + </div> + </body> +</html> diff --git a/cobalt/index.md b/cobalt/index.md @@ -0,0 +1,10 @@ +--- +layout: default.liquid +--- +## Blog! + +{% for post in collections.posts.pages %} +#### {{post.title}} + +[{{ post.title }}]({{ post.permalink }}) +{% endfor %} diff --git a/cobalt/posts/making-quicksilver-and-friends-play-nice-with-wasm32.md b/cobalt/posts/making-quicksilver-and-friends-play-nice-with-wasm32.md @@ -0,0 +1,192 @@ +--- +layout: default.liquid + +title: Targeting wasm32 with Quicksilver and friends. +is_draft: true +--- + +# Making Quicksilver work with wasm32. + +## Disclaimer: + +This technology is indistinguishable from magic. I am merely recalling which + spells and incantations worked for me. If you have anything to add, you can + reach me on <https://gitgud.io/yuvallanger/kaka.farm/> or + <https://gitlab.com/yuvallanger/kaka.farm/>. + +Several months ago, writing a Flappy Bird clone called [Rectangly +Rect](https://gitgud.io/yuvallanger/rectangly-rect/), I have done a bunch of +asking around and found exactly which parts don't work and how to replace them. +Yesterday, trying to adapt YasamSim to the web, I have re-discovered those +workarounds, and decided to write this down. + +## `println!`! + +First thing, drop all of your `println!`s. For some esoteric reason, this +function throws a wrench into the web's machinery. Same goes for +`std::time::Instance::now()`. For now I just dropped all calls to `now()`, +maybe I could ask the browser manually with whatever function Javascript has, +or maybe there is a more standardized `std` alternative for the web - I don't +know. + +In order to replace `println!`, I had to add to `Cargo.toml` a general +dependency for the crate `log`, an entry for every target that is not wasm32 +for the crate `env_logger`, and an entry for the crate `web_logger` for the +wasm32 target: + +```Cargo.toml +[dependencies] +log = "0.4" + +[target.'cfg(not(wasm32))'.dependencies] +env_logger = "0.6" + +[target.'cfg(wasm32)'.dependencies] +web_logger = "0.1" +``` + +In `src/logging.rs`, conditionally compile a different `init_logger()` function +for each platform, wasm32 and not-wasm32: + +```src/logging.rs +#[cfg(target_arch = "wasm32")] +pub fn init_logger() { + ::web_logger::init(); +} + +#[cfg(not(target_arch = "wasm32"))] +pub fn init_logger() { + ::env_logger::init(); +} +``` + +In `src/main.rs`, call the `init_logger()` defined in the `logging.rs` +sub-module at the head of your `main()` function: + +```src/main.rs +mod logging; + +fn main() { + logging::init_logger(); + … +} +``` + +Now you can call `info!()`, `error!()`, `warn!()`, etc., as described in <https://docs.rs/log/0.4/log/>. + +If you also debug it in your native target, you can also provide the `RUST_LOG` +environment variable, as per <https://docs.rs/env_logger/0.6/env_logger/>'s +documentation, in your command line incantations: + +``` +$ RUST_LOG=DEBUG cargo run +``` + +## Sequentialize SPECS. + +For some more esoteric reasons, probably something to do with threads, I had to +rewrite how I run my `specs::System`s , and +how `specs::System`s written. + +### Dispatching `specs::Dispatcher`. + +One normally builds a dependency graph of `specs::System`s using something +like: + +```src/main.rs +fn make_specs_dispatcher() -> specs::Dispatcher<'static, 'static> { + specs::DispatcherBuilder::new() + .with( + SystemFoo, + "system_foo", + &[], + ) + .with( + SystemBar, + "system_bar", + &["system_foo"], + ) + .build() +} + +struct OurGameState { + specs_world: specs::World, + specs_dispatcher: specs::Dispatcher, +} + + +impl State for OurGameState { + fn new() -> Result<World> { + let specs_world = make_specs_world_and_register_components(); // Implemented elsewhere… + let specs_dispatcher = make_specs_dispatcher(); + + Ok( + OurGameState { + specs_world, + specs_dispatcher, + } + ) + } + + fn update(&mut self, window: &mut Window) -> Result<()> { + let system_foo = SystemFoo; + let system_bar = SystemBar; + + system_foo.run_now(&selfworld.res); + system_bar.run_now(&world.res); + + world.maintain(); + + Ok(()) + } + + [imagine the rest of the quicksilver::lifecycle::State methods implemented here…] +} +``` + +In this example `SystemBar` depends on the state of the `specs::World` left by +`SystemFoo` after it does its thing. + +Instead of using this `Dispatcher` as described in +<https://slide-rs.github.io/specs/03_dispatcher.html>, you do this in your +`quicksilver::lifecycle::State::update()` + +``` +struct OurGameState { + specs_world: specs::World, +} + +impl State for OurGameState { + fn new() -> Result<World> { + let specs_world = make_specs_world_and_register_components(); // Implemented elsewhere… + + Ok( + OurGameState { + specs_world, + } + ) + } + + fn update(&mut self, window: &mut Window) -> Result<()> { + let system_foo = SystemFoo; + let system_bar = SystemBar; + + system_foo.run_now(&selfworld.res); + system_bar.run_now(&world.res); + + world.maintain(); + + Ok(()) + } + + [imagine the rest of the quicksilver::lifecycle::State methods implemented here…] +} +``` + +But in order to sequentialize how you deal with `specs`, you'd need to change one more thing: + +### Lay off `specs::LazyUpdater`. + +If you do anything with `specs::LazyUpdate`, you would have to convert it into +another form, interacting with your `Component` `Storage`s directly with +`WriteStorage` or whatever.