#bevy_trenchbroom
1 messages Β· Page 2 of 1
Oh, I can't do that anyways, since then the avian collider constructors on those props fail. Nvm, I'll have to set the render asset usage manually at OnRemove, ColliderConstructorHierarchy
(and at SceneCollidersReady, thanks for that trigger!)
@dim warren I think i got the new rotation fix working, feel free to try the correct-coordinate-conversion branch at your earliest convenience
I'll check it out in a few hours π
I'll probably also make a little crate like bevy_fix_gltf_coordinate_system that does this for all glTFs
TB:
The branch:
main:
Dang, can you send me the chair model, so i can test it in mine?
Though the actual thing spawned in-engine is this
I didn't check the world rotation, in case you touched that. Could be that the chair is oriented correctly, but the world itself is rotated
Update: checked the world rotation, and your branch has it correct
(based on how my camera spawns)
Since this is rotated by 180 deg, this should be correct when using a global glTF coordinate fixer
It's working fine in my testing environment, perhaps it is an application problem, do you have a world inspector you can look at? The map scene should have a FixGltfRotationsUnderMe component, and the chair's X and Z scales should be negative
Is bevy_inspector_egui on 0.16?
Yes (0.31)
cool, sec
sorry I took a while, ready now
the level has it
All good
And here is the transform of the chair
That looks to me like TAU / 12
so uuuhm
360 / 12 = ??
30
about a 30 degree rotation
In the editor, it has a yaw of 150 degrees
I think think we need to be looking at rotation since my code doesn't touch it, only scale
Which is indeed not negative
yep
by scale, you mean the world's coordinate system?
oh wait
no, I got it
fn fix_gltf_scenes(
mut events: EventReader<DeferredGltfRotationFix>,
mut commands: Commands,
mut scene_root_query: Query<(&mut Transform, &SceneRoot)>,
ancestor_query: Query<&ChildOf>,
rotation_fix_query: Query<(), With<FixGltfRotationsUnderMe>>,
do_not_fix_query: Query<(), With<DoNotFixGltfRotationsUnderMe>>,
) {
for DeferredGltfRotationFix(entity) in events.read() {
let entity = *entity;
let Ok((mut transform, scene_root)) = scene_root_query.get_mut(entity) else { return };
let Some(path) = scene_root.0.path() else { return };
let Some(ext) = path.path().extension().and_then(std::ffi::OsStr::to_str) else { return };
match ext {
"map" | "bsp" => {
if !do_not_fix_query.contains(entity) {
commands.entity(entity).insert(FixGltfRotationsUnderMe);
}
}
"glb" | "gltf" => {
for entity in ancestor_query.iter_ancestors(entity) {
if rotation_fix_query.contains(entity) {
if transform.scale.x.is_sign_positive() {
transform.scale.x = -transform.scale.x;
}
if transform.scale.z.is_sign_positive() {
transform.scale.z = -transform.scale.z;
}
break;
}
}
}
_ => {}
}
}
}
Here's the full system for convenience
Neither the chair scene root nor the mesh itself has a negative scale on my end
btw, I would avoid that
Some third party crates really really don't like negative scales
IME rotation is much safer
Well that sucks
Any crates in particular?
Whew, don't remember
I mean we can use scale until any problems come up and still switch, no biggie
But anything that works assuming isometries is affected
The only thing i can think of is that somehow the prop scenes are being added before the map scsne, but that doesn't make any sense
I preload them
Dunno if that affects it
It looks for Trigger<OnAdd, SceneRoot> so i doubt it
Actually, i can probably just clone the repo and debug this myself, right?
Can you send a link and branch?
Sec
It's on main now
@dim warren I fixed it, may have worked a little too well, the fox is now following me backwards
Also the lantern is not able to be picked up, not sure if that is caused by this though
hehehehe
Oh yeah the mesh is being made RENDER_WORLD-only a bit too eager
@urban zealot this error is due to the CI cache being suboptimal. I can fix it for you later π
That'd be quite nice of you :)
Just updated to BTB main and the backwards walking fox is quite funny π
there you go: https://github.com/Noxmore/bevy_trenchbroom/pull/88
just delete the CI caches before merging
that's done here ^
just click on the trash icon for all caches
no, GitHub does not have a button to select all at once 
Thanks a bunch!
heheheehe
For context here is the red hallway now
Aww, thank you!
btw, I'm now trying to cram all of the weird texture hacks I had to do into one python file that you may be also interested in. It should do the following:
- move all textures so that
qbsp(the tool, not the crate) can deal with them- change the
.mapfile accordingly
- change the
- generate mipmaped ktx2 files for all map textures
- change the material files to point to the new textures
- generate mipmaped ktx2 files for all glTF textures
- change the glTFs to point to the new textures
- run
qbsbandlight- delete the
.mapfile and intermediate compilation products
- delete the
The idea is to do that in the CI release step so that a user doesn't need to care about it
But they could still run it locally if they want
And that would produce an assets_new directory that contains the baked assets
That way, users don't need to deal with the weird Quake 1 restrictions for bsp generation
I don't know how powerful Bevy's asset pre-processing currently is as i haven't used it, do you know if it could be used for any/all of these steps?
It should be able to do all of those
But every time I ever asked anyone to explain to me how asset pre-processing works, I got shrugged shoulders
I have no clue how any of that works, so I tried the basic built-in KTX2 converter
And that one cannot read any PNGs for some reason
Looked around and apparently that's just broken since an unknown amount of time
I want to look into it sometime, would be cool to have my bsp compile for me when i load up the game
If you find out how to do that, please please teach me
Feel free to just take my python code that I'm writing right now for the logic of that
Especially the part about moving the textures around
and truncating the names
that's not something any user should ever have to deal with haha
Making custom Quake levels with custom textures in the past i'm pretty used to it, but thank you
Oh yeah good point, this is probably not new to a lot of people π
@urban zealot @gloomy fable done with the simple global glTF rotation fix: https://github.com/janhohenheim/bevy_fix_gltf_coordinate_system
Dang, that was fast
It's really small π
You may want to copy the logic to your fix thingy
OR
I could also add an opt-in mode
hmm nevermind, that wouldn't be nice for people consuming the crate
I also learned that in current Bevy, Assets<Gltf> is almost guaranteed to always be empty
that was unexpected
Yep, was unexpected to me too
You're welcome π
once the tests pass, I'll publish
@urban zealot could you ping me once BTB doesn't affect non-level glTFs anymore?
Then I can opt-out and just use my new crate globally
It currently already doesn't affect glTFs not under a level, unless i misunderstand what you are saying
why did the fox flip then?
I assume it was placed in-editor, and thus was a child of the level
oh wait, you're right π
I would like to probably switch to your crate at some point though
Have it be included in the PluginGroup by default
Just realized I had two from_rotation_y(PI) in my code that I completely forgot about
I think I just added them without much thoughts when I noticed things were flipped in-game
Well, now I know why π
Was able to remove them now 
@dim warren In the CI, why did you put --locked in the cargo test command?
Just wondering because
error: the lock file /home/runner/work/bevy_trenchbroom/bevy_trenchbroom/Cargo.lock needs to be updated but --locked was passed to prevent this
If you want to try to generate the lock file without accessing the network, remove the --locked flag and use --offline instead.
Best practice to make it reproducible and ensure that you and the CI are actually testing the same thing. Notice that I also sneakily added the lock file back in π
I would encourage you to commit the lock-file. I know some time ago the recommendation was to omit it for libraries, but the vibes have shifted in that regard
It's also way nicer when you are pointing to git dependencies on main, e.g. when updating to a new Bevy version and some stuff still needs manual patching
That way, you and I and the CI will all use the same commits of that git dependency
I wondered why that was there again!
@urban zealot I've encountered a weird phenomenon
This is my base.toml:
type = "StandardMaterial"
[material]
base_color_texture = "${name}/${name}.ktx2"
normal_map_texture = "${name}/${name}_normal.ktx2"
perceptual_roughness = 0.7
This is my blocks_uneven_b.toml:
inherits = "/textures/base.toml"
[material]
perceptual_roughness = 0.9
(sec, I accidentally yeeted my example)
here's the relevant file structure
looks fine in-game
Notice that I never reference the .png in my material files. So let's delete it and run the game again
oh no!
Let's walk veeeery close up to the wall:
aha, the texture is there, it's just incredibly small
Now, this could very well be an issue with how I generaty my .ktx2 files
But what I am wondering is why this is behaving differently whether or not I have a png?
Is it possible that bevy_materialize is somehow still loading that png? Note that I get no warnings whatsoever.
Update: welp, I upgraded to main and the spooky PNG having an effect is fixed
Also, the tiny tiny KTX textures are fixed when using the BSP instead of the .map
I don't know why any of this is the case, but I found my solution and I'm happy, as the .map build in my script uses PNGs instead of KTX anyways
Also, as luck would have it, I just ran into https://github.com/Noxmore/bevy_trenchbroom/commit/b8bd384650fe2f59c14afd9138ba9bd0d26fd939, which updating to main also fixed π
This is because to correctly generate brush UVs BTB needs to know the size of the texture
I would guess it's fixed on main because you have ktx2 as a specified texture extension
And this is because the compilation step scales UVs, so we don't need to
thanks, that makes sense π
Then I'm aaaalmost done with my asset preprocessing script: https://github.com/janhohenheim/foxtrot/blob/bake/scripts/bake_assets.py
You may get some use out of it too
it changes all textures to KTX2 with enabled mips, and then modifies the .map and all .gltf files to point to the new textures, makes all textures correctly follow the quake 1 map limitations, then compiles the BSPs
The idea is to then run this script in the release workflow automatically π
I'm not making any games at the moment, but i'll have a look if i do!
The only thing that's missing right now is that I need to convert PBR textures a bit differently
The resulting assets directory is 25% smaller than the original, that's pretty neat
But also more performant at the same time π₯
@urban zealot I assume you don't have an idea of how we could hack our way around the Bevy unwrap we're hitting, right? :/
In WASM builds?
yep
Not a clue
same
@urban zealot do we not support BSP on WebGL2 at all?
I know that I cannot use the light maps etc., but should I be able to load the geometry etc. from the BSP?
I'm asking because I'm getting
Failed to load asset 'maps/foxtrot/foxtrot.bsp' with asset loader 'bevy_trenchbroom::bsp::loader::BspLoader': Encountered HTTP status 403 when loading asset
on itch
You should, not sure why that's not working
huh, would you look at that, it works on my machine β’οΈ
mind checking out https://janhohenheim.itch.io/foxtrot?secret=kBHgd56pLNSzi846z6z3gej5K6k ?
I double checked, and the file definitely is there
it seems that both of those return this xml in the response
I thought for half a second that I was missing some request header, but the response body from these are the same in the console
I added some placeholder data that I found laying around my Quake files, let's see π
Update: that worked π @urban zealot can we make the absence those two files not crash the bsp loading?
Try it now
Took a while to remember how to manually upload stuff to itch, but yes, it works! Thank you so much! π
Now I can finally put my big big asset processing side-quest to rest, I'm quite happy with this π
Back to level design!
No problem! It was another case of forgetting that on wasm you get a 403 instead of a file not found error
It's a quirk of itch.io, actually
On regular old Wasm (bevy run web), it's a recoverable 404
Ooh, so that's why i couldn't reproduce it on my setup, i thought i was just doing something wrong
But itch turns all 404s into 403s
I also had to learn that the hard way π
Any reason the hashbrown feature is enabled for quake-util? That was intended for non-std (I had been using the data types when experimenting with non-WASI WASM modules; it's useless otherwise b/c the io::Read/Write traits aren't in non-std π’ ). I don't think it does much harm to use hashbrown w/ std, just curious.
And as a side-note, I was toying with the idea of replacing the hashmaps with Vec<pair>s. Pros: you can do "non-standard" things like duplicate keys, and the order of key/values is preserved; Cons: less ergonomic, needless breaking change if the pros aren't desired. Thoughts?
oh, and no progress on the Quake 2 surface flags, I'm in the throes of a Blue Prince addiction π
actually the hashmaps aren't very ergonomic to begin with b/c they use CString, and I need CString (for, as I call it, "Quake-encoded" strings) for parsing the entity lumps of BSPs
I don't know what @urban zealot's reasoning was, but Bevy in general is now trending towards supporting more and more no_std, so plugins going that same direction makes sense π
I don't know either, that was ages ago
I only read entity properties via an iterator so i don't mind either way
I have a conversion that seems to work well in my qbsp crate
@urban zealot how are we scaling the textures in BTB?
I'm having some troubles with normals, and either I completely messed up while importing my normals or BTB / bevy_materialize is doing something wonky
When I scale a texture in TB, I would expect BTB to use a uv_transform for the textures, but it doesn't
What do you mean by a uv_transform?
Sorry, I meant texture_transform
oh wait, that's glTF only anyways, nvm
(I should have known better, I implemented it π)
Anyways, how do we scale them?
I correct myself again: I was thinking of something else
A material with βstandardβ properties used in PBR lighting. Standard property values with pictures here: https://google.github.io/filament/Material Properties.pdf.
There, that one should affect all textures of that material
hmm, but that doesn't make sense, as the scale is per face, not per material
The UVs are scaled in the function generate_mesh_from_brush_polygons
Hmm that function makes total sense
Do you know a good way to check the normals I'm actually using in Bevy?
The vertex normals?
sorry, I'm bad at expressing my thoughts today π
The normal map
Nah, it could've meant either
reference (TheDarkMod)
You could just make the base_color_texture the normal map
Indeed
thanks to the base.toml material, that should be easy. sec
It should also be visible in bevy-inspector-egui
Looks like +Y is down, but i don't know too much about normal map formats, that's probably normal
This is it with a flipped Y:
The only thing i can think of that would silently cause normal maps to not work is if the mesh doesn't have any tangents, though i'm pretty sure BTB generates those
If you check bevy-inspector-egui it should tell you
Unfortunately it seems like the BTB generated meshes have no nice names
So I have these
You should be able to follow the Mesh3D
nope
Looking at the code though, i don't see where tangents are generated, i might have removed it accidentally in the .map loader rewrite
Dang, i'm 99% sure you used to be able to do that, maybe before they removed the Component impl from handles
Just to confirm, try generating tangents for all of those meshes and see if it fixes it
Is it possible to give them nice names?
no clue
clicking on "Generate Tangents" for all looks the same to me
But idk what the effects of that are when done at runtime
I'm currently neck-deep in implementing #89, so i'll re-add tangent generation in a bit
alright π
It's on Foxtrot's main if you want to reproduce it
FYI it's not looking better on BSP
Is it possible BTB or bevy_materialize are loading normal maps as rgba instead of linear?
@urban zealot could you point me to where the actual StandardMaterial is being put together? I have a good feeling about this hunch
With material files it's registered with ReflectGenericMaterialSubAsset
Oh wait i thought you were talking about the image, the material itself is put together in GenericMaterialLoader
Assets are inserted via AssetLoadingProcessor, which uses ReflectGenericMaterialSubAsset to load them, so that might be what you're looking for actually
This is really hard to think about 
I'm afraid I need a bit more guidance
I'm just trying to figure out where the normal map is loaded
because it needs to have is_srgb = false in its settings
Is that in ImageLoaderSettings?
yep
I don't see it anywhere
Also i thought color spaces were determined from the image file itself
API documentation for the Rust ImageLoaderSettings struct in crate bevy.
Oh i did a cargo update and it just appeared
dunno
heheh
But if it did load it as srgb, that would explain everything
IIRC every texture except the base color texture is expected to be linear
Hmm, how do we specify that on a per-field basis without a meta file for almost every image i wonder
For the StandardMaterial case, can't we just hardcode it?
We could but that's not very good design, bevy_materialize is like 70% about custom materials
fair enough
I'm just over here in the 30% camp wanting my normal maps though π
I wonder if there's some place where I can easily hack in the image loader settings to see whether this actually fixes my problem or not
Can I hack this line? https://github.com/Noxmore/bevy_trenchbroom/blob/ad558941bd056134e1175811fe90594639923760/src/config/main_impl.rs#L155
Like, will those settings be propagated to the normal map loading?
There should be one where TrenchBroomConfig::texture_sampler is, but i haven't gotten around to making that more powerful
It will, i was actually looking at that exact line of code!
You'll probably have to copy the function entirely though (or edit a local checkout actually)
I'm doing path = ... in my Cargo.toml π
good news: it works!
But I'm not sure what fixed it
Since in this change I also realized I was not generating the correct tangents at runtime
so let me check again without the SRGB stuff
(for context, I had set my meshes to RENDER_WORLD, so they didn't even show up in the inspector)
this is with just the tangets
Looks good!
That means that the linearity is indeed being inferred from the image π
Although....
This is using TGA, which has metadata. Let's see if this works with PNG still
looks file as well
which brings me to the question of how this even works 
Though it could just be luck that it works. Issues with loading normals with the wrong settings tend to only crop up with light from certain directions.
btw, the names are not bad!
It doesn't look fine to me, the top left is wrongly in shadow
I was having this problem before
Hmm you're right
this one does look the most correct
but it's a bit hard to tell because I'm loading the base color with the wrong settings (linear instead of srgb)
BTW, I love asset_server.exists
It's a bit too bad that it needs to read the asset to work
But it's such a good feature π
Good job on that one
Alright, this is it with only setting the normal map to linear and generating tangents:
Same with flipped Y for normals:
Thanks! I really think that should be a built-in Bevy feature, perhaps a new part of the asset source interface so it doesn't need to start reading the asset (i don't think it actually reads any data, even on web)
So the only difference between this and the screenshot with the correct looking normals was with other maps using linear as well?
You mean the difference with this?
Yea
Yes, the first image uses linear for everything, the last only for normals
Weird, what other maps do you use other than normal and diffuse?
none
Hacked my way around the issues, looks pretty neat now π
I think that's expected, as the base color is not linear, but srgb
Me too, surely there must be something else
It does look pretty neat!
Thanks! This is now with this ugly ugly hack and generating tangents when BTB is done creating colliders
this is obviously not for a PR, but I can depend on it for now π
Added some GH issues for the things we discussed
@urban zealot bad news: the same approach looks really wrong when using BSPs
Could you check whether you get the same issue in your test scenes?
This is testing my release workflow, so it may be something else
I'll get to that in a little bit and let you know how it goes
thanks π
Oh wow, you already implemented the type registry stuff? great!
I saw you thought it would be annoying to setup, but it was surprisingly easy!
Bevy's reflection system is pretty sick
Looking at the diff right now
Looks pretty neat indeed π
Just updated my app to move all things relating to a specific TB entity into their own little file. Much better now! Thanks for the feature π
Glad you like it!
Just learned that not all images use ImageLoaderSettings, complicating things further
I also probably need to restructure bevy_materialize in general, while i think the design of things is sound, both of us had a hard time navigating it earlier
what
which images?
I'm getting this with a PBR texture, but i haven't tried a linear normal map yet
Did you have to add tangents to bsp meshes as well? I didn't see any code that generates those
Forgot to specifiy, exr was the one i tried
I ended up converting it anyway since it was using an unsupported compression method
I added it to all Meshes that were under SceneCollidersReady: https://github.com/janhohenheim/foxtrot/commit/b232fb59cd4f12f87e2612b538d0c57ff06737bc
Alright, well they now generate tangents as well, not sure how i forgot to do that
So you can reproduce it?
Yes
I probably should've tried turning is_srgb off before starting a bunch of refactoring in bevy_materialize :P
hehe
that's good (for me), as that means I don't have to fix my asset baking pipeline π
Like i said i've run into this exact problem a while back, for some reason i thought the tangents were just incorrectly generated and didn't really look into it further
Oh I didn't catch that
I can reproduce that turning is_srgb off across the board seemingly fixes it, i am too tired for API design but tomorrow i will make a hopefully much better asset settings system
I do remember thinking "this is ridiculous and dumb" while writing the current API, especially this
/// Same as [`register_generic_material_sub_asset`](Self::register_generic_material_sub_asset), but passes image settings through.
/// This will cause an error if the asset loader doesn't use image settings.
fn register_generic_material_sub_asset_image_settings_passthrough<A: Asset>(&mut self) -> &mut Self;
So you still get that behavior when is_srgb is on for the base color?
Haven't tested that yet
(that one would be the default use-case)
If you manage to get it running with is_srgb = false on normals and is_srgb = true on base colors, that must mean that I hecked up in my hack and am not actually turning it off correctly
(or indeed my asset preprocessing is to blame)
My issue is indeed that my KTX files are being read as srgb 
Okay, after some digging, that hack is not enough. Not quite sure why, but I really need to set is_srgb = false in BTB itself to have all my KTX2 files loaded as non SRGB.
The line in question is being executed though. This means that the KTX2 files are being loaded with the default settings before these settings are applied. I'd be happy if you could double-check this however. I really really don't understand bevy_materialize, my bad π
(Note that I think this is also the case when using .map and when using .pngs, but not sure)
Here's a test material with both its PNG and KTX2 forms
This may be related to me preloading the level, come to think of it.
Edit: nope, not preloading my level also gets me Bc7RgbaUnormSrgb instead of Bc7RgbaUnorm for the normal textures
Got a workaround for now: preload all base color textures as srgb (which is simple as their paths are right in the .map) and then let BTB load all the rest as linear
Alright, now that I've got that workaround I'm back to mapping some more. I'm currently trying to make a brush that has a window texture emit light.
I tried doing so by using a SolidClass on the window brush and inserting a point light. That resulted in two things:
- The window lost its texture
- The light spawned at the world origin
Looking at the inspector, I see that I have created two new entities through this action
This first is this:
LightWindow is my solid class, and it is at the world origin.
Next to it in the hierarchy, I see this:
That big name is the name of my texture. This entity has the right transform and is holding the collider, so it seems like the one I'm actually interested in. However, the LightWindow marker is on the other entity.
Am I doing something wrong here?
next to it in the hierarchy? not under it?
As for the light spawning at the world origin (assuming you spawned it at the brush entity's transform), that's expected behavior if you don't have an origin brush in the brush entity
Not sure about the window losing its texture though
BTW @dim warren, did you figure out that non-base-color textures have to be linear by reading it from somewhere, or was it just through testing?
I believe so, let me double check
Don't know where I learned it, possibly a rendering course in university? It's not Bevy specific, if that's your question π
yep, siblings
Hmm, i feel like Bevy should at least warn you that it won't look right, if not just load as linear by default
That's a bug!
fully agreed
This is loading the .map, right?
Could you point me to the manual entry for TB for that?
yep
Or like a quick explanation of how I do that
That would be in the ericw-tools docs actually
Thanks, but I'm afraid I have no idea how to do that :<
I'm still a bit new to TB, haha
You'll just need a texture named "origin", then you apply it to all of a brush's faces, and make sure that brush is part of the brush entity you want to set the origin of
Oooh okay
(TIL multiple brushes can be part of a brush entity)
I've had other people confused about that too!
Good news: that worked! Bad news: even the white texture of the brush is gone now, it's completely transparent
If you were using a pure-bsp workflow, the compiler can actually automatically insert light entities at certain textures you specify
Dang
Maybe for context, this is TB
This is the window without a brush entity
(sorry for the blinding light, haha)
Huh, weird, I wanted to repeat the screenshot without a light and now the textures are gone again
π€·ββοΈ
The sides of the the window look like that with the light
Spooky
Okay, not sure what kind of sorcery this is
But now the same with the brush entity + origin:
also no collider, btw
Does the mesh entity exist here?
both there
there even is a collider, in theory
found it!
It went to the world origin as well now
For reference, I put the origin brush there in TB
don't know if that was correct?
I would guess that's because the mesh entity isn't a child of the light_window entity
Ooooh right
I can't see it in the screenshots, what entity is the marker component on?
Oh wait i see it now
light_window
the other entity that ends in brightlit is supposed to be its child I believe (that one has the collider and mesh)
Currently staring at the line of code that adds the mesh as a child
world.entity_mut(entity_id).add_child(mesh_entity);
Looks right...
Is entity_id one level too high?
Though should be inserting a ChildOf component because of 0.16 changes
I don't think so, that's the one we're calling all the spawn functions on
I might have to put a pause on this to focus on materials and settings and stuff
I'm going to bed for now, but I've pushed everything onto main in case you want to reproduce it.
This is how you reach the window:
Sure, I can always work around it by just placing a regular entity, I believe π
BTW I noticed you already started fixing https://github.com/Noxmore/bevy_trenchbroom/issues/93
Thanks for that π
Appreciate it!
No problem! That was a pretty easy change, i don't think the only other use should matter since it only has to do with physics, but i'll look closer after material stuff
update: for some reason, the hierarchy is correct for func_group of brushes:
But when creating a func_group of a single brush entity, it creates 3 siblings:
Hmm not quite, I need the window to be NotShadowCaster for the light to pass through :/
Okay, I have found the condition on which this arises:
pub(super) fn plugin(app: &mut App) {
app.register_type::<LightWindow>();
app.add_observer(setup_light_window);
}
#[derive(SolidClass, Component, Debug, Reflect)]
#[reflect(QuakeClass, Component)]
#[base(Transform, Visibility)]
#[geometry(GeometryProvider::new().trimesh_collider().smooth_by_default_angle().with_lightmaps())]
pub(crate) struct LightWindow;
fn setup_light_window(trigger: Trigger<OnAdd, LightWindow>, mut commands: Commands) {
let entity = trigger.target();
commands
.entity(entity)
// Remove this line to make the problem go away
.insert(children![Name::new("Child")]);
}
The brush entity is not allowed to have children on its own, otherwise we run into the bug!
On that note, is there some kind of trigger I can observe that tells me "this brush entity is done, its hierarchy has been constructed, you can use it"? Like SceneCollidersReady but just for an entity brush
I need to manipulate the entity that is holding the brush entity's mesh, but to do that, I would have to wait with my observer until that child is actually there
I tried Trigger<OnAdd, Children>, but that is not triggered on EntityCommands
Just noticed that I don't need children on the entity brush marker object anyways, I need the child on the child that holds the mesh
So this bug is not as bad as it seems for my case π
Got a good hack in the meantime:
#[derive(Component, Reflect)]
#[reflect(Component)]
pub(crate) struct NotifyBrushEntitySpawned;
#[derive(Event)]
pub(crate) struct BrushEntitySpawned;
fn trigger_entity_brush_spawned(
brush_entities: Query<(Entity, &Children), With<NotifyBrushEntitySpawned>>,
mut commands: Commands,
) {
for (entity, children) in brush_entities.iter() {
if children.is_empty() {
continue;
}
commands
.entity(entity)
.trigger(BrushEntitySpawned)
.remove::<NotifyBrushEntitySpawned>();
}
}
used like this:
fn setup_light_window_entity(trigger: Trigger<OnAdd, LightWindow>, mut commands: Commands) {
let entity = trigger.target();
commands
.entity(entity)
.insert(NotifyBrushEntitySpawned)
.observe(setup_light_window_brushes);
}
fn setup_light_window_brushes(
trigger: Trigger<BrushEntitySpawned>,
children: Query<&Children>,
mut commands: Commands,
) {
let entity = trigger.target();
let Ok(brushes) = children.get(entity) else {
return;
};
for brush_entity in brushes.iter() {
// do things with the actual brushes
}
}
got the window finally working now, great π
Are angles supposed to work for brush entities?
I can't get them to have a rotation other than IDENTITY
Well, I can just add a field called angles to my brush entity and use that for my transform, so that works. But it seems weird that the origin brush worked for setting the translation, but not the rotation.
Nope, it doesn't do anything in-editor so i just remove the rotation when loading
Can't you just use the rotation tool?
It does for me π
sec
The rotation tool is AFAIK just a visual aide that sets the angles
that little arrow is the direction the light will shine towards in my setup
Oh, i thought you wanted to just rotate the brush
oh I see π
Yeah, i don't think i thought that one completely through
yeah that works of course haha
Should I open an issue?
Sure
Oh yeah, the color space thing should be fixed by default now
Ended up scrapping basically the entirety of yesterdays work :)
Oh that's really really good news! Let me check it out real quick
I feel like everytime that happens to me, my second design ends up being extremely neat
So congrats π
I agree, it's still a little hacky, but a lot simpler
Thoughts on this?
I'm still a little confused
The entity that is holding the mesh would be the one being spawned, right?
Or do you mean the entity that contains Mesh3d?
And i am beyond confused on why this could cause it
Me too
I was about to say "the brush entity has no children yet when I use Trigger<OnAdd, BrushEntity>", but that is not true 
Sorry to say, current main does not fix it
Except if I need to enable something
Dang
(let me run a cargo update just in case)
I think I got myself confused about how things work because of the siblings thing
I'll double check what my issue was
The heck
So, when entering Trigger<OnAdd, BrushEntity>, we have a child. So far, so good.
When I insert a second child, the first child becomes a sibling 
????
Agreed
Yeah, I did not expect this behavior, which is why I assumed that there were no children to begin with then entering the observer
That's why I wrote my earlier messages that way
Good news for me: I can remove my hack and iterate over the children of the brush entity directly, yay!
Adding a grandchild to the brush entity is no problem
Just adding a new child is problematic
cargo update didn't help, the normals are still broken on main 
Running the color space fix system in PreUpdate didn't work for me before, now it does, i have a suspicious feeling there might be a hard-to-track-down bug at play
We'll see though, trying to reproduce this heriarchy bug first
For reference, this is how it looks with correct normals
I think since I realized that I'm actually caring about the Mesh entity and not the one with the marker, that one doesn't affect me at all anymore. So don't worry if it's hard to track π
Because it sounds pretty spooky
Thank you again for dealing with all my bug reports 
@dim warren Aha!
commands.spawn((PointLight { intensity: 10_000., ..default() }, ChildOf(trigger.target()))); // Works fine!
commands.entity(trigger.target()).insert(children![PointLight { intensity: 10_000., ..default() }]); // Messes everything up!
Children::spawn() is broken
Huh??
Whaa
Aren't those the exact same?
They should be
Should probably narrow it down first
Weird request, try looking at the materials in inspector-egui
When it wasn't working in PreUpdate, that seemingly made the images update to the new settings for me
In general, I have found it very hard to reliably change already loaded images' settings
this is the ground material
hold on, I just remembered I set all imaged to RENDER_WORLD
let me disable that
ah sad, that didn't fix it
I also tried turning that on, didn't break it either
Is your thing in a state i can checkout and step through to see what's not firing?
yep, main is completely runnable π
Just need to update the patch in the Cargo.toml to point back at your repo
The RENDER_WORLD move is in the system move_textures_to_render_world if you want to disable it
Wait, have you been just updating to the latest version of BTB? Not materialize?
...yes?
Sorry, I didn't catch that π
Alright alright, let me patch that one, haha
Understandable mistake, i probably should've clarified
well, it makes sense to patch that one instead of BTB π
Things probably aren't setup for both versions of materialize, let me commit BTB real quick
Github scrolling in urls is weird for me, but if i see the comment you mean, you are correct
Assuming that's coming from BTB, that is expected (will fix in commit shortly)
Cool, then all is well!
Yay, I'm really excited that this works now π
thx!
No problem!
Even works when using RENDER_WORLD as you said!
Sweet! I was at least 70% sure there was going to be some edge case that made that not work for you
hehe
@dim warren Alright, give that a try
on it π
Works perfectly ππππππ
Sick!!!!!
Unrelated: I was wondering how TDM implemented those round storm drains, seeing as its editor is also brush based and those have no good presets for circles
So I took a closer look and
hehe, they just cut it out more or less circularly
That is one wonky looking circle lol
TB actually has a good circle preset now
Oh really? where?
it looks alright from an angle
But oh boy is it wonky when looked at up-close
TIL π thx
What engine/editor does it use? I've never heard of this game before
It's a recreation of the Thief mechanics in id Tech 4, which is the engine powering Doom 3
Oh it's FOSS, neat!
It's editor is a customized radiant called DarkRadiant
Yep!
Hence why I'm yoinking all textures. Most models and textures are CC sharealike non-commercial by-attribution
Which is really generous given the quality
Any plans to support the Quake 3 format eventually?
I dont even know what editor Q3 people use, NetRadiant maybe?
from what I recall the main difference are the patches/curves
Blocker on that is quake-util, which so far only parses Quake 1
Yeah, and the more I think of it the less appealing it might be for people. IMO Trenchbroom is miles ahead in stability than the other radiant editors out there. And so as long as it sticks to Valve1/Quake1 there may not be a demand for Q3 with this plugin.
Also its not like curves aren't achievable with TB
Quake 2 would be nice though π
Hmm, I actually don't know the difference, do you know?
I'd assume the bsp is different because of the different hull sizes for various enemies.
but not sure about the .map format
surface flag data is the big one. Those can vary per surface for the same brush.
The bsps can also read 32 character texture names instead of only 15
Relevant issue: https://github.com/Noxmore/bevy_trenchbroom/issues/28
Ahhh yes the surface flag data is huge
I was actually just thinking about surface data the other day. I know this is getting a bit off topic but where would you actually store that on the Bevy side of things? And how would you retrieve it?
say I want to do different footstep sounds based on what im walking on
@urban zealot I'm again facing the problem that a PNG has to be in the textures folder for the map to scale textures properly
It works fine when using .bsp, but when I have a .map, I need to have a PNG laying around even though the material file only references KTX2, otherwise I get this:
I've verified that no actual .PNGs are ever loaded as assets
It works when I convert the png to an extremely compressed (~ 500 Byte) JPG, so I assume only the texture dimensions are read from it?
That is correct, i suppose we could have a dummy file that just contains texture size
That is actually a good point, vertex data would work, but i'm not sure physics engines would give us an id in collisions that we could easily map to that
semi-related: https://github.com/Noxmore/bevy_trenchbroom/issues/60
I'll switch to your crate hopefully pretty soon, so we won't have to worry about that
@dim warren Speaking of, what was your rotation fix crate called again? I would like to add it.
Note that that crate is intentionally global, though
And you'll probably want to do the if not plugin added song and dance
Hmm. I wonder if making it the default to have this fixed will overall make the transition to the Bevy fix easier.
Probably. I also doubt this would cause problems or break existing scenes as BTB is not exactly the kind of plugin you just plug into an existing project one day, but then continue loading your old levels
Btw, how well is the hot reloading supposed to work?
It should work, i just tested it in map_loading, not working for you?
oh don't get me wrong, it definitely does work mostly
But every now and then it doesn't update something, or gives it no texture, or doesn't scale the texture, etc
So I end up reloading the level
Not a big deal though π
this however is more of a big deal π
Requires me to restart the whole app
Any ideas what might be the issue?
Hmm
This would happen if the map somehow preloads before classes are registered
When does the preloading kick off?
here's what I mean
Also, the new brushes have no colliders
PreUpdate
although, not quite true
impl LoadResource for App {
fn load_resource<T: Resource + Asset + Clone + FromWorld>(&mut self) -> &mut Self {
self.init_asset::<T>();
let world = self.world_mut();
let value = T::from_world(world);
let assets = world.resource::<AssetServer>();
let handle = assets.add(value);
let mut handles = world.resource_mut::<ResourceHandles>();
handles
.waiting
.push_back((handle.untyped(), |world, handle| {
let assets = world.resource::<Assets<T>>();
if let Some(value) = assets.get(handle.id().typed::<T>()) {
world.insert_resource(value.clone());
}
}));
self
}
}
This is the extension on App that actually inits the handle
So it technically starts at plugin creation time
Does that count as StartUp?
It used to work before, in any case
Oh wait, I could try just executing that later in the plugin setup
Yep, that seems to work
Before:
app.add_plugins((
asset_processing::plugin,
asset_tracking::plugin,
shader_compilation::plugin,
#[cfg(feature = "dev")]
dev_tools::plugin,
gameplay::plugin,
props::plugin,
screens::plugin,
theme::plugin,
ui_camera::plugin,
hdr::plugin,
));
After:
app.add_plugins((
asset_processing::plugin,
asset_tracking::plugin,
#[cfg(feature = "dev")]
dev_tools::plugin,
props::plugin,
screens::plugin,
theme::plugin,
ui_camera::plugin,
hdr::plugin,
// Moved these two to the end, because they start preloading the levels
gameplay::plugin,
shader_compilation::plugin,
));
I wouldn't think that starts the loading process, but if it works now then maybe?
Restarted it a bunch of times, this really is the fix
Thanks for the help π
weirdly enough, some brushes I didn't even touch lose their textures
I did a little research and reached out to a trusted source on the Quake 2 front. Seems the required augmentation to the grammar is three additional tokens to each plane/half-space. I'm told the three tokens are parsed as signed integers by Carmack's original tools, though the third can be written as a floating-point by TrenchBroom
from the TB ui those are the "content flags", "surface flags", and "value" respectively
That sounds simpler than I thought π
Thanks for looking into it π
yeah, thought I'd put some updates here. Helps keep me motivated to keep a line of communication open with consumers. Plus, I think these particular tidbits (float vs. integer) may impact how Q2 map support gets integrated with BTB
I have the changes in for Quake II maps (https://github.com/4LT/quake-util)
Haven't published to crates.io yet, I just want a little more confidence w/ testing
@dim warren @urban zealot Just published an update to quake-util. Version 0.4.0 adds support for Quake II maps. There's API-breaking changes, so some refactoring is required
Sweet, thanks!
wow, that was quick!
Good job π
Ayee awesome, thanks for that
So i just made a PR (could use some help with CI) to update BTB to avian 0.3. and now I wanted to migrate my project to the current BTB, i am coming from 40c124d from 25th of april and nothing works anymore π - Do we have a migration guide work-in-progress for someone coming from 0.7 ?
Trying to find the diffs to how I did stuff before using the examples:
- do we have to
#[reflect(QuakeClass, Component)]now on everything that used to do#[reflect(Component)]only before? - ok seems
#[require(Transform, Target)]now needs to be#[base(Transform, Target)] - somehow the
.materialfiles have no effect anymore - combined brushes with an origin get their colliders now misplaced
- the content of the
fgdfile is not deterministically sorted anymore - wait is auto registration gone?
Yeah the API had quite a few overhauls. That should definitely be written down somewhere. I can write the changes that have noticed / been involved with later π
No clue whatβs up with your materials and origin brushes, those work for me
Maybe youβre running into https://github.com/Noxmore/bevy_trenchbroom/issues/95 ?
- Every class that needs to interact with TB (i.e.
PointClasses andSolidClasses) needs to#[reflect(QuakeClass)], yes - Yep, use
basefor things that should show up in the TB editor - I think they're just
some_cool_wood.tomlnow, no.material. Maybe.material.tomlworks, too. - Make sure you're not running into the issue I sent.
- I'm curious, why do you need that to be sorted?
- Yeah, use
app.register_type::<Foo>()just like you would with other things that need to be reflected until https://github.com/bevyengine/bevy/pull/15030 lands π€
Some more stuff I can think of:
- Dunno if material inheritance was a thing in
0.7, but you can now doinherits = "/textures/base.toml"in your materials to inherit definitions from abase.tomlthat looks like this, for example
type = "StandardMaterial"
[material]
base_color_texture = "${name}.png"
normal_map_texture = "${name}/${name}_normal.png"
perceptual_roughness = 0.7
- Normal maps, roughness/metallic maps and such are now supported out of the box (they used to be important in the completely wrong color space)
TrenchBroomConfignow takes plurals for many things, liketexture_extensionsinstead oftexture_extension
- Don't remember whether this was the case in
0.7, but your setup should call bothwrite_game_config_to_default_directoryandadd_game_to_preferences_in_default_directoryto get full TB config out of the box
write_game_config_to_default_directorytakes a type registry now
Here's some maybe useful boilerplate:
Setup config:
/// Set up TrenchBroom so that it can create maps for our game.
/// This is intentionally not gated to dev builds so that players can edit the levels themselves if they want.
#[cfg(feature = "native")]
fn write_trenchbroom_config(server: Res<TrenchBroomServer>, type_registry: Res<AppTypeRegistry>) {
info!("Writing TrenchBroom config");
// Errors at this point usually mean that the player has not installed TrenchBroom.
// The error messages give more details about the exact issue.
if let Err(err) = server
.config
.write_game_config_to_default_directory(&type_registry.read())
{
warn!("Could not write TrenchBroom game config: {err}");
}
if let Err(err) = server.config.add_game_to_preferences_in_default_directory() {
warn!("Could not add game to TrenchBroom preferences: {err}");
}
}
world spawn:
app.register_type::<Worldspawn>();
#[derive(SolidClass, Component, Reflect, Default)]
#[reflect(Component, QuakeClass)]
#[geometry(GeometryProvider::new().convex_collider().smooth_by_default_angle())]
pub(crate) struct Worldspawn;
func_group:
app.register_type::<FuncGroup>();
#[derive(SolidClass, Component, Debug, Clone, Copy, Default, Reflect)]
#[base(Transform, Visibility)]
#[reflect(QuakeClass, Component, Default, Debug)]
#[geometry(GeometryProvider::new().convex_collider().smooth_by_default_angle())]
struct FuncGroup;
Some generic entity:
app.register_type::<Foo>();
app.add_observer(setup_foo);
#[derive(PointClass, Component, Debug, Reflect)]
#[reflect(QuakeClass, Component)]
#[base(Transform, Visibility)]
#[model("models/foo.gltf")]
#[spawn_hook(preload_model::<Self>)]
pub(crate) struct Foo;
Where the model path "models/foo.gltf" can be fetched in the rest of your code with Foo::CLASS_INFO.model_path().unwrap()
And setup_foo is just an OnAdd observer. There are also spawn hooks, but the only one I personally use is preload_model which starts loading the glTF when the app starts.
There's a lot of boilerplate for these classes right now, as you can see. See https://github.com/Noxmore/bevy_trenchbroom/issues/92
Pretty sure much of what I just wrote won't be new to you, but I thought it's better to write too much than too little π
Oh, here's something else you might want:
pub(crate) trait GetTrenchbroomModelPath: QuakeClass {
fn model_path() -> String {
Self::CLASS_INFO.model_path().unwrap().to_string()
}
fn scene_path() -> String {
format!("{file_path}#Scene0", file_path = Self::model_path())
}
fn animation_path(index: u32) -> String {
format!(
"{file_path}#Animation{index}",
file_path = Self::model_path()
)
}
}
impl<T: QuakeClass> GetTrenchbroomModelPath for T {}
pub(crate) trait LoadTrenchbroomModel {
fn load_trenchbroom_model<T: QuakeClass>(&self) -> Handle<Scene>;
}
impl LoadTrenchbroomModel for DeferredWorld<'_> {
fn load_trenchbroom_model<T: QuakeClass>(&self) -> Handle<Scene> {
self.resource::<AssetServer>().load_trenchbroom_model::<T>()
}
}
impl LoadTrenchbroomModel for AssetServer {
fn load_trenchbroom_model<T: QuakeClass>(&self) -> Handle<Scene> {
self.load(T::scene_path())
}
}
Allows you to do
let model = asset_server.load_trenchbroom_model::<Robot>();
The project has gotten large enough that we probably should start writing a migration guide between versions.
Jan did a great job at explaining, to claify, the material files have had their default extension set to toml because the default material deserializer is TomlMaterialDeserializer, you can easily change it back if you want
Not sure what's happening with CI, the preloading test is failing on Github's side, but not on my machine, which will make troubleshooting rather annoying
I'll have a look into the misplaced colliders
I was sad to see builtin auto-registration go, but there are some annoying problems with platform compatibility we were facing with wasm, and we wanted to move it into the type registry anyway. There are existing and (as Jan says) up-coming solutions for auto-registration for the type registry. I'd look into those.
BTW Thanks @dim warren for summarizing the changes, how does Bevy handle migration guides? Is it just stuck in a big file somewhere?
- Some crates have their migrations in their releases, e.g. Avian
- Some crates have a changelog file following keep a changelog, e.g. hanabi
- Bevy itself has a directory with dedicated files for each migration which they then accumulate when generating the website.
I personally try to never commit straight onto main, but try to do as much work in dedicated PRs as possible. Then I can just write the migration directly into the PR description. When it comes time to publish stuff, I just take a look at the autogenerated PR list GitHub gives me for the release and copy-paste the migrations
For the CI failure, that looks like a scheduling ambiguity. Have you tried bevy_mod_debugdump ?
The convenience of commiting to main still has me, but i try to use PRs when i want it to appear in the changelog
I'm leaning towards just keeping a big file for migration guides for now; simple and easy
Oooh, i will check it out!
makes sense π
I'm currently doing the same, i.e. copy migration guides from PRs when I do a GitHub release, and then do a manual clean-up pass to fix any outdated info and make things more cohesive. I'm considering switching to having migration guides in markdown files in-repo though, since some people have asked if there's an up-to-date migration guide or changelog before the release is out, such as in the release candidate stage when people often switch to using the main branch
We probably wouldn't need a file per "thing" like with Bevy, but rather e.g. a 0.3-to-0.4.md or 0.3-to-main.md file that is updated whenever breaking changes are made
I'll have a look into the misplaced colliders
did you have a chance to look into broken colliders for brushes with origin? created an issue with a bit more context: https://github.com/Noxmore/bevy_trenchbroom/issues/103
I'm curious, why do you need that to be sorted?
I have my configs checked into git and symlinked from there into the TB folder. This makes it nicely diffable.
Ooooh I see, that makes sense π
I've been quite busy, and haven't been able to get around to it yet, sorry!
I have now gotten around to it
Did you find the issue? π€©
Yep
It works like a charm now! Thank you!
So we could release 0.8? π«£
Is bevy_rapier updated on crates.io yet?
edit: just checked, i don't think it is, that's the last blocker
oh right, I completely forgot we supported that π
There's also bevy_flycam, but that's just for debugging and we can always just write our own
Yeah you are right it seems not released yet - will pester @lucid mantle about it at rustweek tomorrow π
What are you talking about, https://crates.io/crates/bevy_rapier3d does support bevy 0.16 ||as of a few seconds ago π€«||
@dim warren If you have the time, could you try rolling the remove-geometry-provider branch for Foxtrot? (See the migration guide diff)
I just want to make sure it doesn't mess anything up in it before i merge the PR, and I'm sure you'll be much faster at migrating Foxtrot than I
sure, sec
I'd advise you to only add that plugin if it was not already added
I can't do that from inside a PluginGroup unfortunately
oh whaat
TIL
Geometry looks correct π
Here, in case you see something weird
But I think it's good π
Oooh, haven't seen the level in a bit, looks cool!
Thanks! My SO helped out a bit in the end. I think it's fine to leave it for now π
I do that with MaterializePlugin within CorePlugin (what used to be TrenchBroomPlugin), i could do that with this, but i'd have to add an option to disable it in the config, which kinda defeats the point of using a plugin group
Her main criticism of the process was that she needed to recompile the game to get new entities in her inspector, which took quite a while on her machine. I think next time, I'll do what @dry portal did and set up a symlink to a checked out file that one can just git pull
Yeah I think it's alright
Let's leave it as-is, I don't think this will annoy anyone and if it does, the fix is trivial (just don't add the plugin yourself or disable it in the group)
0.8.0 has been released!
yay!
works like a charm! Thank you! π
@urban zealot are brush entity rotations supposed to work on main? I think they're still broken right now
this is my test setup
And this is my spawn:
fn setup_light_window_brush_entity(
trigger: Trigger<OnAdd, LightWindow>,
brush_entity: Query<(&Transform, &Children), With<LightWindow>>,
mut commands: Commands,
) {
let entity = trigger.target();
let Ok((transform, children)) = brush_entity.get(entity) else {
return;
};
for brush in children.iter() {
commands
.entity(brush)
.insert(children![(SpotLight {
color: Color::srgb_u8(239, 173, 144),
intensity: 200_000.0,
radius: 0.1,
shadows_enabled: true,
#[cfg(feature = "native")]
soft_shadows_enabled: true,
..default()
},)])
.queue(disable_shadow_casting);
}
}
Note how I just spawn the spotlight as a child of the entity brush, as would assume it to point in the correct direction now
But this is how it looks in-game
Note how the light is pointing in the wrong direction
This is the Transform of the LightWindow:
This is the child holding the Mesh:
And this is the spot light itself:
Note the angles I used in TB are 270:
Oh wait, am I maybe not supposed to insert it as a child of the meshes? I see
Attempt 2:
fn setup_light_window_brush_entity(trigger: Trigger<OnAdd, LightWindow>, mut commands: Commands) {
let entity = trigger.target();
commands
.entity(entity)
.insert(children![(SpotLight {
color: Color::srgb_u8(239, 173, 144),
intensity: 200_000.0,
radius: 0.1,
shadows_enabled: true,
#[cfg(feature = "native")]
soft_shadows_enabled: true,
..default()
},)])
.queue(disable_shadow_casting);
}
Results in:
The mesh is gone because we run into https://github.com/Noxmore/bevy_trenchbroom/issues/95
pub(super) fn plugin(app: &mut App) { app.register_type::<LightWindow>(); app.add_observer(setup_light_window); } #[derive(SolidClass, Component, Debug, Reflect)] #[reflect(QuakeClass, Co...
Light is correct
Not sure why the collider is over here though
Attempt 3:
fn setup_light_window_brush_entity(trigger: Trigger<OnAdd, LightWindow>, mut commands: Commands) {
let entity = trigger.target();
commands
.entity(entity)
.with_child(SpotLight {
color: Color::srgb_u8(239, 173, 144),
intensity: 200_000.0,
radius: 0.1,
shadows_enabled: true,
#[cfg(feature = "native")]
soft_shadows_enabled: true,
..default()
})
.queue(disable_shadow_casting);
}
Results in:
The light is correct, the mesh is correct (I intentionally placed the window like that for debugging), but the collider is rotated by 90 degrees around the origin brush
@dry portal I suppose your entity brushes with origins don't have a rotation?
I'll stay on an earlier version until this is fixed then
btw, did you hit up the #ecs-dev people about this?
Try latest commit
I have not yet
sec
Perfect! Thanks for the extremely quick fix!!
No problem! Mainly just forgot to inverse the rotations of convex colliders, will put that out in a patch release shortly
I'm beginning to suspect that this isn't a Bevy bug per-se, just a quirk that we are somehow running into
What makes you think that?
Oh good question I suppose not
AFAIK children! inserts the Children component directly, while ChildOf and with_child will have a delay until the parent has Children
And just doing this triggers our bug:
Ohh, there needs to be a tick to update it? Like assets being added to Assets<T>?
fn setup_light_window_brush_entity(trigger: Trigger<OnAdd, LightWindow>, mut commands: Commands) {
let entity = trigger.target();
commands.entity(entity).insert(Children::default());
}
Results in:
(meshes are at origin)
Not sure if it's a full tick or whether it's done at the end of the frame, but I suspect we are either
- somehow depending on this delay or
- somehow depending on there not being a
Childrencomponent from the get-go
Just checked, Children doesn't seem to implement MapEntities, i wonder if that's why it's being weird
Neither does ChildOf though
Do we mark the entity as "already processed" when we iterate once through its Children?
Not sure what you mean by "already processed", or "when we iterate once through its Children"
In other crates, I've seen this pattern:
fn process(entities: Query<Entity, Without<Processed>>, mut commands: Commands) {
for entity in &entities {
// do something
commands.entity(entity).insert(Processed);
}
}
That is useful when entities has some filter, e.g. entities: Query<Entity, (With<A>, With<B>, Without<Processed>)>
That way, this system will only execute once A and B have both been inserted into the entity
I donβt think BTB does anything like this, but if it did, it would explain it
Idea: does children! override already pre-existing Children?
@urban zealot little update: I ran this code:
use bevy::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.add_observer(on_parent_added_with_child)
//.add_observer(on_parent_added_children)
.add_systems(Update, print_hierarchy)
.run();
}
#[derive(Component)]
struct Parent;
#[derive(Component)]
struct Child1;
#[derive(Component)]
struct Child2;
fn setup(world: &mut World) {
let parent = world.spawn((Parent, Name::new("Parent"))).id();
let child = world.spawn((Child1, Name::new("Child1"))).id();
world.entity_mut(child).insert(ChildOf(parent));
}
fn on_parent_added_with_child(trigger: Trigger<OnAdd, Parent>, mut commands: Commands) {
let parent = trigger.target();
commands
.entity(parent)
.with_child((Child2, Name::new("Child2")));
}
fn on_parent_added_children(trigger: Trigger<OnAdd, Parent>, mut commands: Commands) {
let parent = trigger.target();
commands
.entity(parent)
.insert(children![Child2, Name::new("Child2")]);
}
fn print_hierarchy(
parent: Single<Entity, With<Parent>>,
children: Query<&Children>,
names: Query<NameOrEntity>,
) {
println!("{}", names.get(*parent).unwrap());
for child in children.get(*parent).unwrap() {
println!(" {}", names.get(*child).unwrap());
}
panic!("Done");
}
Running this, I get the following hierarchy with on_parent_added_with_child:
- Parent
- Child2
- Child1
But using on_parent_added_children:
- Parent
- 8v1
- Child2
- Child1
There's an extra element in there 
But children definitly does not override past children, it appends new ones
Huh, well i appreciate you looking into this
I tried flushing commands before/after every spawner and nothing changed
I tried finding the exact issue, but I wasn't able to :/
children! is new in 0.16, so reporting this bug now may lead to a fix in 0.16.1
but I struggle creating a minimal reproducible example
Anyone know why writing the game config might get deadlocked?
Is the file maybe locked by another process?
Or maybe your OS is restricting the app from accessing the directory
It worked the first time, it might be locked...
Oh hey, the new TrenchBroom is out! https://github.com/TrenchBroom/TrenchBroom/releases/tag/v2025.3
@urban zealot https://github.com/Noxmore/bevy_trenchbroom/pull/119 exciting!
btw, I got a commision to write something about 3D gamedev with Bevy, and I'd like to dedicate a chapter to BTB.
I believe the new attribute stuff got merged, right? π
If so, is there anything else of note that I should wait for before digging in?
No rush, I first need to finish my recastnavigation port
Also, we can probably close https://github.com/Noxmore/bevy_trenchbroom/issues/95 as "this weird design is intentional upstream Bevy behavior"
The only thing left in my immediate todo list is some changes to field attributes, namely wrapping them in #[class(...)] or #[trenchbroom(...)], but that's about it
sounds good
Going through the open issues right now
I still want to PR https://github.com/Noxmore/bevy_trenchbroom/issues/60 at some point
If you don't get to it first, haha
I just don't know i would tackle it to be honest
Yeah I think we can just disable the test in question for https://github.com/Noxmore/bevy_trenchbroom/issues/117
Add a #[ignore("blabla") to it
or was it #[ignored]?
I think we settled on adding a component to colliders that contains a mapping from some index to a material handle, or something like that
Been a while
just had to look up what #[ignore] does, sounds reasonable
We also had to #[ignore] a test in Avian a while ago because the Ubuntu runners just refuse to run it haha
I can see that, I just took a melatonin so I do not have the brain capacity to talk about much more implementation atm
Little heads-up about https://github.com/Noxmore/bevy_trenchbroom/issues/115:
if you test it on web, it will only work with the following combination:
- using forward decals
- using WebGPU
- using something else than MSAA, e.g. FXAA
sure! good night π
actually, I should add that to the issue for future reference
I'm so proud of this little crate for sniping half of all maintainers into discussing ergonomics haha
This is cursed, but I believe this would fix our problems in a very unobtrusive way in case 0.17 doesnβt ship with nice semantics π
Reminder for self: change bevy_fix_gltf to this abomination
hey! could I get a hand lent into loading textures?
I guess it's not even a bevy_trenchbroom question, but more of a Trenchbroom question
maybe I should have a deeper look at the manual but I couldn't find much info besides creating a texture/ directory in the game_path
(which is not working?)
OOOOOOOH
Wait after loading bevy a new game engine appeared in the settings
when I opened trenchbroom for the first time bevy wasn't there
okay, I guess that did something but my .png is still not loading as a texture
π
ima try to read this chat, because discord doesn't allow searchind inside an specific thread
Okay, it just needed to go into the assets/ folder instead of /

Glad you figured it out!
I've got another question
I noticed by your talk that the way you attach properties to a point_class is by... well... the way you showed on the slide
with an observer and a trigger function
and I figured that for solid_classes it might be the exact same
and yeah, it works
The collider is probably missing?
but how do I do it for non-point non-solid meshes?
no no, that code works perfectly fine
Im wondering how do I add components to the default meshes
that arent assigned anything
So the grey and blue
how would I give them components like the collider
They are part of Worldspawn π
oh, so I can do the observertrigger pattern to worldspawn?
Thereβs an annotation there that says to add colliders to that
See my slide where I show Worldspawn
Ding ding ding!
Hmm, not sure if Worldspawn is allowed to have extra properties. If so, they would not be separate for the gray and blue area, but kinda global.
The idiomatic way is to use brush entities, like you did for the orange stuff
What exactly are you trying to achieve?
yeah, I assumed they would be the same for both gray and blue
but I'm not really trying to achieve anything yet
just getting comfy with the tool
alright, makes sense then π
I recommend using inspector_egui to check out the hierarchy generated by bevy_trenchbroom. It made it much clearer to me how brushes were handled when I first started!
has the trenchbroom prelude changed recently?
Current main is very different
But my slides use the latest release
lol nvm
@urban zealot I didn't notice you already published the release haha
yeah never mind my slides then hahahah
Yeah the recent changes are really good imo π
hah
MUCH less boilerplate hehe
Oh hey I didn't notice there's a manual now!
Introduction
looks great π
Just noticed something π
I believe spawnflags could be used for Avian physics layers
TrenchBroomConfig writing now happens automatically with WriteTrenchBroomConfigOnStartPlugin. If you're writing out your config on startup, you can remove that system. If not, disable WriteTrenchBroomConfigOnStartPlugin through TrenchBroomPlugins.
does this mean I can remove this?
neat
yep!
TIL about inspect_err
it even returns the value so that you can keep chainin
Rust has been getting so much nicer lately
neat π
I have a weird issue 
oh wait
nvm I dont
its just working perfectly
love to solve things just when I say them out loud
thanks for the help, I think I'm on the right path now
Hehe
well I've in fact noticed a problem
but its related to probably rendering
notice the shadow casted on the plane mesh
it's flickery af
while the ones on the other meshes are completely smooth
Hello!! idk if you've solved this yet, but a bunch of entities (like worldspawn) are builtin, you can totally add more properties to them, you just have to define them yourself (feel free to just copy them) and .override_class::<T>()
Worldspawn properties are pretty idiomatic and mean map-wide properties
Makes sense, thanks π
Is it a directional light?
nop
// Light
commands.spawn((
PointLight {
intensity: 10000000.0,
range: 999999999.0,
shadows_enabled: true,
..default()
},
Transform::from_xyz(4.0, 20.0, 4.0),
));
nice range lol
Just FYI, rendering is massively slower when you have lights with overlapping ranges on screen
So this will slow down to a crawl if you use 20 or so lights with that setting π
yeah, it goes exponential
But yeah no clue about that rendering artifact, sorry
I just put it there to light the whole scene and not worry about it
Might have to ask #rendering
ha, interesting
I dont really mind it anyway
im not gona use textureless meshes
and I'm gonna write a pixel-art shader
so a non-issue
aww
I was expecting checkboxes and radiobuttons
There should be π
here's a dropdown
disclaimer: this was not generated with bevy_trenchbroom, this is from opening up a Quake map
Looks right to me, can you send your generated FGD?
I would if I knew what that was
hahaha
maybe I should restart trenchbroom
?
nope, that wasn't it
tell me what the fgd is and I send it to you
/games/your_game/your_game.fgd
FGD looks good too

What version of TrenchBroom are you using?
2025.3
yeah i got nothing then
hahahaha don't worry
maybe it's because its the worldspawn?
@SolidClass base(worldspawn) = worldspawn
wait yeah what
what is BaseWorldspawn?
Ohh, there should be an error in the console telling you that 2 classes have the same name
I meant Bevy console but that tells you too :)
checks out
Just remove the BaseWorldspawn
At least we got to the bottom of it
I'm glad I brought it to your attention tho, so you can fix it when you have time
indeed
however one question, what did the documentation mean then?
?
BspWorldspawn has some compiler properties if you want to use .bsp files
If you're just using .map files you don't need any base classes
Oh
I've been considering switching to nvim so many times
but helix just works too well
for 99% of usecases
without any trouble
so.... I can't be bothered to care
Same, back when i trying using terminal editors i even put together an entire nvim config
but helix is just so already set up
never could get into it though for everyday use
maybe one day
Yeeeeeeees
its working now
I also had multiple tries in the past
with terminal editors
it never worked until I went FULL terminal
nowadays I basically just use Slack, a web browser, Discord and a couple of other things outside of the terminal
so it makes sense, having nix also helps with it
Would you say this is an Avian or a Trenchbroom issue?
For some reason when rotating brushes the collisions basically go crazy on spawn
This is all I'm doingto the colliders so it definitely isn't on my side

I'm so puzzled by this lmao
@digital heath any idea about what it could be?