Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Messages - Nightinggale

#181
Quote from: pardeike on November 29, 2017, 02:26:30 PMyou should look into the readymade transpilers that come with Harmony, like the MethodReplacer
Is there a list of Harmony features like that anywhere? I missed the existence of this one until right now. It looks to me like it totally beats both then redirection and then Prefix+return false approaches since both supports Postfix just fine.

In fact is there any Transpiler documentation other than the wiki from the first post? It seems that the most useful I can find is working examples of code, but looking at Harmony source code, it looks like they are only scratching the surface of all the features.

Also how soon can Transpiler be applied? It looks like all dll files are loaded in Verse.LoadedModManager.LoadAllActiveMods() and obviously Harmony will not work before being loaded. However can it be used in this method after the dll files have been loaded or will it only work on methods called after harmony is loaded?
#182
<Patch>
<Operation Class="PatchOperationAdd">
<xpath>Defs/ThingDef[ defName= "HiTechResearchBench"]/CompProperties_AffectedByFacilities/linkableFacilities</xpath>
<value>
<li>ResCogitator</li>
</value>
</Operation>
</Patch>

You want to add something to a list, which is why you have to use PatchOperationAdd.
The path in xml you want to change is Defs/ThingDef/CompProperties_AffectedByFacilities/linkableFacilities, where ThingDef has DefName= "HiTechResearchBench".
For each location it finds, which matches the path (in this case just one), it will insert everything listed in value in the patch operation.
#183
Quote from: Barky on November 28, 2017, 10:30:06 PM
Blass88 this multi-threaded mod of yours, is it expandable? Could you perhaps put 'fire' onto another thread, or something along those lines? I'm curious to see if we're just scratching the surface with this or not.
If you want to look at multi-threading and the potential, you should look at this thread https://ludeon.com/forums/index.php?topic=35982.0. It would appear to be an attempt at going all out on multi-threading and is worth keeping an eye on.
#184
Outdated / Re: [B18] Textile Storage
November 28, 2017, 10:33:36 PM
Quote from: frenchiveruti on November 28, 2017, 09:37:45 PM
Quote from: Kiame on November 28, 2017, 09:30:51 PM
For anyone that downloaded this earlier today please download it again. I introduced a bug which prevents the building of basically any furniture. SO sorry for any trouble!
May I suggest putting version numbers on the zip files so we can know when the mod gets "updated" in that way?
Because there's no way I would've notice that unless I checked the files.
The recommended format is v{rimworld major}.{Rimworld minor (18)}.{mod major}.{mod minor}
Speaking of version numbers, RimWorld is based on major.minor.build and so is targetVersion in About.xml. However from what I can tell from the vanilla code, only minor is actually used in the game and we can put whatever we want in build. I have decided to start with 0 and then increase by 1 each time I make a new release. ModCheck can read targetVersion of any loaded mod and make conditional patching or throw errors. This is done because it checks for the value of each number compared to a reference tag in the patch call to ModCheck. I'm not sure if anybody use this feature, but it might be more useful if mods generally would provide their version number this way.
#185
Mods / Re: [Mod Tool request] Loot for rimworld
November 28, 2017, 10:27:27 PM
QuoteWhile sorting, LOOT checks for load order errors (such as incompatibilities and missing requirements) and notifies you of any issues that it detects.
ModCheck can be used to display errors on missing mods, incompatible and incorrect order. However it's not automatic as such. Instead the mod creator has to fill in xml data to tell what is required. It's my impression that it's mainly used make a mod able to patch itself if a certain other mod is loaded, such as a mod with animals will apply a patch only if A Dog Said is loaded.

While it sounds cool to have auto detection of conflicts and missing stuff, I won't code it into ModCheck. It's intentionally small, written for speed and is intended to help make game startup faster, not slower as such a complex automatic detection would result in.
#186
Quote from: TeflonJim on November 28, 2017, 02:18:04 PM1. Only create a set of ThingDefs if a particular mod is present (and loaded)
I wrote a patch for that. I added it here with comments.

The idea is to use PatchOperationSequence. It's important to realize that a patch will be applied to each xml file in Defs in each mod. This mean you need to apply some xpath, which ensures the add new item will only apply once and not once for each xml file.
In this specific case PatchOperationAdd takes up that job because that operation is needed anyway, but there are multiple ways to do it.
<Patch>
<!-- a sequence works by taking each PatchOperation in operations and execute them one by one -->
<!-- if a PatchOperation in operations fail, the following will not be executed -->
<Operation Class="PatchOperationSequence">
<success>Always</success>
<operations>
<!-- only work if the needed mod is loaded -->
<li Class="ModCheck.isModLoaded">
<modName>A Dog Said...</modName>
<yourMod>MoreMonstergirls B18 Vanilla</yourMod>
</li>
<!-- make sure the mods are loaded in the needed order -->
<!-- delete this one if order doesn't matter -->
<li Class="ModCheck.loadOrder">
<modName>A Dog Said...</modName>
<yourMod>MoreMonstergirls B18 Vanilla</yourMod>
<errorOnFail>true</errorOnFail>
</li>
<!-- test if an xpath exist -->
<!-- PatchOperationAdd, PatchOperationInsert and PatchOperationTest can be used -->
<!-- which one you pick depends on your specific needs -->
<li Class="PatchOperationAdd">
<xpath>/Defs/ThingDef[defName = "BlackHarpy"]/recipes</xpath>
<value>
<li>InstallPegLegAnimal</li>
<li>InstallSimpleProstheticLegAnimal</li>
<li>InstallBionicLegAnimal</li>
<li>InstallSpineAnimalSimple</li>
<li>InstallSpineAnimalBionic</li>
<li>InstallBionicEyeAnimal</li>
<li>InstallAnimalBrainStimulator</li>
<li>InstallBionicAnimalHeart</li>
<li>InstallBionicAnimalLung</li>
<li>InstallBionicAnimalLiver</li>
<li>InstallBionicAnimalKidney</li>
<li>InstallBionicAnimalStomach</li>
<li>InstallNoseAnimalSimple</li>
<li>InstallJawAnimalSimple</li>
<li>InstallJawAnimalBionic</li>
<li>CureInjuryBurnAnimal</li>
<li>CureInjuryCrushAnimal</li>
<li>CureInjuryCrackAnimal</li>
<li>CureInjuryCutAnimal</li>
<li>CureInjurySurgicalCutAnimal</li>
<li>CureInjuryScratchAnimal</li>
<li>CureInjuryBiteAnimal</li>
<li>CureInjuryStabAnimal</li>
<li>CureInjuryGunshotAnimal</li>
<li>CureInjuryShreddedAnimal</li>
<li>CureInjuryBruiseAnimal</li>
</value>
</li>
<!-- insert the new item into Defs. In this case it's a recipe, but it can be anything -->
<li Class="PatchOperationAdd">
<xpath>/Defs</xpath>
<value>
<RecipeDef ParentName="SurgeryFleshAnimal">
<defName>InstallSimpleProstheticWingHarpy</defName>
<label>install simple prosthetic harpy wing</label>
<description>Installs simple prosthetic harpy wing. Requires a min skill of 4 in Medicine.</description>
<workerClass>Recipe_InstallArtificialBodyPart</workerClass>
<jobString>Installing simple prosthetic harpy wing</jobString>
<workAmount>2000</workAmount>
<skillRequirements>
<Medicine>4</Medicine>
</skillRequirements>
<ingredients>
<li>
<filter>
<categories>
<li>Medicine</li>
</categories>
</filter>
</li>
<li>
<filter>
<thingDefs>
<li>SimpleHarpyWing</li>
</thingDefs>
</filter>
</li>
</ingredients>
<fixedIngredientFilter>
<categories>
<li>Medicine</li>
</categories>
<thingDefs>
<li>SimpleHarpyWing</li>
</thingDefs>
</fixedIngredientFilter>
<appliedOnFixedBodyParts>
<li>LeftShoulder</li>
<li>RightShoulder</li>
</appliedOnFixedBodyParts>
<addsHediff>SimpleHarpyWing</addsHediff>
<recipeUsers>
<li>BlackHarpy</li>
<li>Harpy</li>
</recipeUsers>
</RecipeDef>
</value>
</li>
</operations>
</Operation>
</Patch>
#187
Mods / Re: [Mod Request] New Hauling Jobs
November 28, 2017, 07:29:39 AM
Quote from: Canute on November 28, 2017, 05:32:24 AMGrrrr i hate it when people point at steam
Here we go again. Last time I linked to a steam only mod, the topic became "no steam" rather than the mods themselves and it turns out your name showed up last time as well.

This time a specific feature is wanted in a new mod and I inform that it already exist and provide access to obtaining the wanted mod for both steam and direct download. Apparently it would have been better if I had just ignored this thread and not inform that the mod already exist because the next post starts out about how annoying I am. It actually annoys me quite a bit to be attacked like that and I may have to report posts like that if I keep getting attacked for being helpful.

It's fine that you post the link to the forum it contributes new and useful information. It may surprise you, but we actually agree that steam is far from perfect (though I said that multiple times already). However the reason why I picked the steam link this time is because I couldn't remember offhand either the name of the mod or if it's on steam, forum or both. I resulted to the ultimate tool for a case like that and apparently google prefer steam because the forum thread didn't show up, yet the steam mod was the second hit. Since it also contained a direct download link, I decided not to spend anymore time searching.
#188
Mods / Re: [Mod Request] New Hauling Jobs
November 28, 2017, 03:34:39 AM
Why start coding when Please Haul Perishables already exist? While it's a link to steam, there is a direct link in the description. It haven't been updated to B18 yet though, but it will happen eventually.
#189
It doesn't look like you can tell leather apart like that. However that's not the same as it looks impossible.

      <ThingCategoryDef>
        <defName>Leathers</defName>
        <label>leathers</label>
        <parent>Textiles</parent>
        <iconPath>UI/Icons/ThingCategories/Leathers</iconPath>
      </ThingCategoryDef>

You need to add domestic leather with Leathers as parent.

For cloth, you need to restrict to just domestic leather.

For butchering, you need to remove leather from the animals in question and then add the new leather types as butcherProducts. Vanilla has this as a fixed value, which is bad. I wrote a DLL for BoneMod where bones can be obtained from butchering and it's scaled for body size and missing body parts. While it's currently hardcoded to bones in the DLL, I have a plan for a standalone version where new butcherProducts can be added to any mod using xml only. It's sort of working, but it needs to be cleaned up and stuff before it's released. Now that I know there is a demand for it, I will give it a higher priority on the todo list.

You might have to create a thing for each new leather for this to work. I'm not sure about that part.

Oh and I like the idea of having groups of leather  :)
#190
Tools / Re: Mod Timing
November 27, 2017, 09:21:46 PM
Quote from: lperkins2 on November 27, 2017, 09:05:50 PMI don't know if DeepProfiler.Start works if it's already been started.  The hard part is profiling the patch methods.
It implements a stack, meaning you can safely start, call something and then end right after the call. If DeepProfiler is already working or is called somewhere in the call, it will just use the stack to still work as intended. The log entries will be indented to inform of the stack layout in case of nested calls.

Harmony Prioritiy annotations makes it look like it's possible to add two postfixes and by using [HarmonyBefore(string[])] and [HarmonyAfter(string[])], it should be possible to start DeepProfiler just before a specific Postfix starts and stop it when it ends. Profiling a Prefix, which returns false is more problematic as it will stop the execution of even the prefix, which will stop the profiling.

Quote from: lperkins2 on November 27, 2017, 09:05:50 PMAs for profiling jobs and job givers, they do seem to generally subclass the base implementation, but most mods don't super the job tick, so adding profiling to the base implementation doesn't do any good.  I don't know if there is a reflection option to get a list of subclasses which override the relevant methods, but applying the profiling patch to those would probably get the relevant information.
That's why I wrote about Transpillar. That will make it possible to inject start and stop code for DeepProfiler just before and after the call and then it doesn't matter which version of the virtual method is called.
#191
Quote from: kaptain_kavern on November 27, 2017, 08:09:20 PMNow I think I will just post a "Not compatible with:" statement in description.
Why do you expect people from not posting bug reports by adding something to the description? Add the incompatible note to the mod too with ModCheck.

<Operation Class="PatchOperationSequence">
<success>Always</success>
<operations>
<li Class="ModCheck.isModLoaded">
<modName>Tables+</modName>
<yourMod>Modular Table</yourMod>
<errorOnFail>true</errorOnFail>
<incompatible>true</incompatible>
<customMessageFail></customMessageFail>
</li>
<li Class="ModCheck.isModLoaded">
<modName>Tables+ (Linkables Only)</modName>
<yourMod>Modular Table</yourMod>
<errorOnFail>true</errorOnFail>
<incompatible>true</incompatible>
<customMessageFail></customMessageFail>
</li>
</operations>
</Operation>

Adding this will add a an error to the log while starting the game with either of those mods is loaded. That will make people notice and not report a bug even if they fail to read the full mod description.

customMessageFail can be removed or if you don't like the default message, you can write your own here. yourMod is supposed to the Name from About.xml from the mod you make. I took a guess at that one without looking it up.
#192
Quote from: coldtoad on October 20, 2017, 12:15:30 AMLet's see what we can do. I was thinking of duplicating the code base and implement the above features. If you would be willing to contribute with some of the code, I would be happy to work together!
Just for the record I haven't forgotten this statement and I still would like to work on such game mechanics at some point. However as it turned out, it seemed that first BoneMod and then patching became topics to take my modding time. I still have a point on the todo list where I plan to get back to this mod.
#193
Conflicting mods: [B18] Tables+ and [B18] Tables+ (Linkables Only). However I'm not sure knowing the offending mods will help you. One approach which might work would be to use PatchOperationAdd to add the offending furniture(s) to >/Defs< if conflicting mods aren't loaded.

The patch sequence would look something like this:
ModCheck.isModLoaded, incompatible>true< (first mod)
ModCheck.isModLoaded, incompatible>true< (second mod)
PatchOperationTest
PatchOperationAdd

The test is to test for a path, which is only present in one file. The alternative is to patch every single xml file with the linkable stool.
#194
Help / Re: [A17] A warning to modders: xpath performance
November 27, 2017, 06:43:13 PM
Another xPath performance pitfall

You should not have multiple Operation for patching the same xml file. Use sequences instead. However one sequence can't patch more than one xml file.

Wrong: (itemA and itemB are in the same xml file)
<Patch>
<Operation Class="PatchOperationAdd">
<xpath>/Defs/ThingDef[defName = "itemA"]/recipes</xpath>
<value>
whatever
</value>
</Operation>
<Operation Class="PatchOperationAdd">
<xpath>/Defs/ThingDef[defName = "itemB"]/recipes</xpath>
<value>
whatever
</value>
</Operation>
</Patch>


Correct: (itemA and itemB are in the same xml file)
<Patch>
<Operation Class="PatchOperationSequence">
<success>Always</success>
<operations>
<li Class="PatchOperationAdd">
<xpath>/Defs/ThingDef[defName = "itemA"]/recipes</xpath>
<value>
whatever
</value>
</li>
<li Class="PatchOperationAdd">
<xpath>/Defs/ThingDef[defName = "itemB"]/recipes</xpath>
<value>
whatever
</value>
</li>
</operations>
</Operation>
</Patch>


The reason is that each patch file is applied to every single xml file inside Defs. When a patch file is applied, it tries to apply each Operation. The first example has two Operations, which mean xPath is checked twice for each Def xml file.

The second has just one Operation. It starts by searching for itemA and only if it is found will it search for itemB. This mean all the files not being patched can be checked in half the time.

The number of def xml files is fairly high. It's almost 400 for core alone and when adding mods, it quickly exceed 1000. This mean it doesn't really matter how much time you spend while patching a file. Instead the performance is mainly determined by how much time you spend on figuring out the patch is working with the wrong file. 20 PatchOperations in sequence will be around twice as fast as two PatchOperations, which aren't in sequence.

However the nature of PatchOperationSequence mean you have to ensure that the items you patch are in fact in the same file. If itemA and itemB aren't in the same file, itemB will not be patched because the search for itemA will fail.

If you release a mod where you expect other mods to patch it, do consider putting the "likely to patch" data in as few files as possible, preferably one if it isn't too ugly. This will allow patching using fewer sequences.

While this is about reducing the number of needed xPath searches, the point in the first post still applies as this is regarding the time spend for each xPath search. Those two "fixes" work well together and you have to use both to the full extend to get the fastest possible patch file.
#195
Quote from: TeflonJim on November 27, 2017, 04:29:09 PM
The biggest problem with PatchOperationFindMod for me at this point is not the need to list by ID and name. Rather that it gives no way of differentiating between mods that are present on the system and mods that are active in a load order. If a mod is present, match will execute.
:o
Checking if a mod is on the HD, but not loaded is so useless while patching that it did not cross my mind, not even testing if it works like that.

ModCheck.isModLoaded will test to see if the mod is in the list from ModsConfig.ActiveModsInLoadOrder, meaning it will not care what is on the HD, but rather it checks for enabled mods. ModCheck.loadOrder can tell the load order of two mods while ModCheck.isVersion tells if a mod is of at least a specific version. Each can be used with success Invert, meaning it should pretty much cover everything I can think of anybody would need when making conditional patching.

Each of those can print errors to the log on failure, or just messages on success or failure. Default is not writing to the log, but it allows the patch file to write an error if a required mod is not present, an incompatible mod loaded, incorrect order etc. This too should cover any case I could think of being useful when writing patch files.

If you think need anything else, let me know and I will consider adding it.