Jump to content

Question on persistence


Recommended Posts

Hello all!

 

I've seen a lot of stuff around about things remaining persistent if they're a script property or a reference alias.

 

My question is, for an actor that I spawn in the following way (with a property and thrown into an alias), will they remain persistent after they die, or have I obliterated them from memory completely after death?

 

ScriptA is on an activator button for testing

ScriptB is on QuestB to allow access to a RefCollectionAlias property called RefCollectionB

ScriptC is on a RefCollectionAlias called RefCollectionB on QuestB

Scriptname ScriptA extends ObjectReference

ScriptB property QuestB auto
Actorbase property LvlRaider auto

Event OnActivate(ObjectReference akRef)

    actor TheRaider = self.PlaceActorAtMe(LvlRaider)
    QuestB.RefCollectionB.AddRef(TheRaider)

EndEvent
Scriptname ScriptB extends Quest

RefCollectionAlias Property RefCollectionB Auto
Scriptname ScriptC extends RefCollectionAlias

Event OnDeath(ObjectReference akSenderRef, Actor akKiller)
    RemoveRef(akSenderRef)
    akSenderRef.delete()
    akSenderRef = none
endEvent

When I tested this with a RefCollectionB.GetCount() it returned 0 as I hoped and when I tested with FindRandomActorFromRef it returned 0 as well.

Thank you for your help guys and girls!

Edited by shatsnazzle
Link to comment
Share on other sites

I have had some fun with volumes (64 to 128) of spawned live and killed NPCs:

 

Live NPCs in a reference/collection alias and/or script ObjectReference property will persist whilst in the alias/property and the quest is running, even when 3D unloads over uGridsToLoad or fLODFadeOutMultActors threshold from the player.

 

Live NPCs removed from a reference/collection alias and/or script ObjectReference property can do really strange stuff when 3D unloads over uGridsToLoad or fLODFadeOutMultActors threshold from the player (I have posted youtubes on this) and eventually disappear.

 

Dead NPCs in a reference/collection alias and/or script ObjectReference property will persist whilst in the alias and the quest is running, even when there are more than iRemoveExcessDeadCount scavenge threshold and/or when 3D unloads over uGridsToLoad or fLODFadeOutMultActors threshold from the player.

 

Dead NPCs removed from a reference/collection alias and/or script ObjectReference property will be automatically disabled and cleaned up when more than iRemoveExcessDeadCount are around either in or out of the 3D loaded area.

 

Now for the strange but: Live NPCs in an alias/property that die when on the 3d and AI activity processing boundaries of uGridsToLoad / fLODFadeOutMultActors (standard around 15,000 game units) from range tweaked projectiles or npc/npc hostility can report both alive and dead states and generate ambigious alias collection counts. More youtube videos posted on that.

 

 

TL;DR if you clear an NPC from Alias and ObjectReference property, it will eventually be removed by a game engine scavenging process dead or alive depending on threshold counts and 3d status.

 

When dealing with volumes of spawned NPCs I would suggest managing the reference release, disable and delete as a scavenge process on a regular timer in script (for you timer haters: at high volumes a flood of OnDeath events can stack and be lost leaving dirty hanging references, so only a timer tick will do).

Link to comment
Share on other sites

SKK50 thank you again as always! I just watched your vids, that poor dead NPC stuck in limbo with a quest marker on him.

 


When dealing with volumes of spawned NPCs I would suggest managing the reference release, disable and delete as a scavenge process on a regular timer in script (for you timer haters: at high volumes a flood of OnDeath events can stack and be lost leaving dirty hanging references, so only a timer tick will do).

 

Instead of an OnDeath() event would it be more thorough if I throw something like this on the quest?

Event OnInit()
    StartTimerGameTime(24, someIndex)
EndEvent

Event OnTimerGameTime(int Index)
   StartTimerGameTime(24, someIndex)
   int counter = RefCollectionB.GetCount() - 1
   while counter >= 0
       if RefCollectionB.GetAt(counter).IsDead()
             actor DeleteMe = RefCollectionB.GetAt(counter)
             RefCollectionB.GetAt(counter).RemoveRef
             DeleteMe.delete()
             DeleteMe = none
        endif
      counter = counter - 1
     endwhile
EndEvent

Should I disable() before I delete() and should I set it = none afterwards? Or is this overkill?

 

And something I've always been a little unclear on:

How do I clear something from being a script property?

If on scriptA above I added a line:

LvlRaider = none

would that clear the property in the manner that I am looking for? Or should I just set the actor "TheRaider" = none?

Or is it unnecessary since ActorBase is not an ObjectReference property?

Edit: nevermind on the last part I think I found the answer right under my nose in the wiki:

 

"When a script property is pointed at a reference in the editor..
..you should not use properties to point at references directly."

and the ActorBase is a Form so I think I'm in the clear there. Or am I mistaken?

 

Thank you again!! :smile:

Edited by shatsnazzle
Link to comment
Share on other sites

All looks good, best to use realtime intervals for system management cadence as players can run game timescale as low as 2:1 rather than 20:1 which may subvert your cycles. 24 game seconds is agressive at only 1 default realtime second, 30 to 60 realtime seconds is my default as a high END player can sprint 15 to 30,000 game units from a stuck or dead npc in that time which is a reasonable 3d unload window.

 

I prefer to disable and then delete as its a better UX visual pop if it happens in player line of sight. It may even complete faster due to synch/asynch calls ... I misplaced those test notes.

 

Edit: to finish as your deleteme ref is defined in the while loop scope it should only last in that code block, but, its good practice to none refs incase they get moved to a wider scope when your not concentrating.

Edited by SKK50
Link to comment
Share on other sites

Some time ago I saw somewhere that OnDying works better that OnDeath. Don't know if it's true, but I used OnDying and it seemed to work for me.

Depending on the purpose you can also use event OnUnload. Despite of it's description, it works pretty well and used in many vanilla scripts. Then your actor will be always deleted when he can't be seen by player. Another way is to use player events to clear your collection (i.e. OnPlayerSleepStop).

 

You don't have anything in your script to keep the NPC persistent apart from the Alias. But as soon as you remove the NPC ftrom collection, he will stop to be persitent.

When you create your Actor or ObjectReference property inside a function or event, it does not create persitence. But if you create it ouside a function , the reference will be persintent untill you clear your property

Creation kit base ID don't make anything persistent. Only references ID do.

Example:

Script MyScriptA  
Form Property  MyObject Auto Const
ObjectReference  MyRef  ; A property outside functions and events makes it possible to  access  it from different functions and events, but then you have to clear to it to avoid persitence

Event OnActivate(ObjectReference akActionRef)
    MyRef = PlaceAtMe(MyObject, 1)
EbdEvent

Event OnUnload()
  If MyRef
      MyRef.Delete()
      MyRef = none ; clear the property so the object  don't get stuck in the world 
  EndIf
EndEvent
Script MyScriptB  
    
Event OnActivate(ObjectReference akActionRef)
  ObjectReference  MyRef = PlaceAtMe(MyObject, 1) ; there is no need to clear anything in this case
  MyRef.Disable()
EbdEvent
Edited by kitcat81
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...