Log in to reply
 

Can you intercept Insert before Reset Scripts takes action?



  • I am working on a mod (not my ground effects mod) that involves looped particles. The problem with them, is that they persist until cleaned up. If you spawn a looped particle and then hit Insert, you don't get chance to clean up the existing ones.

    If you try to use REMOVE_PARTICLE_FX_IN_RANGE, it doesn't work on them because they weren't spawned during this instance of the scripts running, so no ID has been generated. I had a significant crash last night that I am concerned is caused by a build up of these persistent looped particles eventually overflowing the memory buffer.

    Ideally, Reset Scripts should have been a two stage process. Hitting Insert should generate an event that you could utilise to perform any cleanup processes and then next frame the scripts would reset but that's not how it works... I tried checking the Insert key to see what happens and it registers after the reset has been performed.

    So does anyone know of a way of getting this early warning at all?



  • You're using cpp, or c#?

    c#

    • Script.Aborted

    don't know about cpp :shrug:



  • @sollaholla I'm using C#... I will take a look at that, thank you.



  • @LeeC2202 It's the same as the tick event, but it's called while the script's thread is exiting. (I bolden the while because it's important to ensure there's no errors in that method or bad Juju will happen)



  • @sollaholla I didn't know that existed at all... these sodding looped particles are a pain in the backside. :D

    All I need to do is a REMOVE_PARTICLE_FX_IN_RANGE and I don't think that can generate any errors... hopefully. I guess I'll soon find out. :slight_smile:



  • @LeeC2202 Yeah, but don't looped ptfx have handles? Try these classes on for size:

    public class PTFXNonLooped
    {
        public PTFXNonLooped(string fxName, string asset)
        {
            FxName = fxName;
            Asset = asset;
        }
        public PTFXNonLooped(string fxName, string asset, Color color) : this(fxName, asset)
        {
            Color = color;
        }
    
        public string FxName { get; }
    
        public string Asset { get; }
    
        public Color Color { get; set; }
    
        public bool IsLoaded => Function.Call<bool>(Hash.HAS_NAMED_PTFX_ASSET_LOADED, Asset);
    
        public void Request()
        {
            if (IsLoaded) return;
            Function.Call(Hash.REQUEST_NAMED_PTFX_ASSET, Asset);
        }
    
        public int Play(Vector3 position, Vector3 rotation, float scale)
        {
            Function.Call(Hash._SET_PTFX_ASSET_NEXT_CALL, Asset);
            var handle = Function.Call<int>(Hash.START_PARTICLE_FX_NON_LOOPED_AT_COORD, FxName, position.X, position.Y, position.Z,
                rotation.X, rotation.Y, rotation.Z, scale, false, false, false);
            Function.Call(Hash.SET_PARTICLE_FX_NON_LOOPED_COLOUR, Color.R, Color.G, Color.B);
            Function.Call(Hash.SET_PARTICLE_FX_NON_LOOPED_ALPHA, Color.A);
            return handle;
        }
    }
    
    public class PTFXLooped : PTFXNonLooped, IHandleable
    {
        private Color _color;
    
        public PTFXLooped(string fxName, string asset) : base(fxName, asset) { }
    
        public PTFXLooped(string fxName, string asset, Color color) : this(fxName, asset)
        {
            _color = color;
        }
    
        public int Handle { get; private set; } = -1;
    
        public new Color Color
        {
            get { return _color; }
            set
            {
                Function.Call(Hash.SET_PARTICLE_FX_LOOPED_COLOUR, Handle, (float) Color.R / 255, (float) Color.G / 255,
                    (float) Color.B / 255, 0);
                Function.Call(Hash.SET_PARTICLE_FX_LOOPED_ALPHA, Handle, (float)Color.A / 255);
                _color = value;
            }
        }
    
        public new int Play(Vector3 position, Vector3 rotation, float scale)
        {
            if (Handle != -1) return Handle;
            Function.Call(Hash._SET_PTFX_ASSET_NEXT_CALL, Asset);
            return Handle = Function.Call<int>(Hash.START_PARTICLE_FX_LOOPED_AT_COORD, FxName, position.X, position.Y,
                position.Z, rotation.X, rotation.Y, rotation.Z, scale, false, false, false, false); ;
        }
    
        public int Play(Entity entity, int boneIndex, Vector3 offset, Vector3 rotation, float scale)
        {
            if (Handle != -1) return Handle;
            Function.Call(Hash._SET_PTFX_ASSET_NEXT_CALL, Asset);
            return Handle = Function.Call<int>(Hash._START_PARTICLE_FX_LOOPED_ON_ENTITY_BONE, FxName, entity, offset.X, offset.Y,
                offset.Z, rotation.X, rotation.Y, rotation.Z, boneIndex, scale, false, false, false, false);
        }
    
        public bool Exists()
        {
            return Function.Call<bool>(Hash.DOES_PARTICLE_FX_LOOPED_EXIST, Handle);
        }
    
        public void Remove()
        {
            Function.Call(Hash.REMOVE_PARTICLE_FX, Handle, 1);
            Handle = -1;
        }
    
        public void Stop()
        {
            Function.Call(Hash.STOP_PARTICLE_FX_LOOPED, Handle, 1);
            Handle = -1;
        }
    }
    

    I just wrote it how I'd imagine it looks in RAGE. There's some methods missing for NonLooped but you get the idea ;)



  • @sollaholla Yeah, for the ground effects mod, I actually built a proper particle handling class but this other mod is that simple, I didn't bother. A single particle is only ever used, so it's all handled by simple function calls.

    The problem is, that if one escapes the cleanup, it doesn't have an ID, but the effect is still present, so you can't remove it.



  • @LeeC2202 Ohhh, I see. Then yeah your best bet is probably REMOVE_PARTICLE_FX_IN_RANGE like you said.



  • @sollaholla It turned out that REMOVE_PARTICLE_FX_IN_RANGE didn't work. So what I ended up doing, was setting a flag in the Script.Aborted function and the creation process would only occur with that flag in the right condition.

    That means now that when the effect is removed in the aborting process, the creation process can't jump and re-create it because the flag won't let it. That was the critical factor, so that simple event has enabled me to solve the problem.

    When you get out of the vehicle, the effect was removed anyway, so pressing insert whilst on-foot wasn't a problem. It was a bit like a juggling script where you pressed reset while three balls were in the air and suddenly had six to deal with. :D

    Thank you again, your help has been invaluable. :thumbsup:


Log in to reply
 

Looks like your connection to GTA5-Mods.com Forums was lost, please wait while we try to reconnect.