Fix crash when using and saving scene with Visual Script object instance which asset was deleted
This commit is contained in:
@@ -1522,12 +1522,16 @@ void VisualScript::unload(bool isReloading)
|
|||||||
if (_scriptingTypeHandle)
|
if (_scriptingTypeHandle)
|
||||||
{
|
{
|
||||||
VisualScriptingBinaryModule::Locker.Lock();
|
VisualScriptingBinaryModule::Locker.Lock();
|
||||||
auto& type = VisualScriptingModule.Types[_scriptingTypeHandle.TypeIndex];
|
ScriptingType& type = VisualScriptingModule.Types[_scriptingTypeHandle.TypeIndex];
|
||||||
if (type.Script.DefaultInstance)
|
if (type.Script.DefaultInstance)
|
||||||
{
|
{
|
||||||
Delete(type.Script.DefaultInstance);
|
Delete(type.Script.DefaultInstance);
|
||||||
type.Script.DefaultInstance = nullptr;
|
type.Script.DefaultInstance = nullptr;
|
||||||
}
|
}
|
||||||
|
char* typeName = (char*)Allocator::Allocate(sizeof(_typenameChars));
|
||||||
|
Platform::MemoryCopy(typeName, _typenameChars, sizeof(_typenameChars));
|
||||||
|
((StringAnsiView&)type.Fullname) = StringAnsiView(typeName, 32);
|
||||||
|
VisualScriptingModule._unloadedScriptTypeNames.Add(typeName);
|
||||||
VisualScriptingModule.TypeNameToTypeIndex.RemoveValue(_scriptingTypeHandle.TypeIndex);
|
VisualScriptingModule.TypeNameToTypeIndex.RemoveValue(_scriptingTypeHandle.TypeIndex);
|
||||||
VisualScriptingModule.Scripts[_scriptingTypeHandle.TypeIndex] = nullptr;
|
VisualScriptingModule.Scripts[_scriptingTypeHandle.TypeIndex] = nullptr;
|
||||||
_scriptingTypeHandleCached = _scriptingTypeHandle;
|
_scriptingTypeHandleCached = _scriptingTypeHandle;
|
||||||
@@ -1653,6 +1657,8 @@ VisualScriptingBinaryModule::VisualScriptingBinaryModule()
|
|||||||
ScriptingObject* VisualScriptingBinaryModule::VisualScriptObjectSpawn(const ScriptingObjectSpawnParams& params)
|
ScriptingObject* VisualScriptingBinaryModule::VisualScriptObjectSpawn(const ScriptingObjectSpawnParams& params)
|
||||||
{
|
{
|
||||||
// Create native object (base type can be C++ or C#)
|
// Create native object (base type can be C++ or C#)
|
||||||
|
if (params.Type.Module == nullptr)
|
||||||
|
return nullptr;
|
||||||
ScriptingType& visualScriptType = (ScriptingType&)params.Type.GetType();
|
ScriptingType& visualScriptType = (ScriptingType&)params.Type.GetType();
|
||||||
ScriptingTypeHandle baseTypeHandle = visualScriptType.GetBaseType();
|
ScriptingTypeHandle baseTypeHandle = visualScriptType.GetBaseType();
|
||||||
const ScriptingType* baseTypePtr = &baseTypeHandle.GetType();
|
const ScriptingType* baseTypePtr = &baseTypeHandle.GetType();
|
||||||
@@ -1663,9 +1669,7 @@ ScriptingObject* VisualScriptingBinaryModule::VisualScriptObjectSpawn(const Scri
|
|||||||
}
|
}
|
||||||
ScriptingObject* object = baseTypePtr->Script.Spawn(params);
|
ScriptingObject* object = baseTypePtr->Script.Spawn(params);
|
||||||
if (!object)
|
if (!object)
|
||||||
{
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
// Beware! Hacking vtables incoming! Undefined behaviors exploits! Low-level programming!
|
// Beware! Hacking vtables incoming! Undefined behaviors exploits! Low-level programming!
|
||||||
visualScriptType.HackObjectVTable(object, baseTypeHandle, 1);
|
visualScriptType.HackObjectVTable(object, baseTypeHandle, 1);
|
||||||
@@ -2060,6 +2064,11 @@ void VisualScriptingBinaryModule::Destroy(bool isReloading)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
BinaryModule::Destroy(isReloading);
|
BinaryModule::Destroy(isReloading);
|
||||||
|
|
||||||
|
// Free cached script typenames table
|
||||||
|
for (char* str : _unloadedScriptTypeNames)
|
||||||
|
Allocator::Free(str);
|
||||||
|
_unloadedScriptTypeNames.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptingTypeHandle VisualScript::GetScriptingType()
|
ScriptingTypeHandle VisualScript::GetScriptingType()
|
||||||
|
|||||||
@@ -305,6 +305,7 @@ class FLAXENGINE_API VisualScriptingBinaryModule : public BinaryModule
|
|||||||
friend VisualScript;
|
friend VisualScript;
|
||||||
private:
|
private:
|
||||||
StringAnsi _name;
|
StringAnsi _name;
|
||||||
|
Array<char*> _unloadedScriptTypeNames;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tries to find a method in a given scripting type by the method name and parameters count.
|
/// Tries to find a method in a given scripting type by the method name and parameters count.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>If the the type contains more than one method of the given name and parameters count the returned value can be non-deterministic (one of the matching methods).</remarks>
|
/// <remarks>If the type contains more than one method of the given name and parameters count the returned value can be non-deterministic (one of the matching methods).</remarks>
|
||||||
/// <param name="typeHandle">The type to find method inside it.</param>
|
/// <param name="typeHandle">The type to find method inside it.</param>
|
||||||
/// <param name="name">The method name.</param>
|
/// <param name="name">The method name.</param>
|
||||||
/// <param name="numParams">The method parameters count.</param>
|
/// <param name="numParams">The method parameters count.</param>
|
||||||
@@ -182,7 +182,7 @@ public:
|
|||||||
/// Gets the value of a given scripting field.
|
/// Gets the value of a given scripting field.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="field">The field.</param>
|
/// <param name="field">The field.</param>
|
||||||
/// <param name="instance">The object instance to get it's member field. Unused for static fields.</param>
|
/// <param name="instance">The object instance to get its member field. Unused for static fields.</param>
|
||||||
/// <param name="result">The output field value.</param>
|
/// <param name="result">The output field value.</param>
|
||||||
/// <returns>True if failed, otherwise false.</returns>
|
/// <returns>True if failed, otherwise false.</returns>
|
||||||
virtual bool GetFieldValue(void* field, const Variant& instance, Variant& result)
|
virtual bool GetFieldValue(void* field, const Variant& instance, Variant& result)
|
||||||
@@ -194,7 +194,7 @@ public:
|
|||||||
/// Sets the value of a given scripting field.
|
/// Sets the value of a given scripting field.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="field">The field.</param>
|
/// <param name="field">The field.</param>
|
||||||
/// <param name="instance">The object instance to set it's member field. Unused for static fields.</param>
|
/// <param name="instance">The object instance to set its member field. Unused for static fields.</param>
|
||||||
/// <param name="value">The field value to assign.</param>
|
/// <param name="value">The field value to assign.</param>
|
||||||
/// <returns>True if failed, otherwise false.</returns>
|
/// <returns>True if failed, otherwise false.</returns>
|
||||||
virtual bool SetFieldValue(void* field, const Variant& instance, Variant& value)
|
virtual bool SetFieldValue(void* field, const Variant& instance, Variant& value)
|
||||||
@@ -242,7 +242,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unloads the module (native library and C# assembly and any other scripting data). Unregisters the module.
|
/// Unloads the module (native library and C# assembly and any other scripting data). Unregisters the module.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="isReloading">If true module is during reloading and should force release the runtime data. Used for C# assembly to cleanup it's runtime data in Mono (or other scripting runtime).</param>
|
/// <param name="isReloading">If true module is during reloading and should force release the runtime data. Used for C# assembly to clean up it's runtime data in Mono (or other scripting runtime).</param>
|
||||||
virtual void Destroy(bool isReloading);
|
virtual void Destroy(bool isReloading);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user