BGE: fix crash and return boolean on scene.replace()

Scene replacement with invalid scene name was crashing blender,
now it's a no-op.
KS_Scene.replace() to return a boolean to indicate if the scene
is valid and is scheduled for replacement. This allows more
robust game management.
This commit is contained in:
Benoit Bolsee 2014-08-23 12:31:32 +02:00
parent a0600debda
commit fb49c5aa56
4 changed files with 32 additions and 11 deletions

@ -152,6 +152,8 @@ base class --- :class:`PyObjectPlus`
:arg scene: The name of the scene to replace this scene with. :arg scene: The name of the scene to replace this scene with.
:type scene: string :type scene: string
:return: True if the scene exists and was scheduled for addition, False otherwise.
:rtype: boolean
.. method:: suspend() .. method:: suspend()

@ -1732,9 +1732,20 @@ void KX_KetsjiEngine::AddScheduledScenes()
void KX_KetsjiEngine::ReplaceScene(const STR_String& oldscene,const STR_String& newscene) bool KX_KetsjiEngine::ReplaceScene(const STR_String& oldscene,const STR_String& newscene)
{ {
// Don't allow replacement if the new scene doesn't exists.
// Allows smarter game design (used to have no check here).
// Note that it creates a small backward compatbility issue
// for a game that did a replace followed by a lib load with the
// new scene in the lib => it won't work anymore, the lib
// must be loaded before doing the replace.
if (m_sceneconverter->GetBlenderSceneForName(newscene) != NULL)
{
m_replace_scenes.push_back(std::make_pair(oldscene,newscene)); m_replace_scenes.push_back(std::make_pair(oldscene,newscene));
return true;
}
return false;
} }
// replace scene is not the same as removing and adding because the // replace scene is not the same as removing and adding because the
@ -1761,10 +1772,16 @@ void KX_KetsjiEngine::ReplaceScheduledScenes()
KX_Scene* scene = *sceneit; KX_Scene* scene = *sceneit;
if (scene->GetName() == oldscenename) if (scene->GetName() == oldscenename)
{ {
// avoid crash if the new scene doesn't exist, just do nothing
Scene *blScene = m_sceneconverter->GetBlenderSceneForName(newscenename);
if (blScene) {
m_sceneconverter->RemoveScene(scene); m_sceneconverter->RemoveScene(scene);
KX_Scene* tmpscene = CreateScene(newscenename); KX_Scene* tmpscene = CreateScene(blScene);
m_scenes[i]=tmpscene; m_scenes[i]=tmpscene;
PostProcessScene(tmpscene); PostProcessScene(tmpscene);
} else {
printf("warning: scene %s could not be found, not replaced!\n",newscenename.ReadPtr());
}
} }
i++; i++;
} }

@ -258,7 +258,7 @@ public:
void ConvertAndAddScene(const STR_String& scenename,bool overlay); void ConvertAndAddScene(const STR_String& scenename,bool overlay);
void RemoveScene(const STR_String& scenename); void RemoveScene(const STR_String& scenename);
void ReplaceScene(const STR_String& oldscene,const STR_String& newscene); bool ReplaceScene(const STR_String& oldscene,const STR_String& newscene);
void SuspendScene(const STR_String& scenename); void SuspendScene(const STR_String& scenename);
void ResumeScene(const STR_String& scenename); void ResumeScene(const STR_String& scenename);

@ -2501,16 +2501,18 @@ KX_PYMETHODDEF_DOC(KX_Scene, restart,
KX_PYMETHODDEF_DOC(KX_Scene, replace, KX_PYMETHODDEF_DOC(KX_Scene, replace,
"replace(newScene)\n" "replace(newScene)\n"
"Replaces this scene with another one.\n") "Replaces this scene with another one.\n"
"Return True if the new scene exists and scheduled for replacement, False otherwise.\n")
{ {
char* name; char* name;
if (!PyArg_ParseTuple(args, "s:replace", &name)) if (!PyArg_ParseTuple(args, "s:replace", &name))
return NULL; return NULL;
KX_GetActiveEngine()->ReplaceScene(m_sceneName, name); if (KX_GetActiveEngine()->ReplaceScene(m_sceneName, name))
Py_RETURN_TRUE;
Py_RETURN_NONE; Py_RETURN_FALSE;
} }
KX_PYMETHODDEF_DOC(KX_Scene, suspend, KX_PYMETHODDEF_DOC(KX_Scene, suspend,