ParticleData's influencer's data

Issue #189 open
NemesisMate created an issue

The current ParticleData has all data in a "raw" manner (all possible attributes that a particle can have, are already declared). If an influencer wants to store custom data, it can't, there is no much space to play with. On older versions, there was a Data Map, and the get/setData that allowed an influencer to store new data values. It would be great to have to have that option back (with a hashmap or an array of objects, like Spatial's controls), but lazily instantiated.

Comments (21)

  1. Aliaksandr Brui repo owner

    I thought about this, the "raw" manner is a better option if you need to have the best performance :( Are you going to make your own influencers?

  2. NemesisMate reporter

    Yes, currently I was about to make an influencer. About the performance, that's why I suggest the lazy initialization, so it only affects the cases where it is used.

  3. Aliaksandr Brui repo owner

    your option provides very slow access to the data, but I will think about what we can do for this :)

  4. NemesisMate reporter

    I dont think a data map would be slow, at least with a custom fast-implementation. For example, the data declaration could be with:

    int declareData();
    

    And that int returned would be the data id to retrieve/set the data with:

    <T> T getData(int dataId);
    void setData(int dataId, Objec dataValue);
    

    So, internally, it could be a simple array when accessing/setting per frame:

    Object[] values;
    

    So, finally you would have something like:

    private Object[] values;
    
    public int declareData() {
        values = <COPY_+1>;
    
        return values.length - 1;
    }
    
    public void setData(int dataId, Object dataValue) {
        values[dataId] = dataValue;
    }
    
    public <T> T getData(int dataId) {
        return values[dataId];
    }
    
  5. NemesisMate reporter

    Well, the problem with that implementation is that it isn't as fast as the one with the array (commented above). I can also see you aren't doing a lazy initialization (what makes sense if your objective is to modularize the full "raw" particle data. But again, what about perf?, wouldn't it be better the array alternative?. It is a little bit less "beautiful" but also have it advantages. It is not just performance, but also reusing the same name on another influencer. If two different persons implements two influencers and set the same name, those would clash if put together (and so, difficulting the share). What do you think about all that matter?

  6. NemesisMate reporter

    Well, the current implementation seems to be faster, but I can't fully understand why the need of a static "reserve" and a non-static one.

    Having both is just over-complicating things. Without the non-static, it would work the same way (It would create always the full sized array for all static-reserved data). So, IMO, or there is a static-reservation (so every particleData will be ready/reserved for every available influencer) or a per-object reservation (so every data will be optimized for the current influencers being used). However, the current implementation is kind of weird or there is something I don't get.

    Another thing to have in mind, is that the static implementation is very limiting. It is causing problems when using the same influencer multiples times on the same ParticleData.

    My suggestion, so, is to just make a per-object reservation, just like the code I proposed (not statics), so you declare them when initializing the influencers.

  7. NemesisMate reporter

    Another point I see that is overcomplicating the class itself, is separating the data per int, float and object. Now that I think, it would be even better if an influencer could only reserve 1 slot. Every influencer can create it data structure (maybe that implements InfluencerData) and this data structure is the one they use on the ParticleData. This particle data could even be passed on the influencer initializer method. For example:

    class ColorInfluencerData implements InfluencerData {
       Color color1;
       Color color2;
    }
    

    And so, in the influencer initializer:

    class ColorInfluencer implements Influencer<ColorInfluencerData> {
        ...
        void initialize(ParticleData particleData, ColorInfluencerData influencerData) {
        }
        ....
    }
    

    The particle data could even be removed from there (but maybe it is useful to access other influencers if present).

    This way, the reservation on the ParticleData would be managed by the particle emitter (the one that has the influencers) and forces the implementing developer to use it in a more standard and easy to understand manner, avoiding too miss-conceptions without sacrificing in terms or efficiency (it allows even for more control: the data array size would be much more limited, for example).

  8. Aliaksandr Brui repo owner

    @NemesisMate how your implementation will work in the case when we change the list of influencers on runtime for a particle emitter?

  9. Aliaksandr Brui repo owner

    @NemesisMate

    "Another point I see that is overcomplicating the class itself, is separating the data per int, float and object"

    have you seen my examples? I used data classes there.

  10. Aliaksandr Brui repo owner

    @NemesisMate

    "Another thing to have in mind, is that the static implementation is very limiting. It is causing problems when using the same influencer multiples times on the same ParticleData." any examples of these problems? I don't think so.

  11. NemesisMate reporter

    "how your implementation will work in the case when we change the list of influencers on runtime for a particle emitter?" It will just work, it doesn't change anything if the influencers are changed at runtime or not.

    "ave you seen my examples? I used data classes there." Yes, I've seen the examples. What I meant is the class itself, not the usage of it (but anyway, the InfluenceData proposal is even simpler to use)

    "any examples of these problems? I don't think so." Well, looking at the code, if you set two ColorInfluencer to the same particledata, they will both override the same ParticleData Id, as they are using a static reserved id.

  12. Aliaksandr Brui repo owner

    @NemesisMate

    "Another thing to have in mind, is that the static implementation is very limiting. It is causing problems when using the same influencer multiples times on the same ParticleData." Hm, then I think my understanding of your implementation is wrong :(

    "Well, looking at the code, if you set two ColorInfluencer to the same particledata, they will both override the same ParticleData Id, as they are using a static reserved id." Are you sure that it is valid use-case? because it can't work at all.

  13. NemesisMate reporter

    Well, It depend on the influencer. For the current color influencers it may not work, but for a direction influencer, for example, you could want to add multiple ones (as if you were giving different forces). I think that while for all current influencers it would not make a lot of sense, maybe it would allow more influencer types (conditional influencers?). Maybe there could be some influencers where you want something to happen based on the current time of emission, so you would have a new way of configuration (eg: InfluencerByTime, an influencer that activates one or other sub-influencers based on the time of the emission. It could have, for example, 3 sub-influencers of the color type, and based on the time, it would activate one or the other).

  14. Aliaksandr Brui repo owner

    @NemesisMate I see..., but I still don't understand your implementation, so I will continue to think about a new implementation for your requirements.

  15. NemesisMate reporter

    The implementation isn't that hard. A working implementation is the posted above:

    private Object[] values;
    
    public int declareData() {
        values = <COPY_+1>;
    
        return values.length - 1;
    }
    
    public void setData(int dataId, Object dataValue) {
        values[dataId] = dataValue;
    }
    
    public <T> T getData(int dataId) {
        return values[dataId];
    }
    

    But, what I suggested after is to not allow influencers to set more than 1 data. So, they can only reserve 1 slot and they manage this slot as they like (with the data structure they want). For that, there are many ways to proceed:

    1. There is no control on which data type they declare. For this, a set containing the influencers that had already reserved their slot sould be created, so for reserving data, you also must specify the THIS influencer (this could be easily bypassed)
    2. There is an InfluencerData interface that must be implemented by all those data structures. Those are initialized, however, in the ParticleEmitterNode and passed to the influencer in the influencer's initialize method. To initialize this data there are two possible ways:

      1. Reflection with the structure class that implements the InfluencerData
      2. Adding a InfluencerData createData() method to the Influencer interface.
  16. Log in to comment