Resizing a C# UNION
Posted: 2012-03-01 Filed under: BattleScape, Coding Leave a commentI have been testing out the *basic* BattleScape scenario (two creatures in a map with an initiative-based turn-tracker), and noticed a problem with rendering one of the cell-types in the client. At each I was expecting a step, I was getting a block. Fortunately I knew from the workshop and host that the map cell-data was correct as it rendered correctly. Also, since the Uzi.Visualize assembly is shared (currently the only bit of code so shared) between the Client and Core assemblies, it wasn’t a rendering glitch. The problem had to be in marshaling the data between application domains.
For background, I have divided cell structural types into “Template” and “Parameter” parts. I build cell-structure templates (indexed) that can be used for multiple cells, and keep a list with the local tactical map. This is the equivalent of deciding what types of bricks I want to use. Physical characteristics (materials and relative dimensions from cell edges) are stored in the template. If I want a 1 foot sliver of rock (the rest being air) bound to a face, and a 2 foot sliver of rock bound to a face, I need 2 templates. The “Parameter” data contains useful situational data, that varies based on the Template base-class needs. A solid CellSpace doesn’t rely on parameter data for anything, but a SliverCellSpace needs binding face information to know how to orient itself. Other cell types (such as CornerCellSpace, WedgeCellSpace, LFrameCellSpace and Stairs) need even more data to orient themselves correctly.
To keep room data fairly compact, the room holds information about the room dimensions, and a three dimensional array of structures that holds both the references to the templates, and the parameters, for each cell in the room. When I serialize the cell data into a data contract for the room, I yield an array of unsigned values, where each value combines one cell’s template index and its parameter data. Rather than doing this programmatically, I simply used a structure with explicit layout and jammed the fields next to each other so I could read them with an overlapping larger field (similar to a UNION in C).
Herein lay my problem. When I created this scheme, I was using unsigned short (ushort) values for the index and parameter values, and the complete value was an unsigned integer (uint):
namespace Uzi.Visualize
{
[StructLayout(LayoutKind.Explicit, Pack=2)]
public struct IndexStruct
{
[FieldOffset(0)]
public ushort Index;
[FieldOffset(2)]
public ushort StateInfo;
[FieldOffset(0)]
public uint ID;
}
}
At some point I found/felt the need to make the parameter an unsigned integer (uint), so naturally I bumped the index as well. Keep in mind that this re-sizing happened in many more places than this data contract. And it all worked well in the Host and Workshop (Core assemblies). What I missed was when I refactored the ushorts to uints was the full impact on this structure. What I was left with is:
namespace Uzi.Visualize
{
[StructLayout(LayoutKind.Explicit, Pack=4)]
public struct IndexStruct
{
[FieldOffset(0)]
public uint Index;
[FieldOffset(2)]
public uint StateInfo;
[FieldOffset(0)]
public uint ID;
}
}
The correct form is:
namespace Uzi.Visualize
{
[StructLayout(LayoutKind.Explicit, Pack=4)]
public struct IndexStruct
{
[FieldOffset(0)]
public uint Index;
[FieldOffset(4)]
public uint StateInfo;
[FieldOffset(0)]
public ulong ID;
}
}