msmfoster Posted November 28, 2025 Posted November 28, 2025 Skimpy Armour Keyword Injector View File A FO4Edit script that injects Skimpy Armour Keyword Resource (SAKR) keywords into patched copies of relevant Armour (ARMO) records. This process uses the existing RobCo Patcher .ini infrastructure as the source of keywords, but does not require RobCo Patcher. Key Features Accepts your entire load order (every single loaded plugin) in one go. Creates the patch, adds all required masters, and injects keywords in a single run. Uses your existing RobCo Patcher .ini files. Requires no new tools to run. Creates a tiny, ESL-flagged patch. Typically under 500 KB for a setup with 400 mods. Fuzzy FormID matching. Works regardless of load order, ESL flags, or overrides. Pre-emptively adds required masters to ensure compatibility with other keyword injectors such as Armour and Weapon Keywords Community Resource (AWKCR) and Complex Item Sorter. Creates a new patch file per run to avoid keyword drift. Recommended for consistency when .ini files change. This requirement can be bypassed if the patch is already loaded in FO4Edit. Extensive, configurable logging. Uses dialogue boxes to notify the user of abnormal runs. E.g. No keywords to inject or nothing to patch. Zero performance impact in-game as the patch is generated by FO4Edit beforehand. Why This Exists Skimpy Armour Keyword Resource was designed to work with RobCo Patcher, which adds keywords at runtime. But: The Next-Gen Update (2024) broke RobCo Patcher. Users waited months for the Next-Gen alpha version of the patcher. The Anniversary Edition has an alpha version of the patcher. This script removes RobCo Patcher from the equation entirely while leveraging the existing configuration files. No more waiting. No more runtime overhead. Just SAKR support. Requirements FO4Edit. Tested on 4.1.5f. Skimpy Armour Keyword Resource (SAKR). Required in your load order. Rubber Duck's SAKR Repository, or NGamma's SAKR RobCo Patches or Equivalent. Provides the required keywords to inject. How to Use Install the script under Scripts in your FO4Edit install. (Optional) Install the blank .esp if you use a mod manager. Do NOT load ZZZ_SAKR_Direct_Injection.esp when starting FO4Edit. If loaded, the script will remind you of this requirement and allow you to bypass if desired. In FO4Edit: Press Ctrl+A to select all plugins. Right-click on any mod and Apply Script. A new window will appear. Choose Fallout4 - SAKR Direct Injection vX.X.X and click OK. Wait ~60–90 seconds (tested with 400+ loaded mods and 2.5M records). Save. Let your mod manager (Vortex/MO2) deploy the new patch. Run the game and go try on some outfits! Tip. For testing, select a few clothing mods to speed up script processing. Cleanup After Use A normal run adds several masters to ensure the winning record is copied and injected. It is recommended that you: Save ZZZ_SAKR_Direct_Injection.esp; Right-click on the mod and select, Clean Masters to remove unnecessary masters. While optional, the above keeps the patch tidy and avoids Missing Masters warnings when changing your mod order within a mod manager. Confirmation Tests The screenshots on the download pages outline various scenarios to confirm the patch works. These tests cover ESLs, base-game items, heavily overridden packs (preview patches), and exposure score changes. Shot in Kziitd Fetish Toolset. Result 100 % skimpy because that mod has no .ini in the Rubber Duck repository. Shots in a Vtaw Wardrobe 6 bikini with or without the top. Highlights the changes in exposure levels and scores. Shot in a COCO Bikini Collection showing exposure and scores change, indicating the .ESL was successfully patched. Shot in Summer Shorts with appropriate scores. Showing that base-game clothing items were successfully patched. Shots in various Vtaw Wardrobe 6 clothing with varying scores. Additionally some are blurry as they triggered Exhibitionist Streak from Provocative Perks because the player is not skimpy enough. Frequently Asked Questions Do I need RobCo Patcher installed? No. This script does not require RobCo Patcher to be installed and the patch negates its requirement for use with the Skimpy Armour Keyword Resource once generated. Will this break if I add new outfits later? No. Just re-run the script — the new items will be included in the patch automatically assuming you have associated RobCo Patcher.ini files to inject the keywords. Why does it stop if the patch file is loaded? There is no reliable way for FO4Edit to unload and remove a mod while loaded. To prevent corrupting the patch, the script confirms the patch is unloaded prior to generating a fresh patch. However, you can opt to bypass this check entirely at the risk of introducing keyword drift over an extended period of time. There are legitimate reasons for doing so: You accidentally ran the script against a mod with no clothing items. You prefer to be surgical in your application of the patch and run it for individual mods or collection. You are trying this for the first time and the default patch (empty by default) is loaded. You manually cleaned the patch yourself and want to proceed. For the above, you will simply be given an option to proceed. I hate getting asked if I want to continue when the patch is already loaded. You can disable this check entirely by setting bFORCE_CLEAN_ESP to False in the script. However, this may lead to keyword drift, especially if you are fine-tuning the .ini files to suit your gameplay. Can I keep the old patch and append changes? Yes. See above. Is this safe with 500+ plugins? Yes. Tested with 500+ mods / 3.2 million records. Process took under 180 seconds to generate a clean patch, but the time required varies based on system specifications. Will it work on Anniversary Edition? Yes. While not explicitly tested on Anniversary Edition, FO4Edit 4.1.5f which was used to develop this script fully supports that version. I still want to keep RobCo Patcher for other features (material swaps, slot masking, etc.) This script does not stop you from continuing to use RobCo Patcher. Both can coexist perfectly, but to prevent duplicate keyword injection, simply delete or move the RobCo Patcher .ini files used for SAKR keywords. Bonus side-effects of removing those .ini files: RobCo Patcher has fewer records to process reducing runtime overhead May reduce the chances of RobCo Patcher crashing. Is this compatible with Armour and Weapon Keywords Community Resource (AWKCR) and Complex Item Sorter? Yes. The script will add these as masters and carry forward any modified or injected keywords. However, this patch needs to be lower in your load order override their records. Some of my clothing packs have no .ini file for it. How can I make these? Rubber Duck has made a SAKR RCP Tool that generate the RobCo Patcher files along with extensive documentation. I keep seeing Error Assigning To and Mapping Errors in my logs. Message such as the one below occurs because the script cannot know for certain every mod that it will need to add a master. Error assigning to [ \ [FA] ZZZ_SAKR_Direct_Injection.esp \ [1] GRUP Top "ARMO" \ [77] Armor_Synth_Underarmor "Synth Uniform" [ARMO:0012B91D] \ [19] Object Template \ [2] Combinations \ [34] Combination \ [2] OBTS - Object Mod Template Item \ [8] Keywords \ [0] Keyword #0] from [ \ [A7] Synth_Fem.esp \ [4] GRUP Top "ARMO" \ [2] Armor_Synth_Underarmor "Synth Uniform" [ARMO:0012B91D] \ [19] Object Template \ [1] Combinations \ [34] Combination \ [2] OBTS - Object Mod Template Item \ [8] Keywords \ [0] Keyword #0]: [Exception] Load order FileID [A5] can not be mapped to file FileID for file "ZZZ_SAKR_Direct_Injection.esp In such cases the keywords will not be injected. However the Script naturally takes precautions to avoid this: Preemptively loads any non-ESL flagged ESM/ESP as a Master. This will cut out most of these errors. Provides an ability to add a custom list of masters. Update the sADDMASTERS constant to include a comma delimited list of additional mods you need to load as masters. Between the above, the script should all relevant masters, and inject keywords without fault. Can I modify or fork your code? Yes. The script is released under the two-clause BSD licence which is a permissive free software licence. Configurable Items The following constants may be changed to alter the script's behaviour. You only need to touch these constants if you have a very custom setup. Most users will be able to ignore these options entirely. There are listed in alphabetical order. bADDALLMASTERS Default: True Automatically adds all non-ESL flagged ESP and ESM files with ARMO records as masters. This ensures that injection will occur most of the time. Tip. Clean up the loaded masters in the mod after running the script and saving the contents. sADDMASTERS Default: '' A comma delimited list of mods that need to be mastered beyond those added as part of the standard script processing. This constant becomes critical when disabling sADDALLMASTERS. iDEBUG_LEVEL Default: DEBUG_INFO Adjust the level and verbosity of logs generated. Available levels are: DEBUG_FATAL DEBUG_ERROR DEBUG_WARN DEBUG_INFO DEBUG_VERBOSE DEBUG_PATHING bDRYRUN Default: False Kept for historical reasons. With a patch-file workflow there are no risks to the game and other mods, but it remains useful for pathing. bESLFLAG Default: True By default the ZZZ_SAKR_Direct_Injection.esp will be created as an ESL-flagged ESP. This means that the patch will not tie up a slot on your limited load order at the cost of reduced entries. Set to False if you need to inject keywords into more than 4095 items. bBALLISTIC Default: True Injects Ballistic Weave related keywords to the item in addition to SAKR. This can be useful for certain mods that expect this slot to exist for their own use and increase available clothing items. bFORCE_CLEAN_ESP Default: True Deletes and recreates the patch every run. Prevents drift when .ini files change. Set False if you prefer incremental patching on selected mods. sLOGFILE Default: '' Set the path of an external file that the log will be written to. iMERGE Default: False By default the script will drop any conflicting keyword injection. This prevents situations where a competing .ini has conflicting keyword injections to make. Any such conflicts will be logged at the end of the process to identify and sort out conflicts. If set to `True` the script will merge the conflicts together into one line. However, there are potential risks. A perfect example of this is Eli's Armour Compendium and Classy Chassis Outfits - Eli's Armour Replacer. The former includes lore friendly and non-lewd clothing items, whereas the latter will spice things up. They both use Eli_Armour_Compendium.esp and a matching identifier leading to the following situation where an item now has keywords for: 0000081A. Top Full 0000081E. Tank Top 00000821. Top Tight 0000080E. Pants Long 0000080F. Pants Shorts The above contains clearly contains keywords that are at odds with each other and should not co-exist. The resulting score will be wildly off from expected behaviour. Hence merge mode is provided for advanced users who understand the risks. When set to False the script generates a report at the end of the run. This permits you to find and correct these conflicts to ensure the desired outcome. sPATCH_ESP Default: ZZZ_SAKR_Direct_Injection.esp Name of the generated patch. ZZZ prefix keeps it at the bottom of the load order. iRECURSION Default: 5 Maximum directory depth when scanning for .ini files to prevent infinite loops. sROBCOPATH Default: F4SE\Plugins\RobCo_Patcher\armor\ Default location of RobCo armour .ini files (overridden by sSCANPATH if used). bSAKRSTATIC Default: False Use static keyword list (True) or read directly from SAKR.esm (False). False is the default as it adjusts to future releases of the mod. sSCANPATH Default: '' Hardcoded location for the RobCo Patcher .ini files. Use '' to use game defaults. sSAKR_ESP / sGAME_ESP / sPATCH_AUTHOR Self-explanatory and should never need changing. License * * Copyright (c) 2025, M.S.M. Foster * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * Submitter msmfoster Submitted 11/28/25 Category Modders Resources Requirements FO4Edit. Tested on 4.1.5f. Skimpy Armor Keyword Resource (SAKR). Required in your load order.
msmfoster Posted November 30, 2025 Author Posted November 30, 2025 (edited) 5 hours ago, Franco Cozzo said: Just letting you know the link in the description is going to [Link] instead of https://www.loverslab.com/files/file/26435-skimpy-armor-keyword-resource-4132023/ Thanks! I'll adjust as soon as I get on my PC. Done! Edited November 30, 2025 by msmfoster Confirming it has been done. 1
4nln415 Posted December 6, 2025 Posted December 6, 2025 Requirement SAKR leads to The Sims 4 Ahegao dress btw 1
deff. Posted December 6, 2025 Posted December 6, 2025 I'm getting this one and looks like, that something went wrong: Spoiler
msmfoster Posted December 6, 2025 Author Posted December 6, 2025 12 hours ago, deff. said: I'm getting this one and looks like, that something went wrong: Hide contents It means it did not find any valid rules in the .INI files scanned. The default is to scan the RoboCo Patcher folder(s) which repositories use to drop off their files. The logs show you had two .INI files found, which is low if you are using something like Rubber Ducks SAKR repository.
msmfoster Posted December 7, 2025 Author Posted December 7, 2025 On 12/6/2025 at 1:01 AM, 4nln415 said: Requirement SAKR leads to The Sims 4 Ahegao dress btw Thanks. I'll adjust when I get on my PC.
iampumpkin Posted December 8, 2025 Posted December 8, 2025 (edited) The script normally processes many records, but at the end the script shows the error: [SAKR] >>> INFO - Now processing: VTAW 68 Raiders.esp <<< [SAKR] INFO - MATCH FOUND for VTAW 68 Raiders.esp|000003C2 : SkimpyArmorKeywordResource.esm|0000080C [SAKR] INFO - Injected 1 SAKR keyword(s) into Vtaw_utilityTop MC ...I cut many successfully processed records for brevity... [SAKR] INFO - MATCH FOUND for VTAW 68 Raiders.esp|00000377 : SkimpyArmorKeywordResource.esm|0000081E,SkimpyArmorKeywordResource.esm|00000820,SkimpyArmorKeywordResource.esm|0000081D,SkimpyArmorKeywordResource.esm|0000081A [SAKR] INFO - Injected 4 SAKR keyword(s) into V7 WD7TankTop [SAKR] INFO - MATCH FOUND for VTAW 68 Raiders.esp|00000376 : SkimpyArmorKeywordResource.esm|00000803 [SAKR] INFO - Injected 1 SAKR keyword(s) into V7 WD7TacticalVestForOutfitsNoMiddle [SAKR] INFO - MATCH FOUND for VTAW 68 Raiders.esp|00000375 : SkimpyArmorKeywordResource.esm|00000803 [SAKR] INFO - Creating Keyword Array (KWDA) [01:57] Exception in unit SAKR_Direct_Injection line 904: [Exception] AvailableCondition3 [AVIF:00000375] can not be edited [01:57] Aborted: Applying script "Fallout4 - SAKR Direct Injection v1.0.0b2" After this I alse see many records edited in `DLCworkshot02.esm` which probably should not happen? I tried on Fo4Edit 4.1.5f. Fallout 1.163.0 (GOG). The row from my .ini that I suppose is causing the problem: // "Vtaw WD7 Tactical Vest For Outfits No Bags V2" filterByArmors=VTAW 68 Raiders.esp|000375:keywordsToAdd=SkimpyArmorKeywordResource.esm|000803 Edited December 8, 2025 by iampumpkin 1
iampumpkin Posted December 8, 2025 Posted December 8, 2025 Another problem I noticed: the script doesn't carry over the overrides of the modified records. See this example: As you can see, `ZZZ_SAKR_Direct_Injection.esp` copied the original record from `VTAW 68 Raiders.esp`, but this record is already overriden by 2 other mods. One of them is Complex Sorter's result, so it is possible to run Complex Sortter after this script and it will solve the problem. But the other is for 3d item previews and it must be before the generated `ZZZ_SAKR_Direct_Injection.esp` in the load order, otherwise one of them will override the other. Probably, as a workaround you can select only `VTAW 68 Raiders Previews.esp` and selectively generate some data AFTER you deselected it and generated the main file, but this is very error-prone and tedious process, and I'm not sure it will work as expected anyway. 1
msmfoster Posted December 8, 2025 Author Posted December 8, 2025 (edited) 16 hours ago, iampumpkin said: The script normally processes many records, but at the end the script shows the error: [SAKR] >>> INFO - Now processing: VTAW 68 Raiders.esp <<< [SAKR] INFO - MATCH FOUND for VTAW 68 Raiders.esp|000003C2 : SkimpyArmorKeywordResource.esm|0000080C [SAKR] INFO - Injected 1 SAKR keyword(s) into Vtaw_utilityTop MC ...I cut many successfully processed records for brevity... [SAKR] INFO - MATCH FOUND for VTAW 68 Raiders.esp|00000377 : SkimpyArmorKeywordResource.esm|0000081E,SkimpyArmorKeywordResource.esm|00000820,SkimpyArmorKeywordResource.esm|0000081D,SkimpyArmorKeywordResource.esm|0000081A [SAKR] INFO - Injected 4 SAKR keyword(s) into V7 WD7TankTop [SAKR] INFO - MATCH FOUND for VTAW 68 Raiders.esp|00000376 : SkimpyArmorKeywordResource.esm|00000803 [SAKR] INFO - Injected 1 SAKR keyword(s) into V7 WD7TacticalVestForOutfitsNoMiddle [SAKR] INFO - MATCH FOUND for VTAW 68 Raiders.esp|00000375 : SkimpyArmorKeywordResource.esm|00000803 [SAKR] INFO - Creating Keyword Array (KWDA) [01:57] Exception in unit SAKR_Direct_Injection line 904: [Exception] AvailableCondition3 [AVIF:00000375] can not be edited [01:57] Aborted: Applying script "Fallout4 - SAKR Direct Injection v1.0.0b2" After this I alse see many records edited in `DLCworkshot02.esm` which probably should not happen? I tried on Fo4Edit 4.1.5f. Fallout 1.163.0 (GOG). The row from my .ini that I suppose is causing the problem: // "Vtaw WD7 Tactical Vest For Outfits No Bags V2" filterByArmors=VTAW 68 Raiders.esp|000375:keywordsToAdd=SkimpyArmorKeywordResource.esm|000803 I pulled in Grok to help see what's going on. According to their analysis it might be a problem related to that specific record. This is a known issue with certain ARMO records that have an certain associated Virtual Machine Adapter (VMAD). When you try to create a thin copy the script cannot be resolved and FO4Edit triggers an exception. I have included a code change with this post. It's supposedly contains the workaround, which you will be asked to confirm prior to implementing it. Effectively it temporarily removes the offending record, does a thin copy, and then puts it right back. From FO4Edit's point of view this won't even count as a change. See if this works for you. I have no way of confirming it unless this a clothing pack that readily supports Fusion Girl. More details below on the failure. Root cause: This specific ARMO record has a VMAD (Papyrus script) attached, with a condition AvailableCondition3 referencing [AVIF:00000375]. AVIF = Actor Value Info condition (e.g., checks player skill/level). During Add('KWDA'), xEdit validates the entire record structure. Validation touches VMAD → tries to "edit" the AVIF condition → fails because: Self-referential FormID (00000375 points to itself?). Load order remapping in patch mismatches the condition's context. VMAD conditions in overrides can't always be "touched" without full copy. This is record-specific — explains why your full-load-order runs worked before: This .ini line newly targets |00000375. Previous configs skipped it → no crash. Not DLC-related: Crash is on VTAW ARMO, not DLC ACTI. (Screenshot shows xEdit view after abort; DLC selected coincidentally.)Loo Root cause: This specific ARMO record has a VMAD (Papyrus script) attached, with a condition AvailableCondition3 referencing [AVIF:00000375]. AVIF = Actor Value Info condition (e.g., checks player skill/level). During Add('KWDA'), xEdit validates the entire record structure. Validation touches VMAD → tries to "edit" the AVIF condition → fails because: Self-referential FormID (00000375 points to itself?). Load order remapping in patch mismatches the condition's context. VMAD conditions in overrides can't always be "touched" without full copy. This is record-specific — explains why your full-load-order runs worked before: This .ini line newly targets |00000375. Previous configs skipped it → no crash. Not DLC-related: Crash is on VTAW ARMO, not DLC ACTI. (Screenshot shows xEdit view after abort; DLC selected coincidentally.) Fallout4 - SAKR Direct Injection v1.0.0b3.zip Edited December 8, 2025 by msmfoster Added more details and attached a potential fix.
msmfoster Posted December 8, 2025 Author Posted December 8, 2025 16 hours ago, iampumpkin said: Another problem I noticed: the script doesn't carry over the overrides of the modified records. See this example: As you can see, `ZZZ_SAKR_Direct_Injection.esp` copied the original record from `VTAW 68 Raiders.esp`, but this record is already overriden by 2 other mods. One of them is Complex Sorter's result, so it is possible to run Complex Sortter after this script and it will solve the problem. But the other is for 3d item previews and it must be before the generated `ZZZ_SAKR_Direct_Injection.esp` in the load order, otherwise one of them will override the other. Probably, as a workaround you can select only `VTAW 68 Raiders Previews.esp` and selectively generate some data AFTER you deselected it and generated the main file, but this is very error-prone and tedious process, and I'm not sure it will work as expected anyway. Here is my understanding of the process. The ARMO records are cumulative in nature, meaning they build on each other as overrides are introduced. For example I used Armour and Weapon Keywords Community Resource (AWKCR) which adds it's own keywords and there is no conflict. When an override is done, it will get the master record for ARMO and we will do a thin copy. This means the patch only includes SAKR keywords in the Keywords Array (KWDA), but the rest of the elements are still there and we now have become the master. This will permit SAKR, AWKCR and other mods that need ARMO keywords to get what they need and do so without conflict, as long as we are low enough in the load order to override them entirely. For example I have mine grouped in 'Late Patches' which is loaded 395th in Vortex. However, if you add clothing mods, or mods that inject their own keywords that will require you to run this script to reflect the change. That's pretty much it. What mod do you use for 3D Item Previews? That would be great for the VTAW library!
iampumpkin Posted December 10, 2025 Posted December 10, 2025 On 12/8/2025 at 1:08 PM, msmfoster said: I have included a code change with this post. It's supposedly contains the workaround, which you will be asked to confirm prior to implementing it. I tried the b3 version. No, it didn't help. Same error: [SAKR] INFO - MATCH FOUND for VTAW 68 Raiders.esp|00000375 : SkimpyArmorKeywordResource.esm|00000803 [SAKR] INFO - Creating Keyword Array (KWDA) [01:59] Exception in unit SAKR_Direct_Injection line 1021: [Exception] AvailableCondition3 [AVIF:00000375] can not be edited [01:59] Aborted: Applying script "Fallout4 - SAKR Direct Injection v1.0.0b3" Just FYI: - The file `VTAW 68 Raiders.esp` is from this mod: https://www.nexusmods.com/fallout4/mods/67483 - The file `VTAW 68 Raiders Previews.esp` is from this mod: https://www.nexusmods.com/fallout4/mods/78802 - And the .ini is mine. It was specifically generated from an INI in SAKR repository, but it affects different items. They technically different because they come from `VTAW 68 Raiders.esp` (they have separate formids), but they are logically the same as in the main VTAW mod. It just happens that the authour of `VTAW 68 Raiders.esp` created a copy of each VTAW item instead of reusing them. Only textures/etc are reused. That is why a separate Robco INI is needed. About the changed `DLCworkshot02.esm` - no, it should not happen. Something is wrong with the script. It should only change the records in a newly created ESP, not in existing ESMs. Of course you can just ignore these changes and only save the generated ESP, but the fact that some of the records in an unrelated file are changed is signaling that something is going wrong. About the record override: I didn't get what you are trying to say. When one ESP overrides a record from another ESP it always does it ENTIRELY. You cannot override record partially (e.g. only keywords). It is alway all or nothing. You copy the record from a ESP/ESM as a new record with the same ID to a different ESP and then modify it. That is why load order matters. This script when it reads a record to add the keywords, it reads this record from the ESP it sees in the .ini file. But this is wrong. First, the script needs to check if this ARMO record is already overriden and read it from the very last instance of the same record (from the latest ESP in the load order that has it). Otherwise the script will just overwrite everything any mod in-between the generated ESP and the ESP in the .ini file added/changed in the record. Of course, what I described is not an exact algorithm. It is just how it logically works.
iampumpkin Posted December 10, 2025 Posted December 10, 2025 (edited) FYI: I disabled the `VTAW 68 Raiders Previews.esp` and run the script - it worked successfully. The `DLCworkshot02.esm` problem was also gone. But the problem with overriding an incorrect record persists. E.g. let's take this record: As you can see, the scipt successfully added the keywords. But it copied the the original ARMO record from `Fallout4.esm` (and added the keywords to it), while it should have copy the ARMO record from `M8r Complex Sorter.esp` as it is the last record in the load order that overrides the original ARMO record. Because of this, the Item name overriden by `M8r Complex Sorter.esp` is overriden again and it is now returned back to the original ("Long Johns"). Maybe if this problem will be fixed, the other problem (with unintentional modification of `DLCworkshot02.esm` and an exception when `VTAW 68 Raiders Previews.esp` is enabled) will automatically gone too.. Edited December 10, 2025 by iampumpkin
msmfoster Posted December 10, 2025 Author Posted December 10, 2025 4 hours ago, iampumpkin said: FYI: I disabled the `VTAW 68 Raiders Previews.esp` and run the script - it worked successfully. The `DLCworkshot02.esm` problem was also gone. But the problem with overriding an incorrect record persists. E.g. let's take this record: As you can see, the scipt successfully added the keywords. But it copied the the original ARMO record from `Fallout4.esm` (and added the keywords to it), while it should have copy the ARMO record from `M8r Complex Sorter.esp` as it is the last record in the load order that overrides the original ARMO record. Because of this, the Item name overriden by `M8r Complex Sorter.esp` is overriden again and it is now returned back to the original ("Long Johns"). Maybe if this problem will be fixed, the other problem (with unintentional modification of `DLCworkshot02.esm` and an exception when `VTAW 68 Raiders Previews.esp` is enabled) will automatically gone too.. I realized yesterday that the VTAW Raiders was not the culprit. Because there were no VMAD elements in mine. Can you send me the .ini with just those elements? I'll recreate your setup and see what's failing. Did you see a pop-up about a VMAD Workaround? Check my FAQ there's something about complex sorter and getting it to work. Based on what you observed the script is working as expected. It copied from the highest override, but failed. That I can work with at least once I create similar conditions.
iampumpkin Posted December 11, 2025 Posted December 11, 2025 (edited) Quote Can you send me the .ini with just those elements? Here is the full INI that causing them problem: VTAW 68 Raiders.esp.zip On 12/10/2025 at 2:41 PM, msmfoster said: Did you see a pop-up about a VMAD Workaround? No, the beuaviour was exactly as in version b2. I seen the diff of the b2 and b3 and seen in the code the dialogue window that was supposed to popup, but no, there was no dialogue window. Just an exception. On 12/10/2025 at 2:41 PM, msmfoster said: Check my FAQ there's something about complex sorter and getting it to work. I seen it, but I do not understand what do you mean by "Add this ZZZ_SAKR_Direct_Injection.esp to the bottom of Complex Sorter's `Plugins` list (or `Force Load After` box).". If what you mean is just puttin ZZZ_SAKR_Direct_Injection.esp down below in the load order, then yes, of course I did that. On 12/10/2025 at 2:41 PM, msmfoster said: Based on what you observed the script is working as expected. It copied from the highest override, but failed. That I can work with at least once I create similar conditions. I think there is some misunderstanding here. My previous comment with the screenshot of "Long Johns" ARMO record was from a successful run of the script. It has nothing to do with the problem we discussed above. It is a totally seaparate problem. And the problem is that it DID NOT copy from the highest override. It copied from the lowest as you can clearly see on the screenshot. It didn't fail. It copied successfully. I'll repeat: this screenshot is from the successful run. Also it has also nothing to do with Complex Sorter. Complex Sorter.esp is just an example here. It could be any other esp, that overrides the base ARMO record. I can give you other examples unrelated to Complex Sorter if you need. Edited December 11, 2025 by iampumpkin
msmfoster Posted December 12, 2025 Author Posted December 12, 2025 (edited) On 12/11/2025 at 6:52 AM, iampumpkin said: Here is the full INI that causing them problem: VTAW 68 Raiders.esp.zip 4.85 kB · 1 download No, the beuaviour was exactly as in version b2. I seen the diff of the b2 and b3 and seen in the code the dialogue window that was supposed to popup, but no, there was no dialogue window. Just an exception. I seen it, but I do not understand what do you mean by "Add this ZZZ_SAKR_Direct_Injection.esp to the bottom of Complex Sorter's `Plugins` list (or `Force Load After` box).". If what you mean is just puttin ZZZ_SAKR_Direct_Injection.esp down below in the load order, then yes, of course I did that. I think there is some misunderstanding here. My previous comment with the screenshot of "Long Johns" ARMO record was from a successful run of the script. It has nothing to do with the problem we discussed above. It is a totally seaparate problem. And the problem is that it DID NOT copy from the highest override. It copied from the lowest as you can clearly see on the screenshot. It didn't fail. It copied successfully. I'll repeat: this screenshot is from the successful run. Also it has also nothing to do with Complex Sorter. Complex Sorter.esp is just an example here. It could be any other esp, that overrides the base ARMO record. I can give you other examples unrelated to Complex Sorter if you need. Okay. First off, I cannot duplicate your setup to get the same type of error. However, you screenshot and mine both show that VMAD entries are not present. So I've worked in a few features in B3.1 of the code: Now specifically calls for the winning override when injecting keywords. Hence you were right about Complex Sorter losing it's keywords. Now automatically adds all non-ESL ESP/ESMs with an ARMO record. The reason for this is that some overrides will inject unique keywords and we need add these as masters to override properly. There is a more refined way to add these masters, but you effectively need to run the script and sift through the console to find them. Has a soft fail features (that can be toggled) for SafeCopy. Hence if an override fails it will not crash the script, and you'll know about the failure(s) at the end. I've been able to confirm that keywords carry forward unless the previous override blocks them off. This allows the VTAW preview system to keep working just fine even after we inject keywords. Hopefully this works as expected. If it does, this will likely become 1.0.0 after I update all of the documentation. Fallout4 - SAKR Direct Injection v1.0.0b3.1.7z Edited December 12, 2025 by msmfoster
iampumpkin Posted December 16, 2025 Posted December 16, 2025 (edited) Hello, tried the last version. First, I got this error: [SAKR] INFO - Adding 58 non ESL-Flagged masters... [SAKR] INFO - Adding 1 custom masters... [ZZZ_SAKR_Direct_Injection.esp] Adding master "ArmorKeywords.esm" [ArmorKeywords.esm] Loading file [00:05] Exception in unit SAKR_Direct_Injection line 1737: [EOSError] System Error. Code: 2. The system cannot find the file specified [00:05] Aborted: Applying script "Fallout4 - SAKR Direct Injection v1.0.0b3.1" I really don't have `ArmorKeywords.esm` in my load order. I do not use AWKCR and all mods in the load order do not depend on it. So, I changed the line 128 in the script and removed this custom master (not sure why you added it this way in the first place). After this, the script started to work, but unfortunately it finished with the same exception as 2 previous versions of the script: [SAKR] INFO - Injected 4 SAKR keyword(s) into V7 WD7TankTop [SAKR] INFO - MATCH FOUND for VTAW 68 Raiders.esp|00000376 : SkimpyArmorKeywordResource.esm|00000803 [SAKR] INFO - Injected 1 SAKR keyword(s) into V7 WD7TacticalVestForOutfitsNoMiddle [SAKR] INFO - MATCH FOUND for VTAW 68 Raiders.esp|00000375 : SkimpyArmorKeywordResource.esm|00000803 [SAKR] INFO - Creating Keyword Array (KWDA) [01:58] Exception in unit SAKR_Direct_Injection line 1039: [Exception] AvailableCondition3 [AVIF:00000375] can not be edited [01:58] Aborted: Applying script "Fallout4 - SAKR Direct Injection v1.0.0b3.1" Based on the script and the line 1039 it looks like the "VMAD workaround" doesn't work. --- Then I disabled these patches from this mod https://www.nexusmods.com/fallout4/mods/78802 (see "Vtaw Wardrobe Preview Meshes Patches" in optional files). And run the script again. It worked successfully without these patches. Now it correctly updates the last winning override. So, the problem somehow appears only when these patches are present in the load order. --- To summarize: 1. Script forcefully adds `ArmorKeywords.esm` as a master, that is strange as not anyone has this (I don't). 2. Script still doesn't work (aborts with an error) with the mentioned .esp patches. 3. Without the mentioned .esp patches the script works (after removing `ArmorKeywords.esm` from the custom masters). Edited December 16, 2025 by iampumpkin
iampumpkin Posted December 16, 2025 Posted December 16, 2025 I tried to add more debug logging into the script and it turns out that when the function `AddKeywordToArmor(e, sKeywords);` is called the `e` is actually absolutely incorrect record. Not even `ARMO` record, but `AVIF` from `Fallout4.esm` with FormID=00000375. While it should be `ARMO` record with FormID=FE04A375 from `VTAW 68 Raiders.esp`. So, it looks like the script incorrectly identifies the record that should be modified. But only in some specific cases. Maybe it is realted to ESL record compaction, I don't know. Didn't investigate further. The INI file says: filterByArmors=VTAW 68 Raiders.esp|000375 But the actual FormID is not 00000375, but FE04A375 because FE04A is a prefix assigned to `VTAW 68 Raiders.esp` in my current load order. Maybe script doesn't take this into account. The output of the script with more debug logging added (just for the reference): [SAKR] INFO - MATCH FOUND for VTAW 68 Raiders.esp|00000375 : SkimpyArmorKeywordResource.esm|00000803 [SAKR] INFO - Creating Keyword Array (KWDA) [SAKR] ERROR - Failed to create KWDA for AvailableCondition3 [AVIF:00000375] (AvailableCondition3) [SAKR] ERROR - Exception details: AvailableCondition3 [AVIF:00000375] can not be edited [SAKR] ERROR - Exception class: Exception [SAKR] ERROR - Record state: Master=True, Override=False, Winning=True [SAKR] ERROR - Record file: Fallout4.esm [SAKR] ERROR - Keywords to add: SkimpyArmorKeywordResource.esm|00000803 [SAKR] ERROR - VMAD exists: False [02:40] Exception in unit SAKR_Direct_Injection line 1115: [Exception] AvailableCondition3 [AVIF:00000375] can not be edited [02:40] Aborted: Applying script "Fallout4 - SAKR Direct Injection v1.0.0b3.1"
msmfoster Posted December 16, 2025 Author Posted December 16, 2025 1 hour ago, iampumpkin said: I tried to add more debug logging into the script and it turns out that when the function `AddKeywordToArmor(e, sKeywords);` is called the `e` is actually absolutely incorrect record. Not even `ARMO` record, but `AVIF` from `Fallout4.esm` with FormID=00000375. While it should be `ARMO` record with FormID=FE04A375 from `VTAW 68 Raiders.esp`. So, it looks like the script incorrectly identifies the record that should be modified. But only in some specific cases. Maybe it is realted to ESL record compaction, I don't know. Didn't investigate further. The INI file says: filterByArmors=VTAW 68 Raiders.esp|000375 But the actual FormID is not 00000375, but FE04A375 because FE04A is a prefix assigned to `VTAW 68 Raiders.esp` in my current load order. Maybe script doesn't take this into account. The output of the script with more debug logging added (just for the reference): [SAKR] INFO - MATCH FOUND for VTAW 68 Raiders.esp|00000375 : SkimpyArmorKeywordResource.esm|00000803 [SAKR] INFO - Creating Keyword Array (KWDA) [SAKR] ERROR - Failed to create KWDA for AvailableCondition3 [AVIF:00000375] (AvailableCondition3) [SAKR] ERROR - Exception details: AvailableCondition3 [AVIF:00000375] can not be edited [SAKR] ERROR - Exception class: Exception [SAKR] ERROR - Record state: Master=True, Override=False, Winning=True [SAKR] ERROR - Record file: Fallout4.esm [SAKR] ERROR - Keywords to add: SkimpyArmorKeywordResource.esm|00000803 [SAKR] ERROR - VMAD exists: False [02:40] Exception in unit SAKR_Direct_Injection line 1115: [Exception] AvailableCondition3 [AVIF:00000375] can not be edited [02:40] Aborted: Applying script "Fallout4 - SAKR Direct Injection v1.0.0b3.1" I'll take a look. I added ArmorKeywords by default because I was under the impression that xEdit would ignore invalid entries. Clearly it does not, so easy enough to side step and keep going. I could also wrap it up in a try just to make it fail gracefully (which was my attempt). When I went to the Nexus mod that provides previews I could not find one for VTAW 68. However, all of the others worked without issue. I'll look into the rest. However, when you got it to patch (without the actual trigger), the overrides were correct?
msmfoster Posted December 16, 2025 Author Posted December 16, 2025 1 hour ago, iampumpkin said: I tried to add more debug logging into the script and it turns out that when the function `AddKeywordToArmor(e, sKeywords);` is called the `e` is actually absolutely incorrect record. Not even `ARMO` record, but `AVIF` from `Fallout4.esm` with FormID=00000375. While it should be `ARMO` record with FormID=FE04A375 from `VTAW 68 Raiders.esp`. So, it looks like the script incorrectly identifies the record that should be modified. But only in some specific cases. Maybe it is realted to ESL record compaction, I don't know. Didn't investigate further. The INI file says: filterByArmors=VTAW 68 Raiders.esp|000375 But the actual FormID is not 00000375, but FE04A375 because FE04A is a prefix assigned to `VTAW 68 Raiders.esp` in my current load order. Maybe script doesn't take this into account. The output of the script with more debug logging added (just for the reference): [SAKR] INFO - MATCH FOUND for VTAW 68 Raiders.esp|00000375 : SkimpyArmorKeywordResource.esm|00000803 [SAKR] INFO - Creating Keyword Array (KWDA) [SAKR] ERROR - Failed to create KWDA for AvailableCondition3 [AVIF:00000375] (AvailableCondition3) [SAKR] ERROR - Exception details: AvailableCondition3 [AVIF:00000375] can not be edited [SAKR] ERROR - Exception class: Exception [SAKR] ERROR - Record state: Master=True, Override=False, Winning=True [SAKR] ERROR - Record file: Fallout4.esm [SAKR] ERROR - Keywords to add: SkimpyArmorKeywordResource.esm|00000803 [SAKR] ERROR - VMAD exists: False [02:40] Exception in unit SAKR_Direct_Injection line 1115: [Exception] AvailableCondition3 [AVIF:00000375] can not be edited [02:40] Aborted: Applying script "Fallout4 - SAKR Direct Injection v1.0.0b3.1" Something to look into. To be fair, the script does not choose the winning override, xEdit does. Still, I have something to work with and see if we can find a workaround.
iampumpkin Posted December 16, 2025 Posted December 16, 2025 (edited) I found the culprit of the issue: // Search ONLY in the patch file — never create in source mods existingOverride := RecordByFormID(cPatchFile, patchedFormID, False); This code doesn't work as expected. It doesn't return a record in `ZZZ_SAKR_Direct_Injection.esp` file. It returns a record from one of the masters of `ZZZ_SAKR_Direct_Injection.esp`. In most of the cases the master with index `patchedFormID` doesn't contain a specified formID, so, most of the times `existingOverride` is `nil`, but sometimes it happens that the master with given index really contains a record with the same formID (usually it is a totally different record!), and then this function returns this record (from the master). And then the script tries to add keywords to this record. The logic is incorrect. I think I found another way to check if existing override already exists. Still invetigating the issue. Will post it later. Edited December 16, 2025 by iampumpkin
iampumpkin Posted December 17, 2025 Posted December 17, 2025 (edited) So, ok, the idea is to not use `RecordByFormID` at all, and instead to check for existing override in `ZZZ_SAKR_Direct_Injection.esp` by using already found `TrueWinner` override. If `TrueWinner` record is in `ZZZ_SAKR_Direct_Injection.esp` then it is already the existing override. Otherwise we copy `TrueWinner` as an override into `ZZZ_SAKR_Direct_Injection.esp`. I.e. in `SafeCopy` function: bTrueWinnerIsExistingOverride := GetFileName(GetFile(TrueWinner)) = GetFileName(cPatchFile); LogMessage('DEBUG <P-7.3>', DEBUG_PATHING); // Reuse existing override if we already made one (prevents duplicates across runs) if bTrueWinnerIsExistingOverride then begin // Log and return result LogMessage('VERBOSE - Found existing override for: ' + sFormID, DEBUG_VERBOSE); Result := TrueWinner; Exit; end; The full code of the updated `SafeCopy` function: function SafeCopy(originalRecord: IInterface; const sFormID: String): IInterface; var patchedFormID: LongWord; TrueWinner: IInterface; sErrorMessage, sPluginName: String; iPos, iLoadOrder: Integer; bTrueWinnerIsExistingOverride: boolean; begin // Assume failure Result := nil; LogMessage('DEBUG <P-7.1>', DEBUG_PATHING); // One of the few cases where we run DRYRRUN this way if bDRYRUN then begin LogMessage('INFO - [DRY RUN] Would create override for: ' + sFormID, DEBUG_INFO); Result := originalRecord; Exit; end; LogMessage('DEBUG <P-7.2>', DEBUG_PATHING); // What we need is the highest level override TrueWinner := WinningOverride(originalRecord); if not Assigned(TrueWinner) then begin LogMessage('DEBUG - WinningOverride failed for ' + sFormID, DEBUG_ERROR); Exit; end; bTrueWinnerIsExistingOverride := GetFileName(GetFile(TrueWinner)) = GetFileName(cPatchFile); LogMessage('DEBUG <P-7.3>', DEBUG_PATHING); // Reuse existing override if we already made one (prevents duplicates across runs) if bTrueWinnerIsExistingOverride then begin // Log and return result LogMessage('VERBOSE - Found existing override for: ' + sFormID, DEBUG_VERBOSE); Result := TrueWinner; Exit; end; LogMessage('DEBUG <P-7.4>', DEBUG_PATHING); // Capture potential errors // Create new thin override in patch file // In this mode we simply let the script fail, immediatly alerts the user that something is wrong if bHARDFAIL then begin LogMessage('DEBUG <P-7.4.1>', DEBUG_PATHING); // This will fail hard if exception is returned Result := wbCopyElementToFile(TrueWinner, cPatchFile, False, True); end // In this mode we log it else begin try LogMessage('DEBUG <P-7.4.3>', DEBUG_PATHING); Result := wbCopyElementToFile(TrueWinner, cPatchFile, False, True); except on E: Exception do begin LogMessage('DEBUG <P-7.4.4>', DEBUG_PATHING); // Track amount of soft failures Inc(iSoftFails); // Any other error — just log it cleanly LogMessage('WARN - wbCopyElementToFile failed for: ' + sFormID + ' | Error: ' + E.Message, DEBUG_WARN); end; end; end; // Something went wrong if not Assigned(Result) then LogMessage('ERROR - wbCopyElementToFile failed for: ' + sFormID, DEBUG_ERROR); end; Tried it and it worked like a charm. No errors anymore. But I never seen in the logs a case when existing override was actually found and reused. I even tried to add 2 INI rows adding 2 different keywords to the same record. Still, only the last one was added. I believe the implementation of `SafeCopy` is correct now, but the problem lies in a different part of the script, where INI files are read and parsed. Probably the last found INI row for the same ESP record wins. But they should be merged instead. E.g. filterByArmors=VTAW 68 Raiders.esp|000004:keywordsToAdd=SkimpyArmorKeywordResource.esm|00080A filterByArmors=VTAW 68 Raiders.esp|000004:keywordsToAdd=SkimpyArmorKeywordResource.esm|00080C This should add both `00080A` and `00080C` keywords, but only `00080C` is actually added. Edited December 17, 2025 by iampumpkin 1
msmfoster Posted December 17, 2025 Author Posted December 17, 2025 1 hour ago, iampumpkin said: So, ok, the idea is to not use `RecordByFormID` at all, and instead to check for existing override in `ZZZ_SAKR_Direct_Injection.esp` by using already found `TrueWinner` override. If `TrueWinner` record is in `ZZZ_SAKR_Direct_Injection.esp` then it is already the existing override. Otherwise we copy `TrueWinner` as an override into `ZZZ_SAKR_Direct_Injection.esp`. I.e. in `SafeCopy` function: bTrueWinnerIsExistingOverride := GetFileName(GetFile(TrueWinner)) = GetFileName(cPatchFile); LogMessage('DEBUG <P-7.3>', DEBUG_PATHING); // Reuse existing override if we already made one (prevents duplicates across runs) if bTrueWinnerIsExistingOverride then begin // Log and return result LogMessage('VERBOSE - Found existing override for: ' + sFormID, DEBUG_VERBOSE); Result := TrueWinner; Exit; end; The full code of the updated `SafeCopy` function: function SafeCopy(originalRecord: IInterface; const sFormID: String): IInterface; var patchedFormID: LongWord; TrueWinner: IInterface; sErrorMessage, sPluginName: String; iPos, iLoadOrder: Integer; bTrueWinnerIsExistingOverride: boolean; begin // Assume failure Result := nil; LogMessage('DEBUG <P-7.1>', DEBUG_PATHING); // One of the few cases where we run DRYRRUN this way if bDRYRUN then begin LogMessage('INFO - [DRY RUN] Would create override for: ' + sFormID, DEBUG_INFO); Result := originalRecord; Exit; end; LogMessage('DEBUG <P-7.2>', DEBUG_PATHING); // What we need is the highest level override TrueWinner := WinningOverride(originalRecord); if not Assigned(TrueWinner) then begin LogMessage('DEBUG - WinningOverride failed for ' + sFormID, DEBUG_ERROR); Exit; end; bTrueWinnerIsExistingOverride := GetFileName(GetFile(TrueWinner)) = GetFileName(cPatchFile); LogMessage('DEBUG <P-7.3>', DEBUG_PATHING); // Reuse existing override if we already made one (prevents duplicates across runs) if bTrueWinnerIsExistingOverride then begin // Log and return result LogMessage('VERBOSE - Found existing override for: ' + sFormID, DEBUG_VERBOSE); Result := TrueWinner; Exit; end; LogMessage('DEBUG <P-7.4>', DEBUG_PATHING); // Capture potential errors // Create new thin override in patch file // In this mode we simply let the script fail, immediatly alerts the user that something is wrong if bHARDFAIL then begin LogMessage('DEBUG <P-7.4.1>', DEBUG_PATHING); // This will fail hard if exception is returned Result := wbCopyElementToFile(TrueWinner, cPatchFile, False, True); end // In this mode we log it else begin try LogMessage('DEBUG <P-7.4.3>', DEBUG_PATHING); Result := wbCopyElementToFile(TrueWinner, cPatchFile, False, True); except on E: Exception do begin LogMessage('DEBUG <P-7.4.4>', DEBUG_PATHING); // Track amount of soft failures Inc(iSoftFails); // Any other error — just log it cleanly LogMessage('WARN - wbCopyElementToFile failed for: ' + sFormID + ' | Error: ' + E.Message, DEBUG_WARN); end; end; end; // Something went wrong if not Assigned(Result) then LogMessage('ERROR - wbCopyElementToFile failed for: ' + sFormID, DEBUG_ERROR); end; Tried it and it worked like a charm. No errors anymore. But I never seen in the logs a case when existing override was actually found and reused. I even tried to add 2 INI rows adding 2 different keywords to the same record. Still, only the last one was added. I believe the implementation of `SafeCopy` is correct now, but the problem lies in a different part of the script, where INI files are read and parsed. Probably the last found INI row for the same ESP record wins. But they should be merged instead. E.g. filterByArmors=VTAW 68 Raiders.esp|000004:keywordsToAdd=SkimpyArmorKeywordResource.esm|00080A filterByArmors=VTAW 68 Raiders.esp|000004:keywordsToAdd=SkimpyArmorKeywordResource.esm|00080C This should add both `00080A` and `00080C` keywords, but only `00080C` is actually added. That's wonderful! Thank you. I was working on some code and you nailed it in a much more elegant fashion. No trouble with attributing you for the code fix in the changelog? That behaviour is not unexpected, when I build the keywords we don't allow duplicates. Current methods drop additional keyword attempts, whereas we should offer the option of dropping, overriding, or merging. Reason being if you have multiple SAKR repositories dropped in. You may not want merged records because you'll end up with competing elements (Eli's Armor Compendium vs the CCO equivalent), override and drop have unexpected results. Thoughts?
iampumpkin Posted December 17, 2025 Posted December 17, 2025 (edited) 8 hours ago, msmfoster said: No trouble with attributing you for the code fix in the changelog? No problem. But it's not very important to me. It was interesting problem to solve. 8 hours ago, msmfoster said: That behaviour is not unexpected, when I build the keywords we don't allow duplicates. I didn't investigate too deep the code that does it, and I also not really know Pascal, but from what I seen it uses 2 parallel lists and marks them as "no duplicates", but I'm not sure if this actually works because according to the docs (https://www.freepascal.org/docs-html/rtl/classes/tstringlist.duplicates.html ) Quote If the stringlist is not sorted, the Duplicates setting is ignored. And if I seen correctly, these lists are NOT sorted in the script. Which is actually good, because otherwise they would not work as a hashmap emulation. So, I believe the duplicates are actually not ignored by the script when the lists are built (I could be wrong though, as I didn't investigate it carefully), but the last key/value pair still wins (maybe later the script blacklists already seen keys, need to check it). 8 hours ago, msmfoster said: Current methods drop additional keyword attempts, whereas we should offer the option of dropping, overriding, or merging. Reason being if you have multiple SAKR repositories dropped in. You may not want merged records because you'll end up with competing elements (Eli's Armor Compendium vs the CCO equivalent), override and drop have unexpected results. It would be interesting to know what the actual Robco Patcher does if it sees the same `filterByArmors` key with different `keywordsToAdd`. I think the most correct behaviour of the script would be to imitate the Robco Patcher logic. Honestly I don't see the problem with merging. For the "Eli's Armor Compendium vs the CCO equivalent" example the keys will be different for both new items and existing vanilla items because .ESP prefix will be different even if formID will be identical. On the other hand, if you drop 2 different INIs adding keywords to the same `.esp|formId` key, why not add both keywords to the item? What can be bad about it? Anyway, what is the alternative? Either merge or ignore one of the INI rows. And if ignore, then which one? First or second? From the user's point of view both options would be surprising because it will look like a random choice. So, I'm for mimicking Robco Patcher logic or just merging them. Probably with logging a warning message notifying the user about the fact that more than one rows for the same ARMO item are found in their INIs (preferably with the both INIs file names and row numbers in them). Edited December 17, 2025 by iampumpkin
msmfoster Posted December 17, 2025 Author Posted December 17, 2025 10 hours ago, iampumpkin said: No problem. But it's not very important to me. It was interesting problem to solve. I didn't investigate too deep the code that does it, and I also not really know Pascal, but from what I seen it uses 2 parallel lists and marks them as "no duplicates", but I'm not sure if this actually works because according to the docs (https://www.freepascal.org/docs-html/rtl/classes/tstringlist.duplicates.html ) And if I seen correctly, these lists are NOT sorted in the script. Which is actually good, because otherwise they would not work as a hashmap emulation. So, I believe the duplicates are actually not ignored by the script when the lists are built (I could be wrong though, as I didn't investigate it carefully), but the last key/value pair still wins (maybe later the script blacklists already seen keys, need to check it). It would be interesting to know what the actual Robco Patcher does if it sees the same `filterByArmors` key with different `keywordsToAdd`. I think the most correct behaviour of the script would be to imitate the Robco Patcher logic. Honestly I don't see the problem with merging. For the "Eli's Armor Compendium vs the CCO equivalent" example the keys will be different for both new items and existing vanilla items because .ESP prefix will be different even if formID will be identical. On the other hand, if you drop 2 different INIs adding keywords to the same `.esp|formId` key, why not add both keywords to the item? What can be bad about it? Anyway, what is the alternative? Either merge or ignore one of the INI rows. And if ignore, then which one? First or second? From the user's point of view both options would be surprising because it will look like a random choice. So, I'm for mimicking Robco Patcher logic or just merging them. Probably with logging a warning message notifying the user about the fact that more than one rows for the same ARMO item are found in their INIs (preferably with the both INIs file names and row numbers in them). The current version does first in gets injected and this was somewhat by mistake, as in that enforcement was being done in the wrong location. I since changed the script to check for duplicates properly, or merge the results together. This is the entry from my ReadMe file: If bMERGE is set to True the script will merge the conflicts together into one line. However, there are potential risks. A perfect example is Eli's Armour Compendium and Classy Chassis Outfits - Eli's Armour Replacer. The former includes lore friendly and non-lewd clothing items, whereas the latter will change things up. They both use Eli_Armour_Compendium.esp and identifier leading to the following situation where an item now has keywords for: 0000081A. Top Full 0000081E. Tank Top 00000821. Top Tight 0000080E. Pants Long 0000080F. Pants Shorts The above contains clearly contains keywords that are at odds with each other and should not co-exist. The resulting score will be wildly off from expected behaviour. Merge mode is provided for advanced users who understand the risks.
iampumpkin Posted December 18, 2025 Posted December 18, 2025 Ah, I see. Didn't know they both use `Eli_Armour_Compendium.esp`. Then yes, merge can lead to strange results. On the other hand, what alternative do we have? Just ignore the conflicting records? But then, which one to ignore? 1st one or the 2nd one? Probably, the script should report in the logs the ignored records, or even merged records (if bMERGE is true), because they are still conflicting (intentionally or not) and user should be aware that there is a potential error in the INIs. It is similar to WARNs the script shows for unrecognized rules in the INI files. They are not necessary malformed. They are either malformed or just not supported by the script (while still supported by RobcoPatcher). The script shows WARNs for such INI rules and it is totally fine. Not an error, but a potential error that user should pay attention to. E.g. these warnings: [SAKR] INFO - Parsing SAKR config: C:\Games\Fallout 4 GOTY\Data\F4SE\Plugins\RobCo_Patcher\armor\LCC\lcc.ini [SAKR] WARNING - Malformed line (no :keywordsToAdd=): filterByArmors=Deviously Cursed Wasteland.esp|D59A3:bipedSlotsToRemove=6 [SAKR] WARNING - Malformed line (no :keywordsToAdd=): filterByArmors=FO4_Basics.esp|180CD3:bipedSlotsToRemove=11 It is fine because script doesn't support `bipedSlotsToRemove` operation. But it is also a signal that I should probably keep `lcc.ini` when game starts to allow RobcoPatcher to apply it. So, yeah, a similar warning for duplicated keys in .INI would be good.
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now