Null pointer exception - need an extra set of eyes

Started by daxter154, January 03, 2018, 06:29:31 PM

Previous topic - Next topic

daxter154

Hello all, I lead a small team and we are working on a new mod - Pharma, a pharmaceutical mod. One of our buildings, a Sprayer, is having a null pointer exception and we could use some extra eyes to see what we are doing wrong. We get a null pointer exception when the building is completed, but not when placed just as a blueprint.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using Verse;
using Verse.AI;
using RimWorld;


namespace Pharma
{
    [StaticConstructorOnStartup]
    public abstract class Building_IngestibleSprayer : Building
    {
       
        // ==================================

        /// <summary>
        /// Do something after the object is spawned into the world
        /// </summary>
        public override void SpawnSetup(Map map, bool respawningAfterLoad)
        {
            base.SpawnSetup(map, respawningAfterLoad);

            powerComp = base.GetComp<CompPowerTrader>();
            powerComp.PowerOn = true;
           
        }


        /// <summary>
        /// To save and load actual values (savegame-data)
        /// </summary>
        public override void ExposeData()
        {
            base.ExposeData();
        }



        #region Destroy
        // ==================================

        /// <summary>
        /// Clean up when this is destroyed
        /// </summary>
        public override void Destroy(DestroyMode mode = DestroyMode.Vanish)
        {
            base.Destroy(mode);
        }

        #endregion

        /// <summary>
        /// This string will be shown when the object is selected (focus)
        /// </summary>
        /// <returns></returns>
        public override string GetInspectString()
        {
            StringBuilder stringBuilder = new StringBuilder();

            string baseString = base.GetInspectString();
            if (!baseString.NullOrEmpty())
            {
                stringBuilder.Append(base.GetInspectString());
                stringBuilder.AppendLine();
            }

            // return the complete string
            return stringBuilder.ToString().TrimEndNewlines();
        }


        public abstract bool IsAcceptableAmmoToSpray(ThingDef thing);


        public virtual bool TrySpray(Pawn p)
        {
            bool administer;

            administer = false;
            if (!Pharma_Utility.PawnHasIngestibleEffect(p, FindAmmoInAnyHopper()))
            {
                administer = true;
            }
            if (administer)
            {
                Spray(p);
                return true;
            }
            return false;
        }


        public override void Tick()
        {
            /*
            base.Tick();

            Map map = base.Map;

            //Pawn[] pawns = Pharma_Utility.GetPawnsInRange(range);
            if (this.CanDispenseNow)
            {
                foreach (Pawn p in map.mapPawns.AllPawnsSpawned)
                {
                    if (!TrySpray(p))
                    {
                        Log.Message("Could not spray pawn with thing.");
                    }

                }
            }
            */

        }

        public CompPowerTrader powerComp;

        private List<IntVec3> cachedAdjCellsCardinal;

        public static int CollectDuration = 50;

        public bool CanDispenseNow
        {
            get
            {
                return this.powerComp.PowerOn && this.HasEnoughAmmoInHoppers();
            }
        }

        private List<IntVec3> AdjCellsCardinalInBounds
        {
            get
            {
                if (this.cachedAdjCellsCardinal == null)
                {
                    this.cachedAdjCellsCardinal = (from c in GenAdj.CellsAdjacentCardinal(this)
                                                   where c.InBounds(base.Map)
                                                   select c).ToList();
                }
                return this.cachedAdjCellsCardinal;
            }
        }


        public virtual ThingDef DispensableDef
        {
            get
            {
                ThingDef spraydef = FindAmmoInAnyHopper().def;
                if (IsAcceptableAmmoToSpray(spraydef))
                {
                    return spraydef;
                }
                return null;
            }
        }


        public virtual bool HasEnoughAmmoInHoppers()
        {
            float num = 0f;
            for (int i = 0; i < this.AdjCellsCardinalInBounds.Count; i++)
            {
                IntVec3 c = this.AdjCellsCardinalInBounds[i];
                Thing thing = null;
                Thing thing2 = null;
                List<Thing> thingList = c.GetThingList(base.Map);
                for (int j = 0; j < thingList.Count; j++)
                {
                    Thing thing3 = thingList[j];
                    if (IsAcceptableAmmoToSpray(thing3.def))
                    {
                        thing = thing3;
                    }
                    if (thing3.def == ThingDefOf.Hopper)
                    {
                        thing2 = thing3;
                    }
                }
                if (thing != null && thing2 != null)
                {
                    num += (float)thing.stackCount * thing.def.ingestible.nutrition;
                }
                if (num >= base.def.building.nutritionCostPerDispense)
                {
                    return true;
                }
            }
            return false;
        }

        public virtual Building AdjacentReachableHopper(Pawn reacher)
        {
            for (int i = 0; i < this.AdjCellsCardinalInBounds.Count; i++)
            {
                IntVec3 c = this.AdjCellsCardinalInBounds[i];
                Building edifice = c.GetEdifice(base.Map);
                if (edifice != null && edifice.def == ThingDefOf.Hopper && reacher.CanReach(edifice, PathEndMode.Touch, Danger.Deadly, false, TraverseMode.ByPawn))
                {
                    return (Building_Storage)edifice;
                }
            }
            return null;
        }



        public void Spray(Pawn pawn)
        {
            //this.TryGetComp<CompProperties_DrugSprayer>().range;
            //Props.ingestible.Ingested(pawn, 0f);
            FindAmmoInAnyHopper().Ingested(pawn, 0f);


        }

        public virtual Thing FindAmmoInAnyHopper()
        {
            for (int i = 0; i < this.AdjCellsCardinalInBounds.Count; i++)
            {
                Thing thing = null;
                Thing thing2 = null;
                List<Thing> thingList = this.AdjCellsCardinalInBounds[i].GetThingList(base.Map);
                for (int j = 0; j < thingList.Count; j++)
                {
                    Thing thing3 = thingList[j];
                    if (IsAcceptableAmmoToSpray(thing3.def))
                    {
                        thing = thing3;
                    }
                    if (thing3.def == ThingDefOf.Hopper)
                    {
                        thing2 = thing3;
                    }
                }
                if (thing != null && thing2 != null)
                {
                    return thing;
                }
            }
            return null;
        }


    }
}



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using UnityEngine;
using Verse.AI;
using Verse;
using RimWorld;

namespace Pharma
{
    /*
    public static class Pharma_ThingDefOf
    {
        public static ThingDef DrugSprayer;
    }*/
    /// <summary>
    /// Drug sprayer building
    /// </summary>
    /// <seealso cref="Verse.Building" />
    [StaticConstructorOnStartup]
    public class Building_DrugSprayer : Building_IngestibleSprayer
    {
        public Building_DrugSprayer()
        {
            this.TryGetComp<CompDrugSprayer>().SetRange(10f);
        }

        public override bool IsAcceptableAmmoToSpray(ThingDef thing)
        {
            if(thing.IsDrug)
            {
                return true;
            }
            return false;

        }
    }

    public class CompDrugSprayer : ThingComp
    {
        public void SetRange(float newrange)
        {
            Props.range = newrange;
        }
        private CompProperties_DrugSprayer Props
        {
            get
            {
                return (CompProperties_DrugSprayer)base.props;
            }
        }

    }

    public class CompProperties_DrugSprayer : CompProperties_IngestibleSprayer
    {
        public CompProperties_DrugSprayer()
        {
            compClass = typeof(CompDrugSprayer);
        }
       
    }


    public class CompProperties_IngestibleSprayer : CompProperties
    {
        public float range;
    }
}



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


using UnityEngine;
using Verse;
using RimWorld;

namespace Pharma
{
    public class Pharma_Utility
    {

        /// <summary>
        /// Check if pawn has the effect of ingestible active.
        /// TODO Fix this code, possible if ingestible gives more than one effect then it wont return false even if main drug effect not active, only additional effects.
        /// </summary>
        /// <param name="pawn">The pawn.</param>
        /// <param name="ingestible">The ingestible.</param>
        /// <returns></returns>
        public static bool PawnHasIngestibleEffect(Pawn pawn, Thing ingestible)
         {
            // check the hediffs for drug effect
            foreach (var ingestoutcome in (ingestible.def.ingestible.outcomeDoers))
            {
                if (pawn.health.hediffSet.HasHediff(ingestoutcome.ChangeType<IngestionOutcomeDoer_GiveHediff>().hediffDef))
                {
                    return true;
                }
             
            }
            return false;
        }

        /*
        public static void AdministerDrugEffect(Pawn pawn, Thing drug)
        {
            foreach (var outcomedoer in drug.def.ingestible.outcomeDoers)
            {
                outcomedoer.DoIngestionOutcome(pawn, drug);
            }
        }*/

    }
}

notfood



BrokenValkyrie

Is the building still there or has it disappeared on being built. If it is the latter the problem may be an xml problem rather assembly. Try placing an inert version of the building.

notfood

this.TryGetComp<CompDrugSprayer>().SetRange(10f);

Null comp?