This is a bit of a mindscrew, so I'm having trouble explaining this the right way. Please bear with me.
In IMS, I have to dynamically add animations to a vessel. For this reason, I'm reading animation data from the config file and create the animations in Orbiter accordingly, in a similar way that SC3 does. With one (surprisingly) important difference: I can't do it all during loadup. IMS is probably one of the only add-ons that calls AddAnimationComponent during sim time, between frames. As such, it would not surprise me too much if I'm dealing with an Orbiter Bug/limitation here. But anyways, what happens:
The animation is created without trouble. The animation also works without trouble. But sometime in closer or further future, there's going to be a CTD. I'm sorry I cannot be much more specific on the circumstances, but the behavior is very much undefined. The only way I have been able to track the problem back to AddAnimationComponent at all is to save a configuration in which I know that the crash happens on the next call to AddMesh, but it is definitaley not AddMesh that is the problem.
The problem also does not cause an access violation. Instead, the code takes a detour into another, completely unrelated function. I know this behavior, alright, I fought with it on two specific occasions: Once when I didn't realise that I was accessing an uninitialised pointer, the other time when I wrote out of bounds in a char-array. Especially in a case where something writes out of bounds, it is evident why a precise reproduction is extremely difficult: Everything, including whether or not there is a crash, depends on where stuff is in the memory, which is not a configuration one can reproduce on another machine, so I am very sorry to not be able to give precise instructions as to the reproduction. It was kind of a lucky strike that I have a watertight repro on my own system (but also even here only on D3D9 client. The crashes occur in vanilla Orbiter too, but I have not been able to nail down a situation that produces the bug every time on my machine there, so I cannot be 100% sure that it is the same problem. If D3D9 client has its own implementation of AddAnimationComponent, the problem might be located there only, but I have so far not gotten an answer to my inquiry).
So how can I be sure that it is AddAnimationComponent? Well, if the only thing I change in the code is to not call AddAnimationComponent, the crash does not occur. If I change most everything else, it still does. More than that, I can actually influence where I find myself in the code when the crash occurs. By changing certain parameters, I can end up in this function or in that function, suggesting that AddAnimationComponent is writing out of bound somewhere, so depending on the input data, there's another memory address written where it doesn't belong.
I checked everything in the function that creates those animations multiple times. I've written a simplified implementation of it to see if the trouble is located elsewhere. I'll post this simplified version here (which loads only translation movements, but that is sufficient to cause the crash):
(note: Tokenize is a function that splits a string into smaller strings based on the passed deliminators. I'm using it all the time.)
The function that creates the MGROUP_TRANSFORM looks like this:
I played around quite a bit with these to find the problem. Down to the point of just defining static properties for the MGROUP_TRANSFORM struct, just to see if that would solve the problem. It doesn't. The only thing that prevents the behavior is not calling AddAnimationComponent at all.
I tried creating a buffer around UINT *groups, to see if the problem was there. It doesn't fix the problem, but the size of groups has an effect of where in the code I find myself when the crash happens.
I also don't ever seem to have the problem when calling the function in clbkPostCreation (where animations from already installed modules are loaded by the very same function I'm using to create them on sim time).
Any Help would be greatly appreciated. If I can get this one out, IMS would become another bit more stable (and I suspect quite a good bit). If not, then it's likely going to haunt me in IMS2 also, which would be a bit of a bleak perspective...
In IMS, I have to dynamically add animations to a vessel. For this reason, I'm reading animation data from the config file and create the animations in Orbiter accordingly, in a similar way that SC3 does. With one (surprisingly) important difference: I can't do it all during loadup. IMS is probably one of the only add-ons that calls AddAnimationComponent during sim time, between frames. As such, it would not surprise me too much if I'm dealing with an Orbiter Bug/limitation here. But anyways, what happens:
The animation is created without trouble. The animation also works without trouble. But sometime in closer or further future, there's going to be a CTD. I'm sorry I cannot be much more specific on the circumstances, but the behavior is very much undefined. The only way I have been able to track the problem back to AddAnimationComponent at all is to save a configuration in which I know that the crash happens on the next call to AddMesh, but it is definitaley not AddMesh that is the problem.
The problem also does not cause an access violation. Instead, the code takes a detour into another, completely unrelated function. I know this behavior, alright, I fought with it on two specific occasions: Once when I didn't realise that I was accessing an uninitialised pointer, the other time when I wrote out of bounds in a char-array. Especially in a case where something writes out of bounds, it is evident why a precise reproduction is extremely difficult: Everything, including whether or not there is a crash, depends on where stuff is in the memory, which is not a configuration one can reproduce on another machine, so I am very sorry to not be able to give precise instructions as to the reproduction. It was kind of a lucky strike that I have a watertight repro on my own system (but also even here only on D3D9 client. The crashes occur in vanilla Orbiter too, but I have not been able to nail down a situation that produces the bug every time on my machine there, so I cannot be 100% sure that it is the same problem. If D3D9 client has its own implementation of AddAnimationComponent, the problem might be located there only, but I have so far not gotten an answer to my inquiry).
So how can I be sure that it is AddAnimationComponent? Well, if the only thing I change in the code is to not call AddAnimationComponent, the crash does not occur. If I change most everything else, it still does. More than that, I can actually influence where I find myself in the code when the crash occurs. By changing certain parameters, I can end up in this function or in that function, suggesting that AddAnimationComponent is writing out of bound somewhere, so depending on the input data, there's another memory address written where it doesn't belong.
I checked everything in the function that creates those animations multiple times. I've written a simplified implementation of it to see if the trouble is located elsewhere. I'll post this simplified version here (which loads only translation movements, but that is sufficient to cause the crash):
(note: Tokenize is a function that splits a string into smaller strings based on the passed deliminators. I'm using it all the time.)
Code:
void IMS::CreateAnimationMovement2(Movement& movement)
{
bool rotateAnimation = false;
MATRIX3 rotMatFirst;
MATRIX3 rotMatSecond;
for (UINT i = 0; i < modulesToRotate.size(); ++i)
//checking whether this module is rotated
{
if (modulesToRotate[i] == movement.moduleIndex)
{
rotateAnimation = true;
break;
}
}
if (rotateAnimation)
//create rotation matrices to rotate animations
{
PrepareModuleRotation(rotMatFirst, rotMatSecond, GetModule(movement.moduleIndex));
}
string configFilePath = "Vessels\\IMS\\";
configFilePath.append(movement.configFileName).append(".cfg");
FILEHANDLE configFile = oapiOpenFile(configFilePath.data(), FILE_IN, CONFIG);
char line[5000];
// char paramName[25];
// char groups[5000];
int movementsCount;
if (oapiReadItem_int(configFile, "Movements", movementsCount))
{
for (int mi = 0; mi < movementsCount; mi++)
{
stringstream paramName("");
paramName << "Movement" << mi + 1;
if (oapiReadItem_string(configFile, (char*)(paramName.str().data()), line))
{
string s = line;
vector<string> tokens;
Tokenize(line, tokens);
if (tokens[1] == "Translate")
{
AddTranslationMovement(tokens, movement, rotMatFirst, rotMatSecond, rotateAnimation);
paramName << "Duration";
if (oapiReadItem_string(configFile, (char*)(paramName.str().data()), line))
{
double animStart, animEnd;
vector<string> tokens;
Tokenize(line, tokens);
animStart = atof(tokens[0].data());
animEnd = atof(tokens[1].data());
movement.animComponents.push_back(AddAnimationComponent(movement.animId,
animStart, animEnd, movement.transforms[movement.transforms.size() - 1]));
}
}
}
}
}
oapiCloseFile(configFile, FILE_IN);
}
The function that creates the MGROUP_TRANSFORM looks like this:
Code:
void IMS::AddTranslationMovement(vector<string> ¶ms, Movement &movement, MATRIX3 &firstRot, MATRIX3 &secondRot, bool transformAnimation)
{
vector<string> groupsString;
Tokenize(params[0], groupsString, ",");
UINT *groups = new UINT[groupsString.size()];
for (UINT i = 0; i < groupsString.size(); ++i)
{
int tempGroup;
tempGroup = atoi(groupsString[i].data());
groups[i] = UINT(tempGroup);
}
//storing pointer for deletion on SimExit
movement.groups.push_back(groups);
vector<string> translationString;
Tokenize(params[2], translationString, ",");
VECTOR3 shift = _V(0,0,0);
shift.x = atof(translationString[0].data());
shift.y = atof(translationString[1].data());
shift.z = atof(translationString[2].data());
if (transformAnimation)
{
shift = mul(firstRot, shift);
shift = mul(secondRot, shift);
}
RoundVector(shift, 1000);
MGROUP_TRANSLATE* tr = new MGROUP_TRANSLATE(movement.moduleIndex + cmParams.meshesNumber,
groups, groupsString.size(), shift);
movement.transforms.push_back(tr);
}
I played around quite a bit with these to find the problem. Down to the point of just defining static properties for the MGROUP_TRANSFORM struct, just to see if that would solve the problem. It doesn't. The only thing that prevents the behavior is not calling AddAnimationComponent at all.
I tried creating a buffer around UINT *groups, to see if the problem was there. It doesn't fix the problem, but the size of groups has an effect of where in the code I find myself when the crash happens.
I also don't ever seem to have the problem when calling the function in clbkPostCreation (where animations from already installed modules are loaded by the very same function I'm using to create them on sim time).
Any Help would be greatly appreciated. If I can get this one out, IMS would become another bit more stable (and I suspect quite a good bit). If not, then it's likely going to haunt me in IMS2 also, which would be a bit of a bleak perspective...
Last edited: