Skip to content

[dev] CBash vs PBash

Infernio edited this page Dec 14, 2020 · 7 revisions

Note: As of #530, CBash has been removed. This page mostly serves as a historical document now.

A rundown of differences of the two patchers for Oblivion (originally by Lojack here).

Fundamentally the way PBash makes a patch is different than how CBash does. PBash reads each mod file in sequential load order. Each patcher knows nothing about what mods come after it, or what comes before. The only thing they remember is what data they cached from previous mod files, so they can do the logic. Here's a perfect example of why PBash can't merge CELL or WRLD records. It would take way way too much memory and processing time to store those records in temporary memory, Python style. Within each mod file, PBash runs through each available patcher, in an order determined by the 'patchOrder' and 'scanOrder' attributes. So each patcher is run in sequential order, passed the relevant records.

CBash, on the other hand, has access to ALL the mod files at once. Each patcher can do a simple check like "is this record winning? if not, just skip processing, cause I don't need the info", or whatever depending on the patcher's specific logic. Not only that, but rather than taking a mod file, and running through each patcher, CBash does things a bit differently here as well (because it needs to, to work correctly). CBash runs through each mod file in order, but from there it deviates. From there it runs through each record type, in a specific order (because order here does matter, specifically for the race patcher). So for example, it will patch all GMST records first, then GLOB, then MGEF, etc etc. Then within each group of records, CBash runs the patchers on those as determined by 'patchOrder' and 'scanOrder'.

And it's not like CBash couldn't be designed to be a drop in exact replacement for PBash, meaning no duplication of code. But, if that was done, CBash wouldn't be as efficient as it is. The end goal has always been to completely replace PBash with CBash, so the PBash code could be removed completely, and only keep somewhere in a deep dark corner for things like new games (Skyrim?). These plans never worked out quite right, but it's a good goal.

If you want to venture more into this, check out classes "PatchFile" and "CBash_PatchFile" in patch_files.py.

Re: long FormIds - originally from DienesToo here

In the CBash source there is a lengthy explanation of FormIDs and CBash handles them. It says they Wrye Bash internally uses an intermediate form of a pair of values it calls a long formID. The name of the mod that the form originates from and the 6 digit hex object ID. So a form in Skyrim.esm with FormID 0x00000800 would be resolved internally in WB to a long formID of ("Skyrim.esm", 0x000800). That way it can track forms from more than 255 plugins at a time and won't lose them if their originating plugin moves in the load order. But when it actually makes the Bashed Patch is returns them to the normal style FormID of an 8 digit hex number. I haven't looked at the actual Wrye Bash code to see if this is still correct but I can't imagine it having changed. The full explanation in CBash starts here.

Clone this wiki locally