[WIPz] CBash (Alpha)

Post » Thu Sep 02, 2010 1:48 am

Well if it is possible to resolve and remove master dependancies. Lets say you want to merge in dlchorse armour AND Unofficial dlc patch, bash shouldn't rely on dlchorsearmour anymore or this merger would obviously be useless. Just my penny for a thought... That way we can merge lets say the entire fcom tree and give all the people that want a single mod file without using bash a single file which they can enable and be done with it.

Basically, if you're merging mod A and mod B that has mod A as a master, the merged mod should no longer depend on the master (mod A), correct? Off hand, this should be easy. I've already planned a master cleaning function that will remove any masters that aren't needed. I haven't started working on the specific merging functions though, so there may be some special cases where it won't work nicely. Dunno yet.

Status Update:
The following record types have been fully exposed since the last update:
  • SBSP
  • SGST
  • WTHR
  • CLMT
  • REGN
This leaves the following for 0.2a:
  • QUST
  • IDLE
  • PACK
  • CSTY
  • LSCR
  • ANIO
  • WATR
  • EFSH
These last few record types have been more time consuming to expose than I originally thought. REGN in particular took up an entire afternoon by itself. I won't have 0.2a ready for release tonight, but it won't take more than a couple extra days.
User avatar
Campbell
 
Posts: 3262
Joined: Tue Jun 05, 2007 8:54 am

Post » Thu Sep 02, 2010 2:18 am

Basically, if you're merging mod A and mod B that has mod A as a master, the merged mod should no longer depend on the master (mod A), correct?


Well in tesGecko that function is called "merge to master" and it works only for a single master. If you merge dlc horsearmour with uodlc patch the dlc horsearmour it will need itself as master. Say you merge all the dlc like this, into one big dlc mod, the single file will depend on all the dlc esp's.
User avatar
Judy Lynch
 
Posts: 3504
Joined: Fri Oct 20, 2006 8:31 am

Post » Wed Sep 01, 2010 10:52 pm

Status Update:

v0.2a http://www.tesnexus.com/downloads/file.php?id=30154 - main post updated.
  • All current record types have been exposed to python.
  • Interface has been split from Test.py into its own file CBashInterface.py

User avatar
Enny Labinjo
 
Posts: 3480
Joined: Tue Aug 01, 2006 3:04 pm

Post » Wed Sep 01, 2010 10:48 am

:goodjob:
User avatar
Invasion's
 
Posts: 3546
Joined: Fri Aug 18, 2006 6:09 pm

Post » Wed Sep 01, 2010 10:26 am

Sweet Gibberin' Jellyfish!

This looks full of great potential. :D Rock on, thou Baron of mad modding.
User avatar
Tyrel
 
Posts: 3304
Joined: Tue Oct 30, 2007 4:52 am

Post » Wed Sep 01, 2010 5:03 pm

I love that you actually have a roadmap laid out for this project. Way to follow the Software Life Cycle! Seriously, this is a great idea and I'm sure as it matures it will become impossible to live without. Keep it up!
User avatar
Kari Depp
 
Posts: 3427
Joined: Wed Aug 23, 2006 3:19 pm

Post » Wed Sep 01, 2010 5:39 pm

Well one of the most exciting utilities for oblivion coming right here. If you get the merging system perfected that is. It would really clean out modlists! I can't wait until this is finished and merged into bash. It would even be a nice idea (which makes some sense) to seperate the modfiles from oblivion tree and place them in a different directory all together since the engine is fond of scanning oblivion's directories for esp's and bsa's. And it would tidy up the data directory pretty much.

Well success and kudo's for this. Hope we can see this in action soon!
User avatar
Philip Rua
 
Posts: 3348
Joined: Sun May 06, 2007 11:53 am

Post » Thu Sep 02, 2010 12:13 am

Thanks for all the encouragement :bigsmile:

I love that you actually have a roadmap laid out for this project. Way to follow the Software Life Cycle! Seriously, this is a great idea and I'm sure as it matures it will become impossible to live without. Keep it up!

Heh, the main reason I put that up is to keep me from being sidetracked. I have a bad habit of premature optimization and switching to whatever part of the program happens to catch my eye...

That, and it keeps people from wondering/asking when the major features will/should work.
Well one of the most exciting utilities for oblivion coming right here. If you get the merging system perfected that is. It would really clean out modlists! I can't wait until this is finished and merged into bash. It would even be a nice idea (which makes some sense) to seperate the modfiles from oblivion tree and place them in a different directory all together since the engine is fond of scanning oblivion's directories for esp's and bsa's. And it would tidy up the data directory pretty much.

Well success and kudo's for this. Hope we can see this in action soon!

Right now, the main problems I see with 'perfect' merging comes from conflicting LAND / ROAD / PGRD record fields in CELL / WRLD records. I can easily replace one with the other (last one loaded wins), but they're too complicated to merge at a finer level (such as merging level lists). So there will always be some element of load order / merging order that will come into play.

The main problem with moving esps/esms out of the data folder is expectations. People are accustomed, and expect to put mod files there. There is also the issue of bsas that require the appropriately named mod in order for them to be loaded (though this can be worked around). I may add support for an alternative directory, but if I do, it'll be disabled by default and only for the more advanced users.

It's near the top of my priority list for new features, but merging will have to wait until I finish implementing the rest of the records. I'll have more to say when I've actually played with it.

Speaking of which...

Status Update:
DIAL and related subrecords have been supported and exposed.

CELL and WRLD should be faster/easier to implement now that I have the groundwork done for supporting subrecords. v0.3a will probably be out this weekend.
User avatar
Rinceoir
 
Posts: 3407
Joined: Thu Jun 29, 2006 1:54 am

Post » Wed Sep 01, 2010 11:42 pm

The main problem with moving esps/esms out of the data folder is expectations. People are accustomed, and expect to put mod files there. There is also the issue of bsas that require the appropriately named mod in order for them to be loaded (though this can be worked around). I may add support for an alternative directory, but if I do, it'll be disabled by default and only for the more advanced users.


Well i was thinking.. Ghosting does pretty much the same. But keeps the esp's inside data folder. In oblivion Mod manager you have the option to move the mod folder and the temp folder. you can move them out of the oblivion tree. But if such a option would be implemented it could be implemented just like ghosting. Renaming the bsa's to "bashed patch,0 - example.bsa"; and moving their respective esp's to a folder of choice.

Anyways, this is just esthetical since ghosting pretty much eliminates the engines bug of reading all the esp's even if they'r not activated. So it's not that important.
User avatar
Emma Louise Adams
 
Posts: 3527
Joined: Wed Jun 28, 2006 4:15 pm

Post » Wed Sep 01, 2010 11:27 am

Reading about merging LAND records I doubt it's doable either, maybe fine tune the merging to quadrants of a LAND record may be possible though(compare each quadrant to vanilla maybe and then merge if 2 mods don't change the same quadrant).

What would be interesting is a check to avoid land tearing if there is a conflict(or even if there is a LAND modification).
It would be relatively simple to adjust the borders of the heightmap to replicate the border values for the adjacent cells heightmaps.

edit:
It might produce VERY sharp terrain if the change of height is big but at least there will not be any tearing :).
User avatar
Trevi
 
Posts: 3404
Joined: Fri Apr 06, 2007 8:26 pm

Post » Thu Sep 02, 2010 12:25 am

What would be interesting is a check to avoid land tearing if there is a conflict(or even if there is a LAND modification).
It would be relatively simple to adjust the borders of the heightmap to replicate the border values for the adjacent cells heightmaps.

edit:
It might produce VERY sharp terrain if the change of height is big but at least there will not be any tearing :).


This is something Elminster had planned for TES4Edit but never got around to producing. You'd want to set it so that land tears get repaired ONLY if the height discrepancy on each side was within a certain small amount, otherwise as you say you'd get some sharp terrain edges.
User avatar
Johanna Van Drunick
 
Posts: 3437
Joined: Tue Jun 20, 2006 11:40 am

Post » Thu Sep 02, 2010 12:36 am

I think we found one of the Monkey Gods lost children :celebrate: (I consider PacificMorrowind one of the run away kids as well)

You want a banana to speed up the progress a bit? :bowdown:
User avatar
TOYA toys
 
Posts: 3455
Joined: Sat Jan 13, 2007 4:22 am

Post » Wed Sep 01, 2010 3:37 pm

I think we found one of the Monkey Gods lost children :celebrate: (I consider PacificMorrowind one of the run away kids as well)

You want a banana to speed up the progress a bit? :bowdown:

LOL, classic quote! This really should be in some bodies signature... I'm just now getting around to checking out this tool. I really like the idea of speeding up bash patching! Will test this out as well. Hopefully this weekend, or whenever I get unnerved with my current bash patching wait time.
User avatar
Jade Payton
 
Posts: 3417
Joined: Mon Sep 11, 2006 1:01 pm

Post » Thu Sep 02, 2010 2:09 am

I don't know that encouragement from me will prove of any help to you, Waruddar. What you are doing is way over my head. But I have been around here long enough to know that when certain members of the community are showing interest in a new development, it is indeed significant. So..........My thanks for your efforts. :)
User avatar
Melanie
 
Posts: 3448
Joined: Tue Dec 26, 2006 4:54 pm

Post » Thu Sep 02, 2010 2:29 am

RE:LAND Records

Interesting discussion. When I get to merging, I'll take a stab at both quadrant merging and smoothing land tears. I'll probably ask someone to make me a test case at that time since I've never messed with land records in the CS. Or, maybe I'll learn. :shrug:
I think we found one of the Monkey Gods lost children :celebrate: (I consider PacificMorrowind one of the run away kids as well)

You want a banana to speed up the progress a bit? :bowdown:

A bribe? :liplick:

Still on track for a weekend release. Can't work much faster atm; family came down with the flu, and I'm having to keep 'em comfortable while dodging the germs.
LOL, classic quote! This really should be in some bodies signature... I'm just now getting around to checking out this tool. I really like the idea of speeding up bash patching! Will test this out as well. Hopefully this weekend, or whenever I get unnerved with my current bash patching wait time.

Thanks for the interest. Keep in mind, it won't do anything for your bash patching times just yet. Still in alpha (though getting closer to beta).

I don't know that encouragement from me will prove of any help to you, Waruddar. What you are doing is way over my head. But I have been around here long enough to know that when certain members of the community are showing interest in a new development, it is indeed significant. So..........My thanks for your efforts. :)

Encouragement is always welcome! :tops:

Status Update:
The top level CELL and WRLD records are supported and exposed.

I'm working on supporting the subrecords (ACRE, ACHR, REFR, PGRD, ROAD, LAND, VWD group, Persistent group, Temporary group) now. They're pretty much shared between both CELL and WRLD records, so there really isn't too much left to do for the next release.

Edit:
Looking over the first page, it looks as if the new forums are barfing on the codeboxs. I have copies of all the data, so if the posters want to remove the Profile.txt stuff, it'd make the thread cleaner.
User avatar
Doniesha World
 
Posts: 3437
Joined: Sun Jan 07, 2007 5:12 pm

Post » Wed Sep 01, 2010 11:57 am

Status Update:

I've been caught up in a bit of code refactoring that will ultimately affect how I expose the WRLD/CELL sub-records, but all records are now supported (just not exposed to python). I'll get the next release out by Thursday at the latest.

Currently, when CBash fully loads Oblivion.esm for the first time, it takes ~9-15 seconds (depending on disk speed). Since I'm using memory mapping, subsequent loads only take 1-4 seconds (depending on how starved for memory the OS is). I expect to be able to shorten the initial load time at least 1-2 seconds on the lower range and 3-4 seconds on the upper range.

As for the memory footprint, it isn't so pretty atm. CBash uses 617 MB to hold Oblivion.esm in memory. Considering that Oblivion.esm is ~270 MB, this is an unacceptable level of overhead...on the other hand, the only memory optimizations I've done are incidental to the code refactoring. There should be plenty of bytes floating around that I can cull.
User avatar
suniti
 
Posts: 3176
Joined: Mon Sep 25, 2006 4:22 pm

Post » Wed Sep 01, 2010 7:31 pm

i'm so glad ur doing this :)
User avatar
Lisa Robb
 
Posts: 3542
Joined: Mon Nov 27, 2006 9:13 pm

Post » Wed Sep 01, 2010 11:10 am

Well, it's taking longer than I thought (surprise!). I turned up a few annoying bugs that took awhile to smash.

Status Update:
  • CELL records and subrecords have been fully exposed to python.
  • Memory usage has been decreased. Minimal loads of Oblivion.esm now use 199 MB (was 376MB), and Full Loads use 609 MB (was 722MB. It increased from 617MB while bug fixing...). Don't be alarmed by the numbers, they'll continue to decrease. I'm targeting 150MB for minimal loads and 450 MB for full loads.

Next up, exposing WRLD subrecords. Should be one more day.

I'm considering postponing the FO3 support for a couple releases to get some more functionality, performance, and memory fixes in. Basically polish up the Oblivion support so that it can start being used a bit sooner. Any thoughts?
User avatar
Dan Endacott
 
Posts: 3419
Joined: Fri Jul 06, 2007 9:12 am

Post » Wed Sep 01, 2010 11:53 pm

personally i dont give a [censored] about the FO3 version ('cuase i don't have FO3, lol) so i say polish up the oblivion version :P
User avatar
Jacob Phillips
 
Posts: 3430
Joined: Tue Aug 14, 2007 9:46 am

Post » Wed Sep 01, 2010 7:38 pm

Just a quick update, since this latest release is taking so long.

Everything is supported and exposed to python except for LAND records. LAND records are supported internally, but haven't been exposed since I'm still trying to create a friendly interface. For most records, I can simply expose the variables in pretty much the same format as they're read from the esm/esp file.

For example, a piece of armor is saved as an ARMO record, and its script is saved in its SCRI sub-record. It's exposed as "armorObject.script". Very straightforward.

LAND records though are a bit more complicated. They have several sub-records that effectively overlay each other. There's a height-map, a normals-map, a colors-map, and up to 9 alpha layers (including the base layer) that each have an associated texture and (optionally) a list of opacities for each point on the record. The height-map, normals-map, and colors-map are all 33x33 grids of values, but the alpha layers are split into 17x17 grids that are sub-quadrants of the main 33x33 grid. How do four 17x17 grids fit into a 33x33 grid? Their left column and bottom row overlap. On top of that, any of the optional opacities are stored as a position within the 17x17 grid, and aren't directly mapped to the points on the 33x33 grid. Actually though, the 33x33 grid is a 32x32 grid, with its left column and bottom row overlapping the adjacent cell's LAND record. Complicated, but not as complicated as pathgrids and roads...

Then again, it isn't so much complicated as awkward to work with. If I simply expose it as is, it won't be very usable. There would be a lot of unnecessary work/math for anyone trying to manipulate the record. So, I've decided to store it in memory and expose it to python in a different format that it is stored on disk. Basically, I'll be merging all the various maps and quadrants into a single structure, and accessing any point in the grid will give access to all of the data associated with that point. With this, manipulating the record will be a bit easier.

Where cLand is whatever LAND record being looked at, the accessors would look like:
cLand.heightOffsetcLand.Position[x][y].baseTexture (same for all points in the quadrant)cLand.Position[x][y].height (adjusted by the heightOffset)cLand.Position[x][y].normalXcLand.Position[x][y].normalYcLand.Position[x][y].normalZcLand.Position[x][y].redcLand.Position[x][y].greencLand.Position[x][y].bluecLand.Position[x][y].AlphaLayer[z].texture (same for all points in the quadrant)cLand.Position[x][y].AlphaLayer[z].opacity


Otherwise, it'd be something like:
cLand.normals[x][y].xcLand.normals[x][y].ycLand.normals[x][y].zcLand.heightOffsetcLand.heights[x][y].heightcLand.colors[x][y].redcLand.colors[x][y].greencLand.colors[x][y].bluecLand.bottomLeftBaseTexturecLand.bottomLeftAlphaLayers[x].quadrantcLand.bottomLeftAlphaLayers[x].texturecLand.bottomLeftAlphaLayers[x].layercLand.bottomLeftAlphaOpacities[x].positioncLand.bottomLeftAlphaOpacities[x].opacityetc...(repeated for each of the four quadrants)


So, I'm doing more work now so you don't have to later. The next release will occur as soon as I get this LAND record taken care of.

I've also been working on reducing the memory footprint of CBash. It is currently at 593.2 MB during a full load, and 200.5 MB during a minimal load. I've shaved off ~172 MB since I first started measuring memory use, but it's been offset by other increases. It's still ~20MB lower than I last reported. ;)

As a comparison, TES4Edit utilizes 578.7 MB when loading Oblivion.esm. You have to rename Oblivion.esm before loading it in TES4Edit to see this; TES4Edit otherwise uses 302 MB. ElminsterEU treats Oblivion.esm as a special case, and by not allowing it to be changed, he can get the memory usage pretty low (the size of Oblivion.esm on disk + some overhead). I'll probably add a similar feature at some point since it can speed up the processing of esm/esps.

Incidentally, LAND records account for 309.9 MB of the data in Oblivion.esm, which is why they're normally compressed. They compress fairly well since they have a lot of redundant data due to the overlapping arrays. Without considering the overhead of storing the data, 309.9 MB is still over half of the memory that CBash consumes during a full load.

I'll likely treat LAND records as a special case and load them into memory only when needed and unload them as soon as possible. Technically it wouldn't be a full load then, but it would cut the normal full load memory usage down to 283 MB.

Back to this LAND mess...
User avatar
Marine Arrègle
 
Posts: 3423
Joined: Sat Mar 24, 2007 5:19 am

Post » Wed Sep 01, 2010 6:44 pm

Glad to see continued progress. I follow the thread and try (and fail) to understand most of what you're doing. I'd hate to be your manager, because I'd have no idea at all if you working smart or hard or anything. I'd just have to sit back and see results once in a while and say, "I have no idea at all what he does all day. But occassionally he produces something like this! So we keep him." :)

gothemasticator
User avatar
sam
 
Posts: 3386
Joined: Sat Jan 27, 2007 2:44 pm

Post » Wed Sep 01, 2010 4:30 pm

@Waruddar:
I'm not sure how you structured your esm/esp loader(at least haven't looked since v0.2) since it's to give easy access to bash(and I don't know how wrye bash handle things) but I found it easier to structure things like this:
3 basic classes:
CGrup
CRecord
CSubRecord

the CGrup contains 2 vectors, one for CRecord * and one for CGrup *.
The CRecord contains a vector for CSubRecord *.

I also made generic derived class like CSubString and CSubFormID who handles subrecords with just a string or a formID(makes it easier to translate formIDs into a global context but I guess you don't need that).
The CRecord class contain some basic generic record stuff like a GetFormID function and stuff like that.

It also helps with LAND records since I can process the subrecords once I've parsed everything, it will still be in order.
Oh and each LAND is separated into 4 quadrants because there is a limit of 8 textures per quadrant(I think it was to reduce the number of calculations in the shader).
Btw the intensity of the base texture isn't indicated so it's always 1.0f-sum of the others(at least it should be, I noticed some strange too bright texture when doing that, not sure why atm).
Also there are some ATXT a bit everywhere with 0 for the formID, my best guess it that they are to be ignored atm(again I'm not sure).

Also a piece of code to calculate the heights if you're having trouble(it's accurate as far as I could see in my renderer):
void CLand::SetPositionsAndHeights(float offset,char *data){	unsigned long index,index2;	float tabHeight[33][33];	unsigned long colIndex,lineIndex,tempIndex;	tabHeight[0][0]=(offset*SCALEHEIGHT);	for(lineIndex=0;lineIndex<33;lineIndex++)	{		for(colIndex=0;colIndex<33;colIndex++)		{			if(colIndex==0) //First item on a line			{				if(lineIndex!=0) tabHeight[lineIndex][0]+=((data[(lineIndex*33)])*SCALEHEIGHT);				//Propagate north				for(tempIndex=(lineIndex+1);tempIndex<33;tempIndex++)				{					tabHeight[tempIndex][colIndex]=tabHeight[lineIndex][colIndex];				}				//Propagate east				for(tempIndex=1;tempIndex<33;tempIndex++)				{					tabHeight[lineIndex][tempIndex]=tabHeight[lineIndex][colIndex];				}			}			else			{				//Propagate east				tabHeight[lineIndex][colIndex]+=((data[(lineIndex*33)+colIndex])*SCALEHEIGHT);				for(tempIndex=(colIndex+1);tempIndex<33;tempIndex++)				{					tabHeight[lineIndex][tempIndex]=tabHeight[lineIndex][colIndex];				}			}		}	}The rest is of no interest to you since I create 4 vertexbuffers for the renderer.Oh and data is the VHGT raw data.


Hope that helps :).

edit:
Oh and SCALEHEIGHT is a define of mine and should be 8.0f is the size of a cell is 4096.0f.
User avatar
Emily Rose
 
Posts: 3482
Joined: Sat Feb 17, 2007 5:56 pm

Post » Wed Sep 01, 2010 4:35 pm

Always good to see another approach.

Atm, CBash doesn't store the GRUP records at all, and only a portion of the record headers (the recType and size are discarded). I both calculate the sizes and recreate the GRUPs from scratch when writing. I can infer most of the GRUP record from how the data is organized except for the stamp. Since it doesn't normally change, and doesn't have any real effect, I just save a single copy of it in the top group. As I recall, this saves me 20-30 MB. Adds a bit of extra processing when saving the file, but not (subjectively) noticeable. I haven't profiled that yet.

The records are derived from a base record class, and explicitly define the possible sub-records. I thought about using the vector approach with a generic sub-record class since it would reduce the memory usage when sub-records aren't actually used, but then I'd have to search through the vector for the right sub-record every time a variable was accessed. I figured it'd be faster not to mess with it.

A typical record definition looks like:
class MISCRecord : public Record    {    private:        enum MISCRecordFields {            eEDID = 0x44494445,            eFULL = 0x4C4C5546,            eMODL = 0x4C444F4D,            eMODB = 0x42444F4D,            eMODT = 0x54444F4D,            eICON = 0x4E4F4349,            eSCRI = 0x49524353,            eDATA = http://forums.bethsoft.com/index.php?/topic/1078195-wipz-cbash-alpha/0x41544144            };    public:        STRING EDID;        STRING FULL;        GENMODEL MODL;        STRING ICON;        OptRecordField SCRI;        ReqRecordField DATA;        //stripped out constructors, destructor        void ExpandFormIDs(_FormIDHandler &FormIDHandler)            {            if(SCRI.IsLoaded())                FormIDHandler.ExpandFormID(SCRI->fid);            }        void CollapseFormIDs(_FormIDHandler &FormIDHandler)            {            if(SCRI.IsLoaded())                FormIDHandler.CollapseFormID(SCRI->fid);            }    //rest stripped out (various declarations)    };

The enum is mostly book-keeping, but it is used by the loader and saver. Loading the records is handled through switches. I read the record type, size, and then switch off to the appropriate sub-record and have it read in the data.

STRING is a custom string class, barebones and nothing fancy. Barely more than a char *. Has a few utility functions defined (Load, Copy, etc).
GENMODEL is just a group of sub-records; modelpath, boundradius, and texture hashes.
GENFID is just a POD with an unsigned int in it. Doesn't do anything special, just signifies that it is indeed a formID.
GENVALUEWEIGHT is just a POD with a value and weight field. It's a generic field present in a lot of different records, so it's defined in the same file as the base record.

OptRecordField is simply a template that acts as a fairly dumb smart pointer, and adds basic read functions to the encapsulated POD. It only loads the data specified if the record is used. Saves memory on larger sub-records, not so much on a simple formID sub-record. Handles allocation / deallocation on its own.
ReqRecordField adds the same basic functions to the POD, but it loads the default data regardless. These fields are ~99% always present, so it makes no sense to not load it. There would just be additional overhead of having to store a pointer and allocating more memory on the heap.


I handle all the formID junk through a FormIDHandler object associated with each modFile. Sadly, I do have to translate the formIDs into the global context in order to handle conflict detection and back down again to save a file. Since formIDs sometimes appear in the middle of other data, each record definition is responsible for saying where formIDs might be found. I expand each formID immediately after the record is read, and only work with expanded formIDs in memory. I then collapse them back into a writable state just before saving the file. Can't do automated conflict resolution (a bashed patch) if you don't know what's conflicting ;)

Speaking of formIDs, you may want to see how I handle it. I spent a good bit of time tweaking it to quickly expand / collapse since every record has one or more to handle. I remember reading that you had some issues with malformed formIDs, but CBash handles them correctly. If the modIndex of the formID exceeds what's defined in the MAST sub-record, that formID belongs to the mod and not any of the masters. I know Oblivion.esm has more than one instance of that happening.

First, after setting the load order and reading the TES4 record:
void _FormIDHandler::UpdateFormIDLookup()    {    //Each ModFile maintains a formID resolution lookup table of valid modIndexs    //both when expanded into a load order corrected format    //and for when collapsed back into a writable format    //This function populates that table, and allows much, much faster formID resolution    //which occurs on every formID that is read, and written...    unsigned char numMods = (unsigned char)LoadOrder.size();    char *curMaster = NULL;    CollapsedIndex = (unsigned char)MAST.size();    for(unsigned int y = 0; y < numMods; ++y)        if(_stricmp(LoadOrder[y], FileName) == 0)            {            ExpandedIndex = y;            break;            }    for(unsigned char p = 0; p < 255; ++p)        {        CollapseIndex[p] = CollapsedIndex;        ExpandIndex[p] = ExpandedIndex;        }    for(unsigned char p = 0; p < CollapsedIndex; ++p)        {        curMaster = MAST[p].value;        for(unsigned char y = 0; y < numMods; ++y)            if(_stricmp(LoadOrder[y], curMaster) == 0)                {                ExpandIndex[p] = y;                CollapseIndex[y] = p;                break;                }        }    return;    }

It only runs when the mod is first loaded, or the load order changes.

Then, expanding or collapsing a formID is simply:
void _FormIDHandler::ExpandFormID(unsigned int &curFormID)    {    if(curFormID == 0)        return;    curFormID = (ExpandIndex[curFormID >> 24] << 24 ) | (curFormID & 0x00FFFFFF);    return;    }void _FormIDHandler::CollapseFormID(unsigned int &curFormID)    {    if(curFormID == 0)        return;    curFormID = (CollapseIndex[curFormID >> 24] << 24 ) | (curFormID & 0x00FFFFFF);    return;    }

User avatar
Tiffany Carter
 
Posts: 3454
Joined: Wed Jul 19, 2006 4:05 am

Post » Wed Sep 01, 2010 2:17 pm

Speaking of formIDs, you may want to see how I handle it. I spent a good bit of time tweaking it to quickly expand / collapse since every record has one or more to handle. I remember reading that you had some issues with malformed formIDs, but CBash handles them correctly. If the modIndex of the formID exceeds what's defined in the MAST sub-record, that formID belongs to the mod and not any of the masters. I know Oblivion.esm has more than one instance of that happening.


Hmm I see what you did there for the formID, I basically do the same except I use a vector(yes I know I'm addicted to those :P) to store what you call the "expandedindex" formids and only do it 1 way(since my patch requires everything to be loaded atm, even things it doesn't change).

I guess I should remplace that error message "FormID out of range" with setting the high byte to the current mod global index then(and while at it, probably change to your method with a 256 value table, more efficient) :).

As for the grup I keep them as it helps finding quickly a cell based on coordinates(which in my program helped to go from 3 minutes to fix the heightmaps to barely a few seconds) and also helps to find the records associated with a cell(LAND in particular in this case). I have a little optimisation step after reading all the mods where I link every grup(in the WRLD grup since I read only that one) with its WRLD/CELL record to speed up everything afterward.

Talking about the grup timestamp, does it actually have any effect or is it purely esthetical so to speak?
User avatar
Cat Haines
 
Posts: 3385
Joined: Fri Oct 27, 2006 9:27 am

Post » Wed Sep 01, 2010 1:15 pm

Hmm I see what you did there for the formID, I basically do the same except I use a vector(yes I know I'm addicted to those :P) to store what you call the "expandedindex" formids and only do it 1 way(since my patch requires everything to be loaded atm, even things it doesn't change).

I guess I should remplace that error message "FormID out of range" with setting the high byte to the current mod global index then(and while at it, probably change to your method with a 256 value table, more efficient) :).

As for the grup I keep them as it helps finding quickly a cell based on coordinates(which in my program helped to go from 3 minutes to fix the heightmaps to barely a few seconds) and also helps to find the records associated with a cell(LAND in particular in this case). I have a little optimisation step after reading all the mods where I link every grup(in the WRLD grup since I read only that one) with its WRLD/CELL record to speed up everything afterward.

Talking about the grup timestamp, does it actually have any effect or is it purely esthetical so to speak?

Yeah, CBash doesn't really have to look up cells by coord's since it does everything by formID lookups. GRUP's have a good purpose, CBash just doesn't really need them for what it does.

I only use a 255 value table (0x00 - 0xFE) since I'm fairly sure that the 0xFF index is reserved for the saved game data. Bash does a little bit of work with saved games, so I didn't want to impinge on adding saved game support at some point in the very distant future.

I've never seen, nor heard of any effect of the grup timestamp. I imagine it was used in version control of some sort, and isn't really all that relevant. I've heard of tests that were done that set it to some random value and no apparent effects were seen in game, but that's complete hearsay. I only keep it around for consistency's sake.
User avatar
Courtney Foren
 
Posts: 3418
Joined: Sun Mar 11, 2007 6:49 am

PreviousNext

Return to IV - Oblivion