Add support for basic classes to Scripting Type (without scripting object as a base)
This commit is contained in:
@@ -1290,11 +1290,11 @@ Asset::LoadResult VisualScript::load()
|
||||
|
||||
// Hack vtable similarly to VisualScriptObjectSpawn
|
||||
ScriptingType& visualScriptType = (ScriptingType&)object->GetType();
|
||||
if (visualScriptType.Class.ScriptVTable)
|
||||
if (visualScriptType.Script.ScriptVTable)
|
||||
{
|
||||
// Override object vtable with hacked one that has Visual Script functions calls
|
||||
ASSERT(visualScriptType.Class.VTable);
|
||||
*(void**)object = visualScriptType.Class.VTable;
|
||||
ASSERT(visualScriptType.Script.VTable);
|
||||
*(void**)object = visualScriptType.Script.VTable;
|
||||
}
|
||||
}
|
||||
const int32 oldCount = _oldParamsLayout.Count();
|
||||
@@ -1361,10 +1361,10 @@ void VisualScript::unload(bool isReloading)
|
||||
if (_scriptingTypeHandle)
|
||||
{
|
||||
auto& type = VisualScriptingModule.Types[_scriptingTypeHandle.TypeIndex];
|
||||
if (type.Class.DefaultInstance)
|
||||
if (type.Script.DefaultInstance)
|
||||
{
|
||||
Delete(type.Class.DefaultInstance);
|
||||
type.Class.DefaultInstance = nullptr;
|
||||
Delete(type.Script.DefaultInstance);
|
||||
type.Script.DefaultInstance = nullptr;
|
||||
}
|
||||
VisualScriptingModule.TypeNameToTypeIndex.RemoveValue(_scriptingTypeHandle.TypeIndex);
|
||||
VisualScriptingModule.Scripts[_scriptingTypeHandle.TypeIndex] = nullptr;
|
||||
@@ -1389,7 +1389,7 @@ void VisualScript::CacheScriptingType()
|
||||
{
|
||||
// Find first native base C++ class of this Visual Script class
|
||||
ScriptingTypeHandle nativeType = baseType;
|
||||
while (nativeType && nativeType.GetType().Class.ScriptVTable)
|
||||
while (nativeType && nativeType.GetType().Script.ScriptVTable)
|
||||
{
|
||||
nativeType = nativeType.GetType().GetBaseType();
|
||||
}
|
||||
@@ -1437,14 +1437,14 @@ void VisualScript::CacheScriptingType()
|
||||
for (ScriptingTypeHandle e = nativeType; e;)
|
||||
{
|
||||
const ScriptingType& eType = e.GetType();
|
||||
if (eType.Class.SetupScriptVTable)
|
||||
if (eType.Script.SetupScriptVTable)
|
||||
{
|
||||
ASSERT(eType.ManagedClass);
|
||||
eType.Class.SetupScriptVTable(eType.ManagedClass, type.Class.ScriptVTable, type.Class.ScriptVTableBase);
|
||||
eType.Script.SetupScriptVTable(eType.ManagedClass, type.Script.ScriptVTable, type.Script.ScriptVTableBase);
|
||||
}
|
||||
e = eType.GetBaseType();
|
||||
}
|
||||
MMethod** scriptVTable = (MMethod**)type.Class.ScriptVTable;
|
||||
MMethod** scriptVTable = (MMethod**)type.Script.ScriptVTable;
|
||||
while (scriptVTable && *scriptVTable)
|
||||
{
|
||||
const MMethod* referenceMethod = *scriptVTable;
|
||||
@@ -1498,12 +1498,12 @@ ScriptingObject* VisualScriptingBinaryModule::VisualScriptObjectSpawn(const Scri
|
||||
ScriptingType& visualScriptType = (ScriptingType&)params.Type.GetType();
|
||||
ScriptingTypeHandle baseTypeHandle = visualScriptType.GetBaseType();
|
||||
const ScriptingType* baseTypePtr = &baseTypeHandle.GetType();
|
||||
while (baseTypePtr->Class.Spawn == &VisualScriptObjectSpawn)
|
||||
while (baseTypePtr->Script.Spawn == &VisualScriptObjectSpawn)
|
||||
{
|
||||
baseTypeHandle = baseTypePtr->GetBaseType();
|
||||
baseTypePtr = &baseTypeHandle.GetType();
|
||||
}
|
||||
ScriptingObject* object = baseTypePtr->Class.Spawn(params);
|
||||
ScriptingObject* object = baseTypePtr->Script.Spawn(params);
|
||||
if (!object)
|
||||
{
|
||||
return nullptr;
|
||||
@@ -1514,9 +1514,9 @@ ScriptingObject* VisualScriptingBinaryModule::VisualScriptObjectSpawn(const Scri
|
||||
// We create a custom vtable for the Visual Script objects that use a native class object with virtual functions overrides.
|
||||
// To make it easy to use in C++ we inject custom wrapper methods into C++ object vtable to execute Visual Script graph from them.
|
||||
// Because virtual member functions calls are C++ ABI and impl-defined this is quite hard. But works.
|
||||
if (visualScriptType.Class.ScriptVTable)
|
||||
if (visualScriptType.Script.ScriptVTable)
|
||||
{
|
||||
if (!visualScriptType.Class.VTable)
|
||||
if (!visualScriptType.Script.VTable)
|
||||
{
|
||||
// Duplicate vtable
|
||||
void** vtable = *(void***)object;
|
||||
@@ -1525,21 +1525,21 @@ ScriptingObject* VisualScriptingBinaryModule::VisualScriptObjectSpawn(const Scri
|
||||
while (vtable[entriesCount] && entriesCount < 200)
|
||||
entriesCount++;
|
||||
const int32 size = entriesCount * sizeof(void*);
|
||||
visualScriptType.Class.VTable = (void**)((byte*)Platform::Allocate(prefixSize + size, 16) + prefixSize);
|
||||
Platform::MemoryCopy((byte*)visualScriptType.Class.VTable - prefixSize, (byte*)vtable - prefixSize, prefixSize + size);
|
||||
visualScriptType.Script.VTable = (void**)((byte*)Platform::Allocate(prefixSize + size, 16) + prefixSize);
|
||||
Platform::MemoryCopy((byte*)visualScriptType.Script.VTable - prefixSize, (byte*)vtable - prefixSize, prefixSize + size);
|
||||
|
||||
// Override vtable entries by the class
|
||||
for (ScriptingTypeHandle e = baseTypeHandle; e;)
|
||||
{
|
||||
const ScriptingType& eType = e.GetType();
|
||||
if (eType.Class.SetupScriptObjectVTable)
|
||||
eType.Class.SetupScriptObjectVTable(visualScriptType.Class.ScriptVTable, visualScriptType.Class.ScriptVTableBase, visualScriptType.Class.VTable, entriesCount, 1);
|
||||
if (eType.Script.SetupScriptObjectVTable)
|
||||
eType.Script.SetupScriptObjectVTable(visualScriptType.Script.ScriptVTable, visualScriptType.Script.ScriptVTableBase, visualScriptType.Script.VTable, entriesCount, 1);
|
||||
e = eType.GetBaseType();
|
||||
}
|
||||
}
|
||||
|
||||
// Override object vtable with hacked one that has Visual Script functions calls
|
||||
*(void**)object = visualScriptType.Class.VTable;
|
||||
*(void**)object = visualScriptType.Script.VTable;
|
||||
}
|
||||
|
||||
// Mark as custom scripting type
|
||||
@@ -1573,10 +1573,10 @@ void VisualScriptingBinaryModule::OnScriptsReloading()
|
||||
if (script->_scriptingTypeHandle)
|
||||
{
|
||||
auto& type = VisualScriptingModule.Types[script->_scriptingTypeHandle.TypeIndex];
|
||||
if (type.Class.DefaultInstance)
|
||||
if (type.Script.DefaultInstance)
|
||||
{
|
||||
Delete(type.Class.DefaultInstance);
|
||||
type.Class.DefaultInstance = nullptr;
|
||||
Delete(type.Script.DefaultInstance);
|
||||
type.Script.DefaultInstance = nullptr;
|
||||
}
|
||||
VisualScriptingModule.TypeNameToTypeIndex.RemoveValue(script->_scriptingTypeHandle.TypeIndex);
|
||||
script->_scriptingTypeHandleCached = script->_scriptingTypeHandle;
|
||||
@@ -1862,7 +1862,7 @@ ScriptingTypeHandle VisualScript::GetScriptingType()
|
||||
ScriptingObject* VisualScript::CreateInstance()
|
||||
{
|
||||
const auto scriptingTypeHandle = GetScriptingType();
|
||||
return scriptingTypeHandle ? scriptingTypeHandle.GetType().Class.Spawn(ScriptingObjectSpawnParams(Guid::New(), scriptingTypeHandle)) : nullptr;
|
||||
return scriptingTypeHandle ? scriptingTypeHandle.GetType().Script.Spawn(ScriptingObjectSpawnParams(Guid::New(), scriptingTypeHandle)) : nullptr;
|
||||
}
|
||||
|
||||
Variant VisualScript::GetScriptInstanceParameterValue(const StringView& name, ScriptingObject* instance) const
|
||||
|
||||
@@ -79,7 +79,7 @@ SceneObject* SceneObjectsFactory::Spawn(ISerializable::DeserializeStream& stream
|
||||
if (type)
|
||||
{
|
||||
const ScriptingObjectSpawnParams params(id, type);
|
||||
obj = (SceneObject*)type.GetType().Class.Spawn(params);
|
||||
obj = (SceneObject*)type.GetType().Script.Spawn(params);
|
||||
if (obj == nullptr)
|
||||
{
|
||||
LOG(Warning, "Failed to spawn object of type {0}.", type.ToString(true));
|
||||
@@ -109,7 +109,7 @@ SceneObject* SceneObjectsFactory::Spawn(ISerializable::DeserializeStream& stream
|
||||
if (type)
|
||||
{
|
||||
const ScriptingObjectSpawnParams params(id, type);
|
||||
obj = (SceneObject*)type.GetType().Class.Spawn(params);
|
||||
obj = (SceneObject*)type.GetType().Script.Spawn(params);
|
||||
if (obj == nullptr)
|
||||
{
|
||||
LOG(Warning, "Failed to spawn object of type {0}.", type.ToString(true));
|
||||
@@ -384,7 +384,7 @@ Actor* SceneObjectsFactory::CreateActor(int32 typeId, const Guid& id)
|
||||
if (type)
|
||||
{
|
||||
const ScriptingObjectSpawnParams params(id, type);
|
||||
const auto result = dynamic_cast<Actor*>(type.GetType().Class.Spawn(params));
|
||||
const auto result = dynamic_cast<Actor*>(type.GetType().Script.Spawn(params));
|
||||
if (result == nullptr)
|
||||
{
|
||||
LOG(Warning, "Failed to spawn object of type {0}.", type.ToString(true));
|
||||
|
||||
@@ -60,16 +60,16 @@ ScriptingType::ScriptingType()
|
||||
, Module(nullptr)
|
||||
, InitRuntime(nullptr)
|
||||
, Fullname(nullptr, 0)
|
||||
, Type(ScriptingTypes::Class)
|
||||
, Type(ScriptingTypes::Script)
|
||||
, BaseTypePtr(nullptr)
|
||||
{
|
||||
Class.Spawn = nullptr;
|
||||
Class.VTable = nullptr;
|
||||
Class.ScriptVTable = nullptr;
|
||||
Class.ScriptVTableBase = nullptr;
|
||||
Class.SetupScriptVTable = nullptr;
|
||||
Class.SetupScriptObjectVTable = nullptr;
|
||||
Class.DefaultInstance = nullptr;
|
||||
Script.Spawn = nullptr;
|
||||
Script.VTable = nullptr;
|
||||
Script.ScriptVTable = nullptr;
|
||||
Script.ScriptVTableBase = nullptr;
|
||||
Script.SetupScriptVTable = nullptr;
|
||||
Script.SetupScriptObjectVTable = nullptr;
|
||||
Script.DefaultInstance = nullptr;
|
||||
}
|
||||
|
||||
ScriptingType::ScriptingType(const StringAnsiView& fullname, BinaryModule* module, int32 size, InitRuntimeHandler initRuntime, SpawnHandler spawn, const ScriptingTypeHandle& baseType, SetupScriptVTableHandler setupScriptVTable, SetupScriptObjectVTableHandler setupScriptObjectVTable)
|
||||
@@ -77,21 +77,39 @@ ScriptingType::ScriptingType(const StringAnsiView& fullname, BinaryModule* modul
|
||||
, Module(module)
|
||||
, InitRuntime(initRuntime)
|
||||
, Fullname(fullname)
|
||||
, Type(ScriptingTypes::Class)
|
||||
, Type(ScriptingTypes::Script)
|
||||
, BaseTypeHandle(baseType)
|
||||
, BaseTypePtr(nullptr)
|
||||
, Size(size)
|
||||
{
|
||||
Class.Spawn = spawn;
|
||||
Class.VTable = nullptr;
|
||||
Class.ScriptVTable = nullptr;
|
||||
Class.ScriptVTableBase = nullptr;
|
||||
Class.SetupScriptVTable = setupScriptVTable;
|
||||
Class.SetupScriptObjectVTable = setupScriptObjectVTable;
|
||||
Class.DefaultInstance = nullptr;
|
||||
Script.Spawn = spawn;
|
||||
Script.VTable = nullptr;
|
||||
Script.ScriptVTable = nullptr;
|
||||
Script.ScriptVTableBase = nullptr;
|
||||
Script.SetupScriptVTable = setupScriptVTable;
|
||||
Script.SetupScriptObjectVTable = setupScriptObjectVTable;
|
||||
Script.DefaultInstance = nullptr;
|
||||
}
|
||||
|
||||
ScriptingType::ScriptingType(const StringAnsiView& fullname, BinaryModule* module, int32 size, InitRuntimeHandler initRuntime, SpawnHandler spawn, ScriptingTypeInitializer* baseType, SetupScriptVTableHandler setupScriptVTable, SetupScriptObjectVTableHandler setupScriptObjectVTable)
|
||||
: ManagedClass(nullptr)
|
||||
, Module(module)
|
||||
, InitRuntime(initRuntime)
|
||||
, Fullname(fullname)
|
||||
, Type(ScriptingTypes::Script)
|
||||
, BaseTypePtr(baseType)
|
||||
, Size(size)
|
||||
{
|
||||
Script.Spawn = spawn;
|
||||
Script.VTable = nullptr;
|
||||
Script.ScriptVTable = nullptr;
|
||||
Script.ScriptVTableBase = nullptr;
|
||||
Script.SetupScriptVTable = setupScriptVTable;
|
||||
Script.SetupScriptObjectVTable = setupScriptObjectVTable;
|
||||
Script.DefaultInstance = nullptr;
|
||||
}
|
||||
|
||||
ScriptingType::ScriptingType(const StringAnsiView& fullname, BinaryModule* module, int32 size, InitRuntimeHandler initRuntime, Ctor ctor, Dtor dtor, ScriptingTypeInitializer* baseType)
|
||||
: ManagedClass(nullptr)
|
||||
, Module(module)
|
||||
, InitRuntime(initRuntime)
|
||||
@@ -100,13 +118,8 @@ ScriptingType::ScriptingType(const StringAnsiView& fullname, BinaryModule* modul
|
||||
, BaseTypePtr(baseType)
|
||||
, Size(size)
|
||||
{
|
||||
Class.Spawn = spawn;
|
||||
Class.VTable = nullptr;
|
||||
Class.ScriptVTable = nullptr;
|
||||
Class.ScriptVTableBase = nullptr;
|
||||
Class.SetupScriptVTable = setupScriptVTable;
|
||||
Class.SetupScriptObjectVTable = setupScriptObjectVTable;
|
||||
Class.DefaultInstance = nullptr;
|
||||
Class.Ctor = ctor;
|
||||
Class.Dtor = dtor;
|
||||
}
|
||||
|
||||
ScriptingType::ScriptingType(const StringAnsiView& fullname, BinaryModule* module, int32 size, InitRuntimeHandler initRuntime, Ctor ctor, Dtor dtor, Copy copy, Box box, Unbox unbox, GetField getField, SetField setField, ScriptingTypeInitializer* baseType)
|
||||
@@ -139,14 +152,14 @@ ScriptingType::ScriptingType(const ScriptingType& other)
|
||||
{
|
||||
switch (other.Type)
|
||||
{
|
||||
case ScriptingTypes::Class:
|
||||
Class.Spawn = other.Class.Spawn;
|
||||
Class.VTable = nullptr;
|
||||
Class.ScriptVTable = nullptr;
|
||||
Class.ScriptVTableBase = nullptr;
|
||||
Class.SetupScriptVTable = other.Class.SetupScriptVTable;
|
||||
Class.SetupScriptObjectVTable = other.Class.SetupScriptObjectVTable;
|
||||
Class.DefaultInstance = nullptr;
|
||||
case ScriptingTypes::Script:
|
||||
Script.Spawn = other.Script.Spawn;
|
||||
Script.VTable = nullptr;
|
||||
Script.ScriptVTable = nullptr;
|
||||
Script.ScriptVTableBase = nullptr;
|
||||
Script.SetupScriptVTable = other.Script.SetupScriptVTable;
|
||||
Script.SetupScriptObjectVTable = other.Script.SetupScriptObjectVTable;
|
||||
Script.DefaultInstance = nullptr;
|
||||
break;
|
||||
case ScriptingTypes::Structure:
|
||||
Struct.Ctor = other.Struct.Ctor;
|
||||
@@ -175,18 +188,18 @@ ScriptingType::ScriptingType(ScriptingType&& other)
|
||||
{
|
||||
switch (other.Type)
|
||||
{
|
||||
case ScriptingTypes::Class:
|
||||
Class.Spawn = other.Class.Spawn;
|
||||
Class.VTable = other.Class.VTable;
|
||||
other.Class.VTable = nullptr;
|
||||
Class.ScriptVTable = other.Class.ScriptVTable;
|
||||
other.Class.ScriptVTable = nullptr;
|
||||
Class.ScriptVTableBase = other.Class.ScriptVTableBase;
|
||||
other.Class.ScriptVTableBase = nullptr;
|
||||
Class.SetupScriptVTable = other.Class.SetupScriptVTable;
|
||||
Class.SetupScriptObjectVTable = other.Class.SetupScriptObjectVTable;
|
||||
Class.DefaultInstance = other.Class.DefaultInstance;
|
||||
other.Class.DefaultInstance = nullptr;
|
||||
case ScriptingTypes::Script:
|
||||
Script.Spawn = other.Script.Spawn;
|
||||
Script.VTable = other.Script.VTable;
|
||||
other.Script.VTable = nullptr;
|
||||
Script.ScriptVTable = other.Script.ScriptVTable;
|
||||
other.Script.ScriptVTable = nullptr;
|
||||
Script.ScriptVTableBase = other.Script.ScriptVTableBase;
|
||||
other.Script.ScriptVTableBase = nullptr;
|
||||
Script.SetupScriptVTable = other.Script.SetupScriptVTable;
|
||||
Script.SetupScriptObjectVTable = other.Script.SetupScriptObjectVTable;
|
||||
Script.DefaultInstance = other.Script.DefaultInstance;
|
||||
other.Script.DefaultInstance = nullptr;
|
||||
break;
|
||||
case ScriptingTypes::Structure:
|
||||
Struct.Ctor = other.Struct.Ctor;
|
||||
@@ -207,13 +220,13 @@ ScriptingType::~ScriptingType()
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case ScriptingTypes::Class:
|
||||
if (Class.DefaultInstance)
|
||||
Delete(Class.DefaultInstance);
|
||||
if (Class.VTable)
|
||||
Platform::Free((byte*)Class.VTable - GetVTablePrefix());
|
||||
Platform::Free(Class.ScriptVTable);
|
||||
Platform::Free(Class.ScriptVTableBase);
|
||||
case ScriptingTypes::Script:
|
||||
if (Script.DefaultInstance)
|
||||
Delete(Script.DefaultInstance);
|
||||
if (Script.VTable)
|
||||
Platform::Free((byte*)Script.VTable - GetVTablePrefix());
|
||||
Platform::Free(Script.ScriptVTable);
|
||||
Platform::Free(Script.ScriptVTableBase);
|
||||
break;
|
||||
case ScriptingTypes::Structure:
|
||||
break;
|
||||
@@ -235,17 +248,17 @@ ScriptingTypeHandle ScriptingType::GetHandle() const
|
||||
|
||||
ScriptingObject* ScriptingType::GetDefaultInstance() const
|
||||
{
|
||||
ASSERT(Type == ScriptingTypes::Class);
|
||||
if (!Class.DefaultInstance)
|
||||
ASSERT(Type == ScriptingTypes::Script);
|
||||
if (!Script.DefaultInstance)
|
||||
{
|
||||
const ScriptingObjectSpawnParams params(Guid::New(), GetHandle());
|
||||
Class.DefaultInstance = Class.Spawn(params);
|
||||
if (!Class.DefaultInstance)
|
||||
Script.DefaultInstance = Script.Spawn(params);
|
||||
if (!Script.DefaultInstance)
|
||||
{
|
||||
LOG(Error, "Failed to create default instance of type {0}", ToString());
|
||||
}
|
||||
}
|
||||
return Class.DefaultInstance;
|
||||
return Script.DefaultInstance;
|
||||
}
|
||||
|
||||
String ScriptingType::ToString() const
|
||||
@@ -268,6 +281,21 @@ ScriptingTypeInitializer::ScriptingTypeInitializer(BinaryModule* module, const S
|
||||
module->TypeNameToTypeIndex[typeName] = TypeIndex;
|
||||
}
|
||||
|
||||
ScriptingTypeInitializer::ScriptingTypeInitializer(BinaryModule* module, const StringAnsiView& fullname, int32 size, ScriptingType::InitRuntimeHandler initRuntime, ScriptingType::Ctor ctor, ScriptingType::Dtor dtor, ScriptingTypeInitializer* baseType)
|
||||
: ScriptingTypeHandle(module, module->Types.Count())
|
||||
{
|
||||
module->Types.AddUninitialized();
|
||||
new(module->Types.Get() + TypeIndex)ScriptingType(fullname, module, size, initRuntime, ctor, dtor, baseType);
|
||||
const MString typeName(fullname.Get(), fullname.Length());
|
||||
#if BUILD_DEBUG
|
||||
if (module->TypeNameToTypeIndex.ContainsKey(typeName))
|
||||
{
|
||||
LOG(Error, "Duplicated native typename {0} from module {1}.", String(fullname), String(module->GetName()));
|
||||
}
|
||||
#endif
|
||||
module->TypeNameToTypeIndex[typeName] = TypeIndex;
|
||||
}
|
||||
|
||||
ScriptingTypeInitializer::ScriptingTypeInitializer(BinaryModule* module, const StringAnsiView& fullname, int32 size, ScriptingType::InitRuntimeHandler initRuntime, ScriptingType::Ctor ctor, ScriptingType::Dtor dtor, ScriptingType::Copy copy, ScriptingType::Box box, ScriptingType::Unbox unbox, ScriptingType::GetField getField, ScriptingType::SetField setField, ScriptingTypeInitializer* baseType)
|
||||
: ScriptingTypeHandle(module, module->Types.Count())
|
||||
{
|
||||
@@ -368,7 +396,7 @@ ScriptingObject* ManagedBinaryModule::ManagedObjectSpawn(const ScriptingObjectSp
|
||||
// Create native object
|
||||
ScriptingTypeHandle managedTypeHandle = params.Type;
|
||||
const ScriptingType* managedTypePtr = &managedTypeHandle.GetType();
|
||||
while (managedTypePtr->Class.Spawn != &ManagedObjectSpawn)
|
||||
while (managedTypePtr->Script.Spawn != &ManagedObjectSpawn)
|
||||
{
|
||||
managedTypeHandle = managedTypePtr->GetBaseType();
|
||||
managedTypePtr = &managedTypeHandle.GetType();
|
||||
@@ -376,12 +404,12 @@ ScriptingObject* ManagedBinaryModule::ManagedObjectSpawn(const ScriptingObjectSp
|
||||
ScriptingType& managedType = (ScriptingType&)*managedTypePtr;
|
||||
ScriptingTypeHandle nativeTypeHandle = managedType.GetBaseType();
|
||||
const ScriptingType* nativeTypePtr = &nativeTypeHandle.GetType();
|
||||
while (nativeTypePtr->Class.Spawn == &ManagedObjectSpawn)
|
||||
while (nativeTypePtr->Script.Spawn == &ManagedObjectSpawn)
|
||||
{
|
||||
nativeTypeHandle = nativeTypePtr->GetBaseType();
|
||||
nativeTypePtr = &nativeTypeHandle.GetType();
|
||||
}
|
||||
ScriptingObject* object = nativeTypePtr->Class.Spawn(params);
|
||||
ScriptingObject* object = nativeTypePtr->Script.Spawn(params);
|
||||
if (!object)
|
||||
{
|
||||
return nullptr;
|
||||
@@ -392,9 +420,9 @@ ScriptingObject* ManagedBinaryModule::ManagedObjectSpawn(const ScriptingObjectSp
|
||||
// We create a custom vtable for the C# objects that use a native class object with virtual functions overrides.
|
||||
// To make it easy to use in C++ we inject custom wrapper methods into C++ object vtable to call C# code from them.
|
||||
// Because virtual member functions calls are C++ ABI and impl-defined this is quite hard. But works.
|
||||
if (managedType.Class.ScriptVTable)
|
||||
if (managedType.Script.ScriptVTable)
|
||||
{
|
||||
if (!managedType.Class.VTable)
|
||||
if (!managedType.Script.VTable)
|
||||
{
|
||||
// Duplicate vtable
|
||||
void** vtable = *(void***)object;
|
||||
@@ -403,23 +431,23 @@ ScriptingObject* ManagedBinaryModule::ManagedObjectSpawn(const ScriptingObjectSp
|
||||
while (vtable[entriesCount] && entriesCount < 200)
|
||||
entriesCount++;
|
||||
const int32 size = entriesCount * sizeof(void*);
|
||||
managedType.Class.VTable = (void**)((byte*)Platform::Allocate(prefixSize + size, 16) + prefixSize);
|
||||
Platform::MemoryCopy((byte*)managedType.Class.VTable - prefixSize, (byte*)vtable - prefixSize, prefixSize + size);
|
||||
managedType.Script.VTable = (void**)((byte*)Platform::Allocate(prefixSize + size, 16) + prefixSize);
|
||||
Platform::MemoryCopy((byte*)managedType.Script.VTable - prefixSize, (byte*)vtable - prefixSize, prefixSize + size);
|
||||
|
||||
// Override vtable entries by the class
|
||||
for (ScriptingTypeHandle e = nativeTypeHandle; e;)
|
||||
{
|
||||
const ScriptingType& eType = e.GetType();
|
||||
if (eType.Class.SetupScriptObjectVTable)
|
||||
if (eType.Script.SetupScriptObjectVTable)
|
||||
{
|
||||
eType.Class.SetupScriptObjectVTable(managedType.Class.ScriptVTable, managedType.Class.ScriptVTableBase, managedType.Class.VTable, entriesCount, 0);
|
||||
eType.Script.SetupScriptObjectVTable(managedType.Script.ScriptVTable, managedType.Script.ScriptVTableBase, managedType.Script.VTable, entriesCount, 0);
|
||||
}
|
||||
e = eType.GetBaseType();
|
||||
}
|
||||
}
|
||||
|
||||
// Override object vtable with hacked one that has C# functions calls
|
||||
*(void**)object = managedType.Class.VTable;
|
||||
*(void**)object = managedType.Script.VTable;
|
||||
}
|
||||
|
||||
// Mark as managed type
|
||||
@@ -557,7 +585,7 @@ void ManagedBinaryModule::OnLoaded(MAssembly* assembly)
|
||||
if (baseClassModule->TypeNameToTypeIndex.TryGet(baseClass->GetFullName(), typeIndex))
|
||||
{
|
||||
nativeType = ScriptingTypeHandle(baseClassModule, typeIndex);
|
||||
if (nativeType.GetType().Class.Spawn != &ManagedObjectSpawn)
|
||||
if (nativeType.GetType().Script.Spawn != &ManagedObjectSpawn)
|
||||
break;
|
||||
}
|
||||
baseClass = baseClass->GetBaseClass();
|
||||
@@ -592,14 +620,14 @@ void ManagedBinaryModule::OnLoaded(MAssembly* assembly)
|
||||
for (ScriptingTypeHandle e = nativeType; e;)
|
||||
{
|
||||
const ScriptingType& eType = e.GetType();
|
||||
if (eType.Class.SetupScriptVTable)
|
||||
if (eType.Script.SetupScriptVTable)
|
||||
{
|
||||
ASSERT(eType.ManagedClass);
|
||||
eType.Class.SetupScriptVTable(eType.ManagedClass, type.Class.ScriptVTable, type.Class.ScriptVTableBase);
|
||||
eType.Script.SetupScriptVTable(eType.ManagedClass, type.Script.ScriptVTable, type.Script.ScriptVTableBase);
|
||||
}
|
||||
e = eType.GetBaseType();
|
||||
}
|
||||
MMethod** scriptVTable = (MMethod**)type.Class.ScriptVTable;
|
||||
MMethod** scriptVTable = (MMethod**)type.Script.ScriptVTable;
|
||||
while (scriptVTable && *scriptVTable)
|
||||
{
|
||||
const MMethod* referenceMethod = *scriptVTable;
|
||||
@@ -657,10 +685,10 @@ void ManagedBinaryModule::OnUnloading(MAssembly* assembly)
|
||||
for (ScriptingType& type : Types)
|
||||
{
|
||||
type.ManagedClass = nullptr;
|
||||
if (type.Type == ScriptingTypes::Class && type.Class.ScriptVTable)
|
||||
if (type.Type == ScriptingTypes::Script && type.Script.ScriptVTable)
|
||||
{
|
||||
Platform::Free(type.Class.ScriptVTable);
|
||||
type.Class.ScriptVTable = nullptr;
|
||||
Platform::Free(type.Script.ScriptVTable);
|
||||
type.Script.ScriptVTable = nullptr;
|
||||
}
|
||||
}
|
||||
ClassToTypeIndex.Clear();
|
||||
|
||||
@@ -186,9 +186,9 @@ void Script::SetupType()
|
||||
while (typeHandle != Script::TypeInitializer)
|
||||
{
|
||||
auto& type = typeHandle.GetType();
|
||||
_tickUpdate |= type.Class.ScriptVTable[8] != nullptr;
|
||||
_tickLateUpdate |= type.Class.ScriptVTable[9] != nullptr;
|
||||
_tickFixedUpdate |= type.Class.ScriptVTable[10] != nullptr;
|
||||
_tickUpdate |= type.Script.ScriptVTable[8] != nullptr;
|
||||
_tickLateUpdate |= type.Script.ScriptVTable[9] != nullptr;
|
||||
_tickFixedUpdate |= type.Script.ScriptVTable[10] != nullptr;
|
||||
typeHandle = type.GetBaseType();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,7 +371,7 @@ public:
|
||||
|
||||
// Create unmanaged object
|
||||
const ScriptingObjectSpawnParams params(Guid::New(), ScriptingTypeHandle(module, typeIndex));
|
||||
ScriptingObject* obj = scriptingType.Class.Spawn(params);
|
||||
ScriptingObject* obj = scriptingType.Script.Spawn(params);
|
||||
if (obj == nullptr)
|
||||
{
|
||||
LOG(Error, "Failed to spawn object of type \'{0}.{1}\'.", String(mono_class_get_namespace(typeClass)), String(mono_class_get_name(typeClass)));
|
||||
@@ -414,7 +414,7 @@ public:
|
||||
|
||||
// Create unmanaged object
|
||||
const ScriptingObjectSpawnParams params(Guid::New(), type);
|
||||
ScriptingObject* obj = type.GetType().Class.Spawn(params);
|
||||
ScriptingObject* obj = type.GetType().Script.Spawn(params);
|
||||
if (obj == nullptr)
|
||||
{
|
||||
LOG(Error, "Failed to spawn object of type \'{0}\'.", String(typeName));
|
||||
@@ -468,7 +468,7 @@ public:
|
||||
|
||||
// Create unmanaged object
|
||||
const ScriptingObjectSpawnParams params(Guid::New(), ScriptingTypeHandle(module, typeIndex));
|
||||
ScriptingObject* obj = scriptingType.Class.Spawn(params);
|
||||
ScriptingObject* obj = scriptingType.Script.Spawn(params);
|
||||
if (obj == nullptr)
|
||||
{
|
||||
LOG(Error, "Failed to spawn object of type \'{0}.{1}\'.", String(mono_class_get_namespace(typeClass)), String(mono_class_get_name(typeClass)));
|
||||
|
||||
@@ -93,9 +93,10 @@ inline uint32 GetHash(const ScriptingTypeHandle& key)
|
||||
/// </summary>
|
||||
enum class ScriptingTypes
|
||||
{
|
||||
Class = 0,
|
||||
Script = 0,
|
||||
Structure = 1,
|
||||
Enum = 2,
|
||||
Class = 3,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -193,6 +194,15 @@ struct FLAXENGINE_API ScriptingType
|
||||
/// The default instance of the scripting type. Used by serialization system for comparision to save only modified properties of the object.
|
||||
/// </summary>
|
||||
mutable ScriptingObject* DefaultInstance;
|
||||
} Script;
|
||||
|
||||
struct
|
||||
{
|
||||
// Class constructor method pointer
|
||||
Ctor Ctor;
|
||||
|
||||
// Class destructor method pointer
|
||||
Dtor Dtor;
|
||||
} Class;
|
||||
|
||||
struct
|
||||
@@ -223,6 +233,7 @@ struct FLAXENGINE_API ScriptingType
|
||||
ScriptingType();
|
||||
ScriptingType(const StringAnsiView& fullname, BinaryModule* module, int32 size, InitRuntimeHandler initRuntime, SpawnHandler spawn, const ScriptingTypeHandle& baseType, SetupScriptVTableHandler setupScriptVTable = nullptr, SetupScriptObjectVTableHandler setupScriptObjectVTable = nullptr);
|
||||
ScriptingType(const StringAnsiView& fullname, BinaryModule* module, int32 size, InitRuntimeHandler initRuntime = DefaultInitRuntime, SpawnHandler spawn = DefaultSpawn, ScriptingTypeInitializer* baseType = nullptr, SetupScriptVTableHandler setupScriptVTable = nullptr, SetupScriptObjectVTableHandler setupScriptObjectVTable = nullptr);
|
||||
ScriptingType(const StringAnsiView& fullname, BinaryModule* module, int32 size, InitRuntimeHandler initRuntime, Ctor ctor, Dtor dtor, ScriptingTypeInitializer* baseType);
|
||||
ScriptingType(const StringAnsiView& fullname, BinaryModule* module, int32 size, InitRuntimeHandler initRuntime, Ctor ctor, Dtor dtor, Copy copy, Box box, Unbox unbox, GetField getField, SetField setField, ScriptingTypeInitializer* baseType);
|
||||
ScriptingType(const ScriptingType& other);
|
||||
ScriptingType(ScriptingType&& other);
|
||||
@@ -268,6 +279,7 @@ struct FLAXENGINE_API ScriptingType
|
||||
struct FLAXENGINE_API ScriptingTypeInitializer : ScriptingTypeHandle
|
||||
{
|
||||
ScriptingTypeInitializer(BinaryModule* module, const StringAnsiView& fullname, int32 size, ScriptingType::InitRuntimeHandler initRuntime = ScriptingType::DefaultInitRuntime, ScriptingType::SpawnHandler spawn = ScriptingType::DefaultSpawn, ScriptingTypeInitializer* baseType = nullptr, ScriptingType::SetupScriptVTableHandler setupScriptVTable = nullptr, ScriptingType::SetupScriptObjectVTableHandler setupScriptObjectVTable = nullptr);
|
||||
ScriptingTypeInitializer(BinaryModule* module, const StringAnsiView& fullname, int32 size, ScriptingType::InitRuntimeHandler initRuntime, ScriptingType::Ctor ctor, ScriptingType::Dtor dtor, ScriptingTypeInitializer* baseType = nullptr);
|
||||
ScriptingTypeInitializer(BinaryModule* module, const StringAnsiView& fullname, int32 size, ScriptingType::InitRuntimeHandler initRuntime, ScriptingType::Ctor ctor, ScriptingType::Dtor dtor, ScriptingType::Copy copy, ScriptingType::Box box, ScriptingType::Unbox unbox, ScriptingType::GetField getField, ScriptingType::SetField setField, ScriptingTypeInitializer* baseType = nullptr);
|
||||
};
|
||||
|
||||
|
||||
@@ -818,7 +818,7 @@ namespace Flax.Build.Bindings
|
||||
|
||||
contents.AppendLine(" ScriptingTypeHandle managedTypeHandle = object->GetTypeHandle();");
|
||||
contents.AppendLine(" const ScriptingType* managedTypePtr = &managedTypeHandle.GetType();");
|
||||
contents.AppendLine(" while (managedTypePtr->Class.Spawn != &ManagedBinaryModule::ManagedObjectSpawn)");
|
||||
contents.AppendLine(" while (managedTypePtr->Script.Spawn != &ManagedBinaryModule::ManagedObjectSpawn)");
|
||||
contents.AppendLine(" {");
|
||||
contents.AppendLine(" managedTypeHandle = managedTypePtr->GetBaseType();");
|
||||
contents.AppendLine(" managedTypePtr = &managedTypeHandle.GetType();");
|
||||
@@ -827,7 +827,7 @@ namespace Flax.Build.Bindings
|
||||
contents.AppendLine(" if (IsDuringWrapperCall)");
|
||||
contents.AppendLine(" {");
|
||||
contents.AppendLine(" // Prevent stack overflow by calling native base method");
|
||||
contents.AppendLine(" const auto scriptVTableBase = managedTypePtr->Class.ScriptVTableBase;");
|
||||
contents.AppendLine(" const auto scriptVTableBase = managedTypePtr->Script.ScriptVTableBase;");
|
||||
contents.Append($" return (object->**({functionInfo.UniqueName}_Signature*)&scriptVTableBase[{scriptVTableIndex} + 2])(");
|
||||
separator = false;
|
||||
for (var i = 0; i < functionInfo.Parameters.Count; i++)
|
||||
@@ -840,7 +840,7 @@ namespace Flax.Build.Bindings
|
||||
}
|
||||
contents.AppendLine(");");
|
||||
contents.AppendLine(" }");
|
||||
contents.AppendLine(" auto scriptVTable = (MMethod**)managedTypePtr->Class.ScriptVTable;");
|
||||
contents.AppendLine(" auto scriptVTable = (MMethod**)managedTypePtr->Script.ScriptVTable;");
|
||||
contents.AppendLine($" ASSERT(scriptVTable && scriptVTable[{scriptVTableIndex}]);");
|
||||
contents.AppendLine($" auto method = scriptVTable[{scriptVTableIndex}];");
|
||||
contents.AppendLine(" MonoObject* exception = nullptr;");
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace Flax.Build.Plugins
|
||||
contents.AppendLine(" if (IsDuringWrapperCall)");
|
||||
contents.AppendLine(" {");
|
||||
contents.AppendLine(" // Prevent stack overflow by calling base method");
|
||||
contents.AppendLine(" const auto scriptVTableBase = object->GetType().Class.ScriptVTableBase;");
|
||||
contents.AppendLine(" const auto scriptVTableBase = object->GetType().Script.ScriptVTableBase;");
|
||||
contents.Append($" return (object->**({functionInfo.UniqueName}_Signature*)&scriptVTableBase[{scriptVTableIndex} + 2])(");
|
||||
separator = false;
|
||||
for (var i = 0; i < functionInfo.Parameters.Count; i++)
|
||||
@@ -61,7 +61,7 @@ namespace Flax.Build.Plugins
|
||||
}
|
||||
contents.AppendLine(");");
|
||||
contents.AppendLine(" }");
|
||||
contents.AppendLine(" auto scriptVTable = (VisualScript::Method**)object->GetType().Class.ScriptVTable;");
|
||||
contents.AppendLine(" auto scriptVTable = (VisualScript::Method**)object->GetType().Script.ScriptVTable;");
|
||||
contents.AppendLine($" ASSERT(scriptVTable && scriptVTable[{scriptVTableIndex}]);");
|
||||
|
||||
if (functionInfo.Parameters.Count != 0)
|
||||
|
||||
Reference in New Issue
Block a user