Loading enums in a datablock...
by Daniel Buckmaster · in Torque Game Engine · 12/25/2007 (11:00 am) · 9 replies
I've set up a custom struct in a datablock that includes an enumerated value, similar to the way ShapeBaseImageData stores its state data (recoil states, etc., are enums). I've copied the way ShapeBaseImageData initialises these fields in the console, but I'm getting run-time errors when I load a level - in consoleTypes.cc, at the line
EDIT: Huh. My 4 latest posts each have 5 other posts in between them :P. What a random thing to notice...
AssertFatal(tbl, "Null enum table passed to getDataTypeEnum()");tbl represents an EnumTable object, and the problem is that it's sort of not there. The first reference I can find to the EnumTable object is as a part of an AbstractClassRep::Field, the 'table' member. I have no idea why it's not there, but it's got something to do with the datablock field that represents the enum in my struct. Does anyone have experience in dealing with this?
EDIT: Huh. My 4 latest posts each have 5 other posts in between them :P. What a random thing to notice...
About the author
Studying mechatronic engineering and computer science at the University of Sydney. Game development is probably my most time-consuming hobby!
#2
Did you provide an enum table?
excerpt:
12/26/2007 (4:32 am)
I'd prefer the enum method as it is exactly what you want, only built in.Did you provide an enum table?
excerpt:
static EnumTable::Enums enumRecoilStates[] =
{
{ ShapeBaseImageData::StateData::NoRecoil, "NoRecoil" },
{ ShapeBaseImageData::StateData::LightRecoil, "LightRecoil" },
{ ShapeBaseImageData::StateData::MediumRecoil, "MediumRecoil" },
{ ShapeBaseImageData::StateData::HeavyRecoil, "HeavyRecoil" },
};
static EnumTable EnumRecoilState(4, &enumRecoilStates[0]);
#3
Is it just that I ask questions only you among the community know how to solve, or...? ;)
EDIT: nope. I get the exact same error as before. I'm having a look at debug information...
Okay, I have no idea what's going on. Do I have to do something special with the enum table?
EDIT: Think I found the problem - addField...
Okay, I got rid of this problem by using addField properly. Now I've gone back to the previous error that I ran into after making sure that this worked. Stupid invalid packets :[
12/26/2007 (5:37 am)
Hmm. That's a big resounding no. That would seem to solve the problem - thanks!Is it just that I ask questions only you among the community know how to solve, or...? ;)
EDIT: nope. I get the exact same error as before. I'm having a look at debug information...
Okay, I have no idea what's going on. Do I have to do something special with the enum table?
EDIT: Think I found the problem - addField...
Okay, I got rid of this problem by using addField properly. Now I've gone back to the previous error that I ran into after making sure that this worked. Stupid invalid packets :[
#4
12/26/2007 (6:57 pm)
Post copies of your packData/unpackData methods for your datablock. Usually an invalid packet error is caused by these methods being out of sync.
#5
For reference, here's the struct that the data is stored in:
12/27/2007 (1:45 am)
I thought that must have been it, because the error only shows up when I include my new class in the build. I can't spot anything, though...For reference, here's the struct that the data is stored in:
struct WatchedField {
const char* name;
F32 minVal;
F32 maxVal;
F32 decayVal;
enum WarnType {
OnMin, OnMax,
OnIncTo, OnDecTo,
OnChange,
NoWarn,
NumWarnBits = 3,
} warnType;
F32 warnVals [4];
} watchedFields [NumWatchedFields];void RangedWeaponData::packData(BitStream* stream)
{
Parent::packData(stream);
if(stream->writeFlag(mProjectile))
stream->writeRangedU32(packed? SimObjectId(mProjectile):
mProjectile->getId(),DataBlockObjectIdFirst,DataBlockObjectIdLast);
U32 i, j;
for(i = 0; i < NumWatchedFields; i++)
{
if(stream->writeFlag(watchedFields[i].name && watchedFields[i].name[0]))
{
WatchedField& f = watchedFields[i];
stream->writeString(f.name);
stream->write(f.minVal);
stream->write(f.maxVal);
stream->write(f.decayVal);
stream->writeInt(f.warnType,WatchedField::NumWarnBits);
for(j = 0; j < 4; j++)
stream->write(f.warnVals[j]);
}
}
}
void RangedWeaponData::unpackData(BitStream* stream)
{
Parent::unpackData(stream);
mProjectile = (stream->readFlag() ?
(ProjectileData*)stream->readRangedU32(DataBlockObjectIdFirst,
DataBlockObjectIdLast) : 0);
U32 i, j;
for(i = 0; i < NumWatchedFields; i++)
{
if(stream->readFlag())
{
WatchedField& f = watchedFields[i];
f.name = stream->readSTString();
stream->read(&f.minVal);
stream->read(&f.maxVal);
stream->read(&f.decayVal);
f.warnType = (WatchedField::WarnType)stream->readInt(WatchedField::NumWarnBits);
for(j = 0; j < 4; j++)
stream->read(&f.warnVals[j]);
}
}
watchedFieldsLoaded = true;
}
#6
I'd put break points in your pack/unpack methods and make sure they seem to be writing/reading properly. Use your debugger to check values (make sure what is written is what is read).
12/27/2007 (1:07 pm)
Well that seems okay to me. Does your object have pack/unpack methods?I'd put break points in your pack/unpack methods and make sure they seem to be writing/reading properly. Use your debugger to check values (make sure what is written is what is read).
#7
Here's the object pack/unpack, just in case:
(First, the struct objects use, which is different to the datablock struct:)
EDIT
From breakpoints on pack/unpack datablock methods, it seems that while an object for mProjectile is being packed, when it gets unpacked, it goes all screwy. Could that be a cause for an 'invalid packet'?
EDIT
This is really damn frustrating. The invalid packet thing only actually happens about half the time - sometimes my levels load fine, other times they get invalid packeted about a second after spawning. Makes it a bugger to debug properly. I'd still like to just breakpoint the piece of code that tells the scripts when there's an invalid packet.
And a nice addition to the engine would be to say which packet was invalid :P
12/28/2007 (3:16 am)
That's an idea - breakpointing the methods themselves. I wasn't sure wht could be causing the invalid packet thing (which dumps me from my level with a dialog), so I just searched for 'invalid packet' in the engine code and breakpointed all those to see which one was being called. None of them, apparently...Here's the object pack/unpack, just in case:
(First, the struct objects use, which is different to the datablock struct:)
struct WatchedField {
bool active;
F32 val;
F32 prevVal;
} watchedFields[RangedWeaponData::NumWatchedFields];U32 RangedWeapon::packUpdate(NetConnection *connection, U32 mask, BitStream *stream)
{
U32 retMask = Parent::packUpdate(connection,mask,stream);
stream->writeFlag(mPrimaryTriggerDown);
stream->writeFlag(mSecondaryTriggerDown);
stream->writeInt(mPrimaryTriggerOnTime,RangedWeapon::TriggerTimeBitSize);
stream->writeInt(mPrimaryTriggerOffTime,RangedWeapon::TriggerTimeBitSize);
stream->writeInt(mSecondaryTriggerOnTime,RangedWeapon::TriggerTimeBitSize);
stream->writeInt(mSecondaryTriggerOffTime,RangedWeapon::TriggerTimeBitSize);
if(mask & WatchedFieldUpdateMask)
{
for(U32 i = 0; i < RangedWeaponData::NumWatchedFields; i++)
if(stream->writeFlag(watchedFields[i].active))
{
stream->write(watchedFields[i].val);
stream->write(watchedFields[i].prevVal);
}
}
return retMask;
}
void RangedWeapon::unpackUpdate(NetConnection *connection, BitStream *stream)
{
Parent::unpackUpdate(connection,stream);
mPrimaryTriggerDown = stream->readFlag();
mSecondaryTriggerDown = stream->readFlag();
mPrimaryTriggerOnTime = stream->readInt(RangedWeapon::TriggerTimeBitSize);
mPrimaryTriggerOffTime = stream->readInt(RangedWeapon::TriggerTimeBitSize);
mSecondaryTriggerOnTime = stream->readInt(RangedWeapon::TriggerTimeBitSize);
mSecondaryTriggerOffTime = stream->readInt(RangedWeapon::TriggerTimeBitSize);
for(U32 i = 0; i < RangedWeaponData::NumWatchedFields; i++)
{
watchedFields[i].active = stream->readFlag();
if(watchedFields[i].active)
{
stream->read(&watchedFields[i].val);
stream->read(&watchedFields[i].prevVal);
}
}
}EDIT
From breakpoints on pack/unpack datablock methods, it seems that while an object for mProjectile is being packed, when it gets unpacked, it goes all screwy. Could that be a cause for an 'invalid packet'?
EDIT
This is really damn frustrating. The invalid packet thing only actually happens about half the time - sometimes my levels load fine, other times they get invalid packeted about a second after spawning. Makes it a bugger to debug properly. I'd still like to just breakpoint the piece of code that tells the scripts when there's an invalid packet.
And a nice addition to the engine would be to say which packet was invalid :P
#8
Maybe that could be your problem...?
12/28/2007 (10:18 am)
Well, from what I can tell from just the code, you seem to have the possibility of reading data that wasn't ever sent.U32 RangedWeapon::packUpdate(NetConnection *connection, U32 mask, BitStream *stream)
{
U32 retMask = Parent::packUpdate(connection,mask,stream);
stream->writeFlag(mPrimaryTriggerDown);
stream->writeFlag(mSecondaryTriggerDown);
stream->writeInt(mPrimaryTriggerOnTime,RangedWeapon::TriggerTimeBitSize);
stream->writeInt(mPrimaryTriggerOffTime,RangedWeapon::TriggerTimeBitSize);
stream->writeInt(mSecondaryTriggerOnTime,RangedWeapon::TriggerTimeBitSize);
stream->writeInt(mSecondaryTriggerOffTime,RangedWeapon::TriggerTimeBitSize);
[b]// Check if we should sent watched field updates[/b]
if(mask & WatchedFieldUpdateMask)
{
for(U32 i = 0; i < RangedWeaponData::NumWatchedFields; i++)
if(stream->writeFlag(watchedFields[i].active))
{
stream->write(watchedFields[i].val);
stream->write(watchedFields[i].prevVal);
}
}
return retMask;
}
void RangedWeapon::unpackUpdate(NetConnection *connection, BitStream *stream)
{
Parent::unpackUpdate(connection,stream);
mPrimaryTriggerDown = stream->readFlag();
mSecondaryTriggerDown = stream->readFlag();
mPrimaryTriggerOnTime = stream->readInt(RangedWeapon::TriggerTimeBitSize);
mPrimaryTriggerOffTime = stream->readInt(RangedWeapon::TriggerTimeBitSize);
mSecondaryTriggerOnTime = stream->readInt(RangedWeapon::TriggerTimeBitSize);
mSecondaryTriggerOffTime = stream->readInt(RangedWeapon::TriggerTimeBitSize);
[b]// Read watched field updates whether we sent them or not[/b]
for(U32 i = 0; i < RangedWeaponData::NumWatchedFields; i++)
{
watchedFields[i].active = stream->readFlag();
if(watchedFields[i].active)
{
stream->read(&watchedFields[i].val);
stream->read(&watchedFields[i].prevVal);
}
}
}Maybe that could be your problem...?
#9
EDIT: Seems to be fixed! Thank you for your astute reading :) You are my official hero ;)
12/28/2007 (12:50 pm)
Ooh. That's probably a bit of an issue :P. I'll fix that up and see what happens.EDIT: Seems to be fixed! Thank you for your astute reading :) You are my official hero ;)
Torque Owner Daniel Buckmaster
T3D Steering Committee
This gave me a new problem - I'm getting an 'invalid packet from server' error when I start a mission. This problem doesn't seem to be connected to my custom clas, though, so it's probably just a script issue.
Next up is changing the integer datablock value into a string, so people can type in strings corresponding to the enum value names, instead of having to put in a number. I'll just use a block of if-elses to convert from a string to an enum value.