DamageDefOf.Bomb cannot be used as a DamageDef

Started by randolphcherrypepper, July 28, 2017, 01:13:53 PM

Previous topic - Next topic

randolphcherrypepper

I am running v0.17.1557 and trying to make something similar to CompExplosive. I was using the mortar as a baseline item.

I attempted to rely on the following, based on CompProperties_Explosive:


public DamageDef explosiveDamageType = DamageDefOf.Bomb;


Mortar overrides the default above with


<explosiveDamageType>Bomb</explosiveDamageType>


That seems silly. It's the default! So of course, in my XML, I decided to leave out <explosiveDamageType> and rely on DamageDefOf.Bomb. Then I receive the following error in the console during Detonate() (whilst calling DoExplosion()).


Object reference not set to an instance of an object.


With a little debugging in (an overridden version of) Detonate(), it turns out I can reproduce the error before reaching DoExplosion(). Same error as above occurs, but right inside Detonate() if the following debug is added before DoExplosion() is called:


Log.Message(props.explosiveDamageType.GetType().ToString());


After putting <explosiveDamageType>Bomb</explosiveDamageType> back into my XML, everything runs smashingly.

That leads me to believe DamageDefOf.Bomb is broken.

For the time being, the work around seems to be avoiding a DamageDef default value using DamageDefOf and instead make sure to specify it explicitly in the XML.

RawCode

what internal (DLL) type of provided enum?

copypaste declaration here

randolphcherrypepper

Ah, the source code was provided for CompExplosive, and it is (RimWorld/Source/RimWorld/ThingComps/CompExplosive.cs). I thought CompProperties_Explosive was also provided but it turns out I was referencing a decompiled source for that.

This is what my decompiler gave for CompProperties_Explosive:


namespace RimWorld
{
public class CompProperties_Explosive : CompProperties
{
public float explosiveRadius = 1.9f;

public DamageDef explosiveDamageType = DamageDefOf.Bomb;

public ThingDef postExplosionSpawnThingDef;

public float postExplosionSpawnChance;

public int postExplosionSpawnThingCount = 1;

public bool applyDamageToExplosionCellsNeighbors;

public ThingDef preExplosionSpawnThingDef;

public float preExplosionSpawnChance;

public int preExplosionSpawnThingCount = 1;

public float explosiveExpandPerStackcount;

public EffecterDef explosionEffect;

public DamageDef startWickOnDamageTaken;

public float startWickHitPointsPercent = 0.2f;

public IntRange wickTicks = new IntRange(140, 150);

public float wickScale = 1f;

public float chanceNeverExplodeFromDamage;

public CompProperties_Explosive()
{
this.compClass = typeof(CompExplosive);
}
}
}


While not an enum, here is what the decompiler got for DamageDefOf:


namespace RimWorld
{
[DefOf]
public static class DamageDefOf
{
public static DamageDef Cut;

public static DamageDef Crush;

public static DamageDef Arrow;

public static DamageDef Blunt;

public static DamageDef Stab;

public static DamageDef Bullet;

public static DamageDef Bomb;

public static DamageDef Scratch;

public static DamageDef Bite;

public static DamageDef Flame;

public static DamageDef Burn;

public static DamageDef SurgicalCut;

public static DamageDef ExecutionCut;

public static DamageDef Frostbite;

public static DamageDef Stun;

public static DamageDef EMP;

public static DamageDef Extinguish;

public static DamageDef Smoke;

public static DamageDef Deterioration;

public static DamageDef Mining;

public static DamageDef Rotting;
}
}


Lastly, here's the decorator above:

namespace RimWorld
{
[AttributeUsage(AttributeTargets.Class)]
public class DefOf : Attribute
{
}
}

RawCode

make sure that no other mod messed with DamageDefOf.Bomb as that declaration both read and write and public

best if you put trace output in multiple places around your code

randolphcherrypepper

#4
I was running Quicktest which disables all Steam Workshop mods. I only had the one mod I was using for debugging.

I'm pretty sure what I'm pointing out is a problem in the base code which is masked by the core defs never using a default value to expose the problem.

If my hypothesis is correct, then the simple test would be, in vanilla, to remove the redundant <explosiveDamageType>Bomb</explosiveDamageType> from Core/Defs/ThingDefs_Items/Items_Resource_Manufactured.xml under <defName>MortarShell</defName> and see if the console still reports a crash.

Procedure:


  • Enable dev tools
  • RimWorld Quickstart with no directory-based mods installed (thus no mods running, which will be reflected in the logs)
  • Tool: try to place near thing...
  • Search for and choose mortar shell
  • Place mortar shell somewhere
  • Use Tool: 10 damage on the shell 5 times

Console after dealing 50 damage with no modification:


[Steamworks.NET] SteamAPI.Init() failed. Possible causes: Steam client not running, launched from outside Steam without steam_appid.txt in place, running with different privileges than Steam client (e.g. "as administrator")
Verse.Log:Warning(String)
Verse.Steam.SteamManager:InitIfNeeded()
Verse.Root:CheckGlobalInit()
Verse.Root:Start()
Verse.Root_Entry:Start()

Command line arguments: -quicktest
Verse.Log:Message(String)
Verse.Root:CheckGlobalInit()
Verse.Root:Start()
Verse.Root_Entry:Start()

RimWorld 0.17.1557 rev1153
Verse.Log:Message(String)
RimWorld.VersionControl:LogVersionNumber()
Verse.Root:CheckGlobalInit()
Verse.Root:Start()
Verse.Root_Entry:Start()

Initializing new game with mods Core
Verse.Log:Message(String)
Verse.Game:InitNewGame()
Verse.Root_Play:<Start>m__850()
Verse.LongEventHandler:RunEventFromAnotherThread(Action)
Verse.LongEventHandler:<UpdateCurrentAsynchronousEvent>m__84C()


Console after removing <explosiveDamageType>Bomb</explosiveDamageType> from Core/Defs/ThingDefs_Items/Items_Resource_Manufactured.xml under <defName>MortarShell</defName>  and then dealing 50 damage:


[Steamworks.NET] SteamAPI.Init() failed. Possible causes: Steam client not running, launched from outside Steam without steam_appid.txt in place, running with different privileges than Steam client (e.g. "as administrator")
Verse.Log:Warning(String)
Verse.Steam.SteamManager:InitIfNeeded()
Verse.Root:CheckGlobalInit()
Verse.Root:Start()
Verse.Root_Entry:Start()

Command line arguments: -quicktest
Verse.Log:Message(String)
Verse.Root:CheckGlobalInit()
Verse.Root:Start()
Verse.Root_Entry:Start()

RimWorld 0.17.1557 rev1153
Verse.Log:Message(String)
RimWorld.VersionControl:LogVersionNumber()
Verse.Root:CheckGlobalInit()
Verse.Root:Start()
Verse.Root_Entry:Start()

Initializing new game with mods Core
Verse.Log:Message(String)
Verse.Game:InitNewGame()
Verse.Root_Play:<Start>m__850()
Verse.LongEventHandler:RunEventFromAnotherThread(Action)
Verse.LongEventHandler:<UpdateCurrentAsynchronousEvent>m__84C()

Object reference not set to an instance of an object
  at Verse.GenExplosion.NotifyNearbyPawnsOfDangerousExplosive (Verse.Thing exploder, Verse.DamageDef damage, RimWorld.Faction onlyFaction) [0x00000] in <filename unknown>:0
  at RimWorld.CompExplosive.StartWick (Verse.Thing instigator) [0x00000] in <filename unknown>:0
  at RimWorld.CompExplosive.PostPostApplyDamage (DamageInfo dinfo, Single totalDamageDealt) [0x00000] in <filename unknown>:0
  at Verse.ThingWithComps.PostApplyDamage (DamageInfo dinfo, Single totalDamageDealt) [0x00000] in <filename unknown>:0
  at Verse.Thing.TakeDamage (DamageInfo dinfo) [0x00000] in <filename unknown>:0
  at Verse.Dialog_DebugActionsMenu.<DoListingItems_MapTools>m__ABB () [0x00000] in <filename unknown>:0
  at Verse.DebugTool.DebugToolOnGUI () [0x00000] in <filename unknown>:0
  at Verse.DebugTools.DebugToolsOnGUI () [0x00000] in <filename unknown>:0
  at RimWorld.UIRoot_Play.UIRootOnGUI () [0x00000] in <filename unknown>:0
  at Verse.Root.OnGUI () [0x00000] in <filename unknown>:0

Exception ticking MortarShell14191: System.NullReferenceException: Object reference not set to an instance of an object
  at Verse.GenExplosion.DoExplosion (IntVec3 center, Verse.Map map, Single radius, Verse.DamageDef damType, Verse.Thing instigator, Verse.SoundDef explosionSound, Verse.ThingDef projectile, Verse.ThingDef source, Verse.ThingDef postExplosionSpawnThingDef, Single postExplosionSpawnChance, Int32 postExplosionSpawnThingCount, Boolean applyDamageToExplosionCellsNeighbors, Verse.ThingDef preExplosionSpawnThingDef, Single preExplosionSpawnChance, Int32 preExplosionSpawnThingCount) [0x00000] in <filename unknown>:0
  at RimWorld.CompExplosive.Detonate (Verse.Map map) [0x00000] in <filename unknown>:0
  at RimWorld.CompExplosive.CompTick () [0x00000] in <filename unknown>:0
  at Verse.ThingWithComps.Tick () [0x00000] in <filename unknown>:0
  at Verse.TickList.Tick () [0x00000] in <filename unknown>:0
Verse.Log:Error(String)
Verse.TickList:Tick()
Verse.TickManager:DoSingleTick()
Verse.TickManager:TickManagerUpdate()
Verse.Game:UpdatePlay()
Verse.Root_Play:Update()


The vanilla, code-based default value of DamageDefOf.Bomb does not function and can be demonstrated using the above procedure. The only alternative I can think of is that my decompiler is wrong about DamageDefOf.Bomb being set as the default per the code pasted in my last post on this thread.

If public DamageDef explosiveDamageType was left undefined (which the decompiler does not suggest), I suspect this error would be the same.