#include "BsScriptComponent.h" #include "BsScriptGameObjectManager.h" #include "BsScriptObjectManager.h" #include "BsScriptAssemblyManager.h" #include "BsScriptMeta.h" #include "BsMonoField.h" #include "BsMonoClass.h" #include "BsMonoMethod.h" #include "BsMonoManager.h" #include "BsMonoUtil.h" #include "BsScriptSceneObject.h" #include "BsManagedComponent.h" #include "BsSceneObject.h" namespace BansheeEngine { ScriptComponent::ScriptComponent(MonoObject* instance) :ScriptObject(instance), mTypeMissing(false) { assert(instance != nullptr); ::MonoClass* monoClass = mono_object_get_class(instance); mNamespace = mono_class_get_namespace(monoClass); mType = mono_class_get_name(monoClass); } void ScriptComponent::initRuntimeData() { metaData.scriptClass->addInternalCall("Internal_CreateInstance", &ScriptComponent::internal_createInstance); metaData.scriptClass->addInternalCall("Internal_AddComponent", &ScriptComponent::internal_addComponent); metaData.scriptClass->addInternalCall("Internal_GetComponent", &ScriptComponent::internal_getComponent); metaData.scriptClass->addInternalCall("Internal_GetComponents", &ScriptComponent::internal_getComponents); metaData.scriptClass->addInternalCall("Internal_RemoveComponent", &ScriptComponent::internal_removeComponent); metaData.scriptClass->addInternalCall("Internal_GetSceneObject", &ScriptComponent::internal_getSceneObject); } void ScriptComponent::setManagedComponent(const GameObjectHandle& managedComponent) { mManagedComponent = managedComponent; } void ScriptComponent::internal_createInstance(MonoObject* instance) { ScriptComponent* nativeInstance = new (bs_alloc()) ScriptComponent(instance); } MonoObject* ScriptComponent::internal_addComponent(MonoObject* parentSceneObject, MonoReflectionType* type) { ScriptSceneObject* scriptSO = ScriptSceneObject::toNative(parentSceneObject); HSceneObject so = static_object_cast(scriptSO->getNativeHandle()); if (checkIfDestroyed(so)) return nullptr; GameObjectHandle mc = so->addComponent(type); return mc->getManagedInstance(); } MonoObject* ScriptComponent::internal_getComponent(MonoObject* parentSceneObject, MonoReflectionType* type) { ScriptSceneObject* scriptSO = ScriptSceneObject::toNative(parentSceneObject); HSceneObject so = static_object_cast(scriptSO->getNativeHandle()); if (checkIfDestroyed(so)) return nullptr; const Vector& mComponents = so->getComponents(); for(auto& component : mComponents) { if(component->getTypeId() == TID_ManagedComponent) { GameObjectHandle managedComponent = static_object_cast(component); if(managedComponent->getRuntimeType() == type) { return managedComponent->getManagedInstance(); } } } return nullptr; } MonoArray* ScriptComponent::internal_getComponents(MonoObject* parentSceneObject) { ScriptSceneObject* scriptSO = ScriptSceneObject::toNative(parentSceneObject); HSceneObject so = static_object_cast(scriptSO->getNativeHandle()); Vector managedComponents; if (!checkIfDestroyed(so)) { const Vector& mComponents = so->getComponents(); for (auto& component : mComponents) { if (component->getTypeId() == TID_ManagedComponent) { GameObjectHandle managedComponent = static_object_cast(component); managedComponents.push_back(managedComponent->getManagedInstance()); } } } MonoArray* componentArray = mono_array_new(MonoManager::instance().getDomain(), metaData.scriptClass->_getInternalClass(), (UINT32)managedComponents.size()); for(UINT32 i = 0; i < (UINT32)managedComponents.size(); i++) { void* elemAddr = mono_array_addr_with_size(componentArray, sizeof(MonoObject*), i); memcpy(elemAddr, &managedComponents[i], sizeof(MonoObject*)); } return componentArray; } void ScriptComponent::internal_removeComponent(MonoObject* parentSceneObject, MonoReflectionType* type) { ScriptSceneObject* scriptSO = ScriptSceneObject::toNative(parentSceneObject); HSceneObject so = static_object_cast(scriptSO->getNativeHandle()); if (checkIfDestroyed(so)) return; // We only allow single component per type const Vector& mComponents = so->getComponents(); for(auto& component : mComponents) { if(component->getTypeId() == TID_ManagedComponent) { GameObjectHandle managedComponent = static_object_cast(component); if(managedComponent->getRuntimeType() == type) { managedComponent->destroy(); return; } } } LOGWRN("Attempting to remove a component that doesn't exists on SceneObject \"" + so->getName() + "\""); } MonoObject* ScriptComponent::internal_getSceneObject(ScriptComponent* nativeInstance) { if (checkIfDestroyed(nativeInstance->mManagedComponent)) return nullptr; HSceneObject sceneObject = nativeInstance->mManagedComponent->sceneObject(); ScriptSceneObject* scriptSO = ScriptGameObjectManager::instance().getScriptSceneObject(sceneObject); if (scriptSO == nullptr) scriptSO = ScriptGameObjectManager::instance().createScriptSceneObject(sceneObject); return scriptSO->getManagedInstance(); } bool ScriptComponent::checkIfDestroyed(const GameObjectHandleBase& handle) { if (handle.isDestroyed()) { LOGWRN("Trying to access a destroyed GameObject with instance ID: " + handle.getInstanceId()); return true; } return false; } MonoObject* ScriptComponent::_createManagedInstance(bool construct) { ManagedSerializableObjectInfoPtr currentObjInfo = nullptr; // See if this type even still exists if (!ScriptAssemblyManager::instance().getSerializableObjectInfo(mNamespace, mType, currentObjInfo)) { mTypeMissing = true; return ScriptAssemblyManager::instance().getMissingComponentClass()->createInstance(true); } mTypeMissing = false; return currentObjInfo->mMonoClass->createInstance(construct); } ScriptObjectBackup ScriptComponent::beginRefresh() { ScriptGameObjectBase::beginRefresh(); ScriptObjectBackup backupData; backupData.data = mManagedComponent->backup(true); return backupData; } void ScriptComponent::endRefresh(const ScriptObjectBackup& backupData) { ComponentBackupData componentBackup = any_cast(backupData.data); mManagedComponent->restore(mManagedInstance, componentBackup, mTypeMissing); ScriptGameObjectBase::endRefresh(backupData); } void ScriptComponent::_onManagedInstanceDeleted() { mManagedInstance = nullptr; if (!mRefreshInProgress) ScriptGameObjectManager::instance().destroyScriptGameObject(this); } void ScriptComponent::setNativeHandle(const HGameObject& gameObject) { mManagedComponent = static_object_cast(gameObject); } }