Manan6619 Posted September 6, 2022 Share Posted September 6, 2022 (edited) I got tired of Brahmin from settlements having corpses that do not despawn -- especially when I've been killing them intentionally for their meat(I have a pile of like 20 corpses in Sanctuary). So, I've made a script that deletes them after a certain period, including preexisting corpses. It seems to work as intended, but I wanted to ask on here to be sure I'm not doing anything that might have consequences later I can't see yet, or if I'm doing it in an overly-intensive way, etc. I'm a novice with ObScript from NV and have just barely gotten a foothold with Papyrus. Script source: Scriptname DeadSettlementBrahminDespawn:WorkshopBrahminCleanupScript extends Actor {Settlement brahmin will be removed a while after death} int DoOnce = 0 Event OnLoad() if DoOnce == 0 && self.isDead() ;If the Brahmin is already dead when you load the area, mark it for deletion. Only runs once to clean preexisting corpses, not instantly delete fresh corpses because you left the area for a short period) DoOnce = 1 self.DeleteWhenAble() ;this seems like the new "MarkForDelete"? Want to ask about this sometime to be sure. Debug.Notification("Preexisting dead settlement Brahmin successfully deleted.") ;Debug message *should* appear when one unloads the settlement with corpses(thereby deleting them), as that's when it sounded like DeleteWhenAble would execute and allow the rest of the Event to run. endif endEvent Event OnDying(Actor AkKiller) Debug.Notification("Settlement Brahmin killed. Beginning pre-deletion Wait period.") Utility.Wait(12960) ;12,960 seconds. Should be about 3 in-game days. Need to double-check forums about best practices, apparently Wait is a "latent"(more demanding?) function so maybe something else should be used to keep track of that time. self.DeleteWhenAble() endEventTo reiterate the concerns I mentioned in my comments, I'm worried about what the right way is to delete things to make sure it actually frees up as many resources as possible, but also doesn't have the potential to cause crashes or other issues later on. This used to be done with disable and MarkForDelete, but MarkForDelete is gone. I'm also concerned about tracking 12,960 seconds in the Wait function. I've heard some info about Latent functions and them being more demanding, but I'm not versed enough to know what a better substitute would be. Edited September 7, 2022 by Manan6619 Link to comment Share on other sites More sharing options...
IsharaMeradin Posted September 6, 2022 Share Posted September 6, 2022 Instead of using Wait, you may want to consider working with StartTimerGameTime coupled with OnTimerGameTime I do not know what the best method to delete things in FO4 might be. Link to comment Share on other sites More sharing options...
SKKmods Posted September 6, 2022 Share Posted September 6, 2022 Cleaner would to simply do an OnUnload() test with a const script Event OnUnload() If((Self as Actor).IsDead() == True) Self.Disable() Self.Delete()EndIfEndEvent Link to comment Share on other sites More sharing options...
LarannKiar Posted September 7, 2022 Share Posted September 7, 2022 I don't think deleting Brahmins could cause CTDs but you can add an IsCreated() check if you'd like. If IsCreated() == 1 ; If Brahmin is created in-game, not editor placed (so its RefID starts with FF) Disable() Delete() Else ; If editor placed, just disable it Disable() EndIf As far as I remember, the only editor placed Brahmins that can die in settlements are the pack brahmins of traveling merchants like Trashcan Carla. Link to comment Share on other sites More sharing options...
Manan6619 Posted September 7, 2022 Author Share Posted September 7, 2022 (edited) Thank you all for the suggestions.Instead of using Wait, you may want to consider working with StartTimerGameTime coupled with OnTimerGameTime I do not know what the best method to delete things in FO4 might be.I like that the unit of measurement for this is in-game hours instead of real-life seconds, it certainly feels cleaner to use over measuring tens of thousands of seconds. Would you happen to know if I can expect making that change to be less resource-intensive? Cleaner would to simply do an OnUnload() test with a const script Event OnUnload() If((Self as Actor).IsDead() == True) Self.Disable() Self.Delete()EndIfEndEventThis looks good, although I'm worried about corpses disappearing because you ran a couple minutes out from your settlement, cleared a dungeon, and returned in less than one in-game day. It's not critical, but I'd like it to feel like other stuff in the game where it might take a day or two for settlement attackers' bodies to despawn. I don't think deleting Brahmins could cause CTDs but you can add an IsCreated() check if you'd like.If IsCreated() == 1 ; If Brahmin is created in-game, not editor placed (so its RefID starts with FF) Disable() Delete() Else ; If editor placed, just disable it Disable() EndIf As far as I remember, the only editor placed Brahmins that can die in settlements are the pack brahmins of traveling merchants like Trashcan Carla. This is the kind of thing I was looking for regarding deleting references. I think you're right about editor-placed Brahmin in the vanilla game, but I think it's good to have a failsafe in case, say, a mod-added/mod-altered settlement starts with a pre-placed Brahmin, then decides to involve that reference in a script later like manipulating it as part of a quest, or whatever. Edited September 7, 2022 by Manan6619 Link to comment Share on other sites More sharing options...
LarannKiar Posted September 7, 2022 Share Posted September 7, 2022 (edited) Thank you all for the suggestions.Instead of using Wait, you may want to consider working with StartTimerGameTime coupled with OnTimerGameTime I do not know what the best method to delete things in FO4 might be.I like that the unit of measurement for this is in-game hours instead of real-life seconds, it certainly feels cleaner to use over measuring tens of thousands of seconds. Would you happen to know if I can expect making that change to be less resource-intensive? Cleaner would to simply do an OnUnload() test with a const script Event OnUnload() If((Self as Actor).IsDead() == True) Self.Disable() Self.Delete()EndIfEndEventThis looks good, although I'm worried about corpses disappearing because you ran a couple minutes out from your settlement, cleared a dungeon, and returned in less than one in-game day. It's not critical, but I'd like it to feel like other stuff in the game where it might take a day or two for settlement attackers' bodies to despawn. I don't think deleting Brahmins could cause CTDs but you can add an IsCreated() check if you'd like. If IsCreated() == 1 ; If Brahmin is created in-game, not editor placed (so its RefID starts with FF) Disable() Delete() Else ; If editor placed, just disable it Disable() EndIf As far as I remember, the only editor placed Brahmins that can die in settlements are the pack brahmins of traveling merchants like Trashcan Carla. This is the kind of thing I was looking for regarding deleting references. I think you're right about editor-placed Brahmin in the vanilla game, but I think it's good to have a failsafe in case, say, a mod-added/mod-altered settlement starts with a pre-placed Brahmin, then decides to involve that reference in a script later like manipulating it as part of a quest, or whatever. You could try something like this: Scriptname YOURSCRIPTNAME extends Actor Const Event OnUnload() If IsDead() && IsDisabled() == 0 && IsDeleted() == 0 ; for extra safety StartTimerGameTime(5, 555) ; 5 in-game hours EndIf EndEvent Event OnTimerGameTime(int aiTimerID) If Is3DLoaded() == 0 ; not loaded UnregisterForAllEvents() ; unregister script If IsCreated() == 1 ; created in-game Disable() Delete() Else ; editor placed Disable() EndIf Else ; if loaded (e.g., Player reentered the location) ; do nothing, OnUnload() will restart the timer if the conditions are met EndIf EndEvent Event OnWorkshopObjectDestroyed(ObjectReference akActionRef) ; Brahmin scrapped or stored in the workshbench (can't happen in the vanilla game, only with mods...) UnregisterForAllEvents() Disable() ; the game code disables (and in most cases deletes) the object when one scraps/stores it so these are not actually necessary Delete() EndEvent Edited September 7, 2022 by LarannKiar Link to comment Share on other sites More sharing options...
RaidersClamoring Posted September 7, 2022 Share Posted September 7, 2022 The reason Wait() is considered expensive is because it remains in occupation of the thread it was occupying at the time of pausing. Whether this is a big deal or never preferable I don't know. I think as a rule of thumb you should try to have as little overhead as possible. Link to comment Share on other sites More sharing options...
Manan6619 Posted September 7, 2022 Author Share Posted September 7, 2022 The reason Wait() is considered expensive is because it remains in occupation of the thread it was occupying at the time of pausing. Whether this is a big deal or never preferable I don't know. I think as a rule of thumb you should try to have as little overhead as possible.Thank you for the specific insight on that. Part of the idea was to make sure this wouldn't be overly-taxing on the game before potentially sharing it. You could try something like this: <snip> Scriptname YOURSCRIPTNAME extends Actor Const Event OnUnload() If IsDead() && IsDisabled() == 0 && IsDeleted() == 0 ; for extra safety StartTimerGameTime(5, 555) ; 5 in-game hours EndIf EndEvent Event OnTimerGameTime(int aiTimerID) If Is3DLoaded() == 0 ; not loaded UnregisterForAllEvents() ; unregister script If IsCreated() == 1 ; created in-game Disable() Delete() Else ; editor placed Disable() EndIf Else ; if loaded (e.g., Player reentered the location) ; do nothing, OnUnload() will restart the timer if the conditions are met EndIf EndEvent Event OnWorkshopObjectDestroyed(ObjectReference akActionRef) ; Brahmin scrapped or stored in the workshbench (can't happen in the vanilla game, only with mods...) UnregisterForAllEvents() Disable() ; the game code disables (and in most cases deletes) the object when one scraps/stores it so these are not actually necessary Delete() EndEvent Oh, uh, wow. This is above and beyond. The comments are very helpful, and the addition of that third event was good thinking -- I wasn't even thinking about protecting users of mods that allow for the scrapping/storing of actors, they aren't uncommon. Well, I mentioned sharing the completed product, but at this point you've done a great deal of the heavy lifting here. May I use this script for a mod that'll be published here on the Nexus? There's practically nothing with it I'd see the need to change. You'll be credited prominently, and if you allow me to also turn on Donation Points, I'd be glad to grant them mostly(or all!) to you. Link to comment Share on other sites More sharing options...
LarannKiar Posted September 8, 2022 Share Posted September 8, 2022 The reason Wait() is considered expensive is because it remains in occupation of the thread it was occupying at the time of pausing. Whether this is a big deal or never preferable I don't know. I think as a rule of thumb you should try to have as little overhead as possible.Thank you for the specific insight on that. Part of the idea was to make sure this wouldn't be overly-taxing on the game before potentially sharing it. You could try something like this: <snip> Scriptname YOURSCRIPTNAME extends Actor Const Event OnUnload() If IsDead() && IsDisabled() == 0 && IsDeleted() == 0 ; for extra safety StartTimerGameTime(5, 555) ; 5 in-game hours EndIf EndEvent Event OnTimerGameTime(int aiTimerID) If Is3DLoaded() == 0 ; not loaded UnregisterForAllEvents() ; unregister script If IsCreated() == 1 ; created in-game Disable() Delete() Else ; editor placed Disable() EndIf Else ; if loaded (e.g., Player reentered the location) ; do nothing, OnUnload() will restart the timer if the conditions are met EndIf EndEvent Event OnWorkshopObjectDestroyed(ObjectReference akActionRef) ; Brahmin scrapped or stored in the workshbench (can't happen in the vanilla game, only with mods...) UnregisterForAllEvents() Disable() ; the game code disables (and in most cases deletes) the object when one scraps/stores it so these are not actually necessary Delete() EndEvent Oh, uh, wow. This is above and beyond. The comments are very helpful, and the addition of that third event was good thinking -- I wasn't even thinking about protecting users of mods that allow for the scrapping/storing of actors, they aren't uncommon. Well, I mentioned sharing the completed product, but at this point you've done a great deal of the heavy lifting here. May I use this script for a mod that'll be published here on the Nexus? There's practically nothing with it I'd see the need to change. You'll be credited prominently, and if you allow me to also turn on Donation Points, I'd be glad to grant them mostly(or all!) to you. Sure you can use this script however you like. And no it's not necessary to send DPs to me, it's up to you. :) Link to comment Share on other sites More sharing options...
Recommended Posts