More Loading Woes - Saving/Loading a complex class

More Loading Woes - Saving/Loading a complex class

Anonymous
Not applicable
266 Views
3 Replies
Message 1 of 4

More Loading Woes - Saving/Loading a complex class

Anonymous
Not applicable
I'm at my wit's end. I've got a HelperObj that keeps a pointer to an instance of a class I've defined that contains a variety of information I use for export later on. I need to save/load the data from this instance along with the HelperObj.

Here's the kicker - if I make a scene with this sort of data then save it, reset, and load (without closing Max) - it works. Like a charm. BUT. If I save the scene then close Max, when I open Max and try to load the scene later it doesn't work. It loads something into the buffer, but when I cast it it's got bogus data (I think). If I try to call methods on the object after loading , I get memory access errors.

I experimented with trying to save it via AddAppDataChunk but had zero luck.

Here's a stripped down version of how I'm trying to accomplish this. "trigger" is the object I'm trying to save. It extends IRefTargMonitor.
IOResult CPhysicsEvent::Save(ISave *isave)
{
ULONG nb;
void *trigBuf = MAX_malloc(sizeof(trigger));
memcpy(trigBuf, trigger, sizeof(trigger));
isave->BeginChunk(TRIGGER_MAIN);
isave->BeginChunk(TRIGGER_CHUNK);
isave->Write(trigBuf,sizeof(trigger), &nb);
isave->EndChunk();
isave->EndChunk();
return IO_OK;
}
IOResult CPhysicsEvent::Load(ILoad *iload)
{
IOResult res = IO_OK;
ULONG nb;
void *trigBuf;
while (IO_OK==(res=iload->OpenChunk()))
{
switch(iload->CurChunkID())
{
case TRIGGER_MAIN:
while (IO_OK==(res=iload->OpenChunk()))
{
switch(iload->CurChunkID())
{
case TRIGGER_CHUNK:
trigBuf = malloc(iload->CurChunkLength());
res=iload->Read(trigBuf, iload->CurChunkLength(), &nb);
trigger = (CPhysicsTrigger*)trigBuf;
break;
}
iload->CloseChunk();
}
break;
}
iload->CloseChunk();
}
return IO_OK;
}

Anybody? Bueller? Bueller?
0 Likes
267 Views
3 Replies
Replies (3)
Message 2 of 4

Anonymous
Not applicable
You seem to be saving just the pointer to your data. This obviously won't work. When you close max's process, all its virtual memory is lost, so naturally, you can't just load back in your pointer and hope what it points to is still valid.

It happens to work by accident when max is still running, since the object happens to still be resident in memory, but if you opened a few other scenes, chances are they would overwrite that block of memory pointing to your 'trigger' object.

What you need to do is write out your actual object, not just a pointer to it.

E.g.

struct FOO {
// Foo's members
int a, b, c;
float d;
};

FOO g_foo; // our FOO instance

IOResult CPhysicsEvent::Save(ISave *isave)
{
ULONG nbytes; // bytes written
isave->BeginChunk(ID_FOO);
// Write our FOO object to disk
isave->Write(&g_foo, sizeof g_foo, &nbytes);

// Handle any errors

isave->EndChunk();

return IO_OK;
}



Remember that in your code,


void *trigBuf = MAX_malloc(sizeof(trigger));
memcpy(trigBuf, trigger, sizeof(trigger));


This just makes a copy of the pointer (4 bytes on Win32) and writes that out to disk. Which is kinda pointless.
0 Likes
Message 3 of 4

Anonymous
Not applicable
I'd reached the same conclusion - that a shallow copy of the pointer was being made rather than a copy of the object. The problem was that the class of the pointer was in fact a parent class, and the actual object was one of a number of subclasses. I was hoping to preserve the type without having to write a bunch of extra code to cast it when the file loads. If I knew the sublcass type I could call the subclass's LOAD method to restore the field values (as in your example).

Ultimately I concluded this was impossible. I had to store a value corresponding to the subclass type, then test for that value at load time and create a new object of the correct subclass at load time, then populate its fields using the subclass's LOAD function.

It works and it's okay it just seems ineligant.

Thanks for your response!
0 Likes
Message 4 of 4

Anonymous
Not applicable
Glad it's fixed.

Couldn't you use the ClassID() method to find out what type of object it is? That's Max's way of providing RTTI.
0 Likes