Copy the recipes (modded or otherwise) from another building

Started by faeldray, March 24, 2017, 08:48:55 PM

Previous topic - Next topic

Granitecosmos

Quote from: RawCode on March 26, 2017, 03:34:10 AM
Quotedburgdorf PMed me some C# code
great community oriented behavior, PMing code instead sharing it with community will definely allow other users to find answers!*


*no, this is unacceptable actually.

static public void Main(string[] ignored)
{
Console.WriteLine("_yacil entry");

ThingDef dest = DefDatabase<ThingDef>.GetNamed("CraftingSpot",false);
ThingDef src = DefDatabase<ThingDef>.GetNamed("TableButcher",false);

//force game to cache data
object o = dest.AllRecipes;
o = src.AllRecipes;
if (o == null)
throw new Exception("to trick codeflow, in other case it will eliminate calls");

FieldInfo ff = typeof(ThingDef).GetField("allRecipesCached",(System.Reflection.BindingFlags)60);

object tmp = ff.GetValue(src);
ff.SetValue(dest,tmp);


Console.WriteLine("_yacil end");
}

run from [StaticConstructorOnStartup]

Says the guy who never spoonfeeds/gives usable C# code to beginners.

Nice double-standard you got there.  ;)

dburgdorf

Actually, Granite, RawCode has a valid point. I don't like to post code because I'm a rank amateur coder and my code is often inelegant, to say the least, but at the same time, if I'm going to answer questions, it makes sense to answer them publicly.

The code I provided to faeldray was as follows.


using RimWorld;
using System;
using System.Collections.Generic;
using System.Linq;
using Verse;

namespace Firepit_Code {

[StaticConstructorOnStartup]
internal static class Firepit {
static Firepit() {
List<RecipeDef> allRecipes = DefDatabase<RecipeDef>.AllDefsListForReading;
for (int i = 0; i < allRecipes.Count; i++) {
if (allRecipes[i].recipeUsers != null && allRecipes[i].recipeUsers.Contains(ThingDefOf.Campfire) && !allRecipes[i].recipeUsers.Contains(ThingDefOf.Firepit)) {
allRecipes[i].recipeUsers.Add(ThingDefOf.Firepit);
}
}
}
}

[DefOf]
public static class ThingDefOf {
public static ThingDef Campfire;
public static ThingDef Firepit;
}

}


It's not elegant, but it's complete and it does what faeldray wanted done, adding campfire recipes from mods to the fire pit.
- Rainbeau Flambe (aka Darryl Burgdorf) -
Old. Short. Grumpy. Bearded. "Yeah, I'm a dorf."



Buy me a Dr Pepper?

dburgdorf

Faeldray, you might actually want to consider using both RawCode's code and my own, as they do different and complementary things.

This stems from the fact that worktable items can have recipes attached to them, OR recipes can have worktable items attached to them. In other words, you can define a worktable and include with it a list of recipes that can be made there, OR you can define a recipe and include with it a list of worktables at which it can be made.

My code adds the fire pit to the list of worktables for any recipes that are defined such that they can be made at a campfire. That means that any recipe added by a mod which says, "this recipe can be made at a campfire," will also be available at the fire pit.

RawCode's code, on the other hand, copies every recipe from the campfire to the fire pit. That may not seem particularly useful, since you're already copying vanilla recipes from the campfire to the fire pit, anyway, but if another mod replaces the campfire and adds new recipes to it, his code would catch the additions, where mine wouldn't, just as my code catches recipes that his doesn't.
- Rainbeau Flambe (aka Darryl Burgdorf) -
Old. Short. Grumpy. Bearded. "Yeah, I'm a dorf."



Buy me a Dr Pepper?

faeldray

It took me a little while to figure out how to integrate RawCode's code and that I needed to include System.Reflection but this is the final code that I got to compile without errors and looks to be working after a glance at it in-game:


using RimWorld;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Verse;

namespace Firepit_Code {

[StaticConstructorOnStartup]
internal static class Firepit {
static Firepit() {
List<RecipeDef> allRecipes = DefDatabase<RecipeDef>.AllDefsListForReading;
for (int i = 0; i < allRecipes.Count; i++) {
if (allRecipes[i].recipeUsers != null && allRecipes[i].recipeUsers.Contains(ThingDefOf.Campfire) && !allRecipes[i].recipeUsers.Contains(ThingDefOf.Firepit)) {
allRecipes[i].recipeUsers.Add(ThingDefOf.Firepit);
}
}
}
static public void Main(string[] ignored) {
Console.WriteLine("_yacil entry");

ThingDef dest = DefDatabase<ThingDef>.GetNamed("Firepit",false);
ThingDef src = DefDatabase<ThingDef>.GetNamed("Campfire",false);

//force game to cache data
object o = dest.AllRecipes;
o = src.AllRecipes;
if (o == null) {
throw new Exception("to trick codeflow, in other case it will eliminate calls");
}

FieldInfo ff = typeof(ThingDef).GetField("allRecipesCached",(System.Reflection.BindingFlags)60);

object tmp = ff.GetValue(src);
ff.SetValue(dest,tmp);

Console.WriteLine("_yacil end");
}
}

[DefOf]
public static class ThingDefOf {
public static ThingDef Campfire;
public static ThingDef Firepit;
}

}


I'm going to playtest it in one of my own games before releasing the mod on Steam Workshop but barring any issues, this is exactly what I wanted to do!

Huge thanks for dburgdorf for providing the first set of code and patiently helping me when I made some silly mistakes at first. Thank you also to RawCode for providing the second set, although I hope that next time you do so in a less harsh manner, therefore encouraging more great community oriented behaviour.

dburgdorf

One small fix, and you should be good to go. Right now, the second method is never used, as you'll see if you remove some of the vanilla recipes from the fire pit definition. (The fire pit will then include any modded recipes, but not those vanilla recipes.) You'll want to make it all a single method, rather than two. If you just delete:


}
static public void Main(string[] ignored) {


You'll be set.
- Rainbeau Flambe (aka Darryl Burgdorf) -
Old. Short. Grumpy. Bearded. "Yeah, I'm a dorf."



Buy me a Dr Pepper?

faeldray

I deleted those lines as well as the vanilla recipes from the firepit thingDef (to test it) and all of the recipes, including the vanilla ones, are still showing at the firepit. Hooray! Now time for the playtesting.