XBox:Framework:Data Objects

From MadoxLabs

Template:Downloads:XBox

Edit Downloads:XBox (http://www.madox.ca/mediawiki2/index.php?title=Template:Downloads:XBox&action=edit)

Data objects provide a disconnect between the game's state and the UI. This is critical because the UI shouldn't need to know what specifically is going on in the game, it is just a consumer of data values that it uses to create an interface.

Stating the Problem

The UI typically is used to display game values to the user, or it uses those values to determine what interfaces/widgets should be available. When the game changes that value, the UI should be able to get the new value easily so the change can be conveyed to the user. Ideally, the UI should have a reference to the data value so when it changes, there is no work to by the UI to use the new value.

The UI should also be a data consumer, which means that it shouldnt know what the producer of that data value is. If the data value is an enemy's health, the producer is the current enemy. When the current enemy changes, the health value referred to by the UI should now represent the new enemy, in an easy way. We dont want the game to have to update the UI every time it need to hand a new reference to the UI. There needs to be a way to change the producer without affecting the consumers.

Finally, if there is no current enemy, the UI needs to handle that by displaying a 0 or some default value. The lack of a producer shouldnt affect the consumers.

Data Library

At a high level, this is how the problem is solved:

mxData

mxData objects are used to represent a value. An mxData contains the value, so instead of using a regular int i you would use mxData<int> i and use i.Value where ever i was used.

The reason for this is that the data library needs to keep references to all the mxDatas, and you can not keep a reference to things like int or float without resorting to /unsafe mode. So it is less than ideal, but its usable. This worked better in C++, but C++ is all /unsafe mode.

Each mxData is also assigned a publish name. When a consumer asks for a data object by name, the mxData with that name is given out.

mxDataSource

This is a contain for all mxDatas that an object will publish. This container is then handed to the data library for publication. Only published mxData can be given out. Publishing objects with a given name replaces any existing objects published with that name.

The mxDataSource can also unpublish its collection, which should be done for sure in the destructor. Unpublishing msDatas makes the consumers resort to using default values until a new source publishes a replacement.

mxDataSource should be a base class, but we cant use multiple inheritance in C# so it has to be a composite.

mxWrapper

When a consumer wants to access a data object, the data library gives it a mxWrapper. This object contains the mxData so that the consumer can get the values, and the data library can swap out the mxData at anytime, invisibly to the consumer.

When a mxData is unpublished, it is swapped out with a default value. If the consumer requests a non-existant data object, it is also given a default value.

Example Usage

A data publisher runs the following code:

       {
           mxDataSource source = new mxDataSource();
           mxDataLibrary lib = new mxDataLibrary();

           // A float value to publish under the name PI
           mxFloat value = new mxFloat("PI", 3.14159f);

           // A list to publish under the name NAMES
           mxDataList<string> list = new mxDataList<string>("NAMES");
           list[0] = "Bob";
           list[1] = "George";
           list[2] = "David";

           // publish that stuff
           source.Publish(value);
           source.Publish(list);
           lib.Publish(source);

           // POINT A: set a default for when PI isnt available - its not even a float!
           lib.SetDefault(new mxString("PI", "You suck"));

           // POINT B: modify original
           value.Value = 9.8f;

           // POINT C: replace it
           mxDataSource source2 = new mxDataSource();
           mxFloat value2 = new mxFloat("PI", 666f);
           source2.Publish(value2);
           lib.Publish(source2);

           // POINT D: unpublish it
           source2.Unpublish();
       }

The consumer runs the following code once:

           mxDataWrapper wrap = lib.GetData("PI");
           float check;

At each point, POINT A,B,C,D, the comsumer runs the following code:

           check = (float)wrap.Value(check);
           System.Diagnostics.Debug.WriteLine("check: " + check + " " + wrap.Data.ToString());

The output is:

POINT A : check: 3.13159 3.14159
POINT B : check: 9.8 9.8
POINT C : check: 666 666
POINT D : check: 0 You Suck

To consume the list:

           mxDataWrapper wrap2 = lib.GetData("NAMES");
           for (int i = 0; i < wrap2.Count; ++i)
           {
               string val = "";
               val = (string)wrap2.Value(val);
               System.Diagnostics.Debug.WriteLine("name " + i + ": " + val);
           }
Personal tools
Toolbox