Critterspawn bug (possible fix)

Post » Wed Feb 27, 2013 11:40 am

Just posting this here incase anyone was having this problem. So with Dragonborn I suddenly was having my log spammed by the critterspawn..and scripts that inherit it. So, I believe I found a bug. Not only that, actual ingame models(bugs, fish) had began multiplying at a rapid pace in the Raven Rock area, causing stutter, and bloating my save endlessly.

The fix is in the SpawnCritter() function. In the original script the else condition did not have a return value. This was a problem because the function expects a boolean returned. Instead Bethesda did some odd thing by setting a variable instead of simply returning false as well. So i inserted a 'return false'. This seemed to have fixed the endless loop the script was stuck in.

Hopefully it eliminates the bloat..initial testing has been positive. Did not see log spamming using a recent save. If anyone wants to test let me know how it turns out, please use a 'test' save if you do.

scriptName CritterSpawn extends ObjectReferenceimport Critterimport Utility;----------------------------------------------; Properties to be set for this Critter spawn;----------------------------------------------; The type of critter (base object) to createFormList property CritterTypes auto{ The base object to create references of to spawn critters}; The distance from this spawner that Moths are allowed to befloat property fLeashLength = 500.0 auto{ The distance that moths are allowed to be from this spawner}float property fLeashHeight = 50.0 auto{ The distance that dragonflies are allowed to be from above spawner}float property fLeashDepth = 50.0 auto{ The distance that fish are allowed to be from below spawner}float property fMaxPlayerDistance = 2000.0 auto{ The distance from the player before the Spawner stops spawning critters}int property iMaxCritterCount = 10 auto{ The maximum number of critters this spawner can generate}float property fFastSpawnInterval = 0.1 auto{ When spawning critters, the interval between spawns}float property fSlowSpawnInterval = 5.0 auto{ When spawning critters, the interval between spawns}GlobalVariable property GameHour auto{ Make this point to the GameHour global }float property fStartSpawnTime = 6.0 auto{ The Time after which this spawner can be active}float property fEndSpawnTime = 11.0 auto{ The Time before which this spawner can be active}float property fLeashOverride auto{Optional: Manually set roaming radius for critters spawned}bool property bSpawnInPrecipitation auto{Should this critter spawn in rain/snow?  DEFAULT: FALSE};----------------------------------------------; Constants (shouldn't need to modify these);----------------------------------------------float fCheckPlayerDistanceTime = 2.0;----------------------------------------------; Variables to keep track of spawned critters;----------------------------------------------int property iCurrentCritterCount = 0 auto hiddenbool bLoopingbool bPrintDebug = FALSE   ; should usually be set to false.int recursions; Do initial stuff when my 3D has loaded up.EVENT OnLoad(); The Spawner will register for update and periodically check whether the player is close or not; - JOEL REFACTOR - Going to use onLoad() & onUnload() instead of states?; GotoState("WaitingForPlayer"); - JOEL REFACTOR - also no longer need to update; RegisterForSingleUpdate(fCheckPlayerDistanceTime)if bPrintDebug == TRUE;   debug.trace("spawner " + self + " loaded.")  recursions = 0endif; set our control bool to start the loopbLooping = TRUEwhile bLooping == TRUE  if bPrintDebug == TRUE   recursions += 1;	debug.trace("spawner " + self +  " while loop #" + recursions)  endif  if shouldSpawn() == FALSE   ; wait a bit, then see if the player is close again.   ; Removing this to eliminate some TPLOG spam; ;	debug.TraceConditional("player not yet near spawner " + self, bPrintDebug)   utility.wait(fCheckPlayerDistanceTime)  else; ;	debug.TraceConditional("spawner " + self + " ready to spawn!!!", bPrintDebug)   ; player must be nearby - spawn our initial critters   ; don't follow up as we no longer wish to re-generate new critters until the player leaves entirely   spawnInitialCritterBatch()   bLooping = FALSE  endifendWhileendEVENTEVENT onUnload(); when our 3D unloads, stop looping until loaded again.bLooping = FALSE; ;  debug.TraceConditional("spawner " + self + " unloading due to onUnload() EVENT.", bPrintDebug)endEVENTEVENT onCellDetach()bLooping = FALSE; ;  debug.TraceConditional("spawner " + self + " unloading due to onCellDetach() EVENT.", bPrintDebug)endEVENTFunction SpawnInitialCritterBatch(); How many do we need to spawn?int icrittersToSpawn = iMaxCritterCount - iCurrentCritterCount; Create that many crittersint i = 0;while (i &--#60; icrittersToSpawn)  ; Create one critter at a time  SpawnCritter()  ; Wait a bit before the next spawn  ;Wait(fFastSpawnInterval)  ; Next  i = i + 1endWhileendFunction; Called by critters when they dieEvent OnCritterDied(); Decrement current critter count, next time OnUpdate; gets called, we'll spawn a new oneif iCurrentCritterCount &--#62; 0  iCurrentCritterCount = iCurrentCritterCount - 1elseif iCurrentCritterCount == 0  ; don't do anything if already @ zeroelse  ; iCurrentCritterCount must be in the negatives.  Something is up, but for now increment towards zero  iCurrentCritterCount = iCurrentCritterCount + 1endifendEvent; Spawns one Critterbool Function SpawnCritter()if (iCurrentCritterCount &--#60; iMaxCritterCount) && (iCurrentCritterCount &--#62;= 0)  ; Go ahead with the actual spawn  SpawnCritterAtRef(self)  ; Increment count  iCurrentCritterCount = iCurrentCritterCount + 1  return trueelseif iCurrentCritterCount &--#60; 0;   debug.trace("("+self+") has invalid iCurrentCritterCount of "+iCurrentCritterCount+", abort!")  ; turn off loop  bLooping = FALSE  return falseelse;   debug.trace("("+self+") SpawnCritter() failed because iCurrentCritterCount is "+iCurrentCritterCount);   ;debug.trace("("+self+") iMaxCritterCount: "+iMaxCritterCount)endifendFunction; Spawns one Critter at a specific locationFunction SpawnCritterAtRef(ObjectReference arSpawnRef); Pick a random critter typeActivator critterType = CritterTypes.GetAt(RandomInt(0, CritterTypes.GetSize() - 1)) as Activator; Create the critter and cast it to the critter base classObjectReference critterRef = arSpawnRef.PlaceAtMe(critterType, 1, false, true)Critter thecritter = critterRef as Critter; Set initial variables on the critter; ;  Debug.TraceConditional("Spawner " + self + " is creating Critter " + thecritter, bPrintDebug);thecritter.SetInitialSpawnerProperties(fLeashLength, fLeashHeight, fLeashDepth, fMaxPlayerDistance + fLeashLength, self)endFunction; Utility method that returns the player's distancefloat Function GetPlayerDistance()return Game.GetPlayer().GetDistance(self)endFunction; Utility method that tells the spawner whether it should spawn crittersbool Function ShouldSpawn();DREW - Added an extra safety measure for if the object is stuck in the spawn check loop while the 3d is not loaded; NOTE - is3dLoaded dumps an error when the 3d is not loaded, but the function still returns false which should;  set bLooping to false and jump out of the bLooping While, at which point no additional errors will be thrownif self.is3dLoaded()  if !(GetPlayerDistance() &--#60;= fMaxPlayerDistance)   return false  endIf  ; Otherwise, base value on time of day (no handling of wrap around though...)  return IsActiveTime()else  ;if the 3d is not loaded jump out of the looped state. Just an extra safety measure.;   ;debug.Trace(self + ": should be setting bLooping to False")  bLooping = FALSE  return falseendifendFunctionbool Function IsActiveTime()bool binTimeRange = falseif (fEndSpawnTime &--#62;= fStartSpawnTime)  binTimeRange = (GameHour.GetValue() &--#62;= fStartSpawnTime) && (GameHour.GetValue() &--#60; fEndSpawnTime)else  binTimeRange = (GameHour.GetValue() &--#62;= fStartSpawnTime) || (GameHour.GetValue() &--#60; fEndSpawnTime)endIfreturn binTimeRange && ((Weather.GetCurrentWeather() == none) || \		 (Weather.GetCurrentWeather().GetClassification() &--#60; 2) || \		 (bSpawnInPrecipitation == TRUE))endFunction
User avatar
Laura Wilson
 
Posts: 3445
Joined: Thu Oct 05, 2006 3:57 pm

Return to V - Skyrim