LeahTheUnknown Posted June 2, 2018 Share Posted June 2, 2018 I'm working on a version of my Wave Spawner that sends increasingly harder enemies at you, and I just wondered if anyone would look over my script and maybe find any flaws, recursions, things the compiler may have missed. It works most of the time (sometimes it delays spawning the enemies, but I think that has to do with script priority). Scriptname _gkx_battlespawnerscript extends ObjectReference Group SpawnLists LeveledActor[] Property VeryEasyArray Auto LeveledActor[] Property EasyArray Auto LeveledActor[] Property NormalArray Auto LeveledActor[] Property HardArray Auto LeveledActor[] Property VeryHardArray Auto LeveledActor[] Property BossArray Auto EndGroup Group Messages Message Property StartMenu Auto Message Property WavesStarting Auto EndGroup Function SpawnVeryEasy(Int NumToSpawn, Int DelayTimer) Int Rand = Utility.RandomInt(1, VeryEasyArray.Length) LeveledActor Spawn = VeryEasyArray[Rand] PlaceAtMe(Spawn, NumToSpawn) Int Delay = DelayTimer * 10 If Delay > 180 Delay = 180 EndIf Debug.Notification("Next wave in " + Delay + " seconds.") Utility.Wait(Delay) EndFunction Function SpawnEasy(Int NumToSpawn, Int DelayTimer) Int Rand = Utility.RandomInt(1, EasyArray.Length) LeveledActor Spawn = EasyArray[Rand] PlaceAtMe(Spawn, NumToSpawn) Int Delay = DelayTimer * 15 If Delay > 180 Delay = 180 EndIf Debug.Notification("Next wave in " + Delay + " seconds.") Utility.Wait(Delay) EndFunction Function SpawnNormal(Int NumToSpawn, Int DelayTimer) Int Rand = Utility.RandomInt(1, NormalArray.Length) LeveledActor Spawn = NormalArray[Rand] PlaceAtMe(Spawn, NumToSpawn) Int Delay = DelayTimer * 20 If Delay > 180 Delay = 180 EndIf Debug.Notification("Next wave in " + Delay + " seconds.") Utility.Wait(Delay) EndFunction Function SpawnHard(Int NumToSpawn, Int DelayTimer) Int Rand = Utility.RandomInt(1, HardArray.Length) LeveledActor Spawn = HardArray[Rand] PlaceAtMe(Spawn, NumToSpawn) Int Delay = DelayTimer * 30 If Delay > 180 Delay = 180 EndIf Debug.Notification("Next wave in " + Delay + " seconds.") Utility.Wait(Delay) EndFunction Function SpawnVeryHard(Int NumToSpawn, Int DelayTimer) Int Rand = Utility.RandomInt(1, VeryHardArray.Length) LeveledActor Spawn = VeryHardArray[Rand] PlaceAtMe(Spawn, NumToSpawn) Int Delay = DelayTimer * 40 If Delay > 240 Delay = 240 EndIf Debug.Notification("Next wave in " + Delay + " seconds.") Utility.Wait(Delay) EndFunction Function SpawnBoss(Int NumToSpawn, Int DelayTimer) Int Rand = Utility.RandomInt(1, BossArray.Length) LeveledActor Spawn = BossArray[Rand] PlaceAtMe(Spawn, NumToSpawn) Int Delay = DelayTimer * 60 If Delay > 300 Delay = 300 EndIf Debug.Notification("Next wave in " + Delay + " seconds.") Utility.Wait(Delay) EndFunction Int WaveNumber Int WaveGroupNum Function StartSpawning() While IsPowered() While WaveGroupNum <= 6 If WaveGroupNum == 1 SpawnVeryEasy(WaveNumber, WaveNumber) ElseIf WaveGroupNum == 2 SpawnEasy(WaveNumber, WaveNumber) ElseIf WaveGroupNum == 3 SpawnNormal(WaveNumber, WaveNumber) ElseIf WaveGroupNum == 4 SpawnHard(WaveNumber, WaveNumber) ElseIf WaveGroupNum == 5 SpawnVeryHard(WaveNumber, WaveNumber) ElseIf WaveGroupNum == 6 SpawnBoss(WaveNumber, WaveNumber) EndIf WaveGroupNum += 1 EndWhile WaveNumber += 1 WaveGroupNum = 1 EndWhile EndFunction Event OnPowerOn(ObjectReference akGenerator) Int StartChoice = StartMenu.Show() If StartChoice == 1 WaveGroupNum = 1 WaveNumber = 1 EndIf WavesStarting.Show() StartSpawning() EndEvent Link to comment Share on other sites More sharing options...
FatsackTony1 Posted June 3, 2018 Share Posted June 3, 2018 1 thing, champolions decompiler changes Events to Functions, so make sure anything you've cannibilzed using that is an event not a function if it begins with On. Also, you can download notepad++ and a format set for it for papyrus, to help you identify mistakes. An output log would also help you narrow down what function and what line is throwing the error. (actually that should do that when you try to compile in the CK). Other than that, what is your probelm? Does it just not work sometimes? does it slow to a crawl? does it CTD? whats going on that it is not working correctly.. Link to comment Share on other sites More sharing options...
LeahTheUnknown Posted June 3, 2018 Author Share Posted June 3, 2018 The script compiles fine, no errors. Just that in-game, I sometimes get the notification that another wave will spawn in x seconds, and nothing spawns. Then when it is time for the next wave to spawn, it spawns both. So, I have no error logs, just a disobedient activator. Link to comment Share on other sites More sharing options...
Evangela Posted June 3, 2018 Share Posted June 3, 2018 There's a lot going on that is slowing your script down. Optimization is needed but you need to know first what papyrus is doing with your script in order to know what to optimize. For Event OnPower() - add these two functionsDebug.StartStackProfiling() ; before the actual code Debug.StopStackProfiling() ; after the actual code You'll get a new folder called Profiling, Here's what the folder address should look like: Documents\My Games\Fallout 4\Logs\Script\Profiling the "bEnableProfiling" flag in the "[Papyrus]" section of the ini file to be set to 1 PUSH = Function is calledPOP = Function has finishedQUEUE_PUSH = Function is waiting its turnQUEUE_POP = Function is waiting to finish Link to comment Share on other sites More sharing options...
payl0ad Posted June 3, 2018 Share Posted June 3, 2018 Utility.Wait(Delay)Disclaimer: I don't have a clue about the inner workings and performance mechanisms of Papyrus. However, somewhere on the wiki I remember reading that using Utility.Wait is bad practice and should be replaced with custom timers and OnTimer events. Link to comment Share on other sites More sharing options...
LeahTheUnknown Posted June 3, 2018 Author Share Posted June 3, 2018 Ok, I did the stack profiling for a one-wave (six spawns) run through and got the following result. I have no idea how to interpret it, however. To my untrained eye, it looks like everything is working normally (queue_push, push, pop, etc) I opted for using Utility.Wait because the delays are so variable, writing all those timer scripts would be a pain in the ass. Reveal hidden contents Stack_321731 log opened (PC-64)86869555^START^32173186869695^POP^321731^1^None^debug..StartStackProfiling86869801^QUEUE_PUSH^321731^1^ (2F001741)^message.??.Show86902717^PUSH^321731^1^ (2F001741)^message..Show89213625^POP^321731^1^ (2F001741)^message..Show89214296^QUEUE_PUSH^321731^1^ (2F001742)^message.??.Show89249862^PUSH^321731^1^ (2F001742)^message..Show90820612^POP^321731^1^ (2F001742)^message..Show90821249^PUSH^321731^1^ (FF0134C1)^_gkx_battlespawnerscript..StartSpawning90821264^QUEUE_PUSH^321731^2^ (FF0134C1)^_gkx_battlespawnerscript.??.IsPowered90856755^PUSH^321731^2^ (FF0134C1)^ObjectReference..IsPowered90856782^POP^321731^2^ (FF0134C1)^ObjectReference..IsPowered90859080^QUEUE_PUSH^321731^2^ (FF0134C1)^_gkx_battlespawnerscript.??.Is3DLoaded90891646^PUSH^321731^2^ (FF0134C1)^ObjectReference..Is3DLoaded90891667^POP^321731^2^ (FF0134C1)^ObjectReference..Is3DLoaded90893880^PUSH^321731^2^ (FF0134C1)^_gkx_battlespawnerscript..SpawnVeryEasy90893903^QUEUE_PUSH^321731^3^None^utility.??.RandomInt90924601^PUSH^321731^3^None^utility..RandomInt90924611^POP^321731^3^None^utility..RandomInt90926863^QUEUE_PUSH^321731^3^ (FF0134C1)^_gkx_battlespawnerscript.??.PlaceAtMe90958256^PUSH^321731^3^ (FF0134C1)^ObjectReference..PlaceAtMe90959456^POP^321731^3^ (FF0134C1)^ObjectReference..PlaceAtMe90960517^QUEUE_PUSH^321731^3^None^debug.??.Notification90992446^PUSH^321731^3^None^debug..Notification90992463^POP^321731^3^None^debug..Notification90994683^QUEUE_PUSH^321731^3^None^utility.??.Wait91026932^PUSH^321731^3^None^utility..Wait101033147^POP^321731^3^None^utility..Wait101035703^POP^321731^2^ (FF0134C1)^_gkx_battlespawnerscript..SpawnVeryEasy101035760^PUSH^321731^2^ (FF0134C1)^_gkx_battlespawnerscript..SpawnEasy101035789^QUEUE_PUSH^321731^3^None^utility.??.RandomInt101068837^PUSH^321731^3^None^utility..RandomInt101068852^POP^321731^3^None^utility..RandomInt101071873^QUEUE_PUSH^321731^3^ (FF0134C1)^_gkx_battlespawnerscript.??.PlaceAtMe101100838^PUSH^321731^3^ (FF0134C1)^ObjectReference..PlaceAtMe101103794^POP^321731^3^ (FF0134C1)^ObjectReference..PlaceAtMe101105249^QUEUE_PUSH^321731^3^None^debug.??.Notification101136223^PUSH^321731^3^None^debug..Notification101136251^POP^321731^3^None^debug..Notification101138146^QUEUE_PUSH^321731^3^None^utility.??.Wait101170870^PUSH^321731^3^None^utility..Wait116182558^POP^321731^3^None^utility..Wait116186500^POP^321731^2^ (FF0134C1)^_gkx_battlespawnerscript..SpawnEasy116186600^PUSH^321731^2^ (FF0134C1)^_gkx_battlespawnerscript..SpawnNormal116186646^QUEUE_PUSH^321731^3^None^utility.??.RandomInt116218894^PUSH^321731^3^None^utility..RandomInt116218917^POP^321731^3^None^utility..RandomInt116221920^QUEUE_PUSH^321731^3^ (FF0134C1)^_gkx_battlespawnerscript.??.PlaceAtMe116254940^PUSH^321731^3^ (FF0134C1)^ObjectReference..PlaceAtMe116258565^POP^321731^3^ (FF0134C1)^ObjectReference..PlaceAtMe116260715^QUEUE_PUSH^321731^3^None^debug.??.Notification116289030^PUSH^321731^3^None^debug..Notification116289047^POP^321731^3^None^debug..Notification116290893^QUEUE_PUSH^321731^3^None^utility.??.Wait116323119^PUSH^321731^3^None^utility..Wait136337123^POP^321731^3^None^utility..Wait136340114^POP^321731^2^ (FF0134C1)^_gkx_battlespawnerscript..SpawnNormal136340159^PUSH^321731^2^ (FF0134C1)^_gkx_battlespawnerscript..SpawnHard136340178^QUEUE_PUSH^321731^3^None^utility.??.RandomInt136368083^PUSH^321731^3^None^utility..RandomInt136368093^POP^321731^3^None^utility..RandomInt136372008^QUEUE_PUSH^321731^3^ (FF0134C1)^_gkx_battlespawnerscript.??.PlaceAtMe136405319^PUSH^321731^3^ (FF0134C1)^ObjectReference..PlaceAtMe136407134^POP^321731^3^ (FF0134C1)^ObjectReference..PlaceAtMe136410158^QUEUE_PUSH^321731^3^None^debug.??.Notification136442999^PUSH^321731^3^None^debug..Notification136443029^POP^321731^3^None^debug..Notification136446937^QUEUE_PUSH^321731^3^None^utility.??.Wait136479026^PUSH^321731^3^None^utility..Wait166503701^POP^321731^3^None^utility..Wait166506433^POP^321731^2^ (FF0134C1)^_gkx_battlespawnerscript..SpawnHard166506493^PUSH^321731^2^ (FF0134C1)^_gkx_battlespawnerscript..SpawnVeryHard166506556^QUEUE_PUSH^321731^3^None^utility.??.RandomInt166536879^PUSH^321731^3^None^utility..RandomInt166536894^POP^321731^3^None^utility..RandomInt166540088^QUEUE_PUSH^321731^3^ (FF0134C1)^_gkx_battlespawnerscript.??.PlaceAtMe166572206^PUSH^321731^3^ (FF0134C1)^ObjectReference..PlaceAtMe166575729^POP^321731^3^ (FF0134C1)^ObjectReference..PlaceAtMe166577387^QUEUE_PUSH^321731^3^None^debug.??.Notification166604971^PUSH^321731^3^None^debug..Notification166604992^POP^321731^3^None^debug..Notification166607774^QUEUE_PUSH^321731^3^None^utility.??.Wait166640696^PUSH^321731^3^None^utility..Wait402405048^POP^321731^3^None^utility..Wait402407990^POP^321731^2^ (FF0134C1)^_gkx_battlespawnerscript..SpawnVeryHard402408054^PUSH^321731^2^ (FF0134C1)^_gkx_battlespawnerscript..SpawnBoss402408083^QUEUE_PUSH^321731^3^None^utility.??.RandomInt402440006^PUSH^321731^3^None^utility..RandomInt402440026^POP^321731^3^None^utility..RandomInt402442677^QUEUE_PUSH^321731^3^ (FF0134C1)^_gkx_battlespawnerscript.??.PlaceAtMe402471728^PUSH^321731^3^ (FF0134C1)^ObjectReference..PlaceAtMe402477524^POP^321731^3^ (FF0134C1)^ObjectReference..PlaceAtMe402479431^QUEUE_PUSH^321731^3^None^debug.??.Notification402502795^PUSH^321731^3^None^debug..Notification402502811^POP^321731^3^None^debug..Notification402505037^QUEUE_PUSH^321731^3^None^utility.??.Wait402537053^PUSH^321731^3^None^utility..Wait Link to comment Share on other sites More sharing options...
payl0ad Posted June 3, 2018 Share Posted June 3, 2018 On 6/3/2018 at 12:18 PM, GenghisKhanX said: I opted for using Utility.Wait because the delays are so variable, writing all those timer scripts would be a pain in the ass. Again, I'm not a professional but from my limited knowledge using that function should actually block the VM or at least its thread, consuming CPU time while the timer is handled by engine-internal logic and probably *way* faster than a Papyrus function call. Link to comment Share on other sites More sharing options...
SKKmods Posted June 3, 2018 Share Posted June 3, 2018 (edited) Utility.Wait doesn't seem to consume any resources I can measure, it just puts a flag on the event queue to trigger at a future time, same a Timer. If you have a simple single path script that isn't referenced or state changed by any external event driven stuff they are fine for a short term break in a function. Infact for short durations I have found timer return times to be less reliable (+10% variance) than wait return times (+2% variance) running parallel scripts. EDIT: @GenghisKhanX Get those Utility.Wait(Delay) out of the subsidiary spawn functions and have one in the StartSpawning() While loop. In this case StartSpawning() starting as a timer may be better as it deoends on an external factor (power) and can be cancelled directly on power off rather than waiting for the wait to return IUSWIM. Edited June 3, 2018 by SKK50 Link to comment Share on other sites More sharing options...
Recommended Posts