[Solved] C# add recipe (or 'c#-patch' it)?

Started by Napoleonite, February 29, 2020, 01:55:43 PM

Previous topic - Next topic

Napoleonite


            //<snip>

            RecipeDef rd = new RecipeDef
            {
                defName = defName,
                effectWorking = DefDatabase<EffecterDef>.GetNamed("Smith"),
                workSkill = DefDatabase<SkillDef>.GetNamed("Mining"),
                workSpeedStat = DefDatabase<StatDef>.GetNamed("MiningSpeed"),
                workSkillLearnFactor = 0.5f,
                jobString = "Drilling" + " " + forthisThingDef.label,
                workAmount = 5000,
                soundWorking = DefDatabase<SoundDef>.GetNamed("Recipe_Machining"),
                label = "Drill" + " " + forthisThingDef.label,
                description = "Drill" + " " + forthisThingDef.label
            };

            rd.products.Add(new ThingDefCountClass(forthisThingDef, 20));
            DefDatabase<RecipeDef>.Add(rd);


Produces the following error when adding it as a bill (everything else seems to work so far):
QuoteException filling window for Verse.FloatMenu: System.NullReferenceException: Object reference not set to an instance of an object
  at Verse.ThingFilter.CopyAllowancesFrom (Verse.ThingFilter other) [0x0001f] in <33b99ab6cf5748ec8fe371b3321b9db6>:0
  at RimWorld.Bill..ctor (Verse.RecipeDef recipe) [0x00043] in <33b99ab6cf5748ec8fe371b3321b9db6>:0
  at RimWorld.Bill_Production..ctor (Verse.RecipeDef recipe) [0x00042] in <33b99ab6cf5748ec8fe371b3321b9db6>:0
  at RimWorld.BillUtility.MakeNewBill (Verse.RecipeDef recipe) [0x0000f] in <33b99ab6cf5748ec8fe371b3321b9db6>:0
  at RimWorld.ITab_Bills+<>c__DisplayClass10_0.<FillTab>b__1 () [0x0004b] in <33b99ab6cf5748ec8fe371b3321b9db6>:0
  at Verse.FloatMenuOption.Chosen (System.Boolean colonistOrdering, Verse.FloatMenu floatMenu) [0x00028] in <33b99ab6cf5748ec8fe371b3321b9db6>:0
  at Verse.FloatMenuOption.DoGUI (UnityEngine.Rect rect, System.Boolean colonistOrdering, Verse.FloatMenu floatMenu) [0x0030e] in <33b99ab6cf5748ec8fe371b3321b9db6>:0
  at Verse.FloatMenu.DoWindowContents (UnityEngine.Rect rect) [0x000fb] in <33b99ab6cf5748ec8fe371b3321b9db6>:0
  at Verse.Window.InnerWindowOnGUI (System.Int32 x) [0x00165] in <33b99ab6cf5748ec8fe371b3321b9db6>:0
Verse.Log:Error(String, Boolean)
Verse.Window:InnerWindowOnGUI(Int32)
UnityEngine.GUI:CallWindowDelegate(WindowFunction, Int32, Int32, GUISkin, Int32, Single, Single, GUIStyle)

Also, does someone have a link to a tutorial or a good example of how to have C# do this through XML perhaps? Can't I just apply an XML patch instead through C#? I think that would be easier. I'd still like to know how to do both though.

Also, is there an option to inspect the XML database in the game to verify that everything went okay?

K

The problem is that you can't have a recipe without ingredients. Or at the very least, you can't have a recipe with null ingredients. The null reference looks to be occurring because when the game tries to create a bill from your recipe it attempts to copy the ingredient filters from the recipe, and since there isn't any it results in the null reference.

Just based on the jobString and label, it looks like you're trying to create a drilling bill. While trying to see how the base game does this, I found that the deep drill doesn't even use a recipe, and instead uses a comp (CompDeepDrill) which you might want to take a look at.

Also, it's generally not a good idea to hard-code strings since it doesn't allow for easy translations. For "injecting" strings into your C# code you should use the keyed string system that the game has in place, since it allows for translators to translate those strings without compiling a new dll.

Napoleonite

#2
I haven't created a translation file yet so, for now, I hardcode them. Later I'll replace them yes.

A recipe doesn't require ingredients. I have XML versions that have no ingredients at all that work just fine. This works (and no ingredients, also none in the base):
<RecipeDef ParentName="myBase">
<defName>drill_myOre</defName>
<label>drill myOre</label>
<description>drill myOre</description>
<jobString>Drilling myOre</jobString>
<workAmount>1000</workAmount>
<products>
<MyOre>15</MyOre>
</products>
</RecipeDef>


I tried adding the line:
ingredients = new List<IngredientCount>(),
but still the same error.

I checked that component but I can't use it because I use bills and recipes instead.

K

Ingredients wasn't really the right word. All recipes have to have a defaultIngredientFilter. Usually you don't define it in XML but the game will populate it while resolving XML references. You need to set your defaultIngredientFilter to something. A new ThingFilter will work.

As for the component, I was just suggesting that you might want to take the approach of using a comp instead of bills and recipes. There's probably some advantages to that approach, since Tynan opted to use it instead.

Napoleonite

Ah, I see.

I got it working using XML-patches applied by C# (why is this not mentioned in the Wiki?).

Thanks, adding:
defaultIngredientFilter = new ThingFilter()
also fixed it! Now I have two ways to go about it + a possible 3rd-way using that comp.