So, finally a bit of time for posting a bit more in detail.
Most work on RC3 is finished now. I still have to take a look at the crash that seems to happen in systems other than sol, but apart from that, things look good... better than I ever expected, really.
After fixing the problem with D3D9 client, I ported some more code back from IMS2, related to the rotation of docking ports. Coupled with the new streamlined mass-integration, the results are pretty astonishing. I integrated Dantassiis Lunar Station as a quick test. Integration took about 3 minutes. No crashes along the way. No meshes missing or rotated wrongly. It's the way it should always have been, but which I didn't really believe to feasible for IMS anymore.
There's still the thing with a crash on exit, or reload if the launchpad wasn't shut down. I'm afraid I haven't found a cure for that yet, but in the great scheme of things it's a rather minor inconvienience.
Anyways, now for the D3D9 specific details. The animation problem was, as expected, an opperation that wrote out of bounds. It was just a bit difficult to track down, because there's nothing wrong with the code per se. Rather the dynamic adding of animations creates a problem that was not foreseen when the client was written, and caused an otherwise fine function to missbehave. That needed a saveguard.
The problem in a bit more detail is this: D3D9 client initialises animations and allocates memory to store the state of those both at loadup, and dinamically when a mesh is added.
This happens in the function
InitAnimations(UINT) in vVessel.cpp.
The trouble is, this function only is called when a mesh is added. nanim receives the number of animations the vessel currently has, but this is
before new animations are added.
IMS (and presumably any other add-on that creates animations on the fly) then goes on to add the new animations if neccessary. After doing so,
vVessel::Update() is called in the client, which calls
UpdateAnimations(UINT = -1).
The new animations will have been added in the meantime. Meaning, nanim will receive the new number of animations, while InitAnimations only got the old number of animations, without the newly added ones.
As a result of this, UpdateAnimations writes over the allocated length of animstate in the block at the end.
I fixed the problem by introducing a new block into UpdateAnimations that checks for newly added animations and calls InitAnimations for them. The block seems a bit overcomplicated. The problem is I need the meshindex, and at this point (called from Update()) The meshindex passed to UpdateAnimations is invalid, so I have to extract all meshindices first, and of course I had to check for duplicity, since I don't want to call InitAnimations over and over for the same mesh. I used a vector, which means I had to include vector.h in vVessel.cpp:
Code:
void vVessel::UpdateAnimations (UINT mshidx)
{
double newstate;
UINT oldnAnim = nanim;
nanim = vessel->GetAnimPtr(&anim);
if (nanim>0 && animstate==NULL) {
LogErr("[ANOMALY] UpdateAnimations() called before the animations are initialized. Calling InitAnimations()...");
InitAnimations();
}
if (nanim > oldnAnim)
//animations have been added without being initialised
{
std::vector<UINT> meshesToInitialise;
for (UINT i = oldnAnim; i < nanim; ++i)
//extracting meshindices for uninitialised animations.
//this might seem overly complicated, but it seems savest
//it guarantees that all new animations are initialised, and are initialised only once
{
for (UINT j = 0; j < anim[i].ncomp; ++j)
{
bool alreadyNoted = false;
for (UINT jj = 0; jj < meshesToInitialise.size(); ++jj)
{
if (anim[i].comp[j]->trans->mesh == meshesToInitialise[jj])
{
alreadyNoted = true;
break;
}
}
if (!alreadyNoted)
{
meshesToInitialise.push_back(anim[i].comp[j]->trans->mesh);
}
}
}
for (UINT i = 0; i < meshesToInitialise.size(); ++i)
{
InitAnimations(meshesToInitialise[i]);
}
}
for (UINT i = 0; i < nanim; i++) {
if (!anim[i].ncomp) continue;
if (animstate[i] != (newstate = anim[i].state)) {
Animate(i, newstate, mshidx);
animstate[i] = newstate;
}
}
}
I'm probably breaking a convention on every line I wrote here, and I don't know if the inclusion of vector is welcome, as there seems to be an avid evasion of both string and vector in the whole client. I could have made a fixed size array with a size that
seems large enough, but I'd rather play it save... :shifty:
Anyways, for those reasons I'm somewhat reluctant to commit the changes. The other change was to increase the buffer size in ParseSkins (also vVessel.cpp) to 256, like this:
Code:
void vVessel::ParseSkins()
{
char classname[256];
D3D9Client *gc = scn->GetClient();
DWORD start = 0;
sprintf_s(classname, 256, "#%s", vessel->GetClassNameA());
These corrections make D3D9Client work with IMS without problems. So where should I go from here? Post the changes in the (suspiciously inactive) D3D9 forum? Make a pull request (as I said, I'm a bit reluctant about this... somoene will probably feel the urge to rewrite that block anyways)? Put a temporary fixed version up with RC3 until there's a new official build?
It is also possible that it would be sufficient to call InitAnimations just once, even if more than one mesh was added (doesn't happen in IMS, so I didn't test)... as far as I can see it wouldn't make much of a difference, but the function requiring a meshindex made me suspicious.