Skip to content

Commit

Permalink
Fix crash when deleting visuals that can still be in use
Browse files Browse the repository at this point in the history
  • Loading branch information
SaiyansKing committed Nov 4, 2021
1 parent 7a14f63 commit 00764c0
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 21 deletions.
48 changes: 27 additions & 21 deletions D3D11Engine/GothicAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1227,34 +1227,45 @@ void GothicAPI::OnVisualDeleted( zCVisual* visual ) {
StaticMeshVisuals.erase( pm );
}

if ( ((zCModel*)visual)->GetMeshSoftSkinList()->NumInArray ) {
// Find vobs using this visual
for ( std::list<SkeletalVobInfo*>::iterator it = SkeletalMeshVobs.begin(); it != SkeletalMeshVobs.end(); ++it ) {
if ( (*it)->VisualInfo && ((zCModel*)(*it)->VisualInfo->Visual)->GetMeshSoftSkinList()->Array[0] == ((zCModel*)visual)->GetMeshSoftSkinList()->Array[0] ) {
(*it)->VisualInfo = nullptr;
zCModel* zmodel = (zCModel*)visual;
if ( zmodel->GetMainPrototypeReferences() <= 1 ) { // Check if it is the last reference in prototype so that we can delete this visual
std::string str = zmodel->GetVisualName();
if ( str.empty() ) { // Happens when the model has no skeletal-mesh
zSTRING mds = zmodel->GetModelName();
str = mds.ToChar();
mds.Delete();
}

auto it = SkeletalMeshVisuals.find( str );
if ( it != SkeletalMeshVisuals.end() ) {
// Find vobs using this visual
for ( std::list<SkeletalVobInfo*>::iterator sit = SkeletalMeshVobs.begin(); sit != SkeletalMeshVobs.end(); ++sit ) {
if ( (*sit)->VisualInfo == it->second ) {
(*sit)->VisualInfo = nullptr;
}
}
}
}

std::string str = ((zCModel*)visual)->GetVisualName();
if ( str.empty() ) { // Happens when the model has no skeletal-mesh
zSTRING mds = ((zCModel*)visual)->GetModelName();
str = mds.ToChar();
mds.Delete();
delete SkeletalMeshVisuals[str];
SkeletalMeshVisuals.erase( str );
}

delete SkeletalMeshVisuals[str];
SkeletalMeshVisuals.erase( str );
break;
}
}

// Add to map
std::list<BaseVobInfo*> list = VobsByVisual[visual];
// Clear
if ( _canClearVobsByVisual ) {
std::list<BaseVobInfo*>& list = VobsByVisual[visual];
for ( auto const& it : list ) {
OnRemovedVob( it->Vob, LoadedWorldInfo->MainWorld );
}
if ( list.size() > 0 ) {
if ( RendererState.RendererSettings.EnableDebugLog )
LogInfo() << std::string( className ) << " had " + std::to_string( list.size() ) << " vobs";

list.clear();
VobsByVisual.erase( visual );
}
} else {
// TODO: #8 - Figure out why exactly we don't get notified that a VOB is re-added after being removed.
/*oCNPC* npcVob;
Expand All @@ -1267,11 +1278,6 @@ void GothicAPI::OnVisualDeleted( zCVisual* visual ) {
}
}*/
}
if ( list.size() > 0 ) {
if ( RendererState.RendererSettings.EnableDebugLog )
LogInfo() << std::string( className ) << " had " + std::to_string( list.size() ) << " vobs";
VobsByVisual[visual].clear();
}
}
/** Draws a MeshInfo */
void GothicAPI::DrawMeshInfo( zCMaterial* mat, MeshInfo* msh ) {
Expand Down
11 changes: 11 additions & 0 deletions D3D11Engine/zCModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,17 @@ class zCModel : public zCVisual {
#endif
}

int GetMainPrototypeReferences() {
zCArray<zCModelPrototype*>* prototypes = GetModelProtoList();
if ( prototypes->NumInArray > 0 ) {
zCModelPrototype* prototype = prototypes->Array[0];
if ( prototype ) {
return *reinterpret_cast<DWORD*>(reinterpret_cast<DWORD>(prototype) + 0x08); // Get reference counter
}
}
return 2; // Allow leakage because it is only container for 3DS models(mob) - better than crash
}

zCArray<zCModelNodeInst*>* GetNodeList() {
return (zCArray<zCModelNodeInst*>*)THISPTR_OFFSET( GothicMemoryLocations::zCModel::Offset_NodeList );
}
Expand Down

0 comments on commit 00764c0

Please # to comment.