StarArawn / bevy_ecs_tilemap

A tilemap rendering crate for bevy which is more ECS friendly.
MIT License
943 stars 199 forks source link

Headless mode (for multiplayer) #50

Open martinfiers opened 3 years ago

martinfiers commented 3 years ago

Hello,

First of all thanks for this great plugin. I was thinking of using it for a multiplayer game in combination with the Tiled support that you recently added. One prerequisite for this is that the plugin should work in headless mode (i.e., without all the graphical plugins). I was wondering whether that's something that you envisioned / considered, and/or if you think this belongs elsewhere.

I like the idea of having a Tile Component in the ECS framework, and I can use it to attach some game logic on it. For multiplayer, the authorative node / server (depending on the terminology you use :) ) should be able to simulate the game (headless). So basically all the infrastructure of loading from a Tiled file + the ECS infrastructure that this crate provides is very useful, however because it links directly with the rendering, headless won't work. Specifically, this is the error I get when I don't load in the default bevy plugins in combination with this plugin:

thread 'main' panicked at 'resource does not exist: bevy_asset::assets::Assets', /home/mfiers/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_ecs-0.5.0/src/world/mod.rs:674:32

Which is to be expected. The way I solved this in my game prototype was to fully split logic from rendering into two separate plugins - which seems to be a good practice in game development anyways. The headless node only needs to run the logic plugin, whereas the client runs both logic + rendering plugins. (the rendering plugin then has a system that extends all entities and attaches the necessary sprites/texture components onto all entities that don't have one yet).

I'm curious to hear your thoughts about this! Let me know if this discussion/issue belongs in the right place here as a github issue.

StarArawn commented 3 years ago

Hello!

I agree with adding headless and the implementation should be very straight forward as all that is needed is to simply not spawn/generate meshes for chunks. This would also pull out the render pipelines. I might have some time to devote to this in a few days. Would a feature flag work okay for this?

martinfiers commented 3 years ago

Hello. Thanks for the response! I can test when you have something. Just curious how a feature flag would work if you have a single project with two binaries (client, server), since the dependencies would be different (the 'game' would have all features, the 'server' would have only the headless part). I guess it's time then that I split up my project using workspaces / separate crates.

Just as a thought experiment, the alternative could be that this crate provides two plugins, a logic and render plugin, and that as users you can choose either the TilemapPlugin plugin (which would load both plugins), or choose to take the more low-level logic plugin. Although the latter would probably be more work and also less user friendly/idiomatic (I'm not yet enough a rust expert to make any comments here ;) )?

I'm fine with either approach, whichever is most rust idiomatic and/or works best for you!

therocode commented 3 years ago

Just FYI I encountered this use case just now as well

blorman commented 2 years ago

Me too:)

LucCADORET commented 2 years ago

+1

StarArawn commented 2 years ago

This is partially done we need to remove some code using the render flag, but I think for the most part we are close.

nerdachse commented 1 year ago

This is my most anticipated feature in bevy_ecs_tilemap! Very important for server authorative based multiplayer.

How can I support in making it happen?

bzm3r commented 1 year ago

@nerdachse I think this should work now! See: https://github.com/StarArawn/bevy_ecs_tilemap/issues/345

Can you try it out and let me know if it's working? I think this issue can be closed if so.

nerdachse commented 1 year ago

@bzm3r I would love to, but at the moment I am stuck at:

thread 'main' panicked at 'Requested resource bevy_asset::assets::Assets<bevy_render::render_resource::shader::Shader> does not exist in the `World`.
                Did you forget to add it using `app.insert_resource` / `app.init_resource`?
                Resources are also implicitly added via `app.add_event`,
                and can be added by plugins.', /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_ecs_tilemap-0.9.0/src/render/mod.rs:134:9

So further investigating... I disabled the default-features, maybe I need some though...

This is what I have so far (note that with rendering, everything works like a charm):

use bevy::prelude::*;
use bevy_ecs_tilemap::prelude::*;

pub struct TerrainPlugin;

impl Plugin for TerrainPlugin {
    fn build(&self, app: &mut App) {
        app.add_plugin(TilemapPlugin);
        app.add_startup_system(generate_terrain);
    }
}

fn generate_terrain(mut commands: Commands) {
    let map_size = TilemapSize { x: 100, y: 100 };
    let mut tile_storage = TileStorage::empty(map_size);

    let tilemap = commands.spawn_empty().id();
    let id = TilemapId(tilemap);

    for x in 0..100 {
        for y in 0..100 {
            let pos = TilePos { x, y };
            let entity = commands.spawn((
                id,
                pos,
            )).id();
            tile_storage.set(&pos, entity);
        }
    }
}

Note that I have:

bevy = { workspace = true, default-features = false }
bevy_ecs_tilemap.workspace = true
bevy_ecs_tilemap.default-features = false

in my Cargo.toml.

Fully aware that this is a layer 8 problem and that it should work. Just not sure what combination of features I need to make it work.