Ludeon Forums

RimWorld => Mods => Tools => Topic started by: Nightinggale on October 31, 2017, 06:57:04 PM

Title: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on October 31, 2017, 06:57:04 PM
Toolkit for xml modders. Adds 13 new patch operations. Eliminate the need for patchmods. Patch according to presence, order or version of mods. Reorder xml elements, write patching results and test results to the log. Allow faster patching (shorter startup time) and measure how long each patch spends patching.

The primary task for ModCheck is to remove the need for patch mods. It's done by adding test operations, which can tell if another mod is loaded, if one mod is before another, is of at least a certain version, either in About or in ModSync. Each of those can be reversed (not loaded etc).

Adds logic operators, like sequence, AND, OR, If else conditions. This can be used together with the test operations or vanilla operations to make complex test conditions if needed.

Boost performance. Need to do multiple patching operations on the same building? Search, keep the result and run a list of patches without performing a full xpath search for each operation.

Added a bed and want it to appear in the build menu next to the vanilla beds? The Move operation allows you to alter where your modded building will appear.

Feature rich log writing. Get operations to write messages, warnings and errors if operations succeed or fail. Tell the user if a needed mod isn't loaded or load order is incorrect. Also allow writing conditionless with whatever message you might want to add.

Profile patches. Measure how much time is spend on each patch. ModCheck is aware of which mod owns which patch, meaning you can get a precise view of the startup time of your mod. You can name your patches if root operation is from ModCheck, like ModCheck.Sequence. This will allow performance printout with names rather than just patch 1,2,3....

Links:
Steam (https://steamcommunity.com/sharedfiles/filedetails/?id=1544705976)
GitHub (https://github.com/Nightinggale/ModCheck) (direct download, source code and wiki manual)

Quote from: Changelog
Updating ModCheck will not break existing xml files unless stated otherwise.

v1.8.1
- Fixed compatibility issue with updated Rimworld. Profiling works again.
- Updated version URL for Fluffy's Mod Manager

v1.8 (RW 1.0)
Update to about only. The DLL file will not even have to be updated.

- RimWorld 1.0 support
- Added support for Fluffy's Mod Manager

v1.8
This is a significant update from a coding point of view. B19 vanilla changed completely regarding patching.
While the code is significantly better, all Harmony calls from ModCheck had to be redesigned and rewritten.

- Added B19 support
- Added Search operation to speed up patching when the same object is patched multiple times in a row
- Added Move operation to control cases where order matters (like order of building buttons)
- Patch profiling now measures the time more accurately (less rounding errors)

XML BREAKING ALERT!!!
Removed FindFile operation (vanilla rewrite renders it both obsolete and impossible to implement)
Any xml file with FindFile will need updating.

v1.7
- Speedboost: cached mod indexes for massive speed boost of some ModCheck internals
- Rewritten the log writing system to give better control/more features to patch writers
- Rewritten error messages to make it easier to find the error
- Changed profiling output. Total on top, one entry for each mod
- All PatchOperation names can now be used starting with both upper and lower case (fixes naming inconsistency)
- Added new mode to LoadOrder. It can now use first and last strings instead of the old approach (which still works)
- Added Sequence operation, which does the same as the vanilla operation, but with ModCheck specific options
- Added logic operations AND, OR, IfElse, Loop and Once
- Added warning/error if outdated versions of ModCheck are being loaded (risk of new vs old conflicts)
- Added a preview logo (thanks to larSyn for drawing it)
- Added support for ModSync RW
- Fix: profiling now displays correct time if the hardware has a high precision timer
- Fix: profiling will no longer cut off the output if you have a lot of patches
- Removed the need to include yourMod and modName unless they are actually used

v1.6
- Added FindFile to greatly speed up patch files
- Added patch operation profiling (with verbose logging only)

v1.5
- Added ModSync.xml
- Added PatchOperation isModSyncVersion

v1.4
- Fixed issue where cache failed to update as needed

v1.3
- Fix: checks are now only executed once (massive performance boost)
- Fix: writing to the log will now always only write one line and never repeat the same many times

v1.2
- Added custom message support (like logging: My mod detected modX and will patch itself accordingly)
- Added ability to detect another mod by more than one name (like name v1.3 and name v1.4)
- Major code redesign to greatly reduce the risk of bugs when adding new features

Note: stopped releasing for A17 due to the release of stable B18.
If you want to use A17, copying the v1.2 DLL will likely work, but it's untested.

v1.1
- Converted to mod layout for steam release

v1.0
- Initial release

(http://verify.modsync.ninja?7d2c6dd5-a2de-432a-80ff-01a413479595) (http://www.modsync.ninja)
Title: Re: [TOOL] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on October 31, 2017, 09:39:16 PM
reserved
Title: Re: [TOOL] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on October 31, 2017, 09:39:24 PM
reserved
Title: Re: [TOOL] ModCheck: patch tests and error logging for mod loading
Post by: kaptain_kavern on November 01, 2017, 01:43:16 AM
Looks quite promising. Thanks for making that
Title: Re: [TOOL] ModCheck: patch tests and error logging for mod loading
Post by: Redfire1200 on November 01, 2017, 06:36:56 PM
Quote from: Nightinggale on October 31, 2017, 06:57:04 PM
including error messages for incorrect setup. .
What exactly do you mean by this, do you mean if I was making a mod and did something wrong in the defs it would point it out? Or do you mean if a put the mods in the wrong order or some thing like that?
Title: Re: [TOOL] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on November 01, 2017, 07:06:25 PM
Quote from: Redfire1200 on November 01, 2017, 06:36:56 PM
Quote from: Nightinggale on October 31, 2017, 06:57:04 PM
including error messages for incorrect setup. .
What exactly do you mean by this, do you mean if I was making a mod and did something wrong in the defs it would point it out? Or do you mean if a put the mods in the wrong order or some thing like that?
No, it refers to incorrect setup of by the user in the mod load order list. It means the user will get an error if required mod is not loaded, is loaded after your mod if it has to be before etc. It will not verify the work you have done in your xml files and you have to make a patch file to tell what it should test on game startup. The front page on GitHub has some examples of setup at the bottom.
Title: Re: [TOOL] ModCheck: patch tests and error logging for mod loading
Post by: Redfire1200 on November 01, 2017, 07:25:16 PM
So if a mod needed hugslib or jecstools loaded first and I put them last it would tell me?
Title: Re: [TOOL] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on November 01, 2017, 07:41:52 PM
Quote from: Redfire1200 on November 01, 2017, 07:25:16 PM
So if a mod needed hugslib or jecstools loaded first and I put them last it would tell me?
Yes it's precisely that, though depending on configuration, it can tell about incompatible mods and outdated mods as well.

Half of the code from the first example in the guide. You want to make ModX require HugsLib.
<Operation Class="PatchOperationSequence">
<success>Always</success>
<operations>
<li Class="ModCheck.isModLoaded">
<modName>HugsLib</modName>
<yourMod>ModX</yourMod>
<errorOnFail>true</errorOnFail>
</li>
<li Class="ModCheck.loadOrder">
<modName>HugsLib</modName>
<yourMod>ModX</yourMod>
<errorOnFail>true</errorOnFail>
</li>
</operations>
</Operation>

It can produce the following errors: (just one, not both at once)
Missing mod: "HugsLib", needed by "ModX"
Mod load order: "HugsLib" needs to be loaded before "ModX"

As all other errors, those lines will show up in the log, be printed in red and force the log to appear on game start.

And do remember that those checks returns a bool, meaning they can be used for conditional patching as well. If errorOnFail is not mentioned, it will not print to the log, meaning you can make patch operations trigger on presence of other mods. No need to make separate patch mods to add compatibility.
Title: Re: [TOOL] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on November 06, 2017, 12:45:42 AM
I have realized I didn't add support for the error strings to be translated. I plan to fix that as well as adding support for a custom error message.

Since it looks like I will be updating anyway, do anybody have any feature requests?
By design you can add whatever you want in as many tags as you like and then it has access to do whatever we want in C# as it has access to everything in the game and then it results in a true/false statement to use to tell if something should be patched. This gives a whole lot of options, but I don't know what you need, so tell me.

Another question: do anybody use this?
So far there has been just 5 downloads and I don't know of any mods, which use this or plan to use it. I'm considering putting development on hold until I know for sure people are actually using this. If you aren't using this, I would like to know why and if there is anything I can do about it. Part of my goal is to get mods to tell me when I make a mistake in mod load order (it has happened), but this tool doesn't help with that problem unless mod creators/maintainers add ModCheck and fill out a patch file with the mod requirements.
Title: Re: [TOOL] ModCheck: patch tests and error logging for mod loading
Post by: kaptain_kavern on November 06, 2017, 10:39:48 AM
A18 will have a method to check for other mods natively BTW

https://ludeon.com/forums/index.php?topic=36208.msg375367#msg375367
Title: Re: [TOOL] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on November 06, 2017, 01:43:22 PM
Quote from: kaptain_kavern on November 06, 2017, 10:39:48 AM
A18 will have a method to check for other mods natively BTW
Looks like I'm not doing too well  :'(

I had a look since it's already in A18 unstable. I find it a bit odd because it requires a list of mods and it is true if one or more is present. In other words to check for 3 mods, you have to make 3 checks, not one check with 3 mods in the list.

Now I'm considering major redesigning of ModCheck. It should be one check, but then it contains lists, like:
<MyModName>something</MyModName>
<MandatoryBefore>
    <li>HugsLib</li>
</MandatoryBefore>
<Incompatible>
    <li>some other mod</li>
</Incompatible>

Would people use it if it is written like this?

Would people be more likely to use this if I turn this into a mod? (no need to include a DLL file in your mod)

What would it take to make this a must have mod? I would really like if the mods themselves tell if your modlist results in incorrectly working mods.
Title: Re: [TOOL] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on November 08, 2017, 09:05:52 PM
Released version 1.1. The only change is that it can now be loaded as a mod. This allows me to put it on steam. Hopefully this will make more people aware of what I have made as it seems to be fairly unknown and unused so far   :'(
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: larSyn on November 11, 2017, 09:08:26 PM
Quote from: Nightinggale on November 08, 2017, 09:05:52 PM
Released version 1.1.....Hopefully this will make more people aware of what I have made as it seems to be fairly unknown and unused so far   :'(

Don't feel bad, Nightingale.  After you posted in my Help thread I downloaded it and rewrote all my patches using it.  I didn't know about the new Patch Operation either... ::)  Anyway, ModCheck worked very well during my testing, and I plan on using it for now.  I would definitely be interested in seeing what else you add.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on November 12, 2017, 12:02:50 AM
Quote from: larSyn on November 11, 2017, 09:08:26 PMDon't feel bad, Nightingale.
I don't feel bad about getting awareness anymore. In the very precisely 3 days it has been on steam, ModCheck has gained 98 subscribers. Granted that's for A17 and A18 combined, but A18 has 67 subscribers alone, meaning it is somewhat known by now.

Quote from: larSyn on November 11, 2017, 09:08:26 PMAfter you posted in my Help thread I downloaded it and rewrote all my patches using it.  I didn't know about the new Patch Operation either... ::)  Anyway, ModCheck worked very well during my testing, and I plan on using it for now.
First mod confirmed to actually using ModCheck. Sounds good and thanks for reporting back. While I expected it to work just fine, it's good to know other people can figure out how to make it work as well.

Quote from: larSyn on November 11, 2017, 09:08:26 PMI would definitely be interested in seeing what else you add.
Me too. Right now all I can think of is allowing the strings to be translated and to allow custom error messages, like adding an xml tag of a line, which will be used if set. While I might change lots of stuff in the future, I plan to be backward compatible meaning the patch xml files being written now should work with future versions as well.

Ideas for new features are welcome.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: larSyn on November 15, 2017, 10:18:53 AM
Quote from: Nightinggale on November 12, 2017, 12:02:50 AM
I don't feel bad about getting awareness anymore. In the very precisely 3 days it has been on steam, ModCheck has gained 98 subscribers. Granted that's for A17 and A18 combined, but A18 has 67 subscribers alone, meaning it is somewhat known by now.

Yeah, Steam seems to be the place to post mods.  I got far more users there than from here.  But, that's all right, I like it here.  Lots of helpful, friendly people.

Quote from: Nightinggale on November 12, 2017, 12:02:50 AM...While I expected it to work just fine, it's good to know other people can figure out how to make it work as well.

The only bit of trouble I had was which mod name to use, the folder name or the name in About.xml.  I obviously figured it out, but maybe you should throw that in the guide on your Github page to prevent any future confusion.  Other than that, everything was very easy to follow.

Quote from: Nightinggale on November 12, 2017, 12:02:50 AMMe too. Right now all I can think of is allowing the strings to be translated and to allow custom error messages, like adding an xml tag of a line, which will be used if set. While I might change lots of stuff in the future, I plan to be backward compatible meaning the patch xml files being written now should work with future versions as well.

Ideas for new features are welcome.

That sounds good.  I was going to ask about the patch operation staying the same, since I don't really want to go back and rewrite it all...lol 

Would something that lets users know about compatibility patches be possible?  For example, I have a patch for Vegetable Garden in my mod.  When someone activates my mod would it be possible to have it say something like "Hey this mod works great with Vegetable Garden!" or something else along those lines?  Perhaps have it in green text on the log, a pop-up, or something in the Mod Settings menu?  And, while I'm at it here, maybe also a way to direct them to the Steam/forum page to download it (a url in the xml maybe)?  I'm just starting to learn about C#, so I don't really know what is and isn't doable in regards to this kind of stuff...so don't worry about it if this isn't possible.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on November 15, 2017, 10:31:03 PM
Quote from: larSyn on November 15, 2017, 10:18:53 AMYeah, Steam seems to be the place to post mods.  I got far more users there than from here.  But, that's all right, I like it here.  Lots of helpful, friendly people.
I realize that's the case for players, but it has turned out it's the case for modders as well.

Quote from: larSyn on November 15, 2017, 10:18:53 AMThe only bit of trouble I had was which mod name to use, the folder name or the name in About.xml.  I obviously figured it out, but maybe you should throw that in the guide on your Github page to prevent any future confusion.  Other than that, everything was very easy to follow.
Updated and good point. At the time ModCheck activates, it only has access to xml contents and is not really aware of folder or filenames. Well it might be aware of other stuff, but I haven't found out yet. This makes it obvoius that it's the name inside an xml file. I tried to write the guide to not require any knowledge of how the code works, but it seems I missed this one.

Quote from: larSyn on November 15, 2017, 10:18:53 AMThat sounds good.  I was going to ask about the patch operation staying the same, since I don't really want to go back and rewrite it all...lol 
Completely as expected  ;D

The thing is that now ModCheck is on steam and for all I know modders will start to depend on the user adding ModCheck rather than downloading the dll. This means if I update on steam and it's not backward compatible, a worst case scenario is that maybe half the mods break. This is of cause completely unacceptable and even the excuse "it's very easy to fix in xml" is not good enough. This means breaking backward compatibility is simply not an option.

If I have to do something, which will break backward compatibility, I will add a new class, possibly based on copy paste of an existing one and then change the new one. Existing mods can then continue to work off the old class. It's entirely likely that I will update the guide to tell modders not to make new mods using the old class, but it will still be there to ensure mods will not break.

If a mod breaks from this (like the user stops using ModCheck), all what will happen is an error in the log each time a ModCheck class is called and all the calls will return false, like mod is not loaded, regardless of it is or not. Other than that, the mods will behave normally, meaning they will often be fully playable. Even if it's not the end of the world to cause problems like this, I will still avoid it as much as possible.

Quote from: larSyn on November 15, 2017, 10:18:53 AMWould something that lets users know about compatibility patches be possible?  For example, I have a patch for Vegetable Garden in my mod.  When someone activates my mod would it be possible to have it say something like "Hey this mod works great with Vegetable Garden!" or something else along those lines?
That's a nice idea. Here is what I'm going to do:
It's nice and simple and it allows great freedom to write whatever you want to the log. Maybe adding default options like "yourMod: detected modName and patched itself to become compatible".

Quote from: larSyn on November 15, 2017, 10:18:53 AMPerhaps have it in green text on the log, a pop-up, or something in the Mod Settings menu?  And, while I'm at it here, maybe also a way to direct them to the Steam/forum page to download it (a url in the xml maybe)?  I'm just starting to learn about C#, so I don't really know what is and isn't doable in regards to this kind of stuff...so don't worry about it if this isn't possible.
All nice ideas, but they all clashes with the design strategy, which is to make a lightweight mod, which adds classes to be called from xml and not touch existing code. By not touching any existing code, the chance for conflicts with other mods is kept at a minimum. It's likely part of the reason why the very same DLL works on both A17 and A18. Not just the same code, but the very same file. The difference between A17 and A18 releases is the number in About.xml and nothing else.

I agree it would be nice to add such info in the mod load menu, but it would have to be done by some other mod. Maybe I will do something like that in the far future, but not anytime soon and it will be in a different mod. It is important that if it conflicts with anything else modding the mod menu, people can turn that feature off without turning ModCheck itself off. With a little creativity, it should be possible to make some xml layout, which can be executed by both mods, meaning you only have to write once that your mod works together with some other mod.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on November 20, 2017, 10:47:36 PM
Is there anybody, who use the patch operators from ModCheck for conditional patching?
I mean the only real reason to do that is to patch if a mod is loaded or not loaded using ModCheck.isModLoaded and B18 fixed that issue with PatchOperationFindMod.

The reason I'm asking this is that I have run into some limitations and is considering to discontinue PatchOperations and implement my own system. The benefits would be the following (most likely incomplete):
The mod list is not something I have plans for at all for the time being. However with a well defined xml layout and C# code to copy paste to pass the xml file, any mod can read the contents and say add red dots if mod is missing requirements or order is incorrect and even write what is wrong. One beauty of this approach is that if somebody writes such a mod for the modlist, the mod creators can write one xml file to support both mod list and ModCheck, making it really easy to use both.

The only issue is that the new system doesn't support patching based on mod order or mod version. I don't really see a big need for this though, but since those are already released, I feel like I better need to ask. Maybe I should just leave those in the DLL and ignore them. It's not like they will hurt the ability to add a new system.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: larSyn on November 21, 2017, 09:25:49 AM
Quote from: Nightinggale on November 20, 2017, 10:47:36 PM
Is there anybody, who use the patch operators from ModCheck for conditional patching?
I mean the only real reason to do that is to patch if a mod is loaded or not loaded using ModCheck.isModLoaded and B18 fixed that issue with PatchOperationFindMod.

Yup, I do, if by "conditional patching" you mean "if Mod X is loaded run this patch" (like I've said before, I'm still very green with all this coding stuff, so if I screw up with/misunderstand some terminology, sorry...I'm actually a 3d artist/designer by profession, so I'm slightly out of my element lol).  I made all my patches with ModCheck in A17 and they all continue to work fine in B18.  I didn't find out they were adding "PatchOperationFindMod" until after I had finished writing the patches with ModCheck. Not a huge deal if you remove it, just means a bunch of copy/pasting the new FindMod operation.  I also used it to check for Architect Sense and then used "ModCheck.loadOrder" to make sure they are loaded in the proper order.

Glad you liked some of my suggestions.  And I see what you mean about the redirect defeating the purpose of the lightweight design.  Looking forward to seeing what you do with it all!

Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on November 22, 2017, 07:29:02 PM
ModCheck 1.2 has been released on Github and steam. I updated the first post with a changelog.

I don't think I will develop this much further, if at all. It seems fairly complete. Also I discovered something interesting in the vanilla code yesterday. It has given me the idea to make a completely new mod where when the game starts, it will verify the loaded mods similar to what ModCheck does. However on failure, it will create a popup asking if it should fix the problems automatically and if you say yes, it will change the order of loaded mods and then restart the game. It might even become able to detect missing mods and subscribe to them from steam if the user clicks yes. While I'm far from certain that this will ever work, it sounds too good to not investigate further and ignore that it smells strongly of being very time consuming to investigate and make.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: SargBjornson on November 23, 2017, 04:09:24 PM
I'm trying to use Modcheck to provide A Dog Said compatibility for Genetic Rim, and everything went perfectly so far, except for one thing! Operations using attributes on the xpath, like for example:

<xpath>/Defs/RecipeDef[@Name = "OldWoundsAnimal"]/recipeUsers</xpath>

seem to be failing. Is this a limitation, or am I derping hard?
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on November 23, 2017, 05:21:08 PM
If you have an issue where one xPath works and one fails, then it's a vanilla issue. All ModCheck does is make a test and return true/false to tell the vanilla patch engine if the test passed. If it passes, then the vanilla patch engine moves on to the next PatchOperation and whatever happens here is completely unrelated to ModCheck.

I left out log writing because while ModCheck can do that, it's completely unrelated to how patching takes place.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on November 24, 2017, 03:46:09 AM
I downgraded the steam version to v1.1 because people report severe performance issues in v1.2, like adding 10 minutes to the startup when using a lot of mods and v1.1 apparently didn't have this issue.

The big question is why because there is no obvious candidate for this, particularly since the vast majority of mods will not even call the DLL.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: larSyn on November 24, 2017, 11:16:52 PM
Quote from: Nightinggale on November 24, 2017, 03:46:09 AM
I downgraded the steam version to v1.1 because people report severe performance issues in v1.2, like adding 10 minutes to the startup when using a lot of mods and v1.1 apparently didn't have this issue.

The big question is why because there is no obvious candidate for this, particularly since the vast majority of mods will not even call the DLL.

I had a couple users on Steam report this to me as well.  I know that one of them (haven't heard back from the other) has the standalone version of ModCheck downloaded, so I'm guessing that is what caused his long loads.  Also, removing my mod stopped the long load times.  This leads to me to a few questions, does the standalone version take precedence over an included dll?  Is it possible that the presence of both causes the long load times?  Did the people who reported it to you have my or some other mod with the ModCheck dll in it? 

*Edit: I've tried downloading the standalone pre-release on github, and running it with my mod with both versions of the dll, but I still couldn't reproduce this.  I will add that I only have a handful of mods installed, if that helps/makes any difference at all.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on November 25, 2017, 12:03:45 AM
Quote from: larSyn on November 24, 2017, 11:16:52 PMThis leads to my question, does the standalone version take precedence over an included dll?
The one used is the one first in the mod list, which is why I recommend the steam version to be first. The reason is that v1.2 can read all xml files for v1.1, but v1.1 can't read v1.2 files if they use the tags added in v1.2.

I figured out what the problem is. It turns out that patching is done differently from what I thought. Instead of reading all defs and then patch, it reads everything in patches in all mods, then read def xml files in the mods one by one and when read file is read, all patches is executed on it. Last all the xml files are merged into one big system in the game.

As a result of this, each patch in ModCheck is executed once for each xml file in Defs in each mod instead of once like I thought it would. Obviously this scales very poorly. Since the result depends on the mod list only, not the individual files, I have turned the checks into checking the first time they are called and the following will return the cached result. I will release this once I'm done testing to ensure that the cache will not break something else.

As a nice sideeffect this happens to be the reason why output was written multiple times in the log and the fix will at the same time fix this issue as well.

All versions of ModCheck suffer from this issue, but the reason why v1.2 is worse is that it supports multiple mod names. What it does is it adds modName to the list and then it loops the list until it finds one, which is present. If none are present, it will loop the entire list. The problem with this is that it adds modName each time it's called, meaning even if you gave just one name, the 500th xml file will have a list of 500 modNames, all the same and it will check each. This mean while v1.1 will have a slowdown of (number of def files), v1.2 will have a slowdown of (number of def files)2. Each is worst case scenario, but it seem that some people ran into it with v1.2.

I ran some tests and with 200 mods and ModCheck can do around 50k tests in the time it takes to load the def files. Even with room for scaling issues I didn't take into account, I will say that the cache will make ModCheck feel instant.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on November 25, 2017, 12:08:50 AM
Quote from: larSyn on November 24, 2017, 11:16:52 PM*Edit: I've tried downloading the standalone pre-release on github, and running it with my mod with both versions of the dll, but I still couldn't reproduce this.  I will add that I only have a handful of mods installed, if that helps/makes any difference at all.
To reproduce this, you need tests where modName is not in your modlist. When that happens, the execution time will be multiplied by (number of def files in all mods)2. I didn't manage to hit that condition either by testing different mod configurations at random. I had run multiple times with verbose logging and read vanilla source code before I figured out what happened and how to trigger the slowdown.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on November 25, 2017, 03:22:24 PM
ModCheck 1.3 has been released. Upgrading right away is strongly recommended.

Table to give an idea of the scale of the performance issue. It lists iterations (executions) of the check code vs the number of def files in all mods combined. This includes core. Remember this is for each test in xml, those numbers will have to be multiplied by the number of times somebody adds patch operation.








500
1000
2000
PatchOperationFindMod (vanilla)
501
1001
2001
ModCheck 1.0
501
1001
2001
ModCheck 1.1
501
1001
2001
ModCheck 1.2*
125251
500501
2001001
ModCheck 1.3**
1
1
1
*v1.2 can be as fast as v1.1, but it depends on what is tested and the test result.
**While called the same number of times as vanilla, it executes once and use cache for the rest of the calls.

I view the performance issue as a lucky accident because if it didn't, we would still be stuck with v1.1 speed. Now we know time spend on each check is too low to be measured because it's below 0.001 seconds. Not even vanilla is that fast.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: SargBjornson on November 26, 2017, 05:14:57 AM
Hi Nightinggale!

People reported errors to me, and it seems Modcheck is giving some problems with 1.3. I swapped it for 1.1 and it seems to work. The operation that seems to be failing is:

<li Class="ModCheck.isModLoaded">
<modName>A Dog Said...</modName>
<yourMod>GeneticRim a18</yourMod>
</li>


Which seems quite simple, and works on 1.1
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on November 26, 2017, 08:59:40 AM
ModCheck 1.4 has been released to fix the issue mentioned below.

Quote from: SargBjornson on November 26, 2017, 05:14:57 AM
Hi Nightinggale!

People reported errors to me, and it seems Modcheck is giving some problems with 1.3. I swapped it for 1.1 and it seems to work. The operation that seems to be failing is:

<li Class="ModCheck.isModLoaded">
<modName>A Dog Said...</modName>
<yourMod>GeneticRim a18</yourMod>
</li>


Which seems quite simple, and works on 1.1
Now that's a bug report, which is really useful when it comes to figuring out what went wrong. It provides both the file, which failed, the mod combo and the info that it used to work. This means instant success in reproducing the problem, which doubles as testing for a fix and the git history provides info on what changed since it last worked.

The issue turned out to be that a copy paste error had resulted in having two variables with the same name, which meant the cache update in this case was written to the short lived variable and then discarded. Usually compilers warn about hiding a variable like that because it's almost always a bug, but it doesn't look like I can get MSVS to provide that warning ???
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: SargBjornson on November 29, 2017, 03:41:15 PM
So it should be safe to update to 1.4 now, right? :)
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on November 29, 2017, 11:41:51 PM
Following the v1.2 incident, I have been looking into patching and performance. It turns out that patching is actually quite slow and as the number of mods increase, so does both the number of patches and how much time each patch will spend patching. Poorly written patches can easily take up most of the startup time, though good written patches can't be considered fast either, just faster than horribly slow. Interestingly the majority of the time spend on a patch is for that patch to look through def xml files and go "no, nothing in this one to patch".

I have come up with a concept where you can write something like:
<li Class="ModCheck.something">
<modName>A Dog Said...</modName>
<file>Defs/RecipeDefs/Recipes_Surgery.xml</file>
</li>

This will then be a test, which is only passed when the two strings match the strings for the current file. This comparison is a lot faster than xpath searching to locate the correct file and as such should improve performance. Since the vast majority of patches are written to patch one specific file, this approach should be something, which can be used for more or less all patches.

An added bonus for this is that it exposes data, which can be used to profile each PatchOperation. Right now xml loading and patching is heavily profiled with results written to the log if verbose logging is on. However it is based on files/mods and figuring out if your newly added patch file is slow is almost impossible. I have an idea on how to get combined time spend on each PatchOperation, which should be reported with owner modname. That way everybody can identify poorly written patches and we can hopefully locate and optimize all of them. I estimate that for people with lots of mods, this can likely save at least 30 seconds for every minute spend on xml loading, though going as high as 45-50 seconds can't be completely ruled out.

There is one big problem though. This will require Harmony. This will clash with the current distribution system where people add a single dll file to their own mods. Instead it will become like HugsLib or similar where the user has to add it. I can probably do something like HugsLibChecker (https://github.com/UnlimitedHugs/RimworldHugsLibChecker), but the user still has to add it. The number of steam subscribers is 672 and that's before any mod has it as requirement.

I thought about splitting ModCheck into two or somehow make a minor version of it, but I think it's a bad idea. Ideally everybody should use the fastest approach and having a version with isModLoaded only or similar will encourage not using the new and faster checks.

Do any of you have anything to say about this before I make up my mind on what to do?

Quote from: SargBjornson on November 29, 2017, 03:41:15 PM
So it should be safe to update to 1.4 now, right? :)
Yeah, it was safe the moment it was released. If people subscribed on steam they already upgraded because the standalone mod takes priority if people load it first, which the description tells them to do  ;)
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: kaptain_kavern on November 30, 2017, 03:44:35 AM
The file checking thing is clever ;-)

About Mod check distribution: maybe see with hugslib author to merge your mods? As it's the only one library nearly every mod users have.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: larSyn on December 01, 2017, 11:45:17 AM
Quote from: Nightinggale on November 29, 2017, 11:41:51 PM
...
Do any of you have anything to say about this before I make up my mind on what to do?

I really like the sounds of faster load times.  I use a lot of patches and anything that speeds up the process is a good thing imo. 

I vote keep it all in one for the same reasons you state.  No need for more mod clutter. 

One question.  Why couldn't we include the Harmony dll in our mods with ModCheck?  I thought that was one of the good things about Harmony, in that users didn't need to download it.

Otherwise, just want to say great work on this so far.  You've made a very useful thing for people like me, and you've been super fast with fixes.  ModCheck is far easier to use than the new vanilla mod checking patch (and far superior), not to mention the other features it adds. :)
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on December 01, 2017, 03:07:20 PM
Quote from: kaptain_kavern on November 30, 2017, 03:44:35 AMAbout Mod check distribution: maybe see with hugslib author to merge your mods? As it's the only one library nearly every mod users have.
Contact established and idea rejected. Both parties have concerns about the same problem: what if ModCheck has an update to release and HugsLib has none? There are other issues as well. I kind of like the thinking of an instant distribution it would include though, meaning it was a good proposal, which would need to be considered. I mean when faced with a problem with no clear best solution, all options should be considered.

Quote from: larSyn on December 01, 2017, 11:45:17 AMOne question.  Why couldn't we include the Harmony dll in our mods with ModCheck?  I thought that was one of the good things about Harmony, in that users didn't need to download it.
It could be done. However there is another problem regarding including DLL files. Say we have two mods called A and B. A has ModCheck 1.1 and B has v1.4. B use some of the tags introduced in v1.2. On startup, A is loaded first, then B. A loads ModCheck and when B loads, it detects ModCheck is already loaded and will not reload it. When patching, the patches from A works just fine. When B patches, it encounters a tag not mentioned in the DLL and it causes an error.

I simplified the problem and loading process, but essentially that's the problem. The ModCheck.dll from the first mod in the modlist is used, even if it isn't updated. I have posted in the Harmony thread about this because Harmony must be affected as well and hopefully a solution will be found. This is already a problem and it actually has nothing to do with adding Harmony, meaning a solution should be found regardless of the directions of development.

I have come up with a different idea though. I can make another mod consisting of one DLL file. A mod, which is intended to be perfect on release and will not have to be updated and as such should not suffer from the different version issue. This mod adds one PatchOperation. It works like .isModLoaded, as in it checks if a mod is loaded and it includes a cache to ensure it's only checked once for performance reasons. On failure, it will open a popup where it will display stuff, which can be set with tags in xml. This will include links to steam, direct download, button for enable mod, subscribe to steam (if I can figure out how to do that). Stuff like that. If each mod adds this, then people will be told to get a specific mod, in this case ModCheck and there will only be one ModCheck.dll. Add minimum required targetVersion and it will even catch the case where somebody use v1.1 as direct download and the mod expects v1.4.

I actually like this idea, perhaps even better than figuring out how to load the newest DLL (though that would be good too) because this can be used for multiple mods, not just ModCheck. Since most people use steam, adding the ability to make RimWorld itself subscribe to a steam ID and enable that mod will make adding more mod requirements less of an issue than it is today.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on December 02, 2017, 08:13:27 AM
Turns out Harmony suffers from the same issue and I have now made a bug report for RimWorld, which will hopefully result in us eventually being able to load the newest DLL rather than what happens to be the first. For the time being, update your mod to the newest DLL even if all it does is adding a new feature (like a PatchOperation), which do don't plan to use.

I kind of discarded the idea of having another mod to tell if ModCheck is loaded. It quickly turned into a ModCheck clone  :-[
One interesting thing came out of it. If I write a modName in the new (now discarded) mod and that mod is on the HD, but not enabled, it will be enabled, but then it will call the "mods changed, needs to restart" window and calling it while patching can't be done because the GUI haven't started yet, which causes the screen to turn all black. However if I force quit and start again, it remembers that the required mod has been enabled and it will load it.

Now if I figure out how to make a stack of (failed) PatchOperations and somehow call it and can loop them when main menu has started, then things can get interesting with popup windows with options for what to do with missing mods etc. Calling in main menu should be doable with Harmony, but I haven't figured out how to create memory, which can be written to while patching and then read later.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on December 03, 2017, 06:16:53 PM
I have done some thinking and some research and I now have a plan for what to do now. This post will list the ideas, though I can't say which order they will arrive in or if any of them will be canceled, nor can I say if they will be in the next release or when that will be.

I decided to expand the target area of ModCheck from conditional patching depending on mods loaded/order to patching in general, mainly focused on improving mod interaction/compatiblity as well as reducing xml loading time. The main reason for this is that it make no sense to make multiple mods for different types of PatchOperations. I will however not change the name to reflect this because a new name will only cause unneeded confusion.

This post is partly to allow feedback, partly to remember my own brainstorming.

Use newest DLL
The current system with adding ModCheck.dll can continue. It will require 0Harmony.dll too in the future, meaning it will have to be added too. While Harmony can be compiled into ModCheck.dll, I won't because if it's two files, Harmony can be updated without resorting to a new ModCheck release.

Right now I have the idea of using Harmony to reload ModCheck from the newest DLL. However since it could be complex to do that with a mod, which use transpilar, it could end up as a feature, which writes an error to the log if multiple versions of ModCheck.dll exist and it's not the newest, which is first. It could possibly add a warning for each mod, which use an outdated version.

ModCheck is released as a standalone mod on steam where people are told to load it before Core. This makes it the first loaded ModCheck.dll and since that one is the first to update, the risk of using an outdated DLL is removed for the subscribers.

Faster file identifier while patching
All patches are applied to all files. Most of the time a patch is written to apply to just one specific file. This mean it's a complete waste of time to try to patch other files. Sadly trying to patch files where the patch will do nothing takes up the majority of the time spend on each patch.

To get around this, I plan to add a PatchOperation, which checks if the current file is of a certain name and is part of a certain mod. This check should be much faster than the xpath search, which is the current system for file identifier.

Profiling each patch
When enabling verbose logging, it writes how long time it takes to load each mod. This includes patching, but it doesn't single out the time spend on the patches in any useful manner.

I plan to add profiling to each patch and on verbose logging, print how much time is spend on each Patches/PatchOperation. This will allow identifying mods with poorly written patches as well as which mod they are located inside.

Autodetection of patch owner(mod) and current file/mod
Create an internal engine to supply information at runtime. This includes the name of the patch to supply the currently working patch, which is what is currently in yourMod, which will then no longer be needed. Also read the name of the xml file currently being patched and the name of the mod providing that file. Info like this can then be used by other features as well as logging.

Log PatchOperation
Add a new baseclass and move all logging actions into this one. Make other PatchOperations inherit this one for consistency. Expand logging options, like adding warning (yellow) and only write to log when verbose logging is on. Add parameters, meaning a custom string can contain stuff like (3) and it will then insert say name of the file currently being patched. Actual list of parameters is not decided, but preferably as much as possible.

Allow patch files to use this directly. Since it always passes the check, it will write customMessageSuccess.

Help getting missing mods
Store results of patch operation testing and recall once Main Menu is up. This allows creating popup windows about any issue that may have been encountered, complete with buttons and as such the game can take action on each problem if the user choose to do so. If I can figure out how to do it, it will include (but not limited to): subscribe to missing mod on steam, open download link to missing mod, enable missing mod if present, change mod loading order, pick mod to disable if conflicting.

Due to the planned design, it's entirely possible that the user might be met with multiple restarts, like first subscribing, then enable (might be together with subscribe, not sure), then change order. Not ideal, but it will allow a user to get a modlist, which meet the requirements set in xml without actually opening the Mod Menu and do manual work there.

Translation of log entries
If log entries are stored and then written to the log after languages and settings have been read, then it will be possible to translate the text before it's written. It will still be written before reaching the main menu and the user will not be able to tell the difference, other than possibly changed order of entries.

Clone
Make an xpath patch, which points to an entry and it will make a copy of that one except it will use a new defName provided by the patch. The PatchOperation will then contain a list of PatchOperations, which will work just like regular PatchOperations, except that the current element in the xml document will be the root of the clone. This makes xpath searches much faster.

The idea is that if you want to make say a new bed, you clone a bed from vanilla instead of making your own. You then patch to apply the differences you want. If the vanilla bed changes, your modded bed will update accordingly. If say somebody adds a new medical monitor of some sort and patches vanilla to use it, your clone will use it too.

TODO: figure out if this is a horrible idea. It introduce the issue of adding something new with a patch, which is ok in some cases, but could be problematic if it is something like a bed and some other mod wants to patch it. Maybe the same goal could be reached by assigning a parent in the def file.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: kaptain_kavern on December 04, 2017, 02:22:23 AM
Quote from: Nightinggale on December 03, 2017, 06:16:53 PM
Maybe the same goal could be reached by assigning a parent in the def file.

I do something like that but with recipes in a simple patch-mod of mine:

Here is the patch: https://github.com/kaptain-kavern/Campfires-Can-Cremate-Corpses/blob/master/Patches/patches.xml

And then I just use the ParentName attribute, here: https://github.com/kaptain-kavern/Campfires-Can-Cremate-Corpses/blob/master/Defs/RecipeDefs/Recipes_Cremation.xml
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on December 05, 2017, 11:10:08 PM
ModCheck 1.5 has been released. It adds support for ModSync, both adding ModSync.xml to itself and the new PatchOperation isModSyncVersion to test the version of other mods.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: historic_os on December 06, 2017, 06:38:06 PM
This is amazing, i love this and honestly surprised its not used more often.

1. the main post is kinda hard to read, maybe do some reformatting on it and consider adding real life use case examples in there
2. I'd rather have it is a library attached to my mods(like harmony) to avoid annoying issues such as players forgetting to download dependencies.
3. I don't think you should be worried about mods not having the latest version. as you said - its relatively stable now and if for some reason there is a bug, mods can push an update with the new library.
another take on updating the library for all mods could be just providing the user with a script, if a user is having an issue due to a mod loading an older version of the library, you can offer the library packed with a little bash script to be placed in the mods folder that will replace all instances of your library with the new version.

this is really cool, i'd download all compatibility patches you can find and investigate them, see how you could add more features to the state where they are all obsolete and hopefully this mod will become as widely used as harmony and hugslib.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on December 06, 2017, 07:47:58 PM
Quote from: historic_os on December 06, 2017, 06:38:06 PM1. the main post is kinda hard to read, maybe do some reformatting on it and consider adding real life use case examples in there
I know. I wrote it for the first release and then just added text with each new feature. My plan is to make the PatchOperation to quickly reject "wrong" files while patching, release that and then rewrite all the documentation, here, on the GitHub page and steam. In addition to that, the real documentation should be on the wiki on GitHub with a multi page system, which will allow getting an overview as well as clicking on each feature to get details on it.

Real life cases aren't included because they didn't exist when the text was written. My examples on GitHub are also not good, particularly not compared to what real life files would look like.

If I add my recommendations for vanilla patching, which I wrote in the help forum (patching performance pitfall sticky), then it will be the wiki to use to make efficient patches. I have had feedback telling that one mod reduced time usage by 80%, the proposed new template for A Dog Said patching exceeds a 90% reduction and that's even before adding tools from ModCheck to make it even faster.

Quote from: historic_os on December 06, 2017, 06:38:06 PM2. I'd rather have it is a library attached to my mods(like harmony) to avoid annoying issues such as players forgetting to download dependencies.
Same here. I released it as a DLL file and everybody ignored it. I then put it into a mod and released it on steam and then people noticed it. In fact it went even better than just getting publicity on the forum because now I know of at least one steam only mod, which use ModCheck.

As the documentation says, ModCheck works both as a standalone mod and as a DLL to add to your mod. As far as I'm aware, all mods using ModCheck has decided on including the DLL, which is also my recommendation.

Adding ModSync.xml serves multiple purposes. One is obviously to allow getting a notification when there is a new release. This is a nice feature if you have a mod with the DLL included. The second is to make it appear in the new list of active mods, the third is it would feel wrong not to add it when adding isModSyncVersion and last, all mods should support ModSync. We need it mentioned everywhere as a standard  ;)

Quote from: historic_os on December 06, 2017, 06:38:06 PM3. I don't think you should be worried about mods not having the latest version. as you said - its relatively stable now and if for some reason there is a bug, mods can push an update with the new library.
The problem is if mods fail to do that because the ModCheck being used is the first one loaded.

Quote from: historic_os on December 06, 2017, 06:38:06 PManother take on updating the library for all mods could be just providing the user with a script, if a user is having an issue due to a mod loading an older version of the library, you can offer the library packed with a little bash script to be placed in the mods folder that will replace all instances of your library with the new version.
I plan to add a warning if the first loaded is not the newest in the list. I could expand this to provide a warning for all outdated if verbose logging is on.

Quote from: historic_os on December 06, 2017, 06:38:06 PMthis is really cool, i'd download all compatibility patches you can find and investigate them, see how you could add more features to the state where they are all obsolete and hopefully this mod will become as widely used as harmony and hugslib.
To be honest I don't think I need to come up with new features to do that. All I need is to make the file filter PatchOperation and the profiling for each patch tool. Releasing those two will make people upset that mod X takes 30 times longer than mod Y despite them patching around the same amount of data. That will cause feedback to mod X to optimize the patch files.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: kaptain_kavern on December 06, 2017, 08:06:41 PM
Quote from: Nightinggale on December 06, 2017, 07:47:58 PM
As far as I'm aware, all mods using ModCheck has decided on including the DLL, which is also my recommendation.

I was about to ask that. Thanks.

I'm starting to play with your tool in order to get familiarized ATM.

So far it's great, and following your previous recommendation I was able to make patches that start to feel like they're quicker - I'm lacking a real way to measure it though :p

Thank you for all of that  ;)
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on December 06, 2017, 08:32:35 PM
Quote from: kaptain_kavern on December 06, 2017, 08:06:41 PMSo far it's great, and following your previous recommendation I was able to make patches that start to feel like they're quicker - I'm lacking a real way to measure it though :p
Enable verbose logging and read the log. It will write how long it spend reading xml files and how long it takes to reach the xml files for each mod. Each of those includes patching. The interesting part is actually core. Even if you do not patch core, your xpath searches will still trigger, meaning you will slow down reading core. Since it contains so many files, I find it to be a good place to benchmark the slowdown of files, which you do not patch. Try without any patches, with the patch you test before optimizing and then with optimizing. Write down the numbers between each run and pay attention to the changes.

As I wrote earlier I plan to make verbose logging print how much time is spend on each patch as this is the most interesting number. However I haven't written the code to calculate this yet.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: kaptain_kavern on December 06, 2017, 08:46:40 PM
Hey, thanks for the tip. It will be fair enough, it's more because I'm curious rather than because I have a very big patch  ::)



On a side note, have you thought about a little logo or a banner to make us, modders, help you make ModCheck noticed? Like ModSync Ninja have?

Not something you should prioritize IMHO, but I was thinking about that while reading you talking about getting the tool noticed.

If your not an artist at all, like myself  :P , just ask the community around in here. I often had textures for my mods freely given to me


Edit:

In the mean time I'm gonna use this : (https://img.shields.io/badge/ModCheck-1.5-blue.svg?style=for-the-badge) (https://ludeon.com/forums/index.php?topic=36534)    8)

more info: https://shields.io/  - For changing color and style
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on December 10, 2017, 09:06:41 PM
Quote from: kaptain_kavern on December 06, 2017, 08:46:40 PMOn a side note, have you thought about a little logo or a banner to make us, modders, help you make ModCheck noticed? Like ModSync Ninja have?
I have started to wonder ever since you wrote that, but I'm not really sure what it should look like. I will need somebody to draw something, but I don't know what I would like to get drawn in the first place.

Quote from: kaptain_kavern on December 06, 2017, 08:46:40 PMIn the mean time I'm gonna use this : (https://img.shields.io/badge/ModCheck-1.5-blue.svg?style=for-the-badge) (https://ludeon.com/forums/index.php?topic=36534)    8)

more info: https://shields.io/  - For changing color and style
Now that looks interesting and it got me wondering. What if I host the image on GitHub instead of people using shields.io. That way when I release, I can put up some 1.6 image and then replace the 1.5 image with one, which use yellow. That way all mods using an now outdated version of ModCheck will automatically change color to highlight this fact. It's not like it would be extremely hard to make. The "image" file is actually a text file with this contents:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="140" height="28">
  <g shape-rendering="crispEdges">
    <path fill="#555" d="M0 0h97v28H0z"/>
    <path fill="#007ec6" d="M97 0h43v28H97z"/>
  </g>
  <g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="100">
    <text x="485" y="175" transform="scale(.1)" textLength="730">MODCHECK</text>
    <text x="1185" y="175" font-weight="bold" transform="scale(.1)" textLength="190">1.5</text>
  </g>
</svg>

It looks like I just need to change one fill RGB and the text saying 1.5 and I have a new version. It's plain text and small enough to not cause issues if I add it to git. Even if I have to generate a new one with new x,y data, it's still no big deal to add it to git.

I could make it change to red if it's an important update where everybody should update right away and yellow if it's ok to wait until you update your mod anyway.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: kaptain_kavern on December 11, 2017, 01:44:00 AM
Looks like a good idea  ;)
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on December 12, 2017, 03:21:30 PM
I had a major breakthrough. It turned out that there is a timing issue as the approach I used in BoneMod starts Harmony after xml files have been loaded and patched. I managed to move the start to after patches have been loaded, but just before defs are loaded and patched, which is perfect. Right now it's only used to write mod names to the log whenever a new mod starts to load def files. Useless except it tells me that I can now access all the needed data without timing issues. I can now move on to do what I actually planned to do when I encountered the timing issue.

Messing with all the load stuff made me wonder. Now that I have a method being called in C# before patching, maybe I can use it to reflect all PatchOperation calls to the newest ModCheck.dll, which would then make ModCheck use the newest version instead of the first, hence reducing the issue where mods with outdated dll files prevent others from using updated functionality.

I have been wondering about writing to the log. I think I will redesign it completely and instead of having a success and a failure message, I will make it display the default error if errorOnFail is set. For custom log entries, I will add a list of strings. For each it should have settings like normal/warning/error, success true/false, onlyWithVerboseLogging and so on. Since it's a list, multiple strings can be added and it should support writing multiple strings to the log if needed. This should be usable with a log writing operation (always true) as well as with any other PatchOperation in ModCheck.

If anybody has any requests or comments regarding log writing (what or how to write), it would be nice to know before I get to do the actual redesigning.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on December 13, 2017, 08:50:33 AM
I have changed my mind regarding the release schedule and decided on a feature freeze for the next release. I have managed to get benchmarking to work and then added the ability to filter based on mod and filename. Those two are very related because the benchmarking tool uses harmony to get what it need and it provides the info for the PatchOperation anyway.

I added this:
<li Class="ModCheck.FindFile">
<modName>Core</modName>
<file>TraderKinds_Orbital_Misc.xml</file>
</li>

If one or both lines are missing, they are assumed to be correct, through I'm not sure when it will not be a good idea to fill out both.

The result from adding this meant that it went from this:
      14.7972 ms A Dog Said...
             5.6831 ms
             3.1271 ms
             2.9940 ms
             2.9930 ms

To this
       2.3822 ms A Dog Said...
             2.0231 ms
             0.1289 ms
             0.1200 ms
             0.1102 ms


After seeing how successful this is, I decided it just needs some more testing and cleaning and then it needs to be released as fast as possible because this is really something all patches should use.

I suspect the first one is slower due to some disk cache or something like that. There is no obvious reason in the file for it to be slower. There is not really anything I can do about that.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: larSyn on December 13, 2017, 09:36:19 AM
Quote from: Nightinggale on December 13, 2017, 08:50:33 AM
I have changed my mind regarding the release schedule and decided on a feature freeze for the next release. I have managed to get benchmarking to work and then added the ability to filter based on mod and filename. Those two are very related because the benchmarking tool uses harmony to get what it need and it provides the info for the PatchOperation anyway.

I added this:
<li Class="ModCheck.FindFile">
<modName>Core</modName>
<file>TraderKinds_Orbital_Misc.xml</file>
</li>

If one or both lines are missing, they are assumed to be correct, through I'm not sure when it will not be a good idea to fill out both.

The result from adding this meant that it went from this:
      14.7972 ms A Dog Said...
             5.6831 ms
             3.1271 ms
             2.9940 ms
             2.9930 ms

To this
       2.3822 ms A Dog Said...
             2.0231 ms
             0.1289 ms
             0.1200 ms
             0.1102 ms


After seeing how successful this is, I decided it just needs some more testing and cleaning and then it needs to be released as fast as possible because this is really something all patches should use.

I suspect the first one is slower due to some disk cache or something like that. There is no obvious reason in the file for it to be slower. There is not really anything I can do about that.

So, as I understand, we would be telling the ModCheck exactly where to look for the file being patched, which, by the looks of it, speeds things way up?  That's pretty awesome.  I'm going to be very curious to see what it can do for SI, as the patch files keep getting bigger.  Last time I checked it was around 1000ms to load.  Not sure if a lot of that is from the patches or just the size of the mod or both...
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on December 13, 2017, 12:04:07 PM
Quote from: larSyn on December 13, 2017, 09:36:19 AMSo, as I understand, we would be telling the ModCheck exactly where to look for the file being patched, which, by the looks of it, speeds things way up?  That's pretty awesome.
That's pretty much it. It's all about how long time it will spend on a file before it figures out that it's the wrong file. xpath searches aren't quick, even if optimized. ModCheck.FindFile compares a few strings where all of them are in memory already without searching, which is more or less instant compared to xpath searching.

Quote from: larSyn on December 13, 2017, 09:36:19 AMI'm going to be very curious to see what it can do for SI, as the patch files keep getting bigger.  Last time I checked it was around 1000ms to load.  Not sure if a lot of that is from the patches or just the size of the mod or both...
The problem with the vanilla time display is that the time for each mod is for loading def files and applying patches from all mods. This mean if you say have A Dog Said..., it will apply those patches too, though the searches will be empty and not do anything to SI. To get a proper indication of time spend, you will have to disable all mods except Core and the one you want to test.

It should be noted that if you write a mod with only patch files, no defs, then it will read instantly according to vanilla because the time spend on it will be measured in the other mods. ModCheck measures time spend on each patch when patching each xml file and it adds up the numbers for each patch. This mean the numbers reported are the time spend on each patch in all mods combined.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on December 16, 2017, 01:43:57 PM
ModCheck 1.6 has been released. It adds patch operation profiling and FindFile.

Quick documentation (will have to do until I rewrite everything within hopefully a few days)
<li Class="ModCheck.FindFile">
<modName>Core</modName>
<file>TraderKinds_Orbital_Misc.xml</file>
</li>

This will be true when patching the chosen file in the chosen mod. Replaces isModLoaded in most cases. FindFile and isModLoaded are equally fast once cache has been set, but setting up the cache in isModLoaded takes around the same time as FindFile use on patching 2000 def files. FindFile is uncached and has no setup overhead.

FindFile has no ability to write to the log. It's only purpose is to boost speed as much as possible. It only has those two tags as well as success tag from vanilla.

I tried benchmarking with only A Dog Said... and Dragon Mod (http://steamcommunity.com/sharedfiles/filedetails/?id=1214454061) loaded. The results are as follows:





PatchingScaling
Template
114.97 ms
114.96 ms
Optimized vanilla
25.13 ms
23.15 ms
With ModCheck.FindFile
1.51 ms
0.03 ms
Patching is the time spend when loading only the 3 mods mentioned. Scaling gives an indication to how well it will behave if mods adds another 400 def xml files, which will not be modified by the patch file. While the actual numbers highly depend on the hardware, the speed of each approach relative to each other will likely remain somewhat fixed, that is FindFile will likely be 70-80 times faster than the template on most computers.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on December 16, 2017, 09:22:28 PM
I started to write documentation on how to use ModCheck. The so far only wiki page is here (https://github.com/Nightinggale/ModCheck/wiki/speed_patching). Feedback is most welcome. Most importantly is it possible to understand what you are supposed to do after reading this?
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on December 18, 2017, 12:42:42 AM
Now that ModSync is live, I find it bad looking that ModCheck lacks an image. Because of this I want ModCheck to get a logo. However I still have no idea what it should look like. Proposals are welcome, particularly if followed up with a donated image because I can't make one myself.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: frenchiveruti on December 18, 2017, 07:48:04 AM
Quote from: Nightinggale on December 16, 2017, 09:22:28 PM
I started to write documentation on how to use ModCheck. The so far only wiki page is here (https://github.com/Nightinggale/ModCheck/wiki/speed_patching). Feedback is most welcome. Most importantly is it possible to understand what you are supposed to do after reading this?
Do you need any help on docs?
I have some questions regarding "isModLoaded", how can I check for multiple mods?
Lets say I make a gun mod for Vanilla, how do I check for Rimsenal and Combat Extended?

I can't make any images because I lack software :)
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on December 18, 2017, 11:32:03 AM
Quote from: frenchiveruti on December 18, 2017, 07:48:04 AM
Do you need any help on docs?
Thanks, but to be completely honest I think it would be best if I write it since I know how ModCheck is supposed to be used. However feedback is most welcome because that's the only way I can tell if the text is good enough.

Quote from: frenchiveruti on December 18, 2017, 07:48:04 AMI have some questions regarding "isModLoaded", how can I check for multiple mods?
Lets say I make a gun mod for Vanilla, how do I check for Rimsenal and Combat Extended?
I wrote a wiki page for isModLoaded (https://github.com/Nightinggale/ModCheck/wiki/isModLoaded), though it's mostly a draft at this point (dead links etc). If you can get away with it, use FindFile and not isModLoaded (performance reasons), but sometimes you need to use isModLoaded or both.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: kaptain_kavern on December 18, 2017, 11:38:00 AM
-Am I correct to assume that now, even a simple mod patching a single vanilla def, will be quicker to execute using FindFile from ModCheck rather than the "vanilla patching system"?

-For using the new version, I need both ModCheck and Harmony dll files, right?

Thank you and please keep up the good job  ;)


Once documentation will be more "stable", I could look at making French translations, but I guess they'll need proper basic modding documentation before needing to delves into patching  8)
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: frenchiveruti on December 18, 2017, 01:47:58 PM
Be sure that If I can give some feedback I will, I was asking if I could help into expanding examples of Do's and Don'ts because those are the most important in my opinion on how to use a LIB, in any real case.
For example If I want to check for multiple mods, I have to create 2 cases of "isModLoaded", instead of only one operation, with both mods named in it (similar to an AND gate, if BOTH mods AREN'T active, my mod doesn't load). or contrary, if BOTH MODS are loaded, then path, if not, give error.
In my small patch mod I ended up with this bloat:
https://github.com/frenchiveruti/PlantGrass-RW/blob/v18.00.02.00/Patches/GrassSowable.xml#L5

As you can see, I had to make 2 <li isModLoaded> in order to check for both mods, while I believe it should've been done in a single one as in either case the patching won't go ahead.

But maybe that's more complicated and not a feature right now. So relying on multiple <li> is the way to go. Am I right?
Feel free to use my code as an example for the wiki.
Greets
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: larSyn on December 18, 2017, 03:48:33 PM
Quote from: Nightinggale on December 16, 2017, 09:22:28 PM
I started to write documentation on how to use ModCheck. The so far only wiki page is here (https://github.com/Nightinggale/ModCheck/wiki/speed_patching). Feedback is most welcome. Most importantly is it possible to understand what you are supposed to do after reading this?

It's pretty good.  I understood what to do with what you had written.  I hope you don't mind, but I took the liberty to rewrite some parts.  I didn't change the message, just fixed some grammar mistakes, reworded some stuff, and did some formatting.  I'll attach it this comment.  Feel free to use any of it you want, and if not, no worries.  :)

I could also take a crack at the logo.  I'll get something done in the next couple days and pm it you.  Let me know if you have any preferences (ie. color, font, etc).

[attachment deleted by admin: too old]
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on December 18, 2017, 06:36:33 PM
Quote from: kaptain_kavern on December 18, 2017, 11:38:00 AM
-Am I correct to assume that now, even a simple mod patching a single vanilla def, will be quicker to execute using FindFile from ModCheck rather than the "vanilla patching system"?
Yes. ModCheck.FindFile will always be much faster than anything with xpath, even if it's just one PatchOperation with one well written xpath search.

Quote from: kaptain_kavern on December 18, 2017, 11:38:00 AM-For using the new version, I need both ModCheck and Harmony dll files, right?
Yes. If the mod already use harmony, then you don't have to replace 0Harmony.dll, though it shouldn't matter. Both versions are hopefully the same.

Quote from: kaptain_kavern on December 18, 2017, 11:38:00 AMThank you and please keep up the good job  ;)


Once documentation will be more "stable", I could look at making French translations, but I guess they'll need proper basic modding documentation before needing to delves into patching  8)
Hmm.... translating the guide. To be completely honest I didn't think of that, but it would be a good idea to translate it into all the languages that mod creators use. The documentation will however change frequently for a while, partly because I have more features planned for ModCheck.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on December 18, 2017, 07:18:46 PM
Quote from: frenchiveruti on December 18, 2017, 01:47:58 PM
Be sure that If I can give some feedback I will, I was asking if I could help into expanding examples of Do's and Don'ts because those are the most important in my opinion on how to use a LIB, in any real case.
Sounds good. Remember that you can add comments in xml files by adding <!-- this is a comment -->
When adding comments to explain each step, it will work better as an example.

It looks to me like the xml parser used in RimWorld is good and that you can add comments everywhere except inside tags themselves (that would be strings, not comments). I have encountered parsers, which have restrictions on where to place comments due to less than perfect usage of the xml API.

Quote from: frenchiveruti on December 18, 2017, 01:47:58 PMFor example If I want to check for multiple mods, I have to create 2 cases of "isModLoaded", instead of only one operation, with both mods named in it (similar to an AND gate, if BOTH mods AREN'T active, my mod doesn't load). or contrary, if BOTH MODS are loaded, then path, if not, give error.
Yeah, just adding operations in a row like that will make it use the AND rules. I have been thinking of OR as well, but it looks like I need to add it in C#. I'm wondering about making something with a list of operations like PatchOperationSequence, but it supports log writing. It can then have a tag to pick what is needed for success, which can be All/Any/None of the child list operations. I do want to make such tools to make checks as versatile as possible and ideas are welcome.

Nested usage of PatchOperationSequence is supported by vanilla. This allows starting with some checks and then one or more PatchOperationSequence. If setting success to Always, it will just move on to the next one if one fails. This mean you can use FindFile to set modName, but not file and then have a PatchOperationSequence starting with FindFile where it searches for a file, but not modName. The speed different is near 0 though and it's only reasonable to use if there are more checks before the first PatchOperationSequence. Comments will be needed for readability.

Quote from: frenchiveruti on December 18, 2017, 01:47:58 PMIn my small patch mod I ended up with this bloat:
https://github.com/frenchiveruti/PlantGrass-RW/blob/v18.00.02.00/Patches/GrassSowable.xml#L5
Perhaps a bit bloated, but clearly readable. One comment though. If you put FindFile first, it will be the fastest execution (minor difference, but still not 100% the same). However error messages from isModLoaded will be written during patching. The way it is right now, the errors will be written when patching the first file, meaning it will be on the top of the log.

Also adding success to every check is good for debugging, but will bloat the log if you load 100+ mods with such comments. I plan on expanding the log writing abilities, which will allow writing only if verbose logging is enabled and I think your success messages will fall into that category.

Quote from: frenchiveruti on December 18, 2017, 01:47:58 PMAs you can see, I had to make 2 <li isModLoaded> in order to check for both mods, while I believe it should've been done in a single one as in either case the patching won't go ahead.

But maybe that's more complicated and not a feature right now. So relying on multiple <li> is the way to go. Am I right?
There is nothing, which is free. If one operation can check for multiple mods, then the C# code needs to be more complex. Now the C# code is simple, but it needs multiple calls from xml.

Quote from: frenchiveruti on December 18, 2017, 01:47:58 PMFeel free to use my code as an example for the wiki.
Thanks.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on December 18, 2017, 07:58:43 PM
Quote from: larSyn on December 18, 2017, 03:48:33 PMIt's pretty good.  I understood what to do with what you had written.  I hope you don't mind, but I took the liberty to rewrite some parts.  I didn't change the message, just fixed some grammar mistakes, reworded some stuff, and did some formatting.  I'll attach it this comment.  Feel free to use any of it you want, and if not, no worries.  :)
Thanks. It's not that I suck at writing or grammar. However when writing the wiki, I has and will continue to focus on explaining how to use ModCheck correctly. This has the sideeffect of slacking off at stuff like grammar because none of us can focus 100% on everything at once. Next thing to come into play is the fact that we are all poor at correcting what we wrote ourselves. The brain can take the easy part and read half the sentence and fill out the other hard from memory because we know what it is supposed to say. This mean we can read the same sentence 5 times and still not notice the mistake we would have noticed instantly if the same had been written by somebody else.

In other words corrections like that is most welcome, be it grammar, clarifications or some other improvements. I will take a look at the document in the near future.

Just one thing. I don't actually have word on this computer and have to use wordpad. It complains that it might have removed something from the document  :-\

Quote from: larSyn on December 18, 2017, 03:48:33 PMI could also take a crack at the logo.  I'll get something done in the next couple days and pm it you.  Let me know if you have any preferences (ie. color, font, etc).
I'm thinking a logo, which while not singlecolored is primarily red. Also the other end of the color spectrum (blueish colors) should be avoided. It should be some icon, which illustrates what ModCheck is about, which is patching and speed. Since it's an icon, which should be used as preview (game, modsync, steam etc), getting the name itself through is not top priority. It's already on the screen.

I know it might be a lot to ask, but there is the idea further back in post #42 in this thread about using an svg as a logo, which mods can display if they include ModCheck. The idea is that the forum links to the git repository and then on release, the old version change color (or something) to indicate that the dll is outdated. It would be awesome if the logo can be included in something like that, like:
logo    using
logo  ModCheck
logo     1.6

I know it might be difficult to make and it's ok if it's not like that, but I really like the idea.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: larSyn on December 20, 2017, 10:02:33 AM
Quote from: Nightinggale on December 18, 2017, 07:58:43 PM
Thanks. It's not that I suck at writing or grammar. However when writing the wiki, I has and will continue to focus on explaining how to use ModCheck correctly. This has the sideeffect of slacking off at stuff like grammar because none of us can focus 100% on everything at once. Next thing to come into play is the fact that we are all poor at correcting what we wrote ourselves. The brain can take the easy part and read half the sentence and fill out the other hard from memory because we know what it is supposed to say. This mean we can read the same sentence 5 times and still not notice the mistake we would have noticed instantly if the same had been written by somebody else.

In other words corrections like that is most welcome, be it grammar, clarifications or some other improvements. I will take a look at the document in the near future.

Just one thing. I don't actually have word on this computer and have to use wordpad. It complains that it might have removed something from the document  :-\

Yeah, I understand you're trying to get the idea across first and foremost.  Like you said, we all suck at noticing our own mistakes, especially when we're trying to get something done fast.  But, that's why editors/proofreaders exist, and I don't mind helping out in that respect. 

I checked the doc with Wordpad and it didn't lose any of the changes/formatting, so you should be good too.  Just an fyi, I use Libre Writer, it's a free open source version of Word.  Might be worth checking out, if you need a word processor.

Quote from: Nightinggale on December 18, 2017, 07:58:43 PMI'm thinking a logo, which while not singlecolored is primarily red. Also the other end of the color spectrum (blueish colors) should be avoided. It should be some icon, which illustrates what ModCheck is about, which is patching and speed. Since it's an icon, which should be used as preview (game, modsync, steam etc), getting the name itself through is not top priority. It's already on the screen.

I know it might be a lot to ask, but there is the idea further back in post #42 in this thread about using an svg as a logo, which mods can display if they include ModCheck. The idea is that the forum links to the git repository and then on release, the old version change color (or something) to indicate that the dll is outdated. It would be awesome if the logo can be included in something like that, like:
logo    using
logo  ModCheck
logo     1.6

I know it might be difficult to make and it's ok if it's not like that, but I really like the idea.

Not a problem.  It's been a while since I opened up Illustrator, but it was fun to use it again.  I did a couple quick logos last night, and exported them as svg's as requested.  I'll attach them both to this comment.  To edit the xml, right click the image file and open with whatever you use for xml files (I like Sublime).  Not sure if you would need this, but this page (https://www.w3.org/WAI/UA/TS/html401/cp0403/0403-FONT-COLOR.html) has the code for changing the colors/fonts. And as a heads up, I found svg's don't like a lot of different fonts and won't allow things like layer effects (multiply, hard light, etc).  Let me know what you think.  I can make some edits/changes if you want.

[attachment deleted by admin: too old]
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: larSyn on December 20, 2017, 11:25:02 AM
I have a question about FindFile.  Obviously, it works well when changing something in another mod/core file, but should it be used if I need to change something in my mod if a certain mod is loaded?  Or would this still be a case where isModLoaded used?
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on December 20, 2017, 12:20:16 PM
Quote from: larSyn on December 20, 2017, 10:02:33 AMBut, that's why editors/proofreaders exist, and I don't mind helping out in that respect.
Sounds good. However right now I put documentation on hold and is working on loading the newest version of ModCheck rather than the first in the load order. It looks like it will require everybody to update once it's out and then updating will not really be an issue unless the mod itself makes use of the new features. I better get this working before too many mods use ModCheck.

Quote from: larSyn on December 20, 2017, 10:02:33 AMI checked the doc with Wordpad and it didn't lose any of the changes/formatting, so you should be good too.  Just an fyi, I use Libre Writer, it's a free open source version of Word.  Might be worth checking out, if you need a word processor.
It's good that nothing is lost. I do have LibreOffice installed. In fact I I used it back before it forked from OpenOffice. However that too can lose formatting when importing word documents.

Quote from: larSyn on December 20, 2017, 10:02:33 AMI did a couple quick logos last night, and exported them as svg's as requested.  I'll attach them both to this comment.
The second one looks awesome. It's nothing like what I had in mind, but that doesn't matter because this one is better.

Now if there can be a version of it, which indicates an update is available, then it would be great. That way I can add each to git and the forum posts can point to one for a specific version. When I release a new one, I can update the old to indicate that it's out of date and it will automatically update for all the mods using it. This will then be a reminder to update the files the next time the mod is released anyway.

Quote from: larSyn on December 20, 2017, 11:25:02 AM
I have a question about FindFile.  Obviously, it works well when changing something in another mod/core file, but should it be used if I need to change something in my mod if a certain mod is loaded?  Or would this still be a case where isModLoaded used?
When patching, you make a sequence as follows:
Remember that every single line needs to pass for the next one to be reached. This mean to reach patching, all the lines before it needs to pass.

FindFile is primarily for improving performance and it should go first. You should only skip it if you patch multiple files using the same code (that's rare). If you patch multiple files in the same mod, you use FindFile without file and it will try to patch all files in modName. Since it's first, the following will not even test if they are ok.

isModLoaded will pass if the mod is loaded (obviously). However it's the same for each call, meaning if the mod is loaded, it will pass for all files and not prevent attempts at patching the wrong files. isModLoaded can be skipped if modName is the same as in FindFile. It's only useful if they look for different mods.
Exception: if modName is required and isModLoaded will give an error if it fails, it has to go before FindFile if they use the same modName. Otherwise the error will never trigger.

loadOrder is useful in case the mod from the previous test(s) needs some other mod to be loaded first and it will cause errors if it's loaded later. Adding loadOrder will prevent those errors. Quite useful if it writes an error to the log since it changes nasty error messages into a single one, which is easy for the users to understand.

Any number of each test can be used, though it often makes little sense to use multiple FindFile. However you can test for modName only and then make nested sequences where each start with FindFile where it only checks for a file because you know at that point it's the correct mod. It's less readable, but if you have other checks in between, which might give error messages or similar, then it could be a good idea.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: larSyn on December 20, 2017, 06:39:11 PM
Quote from: Nightinggale on December 20, 2017, 12:20:16 PM
Sounds good. However right now I put documentation on hold and is working on loading the newest version of ModCheck rather than the first in the load order. It looks like it will require everybody to update once it's out and then updating will not really be an issue unless the mod itself makes use of the new features. I better get this working before too many mods use ModCheck.

No problem.  I look forward to any updates you have planned.

Quote from: Nightinggale on December 20, 2017, 12:20:16 PMThe second one looks awesome. It's nothing like what I had in mind, but that doesn't matter because this one is better.

:)  Glad you like it!  I updated it to make the xml easier to use.  It's attached to this comment.

Quote from: Nightinggale on December 20, 2017, 12:20:16 PMNow if there can be a version of it, which indicates an update is available, then it would be great. That way I can add each to git and the forum posts can point to one for a specific version. When I release a new one, I can update the old to indicate that it's out of date and it will automatically update for all the mods using it. This will then be a reminder to update the files the next time the mod is released anyway.

This page (https://www.sitepoint.com/why-hosting-your-svgs-is-hard-and-how-to-beat-it/) tells how to set it up on Github.  I tried it and it wasn't too hard.  If I knew how I could transfer the gist over to you I would, but I have no idea if I can or if it's possible...let me know if you know of a way. 

This is the code you will be looking for:

<g id="red_x5F_BG">
<g>
<g>
<path id="SVGID_1_" fill="#FFFFFF" d="M566.047,130.993c0,6.56-4.873,12.378-11.5,12.378h-514c-6.627,0-12.5-5.818-12.5-12.378
V57.747c0-6.56,5.873-11.375,12.5-11.375h514c6.627,0,11.5,4.815,11.5,11.375V130.993z"/>
</g>
<g>
<defs>
<path id="SVGID_2_" d="M566.047,130.993c0,6.56-4.873,12.378-11.5,12.378h-514c-6.627,0-12.5-5.818-12.5-12.378V57.747
c0-6.56,5.873-11.375,12.5-11.375h514c6.627,0,11.5,4.815,11.5,11.375V130.993z"/>
</defs>
<clipPath id="SVGID_3_">
<use xlink:href="#SVGID_2_"  overflow="visible"/>
</clipPath>

<rect x="511.547" y="45.871" clip-path="url(#SVGID_3_)" fill="#ff0000" stroke="#000000" stroke-width="5" stroke-miterlimit="10" width="55" height="97"/>
</g>
<g>
<defs>
<path id="SVGID_4_" d="M566.047,130.993c0,6.56-4.873,12.378-11.5,12.378h-514c-6.627,0-12.5-5.818-12.5-12.378V57.747
c0-6.56,5.873-11.375,12.5-11.375h514c6.627,0,11.5,4.815,11.5,11.375V130.993z"/>
</defs>
<clipPath id="SVGID_5_">
<use xlink:href="#SVGID_4_"  overflow="visible"/>
</clipPath>

<rect x="128.548" y="45.871" clip-path="url(#SVGID_5_)" fill="#ff0000" stroke="#000000" stroke-width="5" stroke-miterlimit="10" width="383" height="97"/>
</g>
<g>
<defs>
<path id="SVGID_6_" d="M566.047,130.993c0,6.56-4.873,12.378-11.5,12.378h-514c-6.627,0-12.5-5.818-12.5-12.378V57.747
c0-6.56,5.873-11.375,12.5-11.375h514c6.627,0,11.5,4.815,11.5,11.375V130.993z"/>
</defs>
<clipPath id="SVGID_7_">
<use xlink:href="#SVGID_6_"  overflow="visible"/>
</clipPath>

<rect x="28.548" y="45.871" clip-path="url(#SVGID_7_)" fill="#ff0000" stroke="#000000" stroke-width="5" stroke-miterlimit="10" width="100" height="97"/>
</g>
<g>
<defs>
<path id="SVGID_8_" d="M566.047,130.993c0,6.56-4.873,12.378-11.5,12.378h-514c-6.627,0-12.5-5.818-12.5-12.378V57.747
c0-6.56,5.873-11.375,12.5-11.375h514c6.627,0,11.5,4.815,11.5,11.375V130.993z"/>
</defs>
<clipPath id="SVGID_9_">
<use xlink:href="#SVGID_8_"  overflow="visible"/>
</clipPath>
<path clip-path="url(#SVGID_9_)" fill="none" d="M566.047,130.993c0,6.56-4.873,12.378-11.5,12.378h-514
c-6.627,0-12.5-5.818-12.5-12.378V57.747c0-6.56,5.873-11.375,12.5-11.375h514c6.627,0,11.5,4.815,11.5,11.375V130.993z"/>
</g>
</g>
</g>


Specifically these lines (there are 2, you will need to change both to change each red section to a different color):


<rect x="511.547" y="45.871" clip-path="url(#SVGID_3_)" fill="#ff0000" stroke="#000000" stroke-width="5" stroke-miterlimit="10" width="55" height="97"/>


You'll want to change the "ff0000" for the fill to alter the colors in the image.  The link I left in the earlier post has a few codes for colors, and I found this page (http://www.december.com/html/spec/colorsvgsvg.html), which has a lot more.

To change the version number, look for the "text" section.  It's the last line in that part.

Quote from: Nightinggale on December 20, 2017, 12:20:16 PMWhen patching, you make a sequence as follows...

Thanks for the explanation.  I have a case where I add a RecipeDef if Vegetable Garden is loaded and since there is no file for it I assume that isModLoaded is the way to go.

I also updated my patches to 1.6, and I definitely noticed an improvement in load times.  Nice work!

[attachment deleted by admin: too old]
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on December 20, 2017, 08:08:17 PM
Question for everybody
I need to place ModCheck.dll in the mod, but outside Assemblies or any subdir of Assemblies. Any proposals to where it could be?

The reason is that I have finally managed to get ModCheck to use the newest DLL instead of the first if multiple are present. This is by far the hardest to implement (Harmony Transpiler is piece of cake in comparison). After a lot of experimentation and research, it turns out that once RimWorld has loaded a dll, then we can't remove or replace it. If the same dll is loaded multiple times, the first will be used. If they aren't all of the same version, some nasty stuff can happen. Despite my efforts there is nothing I can do about that.

The solution is to add ModCheckLoader.dll. It has just one purpose, which is to loop all mods, look for ModCheck.dll and figure out which one has the newest AssemblyFileVersion. It then manually loads that one and calls the init code. No more and no less, meaning ModCheckLoader.dll should ideally never have to be replaced, which removes the risk of multiple versions of the same DLL.

WARNING: this will NOT work if the game can find any ModCheck.dll in Assemblies (it searches recursively), meaning starting from the next version, an error will be written to the log for each such file found. This mean anybody who released a mod with an included DLL will have to update it in the near future. The only alternative is to rename every single class used in the patch files, which I consider even worse. Remember the update is to prevent urgent update requirements in the future.

Quote from: larSyn on December 20, 2017, 06:39:11 PMI also updated my patches to 1.6, and I definitely noticed an improvement in load times.  Nice work!
Turn on verbose logging and ModCheck will print how much time is spend on each patch. That way you can tell how much faster it is and not just "it feels faster". With just the patching mod loaded (it patches Core), using FindFile tend to make the patch around 30 times faster if xpath searches are already optimized. Obviously the gain is even greater if it's dead slow to start with.

I will look into the logo stuff when my head is not full of dll issues.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Jaxxa on December 20, 2017, 10:08:25 PM
I suggest a new Folder next to Assemblies.

Maybe named something along the lines of "AdditionalAssemblies" or "LibraryAssemblies".

In it should contain a .txt file explaining what you said in your post about why this additional folder is required.

If this is an issue with other library type mods, such as Harmony / HugsLib it might be a good idea to see if you can standardize the folder and the .dll that does the loading.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: frenchiveruti on December 20, 2017, 11:27:59 PM
Something like "Modcheckdll"? like, straight on point.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on December 21, 2017, 06:28:25 PM
Quote from: Jaxxa on December 20, 2017, 10:08:25 PM
I suggest a new Folder next to Assemblies.

Maybe named something along the lines of "AdditionalAssemblies" or "LibraryAssemblies".
I was thinking of ManuallyLoadedAssemblies, but I decided to not mention it as it would disturb the feedback.

Quote from: Jaxxa on December 20, 2017, 10:08:25 PMIn it should contain a .txt file explaining what you said in your post about why this additional folder is required.
Good point.

Quote from: Jaxxa on December 20, 2017, 10:08:25 PMIf this is an issue with other library type mods, such as Harmony / HugsLib it might be a good idea to see if you can standardize the folder and the .dll that does the loading.
I have been wondering about this one. It sounds like the way to go, but it's not as easy as it would appear at first. Some mods have special requirements.

What I came up with is this (after many ideas, which ended up as flawed)
It seems simple, but some consideration went into this. Sorting alphabetically allows 0Harmony to load first (not sure if Harmony needs this, but it better support it if needed). The create instance code is because currently it calls this:
assembly.CreateInstance("ModCheck.HarmonyStarter");
It creates an instance, which goes out of scope right away. However it's still useful because it calls the default constructor of that class inside the newly loaded dll file. ModCheck use this to start Harmony and then set up a singleton, which is used to keep track of a bunch of stuff while patching. The class can be renamed to meet a standard.

I would need to create a new LIB mod for this. Making the code part of ModCheck is not the way to go if it is to be used for other mods as well.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: sulusdacor on January 25, 2018, 10:01:13 AM
maybe a bit of a noob question here: is this faster then using the short code?

meaning this:
internal class PatchOperationFindMod : PatchOperation
{
private string modName;

protected override bool ApplyWorker(XmlDocument xml)
{
return !GenText.NullOrEmpty(this.modName) && ModsConfig.ActiveModsInLoadOrder.Any((ModMetaData m) => m.Name == this.modName);
}
}

(thats what i currently use and it seems to works fine.)

in one post on the previous page you mention shorter load times, suggesting that using modcheck speeds it up quite a bit. if thats the case what would be the order/minimum to implement the modcheck patchoperations to benefit from that speed up. you mentioned:
    FindFile
    isModLoaded
    loadOrder
    patching
Or
like this what BrokenValkyrie did:

<Patch>
<!--Patch in projectile def if Framework detected.-->
<Operation Class="PatchOperationSequence">
<success>Always</success>
<operations>
<li Class="ModCheck.isModLoaded">
<modName>Combat Extended</modName>
<yourMod>Dragon Mod</yourMod>
<success>Invert</success>
</li>
<li Class="ModCheck.isModLoaded">
<modName>Range Animal Framework</modName>
<yourMod>Dragon Mod</yourMod>
<customMessageSuccess>Range Animal Framework: Adding Range attack to Dragon Mod.</customMessageSuccess>
</li>
<li Class="ModCheck.FindFile">
<modName>Dragon Mod</modName>
<file>Projectile_Dragon.xml</file>
</li>
<li Class="PatchOperationReplace">
<xpath>Defs/ThingDef[defName = "ARA_DragonFireBreathAlpha"]</xpath>
<value>
// do stuff
</value>
</li>
</operations>
</Operation>
</Patch>

(code taken from here (https://ludeon.com/forums/index.php?topic=38817.0))

so does findfile first or ismodloaded?

is the loadorder check needed? since i found recently that in b18 this did not matter at all when patching with the simple modcheck i posted at the start. so i'm a bit confused on that.

if i wanted to include the ismodsyncversion, at which position would that go in the sequence? or does that even matter?

just asking, couse the guide/github linked at the first page is a bit older and i'm slighty confused here^^

thx for putting the work. seems like a really big help for modders ;)
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on January 25, 2018, 03:26:10 PM
Quote from: sulusdacor on January 25, 2018, 10:01:13 AM
maybe a bit of a noob question here: is this faster then using the short code?
Despite being a simple question, the answer is not simple. You can't predict performance based on the number of C# lines. You have to consider how the CPU will handle the resulting code and while it is often possible to merge multiple lines into one, the resulting IL code might not change at all. In other words it's not possible to give a simple yes or no answer.

The best approach is to measure multiple solutions to see the result. Also it makes sense to measure the "before" code since even an 80% reduction is worthless if the method use 0.00001% of the combined CPU time. Luckily I added profiling to v1.6. Just enable verbose logging and it will tell how long it spends on each patch, even patches, which have nothing to do with ModCheck.

Quote from: sulusdacor on January 25, 2018, 10:01:13 AMinternal class PatchOperationFindMod : PatchOperation
{
private string modName;

protected override bool ApplyWorker(XmlDocument xml)
{
return !GenText.NullOrEmpty(this.modName) && ModsConfig.ActiveModsInLoadOrder.Any((ModMetaData m) => m.Name == this.modName);
}
}

(thats what i currently use and it seems to works fine.)
This code will do the same as isModLoaded. It's less code and less method call overhead, which will in theory speed up the test. However the difference is so minor that you can't tell the difference. 99%+ of the time is spend on the search in ModsConfig.ActiveModsInLoadOrder.Any(). This mean the time the CPU spend is a constant multiplied by the number of calls to that method. Your approach will search every time the PatchOperation is called, which might be once for each xml file in each mod, meaning it can easily be a 4 digit number of times (it's around 400 times for vanilla alone). That's how ModCheck started out and reports of adding 10 minutes to startup time made me rethink the design. Starting from v1.3, ModCheckBase makes the check once and stores the result. The following calls will return the cached result. This mean your approach is significantly slower despite using way less lines of code.

Quote from: sulusdacor on January 25, 2018, 10:01:13 AMin one post on the previous page you mention shorter load times, suggesting that using modcheck speeds it up quite a bit. if thats the case what would be the order/minimum to implement the modcheck patchoperations to benefit from that speed up. you mentioned:
    FindFile
    isModLoaded
    loadOrder
    patching
Or
like this what BrokenValkyrie did:

<Patch>
<!--Patch in projectile def if Framework detected.-->
<Operation Class="PatchOperationSequence">
<success>Always</success>
<operations>
<li Class="ModCheck.isModLoaded">
<modName>Combat Extended</modName>
<yourMod>Dragon Mod</yourMod>
<success>Invert</success>
</li>
<li Class="ModCheck.isModLoaded">
<modName>Range Animal Framework</modName>
<yourMod>Dragon Mod</yourMod>
<customMessageSuccess>Range Animal Framework: Adding Range attack to Dragon Mod.</customMessageSuccess>
</li>
<li Class="ModCheck.FindFile">
<modName>Dragon Mod</modName>
<file>Projectile_Dragon.xml</file>
</li>
<li Class="PatchOperationReplace">
<xpath>Defs/ThingDef[defName = "ARA_DragonFireBreathAlpha"]</xpath>
<value>
// do stuff
</value>
</li>
</operations>
</Operation>
</Patch>

(code taken from here (https://ludeon.com/forums/index.php?topic=38817.0))

so does findfile first or ismodloaded?

is the loadorder check needed? since i found recently that in b18 this did not matter at all when patching with the simple modcheck i posted at the start. so i'm a bit confused on that.

if i wanted to include the ismodsyncversion, at which position would that go in the sequence? or does that even matter?
FindFile should always go first if used and if you can find a case where it shouldn't be used, then I would like to know about it. Admittedly isModLoaded can't be considered slow, but it's generally a good idea to have the guidelines aiming for the best result. It's purely a matter of performance.

Don't use FindFile and isModLoaded for the same mod since FindFile will fail if the mod isn't loaded (obviously). isModLoaded is useful like in the example where Dragon Mod is patched if CE and Range Animal Framework are loaded.

The reason is that in a sequence each PatchOperation is called until one fails. This mean it will make sense to sort the tests based on speed and likelihood of failure (fail as early as possible if failing). Tests such as isModLoaded will always be either true or false while FindFile will change result based on the current file and it will in most cases be false.

loadOrder is useful in one specific case. If you add a def file, which includes something with a parent where the parent is in another mod, then that other mod needs to be loaded first. A good example of this is alien races, which relies on alien framework. Often it's used to display an error if the requirement isn't met, though it supports conditional patching. If you don't what I wrote here, then you don't need to use it.

ismodsyncversion can be added in any order, though I would recommend after FindFile.

Quote from: sulusdacor on January 25, 2018, 10:01:13 AMjust asking, couse the guide/github linked at the first page is a bit older and i'm slighty confused here^^
I have a plan for a complete rewrite. It was sort of ok at first and then I just added each time I updated something and now it's an unplanned mess. I'm holding off updating it before v1.7 though because that one will split into two DLL files and it will once and for all solve the issue of the problems from mods not using the same version of ModCheck. Keeping ModCheck up to date will still be a good idea, but failing to do so will not break other mods.

Quote from: sulusdacor on January 25, 2018, 10:01:13 AMthx for putting the work. seems like a really big help for modders ;)
Thanks. It's supposed to be useful because I wrote it to cover my own needs. Since I instantly viewed it as useful for everybody and no such standalone mod existed at the time, I decided to make one. Ironically ModCheck has taken up all of my modding time and the planned mod it's made for is still a planned mod.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: ilikegoodfood on January 31, 2018, 06:38:01 AM
Hi, I'm brand new to modding and have just started work on a monster mod, called Monster Mash.

I implemented my first creature, the Inferno Beetle, and am now working on compatibility with other mods, using ModCheck.
My vanilla patch to implement the Range Animal Framework (LINK (https://ludeon.com/forums/index.php?topic=38290.15)) is working perfectly, however, it is using the vanilla patch even when I have Combat Extended (A18 pre-release) installed and the Combat Extended Patch set up.

Here is the code for the Vanilla patch that is supposed to disable it if CombatExtended is installed:
<Patch>
<Operation Class = "PatchOperationSequence">
<success>Always</success>
<operations>
<!--Continue if combat extended does not exist IE patch vanilla-->
<li Class="ModCheck.isModLoaded">
<modName>Combat Extended</modName>
<yourMod>Monster Mash</yourMod>
<success>Invert</success>
<customMessageSuccess>Vanilla combat systems: Patching ranged attacks...</customMessageSuccess>
</li>
<li Class="ModCheck.loadOrder">
<modName>Core</modName>
<yourMod>Monster Mash</yourMod>
<errorOnFail>true</errorOnFail>
</li>
<li Class="ModCheck.FindFile">
<modName>Monster Mash</modName>
<file>Races_Animal_Insect.xml</file>
</li>
<li Class="PatchOperationAdd">


And here is the code in the CombatExtended Patch taht should trigger it if the CombatExtended mod is installed:
<Patch>
<Operation Class="PatchOperationSequence">
<success>Always</success>
<operations>
<li Class="ModCheck.isModLoaded">
<modName>CombatExtended</modName>
<yourMod>Monster Mash</yourMod>
<customMessageSuccess>Combat Extended found: Modifying organisms for extreme combat realism...</customMessageSuccess>
</li>
<li Class="ModCheck.loadOrder">
<modName>CombatExtended</modName>
<yourMod>Monster Mash</yourMod>
<errorOnFail>true</errorOnFail>
</li>


I'm really not sure where my error is and I would be very grateful if someone could explain to me what is going wrong and how to fix it.

Thanks in advance.

EDIT: I have found the error that was preventing the patch from working.
Combat Extended has a space in the mod name, which I correctly implemented in the vanilla patch, but I somehow removed the spaces for the CE patch.
Now to bugfix the patch itself...
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on May 24, 2018, 08:39:23 PM
I have good news and bad news. The good news is that I have finally made a DLL, which is able to pick which ModCheck DLL to load and it will indeed pick the newest one if there are multiple available. The bad news is that while I can load the DLL this way and call methods from it, I can't get it to work with the xml passing code, meaning it can't find ModCheck.FindFile even if that method is loaded. Even worse, despite my efforts, I can't really tell why, meaning it doesn't appear I will be able to fix it :'(

Right now I can't really think of any other approach than to keep the current system and rely on people to update whenever ModCheck is updated. What I can do is to add code to ModCheck startup, which makes it scan for ModCheck in all loaded mods and print a warning for each outdated and error if it isn't the newest, which is in use. Not ideal, but it's the best solution I can think of.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on June 03, 2018, 07:04:47 PM
ModCheck 1.7 has been released.
Quotev1.7 changelog
- Speedboost: cached mod indexes for massive speed boost of some ModCheck internals
- Rewritten the log writing system to give better control/more features to patch writers
- Rewritten error messages to make it easier to find the error
- Changed profiling output. Total on top, one entry for each mod
- All PatchOperation names can now be used starting with both upper and lower case (fixes naming inconsistency)
- Added new mode to LoadOrder. It can now use first and last strings instead of the old approach (which still works)
- Added Sequence operation, which does the same as the vanilla operation, but with ModCheck specific options
- Added logic operations AND, OR, IfElse, Loop and Once
- Added warning/error if outdated versions of ModCheck are being loaded (risk of new vs old conflicts)
- Added a preview logo (thanks to larSyn for drawing it)
- Added support for ModSync RW
- Fix: profiling now displays correct time if the hardware has a high precision timer
- Fix: profiling will no longer cut off the output if you have a lot of patches
- Removed the need to include yourMod and modName unless they are actually used

The best I can do regarding people running multiple versions of ModCheck is to make the DLL aware of it and print a warning if multiple versions are loaded and an error if the newest isn't first. On top of that all harmony code will only trigger in the newest version. In other words if the newest is loaded first, it should work, particularly when the time comes for 1.7 to be the oldest. However it's not great and I will try to avoid minor updates in the future and instead wait and collect for major releases.

The log writing system is completely rewritten. You can now use tags to tell when the string should be used and what kind of output: message(white), warning(yellow) and error(red). You can add verbose to make it only trigger if verbose logging is enabled. Examples: ErrorFail and VerboseMessageSuccess. Works on cached operations and the new ModCheck.LogWrite.

Log writing can now take arguments, like {0} and {1}, which are mod and file being patched respectively. Those two are likely the most useful because that's the strings needed for ModCheck.FindFile. There are 5 such arguments in total.

ModCheck.OR has been added. It's a sequence where it stops at the first operation, which passed and then it will pass itself and only fail if everything failed. You can use it to make a list of FindFile operations if you for some reason want to apply the same patch operation(s) to multiple files.

The changelog will have to do for the rest of the changes for the time being. I plan to rewrite the wiki from scratch. Since this release is fully backward compatible, updating shouldn't break anything and you can continue to use the 1.6 documentation until the 1.7 version is ready.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on June 04, 2018, 07:46:11 PM
I started writing the wiki for 1.7, but it would be nice to get feedback on the style of writing/layout before I go through all the operations. The pages so far:
Is this something people can read and understand?
Obviously it will need some overview page at some point. This is pages for getting details on specific features.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on June 17, 2018, 03:29:53 PM
I have good news and bad news.

The good news is that I finished documenting each PatchOperation on the wiki. I have plans for other pages, like concepts and guides for how to use them together and stuff like that.

The bad news is that I just provided feedback to RimWorld 1.0 because it completely destroys ModCheck in such a way that it's not possible to fix. If ModCheck will make it to 1.0, RimWorld itself will have to change to become more open to ModCheck.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: SargBjornson on June 18, 2018, 02:15:43 PM
Keep us informed! I hope Tynan can patch things up
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on June 18, 2018, 05:30:53 PM
Quote from: SargBjornson on June 18, 2018, 02:15:43 PM
Keep us informed! I hope Tynan can patch things up
Current status is that I received feedback on my feedback. The method in question changed and is updated in the next build. I'm told to report back if it's not enough to do what I want to do. Looks like we will keep ModCheck in RW 1.0  :)

I have no ETA for the next release though, partly due to not having seen the next build yet, partly because I know I more or less will have to modify the core of ModCheck. However it looks like it requires a lot of work (time) and I will likely end up releasing a partial version with the most used operations out ASAP. That way I will likely not hold back releases of other mods while I figure out how to get everything working perfectly as well as fully optimized to the new RW 1.0 code design (which is essentially a rewrite).
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on June 19, 2018, 03:06:26 PM
Build 1939 appears to have solved the issue. In fact everything without any exceptions related to xml loading and patching has become fully modable, which is even better than B18  :D

The situation is this. Vanilla patching approach:

B18:

1.0:

The reason for this change is that XPATH is by far the slowest part and by using it on just one file, the number of XPATH calls is reduced alot, which translates to faster patching. The problem is that this one file is huge compared to the multi file approach of B18 (and A17).

My plan:
My splitting patches into two folders, it will be possible to have vanilla patching and B18 style patching working side by side. This way mods using ModCheck will be able to use FindFile, which should still be significantly faster than even the new vanilla. Both approaches will then use a single XPATH search, but the performance difference lies in the fact that ModCheck will use the search a much smaller file. Mods not using ModCheck will use the new vanilla code and benefit from the improved performance.

All operations will work in both patch folders and both will be profiled. However the vanilla one will keep file and modName blank for obvious reasons, meaning features relying on those will not really work. This completely destroys the idea of FindFile, but it will technically still work. It just compares against empty strings.

Still no ETA on this, but I have a plan and I have made vanilla support the plan. That's way better than yesterday.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: SargBjornson on June 19, 2018, 03:20:35 PM
Awesome! Your work is appreciated, man!
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on June 20, 2018, 09:59:21 AM
I made a pre-release version for RW 1.0. It can be downloaded here (https://github.com/Nightinggale/ModCheck/blob/1.0/Assemblies/ModCheck.dll). It's linked against the new Harmony 1.1.0, which I added to git here (https://github.com/Nightinggale/ModCheck/blob/1.0/Assemblies/0Harmony.dll).

Do note that being a pre-release it's not intended to be released with other mods. It's purely intended to allow other mods to be tested with RimWorld 1.0 even if they use ModCheck. Testing is limited, but it passed the automated test. FindFile is broken for the time being and will always be true.

Now I will carry on to implement B18 style patching and generally optimize for the new conditions present in RW1.0.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on June 21, 2018, 07:40:02 PM
I just committed a new version, which can be downloaded with the link from the last post. ModCheck now reads patches in ModCheckPatches and apply them to each xml file individually, just like B18. Patches are still applied by vanilla code. All PatchOperations work in both places. ModCheck.FindFile works again, though it only makes sense to use it in ModCheckPatches. Profiling adds M or P to tell which folder each patch is located in.

I haven't tested it much yet and as such it's still not ready for a real release. I have rewritten most of the harmony interface and the internal memory/cache in order to handle the new vanilla code and two locations for patches. As a result, it really should be tested well. The individual PatchOperations are however untouched.

Feel free to report back what works and what doesn't.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on June 25, 2018, 04:33:47 PM
I pushed a new version. This time I fixed a crashing bug for empty patch folders and improved profiling.

However now I ran into an unexpected issue. I made a simple patch, which changes the construction cost of a building. This resulted in the following profiling.





B18 patching
20 ms
B18 patching with FindFile
14.5 ms
1.0 vanilla patching
0.065 ms
new operation (see below)
0.044 ms
This made me suspect something is wrong with my approach and I tried B18 style patching with an empty sequence and it turns out patching that one takes 0.3 ms or almost 5 times as long as applying the patch using the new 1.0 style patching. I honestly did not expect that or the big difference between B18 and 1.0. It would appear vanilla code itself is 300 times faster. I'm considering removing FindFile and B18 style patching, but since it works, I might as well keep it and see what happens with hundreds of patches when those are available.


I did however finally implement the last operation I have been thinking of regarding performance boosting.
<li Class="ModCheck.tmp">
<xpath>Defs/ThingDef[defName="WatermillGenerator"]</xpath>
<operation Class="PatchOperationReplace">
<xpath>Defs/tmp/ThingDef/costList/WoodLog</xpath>
<value>
<WoodLog>100</WoodLog>
</value>
</operation>
</li>

What it does is it makes the search and for each found xml node, it moves that node into Defs/tmp, calls operation and then it moves the node back. The result is that when operation is called, Defs/tmp will only contain a single node and as such xpath can use a fixed path without any searching. This simplifies the xpath search and as the table shows, this is even faster than vanilla patching. Even better, if operation is a sequence, multiple patching can be done on the same node (in this case ThingDef). I can't really tell the time difference between patching one or 3 values, meaning I can patch all 3 cost values for less than it takes to change even just one using pure vanilla operations.

This leaves one question: what should the new operation be called? And what should the temporal path be called?
Right now I can't think of a good name. Hopefully somebody else can come up with something, which doesn't seem to be disconnected from the functionality.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: larSyn on August 28, 2018, 09:36:44 AM
Hey Nightinggale

I don't have a name for the new operation, but I wanted to ask if this new operation is more efficient than findFile?  Now that B19 is official I wanted to get to work on the updates for my mods that use Modcheck, and everything uses findFile.  I am just wondering if there is going to need to be significant changes to my patches, as there are a lot of them.

And, thanks for keeping modcheck going.  SI is pretty much designed to work with it now and I'd hate to rewrite all of it using the vanilla system.  :)

Edit:  I'm also getting an error anytime I use the .isModLoaded and .findFile together.  See the code below for how I had it written for B18 (this is how I was modifying my mods files in the presence of other mods)
<Operation Class="PatchOperationSequence">
<success>Always</success>
<operations>
<li Class="ModCheck.isModLoaded">
<modName>VGP Garden Gourmet</modName>
<yourMod>Smokeleaf Industry</yourMod>
</li>
                        <li Class="ModCheck.FindFile">
                                <modName>Smokeleaf Industry</modName>
                                <file>MSI_Items_Edibles.xml</file>
                        </li>
<li Class="PatchOperationReplace">
<xpath>Defs/ThingDef[defName = "HempFlour"]/thingCategories</xpath>
<value>
<thingCategories>
<li>CookingSupplies</li>
</thingCategories>
</value>
</li>
<li Class="PatchOperationReplace">
<xpath>Defs/ThingDef[defName = "HempMilk"]/thingCategories</xpath>
<value>
<thingCategories>
<li>CookingSupplies</li>
</thingCategories>
</value>
</li>
<li Class="PatchOperationReplace">
<xpath>Defs/ThingDef[defName = "SmokeleafSeedOil"]/thingCategories</xpath>
<value>
<thingCategories>
<li>CookingSupplies</li>
</thingCategories>
</value>
</li>
<li Class="PatchOperationReplace">
<xpath>Defs/ThingDef[defName = "SmokeleafButter"]/thingCategories</xpath>
<value>
<thingCategories>
<li>CookingSupplies</li>
</thingCategories>
</value>
</li>
</operations>
</Operation>


Here's the error from the debug window:
[Smokeleaf Industry] Patch operation Verse.PatchOperationSequence(count=6) failed
file: C:\Games\Steam\steamapps\common\RimWorld\Mods\Smokeleaf_Industry\Patches\Vegetable Garden Patches\SmokeleafInd-VG_ediblesPatch.xml
Verse.Log:Error(String, Boolean)
Verse.PatchOperation:Complete(String)
Verse.PatchOperationSequence:Complete(String)
Verse.LoadedModManager:ClearCachedPatches()
Verse.LoadedModManager:LoadAllActiveMods()
Verse.PlayDataLoader:DoPlayLoad()
Verse.PlayDataLoader:LoadAllPlayData(Boolean)
Verse.Root:<Start>m__1()
Verse.LongEventHandler:RunEventFromAnotherThread(Action)
Verse.LongEventHandler:<UpdateCurrentAsynchronousEvent>m__1()


Edit 2:  Also getting these two errors:
Error while instantiating a mod of type ModCheck.HarmonyStarter: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.MissingMethodException: Method not found: 'Verse.Log.Error'.
  at ModCheck.HarmonyStarter..ctor (Verse.ModContentPack content) [0x00000] in <filename unknown>:0
  at (wrapper managed-to-native) System.Reflection.MonoCMethod:InternalInvoke (object,object[],System.Exception&)
  at System.Reflection.MonoCMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <filename unknown>:0
  --- End of inner exception stack trace ---
  at System.Reflection.MonoCMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <filename unknown>:0
  at System.Reflection.MonoCMethod.Invoke (BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <filename unknown>:0
  at System.Activator.CreateInstance (System.Type type, BindingFlags bindingAttr, System.Reflection.Binder binder, System.Object[] args, System.Globalization.CultureInfo culture, System.Object[] activationAttributes) [0x00000] in <filename unknown>:0
  at System.Activator.CreateInstance (System.Type type, System.Object[] args, System.Object[] activationAttributes) [0x00000] in <filename unknown>:0
  at System.Activator.CreateInstance (System.Type type, System.Object[] args) [0x00000] in <filename unknown>:0
  at Verse.LoadedModManager.CreateModClasses () [0x00000] in <filename unknown>:0
Verse.Log:Error(String, Boolean)
Verse.LoadedModManager:CreateModClasses()
Verse.LoadedModManager:LoadAllActiveMods()
Verse.PlayDataLoader:DoPlayLoad()
Verse.PlayDataLoader:LoadAllPlayData(Boolean)
Verse.Root:<Start>m__1()
Verse.LongEventHandler:RunEventFromAnotherThread(Action)
Verse.LongEventHandler:<UpdateCurrentAsynchronousEvent>m__1()


Error in patch.Apply(): System.MissingMethodException: Method not found: 'Verse.Log.Message'.
  at ModCheck.ModCheckLog.printLogMessages (Boolean success) [0x00000] in <filename unknown>:0
  at ModCheck.ModCheckBase.ApplyWorker (System.Xml.XmlDocument xml) [0x00000] in <filename unknown>:0
  at Verse.PatchOperation.Apply (System.Xml.XmlDocument xml) [0x00000] in <filename unknown>:0
  at Verse.PatchOperationSequence.ApplyWorker (System.Xml.XmlDocument xml) [0x00000] in <filename unknown>:0
  at Verse.PatchOperation.Apply (System.Xml.XmlDocument xml) [0x00000] in <filename unknown>:0
  at Verse.LoadedModManager.ApplyPatches (System.Xml.XmlDocument xmlDoc, System.Collections.Generic.Dictionary`2 assetlookup) [0x00000] in <filename unknown>:0
Verse.Log:Error(String, Boolean)
Verse.LoadedModManager:ApplyPatches(XmlDocument, Dictionary`2)
Verse.LoadedModManager:LoadAllActiveMods()
Verse.PlayDataLoader:DoPlayLoad()
Verse.PlayDataLoader:LoadAllPlayData(Boolean)
Verse.Root:<Start>m__1()
Verse.LongEventHandler:RunEventFromAnotherThread(Action)
Verse.LongEventHandler:<UpdateCurrentAsynchronousEvent>m__1()




Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: SargBjornson on September 02, 2018, 01:07:20 PM
Hi Nightingale! Have you updated this to B19? Cheers!
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Fuglypump on September 02, 2018, 06:56:28 PM
Pretty much have my mods stuck on hold to update for B19 until modcheck is updated, the B18 .dll does not seem to work properly for B19
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on September 14, 2018, 05:38:45 PM
ModCheck 1.8 has been released. The main change is B19 support and dropped support for B18.

Vanilla made a complete rewrite of xml loading from mods, meaning ModCheck had to be partially rewritten too. Now all files are read, merged into one giant xml file and then patched. This is a great move because it's much faster, even faster than ModCheck could make B18. However since there is no longer an owner of the file being patched, FindFile is dead. I did work on preserving it, but it didn't turn out well and actually slowed down patching. You will have to rewrite FindFile to either not use it at all or use the other operations to test for presence of other mods.

I added a search operation. It's used like this:
<li Class="ModCheck.Search">
<xpath>Defs/ThingDef[defName="WatermillGenerator"]</xpath>
<operations>
same code as a sequence
</operations>

What it does is whatever it finds will be moved to Defs/SearchResult/ThingDef and then back once operations are done. This mean xpaths can use "Defs/SearchResult/ThingDef" instead of "Defs/ThingDef[defName="WatermillGenerator"]". It has an overhead in setting up, which is around 2.5-2.7 xpath searches (at least if only vanilla is loaded). However if you need to do 3 modifications it will be faster because "Defs/SearchResult/ThingDef" is following a path, not a search. If you need to do 4 operations, it's still faster than 3 vanilla operations with a searching xpath. In other words it's a performance boosting tool for the cases where you need to do a bunch of operations to the same item.

I also added the Move operation.
<Operation Class="ModCheck.Move">
<xpath>Defs/ThingDef[defName="SolarGenerator"]</xpath>
<followers>
<li>Defs/ThingDef[defName="AdvancedSolarGenerator"]</li>
</followers>
</Operation>

This will make use of the fact that it's now one big xml file. What is does is that it will find xpath and then it will take whatever is in followers (it's a list of unlimited size) and move the elements to be right after the xpath element. In this specific case it will move AdvancedSolarGenerator to be next to SolarGenerator. If multiple followers are added, they will be added in the order they are written. This should allow placing the buildings in useful groupings rather than the vanilla approach, which is semi random based on load order.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: larSyn on September 20, 2018, 07:09:45 AM
Thanks Nightinggale!  :)
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: hauvega on September 22, 2018, 11:28:51 AM
Thanks Nightinggale.  This mod has help in patching everything in one mod instead of a bunch of separate mods.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: ilikegoodfood on October 07, 2018, 09:29:37 AM
Hey folks.

I've finally reached the final stage of updating my one and only mod to b19; compatibility. I'm trying to understand what changes I'll need to make in order to get my patches working as smoothly as possible. Having read through the conversation, I have extracted the following information:


Is that correct, and is that all I need to do?
I've already updated ModCheck and it works, but I need to rebuild some of it anyway, so I should tidy up as I do so.

Thanks.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on October 07, 2018, 02:22:08 PM
Quote from: ilikegoodfood on October 07, 2018, 09:29:37 AM
2. Performing ModCheck.isModLoaded, immediately followed by ModCheck.loadOrder causes ModCheck.LoadOrder to fail. Does anyone have a fix for this?
Huh  :o
The checks themselves shouldn't influence each other at all, other than the obvious failure stops sequence.
If the mod isn't loaded, LoadOrder is never called. If the mod is loaded, LoadOrder should be called just like IsModLoaded isn't there at all. If you managed to get it to do anything else, then do tell about it.

Quote from: ilikegoodfood on October 07, 2018, 09:29:37 AM3. If performing three or more operations on a single def, use ModCheck.Search to increase performance. The absolute patch is then Defs/SearchResult/ThingDef.
Yeah that's pretty much it. However like with everything else regarding performance you should likely test the result to see if you get the expected result.

Also remember the wiki on GitHub has a full list of operations (https://github.com/Nightinggale/ModCheck/wiki/List-of-operations), complete with explanations of each possible tag for each and how to use it.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: ilikegoodfood on October 08, 2018, 06:34:17 AM
I have found the error. The XML for the fail message used to be <errorOnFail>Message</erroronFail>, but it is now just <errorFail>Message</errorFail>. It's my version of the command that is outdated and broken.

EDIT: Various small changes to the way patches are labelled now all fixed and restructured. It works perfectly. Thanks.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on October 21, 2018, 11:42:27 AM
Released a new version for RimWorld 1.0. The only other change is added support for Fluffy's Mod Manager.

The DLL is still the B19 file, meaning mods including the file will not have to update.

It's still version 1.8 because the version tag is in the DLL. Updating the number means replacing all DLL files in all mods. It seems like a major task for no DLL change at all.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Canute on December 27, 2018, 08:58:30 AM
Nightinggale,
maybe you should add at the workshop entry a big sign that regular player don't need to add it to their modlist.
I saw now serveral modlist with Modcheck in their modlist.
Ok it don't hurt, but not nessesary.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: Nightinggale on May 29, 2019, 05:19:39 PM
Updated to 1.8.1
- Fixed compatibility issue with updated Rimworld. Profiling works again.
- Updated version URL for Fluffy's Mod Manager

The compatibility issue is related to transpiler patching. In order to be sure nothing bad would happen to vanilla xml patching, I decided to only apply the transpiler if the method in question is unaltered. The unstable Rimworld is viewed as modified because the compiler came up with the idea of renaming the autogenerated name f__am$cache0 to f__am$cache2.

I made the modification detector a little less picky, but it did give us a test that it would actually do as intended if Rimworld updates, which is to allow patch operations to continue to work as intended while disabling profiling. Also vanilla xml patching does indeed seem to be unbreakable by ModCheck.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: SargBjornson on May 31, 2019, 02:18:06 AM
Thanks man
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: SargBjornson on February 19, 2020, 10:59:29 AM
Any chance of this getting a 1.1 release? It really accelerated all the conditional patching operations :(
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: cucumpear on February 24, 2020, 07:54:07 AM
I second that request, I use ModCheck for so many of my mods.
In either case, thank you so much for making my life easier!
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: SargBjornson on February 24, 2020, 08:57:10 AM
I have a feeling he is no longer around here :( I looked at the code, but it is way too advanced for me
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: cucumpear on February 24, 2020, 09:17:00 AM
TBF it would require updating to the new harmony. Welp, that will make patching fun, I always have trouble with checks when using vanilla operations.
Title: Re: [LIB] ModCheck: patch tests and error logging for mod loading
Post by: grapenuts on March 07, 2020, 11:47:40 PM
I took at stab it it because there's a mod that's super-critical for me and it depends on ModCheck. Getting it updated for Harmony 2.0 seemed easy enough as I've already updated a couple other mods, but there's a method where I'm stuck. In Harmony.cs it uses the Harmony Transpiler on Verse.LoadedModManager.ApplyPatches and verifies it's the same as what it expects it to be by line number and string comparisons. I looked at the decomplied Verse code but I don't see how he got it to match, and thus I'm not sure how to replace it.

I'm not looking forward to trying to pick apart the original mod I wanted to fix and try to get it working without ModCheck :(