- Joined
- May 31, 2019
- Messages
- 150
Recently I stumbled on a crash in my project, but in the fortunate position of having saved shortly before it occurred, and so I was able to reliably reproduce it.
It was occurring when a specific Peasant was killed. There's nothing unique about this peasant that the map cares about. As in, it's not pre-placed, and there's no trigger or function in the map that references it. It was simply trained by the AI to do AI things.
An otherwise identical Peasant that will get killed right after the the game is loaded (but before the crashy peasant will die) dies without any crash or other issue.
Yet, in the map instance where this crash happened, every time the game was loaded, the same Peasant will crash the game upon death.
I believe this crash is something that was not going to happen in the game's initial (not 'loaded') state, because
It's a bit tricky, since this does not happen every game either. I'm not sure under what conditions a 'crash-when-dying' unit will appear, but when there is such a unit, it can be reliably crash the game every time if a game is loaded and you know which unit it is.
This is function in my modified blizzard.j that is called every time a unit dies. It's a series of checks to determine if anything special needs to happen based on what kind of unit it is and what state it's in.
The peasant meets none of these checks, so we can safely assume that it is one or more of the checks themselves that are causing the crash.
Also worth noting, i have a debug trigger that that kills units selected by a player entering the 'die' command. The crash also occurs if the peasant dies from this trigger.
Since I recently stumbled on another issue with a function not behaving correctly after a game load that turned out to be known by the community, I'm wondering if there are any other functions that have issues after loading a game.
I'll attach the entire Blizzard.j here. If you want a 'development build' of my mod so you can try to replicate the issue yourself, let me know.
It was occurring when a specific Peasant was killed. There's nothing unique about this peasant that the map cares about. As in, it's not pre-placed, and there's no trigger or function in the map that references it. It was simply trained by the AI to do AI things.
An otherwise identical Peasant that will get killed right after the the game is loaded (but before the crashy peasant will die) dies without any crash or other issue.
Yet, in the map instance where this crash happened, every time the game was loaded, the same Peasant will crash the game upon death.
I believe this crash is something that was not going to happen in the game's initial (not 'loaded') state, because
- I played for a little bit after saving without crashing, and the Peasant in question ran into my army at the same point regardless.
- I've been able to play through the map many times before without saving/loading and the crash never happened.
- Previously I remember experiencing other random crashes after saving and loading my game in other missions, but I just chalked it up as a 'random event' at the time without investigating it further.
It's a bit tricky, since this does not happen every game either. I'm not sure under what conditions a 'crash-when-dying' unit will appear, but when there is such a unit, it can be reliably crash the game every time if a game is loaded and you know which unit it is.
This is function in my modified blizzard.j that is called every time a unit dies. It's a series of checks to determine if anything special needs to happen based on what kind of unit it is and what state it's in.
JASS:
function SC_RouteUnitDies takes nothing returns nothing
local unit dyingUnit = GetTriggerUnit()
local integer unitId = GetUnitUserData(dyingUnit)
local integer dyingUnitType = GetUnitTypeId(dyingUnit)
local unit killingUnit = GetKillingUnit()
local integer i = 0
local boolean debugThis = false
// Common - StarCrat Mines
if SC_Cond_UnitIsStarcraftGoldMine(dyingUnit) then
call SC_Mine_Death(dyingUnit)
endif
// Common - Death Replacement
if GetUnitAbilityLevel(dyingUnit, sc_ABIL_DEATH_REPLACE) > 0 then
call SC_DeathReplace(dyingUnit, dyingUnitType)
endif
// Common - Model Attachment Ability
loop
exitwhen i > sc_ARRAYMAX_MODEL_ATTACHMENT_ABIL
if GetUnitAbilityLevel(dyingUnit, sc_ARRAY_MODEL_ATTACHMENT_ABIL[i]) > 0 then
call UnitRemoveAbility(dyingUnit, sc_ARRAY_MODEL_ATTACHMENT_ABIL[i])
endif
set i = i + 1
endloop
// Protoss
if IsUnitInGroup(dyingUnit, sc_array_carrier_ints[unitId]) then
call SC_Carrier_InterceptorDeath(dyingUnit, unitId)
endif
// Protoss Dummy Units
if dyingUnitType == sc_TIMER_INTERCEPTOR_LAUNCH then
call SC_Carrier_LaunchTimerExpire(unitId)
endif
if dyingUnitType == sc_TIMER_INTERCEPTOR_FORMATION then
call SC_Carrier_FormationTimerExpire(unitId)
endif
if dyingUnitType == sc_TIMER_CARRIER_COMBAT then
call SC_Carrier_CombatTimerExpire(unitId)
endif
// Zerg - Lurker
if SC_Cond_UnitIsLurker(dyingUnit) then
call SC_Lurker_Death(unitId)
endif
if dyingUnitType == sc_TIMER_LURKER_SPINE then
call SC_Lurker_SpawnSpine(dyingUnit)
endif
if dyingUnitType == sc_TIMER_LURKER_SPINE_DAMAGE then
call SC_Lurker_SpineDamage(unitId, dyingUnit)
endif
// Zerg - Queen
if GetUnitTypeId(killingUnit) == sc_DUMMY_SPAWN_BROODLING then
call SC_SpawnBroodling_End(GetOwningPlayer(killingUnit), dyingUnit)
endif
if dyingUnit == sc_array_infest_timer[unitId] then
call SC_Infest_End(unitId)
endif
// Zerg - Defiler
if dyingUnit == sc_array_consume_timer[unitId] then
call SC_Consume_End(unitId)
endif
// Zerg - Building
if SC_Cond_UnitIsZergBuilding(dyingUnit) then
if SC_Cond_UnitIsZergBuildingUnderConstruction(dyingUnit) then
//call DisplayTextToPlayer(Player(0), 0, 0, "Dying Unit is a zerg building under construction")
call SC_ZergBuilding_RemoveBirthFx(dyingUnit, true)
else
//call DisplayTextToPlayer(Player(0), 0, 0, "Dying Unit is NOT a zerg building under construction")
//call DisplayTextToPlayer(Player(0), 0, 0, "it's prop window is: " + R2S(GetUnitPropWindow(dyingUnit)) + ".")
call SC_ZergBuilding_Death(dyingUnit)
endif
endif
if GetUnitAbilityLevel(dyingUnit, sc_ABIL_ZERG_BUILDING_DEATH_REPLACE) > 0 then
call SC_ZergBuilding_DeathReplace(dyingUnit)
endif
// Remove Creep Generator (if it has one. if it doesn't, this function below knows to do nothing)
call SC_Creep_RemoveGenerator(dyingUnit)
// Zerg - Larva
if SC_Cond_UnitIsLarva(dyingUnit) then
call SC_Larva_Death(unitId, dyingUnit)
endif
// Zerg - Larva Egg
if SC_Cond_UnitIsZergEgg(dyingUnit) then
call SC_Larva_EggDeath(dyingUnit, unitId)
endif
// Zerg - Aspect Egg
if SC_Cond_UnitIsAspectEgg(dyingUnit) then
call SC_AspectEgg_Death(unitId)
endif
// Zerg - Hatchery
if SC_Cond_UnitIsHatchery(dyingUnit) then
call SC_Hatchery_Death(unitId, dyingUnit)
endif
// Zerg - Nydus
if dyingUnitType == sc_ZERG_NYDUS_PAIRED then
call SC_Nydus_Death(unitId)
endif
// WC2 Orc Dummy Units
if dyingUnit == sc_array_unholyArmor_timer[unitId] then
call SC_UnholyArmor_End(unitId)
endif
if dyingUnit == bribe_UDexUnits[unitId] and sc_array_unholyArmor_timer[unitId] != null then
call SC_UnholyArmor_End(unitId)
endif
// Clear leaks
set dyingUnit = null
set killingUnit = null
endfunction
The peasant meets none of these checks, so we can safely assume that it is one or more of the checks themselves that are causing the crash.
Also worth noting, i have a debug trigger that that kills units selected by a player entering the 'die' command. The crash also occurs if the peasant dies from this trigger.
Since I recently stumbled on another issue with a function not behaving correctly after a game load that turned out to be known by the community, I'm wondering if there are any other functions that have issues after loading a game.
I'll attach the entire Blizzard.j here. If you want a 'development build' of my mod so you can try to replicate the issue yourself, let me know.
Attachments
Last edited: