kayak_ui icon indicating copy to clipboard operation
kayak_ui copied to clipboard

Panic When Accessing Resource via Context

Open Psikik opened this issue 3 years ago • 5 comments

I'm not entirely sure if I'm doing something wrong here (still pretty new to rust) but I'm getting a panic when trying to pull an initialized resource out of kayak's BevyContext::query_world. If I get rid of all the kayak_ui stuff, the resource is present as expected.

error

Initial seed: 3485847679
creating ui
getting seed from res
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: NoSuchResource(NoSuchResource)', ~\
.cargo\git\checkouts\kayak_ui-299a0b6ac8320811\f90c054\kayak_core\src\context.rs:677:71
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: process didn't exit successfully: `target\debug\examples\kayak_res_panic.exe` (exit code: 101)

I did my best to try and cut it down to a bare bones reproduction.

cargo.toml

bevy = "0.6.1"
kayak_ui = { git="https://github.com/StarArawn/kayak_ui", rev="f90c0541ea1b8016ccf44904c426ce70e1c9a2aa", features = ["bevy_renderer"] }
rand = "0.8.5"
rand_xoshiro = "0.6.0"

panic.rs

use bevy::prelude::{App as BevyApp, Commands, Res, SystemSet};
use bevy::DefaultPlugins;
use kayak_ui::bevy::BevyKayakUIPlugin;
use kayak_ui::widgets::{App, Text};
use kayak_ui::{
    bevy::BevyContext,
    core::{render, Index},
};
use rand::Rng;
use rand_xoshiro::{rand_core::SeedableRng, Xoshiro256PlusPlus};

#[derive(Clone, Eq, PartialEq, Debug, Hash)]
enum GameState {
    Playing,
}

fn create_ui(mut commands: Commands) {
    println!("creating ui");

    let context = BevyContext::new(|context| {
        println!("getting seed from res");

        let seed = context.query_world::<Res<RandomResource>, _, u32>(|c| c.seed);

        println!("got seed: {}", seed);

        render! {
            <App>
                <Text content={format!("Seed: {}", seed)} size={12.0} />
            </App>
        }
    });

    commands.insert_resource(context);
}

struct RandomResource {
    seed: u32,
}

impl Default for RandomResource {
    fn default() -> Self {
        let mut rng = Xoshiro256PlusPlus::seed_from_u64(1);
        let init_seed = rng.gen::<u32>();
        println!("Initial seed: {}", init_seed);

        RandomResource { seed: init_seed }
    }
}

fn main() {
    BevyApp::new()
        .init_resource::<RandomResource>()
        .add_state(GameState::Playing)
        .add_plugins(DefaultPlugins)
        .add_plugin(BevyKayakUIPlugin)
        .add_system_set(SystemSet::on_enter(GameState::Playing).with_system(create_ui))
        .run();
}

I tried to make a nearly identical example without kayak that doesn't panic to make sure I wasn't going crazy.

no_panic.rs

use bevy::prelude::*;
use rand::Rng;
use rand_xoshiro::{rand_core::SeedableRng, Xoshiro256PlusPlus};

#[derive(Clone, Eq, PartialEq, Debug, Hash)]
enum GameState {
    Playing,
}

fn create_ui(res: Res<RandomResource>) {
    println!("getting seed from res");

    let seed = res.seed;

    println!("got seed: {}", seed);
}
struct RandomResource {
    seed: u32,
}

impl Default for RandomResource {
    fn default() -> Self {
        let mut rng = Xoshiro256PlusPlus::seed_from_u64(1);
        let init_seed = rng.gen::<u32>();
        println!("Initial seed: {}", init_seed);

        RandomResource { seed: init_seed }
    }
}

fn main() {
    App::new()
        .init_resource::<RandomResource>()
        .add_state(GameState::Playing)
        .add_plugins(DefaultPlugins)
        .add_system_set(SystemSet::on_enter(GameState::Playing).with_system(create_ui))
        .run();
}

Psikik avatar Mar 24 '22 01:03 Psikik

Does it panic if you move that same resource access into a custom widget?

My guess is that we actually don't have access to World at this point.

MrGVSV avatar Mar 24 '22 01:03 MrGVSV

Seems to be that way. I hadn't yet ventured into custom widgets yet. Building a custom widget that checks world.is_err() as in the full_ui example does not panic.

Psikik avatar Mar 24 '22 01:03 Psikik

Hm, yeah it probably is:

https://github.com/StarArawn/kayak_ui/blob/f90c0541ea1b8016ccf44904c426ce70e1c9a2aa/bevy_kayak_ui/src/bevy_context.rs#L40-L49

I think the only way to achieve this unfortunately would be to do so within a widget— where World access is guaranteed— rather than within the constructor function for BevyContext.

This means that we should probably make query_world a pub(crate) access instead of a pub one so other users don't stumble upon the same issue. This should be okay since the only pub access (that I know of) is here: https://github.com/StarArawn/kayak_ui/blob/f90c0541ea1b8016ccf44904c426ce70e1c9a2aa/bevy_kayak_ui/src/lib.rs#L73-L78

So that will probably need to be dealt with as well (perhaps by just simply moving the process_event system into the update system).

MrGVSV avatar Mar 24 '22 02:03 MrGVSV

BevyContext::new( wont have access to world here. Another suggestion would be to load in the resource via the create_ui system.

StarArawn avatar Mar 25 '22 20:03 StarArawn

Another suggestion would be to load in the resource via the create_ui system.

Actually, yeah this might be a simpler solution assuming you can pass the resource into the closure (which is probably trivial for your RandomResource type since it could implement Copy).

MrGVSV avatar Mar 25 '22 21:03 MrGVSV

Since solutions to the problem above have been suggested I'm going to close this for now. Feel free to open up a new issue if you feel there is more to do here.

StarArawn avatar Aug 18 '22 16:08 StarArawn