Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
Zakarum
@omni-viral
It can't return downcasted type, cuz, you know, all those closures should have same signature
XBagon
@XBagon_gitlab
hey! does someone have any advice how I would efficiently get the amount of entities in a join and probably then cache and update it accordingly?
WaDelma
@WaDelma
I am not sure what you are asking. Can you give some simple example or more details?
XBagon
@XBagon_gitlab
hm, well I thought about trying to combine specs with some methods to "bulk simulate" find entities that have specific components and instead of doing something for each of them, do it for the amount of them instead and save the relative change to then be able to lazyily retrieve it when acting on a single entity for example. Though I'm not sure how feasible that is and how big the performance improvement really could be. especially when you have to save these things for 1000s of component combinations and also have to calculate changes for broader combinations, when having changes to more specific ones... maybe I got a bit carried away
Ghost
@ghost~5d4078b1d73408ce4fc75281
Hi! I'm trying to wrap my head around specs and specs-hierarchy. In specs is it possible to add a component to an existing entity? If so, how?
WaDelma
@WaDelma
@danaugrs_twitter You can use https://docs.rs/specs/0.15.0/specs/storage/struct.Storage.html#method.insert to add components to existing entities.
Ghost
@ghost~5d4078b1d73408ce4fc75281
Figured it out - thanks!
Is there any way to modify the order that entities/components are obtained from a .join() iterator? e.g. for z-ordering?
WaDelma
@WaDelma
@torkleyy Is there reason for not implementing Send for Dispatcher? I asked this in slide-rs/shred#147 but never got answer and now it's merged
David Komer
@dakom
Is specs suitable for wasm where there's no real multithreading (yet)?
Martin Jensen
@malynome
Hey everyone, sorry if this is a noob question(or if there is an example somewhere, although I couldnt find any), but how would I go about "comparing" entities to each other when running a system, i.e. pairwise iteration, for something like collision detection? If i also want to mutate in that system? Or is it better to separate collision detection and collision handling into 2 systems? - Thanks in advance if anyone is able to help!
Roman Holovin
@roman-holovin

Hi, I've been working on the movement system and got an issue:

impl<'a> System<'a> for DestinationMovement {
    type SystemData = (
        Entities<'a>,
        WriteStorage<'a, Position>,
        ReadStorage<'a, Speed>,
        ReadStorage<'a, Destination>,
        ReadExpect<'a, Timings>,
        ReadExpect<'a, Map>,
    );

    fn run(
        &mut self,
        (entities, mut positions, speeds, destinations, timings, map): Self::SystemData,
    ) {
                for (_entity, speed, destination, position) in
            (&entities, &speeds, &destinations, &mut positions).join()
        {
                let destination_position = positions.get(destination.0).cloned().unwrap();

                // rest of the code is irrelevant
        }
    }
}

Some entities have a destination, which is wrapper over Entity, and to calculate a path to destination I need to retrieve destination's position. Naturally, I also want to have own position of the current entity itself.

Issue is that iterator mutably borrows positions, so I cannot use it inside loop. For me it looks like a very common issue, so maybe there is known solution for this problem?

I could remove positions dependency from join and get both entity and destination position inside loop, but I don't like that it will relax component requirements for this system. Another potential solution I can think of, but haven't tried, is to collect all new positions into separate Vec and then assign them with another loop. I don't like performance implications of this approach and unsoundness of it.

Is there anything else I can do?

WaDelma
@WaDelma
@dakom Specs can be used in wasm if you disable parallel feature
David Komer
@dakom
yup! got it working :D
WaDelma
@WaDelma
@roman-holovin I think you can use mask method and get similar dependency for join, but without access to component and then get the positions. I am not sure how restrict* are supposed to be used actually. Maybe those could also be used?
WaDelma
@WaDelma
@malynome You can do join within join by using just Entities to get both entities, then compare them for inequality and then access storages. In our game I think we first did that, but now were doing simple sweep-and-prune by using flagged storage to maintain internal data structure.
David Komer
@dakom
looking at the Rendering example in the docs, for Piston, does "actual dispatching" mean to run a system that would then drain the ResizeEvents and modify the required components?
Yusuf Bera Ertan
@yusdacra_gitlab

Hello, i have a question about joining. How can i join a storage with an entity? Like this

(&mut world.write_storage::<Enemy>(), &enemy_entity).join()

enemy_entity is an specs::Entity. When i do that, compiler gives a trait bound error.

Or is there another way to get components of an entity if you know the entity already?
Yusuf Bera Ertan
@yusdacra_gitlab

Nvm, i just found it. The thing i was looking for was

world.write_storage::<Enemy>().entry(enemy_entity)

Sorry for not reading the docs.

Aaron DeVore
@adevore
Hey, I'm maintainer of the Rudy crate. At this point, I'm not really putting any development time into Rudy, so I don't think it will ever be faster than the built-in data structures. I was wonder about whether specs should remove its support.
For that matter, it's unclear as to whether Judy arrays (the data structure that Rudy aims to implement) are even any faster. They were designed a while ago, so modern CPU's might have different performance bottlenecks.
Aleksi Juvani
@aleksijuvani
is there any reason for insert in World to require Resources to have a 'static lifetime? it seems to me like this should be the lifetime of the World instead
Aleksi Juvani
@aleksijuvani
this is what i end up doing right now which is kinda gross
world.insert(unsafe { transmute::<&'_ DebugOverlay, &'static DebugOverlay>(surface.debug_overlay()) });
Matthew Hoffman
@mhoff12358
I'm profiling my code and seeing that DispatcherBuilder::add eventually starts to take a long time (~400ms). A RawVec realloc is what's taking up the whole time. The only thing I can think of is that there's some global state associated with each System that keeps getting added to when I make a new Dispatcher each frame. I wanted to try making the Dispatcher once, but I can't figure out how to have one as a member variable on my struct because I don't know what lifetimes to template it with.
Matthew Hoffman
@mhoff12358
I managed to figure it out. The 'a and 'b lifetime templates for Dispatcher ensure any System passed in through .with or .with_thread_local live at least as long as 'a and 'b. But since none of my Systems have any references it is okay to just have 'a and 'b be 'static.
Alex Davidson Bryan
@alxdb

hey, can someone tell me if a VecStorage will ever shrink in size?

Looking at the VecStorage implementation of UnsafeStorage it seems that when entities as entities are added the vec grows, but the only way it can shrink is when it is cleaned, where all entities are removed. Is my thinking correct?

WaDelma
@WaDelma
Yes it only shrinks when it's cleared. The size of VecStorage is always larger than the largest id of an entity.
Roman Holovin
@roman-holovin
Hi, is there is a way to get immutable borrow of the world from within system run function? I know about LazyUpdate``exec function, but given closure to it will be executing at the end of a frame and I'm not sure if it is suits me.
WaDelma
@WaDelma
What do you want to do with it?
Roman Holovin
@roman-holovin
Basically, spare some typing, pathfinding need half of the world to be able to route entities that move, so I would like to just pass immutable reference to world, so pathfinding logic would query whatever it needs
uzkbwza
@uzkbwza
so I saw this article, using specs, about events being used in the form of functions. I'm writing my code pretty faithful to the way it is done in the specs documentation (main loop doesn't do much more than dispatch and check if the game is ended). I'm wondering how one would accomplish this inside the systems themselves, or if it is something I should avoid doing in the first place, and just stick to using components for events
Daniel Salvadori
@danaugrs
@uzkbwza I'm working on a game engine using specs and I'm using shrev for events. Each event/event type (usually an enum type) has an associated global EventChannel resource which can be read and written to by systems. This allows specs/shred to optimize which systems can be executed in parallel automatically, like it's done for component reads/writes. It's working pretty nicely for me so far. Also, this is how specs does events internally for its FlaggedStorage, which allows you to check if/which components have been modified.
uzkbwza
@uzkbwza
If you don't mind, could you post an example of how you're using shrev with specs?
Oh, funny. it even mentions shrev in the specs book. https://slide-rs.github.io/specs/07_setup.html
This is exactly what i needed! lol.
Daniel Salvadori
@danaugrs
@uzkbwza wow yep that explains it pretty well :D
Thomas Schaller
@torkleyy
@WaDelma Dispatcher isn't Send because it can contain thread-local systems.
Roman Holovin
@roman-holovin

I have a problem with pathfinding. I wrote a function to calculate paths. It needs bunch of storages, read-only. Unfortunately, one system that interacts with pathfinding requires one of this storages for mutable access. I had to specify WriteStorage for pathfinding arguments just because one of system needs it this way. Documentation specifies that it is forbidden to require both ReadStorage and WriteStorage simultaneously, so I cannot do that. At this point it doesn't really bother me that much, but I suspect I will have problem with FlaggedStorage in future.

Is there way to specify argument type for function so it would accept both ReadStorage and WriteStorage whichever is available for me in the system, so I can pass it to pathfinding?

Daniel Salvadori
@danaugrs
@roman-holovin Could try one of the storage traits
WaDelma
@WaDelma
@torkleyy Makes sense
So that probably could be added to the documentation, because it confused me quite bit
uzkbwza
@uzkbwza

i'm having trouble using the .join() method outside of the System trait implementation block. anyone know how i should fix it?

pardon the ugly code, but here is something that I'm having issues with.
https://pastebin.com/wzURVPS5

the method at line 121 does not work when used in a method for the Ai struct, but it does inside the system's .run() function at line 156. what am i doing wrong? perhaps am I just structuring my code wrong in the first place? should I be approaching this sort of thing in a different way?

Aleksi Juvani
@aleksijuvani
i think you're just missing borrows there
try for (player_entity, target_pos, player) in (&data.entities, &data.positions, &data.players).join()
uzkbwza
@uzkbwza
ahh, thanks. dumb mistake on my part
Aleksi Juvani
@aleksijuvani
oof the saveload api seems like a whole ordeal
i was expecting just to be able to call serialize on the world and be done with it
but this seems to expect that i want to use markers and do some kind of error handling stuff in a trait when i don't care about any of that