#bevy_mod_scripting

1 messages · Page 2 of 1

old trail
#

But at rust level

vast dock
#

Callback for onStartup and such?

old trail
#

Yeah like, think on_script_loaded but called on the rust side

#

And more

vast dock
#

The way I'm setting things up is all the logic/game will all be rust based, and scripting are ways to insert things or change things.

As of now I don't have enough experience with rust/bevy/BMS to exactly say what I need or want unfortunately.

#

And even if I did I wouldn't want to place expectations considering this is mainly technology evaluation and feasability for an escape game project.

#

For now I feel like what you said seem very sensible.

#

But maybe an git issue to discuss what would be the most sensible callbacks ?

old trail
#

I am thinking of pipelining the whole script load process so that people can react to things in between all the internal machinery

vast dock
#

Because a callback on_script_loaded could trigger a reload of other things.

#

Library reloads -> all scenario and tooling reload

#

Although not automatic that could be a way to still have it sandboxed.

#

perhaps wrap a the "require()" call with a register internally could also be another aproach, but then we hit this...

#

Anyways. Those are dreams for now and i find the direction you shared to be very sensible.

#

One step at a time.

untold wharf
#

id prefer two steps at a time for double the speed Hehe

vast dock
old trail
#

Yeah, I'll have to pull out handler resources to be more portable for all of this i think

untold wharf
#

@old trail Should this be working? world.get_type_by_name("bevy::render::camera::ScalingMode")

old trail
#

Replied to the wrong message

untold wharf
old trail
#

Yeah, I think they follow the internal paths

grim flower
#

boa_engine

#

When I get time I’ll try to make it work for gleam generated js, which is my objective. That being said should I named it bevy_mod_scripting_gleam?

old trail
#

Very cool, that sounds reasonable

#

I think that would be the first external language crate if you release it

#

Exciting

grim flower
#

I hope I get there before uni recess
ends

#

lets see how it goes

vast dock
#

Finally got the observers and such working nice now. I'm debating wether to try networking or saving or integration tests next...

grim flower
#

@old trail

        .add_systems(
            FixedUpdate,
            (
                update_rendered_state.after(sync_window_size),
                send_on_update.after(update_rendered_state),
                (
                    event_handler::<OnUpdate, LuaScriptingPlugin>,
                    #[cfg(feature = "rhai")]
                    event_handler::<OnUpdate, RhaiScriptingPlugin>,
                    event_handler::<OnClick, LuaScriptingPlugin>,
                    #[cfg(feature = "rhai")]
                    event_handler::<OnClick, RhaiScriptingPlugin>,
                )
                    .after(send_on_update),
            ),
        );

is that right? why rhai appears twice

untold wharf
#

If u removed the last one for example and triggered an OnClick, it would only get handled for lua scripts and not rhai scripts.

grim flower
#
                    event_handler::<OnUpdate, LuaScriptingPlugin>,
                    #[cfg(feature = "rhai")]
                    event_handler::<OnUpdate, RhaiScriptingPlugin>,
                    event_handler::<OnClick, LuaScriptingPlugin>,
                    #[cfg(feature = "rhai")]
                    event_handler::<OnClick, RhaiScriptingPlugin>,
                    #[cfg(feature = "gleam")]
                    event_handler::<OnUpdate, GleamScriptingPlugin>,
                    event_handler::<OnClick, GleamScriptingPlugin>,
                    #[cfg(feature = "gleam")]
                    event_handler::<OnClick, GleamScriptingPlugin>,

so this?

untold wharf
grim flower
#
                (
                    event_handler::<OnUpdate, LuaScriptingPlugin>,
                    #[cfg(feature = "rhai")]
                    event_handler::<OnUpdate, RhaiScriptingPlugin>,
                    event_handler::<OnClick, LuaScriptingPlugin>,
                    #[cfg(feature = "rhai")]
                    event_handler::<OnClick, RhaiScriptingPlugin>,
                    #[cfg(feature = "gleam")]
                    event_handler::<OnUpdate, GleamScriptingPlugin>,
                    event_handler::<OnClick, GleamScriptingPlugin>,
                )

like so?

untold wharf
old trail
#

I just realised the CI was not publishing benchmarks from main because it detected it as a fork thonk

vast dock
old trail
#

what emails?

#

do you mean github notifications?

vast dock
#

Yep.

old trail
#

ah yeah, I don't think I have control over that, but you can filter out some of them here:

#

I wish I could auto filter out bots from these

vast dock
#

Yeah makes sense!

old trail
#

Thoughts on these PR's? The gist is:

  • the concept of loading/reloading contexts, as well as the main handler function for each scripting plugin (think Lua, Rhai, MyHomemadeLuaPlugin), is set in stone at compile time ( not context initializers, the core ones )
  • makes stuff easier to access, don't need world
  • cannot edit these things at runtime
  • meaning you can't for example take the default Lua plugin and just replace the handler, you'd need to use a different type with a different implementation
  • I am thinking that sort of modding is gonna be rare, and it should be easy to replace all occurrences of the default plugin with your own across the codebase (and you'd need to since the resources are keyed by the IntoScriptPluginParams type)

https://github.com/makspll/bevy_mod_scripting/pull/455
https://github.com/makspll/bevy_mod_scripting/pull/456

vast dock
#

With the limited usage ive done with BMS I like the idea of simplifying these calls.

vast dock
#

I'm trying to figure out how to save script data and apply it again.

Currently i've got a very basic example working with bevy_save, they seem to be using MapEntity trait and ReflectMapEntity trait, much like this example : #1172649537098235924 message

This allows to map entities between two states as their ID changes.

As I get a ScriptValue out of a script, I would like for it to be mapped too so when the data is sent back to the script, it would be with the updated reference.
Do you think it would make sense to add the MapEntity and ReflectMapEntity traits to ScriptValue? Or at least just MapEntity?

Also, I was thinking about what behaviour to do for references that are not entities since it likely means they might not be valid after the save/load process.

vast dock
#

Okay so as I'm trying to implement the MapEntity trait I realise that it might not be as simple as I thought...

Is there a way to get an Entity reference from a ScriptValue::Reference without world?

ScriptValue::Reference(reflect_reference) => {
   // Get an Entity ref for entity mapping
   // I want do something like
   // let entity: Entity = entity_mapper.map_entity(entity: Entity)
},
clear solar
#

Hmmm... Am I misunderstanding how script systems work? I'm passing along system_builder("test_system", script_asset) but it results in a crash:
thread 'main' panicked at crates\bevy_mod_scripting_core\src\script\context_key.rs:7:45:
variant with name Weak does not exist on enum bevy_mod_scripting_core::script::context_key::ScriptAttachment

#

Unsure if this is a bug or if I should be passing along something else, buuut I'm not seeing where I pass along the ScriptAttachment of the script.

untold wharf
clear solar
#
function on_script_loaded()
    print(script_asset)
    local TransformType = world.get_type_by_name("Transform")
    
    local update_schedule = world.get_schedule_by_name("Update")
    local system = system_builder("test_system", script_asset)
        :query(
            world.query()
                :component(TransformType)
        )
    
    world.add_system(update_schedule,system)
    
end

function test_system(query_result)
    for i,result in query_result do
        print(result:components()[1])
    end
end```
#

I'm assuming script_asset isn't the correct thing to pass. I assumed so with the changes to the script_id that it accepts script_asset :P

untold wharf
clear solar
#
commands.spawn((
    Transform::from_xyz(3.0, 2.0, 0.0),
    ScriptComponent(vec![asset_server.load::<ScriptAsset>("test_system.lua")])
));```
clear solar
#

though interestingly

local static_script = ScriptAttachment.new_static_script(script_asset)
local system = system_builder("test_system", static_script)
:query(
       world.query()
            :component(TransformType)
)

world.add_system(update_schedule,system)

does not crash.

#

though the script attachment isn't loaded in: WARN bevy_mod_scripting_core::bindings::script_system: Dynamic script system test_system could not find script for attachment: StaticScript(script: id AssetId<bevy_mod_scripting_core::asset::ScriptAsset>{ index: 0, generation: 0}). It will not run until it's loaded.

#

Feels like I shouldn't be creating a new ScriptAttachment if it's managing a scripts' own systems, no?

untold wharf
#

damn yeah im behind, i need to use 0.15 and migrate to handles

old trail
# clear solar Feels like I shouldn't be creating a new ScriptAttachment if it's managing a scr...

the attachment here is just a reference (it doesn't actually attach anything, that struct in itself has the job of describing a way of attaching a script), if you want to run the system on the current scripts context, you need to use the same attachment, This was previously more muddied, as in we were referring to the script id, which essentially referred to either static script or entity script with this name. There is perhaps a case to be made if we should also have a script_attachment global equivalent, I wasn't sure what'd work best

old trail
#

Hmm persisting across saves is something I'd recommend having specific hooks for like on_serialize and on_deserialize and then let the script reproduce the runtime state

vast dock
#

Currently what I was thinking is creating a new struct that creates from ScriptValue using world. Or serialize deserialize as you said but I'm not sure how to keep entity references in scripts.

clear solar
#

Am I right to be passing script_asset? Or?

untold wharf
#

@old trail I'm migrating to handles. it seems add_context_initializer() stopped running? The provided function just doesnt get called. Did something change with that?

old trail
old trail
untold wharf
# old trail Is that after attaching the script? I.e. adding the component or static script m...

Not sure what u mean. I have a script that loads and runs fine, but the context initializer doesnt seem to run at all (my prints dont print). Il need to look into it more to get more details cus im weirded out by the fact that there are no lua errors. Im importing packages, but that cant work if the context initializer doesnt work. I should be getting "null pointer exceptions". Anyway, the first thing i noticed was that the intializer wasnt running so i need to fix that first.

#

Im adding it as a static script

vast dock
# vast dock It's because I'm trying to implement the MapEntities trait which needs this stub...

To be more precise, what I have now is the following:

  • player presses F5
  • on_save lua call script sends ScriptValue I save it in a resources
  • bevy_save does a snap shot that includes this resource.

Then

  • player presses f9
  • bevy_save applies snapshot (this is where ReflectMapEntities is applied to remap to the new entities )
  • I send the data back to script with an on_load lua call.

but perhaps using serialisation would work for entity too? I'm would have to look into that.

untold wharf
#

@old trail Damn, please disregard. It does seem to be working, i just kept missing it somehow.

#

The search feature in the vscode terminal is a bit wonky.

woeful mirage
#

Hi, I'm trying to integrate bevy_mod_scripting (feature luau, version 0.15.1) into my game and it seems like I'm missing types. When dumping the types global variable I see that i'm missing entries. For exemple i'm missing types.Color and types.LinearRgba. The dump is performed inside a callback of a static script.

I there a specific feature i need to enable for these types to be visible ?

vast dock
#

I have bevy = { version = "0.15.3", features = ["dynamic_linking", "file_watcher"] }in my project and it works fine. But perhaps bevy_reflect is not by default for 0.15.3? (works on luau + bevy 0.15.3)

Color has #[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(PartialEq, Default))]so it does seem to be dependent on a feature?

#

let me try and dump the type global myself.

#

I have it :
Color: <Reference to Allocation(11280)(bevy_mod_scripting_core::bindings::query::ScriptTypeRegistration) -> bevy_mod_scripting_core::bindings::query::ScriptTypeRegistration>

#

i'm on BMS 0.13.0

clear solar
#

Yeah I think they’re on BMS 0.15.1

vast dock
#

Yeah, but I don't see why that binding would have dissapeared, unless bug?

woeful mirage
#

I'm on bevy 0.16.1 and bevy_reflect is enabled by default

vast dock
#

Ah. BMS is not compatible with bevy 0.16

#

bevy 0.15.3, unless you are on the specific 0.16 branch, but that currently has regression because of a blocking issue on bevy 0.16

#

This issue.

woeful mirage
#

Okay, thank you

untold wharf
#

Oh cool, i think im done with the handles migration.

untold wharf
clear solar
#

i.e., if i wanted to run ‘test_function’ in the same script context, i don’t think there’s a way for me to get the script’s own scriptattachment

untold wharf
# clear solar i.e., if i wanted to run ‘test_function’ in the same script context, i don’t thi...

Uhh, so idk how ur handling the assets but im using bevy_asset_loader and so for me the binding to get that done is pretty simple:

pub fn get_system_script(
    ctx: FunctionCallContext,
    script_id: String,
) -> Result<Val<ScriptAttachment>, InteropError> {
    let handle = ctx.world()?.with_global_access(|world| {
        let my_assets = world.resource::<MyAssets>();

        my_assets.get_script_handle(&script_id)
    })?;
    Ok(Val(ScriptAttachment::StaticScript(handle)))
}

The handles are stored in a HashMap<AssetFilePathName, Handle<ScriptAsset>> in MyAssets and get_script_handle just retrieves it via the "Script id". The details for u in this case might be different, but the general idea is still the same.

clear solar
#

🫡 Appreciate it. I figured I needed to grab the handle somehow but couldn't figure it out last night.

untold wharf
vast dock
#

@old trail

Would it make sense to add an Entity(Entity) inside ReflectBase? This would allow the MapEntity to directly change the Entity if the reflect is just an entity, and if not it could call an error because it's trying to map something that should not be mapped?

/// The Id of the kind of reflection base being pointed to
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd)]
pub enum ReflectBase {
    /// A component of an entity
    Component(Entity, ComponentId),
    /// A resource
    Resource(ComponentId),
    /// an allocation
    Owned(ReflectAllocationId),
}
#

This would allow to directly implement MapEntity on ScriptValue and therefore making it very easy to map entities as we save/load.

Example code with a component

ScriptValue::Reference(reflect_reference) => {
    match &reflect_reference.base.base_id {
        ReflectBase::Component(entity, component_id) => {
            let mapped = entity_mapper.map_entity(*entity);

            let mut new_ref = reflect_reference.clone();
            new_ref.base.base_id = ReflectBase::Component(mapped, *component_id);

            ScriptValue::Reference(new_ref)
        }
        // resources and owned allocations don’t need entity remapping
        _ => {
            error!("Attempted to map reflect_reference, that was not component");
            ScriptValue::Unit
        }
    }
}
#

I'm going to check how well it works on components this afternoon.

vast dock
#

I just confirmed that mapping components with this approach works.

Implementing MapEntity and ReflectMapEntity for ScriptValue would likely be possible by separating ReflectBase with a new Entity(Entity) enum type. This would then make it very easy to keep track of entity references during state changes, saves and loads.

I'll create an issue on the repo to have a trace of my work somewhere.

vast dock
#

Wait, BMS 0.15.1 is for bevy 0.16...?

#

I was trying to upgrade and getting some silliness...

#

@woeful mirage I got it wrong as the newer BMS 0.15.1 is compatible with bevy 16.0, I just hadn't double checked. It still has the regression from the issue I mentionned, though it is usable for things.

woeful mirage
#

Ok, I this case there must be a problem for types to be missing. Maybe the type registration is done too late ?

vast dock
#

Maybe something that changed between bevy 0.15.3 and 0.16.0, or maybe a change between 16.0 and 16.1

woeful mirage
#

Yeah probably, I'll try to debug it tomorrow

woeful mirage
#

That's also my theory

old trail
#

Yeah it seems those impls moved from bevy_reflect to bevy_color and for some reason that crate is not being codegened

old trail
#

I am gonna look into making the crate graph calculation better and more transparent

old trail
#

It'd make more sense to add a variant to ScriptValue for Entity specifically

#

that has some performance benefits

vast dock
old trail
#

oh and since now scripts only run when attached, callbacks actually should always have access to entity/script etc

untold wharf
#

@old trail Random thought: lets say i had a game that allowed people to script logic directly into the game via an in-game editor. And the users simply queued commands from the scripts so they can indirectly make changes to the world. I.e Move(direction) could be one of those commands. For debugging purposes, i may way want to visually show the queue of commands or a history of commands and tie each command to a line of code in a script. Is that something that I could do today with BMS, and if not, could it be theoretically possible later?

old trail
#

I am guessing you're wondering specifically about getting the current line of code in bindings?

untold wharf
#

And again, just for debug purposes. If a command is showing up unexpectedly for the user i can see that being very helpful in figuring out where the issue is. This is a very minor requirement btw and its not even for the game im making atm, but i was thinking for other future games.

old trail
untold wharf
old trail
#

oh wait that's luau

untold wharf
old trail
untold wharf
old trail
#

I had to add the () or rhai was expecting the never type ! lmao

vast dock
#

Oh my....

vast dock
vast dock
# old trail It'd make more sense to add a variant to ScriptValue for Entity specifically

There is still this problem of needing to have access both to the ReflectReference for lua and the Entity for MapEntities.

So either I create a ScriptValue::Entity(Entity) which works fine for the converts, but not for lua as it would need a ReflectReference, or a ScriptValue::Entity(Entity, ReflectReference), which becomes a pain for things like From<Entity> or From<ReflectReference> (unless I do all the process that reflect does as you mentionned).

vast dock
#

I'll think about it more.

vast dock
#

Maybe a dummy component...

old trail
#

I don't know if trying to serialise everything is the way to go, personally my instinct would be to create a resource which is stable across reloads and use it to recreate state

vast dock
#

That resource would end up containing ScriptValues no ? Then the ScriptValue need to be entity mapped when saved?

#

I'm going to go with a dummy component for now as a workaround, it's frustrating to see components being easily mapped but not entities...

vast dock
#

I have it working now.

The script has a reference to a component that refers to it's own entity. As I save and load the path is mapped allowing to keep references to the entity despite the state change.

This is a script modifying the transform of two entity, the entity are despawned and respawned and the reference stay valid as they have been updated by MapEntities.

vast dock
#

The down side is that a deleted entity leads to errors instead of null values.

old trail
#

damn, rhai is actually quite bad for build times:

#

I'll need to think about serializing/deserializing in general, BMS doesn't currently have much in the way of utils for those things

old trail
#

I am thinking I might be able to pre-expand the macros generated in _functions, to cut down like 80% of the compile time

vast dock
old trail
untold wharf
old trail
#

clean compiles

old trail
#

Ah, actually it did not nearly affect the compile time as much as i'd hoped :C I guess the script_bindings macro is not at all slow

pale fern
#

I'll still try it out. I also found something wrong in my laptop that was slowing it down, so hopefully the compile times will be more reasonable

old trail
#

another thing I can try do is instead of depending on all of bevy, point directly at its subcrates

#

that might decouple the compilation quite a bit, and let us parallelize functions earlier

pale fern
#

Well it did speed up by about 40 minutes in my machine

old trail
#

seriously ?

#

damn

#

I am working on splitting out the crates too, so that should give a big boost

pale fern
#

I said speed up, not slow down

old trail
#

oh yeah that was me being positively surprised

pale fern
#

😄

old trail
#

I guess the macro work load just happens to be super slow for you

pale fern
#

Yeah, my laptop is pretty unpredictable

old trail
#

what was your total build time ?

pale fern
#

1h22min

#

From scratch

#

Without bms its about 58 mins

old trail
#

that's crazy

vast dock
#

I was at 28minutes for a clean build last time I tried on osx mbp 2020 intel maxed out.

#

(not sure if sharing that info is useful)

pale fern
#

Showoff

#

/s

vast dock
#

Honestly I think clean build time is one of the annoying things... 40GB for a debug build is silly.

pale fern
#

:0

#

How

#

Mine is just 5GB

vast dock
#

Ah... Maybe I'm doing something stupid in my toml....

#

Or maybe the osx target is silly

#

I would tend to think I'm silly first though.

pale fern
#

Do you use the opt-level = 1 and = 3 options?

vast dock
#

Yeah I think so. I don't have my toml on hand right now though.

pale fern
#

I see

#

How weird

#

Biggest I've ever gotten has been 15GB

vast dock
#

Actually it's there. #1406122398276653107 message

#

An older version but it's very similar.

#

I didn't test things too thoroughly so I don't have much data

untold wharf
#

I just did a clean compile: 3m05s

#

Yall need to get better PCs lol

vast dock
#

Or better configs ahahaha

#

I need to upgrade to M4 after my PhD.

#

Or M5

untold wharf
#

that was with a AMD Ryzen 9 7950X

pale fern
#

If you're willing to chip in with a few hundred dollars, I'll gladly let you help me

vast dock
old trail
#

my clean builds are usually around 12 minutes

#

Processor: AMD Ryzen 7 6800HS with Radeon Graphics, 3201 Mhz, 8 Core(s), 16 Logical Processor(s)

untold wharf
#

and then for non clean its about 3-6 seconds depending on the alignment of the stars.

#

my next pc will hopefully be sub-second Prayge

vast dock
untold wharf
vast dock
#

Maybe 10-25 when I start doing changes.

untold wharf
#

10-12 is the highest i have seen but those are rare

vast dock
#

Nah I think the link might not be parallel ?

#

The moment I hit many crates in my project it goes up to 25

untold wharf
pale fern
#

With cranelift and generic sharing it got my iterative compiles from 10 to 15 minutes down to around 1

untold wharf
#

Cranelift doesnt seem to do anything for me and generic sharing has always been on

pale fern
#

nope

vast dock
#

Try doing that it Maaasssively improved my project

pale fern
#

I haven't tried it. Does it speed up the compiles a lot for you?

vast dock
#

And also makes it much cleaner to organise.

pale fern
#

oki dok

untold wharf
#

My older pc had 90 second non-clean compiles. It was miserable. I upgraded as soon as i get serious with bevy.

vast dock
untold wharf
pale fern
#

Oh woah

vast dock
#

I'm planning on using bevy inside escape games. I want to use my knowledge to create art.

#

We'll see if it still holds after I do market analysis and my technology evaluation

untold wharf
#

Later on il start a discord for it and might do something like that there

#

But thats way later

vast dock
#

I tried to join empty epsilon but I don't think I can get over the limitation they have in their game. Hence me evaluating bevy.

untold wharf
untold wharf
#

Ah found it

vast dock
#

Artemis is designed for anyone who watched Star Trek and dreamed of what it would be like to sit on the bridge of a star ship.

Artemis simulates a spaceship bridge by networking several computers together.** You cannot play Artemis single-player!** One computer runs the simulation and the "main screen", while the others serve as workstations for…

Price

$6.99

Recommendations

296

▶ Play video
untold wharf
#

This feels like something bevy would be good at. But obviously if u care about modding then maybe not the best choice. I love bevy too much to pick something else so here i am lol

vast dock
#

Empty epsilon has a fantastic modding lua interface which is why I'm here in the first place.

#

Honestly the Empty Epsilon people have done wonderful work. And working on their codebase really helped me give an even richer vision than I originally had.

pale fern
#

My game is basically Total War x Paradox games

vast dock
#

Noice !

pale fern
#

The idea is that it be a highly moddable game, which is why I'm so invested in this crate

vast dock
#

Modding is such more work to setup though...

#

Now that I've applied snapshots, I'm going to have to do actual save files and load them.

#

In a fresh game restart

pale fern
#

Yeah, but I like modding, and I'm building the game from the ground up to take data from external files that can be easily edited

vast dock
#

Yep. Doing the same also

pale fern
#

So for example the map is saved as a csv, and there's an editor mode to be able to create your own

vast dock
#

For me everything will be lua based.

pale fern
#

I think that's a good idea, but not to define the huge amounts of data I need for the map

vast dock
#

You can load data from lua.

#

As in CSV.

pale fern
#

Oh really? I'd been using csv::ReaderBuilder

vast dock
#

There has to be function to read CSV files no? We were reading JSON files in Empty Epsilon in lua.

#

But then maybe the sandboxing in BMS will not allow you to do that ?

pale fern
#

I know that the sandboxing prevents you from requireing, but there's also a feature for that

vast dock
#

To abstract all the world and such from scripters

#

My ship template are lua defined and also a require.

pale fern
#

Though I do like the way I define cities. A toml file for each city recursively loaded

vast dock
#

If file A requires B and B is reloaded, A is not reloaded too.

pale fern
#

Oof

vast dock
#

Yeah a bit of a pain but easy to avoid.

#

I'm debating with myself wether to move my ship templates to toml.

#

We'll see it's part of the things I need to figure out as currently, templates are not propagated.

vast dock
vast dock
old trail
#

i just got my build time down by like half by pointing at bevy subcrates:

#

I think mostly by removing unnecessary crates, and slightly imroving parallelisation, not sure how it will affect end-users who will pull in most bevy crates

#

actually really good:

#

2 minutes!

pale fern
#

:0

vast dock
#

Do you think it's worth it to do it on game level ?

vast dock
old trail
old trail
vast dock
#

I did not know that existed. Cargo has everything.

vast dock
old trail
#

hmm, I think probably yes, or at least thinking about disabling features from bevy you don't need

vast dock
#

Because I don't think bevy and BMS will be compiled often

#

I'll have to see about it later.

#

I'm excited to order my save calls properly and pause the game to make sure all the save data is synched and have an actual save file next week.

#

Which is probably the highest risk in the project currently. Then the final step is networking.

old trail
#

I think with the recent changes coming in handles, BMS will be slightly more deterministic, in that you control exactly when scripts will execute (when you attach them), but we'll still need to make all of the queries use deterministic versions to get fully there, so you might bump into that with networking

untold wharf
old trail
#

Oh nah, I mean the handles changes

vast dock
# old trail I think with the recent changes coming in handles, BMS will be slightly more det...

The scripts won't be sent over networking the way I plan it.

The script is an API for the server instance to interact with the game model. The game model will be what is network replicated.

Basically I want people to be able to create scenarios and stories using my foundations.

However having instant script execution could be nice to avoid a pause and a back and forth between events for saving.

solar cipher
#

@vast dock Out of curiosity, how did you make the 2D grid in your spaceship game? Trying to do this on another project if you could share.

vast dock
#

Code has not changed from this. But it's not going to be the final thing. It's a placeholder.

#

I'll likely use a shader in the final thing

solar cipher
#

Thanks!

pale fern
old trail
#

Will have to split out each individual binding feature into its own crate I think

#

but that's for later

#

@woeful mirage this wll bring back generation for bevy_color

old trail
#

if I was to split out the bindings crates into their own individual crates, what should the naming scheme be? bevy_asset_bindings bevy_asset_bms_bindings ?

untold wharf
#

_bindings works

#

I never have to deal with this so i dont think it matters too much

old trail
#

yeah, mostly worried about not stealing a crate bevy itself might want later

untold wharf
old trail
#

true

old trail
#

publishing is gonna be interesting:

vast dock
#

Oh dear.

#

That's a big one !

old trail
#

yup!

#

really curious how that's going to affect compiling

untold wharf
#

@old trail am i going crazy? Can i not set an Option<t> field to nil when constructing in lua?

#

Well, looks like that was actually my first time trying it. Interesting.

#

Deriving default doesnt seem to do anything

vast dock
#

Just checked on my end and I have a problem with nil too on 0.13

#[derive(Component, Reflect, Default)]
#[reflect(Component, MapEntities)]
#[require(CollidingEntities)]
pub struct SimpleMissileAI {
    pub target: Option<Entity>,
    #[reflect(ignore)]
    pub previous_target_pos: Option<Vec2>,
}
function ODEntityT.set_simple_missile_ai(self: ODEntity, target: ODEntity?)
    if target then 
        world.insert_component(self:get_entity_ref(), types.SimpleMissileAI, construct(types.SimpleMissileAI, {target = target:get_entity_ref()}))
    else
        world.insert_component(self:get_entity_ref(), types.SimpleMissileAI, construct(types.SimpleMissileAI, {target = nil}))
    end
end
#

Giving it an entity ref works, but giving it a nil fails.

#

ERROR bevy_mod_scripting_core::handler: error in script `lua/scenarios/missile_intercept.luau`: Error in function construct : Missing data in constructor for type: core::option::Option<bevy_ecs::entity::Entity>. Missing data: target.

untold wharf
#

Yeah i get the same error. For now i just made a binding that acts as a constructor method (which is for the the best)

vast dock
untold wharf
vast dock
#

But also nothing stops you from assigning nil just after it was constructed and create a lua wrapper? Or that would hit the world flush limitations from bevy 0.16?

#

You are on bevy 16 right?

untold wharf
vast dock
#

Ah... Yeah...

#

Does seem like a bug indeed.

old trail
#

I think this is a case of ReflectDefault missing on your field type

#

Or not being registered in the type registry

old trail
#

I do remember we had a conversation around this and agree we should also look for a default at the constructed type level

old trail
#

I think I got a useful utility out of this work too:

vast dock
old trail
#

yeah, to figure out what dependencies I need in the generated crates, I need to understand the crate graph within the bevy workspace, and AFAIK there's no out of the box way to do this to this level of detail

vast dock
#

What is the name of that tool?

#

I'm really enjoying hanging out here, I'm learning lots it's nice.

old trail
#

crate_feature_graph but it's unpublished yet

vast dock
#

I just managed to get the saving all properly ordered using states. It's pretty nice and it makes sure all my data is properly handled, final step is to write it down to a file.

Then I think I might try to look into the blocking issue at bevy as I want to catch up to the latest version of bevy_save and avian before starting to do networking...

untold wharf
old trail
#

The splitting of crates btw, with all of the additional code, I am at 7minutes clean compile time (like 10x more crates being generated), so pretty good:

pale fern
#

What tool is it?

vast dock
vast dock
old trail
old trail
#

all of these build time improvements are live on main now

vast dock
#

You've been pushing hard lately!

#

Nice job honestly!

woeful mirage
#

Yeah you've done so much, that's amazing!

vast dock
#

I'm digging more towards the saving things. I'm now getting into the serialization/deserialization as I have managed to save my game to a JSON file.

I'm going to see if I can implement the needed traits like I did for map entities

vast dock
#

is there a simple way to detect what ScriptValue::Reference is pointing to without world?

#

I got it by saving world.component_id::<Component>();

vast dock
#

It's a pain to try to recreate ScriptValues without the allocators and references xD

old trail
#

I once looked into making the allocations actually use a global allocator, but the allocator api is unstable and bevy doesn't hold alignment information for types via reflection yet

vast dock
#

Honestly I'm not too far, I managed to go all the way down to entities from a ScriptValue into a json save file.

#

Now I'm trying to get back out of it.

#

But I'm not sure I can do that without changing BMS itself because of private fields and such...

untold wharf
old trail
untold wharf
vast dock
#

Ha ! Now I have loading for everything except the entity reference...

old trail
vast dock
#

Any idea on how to force create a component ScriptValue::Reference(), with the ComponentID, or TypeID, or anything outside of the BMS crate without the existing allocators?

#

Technically for a component all the data is still valid after load, but I need to feed it to private values...

untold wharf
# old trail same tbh, here you just need to make sure the allocations don't get dropped whil...

Right, but i was just talking about initializing the scriptvalue, i.e

let mut allocator = allocator.write();
let entity_payload = ReflectReference::new_allocated(trigger.target(), &mut allocator);
let entity_val = ScriptValue::Reference(entity_payload);

I feel like im doing this with everything, regardless of the type (of course as long as I need it to be a reference and not just a primitive)

#

So this part i felt could be automated,

old trail
#

oh right, yeah that's true, I think the only thing is if you hide the allocator .write() bit you can cause deadlocks

untold wharf
old trail
#

Wait do you mean having something like ScriptValue::new_allocated(payload, &mut allocator) that would be perfectly fine

untold wharf
#

And hence the global allocator u mentioned before.

#

ScriptValue::new_allocated is a good idea tho, def throw that in the to-do list. If u can update examples to use that, it can make that whole process seem less intimidating.

#

But ideally i could pass in a ScriptValue::UnprocessedReference(MyValue) and somewhere down the line the 3 lines i posted (including the query that gets the allocator) gets run on it and turns it into the ScriptValueReference. But...yeah not sure if thats feasible.

wide charm
#

@old trail RE: https://github.com/makspll/bevy_mod_scripting/issues/12, I'm an un-invested but curious third-party: would there be resistance against scoping down this issue to a simple implementation of Serialize and Deserialize for ScriptValue ? What are some of the technical challenges here?

GitHub

Bevy Scripting Plugin. Contribute to makspll/bevy_mod_scripting development by creating an account on GitHub.

vast dock
#

I now have managed to make the save and load work, I am currently saving to a json for human readability, but I'll do it on the binary format bevy_save use later.

vast dock
#

I didn't see any and had to scroll up discord. If not I'll create one.

#

Also we should update the compatibility table in the README.md, iirc BMS 0.14 bumps to bevy 0.16.0?

solar cipher
#

Lots of folks here use Luau for type annotations right? Might migrate to that.

#

Also, anyone think a pypy implementation would be interesting? I bet Lua almost certainly still outperforms. But would be interesting to benchmark a Python JIT.

vast dock
untold wharf
#

I think luajit is faster tho?

clear solar
#

Luau has comparative speeds to LuaJIT

#

Not better performance but still competitive

#

I know there’s also LuauJIT but IDK what that’s like

#

The type checking makes it well worth to use over JIT imo

#

And Luau has support for continue and x += 10 🙂

untold wharf
#

Later when i start doing benchmarks il see how much it affects me

vast dock
vast dock
#

Nvm it's a roblox thing it seems...

untold wharf
untold wharf
#

Well, we have Vec2 and Vec3 and those have bindings for us to use in the scripts

vast dock
#

Yeah but they are reflect values right?

#

And you need to use construct

untold wharf
#

Uhh, i use Vec2.new() actually

vast dock
#

Uh....

untold wharf
#

but i cant remember if i made that binding for myself or if its provided by bms

vast dock
#

Am i missing something?

#

Can you do Class.new()?

vast dock
untold wharf
vast dock
#

Or at least they have Vector3.new()

untold wharf
vast dock
untold wharf
#

new is listed there, so yeah its in BMS

vast dock
#

Ah.

untold wharf
#

and not just that, a bunch of methods are there too

vast dock
#

Would make sense.

untold wharf
#

seems gedes gave it some love considering how important it is

#

There are some types that dont have a new binding

vast dock
#

I've launched a fresh build trying to upgrade to bevy 0.16 as i think the blocking issue won't affect me in the end... I've been waiting for 15 minutes so far...

vast dock
#

Eh.. I should pay more attention to the doc I do unecessary constructs...

untold wharf
#

Sometimes il make a binding just to avoid using construct haha. Low key dislike that method. (no offense gedes <3)

vast dock
#

If we ever get into trouble with luau performances we'll integrate luauJIT from mlua.

#

Yeah mine are all hidden behind luau bindings.

untold wharf
#

Yeah that probably wont be too hard to use

vast dock
#

Most likely.

vast dock
#

I'm currently upgrading to bevy 0.16.1, Is there a simple way of having the previous behaviour when loading a script? I'm trying to execute the the script once and then deactivating it (as I need it to register some data to my app)

I tried doing something like this, but they don't get removed:

commands.queue(AddStaticScript::new(handle.clone()));
commands.queue(RemoveStaticScript::new(handle.clone()));
untold wharf
#

RemoveStaticScript doesnt remove the script?

vast dock
#

It probably does, but I'm calling it within the same function so the commands are one after the other

#

So I'm guessing maybe some orders somewhere is calling remove before add ?

#

I didn't have time to debug much yet.

untold wharf
#

oh i see, yeah maybe ur removing it too fast before anything can happen. Delay the removal by 1 frame.

vast dock
untold wharf
vast dock
#

It's not a bug really, it's about choosing if you delete or create first. I think?

Something in the line of this.

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
    let handle = asset_server.load("path");
    commands.queue(AddStaticScript::new(handle.clone()));
    commands.queue(RemoveStaticScript::new(handle.clone()));
}
#

I had to delay the delete by a few frames but it works.

Other things are broken in my code though, I think it's also to do with a change in operation orders.

#

One thing that might be a bug though, this

commands.queue(AddStaticScript::new(handle));
events.write(ScriptCallbackEvent::new_for_all_scripts(
    OnStartScenario,
    vec![ScriptValue::Map(map)],
));

Did not seem to shoot the the OnStartScenario callback in lua when it used to before.

#

I'll look into it when I have time later on.

untold wharf
#

These are some interesting "edge cases" that @old trail might be interested in knowing about at the very least.

vast dock
#

I will need to triple check if I didn't do anything stupid while migrating to bevy 0.16.1

vast dock
#

I created two issues.

#

Also RemoveStaticScriptis not in prelude

#

But that might be intentional?

untold wharf
#

Might be calculated.

old trail
old trail
# wide charm <@269851364253892627> RE: https://github.com/makspll/bevy_mod_scripting/issues/1...

There wouldn't be resistance to it, there are many considerations though as to and simple serialization might not be enough to persist state across runs:

  • TypeId I don't know if you'll be able to easilly deser this
  • ReflectAllocationId is essentially a pointer to a PartialReflect value living inside the ReflectAllocator would this require additional bounds here? If you don't persist the actual values the references will be missing their values
  • unserializable variants, like Error or DynamicScriptFunction
old trail
old trail
old trail
#

if not remove will likely run first, because Add waits for loads to complete

#

I would reccomend manually using the create script / run callback /delete script commands on short lived scripts like these

old trail
vast dock
#

What I was doing used to work, but yeah I'll look into the manual load commands.

untold wharf
#

@old trail Auto-registering of reflect values is coming soon, which to me seems like fuckin magic. Do you think its possible for BMS to have auto registration of bindings? Not a big deal but its one of those annoying boilerplatey things.

old trail
#

if you mean calling register_X_functions on your app for each binding block

#

that could be automated

untold wharf
#

yeah exactly, damn thats dope.

old trail
vast dock
#

On a first load I put 30 frame although I might get away with less

#

Once they are loaded, when reloading I can just put one frame delay on the callback.

#

I've managed to completely update to BMS 0.15.1 and bevy 0.16.1

old trail
#

getting closer to fixing the handler resource removal problem

vast dock
#

I've yet to use the handler context so I can't really have critical feedback. But the description in the PR seems to be resonable to me.

old trail
pale fern
#

I tried out cargo build --timings=html, on a clean compile, and thanks to splitting the code into different crates and the improvements on the bms side, it took the compile time below 1 hour

#

52m40s to be precise

vast dock
old trail
vast dock
#

Also feel free to close my issues if they are not relevant @old trail

old trail
#

aand I can get the context to just this:

old trail
#

now it's just a case of Arc ing the context resource and voila you no longer need to remove any resources to handle callbacks

vast dock
#

Wonderful job!

untold wharf
#

The slowness of lua might dwarf whatever Arc introduces so it might not matter.

hushed zodiac
#

oh yeah almost certainly. interpreting a language is waaaay slower than dereferencing a couple pointers lol

#

ofc, it depends exactly what's going on in there. would looooove to see some benches :D

old trail
#

Yeah it will be slightly less cache friendly, surprisingly it might be faster since we are avoiding resource removal and reinsertion

vast dock
#

Unsure if you'll find what you want in there but there are some benchmarks.

old trail
#

All in all minuscule impact most likely

hushed zodiac
#

also... that's surprisingly fast..? thought that stuff would be waaaaay slower tbh

old trail
#

Napkin math is like 9k 4 argument lua calls to rust bindings (empty) per frame at 60 fps

untold wharf
#

Awesome change then. Ship it!

old trail
#

this will alleviate the problems introduced in bevy 0.16 w.r.t callbacks, commands running simultaneously will be able to use the script contexts, as long as they are not trying to modify the same one

untold wharf
#

ty for all the good work ❤️

vast dock
#

Omg that is actually amazing !

old trail
#

then it might be bevy_mod_scripting_dynamic_ecs or bevy_mod_scripting_error, generally heading towards reducing cognitive load in each area, as well as making the boundaries much clearer

untold wharf
#

Im starting to really hate lua

vast dock
untold wharf
#

Its just one of many things thats missing from rust.

old trail
#

what about?:

for v in pairs(res.vec_usize) do
    iterated_vals[#iterated_vals + 1] = v
end
untold wharf
#

@old trail actually for that specific thing, how hard would it be? im talking about .iter().enumerate() . It works nicely with lua cus its basically ipairs

untold wharf
old trail
#

for val in vec:iter() does it? damn

#

oh you mean with an index

untold wharf
#

yeah so in rust u would have something like for (i, comp) in components.iter().enumerate()

#

which looks a lot like ipairs anyway

#

iter by itself only returns a value in lua, if im not mistaken.

#

im finding myself needing to create index variables outside of the loop and manually incrementing them. Which is gross lol.

old trail
#

Its a bit annoying since you can't define bindings on the function that iter returns

#

But something like iter_enumerated() should work AFAIK

untold wharf
vast dock
#

I'm currently figuring out unit tests. I'm staying within cargo test for now. I'm going to have to do the lua integration test soon

old trail
#

I've gotten somewhere with splitting out bindings and display things into different crates:

#

Cooking making these easier to use via statics/thread locals

untold wharf
vast dock
#

But it looks super dope

untold wharf
#

if im too incompetent to help contribute code, then i shall contribute memes

old trail
#

I am now working on tightening the script loading pipeline

#

turning this whole thing into a compile time typed state machine:

#

ideally people will be able to insert systems to manipulate the process at various points

vast dock
#

You are off doing fancy things!

untold wharf
#

interesting 👀

old trail
#

it's going to be ultra parallelizable too:

vast dock
#

Oh wow. That is sweet !

untold wharf
# old trail it's going to be ultra parallelizable too:

but with script loading, do we really need that? I suppose performance improvements for the initializers that execute before each script callback could make a difference but im not sure how a bunch of them would be running at the same time?

old trail
#

not really, although you would notice a difference I imagine if you're loading thousands of scripts, the main benefit will be how modular this will become

#

also this will mean that if you load a batch of scripts, all of their on_script_loaded events will happen in the same time step, as opposed to each script loading wholly before the next one does

untold wharf
old trail
untold wharf
#

Would just need to set up a queue i guess

vast dock
#

That would save me from waiting frames for a load/delete sequence

vast dock
#

Can BMS run on MinimalPlugin? (I'm trying to do unit tests)
I get some errors:
ERROR bevy_asset::server: Could not find an asset loader matching: Loader Name: None; Asset Type: None; Extension: None; Path: Some("lua/scenarios/missile_test.luau");

#

Min repro :

#[test]
fn min_repro() {
    let mut app = App::new();
    app.add_plugins(MinimalPlugins);
    app.add_plugins(DiagnosticsPlugin);
    app.add_plugins(AssetPlugin::default());
    app.add_plugins(LogPlugin::default());
    app.add_plugins(BMSPlugin);

    app.update();

    let handle: Handle<ScriptAsset> = app
        .world_mut()
        .resource_mut::<AssetServer>()
        .load("lua/mainSettings.luau");

    app.update();
    app.update();
    let is_loaded = app
        .world_mut()
        .resource_mut::<AssetServer>()
        .is_loaded(&handle);

    assert!(is_loaded);
}
old trail
vast dock
#

Ah makes sense.

vast dock
#

I managed to make everything work when it comes to loading all my script files. Now to unit test the save/load mechanism.

untold wharf
#

@old trail So because of how everything works, mutating component data that are script values is very awkward:

local my_component = world.get_component(my_component_e, types.MyComponent)
-- data is of type ScriptValue
local data = my_component.data
data.amount = 32
my_component.data = data

If i try to mutate data directly, i.e my_component.data.amount = 32, nothing happens. The problem is that ScriptValue becomes a plain old lua table. Not a reference to a lua table inside the component. I feel like i may have brought this up a while ago but i forgot what was said 😅. I am curious if i can do anything so that it acts more like a reference in this case?

old trail
#

So the thing about ScriptValue is that it's like this by design, and the same behaviour makes it possible to return a variety of lua values etc at all, so making it a reference type would mean that instead of returning and accessing "my_string" as a literal you'd have to "out.0" check variants and all that jazz

#

When you use it on a component the users have to replace the whole thing

#

Its a bit of a magical primitive

#

Whats the intention behind using ScriptValue here?

untold wharf
# old trail Whats the intention behind using ScriptValue here?

Well, not sure how to explain it. Im keeping things dynamic so that modders can easily make their own stuff. Certain things are expected to have a state, but i dont want the structure of that to be set in stone. So i just set it to a ScriptValue which is basically an "any" type.

Anyway, i think i get what ur saying but in my case im strictly talking about the Map variant (although a luaType[1] should also be a reference for sake of completeness). Is there any chance that could be tweaked to get the desired behavior?

untold wharf
#

Today I pulled all ur updates into the local branch im using and it works great! I was able to get rid of my work-around to solve that issue i was having with triggering callbacks from within scripts. Glad we're done with that chapter lol

old trail
#

which means any sort of by-reference semantic for dictionaries is going to be difficult

#

I think your best bet is a custom type with bindings like set_key get_key , by default non primitive types are converted into references

untold wharf
old trail
#

yeah just a rust wrapper around a type that has the semantics you want, probably some sort of recursive map with ScriptValues as tail types?

#

I'd say it's not a footgun anymore than dictionaries atm

vast dock
#

Why not wrap around everything in a lua library ?

#

It's a bit more work but you'll get all the auto complete with luau

untold wharf
vast dock
#

No but as a workaround for modders

#

To make their life easy

old trail
untold wharf
#

Im not very familiar with lua but i have seen some crazy stuff u can do with lua objects. Im being vague cus im not sure how to describe it, but If u can do that with assignment, then perhaps u can make it do that replacement under the hood. Not something I could figure out right now but i might look into it later. The value in question is being passed into a callback that the modder would define, so i could make such a manipulation (if possible) before passing it to the callback.

vast dock
#

Although the functions are reatached to the data when luau recieves the struct from rust

untold wharf
#

So heres an example of what i meant:

function createWatchedObject()
    local raw_data = {}
    local meta = {
        __index = function(_, key)
            return raw_data[key]
        end,
        __newindex = function(_, key, value)
            raw_data[key] = value
            print("Update:", key, value)
        end
    }
    return setmetatable({}, meta)
end

local obj = createWatchedObject()
obj.name = "Alice"  --> Prints: Update: name Alice
obj.age = 30        --> Prints: Update: age 30
obj.name = "Andrew" --> Prints: Update: name Andrew

The solution wouldnt look quite like this but it highlights what I mean

untold wharf
#

@old trail Ran into some weird compiler errors and i had to make a bunch of changes to /bevy_mod_scripting/crates/bindings/bevy_reflect_bms_bindings/src/lib.rs

Had to do a search and replace of ::bevy_reflect::erased_serde::__private::serde::__private::. Replaced it with nothing so it would go away. This file is auto generated right? Does using ::bevy_reflect::erased_serde::__private::serde::__private::Clone/Option make sense? Cus thats what it was doing and why it was complaining

vast dock
#

I’m working on unit tests, and I was wondering why the Rust callback function use FunctionCallContext and not just a worldguard

old trail
#

when I re-codegened it fixed itself

old trail
#

bencher working as intended 🦾

untold wharf
untold wharf
old trail
untold wharf
urban talon
#

Amazing work, @gedes! Thank you kindly for the shout out.

old trail
vast dock
#

My they are really close to release indeed...

rare badge
#

hey hey! quick question on the upgrade.

right now I have something like this for triggering a callback for all scripts attached to an entity:

writer.write(ScriptCallbackEvent::new(
    callbacks::OnUpdate,
    vec![],
    Recipients::Entity(entity),
));

Am I correct in thinking that I now should be looping through each script for the recipient? e.g.

writer.write_batch(
  query
      .iter()
      .map(|(entity, scripts)| {
          scripts.iter().map(move |script| {
              ScriptCallbackEvent::new(
                  callbacks::OnRoundStart,
                  vec![],
                  Recipients::ScriptEntity(script.id().clone(), entity),
                  None,
              )
          })
      })
);
old trail
rare badge
#

thanks!

rare badge
#

also, is there some info on how to update namespace registrations? e.g.

register(
    "create_peg",
    |ctx: FunctionCallContext, pos: Ref<Vec2>, bonus: bool| {
        let world_guard = ctx.world().unwrap();
        let world = world_guard.as_unsafe_world_cell().unwrap();
        let world = unsafe { world.world_mut() };
        let mut cmd = world.commands();
        let mut entity = cmd.spawn((
            StateScoped(GameState::Main),
            Object {
                pos: *pos,
                data: ObjectData::Peg(PegData::Single),
            },
        ));
        if bonus {
            entity.insert(Bonus);
        }
    },
);

errors with

This function does not fulfil the requirements to be a script callable function. All arguments must implement the ScriptArgument trait and all return values must implement the ScriptReturn trait
If you’re trying to return a non-primitive type, you might need to use Val<T> Ref<T> or Mut<T> wrapper

And not totally sure why. (Sorry if this is obvious and im just missing something!)

old trail
#

Oh do you have default bevy features disabled? Does tour Vec2 implement reflect?

rare badge
#

oh lol yeah that was it i think, thanks again!

#

hmm okay, another weird thing...

error[E0004]: non-exhaustive patterns: `ReflectRef::Function(_)` not covered
   --> /Users/doomy/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bevy_mod_scripting_display-0.16.0/src/printer/mod.rs:38:15
    |
 38 |         match value.reflect_ref() {
    |               ^^^^^^^^^^^^^^^^^^^ pattern `ReflectRef::Function(_)` not covered

This is in the 0.16 version with bevy 0.16.1. not sure what could be causing - I tried enabling all features just in case it was that.

old trail
#

Do you use function reflection? Bevys specifically

#

That should be feature gated in bms but if you disable that feature it should dissapear

#

That enum is a bit problematic

rare badge
#

oh, got it. i think i was using the "reflect_functions" feature as I thought it would enable bevy's reflection, whoops. i didnt solve my error i just broke it for a second. enabling default features on bevy puts me back to the "This function does not fulfill the requirements" error

#

hmm but deleting the vec2 seems to make the error go away, so i guess that is still the issue? it worked on 0.15 so not sure what I changed. also seems to be an issue for Ref<Entity>

#

oh hold on, i think it might be using the wrong Ref :|

#

ahhhhhhhhhhh yeah that was it 😭

rare badge
#

alright, i think i got all the compiler errors handeled updating! was also wondering if script loading changed from being automatic? It looks like my script assets are loading, but scripts don't seem to be firing off (even if i put some global print in a lua file it doesn't do anything, when it used to on load).

#

hmm, seems like adding a scriptcomponent should initialize it, reading through the docs, so i might be doing something wrong elsewhere

untold wharf
#

Oh wait, u say u are doing that. How are u adding it?

rare badge
#

I'm adding via a ScriptComponent and then triggering. e.g.:

--    writer.write(ScriptCallbackEvent::new(
--        callbacks::OnLaunch,
--        vec![ScriptValue::Reference(ReflectReference::new_allocated(
--            ball_entity,
--            &mut alloc,
--        ))],
--        Recipients::Entity(*backing_entity),
--    ));

++    if let Ok(scripts) = scripts.get(*backing_entity) {
++        writer.write_batch(scripts.iter().map(move |script| {
++            ScriptCallbackEvent::new(
++                callbacks::OnLaunch,
++                vec![ScriptValue::Reference(ReflectReference::new_allocated(
++                    ball_entity,
++                    &mut alloc,
++                ))],
++                Recipients::ScriptEntity(script.id(), *backing_entity),
++                None,
++            )
++        }));
++    }
untold wharf
rare badge
#

yeah it just seems like everything is sent to a black hole on the lua end

untold wharf
#

Just as a debug step, can u add it with AddStaticScript and see if the global print statement goes off?

rare badge
#

yeah, that should narrow down. i am using loading states so i think it should be ok? but unsure how things changed in totality

untold wharf
#

in the provided example, he adds the scriptcomponent immediately

old trail
#

Yeah i think it's a case of waiting, the loading can now happen over multiple frames, you can check if a script is loaded by calling ScriptContext<P>::contains

untold wharf
old trail
#

That's still correct, its just it might take longer to be given a context and start responding

#

Using AttachScript commands will load instantly, but if you then attach the component it will reload later

untold wharf
#

Well, they were saying they were getting nothing at all. Print statements werent even firing.

old trail
#

If the print statements are in a callback, and the script is not loaded when the callback is fired, then it will be dropped

untold wharf
#

Thats the weird part for me.

#

Its been a hot min tho so maybe they got it fixed

untold wharf
#

@old trail I wanna make a binding that takes in a single unique marker component type as an input and then returns the entity that has that marker. Assuming there isnt already something like this (besides using a query inside lua which i dont want to do), is this doable?

#

gonna try to learn how to do that with component_id before u respond 🏃‍♂️‍➡️

untold wharf
#

Quick and dirty but it works

fn get_entity(
    ctx: FunctionCallContext,
    comp: Val<ScriptComponentRegistration>,
) -> Result<Val<Entity>, InteropError> {
    let entity = ctx.world()?.with_global_access(|mut world| {
        let mut query = QueryBuilder::<FilteredEntityMut>::new(&mut world)
            .with_id(comp.0.component_id)
            .build();
        
        query.single(world).expect("err").entity()
    })?;

    Ok(Val(entity))
}
untold wharf
#

@old trail I figured it out...

~~oh no, i think i found a bug? I have a script that is static, and im pretty sure i havent added it again as another static script or as a scriptcomponent, but an event on it is getting triggered twice. When i move the event to a different script that is also static, it does not happen. So its something particular about this script. Based on my debugging, im not triggering the event more than once. Its as if there are multiple instances of the script and they're both just getting caught by ScriptCallbackEvent::new_for_all_scripts

The script thats reproducing it isnt random. Im doing something else with it (kinda complicated) while the bug occurs. Instead of trying to explain what im doing, im just wondering if u know of another way to call an event on a script (with the ScriptCallbackEvent i mentioned earlier) besides having an instance of a static script or scriptcomponent? I suspect this third (and undocumented?) way is whats causing this.

Im not setting a ContextPolicy so i guess its set to "per_entity_and_script" but again if im only spawning it as a static script then this shouldnt matter.~~

untold wharf
#

oh boy..I was doing something else unrelated to this and ran into the same problem, but this time it couldnt have been BMS's fault. And this time it made it clear. Because i was importing the file in question in another script, the global callback function was being pulled into said script and thus creating a duplicate callback. I ALREADY RAN INTO THIS AWHILE GO AND JUST FORGOT. God fucking damn it, this is such a bad foot gun.

It would be really nice if we could make the callbacks local and figure out a way for BMS to get to it.

#

I think the best way forward is to keep the current behavior, but also add a global function called "register_callback" that lets me pass in any function and registers it as a callback.

i.e:

local function my_callback(params)
end

register_callback(my_callback)
vast dock
old trail
old trail
old trail
rare badge
untold wharf
#

Not sure if it can be this simple, but wherever the scripts are getting stored, u just create a wrapper that includes it and a Vec<Callback> or something.

untold wharf
#

@old trail decided to try and pull the latest updates in main. Things broke, as I expected. When i queue a RunScriptCallback i get a "No context found for script". When i log the contexts, i can see some but not all. It feels like im sending the callback too soon, but this is happening multiple frames after i queue "AttachScript" so im not sure why that would be the case.

untold wharf
#

Did some dumb stuff to confirm. It is indeed a timing issue. But i need like 2 or 3 frames of delay. Too tired to say how many for sure. This is not ideal, may be related to doomy's issue. Whats strange is that it has nothing to do with the asset loading. Im waiting for the assets to completely load before moving forward. The unusual delay is required after queuing AttachScript.

untold wharf
#

For the record, im fine with requiring a single frame delay if we can't help it, it lines up with how state transitions work (buffered). But anything more than that is awkward.

old trail
maiden sky
#

Hi! Niot sure if this is the best place to ask this question but it's the channel where Rhai is mentioned the most 😅
I'm writing a utility to process graphs (using petgraph) with the intention of using those graphs to generate levels, missions, overworld maps, factions, etc. for a game and I have this little utility that reads a grammar file and shows the nodes in Bevy.
To develop more graph creation algoritms I though to add Rhai (but not using bevy_mod_scripting, since I want to keep the graph & grammar part of the code as generic as possible).
The interface between Rhai and Rust works: I added my variables and functions to the scope, the script is parsed and run successfully... however I'm at a loss with Rhai: inside a function VERY simple code gives me ExprTooDeep errors... while outside functions it "parses" and runs and produces nodes and edges...
Can you tell me if this is a known limitation of Rhai's parser, if there's a place that describe how I should approach writing code to avoid triggering it, or if in your opinion I did something wrong? 😅
It's so annoying that I'm seriously thinking about using pyo3 to embed Python...

untold wharf
#

OK so yeah, that worked. Im starting to understand the work u were doing there lol.

I had to set the time budget to 69 hours

old trail
#

I.e. the rhai engine has settings

untold wharf
#

@old trail How disruptive was 0.17 for bms? Just curious.

vast dock
#

Also I forgot to put an issue but the compatibility table is out of date on the GitHub

maiden sky
# old trail This is something that annoys me about rhai but you can customise the max depth ...

Thanks! I started reading the book "cover to cover" and I got to the "64 in global and 32 in functions but hey counting the depth layers isn't easy" part yesterday my late night 😅 and yeah, it's not easy because apparently LOOPS COUNT FOR THE DEPTH, since I had a 3 deep loop over an array.
I find it quite strange that they explain the optimization strategies and the recursion stack etc. before telling me how I should actually write code in the language, but I guess it's in another part of the book or in a different book.
My worry is that the time saved on compiling the algo in Rust will be wasted in trying to debug strange AST building issues... now that I have this stable enough to run and compare I think I'll try to integrate pyo3 (the big advantage being that it should be the "regular" Python I know well)

chilly bane
#

b crate

old trail
urban talon
#

Hmm, I'm trying to update Nano-9 to Bevy 0.16, and I'm getting stuck on this code:

#[derive(Debug, Clone, Copy, Reflect)]
#[cfg_attr(feature = "scripting", derive(GetTypeDependencies))]
pub enum PColor {
    Palette(usize),
    Color(Srgba),
}

which produces this error:

 1  error[E0412]: cannot find type `TypeRegistry` in this scope                    ▐
   --> src/color/n9color.rs:15:10
    |
 15 | pub enum N9Color {
    |          ^^^^^^^ help: a struct with a similar name exists: `AppTypeRegistry`
    |
   ::: /Users/shane/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bevy_ecs-0
 .16.1/src/reflect/mod.rs:31:1
    |
 31 | pub struct AppTypeRegistry(pub TypeRegistryArc);
    | -------------------------- similarly named struct `AppTypeRegistry` defined h
 ere

Any ideas?

#

Found a solution. I just needed to add use bevy::reflect::TypeRegistry;.

untold wharf
#

"cannot find type TypeRegistry in this scope" can be solved by adding use bevy::reflect::TypeRegistry;.

#

(not making fun of u, haha)

untold wharf
#

@old trail So if i attach a bunch of scripts all at once, im assuming they go into some kind of queue (or effectively so). It would be nice if there was an event (now called Messages) that was emitted when the last one finished loading (i.e whenever the queue transitions to an empty state from not being in an empty state). That way i can get rid the 69 hour time budget and listen for that event. Or maybe u have a better idea, lol.

old trail
#

Or is this a macro change in bevy

urban talon
manic glen
#

Is a BMS version for 0.17 in the works? I did have a quick look at the codebase, and it looks like it's bloody massive, so I'm guessing it's going to take a while?

old trail
old trail
#

It shouldn't take too long assuming no big changes to latest rust compiler internals

#

I am currently working on registered callbacks

#

It should make @untold wharf happy. You'll be able to fully use shared contexts, since the callbacks are "frozen" when you store them i believe

#

This will also let you register callbacks from within callbacks no problem, and the old "dynamic" or "loose" callbacks will still work

untold wharf
#

im looking forward to this tho!

old trail
#

got this working:

function on_script_loaded()
    register_callback("on_test", dynamic_on_test)
end

function dynamic_on_test()
    register_callback("on_test_last", dynamic_on_test_last)
    return "on test: I am dynamically registered from a normal callback!"
end

function dynamic_on_test_last()
    return "on test last: I am dynamically registered from another dynamic callback!"
end

And, once the callbacks are stored, if the script is reloaded, with say a completely empty body, they still work 😄

#

this also works for core callbacks like on_script_loaded and registered callbacks take priority over free-standing ones, meaning you can register all your callbacks in on_script_loaded in a shared context setting, and this will work as expected

#

there is also no issue registering callbacks within callbacks, as functions are read only Arc function pointers, cloned per read

untold wharf
#

Awesome!!!

solar pendant
#

Wait is register_callback new and not available in the current release? I saw it in the docs 🙃

untold wharf
#

Its new, its not in the current release but i think its on main?

solar pendant
#

I thought I was going crazy trying to figure out why it wasn't working BocchiDead

untold wharf
solar pendant
#

I didn't really have one, I was just messing around reading the docs, but one thing I was thinking of was having events fire from my animation controller.

solar pendant
#

Are there any stub files or similar to allow for autocompletion in scripts, for the types and globals that BMS exposes?

untold wharf
#

I think this was the last time this was mentioned, it doesnt appear to be a huge ask. Not sure how far along they are with this.

solar pendant
#

Something to look forward too then bigcomfy Thank you

rare badge
# old trail <@210437037751402507> where were those prints exactly, was it directly in the sc...

i found the issue! was something strangeish.

If i already had a script component on an entity hook.entity,

world.commands().entity(hook.entity).insert(
    bevy_mod_scripting::core::script::ScriptComponent::new(scripts),
);

Doesn't seem to add necessary stuff. If I remove the scriptcomponent beforehand, then it works!

world
  .commands()
  .entity(hook.entity)
  .remove::<bevy_mod_scripting::core::script::ScriptComponent>();

world.commands().entity(hook.entity).insert(
    bevy_mod_scripting::core::script::ScriptComponent::new(scripts),
);
#

so scripts were being loaded, they just werent being updated after initialization 🤔 might be something on my end tbh

old trail
#

Hmm, so you add a script component to an entity, before there are assets loaded?

#

Or maybe somehow the script component doesnt emit onAdd somehow

vast dock
rare badge
untold wharf
#

@old trail with the new updates im getting this warning for types i dont own: " WARN bevy_mod_scripting_bindings::globals::core: duplicate entry inside types global for type: ScalingMode. This can cause confusing issues for script users, use CoreScriptGlobalsPlugin.filter to filter out uneeded duplicate types."

#

In this case, i dont see how i can foresee which ones are not needed. Just cus i dont need it doesnt mean a future modder wont, so i wouldnt want to filter it out. Id prefer to just give them different names. I.e i could call one "ProjectionScalingMode". So instead of a filter, maybe a way for the BMS implementer to rename those types would make sense?

#

I guess my final thoughts are:
-its good theres a warning
-its not great that its being caused by BMS
-Maybe my method of resolving it is better than CoreScriptGlobalsPlugin.filter, in which case BMS itself could solve it with my proposed solution.
-whenever something is renamed like that, it should print an INFO log so ppl still know. INFO logs are fine, warnings are eww 🙂

vast dock
#

I'm trying to move up to 0.16, did something happen to display_value_with_world? I can't seem to find it anywhere now

#

Nvm I just found the migration notes...

#

silly me

#

Now to figure out how to use the display_with_type_info

old trail
old trail
old trail
#

FYI, I am currently overhauling reflection paths, I think relying on Bevy's is ultimately going to take a long time for us to get to a nice place:

  • No more _1 etc. accessed for tuple structs and tuples, [1] does it for everything
  • Maps and Sets support
old trail
#

aaand done, now you will be able to modify stuff through dictionaries, no need for map_get and you can even use non-primitive types:

local key_simple_type = construct(SimpleType, {
    inner = "foo"
})
assert(resource.simple_type_map[key_simple_type],
    "Expected 'bar', got " .. tostring(resource.simple_type_map[key_simple_type]))
#

you can't make mutable references into sets for some reason with bevy reflection, that's something that definitely has to be fixed upstream

brave garden
#

This is a bit wishy washy, but after upgrading my game to BMS for Bevy 0.16 ([email protected]), I find that my callbacks are sometimes not firing. For me this manifests as me pressing the "New Campaign" button and sometimes the callback won't fire. So then I have to exit the half-loaded campaign state, return to the main menu and try again. Sometimes it works, sometimes it doesn't. Is this a known issue with the Bevy 0.16 upgrade?

Somewhat related, why do my callback handlers have to be registered in FixedUpdate, e.g.,

app.add_systems(
    FixedUpdate,
    (
        event_handler::<ResumeCallback, LuaScriptingPlugin>,
        event_handler::<MainCallback, LuaScriptingPlugin>,
    ),
);

My question is wishy washy because it's pretty hard for me to provide much more info than this, but maybe it's a known issue? I'm still on [email protected] but I note that [email protected] doesn't list any "fixes" in its changelog so I've been hesitant upgrade because it doesn't appear to have any bugfixes.

untold wharf
brave garden
untold wharf
# brave garden The [example](https://github.com/makspll/bevy_mod_scripting/blob/ab3d48cc23e9c40...

Ok, well i have never done this and i haven't run into your issue. I think the reason why FixedUpdate was used in this case was for the sake of implementing the game of life. In the docs for attaching scripts, the Update schedule is used in the example. So its definitely not required. It just comes down to how fast u want the events to be processed (every X seconds vs every frame).

The fact that its intermittent is weird, not sure how to debug that without the code in front of me.

brave garden
# untold wharf Ok, well i have never done this and i haven't run into your issue. I think the r...

Hmm right, well if you are using Update and as you suggest that GoL example used FixedUpdate for reasons specific to the game logic, maybe I need to look elsewhere. It definitely worked 100% of the time in the Bevy 0.15 BMS version which is why I wondered if anything could have changed in BMS itself for this version. And yeah, that's why my question is wishy washy, it's hard for me to get a minimal reproducing example to share.

brave garden
#

(I'll try turning on BMS logs as well to see if I can see anything of interest)

brave garden
#

OK I have traced it down to the recipients list being empty during the case when the campaign fails to load (and so the for loop just after is skipped entirely).

This is the system I use to send the event for the main callback.

fn start_script(
    mut commands: Commands,
    script_assets: Res<Assets<ScriptAsset>>,
    mut script_callback_events: EventWriter<ScriptCallbackEvent>,
    script: Option<Single<(Entity, &CampaignScript)>>,
) {
    let Some((campaign_script_entity, campaign_script)) = script.map(|s| s.into_inner()) else {
        error!("Could not find script");
        return;
    };

    debug!("Starting script");

    commands
        .entity(campaign_script_entity)
        .insert(ScriptComponent::new(vec![campaign_script.script.clone()]));

    // Added this panic if the script asset is not loaded just to make sure
    // the asset not being loaded is not the issue.
    let _script_asset = script_assets
        .get(&campaign_script.script)
        .expect("Campaign script asset not loaded");

    script_callback_events.write(ScriptCallbackEvent::new(
        MainCallback,
        vec![ScriptValue::Integer(campaign_script.step as i64)],
        Recipients::ScriptEntity(campaign_script.script.id(), campaign_script_entity),
        None,
    ));
}

So the recipient is a Recipients::ScriptEntity.

But I'm not too sure how to debug inside get_recipients further to see why the result from the match is empty (sometimes).

old trail
#

the recipients will be empty if the script is not loaded fully, one of the changes was that script loading might take multiple frames, you can opt out of this by disabling the load time budget

old trail
#

there is something funky going on that @rare badge is facing that I haven't been able to identify yet, todo with loads not triggering sometimes that they got around by re-inserting the script component, but I am not sure if this is something in BMS yet

amber glen
#

I'm trying to run both client and server Lua environments in the same Bevy app. I'm using per-script context and want to provide different globals per environment. Currently I'm manually clearing the context initializers in LuaScriptingPlugin and setting the ones I need depending on the script being loaded. Is there a better way to do this?

In the future I'd also like to support modifying the world instance the client is provided, and for example filter query results and resource/asset access. I'm assuming I'll have to write manual bindings for his?

brave garden
old trail
#

The asset loaded != script loaded anynore

#

Because after the asset loads, the processing can be spread over multiple frames

untold wharf
#

The reason why didnt think it was a loading issue was because i had a feeling this was being done much later, based on what they said earlier. However, if thats the issue then the intermittency makes sense. And the fact it doesnt work at all in Update also makes sense. When u were using FixedUpdate, the delay it was causing would sometimes be enough for the script to fully load. But sometimes it wouldnt be enough. With Update ur only giving it 1 frame so it simply never loaded.

old trail
amber glen
old trail
#

this wouldn't require modifying/replacing any bindings, as they would be blocked at rust level

#

if you're looking to block off a small number of resources, you could maybe consider claiming accesses to those, but not releasing them, I think that gets reset after every handling

brave garden
# old trail The asset loaded != script loaded anynore

So do I need to add a function on_script_loaded() to my Lua and then inside that function, signal back to, say, some ECS resource/entity that the script is now fully loaded? Or is there another way I'm meant to detect "script loaded"?

untold wharf
#

I think u can listen to ScriptCallbackEvent and check the label to see if its equal to OnScriptLoaded? Would be nice if we had a more direct event to listen to.

rare badge
brave garden
untold wharf
old trail
# brave garden So do I need to add a `function on_script_loaded()` to my Lua and then inside th...

you will need to wait untill all the scripts you need loaded are loaded (or have failed to load), atm there are the following options:

  • ScriptContext<LuaScriptingPlugin> let's you iterate over all residents, these are all currently loaded scripts, you can also access that via Recipients::get_recipients
  • listen to ScriptCallbackResponseEvent, they're not emited by default for core callbacks, but you can enable this via ScriptingPlugin::emit_core_callback_responses, one per loaded script
  • check ActiveMachines<LuaScriptingPlugin>::active_machines, this will tell you if there are any scripts being processed (loaded/reloaded) atm, once that's zero and you are not issuing more asset changes/attachments etc, then everything has been processed

Seeing as this is a bit rough atm, I am cooking a system parameter + rust example on a simple script loading bar using that

old trail
untold wharf
#

@old trail my game runs at 15fps when i try to run with --release and tracy. Maybe u know whats ups? Using profile_with_tracy doesnt seem to change anything.

old trail
untold wharf
old trail
#

Yeah profiling builds are much slower

old trail
#

oh nice result flattening is now stable in rust

untold wharf
old trail
#

try running with RUST_LOG=your_crate=trace,bevy_mod_scripting_core=error,bevy_mod_scripting_bindings=error

untold wharf
#

looks like it did nothing

old trail
#

how about RUST_LOG=none,your_crate=trace

untold wharf
#

your_crate should be the name of my crate, right?

#

I do see warnings getting printed, so maybe its not applying somehow

old trail
#

it might also be off instead of none

untold wharf
#

off in the ENV didnt work

but setting the LogPLugin worked:

.set(bevy::log::LogPlugin {
    filter: "error".to_owned(),
    level: bevy::log::Level::ERROR,
    custom_layer: |_| None,
})
#

Thats kinda weird tho, cus before it was not spamming logs as f ar as i could see. Were there logs that were invisble but still taking up cpu time somehow?

old trail
#

it's the trace logs, they're not visible in console, but they do get sent over the wire to tracy

untold wharf
old trail
#

You'll want to enable the crates you want to investigate, but it will slow everything down, I'd start by adding profiling scopes where you suspect things are slow, then drill down into those areas enabling scopes selectively if full profiling is slow

untold wharf
#

unless ur talking about the error levels

old trail
#

Like example::test::module::submodule=trace

untold wharf
old trail
untold wharf
old trail
#

sneak peek

untold wharf
# old trail sneak peek

Thats pretty cool! How easy is it to get this to work with our own APIs? So when we use NamespaceBuilder to register functions or when we use the script bindings macro in structs

old trail
#

really easilly, it will just work

untold wharf
old trail
#

yup those too get to declaration files

untold wharf
old trail
#

Yeah, if you use the script bindings macro all comments get auto yoinked into docs, on the namespace builder you add them manually, but yeah

rare badge
#

as someone who is worse than an 8 y/o on roblox at programming lua i am very excited for this

untold wharf
# old trail Yeah, if you use the script bindings macro all comments get auto yoinked into do...

Thats pretty cool! And i bet there will be a way to improve the namespace builder to include comments in the same way. For example, currently i could just make a struct that has my API, and simply registering it with bevy makes it available with the script bindings macro. The only difference is not having access to the world, which might be addressable with let world = ThreadWorldContainer.try_get_world().unwrap();. I did a quick test and it seems to work? Either way, I think we're pretty close to a good solution there.

old trail
untold wharf
# old trail The macro uses the builder underneath, so everything possible via the macro shou...

I see. I guess what I had in mind is "Namespace via structs". That way we get the comments for free but still somehow maintain the same experience. Something like how Ref and Mut work, for example. I believe ur doing some kind of dependency injection there? Idk how that magic works lol, but it would be cool if u could make this an injectable parameter: ctx: FunctionCallContext as well. With that, i dont see myself needing to use the Namespace builder directly. it would just be ApiName.function() on the lua side. And we would only need it for associated functions, if doing it with methods (functions with self) makes it tricky, then we can ignore that case.

vast dock
old trail
#

If so its already possible, and all the macro is doing is passing stuff into the same builder

#

The injection happens via traits

untold wharf
old trail
vast dock
#

I'll be able to go back to things soon, I'll be looking forward to that!

untold wharf
untold wharf
#

@old trail so about a week ago i noticed that some things stopped being logged (i.e things are crashing silently), like when theres an internal issue when i use world.get_component or construct. Im not using any log custom log filters (and other warnings and errors do show up anyway, so its a specific kind of error)

#

An example of an error that does this: using construct and providing a field that doesnt exist. Completely silent error.

old trail
old trail
untold wharf
# old trail Won't the field just get ignored ?

Id love to debug it, but i need the errors first haha. For example this doesnt work construct(types.Node, {}) and i figured just the defaults would be used, but i guess not. Dunno why.

This doesnt work either (cus _1 doesnt work anymore). The error there might be because it was missing a required field, again idk cus its silently failing lol.

local projection = construct(types.Projection, {
    variant = "Orthographic",
    _1 = ortho_proj
})
old trail
#

_1 still works just without the underscore

untold wharf
old trail
#

Why do you think it's failing?

#

I am pretty sure the function will just ignore things not on the type

untold wharf
old trail
#

Strange, errors are definitely propagated to the function call and logged from there

untold wharf
old trail
#

I think should send an error event

#

Actually nvm

#

It does later

untold wharf
#

I just put a print statement there and it didnt go off. From what i can tell, im getting to that block but that condition is never met

untold wharf
#

Wait a min, is this in regards to script loading? In my case im talking about callbacks. Not entirely sure if this ScriptMachine business deals with that.

amber glen
#

Any examples/pointers on how I can do something like the below (global function, not using the standard NamespaceBuilder, with world access)?

context.globals()
    .set(
        "func",
        LuaScriptValue::from(ScriptValue::Function(|key: String, value: ScriptValue| {
            let world = ...
        })),
    )
untold wharf
amber glen
untold wharf
#

FYI: This works but the docs dont really cover it:

construct(types.LineHeight, {
    variant = "RelativeToFont",
    ["1"] = 1
})
old trail
untold wharf
old trail
#

This is on main

#

The pr is not merged yet

untold wharf
untold wharf
#

@old trail so uh, finally got around to actually trying the 0.17 branch but im getting a "unresolved import bevy_mod_scripting_bindings::function::glue
could not find glue in function" for the safe_transmute function.

urban talon
#

I'm writing a Nano-9 plugin nano9_ink to access inkle stories from Lua. Here's a toot that demos it. But I realize it actually has no requirement for Nano-9. It's actually just a BMS plugin. So I'm thinking maybe I ought to rename this project to bms_ink. Thoughts?

GitHub

A Pico-8 compatibility layer for Bevy. Contribute to shanecelis/nano-9 development by creating an account on GitHub.

Have you ever wanted to Inkle in Pico-8? #pico8 #inkle

▶ Play video
untold wharf
urban talon
finite spoke
#

is it possible to use bevy_mod_scripting in a shared library? i'm building my game's simulation as an mlua module that's loaded by a larger lua program.

#

it would be nice to have bevy_mod_scripting ease the communication between the two

untold wharf
urban talon
old trail
old trail
untold wharf
untold wharf
# old trail Oh did you pin the commit?

I just realized the reason why u asked. I didnt read the PR 😅 but on 42d87a0 im getting "failed to resolve: could not find glam in the list of imported crates" in like 133 places

untold wharf
#

i refactored it to use the bevy_math type as a temp fix.

old trail
#

Hmm I managed to compile it with this setup:

bevy = "0.17"
bevy_mod_scripting = { git = "https://github.com/makspll/bevy_mod_scripting/", rev = "d9501a0", features = [
    "lua54",
] }
#

I think I mentioned one commit later than I meant in the PR but this one seems to work

untold wharf
#

oh i can try it in a min

#

Yeah, that works for me without the temp fix. Thanks 👍

#

uhh, im getting a runtime error that I didnt get before, tho

Error in dynamic script system `my_system`: WithContext(
    stack traceback:
        [C]: in function '__index'
        [string "/home/peepo/rust/bevy/bevy_mod_scripting/crat..."]:45: in function <[string "/home/peepo/rust/bevy/bevy_mod_scripting/crat..."]:28>,
    ReflectionPathError {
        error: Cannot reflect into tuple truct of type: bevy_transform::components::global_transform::GlobalTransform with string key: `["translation"]`,
        reflected: Some(
            ReflectReference {
                base: ReflectBaseType {
                    type_id: TypeId(
                        "bevy_transform::components::global_transform::GlobalTransform",
                    ),
                    base_id: Component(
                        105v0,
                        ComponentId(
                            Unregistered ComponentId - ComponentId(97),
                        ),
                    ),
                },
                reflect_path: ReferencePath {
                    one_indexed: true,
                    path: [
                        StringAccess(
                            translation,
                        ),
                    ],
                },
            },
        ),
    },
)
#

thats from calling :translation() on a : GlobalTransform(Affine3A { matrix3: Mat3A { x_axis: Vec3A { x: 0.6, y: 0.0, z: 0.0 }, y_axis: Vec3A { x: 0.0, y: 0.6, z: 0.0 }, z_axis: Vec3A { x: 0.0, y: 0.0, z: 0.6 } }, translation: Vec3A { x: -76.4, y: -415.0, z: 1.0 } })

old trail
#

Oh that's because that method seems to be missing

#

it's probably because I now filter out types which don't have public import paths, gonna try something

#

ohh right yeah I did fix that in 42d87a0 but prolly included something else

untold wharf
#

yeah thats what i figured

old trail
#

aight I've split out some of the fixes I've made in later commits from my holiday stash I was working on, c18ae77 should get you there I can see the 'translation' function there and it's building for me

#

Unfortunately I can't merge until I fix tests, which requires improved bindings which requires quite a big step up in how we codegen, on the plus side once that's done that's gonna get much more comprehensive

#

Also, hope ur doing ok man. Its been a hot min 🙂
I am doing great thanks! The codegen work is a bit involved and slowing down towards the holidays 😄

urban talon
#

Hey @Gedes, just wanted to let you know you got a new alpha tester for your BMS branch "feat/bevy-0.17-part-2": I updated Nano-9 to Bevy 0.17 tonight using your branch and so far things seem to be working fine.

old trail
#

nice! That's good to know, FYI that branch is definitely WIP (on the bindings side things will be moving around), I will be trying to merge the first part today though as I see bevy 0.18 is round the corner (things are moving fast haha!)

untold wharf
urban talon
untold wharf
#

@old trail Once again i gotta thank you for your hard work on this project. Really means a lot!

urban talon
#

I finally got bevy_minibuffer updated for Bevy 0.17. Just in time for Bevy 0.18, which is around the corner. Maybe when BMS 0.15 is ready, maybe Nano-9 will be ready for a real 0.1.0 release. We're just late bloomers.

GitHub

A gamedev console inspired by classic Unix text editors - shanecelis/bevy_minibuffer

GitHub

A Pico-8 compatibility layer for Bevy. Contribute to shanecelis/nano-9 development by creating an account on GitHub.

untold wharf
#

I think migrating BMS to 0.18 will be ez.

vast dock
old trail
#

Alrighty, I am finally gonna write those release notes and announce the work so far and start cracking on bevy 0.18

old trail
#

Damn I forgot how much good stuff was added last few months

brave garden
#

@old trail I don't think this really affects me (I'm just curious) but why is BMS rust toolchain only on Rust 1.89?

old trail
#

Its the minimum bump needed to make 0.18 bevy work, larger bumps may entail updating the nightly version used in codegen which will mean following internal compiler changes in our compiler plugin. Avoiding that means a much quicker bump.

It should build fine with higher toolchain versions anyway

untold wharf
#

Can confirm, i been using nightly the entire time i been using BMS 🙂

brave garden
#

@old trail upgrading to Bevy 0.18 (and BMS 0.19 via main/7401da44), it looks like the following error could be related/caused by BMS. I don't have a repro, but just wondered if anything stands out on BMS side? #ecs message

Attempted to update the location of a despawned entity, which is impossible. This was the result of performing an operation on this EntityWorldMut that queued a despawn command

old trail
#

Hmm, i wonder if it is to do with entity index 0

#

Is it now a legal index?

brave garden
vast dock
#

@old trail your update logs in the book are a godsend, it's making me less scared of moving from 0.15.1 to 0.19

rugged spoke
#
fn message_spawn(
    mut reader: MessageReader<OnSpawn>,
    mut writer: MessageWriter<ScriptCallbackEvent>,
    query: Query<&ScriptComponent, With<Enemy>>,
) {
    for message in reader.read() {
        let script = query.get(message.entity).unwrap().0.first().unwrap();
        println!("Sending message for ID: {}", message.entity.index_u32());
        writer.write(ScriptCallbackEvent::new(
            UnitSpawn,
            vec![
                ScriptValue::Integer(message.entity.index_u32() as i64),
            ],
            Recipients::ScriptEntity(script.clone(), message.entity),
            Some(Language::Lua)
        ));
    }
}

Would this be an "idiomatic" way to fire an event to a specific entity's script component? I am firing a message whenever a unit is spawned and acting on that message in a few places, one of these is executing a script's method

vast dock
#

Going up to bevy 0.16->0.18 was quite smooth except me being silly. Thank you again for the good documentation and all...

solar juniper
#

am i able to access the Time resource from a script?
this is giving an error:

local MovementAcceleration = world.get_type_by_name("MovementAcceleration")
local LinearVelocity = world.get_type_by_name("LinearVelocity")
local Time = world.get_type_by_name("Time")

function on_movement_action(action)
    local variant_name = action:variant_name()

    print(variant_name)
    
    if variant_name == "Move" then
        local move_dir = action[1]

        local acceleration = world.get_component(entity, MovementAcceleration)[1]
        local velocity = world.get_component(entity, LinearVelocity)[1]

        local delta_time = world.get_resource(Time):delta_secs()

        velocity.x = move_dir.x * acceleration * delta_time
        velocity.y = move_dir.y * acceleration * delta_time
    end
end

and i registered the type.

Error:

Error in language: Lua, in script: scripts/player.lua, at line: 17
 in function get_resource on Namespace for type World:
 Error converting argument 1: Value type mismatch: expected bevy_mod_scripting_bindings::query::ScriptResourceRegistration, got ()
Context:
stack traceback:
        [C]: in field 'get_resource'
        [string "/home/storm/.cargo/registry/src/index.crates...."]:17: in function 'on_movement_action'
callback: on_movement_action
args: [Move(Vec2 { x: 1.0, y: 0.0 })]
Language: Lua
solar juniper
#

^ still curious if i can, but i just did it a different way where i passed delta_secs as an argument.

molten pine
#

Hello! I've been doing some experimenting with BMS lately and I was wondering if there was an API for inserting resources from a script? I though the world global would have insert_resource but it seems not.

pale fern
solar juniper
pale fern
#

Oop, forgot the closing >

solar juniper
#

hmm oki ill try that

solar juniper
old trail
old trail
old trail
solar juniper
# old trail

ty i did have confusion because delta_secs wasn't a method

olive drift
#

with BMS systems that use queries, is there an equivalent for .get() yet? To get the components corresponding to a given entity without doing a linear scan on everything the query picked up

olive drift
#

Also have some other questions:

  • While testing script systems I ran into multiple different ways to crash the game, is this also an issue when not using systems?
  • Is there a way to prevent callbacks from running for an entity that has already despawned?
  • Are there any better ways to attach scripts to entities from the scripting side? Systems would be convenient since they can automatically pick up entities by their components, but is there a way to e.g. "extend" a given component with a script?
solar juniper
olive drift
#

I definitely had an instance where an entity had already despawned when its callback hit; it caused the script to throw an error trying to access its components

old trail
#

In fact this might work (it compiles) in a binding of your own, to be used like world:query():component(ComponentA):query_get(MyEntity)


#[script_bindings(name = "query_functions", remote)]
impl ScriptQueryBuilder {
    pub fn query_get(
        ctxt: FunctionCallContext,
        query: Val<ScriptQueryBuilder>,
        entity: Val<Entity>,
    ) -> Result<Val<ScriptQueryResult>, InteropError> {
        let world = ctxt.world()?;
        let query = query.into_inner();

        let result: Val<ScriptQueryResult> = world
            .with_global_access(|world| {
                let mut built_query = query.as_query_state::<EntityRef>(world);
                let query_result = built_query
                    .get(world, entity.into_inner())
                    .map_err(InteropError::external)?;

                let references: Vec<ReflectReference> = query
                    .components
                    .iter()
                    .map(|c| {
                        ReflectReference::new_component_ref_by_id(
                            query_result.id(),
                            c.component_id(),
                            c.type_registration().type_id(),
                        )
                    })
                    .collect();

                Ok(Val(ScriptQueryResult {
                    entity: query_result.id(),
                    components: references,
                }))
            })
            .flatten()?;

        Ok(result)
    }
}
old trail
#

Is there a way to prevent callbacks from running for an entity that has already despawned?
Callbacks only run on "loaded" and "active" "attached" contexts within the framework, and since despawning an entity triggers an "unload", callbacks should not trigger on these. We have a bunch of lifecycle tests that verify this here: https://github.com/makspll/bevy_mod_scripting/blob/1391f0d0615a89f391ea55e7b168a6288168e8dd/assets/tests/lifecycle/default/entity_script/loading/scenario.txt, I wonder if maybe this is due to unloading now potentially taking more than one frame to complete, see: https://makspll.github.io/bevy_mod_scripting/ScriptPipeline/pipeline.html#timing--order. Would be keen to hear how you managed to see those errors!

vast dock
#

I might need to use that !

old trail
#

Are there any better ways to attach scripts to entities from the scripting side? Systems would be convenient since they can automatically pick up entities by their components, but is there a way to e.g. "extend" a given component with a script?
You can create ScriptAttachment 's via scripts directly https://makspll.github.io/bevy_mod_scripting/core_bindings/types/scriptattachment.html, and you can create references to script assets via ReflectReference

So given bindings that load and give you the handle to a script asset, you can directly add a ScriptComponent to an entity as normal

old trail
#

FYI, I am currently in the middle of writing an open source game that will use BMS as both:

  • a large example
  • a tech demo
  • a way for me to gain some perspective and pick the right way forward in improving the framework
  • actually figure out the idiomatic patterns in bevy
vast dock
#

Is it public yet?

old trail
vast dock
#

I'll take a look at it.

#

I am also in the middle of doing some sort of tech demo which I plan to be open source once once I get it where I want.

#

I would be happy to use it as an example too if needed.

old trail
#

That would be amazing, I think BMS is fairly hard to grasp at the beginning so the more real examples the better!

vast dock
#

Although I use BMS to interact with rust compiled game logic, not for entity attached scripting.

#

I do have a save setup that saves lua data.

#

which might be interesting for people.

#

(as in my whole scenario state)

old trail
#

Yeah even better!

vast dock
#

I can give you access to that in private if you so wish to take a look at it.

old trail
#

Sure, can't hurt!

vast dock
#

(sent a dm)

vast dock
old trail
#

Mostly since rapier seems more established and it had a ready to go character controller, didn't give it too much thought

vast dock
#

Makes sense!

#

I went for Avian because it had a lightyear integration example at the time

olive drift
solar juniper
molten pine
untold wharf
molten pine
#

Hmm I suspect there's something that I'm not understanding properly.
Let's say I have

#[derive(Reflect, Default, GetTypeDypendencies)]
struct MyStruct {
  pub foo: String,
  pub bar: Option<String>
}
construct(types.MyStruct, { foo = "Foo" } -- External error: field missing and no default provided: 'bar'
construct(types.MyStruct, { foo = "Foo", bar = nil } -- External error: field missing and no default provided: 'bar'
construct(types.MyStruct, { foo = "Foo", bar = "Bar" } -- Works

I've even tried

construct(types.MyStruct, { foo = "Foo", bar = construct(types.Option, { variant = "None" })

but that doesn't work either.

I'm afraid I don't quite understand where ReflectDefault comes into play?

untold wharf
#

I believe you have to use #[reflect(Default)], i.e i found from an example:

#[derive(Debug, Default, Clone, Reflect, Component)]
#[reflect(Component, Default)]
pub struct LifeState {
    pub cells: Vec<u8>,
}
#

Yours doesnt seem to be a Component so ignore that part. U just need Default.

molten pine
#

Doesn't work either. Seems to boil down to this issue by @old trail about a year ago https://github.com/bevyengine/bevy/issues/18018. I guess I'll just bypass this for the time being. Thanks a lot for your help @untold wharf !

GitHub

A refreshingly simple data-driven game engine built in Rust - bevyengine/bevy

old trail
#

You can manually register the type if it doesnt have a default type data btw

urban talon
#

There's a new Lua implementation in pure Rust rilua, and I mentioned how we'd all like to be able to use bevy_mod_scripting with wasm, and how it seemed like his project might help facilitate that. Well, not only is he agreeable but he may do some of the integration work himself, which would be swell. So maybe we'll see a PR in the near future.

-# ↩ Daniel S. Reichenbach
@danielsreichenbach Well, my aim would be to get it supported by bevy_mod_scripting, which is what I use in Nano-9. I really want Nano-9 games to be able to run in wasm so that it has closer feature parity to Pico-8.

github.com/makspll/bevy_mod_sc…

github.com/shanecelis/nano-9

vast dock
#

He has his lua lib working in WASM today.

old trail
#

Looks very cool! Would be curious how the benchmarks look, but if we have a wasm lua runtime we can run tests as examples in the book which is cool

vast dock
#

Hadn't thought about that! That would be dope !

late idol
late idol
urban talon
#

Welcome! We're excited to see what you've been working on.

late idol
old trail
olive drift
#

neat!

old trail
vast dock
#

So that would mean luau as well right ?

old trail
#

From what i remember it would be lua53 or one of those

old trail
#

I am trying to wrap my head around potential usage paterns around async callbacks,

How do people think they should work?

Lets say we have a callback async fn do_time_consuming_thing,
It is triggered by a one off event and script begins executing it over many frames.

Id be surprised if that allowed us to execute any other callbacks for the duration of the processing, since this future will be referencing the script context, or at least a part of it. So the whole context would be out of action for a few frames and not receive any other callbacks ( and if its possible to drive multiple parallel callbacks against one context, would you want this allowed ? Sounds messy )

Does that sound useful? Would we want to allow core (on script loaded etc) callbacks be executed asynchronously too?

I am kind of mostly imagining async callbacks as a way to smooth out the framerate when bigger processing is happening within scripts / sandboxing somewhat

vast dock
#

In my case I was having frozen frames because of silly inneficient Rejection Sampling Method for random positions in a circle.

#

I would have potentially use for it for functions that create things as a one off.

However for fixed updated stuff I probably don't want it to spill over. Or at least I'd want a warning when that happens.

#

Maybe I'd want it to be used for macro ai stuff like managing a whole faction ?

But it would likely require the compatibility with fixed update in some sort of dual thread like thing ?

#

Perhaps the way to do it is to run the function as a lua coroutine ?

vast dock
#

That way if the user knows their function is going to take a while they can yield when needed.

late idol
late idol
#

I hope it will be useful. Its gonna be updated every time I publish a new release.

vast dock
#

Although i've stuck muself to using luau for types and won't be able to use it xD

late idol
vast dock
urban talon
old trail
#

Oh I guess the difference is they use generics whereas we need to use ComponentID at runtime etc

old trail
# urban talon Oof, async is a tricky thing to absorb. I'd suggest looking at [bevy_defer](http...

One thing I am considering is the "async" within our context could be limited to the handler lifecycle, i.e. instead of thinking about spawning a background thread, instead we're "alotting dedicated time" for coroutines within the handler, essentially splitting the execution of a callback across multiple frames, but always with exclusive world access and in the same point in the schedule

#

or maybe even just allowing the initial load of a script to be async (as that already happens in a multi-frame context)

#

although I can see how having the world change in between yield points could be very confusing

#

but I think I agree, the more I am thinking about the ergonomics and amount of possible surprises, the more I think it's perhaps best to force people to implement their own async abstractions and script API's into those, while expecting callbacks to be cpu bound

urban talon
#

I have exactly one async-y API from Pico-8 that I may or may not implement in Nano-9, and that's flip(). In Pico-8 it flips the frame buffers so that you can write a tight loop in Lua without having to always be called via _draw(). In Nano-9 to implement it, I believe I'd have to do my Lua calls within a coroutine and have flip() call yield unless there is some other way to suspend Lua's execution that I don't know about from the runtime. It's doable with coroutines but it complicates everything if I want to support it in general.

old trail
#

made an extension for writing bms integration tests!

vast dock
#

I also need to export all my typing too...

#

Is there documentation about those DSL .scenario files?

old trail
#

they're currently only used internally, but I plan on making them usable by external crates + extensible too, so not many docs atm

vast dock
#

If there are angles where I can contribute for docs and such I would be happy to

old trail
#

Developing BMS docs on how these work could be useful to help contributors

#

ATM I am looking at making ScriptValue::Tuple or more first-class multiple value returns

vast dock
molten pine
old trail
#

I think its a case of:

type_registry.register_type_data::<Option<Vec2>,ReflectDefault>()

Cant remember the exact syntac

molten pine
#

Oh right @old trail and @vast dock now I remember! I did get it working as Gedes described, you have to manually register Option<ForceMoveAi>’s ReflectDefault.

vast dock
#

Oki I'll look at it

#

Thank you !

old trail
old trail
vast dock
#

Is that a way to trigger events using reflection and therefore in lua?

old trail
#

Yup

vast dock
#

👀 That an interesting find indeed!

vast dock
#

@old trail do you have a mechanism setup for lua code coverage in BMS?

old trail
vast dock
#

Yeah I saw that!

#

I am currently setting up code coverage for my project.

#

Hence me working on it.

#

I will need to work on how to run test on lua mod/plugins in the context of what i'm doing.

#

But that is a problem for later me, the rust codebase is a start.

old trail
#

I see

#

yeah lua tests are gonna be interesting

vast dock
#

I am planning on trying to create mods in a similar way to factorio.

I am assuming they did their work right and I would like to try and include tests within mod folders.

#

But I have a lot of work to do to learn their dev environment.

amber glen
#

Hey, I want to override the require method for a Lua context. tl;dr: load script from a specific directory depending on which Lua context is running a script. I'm currently doing this in Lua by overloading the require function and adding the static paths to the requested file, but I want to define this function in rust. Is this possible?

old trail
#

I dont see why you wouldnt be able to do that in mlua, youd be able to hook into the lua context in a context initializer or in a loading pipeline transition listener. Youd probably want to retrieve the original require function and then override it before calling it inside the override

#

Unless mlua has a denylist on function names

amber glen
#

Thanks! I'm running untrusted lua code, I don't want to allow them to override my lua definition/guards.

vestal trench
#

Hey! I see you've already been discussing how to make async work. I'm currently exploring something that would greatly benefit from async scripts as well and thought I'd give some input.

What I'm trying to do is implement procedural generation through scripts. Expectedly this isn't particularly fast, so running these scripts freezes the program, which is not acceptable in a game.
This particular task happens to have one major advantage: it doesn't really need access to the world at all. If I were to implement this directly in Rust I'd simply spawn a task in the compute pool, and then perform all of the world updates once the result is ready.
I'm basically looking for a solution to do pretty much exactly that but with a script. If the script doesn't get access to the world (and instead only, say, a CommandQueue) it should be much easier to execute it asynchronously.

old trail
#

That's a useful perspective @vestal trench!

#

async commands is something that might be introduced into bevy natively as well

#

perhaps scripts lifetimed entirely to an async task could be the way to go

vestal trench
#

There are certainly pros and cons, I just threw this out because it happens to match a specific use case I have, though I might say this use case could be common in games.
You can sort of implement async commands by using the CommandQueue type, requires polling the task and applying it manually tho. You could potentially hide this away inside the crate, in the same system that generates the script result events for example, but it's not a terrible amount of code to write yourself anyway.

vast dock
vestal trench
#

Like most scripting it's a tradeoff between speed and flexibility.
Think about a game like Age of Empires for example. There are many different kinds of map presets available. Using scripts greatly simplifies creating and distributing more of them, both by devs and by users.

#

I'd probably only consider this for games where the generation is hidden behind a loading screen. If you need to generate large amounts of terrain on the fly like say Minecraft then scripting would probably be too slow.

vast dock
#

Makes sense !

ornate pond
#

trying to add a system from script, don't really know what is happening here

Error in language: Lua, in script: scripts/main.lua, at line: 11
 in function add_system on Namespace for type World:
 Invariant broken: After adding the system, it was not found in the schedule, could not return a reference to it
Context:
stack traceback:
        [C]: in field 'add_system'
        [string "~/.local/share/cargo/registry/src/ind..."]:11: in main chunk
Language: Lua
#

main.lua is simply

local startup_schedule = world.get_schedule_by_name("Startup")
local script_attachment = ScriptAttachment.new_entity_script(entity, script_asset)
local startup_system = system_builder("startup", script_attachment)
-- fails here:
local added_system = world.add_system(
    startup_schedule,
    startup_system
)

function startup()
    print("startup system ran")
end
#

I can print the first 3 things and see

ReflectSchedule { type_path: "bevy_app::main_schedule::Startup", label: Reflect(bevy_system_reflection::ReflectableScheduleLabel) }

EntityScript(17v0, Strong(Reflect(bevy_platform::sync::Arc<bevy_asset::handle::StrongHandle>)))

Reflect(bevy_mod_scripting_core::script_system::ScriptSystemBuilder)
old trail
#

Try adding the system in a callback

#

Not directly in the script body

#

Not sure why that ugly error is hitting though

ornate pond
#

I moved it to on_script_loaded, same error unfortunately

#

I'm copying script loading code from one of the examples, maybe I picked an incompatible one?

#
use bevy::prelude::*;
use bevy_mod_scripting::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugins(BMSPlugin)
        .add_systems(
            Startup,
            move |asset_server: Res<AssetServer>, mut commands: Commands| {
                let script = asset_server.load::<ScriptAsset>("scripts/main.lua");
                commands.spawn(ScriptComponent(vec![script]));
            },
        )
        .run();
}
#

or maybe adapted incorrectly?

#

oh no access to the entity in on_script_loaded

old trail
#

hmm so this test is passing for me on main:

function on_script_loaded()
  local post_update_schedule = world.get_schedule_by_name("PostUpdate")

  local test_system = post_update_schedule:get_system_by_name("on_test_post_update")

  local script_attachment = ScriptAttachment.new_entity_script(entity, script_asset)

  local system_a = world.add_system(
    post_update_schedule,
    system_builder("custom_system_a", script_attachment)
    :after(test_system)
  )

  local system_b = world.add_system(
    post_update_schedule,
    system_builder("custom_system_b", script_attachment)
    :after(test_system)
  )

  -- generate a schedule graph and verify it's what we expect
  local dot_graph = post_update_schedule:render_dot()

  local expected_dot_graph = [[
digraph {
-- schedule assertion ...
}
    ]]
  assert_str_eq(dot_graph, expected_dot_graph, "Expected the schedule graph to match the expected graph")
end
#

statements in the top level of the script may be called at unexpected times

#

maybe they get called twice and the system already exists or something

#

ok funnily enough it also works for me at the top level

#

and even if i register the same system twice it doesn't error

#

weird

ornate pond
old trail
#

yeah, and even running the same exact code works for me:

#

platform difference ? 🤔

ornate pond
#

I tried to recompile the packages without cranelift (as recommended in Getting Started)

#

no luck

#

changing cargo settings is a 51 years type little maneuver xD

ornate pond
#

is this relevant at all? I added tracing around the part that errors and it seems a "reached final state" trace happens after my script has failed to add a system?

2026-03-31T23:59:02.040427Z DEBUG bevy_mod_scripting_core::script_system: Adding script system 'startup' for script 'EntityScript(entity: 25v0, script: path scripts/main.lua)' to schedule 'Startup'
2026-03-31T23:59:02.040548Z DEBUG bevy_mod_scripting_core::script_system: (MY LOG) Attempted to add script system "startup" to schedule Startup
2026-03-31T23:59:02.040882Z DEBUG bevy_mod_scripting_core::script_system: (MY LOG) Now find the system:
2026-03-31T23:59:02.041262Z TRACE bevy_mod_scripting_core::pipeline::machines: Reached final state 'bevy_mod_scripting_core::pipeline::machines::LoadingCompleted'. For script EntityScript(entity: 25v0, script: path scripts/main.lua)
2026-03-31T23:59:02.083974Z ERROR bevy_mod_scripting_core::handler: Error in script: 'path scripts/main.lua' :