PackedSheets

Version 1 (kervala, 09/29/2010 09:52 pm)

1 1 kervala
h1. Packed Sheets
2 1 kervala
3 1 kervala
h2. Summary
4 1 kervala
5 1 kervala
A packed sheet is a way of storing multiple Georges sheets in a binary format. What a packed sheet does is load all of the sheets/forms into a single binary file that can be serialized by a loader that can automatically populate the proper data. It also will update the packed sheet (if informed to) to either create a new packed sheet (if one does not already exist) or add new entries to a packed sheet.
6 1 kervala
7 1 kervala
h2. Process of Loading
8 1 kervala
9 1 kervala
For packed sheets, you must declare a class that will be used by the form packer:
10 1 kervala
11 1 kervala
1 - Create a class (or struct) that is needed to conform to the following interface:
12 1 kervala
13 1 kervala
<pre><code class="CPP">
14 1 kervala
struct TMyLoader
15 1 kervala
{
16 1 kervala
     /**
17 1 kervala
      * \brief Here you read in the form if necessary, storing it in members of the TMyLoader class
18 1 kervala
      */
19 1 kervala
     void readGeorges (const NLMISC::CSmartPtr<NLGEORGES::UForm> &form, const NLMISC::CSheetId &sheetId);
20 1 kervala
21 1 kervala
     /**
22 1 kervala
      * \brief Here you write a standard NeL serial for all the member of TMyLoader that need to be packed.
23 1 kervala
      */
24 1 kervala
     void serial(NLMISC::IStream &f);
25 1 kervala
26 1 kervala
     /**
27 1 kervala
      * \brief This method returns the version of the packed sheet.
28 1 kervala
      * The coder needs to increment the number each time the packed sheet changes and the serial method
29 1 kervala
      * is updated so the code will discard old packed sheets.
30 1 kervala
      *
31 1 kervala
      * \return uint This must always return an integer. Unsigned is probably best.
32 1 kervala
      */
33 1 kervala
     static uint getVersion();
34 1 kervala
35 1 kervala
     /**
36 1 kervala
      * \brief Here you can write custom code for when the packed sheet loader needs to remove an old sheet.
37 1 kervala
      * \note This is rarely used.
38 1 kervala
      */
39 1 kervala
     void removed();
40 1 kervala
};
41 1 kervala
</code></pre>
42 1 kervala
43 1 kervala
h2. Loader Structure/Class Notes
44 1 kervala
45 1 kervala
    * A good example of a packed sheet loader is CSoundSerializer in sound_bank.cpp
46 1 kervala
    * readGeorges would do something like load variables in from the sheet using UFormElm's and the like and then use that data to create a new object. It essentially is form loading\.
47 1 kervala
    * serial is basic NeL serialization. This is for when loadForm wants to save or load the loader structure from a stream. It's the same thing as readGeorges except you're doing f.serial(myVar); instead of myVar=root.getValueByName(".MyVar"); Examples of serialization are everywhere in NeL.
48 1 kervala
    * removed() is called when the loadForm update cycle determines that the file that created this particular object is no longer in the file system. Essentially it just clears the members of the class as a destructor would.
49 1 kervala
    * getVersion() just tells the version number of the sheets. Any time you change the loader structure/class or the sheet forms for this loader you will want to increment the version number so that old versions of sheets get dropped from the packed sheet. *This is very important*.
50 1 kervala
51 1 kervala
Now that you have your class that conforms to the requirements of the packer and loader you have to create a container for the form loader to populate with sheets. This must always be like a map similar to the one below.
52 1 kervala
53 1 kervala
2 - Declare a container for all the loaded sheets:
54 1 kervala
55 1 kervala
std::map<CSheetId, TMyLoader> MySheets;
56 1 kervala
57 1 kervala
Usually Nevrax declares this globally but there is no constraint about that. It is used for a single call to loadForm (which is described below) and not for all sheets in an application. This method loads all of the sheets into the container.
58 1 kervala
59 1 kervala
3 - Call the packed sheet loader:
60 1 kervala
61 1 kervala
<pre><code class="CPP">loadForm( "my_extension", "packed_sheet_file_name.packed_sheets", MySheets, true);</code></pre>
62 1 kervala
63 1 kervala
Essentially what loadForm does is if told to go through the files with my_extension for an extension and check if there are newer ones than in the packed sheet, new ones period, or if some have been removed and marks these files appropriately in memory. It then loads all of the forms and puts them into cached lists and removes any files it found missing from the packed sheet. If it changed the container at all (added new files, updated changed files, or removed old files) it saves the file back out as the file passed in the parameter, which is packed_sheet_file_name.packed_sheets in the above example. In the process your map will be populated either via serialization (unchanged sheets) or by the readGeorges method (added or updated sheets.)
64 1 kervala
65 1 kervala
h2. Loading Notes
66 1 kervala
67 1 kervala
    * The packed sheet form loader requires that the file extension be .packed_sheets - however the logic lets you get away with .packed_sheetsbar for example. As a matter of practice though the packed sheet extension should stay with the standard.
68 1 kervala
    * The above function actually converts "my_extension" into a single-entry std::vector and calls:
69 1 kervala
70 1 kervala
void loadForm (const std::vector< std::string > &sheetFilters, const std::string &packedFilename, std::map< NLMISC::CSheetId, T > &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true)
71 1 kervala
72 1 kervala
    * loadForm is a template function, as seen above it will deduce it's argument from the ''container'' paramenter, where you will pass ))MySheets((.
73 1 kervala
74 1 kervala
h2. Summary / Details
75 1 kervala
76 1 kervala
As you have defined you own class to hold packed data, and as you declared you own container to hold them (in fact, the container MUST be a std::map<CSheetId, you_class> ), then it's easy to access the container with a valid sheet id to retreive your data
77 1 kervala
78 1 kervala
There is no progress callback for during packing - only a debug log every 10 seconds. But when you only load a packed sheet (without updating it with current sheets data) the loading time is very short.
79 1 kervala
80 1 kervala
CSheetId and sheet_id.bin file is a manner to uniquely identify sheet file with a 32 bit integer.
81 1 kervala
82 1 kervala
There is a (private) tool that builds the sheet_id.bin from a collection of files. The sheet_id.bin is always apended, never are old sheets removed. This ensures persistent data storage to be efficient and stable.
83 1 kervala
84 1 kervala
There is also a tool in the public CVS for retrieving information on sheets called ''disp_sheet_id''.
85 1 kervala
86 1 kervala
So, when you program starts, you can init the sheet id system by loading the sheet_id.bin file, than CSheetId instance can be created from file name or from 32 interger and converted to/from the int or filename.
87 1 kervala
88 1 kervala
It has to be in your search path, then you call the init method in CSheetId (or somethink near that)
89 1 kervala
90 1 kervala
<pre><code class="CPP">CSheetId::init(false);</code></pre>