Ludeon Forums

RimWorld => Mods => Help => Topic started by: 1000101 on April 06, 2015, 05:50:29 PM

Title: [Example] Using a DLL to unlock researchable recipes all defined in XML
Post by: 1000101 on April 06, 2015, 05:50:29 PM
After many hours examining code, trying to learn how RimWorld does what and what others have done to do things, I figured out my problem.  The method Saularain proposed below to remove and then re-add recipes from tables is the way to allow recipes to be unfinished.

I present my humble efforts at some sort of basic tutorial for those trying the same thing.  Not everyone will find this useful, but here you go to those that do.

Functional info:
AdvancedRecipeDefs define what recipes are linked with what research projects.  When a new colony is started, the MapComponent (DLL) loads all the AdvancedRecipeDefs, creates a list of the research to monitor for completion and then sits idle, periodically checking for research completion and unlocking recipes (re-adding the tables to the recipeDef) as they become available.


Notes:
In the XML for your recipes and tables, link the recipes to the tables and not the other way around.  That is, use <recipeUsers> in the recipeDef, not <recipes> in the building ThingDef.  The MapComponent is working on the recipe and not the table, the table itself is untouched except to have it's recipe cache flag cleared.



Quote from: OPThis is related to this post --> https://ludeon.com/forums/index.php?topic=11993.0

I have been trying to add recipies which may be unfinished dynamically to a table after research via DLL.  Everything works in that regard.  What does not, is that if a recipe can be unfinished (has an unfinishedThingDef), the job won't continue and exceptions are thrown.  Recipes without the tag work exactly as they should, it's only the unfinished ones.

Is there another table/list which needs to be updated for unfinished recipes to complete?  If so, then I would guess this is automagic in the xml loading and thus far hasn't become an issue.

Attached is a bare bones example of what's happening.

Tested against Core only on a new world and a new colony.

[attachment deleted due to age]
Title: Re: Help needed with unfinished things and dll added recipies
Post by: Saularian on April 07, 2015, 11:43:18 AM
Problem could probably be due to wrong encoding of the advancedrecipedef... (it's not UTF8 but UTF8 w/o BOM) as this usually screwed up my own mods, but that doesn't seem to be the case here after I altered the defs...

It looks as if the unfinished object isn't "defined" as it can't be touched after someone started on it, but yet it can be canceled.

Although I'm curious as to why you want to inject a recipe via dll as it can be done in the defs, (research pre-requisition).

Havent looked at how another mod does it though, but maybe you should look at the gun crafting mod. Don't know if it has it's recipes injected by dll, but if it does, your solution could be in there.
Title: Re: Help needed with unfinished things and dll added recipies
Post by: 1000101 on April 07, 2015, 04:21:16 PM
As to the XML - I didn't even notice the byte-encoding was wrong (notepad++ defaults).  I did notice that I had to change the encoding to load RimWorld xml's into some specialized code of my own (xml library I use only supports utf-8) and I had to convert.  But if the encoding was at fault then the game engine would fail long before it does.

It uses DLL injection because recipes can't be unlocked and added to tables using XML (and lots of mods use this technique, M&Co, MD2, Clutter, etc).  In fact, I "borrowed" MD2's research injection method due to the nice way it uses xml defs to link everything (AdvancedRecipeDefs is the same as MD2's ResearchRecipeDefs used for it's Droid Assembly table).

I don't want to just add new tables since that just adds to the clutter of the UI and it's a logically broken method anyway - I don't need a new stove because I now know how to make lasagna.

What I need is a recipe which can yield an unfinished step to actually complete on injection.  Failing that I would have to break the recipe down into discrete steps instead of the generalized recipes.  eg, produce gun barrels, rifled barrels, rifle stocks, pistol grips, etc, *then* turn a rifle barrel + rifle stock + iron sights + short time = survival rifle or rifle barrel + rifle stock + scope + longer time = sniper rifle.

But that means more things to just lie around your base with limited use.  While I like the idea of discrete steps, it's the item creep I worry about.

If I have to, I have to, but...
Title: Re: Help needed with unfinished things and dll added recipies
Post by: Saularian on April 07, 2015, 05:17:47 PM
Yeah it took me a while before I got tired of the notepad++ default and changed those

but i havent looked at MD2's source, but did have a look at Ykara's craftable guns (https://ludeon.com/forums/index.php?topic=10850.0) source, which in my opinion does a good job on the recipe injection part, and even for me easy to read and understand.namespace CraftableGuns
{
    public class UnlockResearch : MapComponent
    {
        public UnlockResearch()
        {
            LockAllRecipes();
        }

        private static void LockAllRecipes()
        {
            LockRecipe("CreateGun_PDW");
            LockRecipe("CreateGun_HeavySMG");
            LockRecipe("CreateGun_LMG");
            LockRecipe("CreateGun_AssaultRifle");
            LockRecipe("CreateGun_SniperRifle");
        }

        private static void LockRecipe(string defName)
        {
            var recipeDef = DefDatabase<RecipeDef>.GetNamed(defName);
            recipeDef.recipeUsers = new List<ThingDef>();
        }

        private static void UnlockRecipe(string tableDefName, string defName)
        {
            var tableDef = DefDatabase<ThingDef>.GetNamed(tableDefName);

            var recipeDef = DefDatabase<RecipeDef>.GetNamed(defName);
            recipeDef.recipeUsers = new List<ThingDef> {tableDef};

            // Clear cache to update existing objects
            typeof (ThingDef).GetField("allRecipesCached", BindingFlags.NonPublic | BindingFlags.Instance)
                .SetValue(tableDef, null);
        }

        public static void Weapons1()
        {
            UnlockRecipe("TableSmithing", "CreateGun_PDW");
            UnlockRecipe("TableSmithing", "CreateGun_HeavySMG");
            UnlockRecipe("TableSmithing", "CreateGun_LMG");
        }

        public static void Weapons2()
        {
            UnlockRecipe("TableSmithing", "CreateGun_AssaultRifle");
            UnlockRecipe("TableSmithing", "CreateGun_SniperRifle");
        }

        }
    }


Allthough I havent used that mod in a while now so I'm not sure if this one gave me any exceptions...


Title: Re: Help needed with unfinished things and dll added recipies
Post by: 1000101 on April 08, 2015, 02:14:05 AM
hrm, that may be the solution then and probably why he did it that way.  Do the process in reverse.  I'll give it a shot and see what happens.


Edit:  It worked, OP updated to reflect that this is now closed and I provide an example for those who are trying the same/similar thing.
Title: Re: [Example] Using a DLL to unlock researchable recipes all defined in XML
Post by: mrofa on April 09, 2015, 09:28:50 AM
Im interested in your results on this code, i did try something similar but it had a problem with other mods that use similar method.
Title: Re: [Example] Using a DLL to unlock researchable recipes all defined in XML
Post by: skullywag on April 10, 2015, 12:17:29 PM
Mrofa wasnt that to do with everyone using researchmodspecial and not unique names?
Title: Re: [Example] Using a DLL to unlock researchable recipes all defined in XML
Post by: mrofa on April 10, 2015, 12:26:01 PM
Im not sure maybe, i dont understand how it works so i cant really say :D
Title: Re: [Example] Using a DLL to unlock researchable recipes all defined in XML
Post by: skullywag on April 10, 2015, 12:40:43 PM
Its simply tying a research def to a class. Nothing more. So whatever class you call from the research def as long as it extends researchmod your good. Thats how i see it anyway.
Title: Re: [Example] Using a DLL to unlock researchable recipes all defined in XML
Post by: mrofa on April 10, 2015, 12:46:49 PM
Oh i didnt mean the research itself, i meant the recipes, i did try it in one of the realese, but it seemed to have problems with mechanical defence.
That only one mod was able to add recipes and other did not.
Title: Re: [Example] Using a DLL to unlock researchable recipes all defined in XML
Post by: skullywag on April 10, 2015, 12:48:57 PM
recipes a list right? If modders always take the current list and append to it, it should work. Hmm might have to investigate this further when im home.
Title: Re: [Example] Using a DLL to unlock researchable recipes all defined in XML
Post by: mrofa on April 10, 2015, 12:53:32 PM
Thats what Saularian is doing now :P
Title: Re: [Example] Using a DLL to unlock researchable recipes all defined in XML
Post by: skullywag on April 10, 2015, 12:56:29 PM
This shouldnt need a map listener and stuff like that...ill see what i can find out. 2 heads and all that...
Title: Re: [Example] Using a DLL to unlock researchable recipes all defined in XML
Post by: 1000101 on April 10, 2015, 01:06:17 PM
Yes, recipeUsers in the recipeDef and recipes in the ThingDef are lists and the code I provide is bad in that it actually recreates the list and may break game compatibility.  My local copy I've actually changed the code a bit to add/remove recipes/tables from the lists instead of using New List< type >();

I can upload a copy of the source if you are interested.  The code in the OP is more a "quick, let's get it working," and less of, "you guys play nice!"  My local copy is more "play nice" and doesn't assume it's the only one using it.  It also removes the restriction on how the recipe is originally linked the the tables as it removes the recipe from the table and the table from the recipe then adds the table to the recipe (creating a table list for the recipe if needed).

I've also changed it to allow multiple recipes, multiple research and multiple tables as a single def (see source) for research/recipe groups.

As to a map listener, it needs some way of either polling or using a research mod on a base research to trigger the same thing - The research scan loop.  The easiest way (from the xml perspective) was a map component so you don't need to worry about it triggering (forgot the add the research mod def or something). The source provided here is much more "mod friendly."

[attachment deleted due to age]
Title: Re: [Example] Using a DLL to unlock researchable recipes all defined in XML
Post by: mrofa on April 10, 2015, 01:54:39 PM
Thanks alot i will study it, btw do you know maybe any sane way to change stuff in statbase from code ?
Im currently using mapcomponent on it and additional failsafe on things themself since map component sometimes fails on it.
Title: Re: [Example] Using a DLL to unlock researchable recipes all defined in XML
Post by: 1000101 on April 10, 2015, 07:59:48 PM
tbh, I have a background in programming but I am unfamiliar with RimWorld.  This has been my first foray into it.  I looked at the dll tutorial mod (the dark-matter generator) as well as other mods code.  You know far more about it than I do I'm sure.  :)
Title: Re: [Example] Using a DLL to unlock researchable recipes all defined in XML
Post by: soltysek on April 12, 2015, 08:12:36 AM
research mod adding recipe to "work_table"  is save compatible ? I mean after game load is puting recip again or you neeed to custom exposedata() owerwrite on worktable  ?
Title: Re: [Example] Using a DLL to unlock researchable recipes all defined in XML
Post by: skullywag on April 12, 2015, 08:53:47 AM
all researchmods run when game is loaded and when a research is completed, so you need to add a check to ensure it doesnt run everytime one is completed, see my omniturret for an example.
Title: Re: [Example] Using a DLL to unlock researchable recipes all defined in XML
Post by: 1000101 on April 12, 2015, 09:10:09 AM
The particular example in my OP does not expose and save the data but there really isn't anything worth saving, it's simply checking what research you have completed and makes sure the recipes are available.  Every rare-tick the MapComponent ticks and checks for research completion, enabling the recipes.  I've also short-cut the first check to happen immediately so at most there would be a single tick which the recipes may not be available.

I have tested this code a bit and it's the basis for my own mods research tree.  It seems to work without issue (for me) after loading games with complex research and recipe trees.

The updated code in a later post makes use of a bool flag for faster processing after an AdvancedRecipeDef is complete.  This is about the only thing which would be exposed and saved.  However, checking for the research to be done is only done once ever 250 ticks (one rare tick) and is fast enough that to save an array of "isEnabled" flags is just not worth it though.  That is, the research check happens so quickly it won't ever be an issue as far is game performance.
Title: Re: [Example] Using a DLL to unlock researchable recipes all defined in XML
Post by: mrofa on April 12, 2015, 09:11:29 AM
Then that is awsome thanks alot :D
Title: Re: [Example] Using a DLL to unlock researchable recipes all defined in XML
Post by: soltysek on April 12, 2015, 09:21:30 AM
skullywag - thx for info in this way its childis easy .

1000101 - its a one way to do it but its have strong minus one more RareTick() event more .imagine ther is 10 mod's that make it same way and checking 50 reserch each so every 250 Tick() you get 500 if's ... beter is to call Class on EventBase like  IsLoading or ResearchIsFinish . Minecraft big mods/modspack have this problem : lag spikes , Fps drop .
Title: Re: [Example] Using a DLL to unlock researchable recipes all defined in XML
Post by: 1000101 on April 12, 2015, 09:28:14 AM
You would need several hundred mods each checking several thousand research with dozens of complex AdvancedRecipeDef per mod.

Unless you are going to mod in about 10,000 AdvancedRecipeDefs, I think you're safe.

My mod I am working on makes more than 4x the changes to the game as all *68* of the mods I have installed, including several big mods (MD2, ED, Clutter, Miscellaneous), and I have only re-defined the core, I haven't really added anything to the game and there is 0 impact.


Edit:  You do make a valid point about needless code execution, I'm just saying it's not something to worry about right now.
Title: Re: [Example] Using a DLL to unlock researchable recipes all defined in XML
Post by: soltysek on April 13, 2015, 02:09:05 PM
i know i just point that mods are geting biger and game is growin needs of opti will be need in future especialy for old spec pc users

1000101 I pm you yesterday did you get it ?
Title: Re: [Example] Using a DLL to unlock researchable recipes all defined in XML
Post by: 1000101 on April 13, 2015, 07:41:44 PM
I agree 100% about optimization.  This is more of "get it work."  Slow working code is better than fast broken code.  :)

re: PM - Didn't even notice, :)  Replied.