2
0
Эх сурвалжийг харах

Managed joints and rigidbodies now properly reference their parent components
Fixing crash when exiting play-mode while physics element are interacting
Fixed crash on shutdown caused by the physics plugin being unloaded before the physics resources were released

BearishSun 9 жил өмнө
parent
commit
0d7ee2ee0e

+ 1 - 1
Documentation/GitHub/features.md

@@ -34,7 +34,7 @@ Here you will find a complete list of all currently available features. New feat
   * Supports arbitrary 3D transformations
   * Supports arbitrary 3D transformations
   * Localization support (string tables)
   * Localization support (string tables)
 * __Input__
 * __Input__
-  * Mouse/Keyboard/Gamepad support
+  * Mouse/keyboard/gamepad support
   * Provides both raw and OS input
   * Provides both raw and OS input
   * Virtual input with built-in key mapping
   * Virtual input with built-in key mapping
   * Virtual axes for analog input devices
   * Virtual axes for analog input devices

+ 4 - 1
Source/BansheeCore/Source/BsCoreApplication.cpp

@@ -58,7 +58,6 @@ namespace BansheeEngine
 		mPrimaryWindow->destroy();
 		mPrimaryWindow->destroy();
 		mPrimaryWindow = nullptr;
 		mPrimaryWindow = nullptr;
 
 
-		PhysicsManager::shutDown();
 		Importer::shutDown();
 		Importer::shutDown();
 		FontManager::shutDown();
 		FontManager::shutDown();
 		MaterialManager::shutDown();
 		MaterialManager::shutDown();
@@ -75,6 +74,10 @@ namespace BansheeEngine
 		GameObjectManager::shutDown();
 		GameObjectManager::shutDown();
 		RenderStateManager::shutDown();
 		RenderStateManager::shutDown();
 
 
+		// This must be done after all resources are released since it will unload the physics plugin, and some resources
+		// might be instances of types from that plugin.
+		PhysicsManager::shutDown();
+
 		RendererManager::shutDown();
 		RendererManager::shutDown();
 
 
 		// All CoreObject related modules should be shut down now. They have likely queued CoreObjects for destruction, so
 		// All CoreObject related modules should be shut down now. They have likely queued CoreObjects for destruction, so

+ 56 - 59
Source/BansheeCore/Source/BsResource.cpp

@@ -1,60 +1,57 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsResource.h"
-#include "BsResourceRTTI.h"
-#include "BsResources.h"
-#include "BsUUID.h"
-#include "BsResourceMetaData.h"
-#include "BsRenderAPI.h"
-
-namespace BansheeEngine
-{
-	Resource::Resource(bool initializeOnRenderThread)
-		:CoreObject(initializeOnRenderThread), mSize(0)
-	{ 
-		mMetaData = bs_shared_ptr_new<ResourceMetaData>();
-	}
-
-	const WString& Resource::getName() const 
-	{ 
-		return mMetaData->displayName; 
-	}
-
-	void Resource::setName(const WString& name) 
-	{ 
-		mMetaData->displayName = name; 
-	}
-
-	bool Resource::areDependenciesLoaded() const
-	{
-		bs_frame_mark();
-
-		bool areLoaded = true;
-		{
-			FrameVector<HResource> dependencies;
-			getResourceDependencies(dependencies);
-
-			for (auto& dependency : dependencies)
-			{
-				if (dependency != nullptr && !dependency.isLoaded())
-				{
-					areLoaded = false;
-					break;
-				}
-			}
-		}
-
-		bs_frame_clear();
-		return areLoaded;
-	}
-
-	RTTITypeBase* Resource::getRTTIStatic()
-	{
-		return ResourceRTTI::instance();
-	}
-
-	RTTITypeBase* Resource::getRTTI() const
-	{
-		return Resource::getRTTIStatic();
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsResource.h"
+#include "BsResourceRTTI.h"
+#include "BsResourceMetaData.h"
+
+namespace BansheeEngine
+{
+	Resource::Resource(bool initializeOnRenderThread)
+		:CoreObject(initializeOnRenderThread), mSize(0)
+	{ 
+		mMetaData = bs_shared_ptr_new<ResourceMetaData>();
+	}
+
+	const WString& Resource::getName() const 
+	{ 
+		return mMetaData->displayName; 
+	}
+
+	void Resource::setName(const WString& name) 
+	{ 
+		mMetaData->displayName = name; 
+	}
+
+	bool Resource::areDependenciesLoaded() const
+	{
+		bs_frame_mark();
+
+		bool areLoaded = true;
+		{
+			FrameVector<HResource> dependencies;
+			getResourceDependencies(dependencies);
+
+			for (auto& dependency : dependencies)
+			{
+				if (dependency != nullptr && !dependency.isLoaded())
+				{
+					areLoaded = false;
+					break;
+				}
+			}
+		}
+
+		bs_frame_clear();
+		return areLoaded;
+	}
+
+	RTTITypeBase* Resource::getRTTIStatic()
+	{
+		return ResourceRTTI::instance();
+	}
+
+	RTTITypeBase* Resource::getRTTI() const
+	{
+		return Resource::getRTTIStatic();
+	}
 }
 }

+ 757 - 752
Source/BansheeCore/Source/BsResources.cpp

@@ -1,753 +1,758 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsResources.h"
-#include "BsResource.h"
-#include "BsResourceManifest.h"
-#include "BsException.h"
-#include "BsFileSerializer.h"
-#include "BsFileSystem.h"
-#include "BsTaskScheduler.h"
-#include "BsUUID.h"
-#include "BsDebug.h"
-#include "BsUtility.h"
-#include "BsSavedResourceData.h"
-#include "BsResourceListenerManager.h"
-
-namespace BansheeEngine
-{
-	Resources::Resources()
-	{
-		mDefaultResourceManifest = ResourceManifest::create("Default");
-		mResourceManifests.push_back(mDefaultResourceManifest);
-	}
-
-	Resources::~Resources()
-	{
-		// Unload and invalidate all resources
-		UnorderedMap<String, LoadedResourceData> loadedResourcesCopy = mLoadedResources;
-
-		for (auto& loadedResourcePair : loadedResourcesCopy)
-			destroy(loadedResourcePair.second.resource);
-	}
-
-	HResource Resources::load(const Path& filePath, bool loadDependencies, bool keepInternalReference)
-	{
-		if (!FileSystem::isFile(filePath))
-		{
-			LOGWRN_VERBOSE("Cannot load resource. Specified file: " + filePath.toString() + " doesn't exist.");
-
-			return HResource();
-		}
-
-		String uuid;
-		bool foundUUID = getUUIDFromFilePath(filePath, uuid);
-
-		if (!foundUUID)
-			uuid = UUIDGenerator::generateRandom();
-
-		return loadInternal(uuid, filePath, true, loadDependencies, keepInternalReference);
-	}
-
-	HResource Resources::load(const WeakResourceHandle<Resource>& handle, bool loadDependencies, bool keepInternalReference)
-	{
-		if (handle.mData == nullptr)
-			return HResource();
-
-		String uuid = handle.getUUID();
-		return loadFromUUID(uuid, false, loadDependencies, keepInternalReference);
-	}
-
-	HResource Resources::loadAsync(const Path& filePath, bool loadDependencies, bool keepInternalReference)
-	{
-		if (!FileSystem::isFile(filePath))
-		{
-			LOGWRN_VERBOSE("Cannot load resource. Specified file: " + filePath.toString() + " doesn't exist.");
-
-			return HResource();
-		}
-
-		String uuid;
-		bool foundUUID = getUUIDFromFilePath(filePath, uuid);
-
-		if (!foundUUID)
-			uuid = UUIDGenerator::generateRandom();
-
-		return loadInternal(uuid, filePath, false, loadDependencies, keepInternalReference);
-	}
-
-	HResource Resources::loadFromUUID(const String& uuid, bool async, bool loadDependencies, bool keepInternalReference)
-	{
-		Path filePath;
-
-		// Default manifest is at 0th index but all other take priority since Default manifest could
-		// contain obsolete data. 
-		for (auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter)
-		{
-			if ((*iter)->uuidToFilePath(uuid, filePath))
-				break;
-		}
-
-		return loadInternal(uuid, filePath, !async, loadDependencies, keepInternalReference);
-	}
-
-	HResource Resources::loadInternal(const String& UUID, const Path& filePath, bool synchronous, bool loadDependencies, bool keepInternalReference)
-	{
-		HResource outputResource;
-
-		bool alreadyLoading = false;
-		bool loadInProgress = false;
-		{
-			// Check if resource is already being loaded on a worker thread
-			BS_LOCK_MUTEX(mInProgressResourcesMutex);
-			auto iterFind2 = mInProgressResources.find(UUID);
-			if (iterFind2 != mInProgressResources.end())
-			{
-				LoadedResourceData& resData = iterFind2->second->resData;
-				outputResource = resData.resource.lock();
-
-				if (keepInternalReference)
-				{
-					resData.numInternalRefs++;
-					outputResource.addInternalRef();
-				}
-
-				alreadyLoading = true;
-				loadInProgress = true;
-			}
-
-			// Previously being loaded as async but now we want it synced, so we wait
-			if (loadInProgress && synchronous)
-				outputResource.blockUntilLoaded();
-
-			if (!alreadyLoading)
-			{
-				BS_LOCK_MUTEX(mLoadedResourceMutex);
-				auto iterFind = mLoadedResources.find(UUID);
-				if (iterFind != mLoadedResources.end()) // Resource is already loaded
-				{
-					LoadedResourceData& resData = iterFind->second;
-					outputResource = resData.resource.lock();
-
-					if (keepInternalReference)
-					{
-						resData.numInternalRefs++;
-						outputResource.addInternalRef();
-					}
-
-					alreadyLoading = true;
-				}
-			}
-		}
-
-		// Not loaded and not in progress, start loading of new resource
-		// (or if already loaded or in progress, load any dependencies)
-		if (!alreadyLoading)
-		{
-			// Check if the handle already exists
-			BS_LOCK_MUTEX(mLoadedResourceMutex);
-			auto iterFind = mHandles.find(UUID);
-			if (iterFind != mHandles.end())
-				outputResource = iterFind->second.lock();
-			else
-			{
-				outputResource = HResource(UUID);
-				mHandles[UUID] = outputResource.getWeak();
-			}			
-		}
-
-		// We have nowhere to load from, warn and complete load if a file path was provided,
-		// otherwise pass through as we might just want to load from memory. 
-		if (filePath.isEmpty())
-		{
-			if (!alreadyLoading)
-			{
-				LOGWRN_VERBOSE("Cannot load resource. Resource with UUID '" + UUID + "' doesn't exist.");
-
-				// Complete the load as that the depedency counter is properly reduced, in case this 
-				// is a dependency of some other resource.
-				loadComplete(outputResource);
-				return outputResource;
-			}
-		}
-		else if (!FileSystem::isFile(filePath))
-		{
-			LOGWRN_VERBOSE("Cannot load resource. Specified file: " + filePath.toString() + " doesn't exist.");
-
-			// Complete the load as that the depedency counter is properly reduced, in case this 
-			// is a dependency of some other resource.
-			loadComplete(outputResource);
-			assert(!loadInProgress); // Resource already being loaded but we can't find its path now?
-
-			return outputResource;
-		}
-
-		// Load dependency data if a file path is provided
-		SPtr<SavedResourceData> savedResourceData;
-		if (!filePath.isEmpty())
-		{
-			FileDecoder fs(filePath);
-			savedResourceData = std::static_pointer_cast<SavedResourceData>(fs.decode());
-		}
-
-		// If already loading keep the old load operation active, otherwise create a new one
-		if (!alreadyLoading)
-		{
-			{
-				BS_LOCK_MUTEX(mInProgressResourcesMutex);
-
-				ResourceLoadData* loadData = bs_new<ResourceLoadData>(outputResource.getWeak(), 0);
-				mInProgressResources[UUID] = loadData;
-				loadData->resData = outputResource.getWeak();
-
-				if (keepInternalReference)
-				{
-					loadData->resData.numInternalRefs++;
-					outputResource.addInternalRef();
-				}
-
-				loadData->remainingDependencies = 1;
-				loadData->notifyImmediately = synchronous; // Make resource listener trigger before exit if loading synchronously
-
-				// Register dependencies and count them so we know when the resource is fully loaded
-				if (loadDependencies && savedResourceData != nullptr)
-				{
-					for (auto& dependency : savedResourceData->getDependencies())
-					{
-						if (dependency != UUID)
-						{
-							mDependantLoads[dependency].push_back(loadData);
-							loadData->remainingDependencies++;
-						}
-					}
-				}
-			}
-
-			if (loadDependencies && savedResourceData != nullptr)
-			{
-				const Vector<String>& dependencyUUIDs = savedResourceData->getDependencies();
-				UINT32 numDependencies = (UINT32)dependencyUUIDs.size();
-				Vector<HResource> dependencies(numDependencies);
-
-				for (UINT32 i = 0; i < numDependencies; i++)
-					dependencies[i] = loadFromUUID(dependencyUUIDs[i], !synchronous, true, false);
-
-				// Keep dependencies alive until the parent is done loading
-				{
-					BS_LOCK_MUTEX(mInProgressResourcesMutex);
-
-					// At this point the resource is guaranteed to still be in-progress, so it's safe to update its dependency list
-					mInProgressResources[UUID]->dependencies = dependencies;
-				}
-			}
-		}
-		else if (loadDependencies && savedResourceData != nullptr) // Queue dependencies in case they aren't already loaded
-		{
-			const Vector<String>& dependencies = savedResourceData->getDependencies();
-			if (!dependencies.empty())
-			{
-				{
-					BS_LOCK_MUTEX(mInProgressResourcesMutex);
-
-					ResourceLoadData* loadData = nullptr;
-
-					auto iterFind = mInProgressResources.find(UUID);
-					if (iterFind == mInProgressResources.end()) // Fully loaded
-					{
-						loadData = bs_new<ResourceLoadData>(outputResource.getWeak(), 0);
-						loadData->resData = outputResource.getWeak();
-						loadData->remainingDependencies = 0;
-						loadData->notifyImmediately = synchronous; // Make resource listener trigger before exit if loading synchronously
-
-						mInProgressResources[UUID] = loadData;
-					}
-					else
-					{
-						loadData = iterFind->second;
-					}
-
-					// Register dependencies and count them so we know when the resource is fully loaded
-					for (auto& dependency : dependencies)
-					{
-						if (dependency != UUID)
-						{
-							bool registerDependency = true;
-
-							auto iterFind2 = mDependantLoads.find(dependency);
-							if (iterFind2 != mDependantLoads.end())
-							{
-								Vector<ResourceLoadData*>& dependantData = iterFind2->second;
-								auto iterFind3 = std::find_if(dependantData.begin(), dependantData.end(),
-									[&](ResourceLoadData* x)
-								{
-									return x->resData.resource.getUUID() == outputResource.getUUID();
-								});
-
-								registerDependency = iterFind3 == dependantData.end();
-							}
-
-							if (registerDependency)
-							{
-								mDependantLoads[dependency].push_back(loadData);
-								loadData->remainingDependencies++;
-								loadData->dependencies.push_back(_getResourceHandle(dependency));
-							}
-						}
-					}
-				}
-
-				for (auto& dependency : dependencies)
-					loadFromUUID(dependency, !synchronous, true, false);
-			}
-		}
-
-		// Actually start the file read operation if not already loaded or in progress
-		if (!alreadyLoading && !filePath.isEmpty())
-		{
-			// Synchronous or the resource doesn't support async, read the file immediately
-			if (synchronous || !savedResourceData->allowAsyncLoading())
-			{
-				loadCallback(filePath, outputResource);
-			}
-			else // Asynchronous, read the file on a worker thread
-			{
-				String fileName = filePath.getFilename();
-				String taskName = "Resource load: " + fileName;
-
-				TaskPtr task = Task::create(taskName, std::bind(&Resources::loadCallback, this, filePath, outputResource));
-				TaskScheduler::instance().addTask(task);
-			}
-		}
-		else // File already loaded or in progress
-		{
-			// Complete the load unless its in progress in which case we wait for its worker thread to complete it.
-			// In case file is already loaded this will only decrement dependency count in case this resource is a dependency.
-			if (!loadInProgress)
-				loadComplete(outputResource);
-			else
-			{
-				// In case loading finished in the meantime we cannot be sure at what point ::loadComplete was triggered,
-				// so trigger it manually so that the dependency count is properly decremented in case this resource
-				// is a dependency.
-				BS_LOCK_MUTEX(mLoadedResourceMutex);
-				auto iterFind = mLoadedResources.find(UUID);
-				if (iterFind != mLoadedResources.end())
-					loadComplete(outputResource);
-			}
-		}
-
-		return outputResource;
-	}
-
-	ResourcePtr Resources::loadFromDiskAndDeserialize(const Path& filePath)
-	{
-		FileDecoder fs(filePath);
-		fs.skip(); // Skipped over saved resource data
-		std::shared_ptr<IReflectable> loadedData = fs.decode();
-
-		if (loadedData == nullptr)
-		{
-			LOGERR("Unable to load resource at path \"" + filePath.toString() + "\"");
-		}
-		else
-		{
-			if (!loadedData->isDerivedFrom(Resource::getRTTIStatic()))
-				BS_EXCEPT(InternalErrorException, "Loaded class doesn't derive from Resource.");
-		}
-
-		ResourcePtr resource = std::static_pointer_cast<Resource>(loadedData);
-		return resource;
-	}
-
-	void Resources::release(ResourceHandleBase& resource)
-	{
-		const String& UUID = resource.getUUID();
-
-		{
-			bool loadInProgress = false;
-
-			BS_LOCK_MUTEX(mInProgressResourcesMutex);
-			auto iterFind2 = mInProgressResources.find(UUID);
-			if (iterFind2 != mInProgressResources.end())
-				loadInProgress = true;
-
-			// Technically we should be able to just cancel a load in progress instead of blocking until it finishes.
-			// However that would mean the last reference could get lost on whatever thread did the loading, which
-			// isn't something that's supported. If this ends up being a problem either make handle counting atomic
-			// or add a separate queue for objects destroyed from the load threads.
-			if (loadInProgress)
-				resource.blockUntilLoaded();
-
-			{
-				BS_LOCK_MUTEX(mLoadedResourceMutex);
-				auto iterFind = mLoadedResources.find(UUID);
-				if (iterFind != mLoadedResources.end()) // Resource is already loaded
-				{
-					LoadedResourceData& resData = iterFind->second;
-
-					assert(resData.numInternalRefs > 0);
-					resData.numInternalRefs--;
-					resource.removeInternalRef();
-
-					return;
-				}
-			}
-		}
-	}
-
-	void Resources::unloadAllUnused()
-	{
-		Vector<HResource> resourcesToUnload;
-
-		{
-			BS_LOCK_MUTEX(mLoadedResourceMutex);
-			for(auto iter = mLoadedResources.begin(); iter != mLoadedResources.end(); ++iter)
-			{
-				const LoadedResourceData& resData = iter->second;
-
-				if (resData.resource.mData->mRefCount == resData.numInternalRefs) // Only internal references exist, free it
-					resourcesToUnload.push_back(resData.resource.lock());
-			}
-		}
-
-		// Note: When unloading multiple resources it's possible that unloading one will also unload
-		// another resource in "resourcesToUnload". This is fine because "unload" deals with invalid
-		// handles gracefully.
-		for(auto iter = resourcesToUnload.begin(); iter != resourcesToUnload.end(); ++iter)
-		{
-			release(*iter);
-		}
-	}
-
-	void Resources::destroy(ResourceHandleBase& resource)
-	{
-		if (resource.mData == nullptr)
-			return;
-
-		const String& uuid = resource.getUUID();
-		if (!resource.isLoaded(false))
-		{
-			bool loadInProgress = false;
-			{
-				BS_LOCK_MUTEX(mInProgressResourcesMutex);
-				auto iterFind2 = mInProgressResources.find(uuid);
-				if (iterFind2 != mInProgressResources.end())
-					loadInProgress = true;
-			}
-
-			if (loadInProgress) // If it's still loading wait until that finishes
-				resource.blockUntilLoaded();
-			else
-				return; // Already unloaded
-		}
-
-		// Notify external systems before we actually destroy it
-		onResourceDestroyed(uuid);
-		resource.mData->mPtr->destroy();
-
-		{
-			BS_LOCK_MUTEX(mLoadedResourceMutex);
-
-			auto iterFind = mLoadedResources.find(uuid);
-			if (iterFind != mLoadedResources.end())
-			{
-				LoadedResourceData& resData = iterFind->second;
-				while (resData.numInternalRefs > 0)
-				{
-					resData.numInternalRefs--;
-					resData.resource.removeInternalRef();
-				}
-
-				mLoadedResources.erase(iterFind);
-			}
-			else
-			{
-				assert(false); // This should never happen but in case it does fail silently in release mode
-			}
-		}
-
-		resource.setHandleData(nullptr, uuid);
-	}
-
-	void Resources::save(const HResource& resource, const Path& filePath, bool overwrite)
-	{
-		if (resource == nullptr)
-			return;
-
-		if (!resource.isLoaded(false))
-		{
-			bool loadInProgress = false;
-			{
-				BS_LOCK_MUTEX(mInProgressResourcesMutex);
-				auto iterFind2 = mInProgressResources.find(resource.getUUID());
-				if (iterFind2 != mInProgressResources.end())
-					loadInProgress = true;
-			}
-
-			if (loadInProgress) // If it's still loading wait until that finishes
-				resource.blockUntilLoaded();
-			else
-				return; // Nothing to save
-		}
-
-		bool fileExists = FileSystem::isFile(filePath);
-		if(fileExists)
-		{
-			if(overwrite)
-				FileSystem::remove(filePath);
-			else
-				BS_EXCEPT(InvalidParametersException, "Another file exists at the specified location.");
-		}
-
-		mDefaultResourceManifest->registerResource(resource.getUUID(), filePath);
-
-		Vector<ResourceDependency> dependencyList = Utility::findResourceDependencies(*resource.get());
-
-		Vector<String> dependencyUUIDs(dependencyList.size());
-		for (UINT32 i = 0; i < (UINT32)dependencyList.size(); i++)
-			dependencyUUIDs[i] = dependencyList[i].resource.getUUID();
-
-		SPtr<SavedResourceData> resourceData = bs_shared_ptr_new<SavedResourceData>(dependencyUUIDs, resource->allowAsyncLoading());
-
-		FileEncoder fs(filePath);
-		fs.encode(resourceData.get());
-		fs.encode(resource.get());
-	}
-
-	void Resources::save(const HResource& resource)
-	{
-		if (resource == nullptr)
-			return;
-
-		Path path;
-		if (getFilePathFromUUID(resource.getUUID(), path))
-			save(resource, path, true);
-	}
-
-	void Resources::update(HResource& handle, const ResourcePtr& resource)
-	{
-		const String& uuid = handle.getUUID();
-		handle.setHandleData(resource, uuid);
-
-		{
-			BS_LOCK_MUTEX(mLoadedResourceMutex);
-			auto iterFind = mLoadedResources.find(uuid);
-			if (iterFind == mLoadedResources.end())
-			{
-				LoadedResourceData& resData = mLoadedResources[uuid];
-				resData.resource = handle.getWeak();
-			}
-		}
-
-		onResourceModified(handle);
-	}
-
-	Vector<String> Resources::getDependencies(const Path& filePath)
-	{
-		SPtr<SavedResourceData> savedResourceData;
-		if (!filePath.isEmpty())
-		{
-			FileDecoder fs(filePath);
-			savedResourceData = std::static_pointer_cast<SavedResourceData>(fs.decode());
-		}
-
-		return savedResourceData->getDependencies();
-	}
-
-	void Resources::registerResourceManifest(const ResourceManifestPtr& manifest)
-	{
-		if(manifest->getName() == "Default")
-			return;
-
-		auto findIter = std::find(mResourceManifests.begin(), mResourceManifests.end(), manifest);
-		if(findIter == mResourceManifests.end())
-			mResourceManifests.push_back(manifest);
-		else
-			*findIter = manifest;
-	}
-
-	void Resources::unregisterResourceManifest(const ResourceManifestPtr& manifest)
-	{
-		if (manifest->getName() == "Default")
-			return;
-
-		auto findIter = std::find(mResourceManifests.begin(), mResourceManifests.end(), manifest);
-		if (findIter != mResourceManifests.end())
-			mResourceManifests.erase(findIter);
-	}
-
-	ResourceManifestPtr Resources::getResourceManifest(const String& name) const
-	{
-		for(auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter) 
-		{
-			if(name == (*iter)->getName())
-				return (*iter);
-		}
-
-		return nullptr;
-	}
-
-	bool Resources::isLoaded(const String& uuid, bool checkInProgress)
-	{
-		if (checkInProgress)
-		{
-			BS_LOCK_MUTEX(mInProgressResourcesMutex);
-			auto iterFind2 = mInProgressResources.find(uuid);
-			if (iterFind2 != mInProgressResources.end())
-			{
-				return true;
-			}
-
-			{
-				BS_LOCK_MUTEX(mLoadedResourceMutex);
-				auto iterFind = mLoadedResources.find(uuid);
-				if (iterFind != mLoadedResources.end())
-				{
-					return true;
-				}
-			}
-		}
-
-		return false;
-	}
-
-	HResource Resources::_createResourceHandle(const ResourcePtr& obj)
-	{
-		String uuid = UUIDGenerator::generateRandom();
-		HResource newHandle(obj, uuid);
-
-		{
-			BS_LOCK_MUTEX(mLoadedResourceMutex);
-
-			LoadedResourceData& resData = mLoadedResources[uuid];
-			resData.resource = newHandle.getWeak();
-			mHandles[uuid] = newHandle.getWeak();
-		}
-	
-		return newHandle;
-	}
-
-	HResource Resources::_getResourceHandle(const String& uuid)
-	{
-		BS_LOCK_MUTEX(mLoadedResourceMutex);
-		auto iterFind3 = mHandles.find(uuid);
-		if (iterFind3 != mHandles.end()) // Not loaded, but handle does exist
-		{
-			return iterFind3->second.lock();
-		}
-
-		// Create new handle
-		HResource handle(uuid);
-		mHandles[uuid] = handle.getWeak();
-
-		return handle;
-	}
-
-	bool Resources::getFilePathFromUUID(const String& uuid, Path& filePath) const
-	{
-		for(auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter) 
-		{
-			if((*iter)->uuidToFilePath(uuid, filePath))
-				return true;
-		}
-
-		return false;
-	}
-
-	bool Resources::getUUIDFromFilePath(const Path& path, String& uuid) const
-	{
-		Path manifestPath = path;
-		if (!manifestPath.isAbsolute())
-			manifestPath.makeAbsolute(FileSystem::getWorkingDirectoryPath());
-
-		for(auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter) 
-		{
-			if ((*iter)->filePathToUUID(manifestPath, uuid))
-				return true;
-		}
-
-		return false;
-	}
-
-	void Resources::loadComplete(HResource& resource)
-	{
-		String uuid = resource.getUUID();
-
-		ResourceLoadData* myLoadData = nullptr;
-		bool finishLoad = true;
-		Vector<ResourceLoadData*> dependantLoads;
-		{
-			BS_LOCK_MUTEX(mInProgressResourcesMutex);
-
-			auto iterFind = mInProgressResources.find(uuid);
-			if (iterFind != mInProgressResources.end())
-			{
-				myLoadData = iterFind->second;
-				finishLoad = myLoadData->remainingDependencies == 0;
-				
-				if (finishLoad)
-					mInProgressResources.erase(iterFind);
-			}
-
-			auto iterFind2 = mDependantLoads.find(uuid);
-
-			if (iterFind2 != mDependantLoads.end())
-				dependantLoads = iterFind2->second;
-
-			if (finishLoad)
-			{
-				mDependantLoads.erase(uuid);
-
-				// If loadedData is null then we're probably completing load on an already loaded resource, triggered
-				// by its dependencies.
-				if (myLoadData != nullptr && myLoadData->loadedData != nullptr)
-				{
-					BS_LOCK_MUTEX(mLoadedResourceMutex);
-
-					mLoadedResources[uuid] = myLoadData->resData;
-					resource.setHandleData(myLoadData->loadedData, uuid);
-				}
-
-				for (auto& dependantLoad : dependantLoads)
-					dependantLoad->remainingDependencies--;
-			}
-		}
-
-		for (auto& dependantLoad : dependantLoads)
-		{
-			HResource dependant = dependantLoad->resData.resource.lock();
-			loadComplete(dependant);
-		}
-
-		if (finishLoad && myLoadData != nullptr)
-		{
-			onResourceLoaded(resource);
-
-			// This should only ever be true on the main thread
-			if (myLoadData->notifyImmediately)
-				ResourceListenerManager::instance().notifyListeners(uuid);
-
-			bs_delete(myLoadData);
-		}
-	}
-
-	void Resources::loadCallback(const Path& filePath, HResource& resource)
-	{
-		ResourcePtr rawResource = loadFromDiskAndDeserialize(filePath);
-
-		{
-			BS_LOCK_MUTEX(mInProgressResourcesMutex);
-
-			// Check if all my dependencies are loaded
-			ResourceLoadData* myLoadData = mInProgressResources[resource.getUUID()];
-			myLoadData->loadedData = rawResource;
-			myLoadData->remainingDependencies--;
-		}
-
-		loadComplete(resource);
-	}
-
-	BS_CORE_EXPORT Resources& gResources()
-	{
-		return Resources::instance();
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsResources.h"
+#include "BsResource.h"
+#include "BsResourceManifest.h"
+#include "BsException.h"
+#include "BsFileSerializer.h"
+#include "BsFileSystem.h"
+#include "BsTaskScheduler.h"
+#include "BsUUID.h"
+#include "BsDebug.h"
+#include "BsUtility.h"
+#include "BsSavedResourceData.h"
+#include "BsResourceListenerManager.h"
+
+namespace BansheeEngine
+{
+	Resources::Resources()
+	{
+		mDefaultResourceManifest = ResourceManifest::create("Default");
+		mResourceManifests.push_back(mDefaultResourceManifest);
+	}
+
+	Resources::~Resources()
+	{
+		// Unload and invalidate all resources
+		UnorderedMap<String, LoadedResourceData> loadedResourcesCopy;
+		
+		{
+			BS_LOCK_MUTEX(mLoadedResourceMutex)
+			loadedResourcesCopy = mLoadedResources;
+		}
+
+		for (auto& loadedResourcePair : loadedResourcesCopy)
+			destroy(loadedResourcePair.second.resource);
+	}
+
+	HResource Resources::load(const Path& filePath, bool loadDependencies, bool keepInternalReference)
+	{
+		if (!FileSystem::isFile(filePath))
+		{
+			LOGWRN_VERBOSE("Cannot load resource. Specified file: " + filePath.toString() + " doesn't exist.");
+
+			return HResource();
+		}
+
+		String uuid;
+		bool foundUUID = getUUIDFromFilePath(filePath, uuid);
+
+		if (!foundUUID)
+			uuid = UUIDGenerator::generateRandom();
+
+		return loadInternal(uuid, filePath, true, loadDependencies, keepInternalReference);
+	}
+
+	HResource Resources::load(const WeakResourceHandle<Resource>& handle, bool loadDependencies, bool keepInternalReference)
+	{
+		if (handle.mData == nullptr)
+			return HResource();
+
+		String uuid = handle.getUUID();
+		return loadFromUUID(uuid, false, loadDependencies, keepInternalReference);
+	}
+
+	HResource Resources::loadAsync(const Path& filePath, bool loadDependencies, bool keepInternalReference)
+	{
+		if (!FileSystem::isFile(filePath))
+		{
+			LOGWRN_VERBOSE("Cannot load resource. Specified file: " + filePath.toString() + " doesn't exist.");
+
+			return HResource();
+		}
+
+		String uuid;
+		bool foundUUID = getUUIDFromFilePath(filePath, uuid);
+
+		if (!foundUUID)
+			uuid = UUIDGenerator::generateRandom();
+
+		return loadInternal(uuid, filePath, false, loadDependencies, keepInternalReference);
+	}
+
+	HResource Resources::loadFromUUID(const String& uuid, bool async, bool loadDependencies, bool keepInternalReference)
+	{
+		Path filePath;
+
+		// Default manifest is at 0th index but all other take priority since Default manifest could
+		// contain obsolete data. 
+		for (auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter)
+		{
+			if ((*iter)->uuidToFilePath(uuid, filePath))
+				break;
+		}
+
+		return loadInternal(uuid, filePath, !async, loadDependencies, keepInternalReference);
+	}
+
+	HResource Resources::loadInternal(const String& UUID, const Path& filePath, bool synchronous, bool loadDependencies, bool keepInternalReference)
+	{
+		HResource outputResource;
+
+		bool alreadyLoading = false;
+		bool loadInProgress = false;
+		{
+			// Check if resource is already being loaded on a worker thread
+			BS_LOCK_MUTEX(mInProgressResourcesMutex);
+			auto iterFind2 = mInProgressResources.find(UUID);
+			if (iterFind2 != mInProgressResources.end())
+			{
+				LoadedResourceData& resData = iterFind2->second->resData;
+				outputResource = resData.resource.lock();
+
+				if (keepInternalReference)
+				{
+					resData.numInternalRefs++;
+					outputResource.addInternalRef();
+				}
+
+				alreadyLoading = true;
+				loadInProgress = true;
+			}
+
+			// Previously being loaded as async but now we want it synced, so we wait
+			if (loadInProgress && synchronous)
+				outputResource.blockUntilLoaded();
+
+			if (!alreadyLoading)
+			{
+				BS_LOCK_MUTEX(mLoadedResourceMutex);
+				auto iterFind = mLoadedResources.find(UUID);
+				if (iterFind != mLoadedResources.end()) // Resource is already loaded
+				{
+					LoadedResourceData& resData = iterFind->second;
+					outputResource = resData.resource.lock();
+
+					if (keepInternalReference)
+					{
+						resData.numInternalRefs++;
+						outputResource.addInternalRef();
+					}
+
+					alreadyLoading = true;
+				}
+			}
+		}
+
+		// Not loaded and not in progress, start loading of new resource
+		// (or if already loaded or in progress, load any dependencies)
+		if (!alreadyLoading)
+		{
+			// Check if the handle already exists
+			BS_LOCK_MUTEX(mLoadedResourceMutex);
+			auto iterFind = mHandles.find(UUID);
+			if (iterFind != mHandles.end())
+				outputResource = iterFind->second.lock();
+			else
+			{
+				outputResource = HResource(UUID);
+				mHandles[UUID] = outputResource.getWeak();
+			}			
+		}
+
+		// We have nowhere to load from, warn and complete load if a file path was provided,
+		// otherwise pass through as we might just want to load from memory. 
+		if (filePath.isEmpty())
+		{
+			if (!alreadyLoading)
+			{
+				LOGWRN_VERBOSE("Cannot load resource. Resource with UUID '" + UUID + "' doesn't exist.");
+
+				// Complete the load as that the depedency counter is properly reduced, in case this 
+				// is a dependency of some other resource.
+				loadComplete(outputResource);
+				return outputResource;
+			}
+		}
+		else if (!FileSystem::isFile(filePath))
+		{
+			LOGWRN_VERBOSE("Cannot load resource. Specified file: " + filePath.toString() + " doesn't exist.");
+
+			// Complete the load as that the depedency counter is properly reduced, in case this 
+			// is a dependency of some other resource.
+			loadComplete(outputResource);
+			assert(!loadInProgress); // Resource already being loaded but we can't find its path now?
+
+			return outputResource;
+		}
+
+		// Load dependency data if a file path is provided
+		SPtr<SavedResourceData> savedResourceData;
+		if (!filePath.isEmpty())
+		{
+			FileDecoder fs(filePath);
+			savedResourceData = std::static_pointer_cast<SavedResourceData>(fs.decode());
+		}
+
+		// If already loading keep the old load operation active, otherwise create a new one
+		if (!alreadyLoading)
+		{
+			{
+				BS_LOCK_MUTEX(mInProgressResourcesMutex);
+
+				ResourceLoadData* loadData = bs_new<ResourceLoadData>(outputResource.getWeak(), 0);
+				mInProgressResources[UUID] = loadData;
+				loadData->resData = outputResource.getWeak();
+
+				if (keepInternalReference)
+				{
+					loadData->resData.numInternalRefs++;
+					outputResource.addInternalRef();
+				}
+
+				loadData->remainingDependencies = 1;
+				loadData->notifyImmediately = synchronous; // Make resource listener trigger before exit if loading synchronously
+
+				// Register dependencies and count them so we know when the resource is fully loaded
+				if (loadDependencies && savedResourceData != nullptr)
+				{
+					for (auto& dependency : savedResourceData->getDependencies())
+					{
+						if (dependency != UUID)
+						{
+							mDependantLoads[dependency].push_back(loadData);
+							loadData->remainingDependencies++;
+						}
+					}
+				}
+			}
+
+			if (loadDependencies && savedResourceData != nullptr)
+			{
+				const Vector<String>& dependencyUUIDs = savedResourceData->getDependencies();
+				UINT32 numDependencies = (UINT32)dependencyUUIDs.size();
+				Vector<HResource> dependencies(numDependencies);
+
+				for (UINT32 i = 0; i < numDependencies; i++)
+					dependencies[i] = loadFromUUID(dependencyUUIDs[i], !synchronous, true, false);
+
+				// Keep dependencies alive until the parent is done loading
+				{
+					BS_LOCK_MUTEX(mInProgressResourcesMutex);
+
+					// At this point the resource is guaranteed to still be in-progress, so it's safe to update its dependency list
+					mInProgressResources[UUID]->dependencies = dependencies;
+				}
+			}
+		}
+		else if (loadDependencies && savedResourceData != nullptr) // Queue dependencies in case they aren't already loaded
+		{
+			const Vector<String>& dependencies = savedResourceData->getDependencies();
+			if (!dependencies.empty())
+			{
+				{
+					BS_LOCK_MUTEX(mInProgressResourcesMutex);
+
+					ResourceLoadData* loadData = nullptr;
+
+					auto iterFind = mInProgressResources.find(UUID);
+					if (iterFind == mInProgressResources.end()) // Fully loaded
+					{
+						loadData = bs_new<ResourceLoadData>(outputResource.getWeak(), 0);
+						loadData->resData = outputResource.getWeak();
+						loadData->remainingDependencies = 0;
+						loadData->notifyImmediately = synchronous; // Make resource listener trigger before exit if loading synchronously
+
+						mInProgressResources[UUID] = loadData;
+					}
+					else
+					{
+						loadData = iterFind->second;
+					}
+
+					// Register dependencies and count them so we know when the resource is fully loaded
+					for (auto& dependency : dependencies)
+					{
+						if (dependency != UUID)
+						{
+							bool registerDependency = true;
+
+							auto iterFind2 = mDependantLoads.find(dependency);
+							if (iterFind2 != mDependantLoads.end())
+							{
+								Vector<ResourceLoadData*>& dependantData = iterFind2->second;
+								auto iterFind3 = std::find_if(dependantData.begin(), dependantData.end(),
+									[&](ResourceLoadData* x)
+								{
+									return x->resData.resource.getUUID() == outputResource.getUUID();
+								});
+
+								registerDependency = iterFind3 == dependantData.end();
+							}
+
+							if (registerDependency)
+							{
+								mDependantLoads[dependency].push_back(loadData);
+								loadData->remainingDependencies++;
+								loadData->dependencies.push_back(_getResourceHandle(dependency));
+							}
+						}
+					}
+				}
+
+				for (auto& dependency : dependencies)
+					loadFromUUID(dependency, !synchronous, true, false);
+			}
+		}
+
+		// Actually start the file read operation if not already loaded or in progress
+		if (!alreadyLoading && !filePath.isEmpty())
+		{
+			// Synchronous or the resource doesn't support async, read the file immediately
+			if (synchronous || !savedResourceData->allowAsyncLoading())
+			{
+				loadCallback(filePath, outputResource);
+			}
+			else // Asynchronous, read the file on a worker thread
+			{
+				String fileName = filePath.getFilename();
+				String taskName = "Resource load: " + fileName;
+
+				TaskPtr task = Task::create(taskName, std::bind(&Resources::loadCallback, this, filePath, outputResource));
+				TaskScheduler::instance().addTask(task);
+			}
+		}
+		else // File already loaded or in progress
+		{
+			// Complete the load unless its in progress in which case we wait for its worker thread to complete it.
+			// In case file is already loaded this will only decrement dependency count in case this resource is a dependency.
+			if (!loadInProgress)
+				loadComplete(outputResource);
+			else
+			{
+				// In case loading finished in the meantime we cannot be sure at what point ::loadComplete was triggered,
+				// so trigger it manually so that the dependency count is properly decremented in case this resource
+				// is a dependency.
+				BS_LOCK_MUTEX(mLoadedResourceMutex);
+				auto iterFind = mLoadedResources.find(UUID);
+				if (iterFind != mLoadedResources.end())
+					loadComplete(outputResource);
+			}
+		}
+
+		return outputResource;
+	}
+
+	ResourcePtr Resources::loadFromDiskAndDeserialize(const Path& filePath)
+	{
+		FileDecoder fs(filePath);
+		fs.skip(); // Skipped over saved resource data
+		std::shared_ptr<IReflectable> loadedData = fs.decode();
+
+		if (loadedData == nullptr)
+		{
+			LOGERR("Unable to load resource at path \"" + filePath.toString() + "\"");
+		}
+		else
+		{
+			if (!loadedData->isDerivedFrom(Resource::getRTTIStatic()))
+				BS_EXCEPT(InternalErrorException, "Loaded class doesn't derive from Resource.");
+		}
+
+		ResourcePtr resource = std::static_pointer_cast<Resource>(loadedData);
+		return resource;
+	}
+
+	void Resources::release(ResourceHandleBase& resource)
+	{
+		const String& UUID = resource.getUUID();
+
+		{
+			bool loadInProgress = false;
+
+			BS_LOCK_MUTEX(mInProgressResourcesMutex);
+			auto iterFind2 = mInProgressResources.find(UUID);
+			if (iterFind2 != mInProgressResources.end())
+				loadInProgress = true;
+
+			// Technically we should be able to just cancel a load in progress instead of blocking until it finishes.
+			// However that would mean the last reference could get lost on whatever thread did the loading, which
+			// isn't something that's supported. If this ends up being a problem either make handle counting atomic
+			// or add a separate queue for objects destroyed from the load threads.
+			if (loadInProgress)
+				resource.blockUntilLoaded();
+
+			{
+				BS_LOCK_MUTEX(mLoadedResourceMutex);
+				auto iterFind = mLoadedResources.find(UUID);
+				if (iterFind != mLoadedResources.end()) // Resource is already loaded
+				{
+					LoadedResourceData& resData = iterFind->second;
+
+					assert(resData.numInternalRefs > 0);
+					resData.numInternalRefs--;
+					resource.removeInternalRef();
+
+					return;
+				}
+			}
+		}
+	}
+
+	void Resources::unloadAllUnused()
+	{
+		Vector<HResource> resourcesToUnload;
+
+		{
+			BS_LOCK_MUTEX(mLoadedResourceMutex);
+			for(auto iter = mLoadedResources.begin(); iter != mLoadedResources.end(); ++iter)
+			{
+				const LoadedResourceData& resData = iter->second;
+
+				if (resData.resource.mData->mRefCount == resData.numInternalRefs) // Only internal references exist, free it
+					resourcesToUnload.push_back(resData.resource.lock());
+			}
+		}
+
+		// Note: When unloading multiple resources it's possible that unloading one will also unload
+		// another resource in "resourcesToUnload". This is fine because "unload" deals with invalid
+		// handles gracefully.
+		for(auto iter = resourcesToUnload.begin(); iter != resourcesToUnload.end(); ++iter)
+		{
+			release(*iter);
+		}
+	}
+
+	void Resources::destroy(ResourceHandleBase& resource)
+	{
+		if (resource.mData == nullptr)
+			return;
+
+		const String& uuid = resource.getUUID();
+		if (!resource.isLoaded(false))
+		{
+			bool loadInProgress = false;
+			{
+				BS_LOCK_MUTEX(mInProgressResourcesMutex);
+				auto iterFind2 = mInProgressResources.find(uuid);
+				if (iterFind2 != mInProgressResources.end())
+					loadInProgress = true;
+			}
+
+			if (loadInProgress) // If it's still loading wait until that finishes
+				resource.blockUntilLoaded();
+			else
+				return; // Already unloaded
+		}
+
+		// Notify external systems before we actually destroy it
+		onResourceDestroyed(uuid);
+		resource.mData->mPtr->destroy();
+
+		{
+			BS_LOCK_MUTEX(mLoadedResourceMutex);
+
+			auto iterFind = mLoadedResources.find(uuid);
+			if (iterFind != mLoadedResources.end())
+			{
+				LoadedResourceData& resData = iterFind->second;
+				while (resData.numInternalRefs > 0)
+				{
+					resData.numInternalRefs--;
+					resData.resource.removeInternalRef();
+				}
+
+				mLoadedResources.erase(iterFind);
+			}
+			else
+			{
+				assert(false); // This should never happen but in case it does fail silently in release mode
+			}
+		}
+
+		resource.setHandleData(nullptr, uuid);
+	}
+
+	void Resources::save(const HResource& resource, const Path& filePath, bool overwrite)
+	{
+		if (resource == nullptr)
+			return;
+
+		if (!resource.isLoaded(false))
+		{
+			bool loadInProgress = false;
+			{
+				BS_LOCK_MUTEX(mInProgressResourcesMutex);
+				auto iterFind2 = mInProgressResources.find(resource.getUUID());
+				if (iterFind2 != mInProgressResources.end())
+					loadInProgress = true;
+			}
+
+			if (loadInProgress) // If it's still loading wait until that finishes
+				resource.blockUntilLoaded();
+			else
+				return; // Nothing to save
+		}
+
+		bool fileExists = FileSystem::isFile(filePath);
+		if(fileExists)
+		{
+			if(overwrite)
+				FileSystem::remove(filePath);
+			else
+				BS_EXCEPT(InvalidParametersException, "Another file exists at the specified location.");
+		}
+
+		mDefaultResourceManifest->registerResource(resource.getUUID(), filePath);
+
+		Vector<ResourceDependency> dependencyList = Utility::findResourceDependencies(*resource.get());
+
+		Vector<String> dependencyUUIDs(dependencyList.size());
+		for (UINT32 i = 0; i < (UINT32)dependencyList.size(); i++)
+			dependencyUUIDs[i] = dependencyList[i].resource.getUUID();
+
+		SPtr<SavedResourceData> resourceData = bs_shared_ptr_new<SavedResourceData>(dependencyUUIDs, resource->allowAsyncLoading());
+
+		FileEncoder fs(filePath);
+		fs.encode(resourceData.get());
+		fs.encode(resource.get());
+	}
+
+	void Resources::save(const HResource& resource)
+	{
+		if (resource == nullptr)
+			return;
+
+		Path path;
+		if (getFilePathFromUUID(resource.getUUID(), path))
+			save(resource, path, true);
+	}
+
+	void Resources::update(HResource& handle, const ResourcePtr& resource)
+	{
+		const String& uuid = handle.getUUID();
+		handle.setHandleData(resource, uuid);
+
+		{
+			BS_LOCK_MUTEX(mLoadedResourceMutex);
+			auto iterFind = mLoadedResources.find(uuid);
+			if (iterFind == mLoadedResources.end())
+			{
+				LoadedResourceData& resData = mLoadedResources[uuid];
+				resData.resource = handle.getWeak();
+			}
+		}
+
+		onResourceModified(handle);
+	}
+
+	Vector<String> Resources::getDependencies(const Path& filePath)
+	{
+		SPtr<SavedResourceData> savedResourceData;
+		if (!filePath.isEmpty())
+		{
+			FileDecoder fs(filePath);
+			savedResourceData = std::static_pointer_cast<SavedResourceData>(fs.decode());
+		}
+
+		return savedResourceData->getDependencies();
+	}
+
+	void Resources::registerResourceManifest(const ResourceManifestPtr& manifest)
+	{
+		if(manifest->getName() == "Default")
+			return;
+
+		auto findIter = std::find(mResourceManifests.begin(), mResourceManifests.end(), manifest);
+		if(findIter == mResourceManifests.end())
+			mResourceManifests.push_back(manifest);
+		else
+			*findIter = manifest;
+	}
+
+	void Resources::unregisterResourceManifest(const ResourceManifestPtr& manifest)
+	{
+		if (manifest->getName() == "Default")
+			return;
+
+		auto findIter = std::find(mResourceManifests.begin(), mResourceManifests.end(), manifest);
+		if (findIter != mResourceManifests.end())
+			mResourceManifests.erase(findIter);
+	}
+
+	ResourceManifestPtr Resources::getResourceManifest(const String& name) const
+	{
+		for(auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter) 
+		{
+			if(name == (*iter)->getName())
+				return (*iter);
+		}
+
+		return nullptr;
+	}
+
+	bool Resources::isLoaded(const String& uuid, bool checkInProgress)
+	{
+		if (checkInProgress)
+		{
+			BS_LOCK_MUTEX(mInProgressResourcesMutex);
+			auto iterFind2 = mInProgressResources.find(uuid);
+			if (iterFind2 != mInProgressResources.end())
+			{
+				return true;
+			}
+
+			{
+				BS_LOCK_MUTEX(mLoadedResourceMutex);
+				auto iterFind = mLoadedResources.find(uuid);
+				if (iterFind != mLoadedResources.end())
+				{
+					return true;
+				}
+			}
+		}
+
+		return false;
+	}
+
+	HResource Resources::_createResourceHandle(const ResourcePtr& obj)
+	{
+		String uuid = UUIDGenerator::generateRandom();
+		HResource newHandle(obj, uuid);
+
+		{
+			BS_LOCK_MUTEX(mLoadedResourceMutex);
+
+			LoadedResourceData& resData = mLoadedResources[uuid];
+			resData.resource = newHandle.getWeak();
+			mHandles[uuid] = newHandle.getWeak();
+		}
+	
+		return newHandle;
+	}
+
+	HResource Resources::_getResourceHandle(const String& uuid)
+	{
+		BS_LOCK_MUTEX(mLoadedResourceMutex);
+		auto iterFind3 = mHandles.find(uuid);
+		if (iterFind3 != mHandles.end()) // Not loaded, but handle does exist
+		{
+			return iterFind3->second.lock();
+		}
+
+		// Create new handle
+		HResource handle(uuid);
+		mHandles[uuid] = handle.getWeak();
+
+		return handle;
+	}
+
+	bool Resources::getFilePathFromUUID(const String& uuid, Path& filePath) const
+	{
+		for(auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter) 
+		{
+			if((*iter)->uuidToFilePath(uuid, filePath))
+				return true;
+		}
+
+		return false;
+	}
+
+	bool Resources::getUUIDFromFilePath(const Path& path, String& uuid) const
+	{
+		Path manifestPath = path;
+		if (!manifestPath.isAbsolute())
+			manifestPath.makeAbsolute(FileSystem::getWorkingDirectoryPath());
+
+		for(auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter) 
+		{
+			if ((*iter)->filePathToUUID(manifestPath, uuid))
+				return true;
+		}
+
+		return false;
+	}
+
+	void Resources::loadComplete(HResource& resource)
+	{
+		String uuid = resource.getUUID();
+
+		ResourceLoadData* myLoadData = nullptr;
+		bool finishLoad = true;
+		Vector<ResourceLoadData*> dependantLoads;
+		{
+			BS_LOCK_MUTEX(mInProgressResourcesMutex);
+
+			auto iterFind = mInProgressResources.find(uuid);
+			if (iterFind != mInProgressResources.end())
+			{
+				myLoadData = iterFind->second;
+				finishLoad = myLoadData->remainingDependencies == 0;
+				
+				if (finishLoad)
+					mInProgressResources.erase(iterFind);
+			}
+
+			auto iterFind2 = mDependantLoads.find(uuid);
+
+			if (iterFind2 != mDependantLoads.end())
+				dependantLoads = iterFind2->second;
+
+			if (finishLoad)
+			{
+				mDependantLoads.erase(uuid);
+
+				// If loadedData is null then we're probably completing load on an already loaded resource, triggered
+				// by its dependencies.
+				if (myLoadData != nullptr && myLoadData->loadedData != nullptr)
+				{
+					BS_LOCK_MUTEX(mLoadedResourceMutex);
+
+					mLoadedResources[uuid] = myLoadData->resData;
+					resource.setHandleData(myLoadData->loadedData, uuid);
+				}
+
+				for (auto& dependantLoad : dependantLoads)
+					dependantLoad->remainingDependencies--;
+			}
+		}
+
+		for (auto& dependantLoad : dependantLoads)
+		{
+			HResource dependant = dependantLoad->resData.resource.lock();
+			loadComplete(dependant);
+		}
+
+		if (finishLoad && myLoadData != nullptr)
+		{
+			onResourceLoaded(resource);
+
+			// This should only ever be true on the main thread
+			if (myLoadData->notifyImmediately)
+				ResourceListenerManager::instance().notifyListeners(uuid);
+
+			bs_delete(myLoadData);
+		}
+	}
+
+	void Resources::loadCallback(const Path& filePath, HResource& resource)
+	{
+		ResourcePtr rawResource = loadFromDiskAndDeserialize(filePath);
+
+		{
+			BS_LOCK_MUTEX(mInProgressResourcesMutex);
+
+			// Check if all my dependencies are loaded
+			ResourceLoadData* myLoadData = mInProgressResources[resource.getUUID()];
+			myLoadData->loadedData = rawResource;
+			myLoadData->remainingDependencies--;
+		}
+
+		loadComplete(resource);
+	}
+
+	BS_CORE_EXPORT Resources& gResources()
+	{
+		return Resources::instance();
+	}
 }
 }

+ 1 - 0
Source/BansheePhysX/Source/BsFPhysXCollider.cpp

@@ -26,6 +26,7 @@ namespace BansheeEngine
 		if (mStaticBody != nullptr)
 		if (mStaticBody != nullptr)
 			mStaticBody->release();
 			mStaticBody->release();
 
 
+		mShape->userData = nullptr;
 		mShape->release();
 		mShape->release();
 	}
 	}
 
 

+ 129 - 128
Source/BansheePhysX/Source/BsFPhysXJoint.cpp

@@ -1,129 +1,130 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsFPhysXJoint.h"
-#include "BsPhysXRigidbody.h"
-#include "PxRigidDynamic.h"
-
-using namespace physx;
-
-namespace BansheeEngine
-{
-	PxJointActorIndex::Enum toJointActor(JointBody body)
-	{
-		if (body == JointBody::A)
-			return PxJointActorIndex::eACTOR0;
-
-		return PxJointActorIndex::eACTOR1;
-	}
-
-	FPhysXJoint::FPhysXJoint(physx::PxJoint* joint)
-		:mJoint(joint)
-	{
-		
-	}
-
-	FPhysXJoint::~FPhysXJoint()
-	{
-		mJoint->release();
-	}
-
-	Rigidbody* FPhysXJoint::getBody(JointBody body) const
-	{
-		PxRigidActor* actorA = nullptr;
-		PxRigidActor* actorB = nullptr;
-
-		mJoint->getActors(actorA, actorB);
-
-		PxRigidActor* wantedActor = body == JointBody::A ? actorA : actorB;
-		if (wantedActor == nullptr)
-			return nullptr;
-
-		return (Rigidbody*)wantedActor->userData;
-	}
-
-	void FPhysXJoint::setBody(JointBody body, Rigidbody* value)
-	{
-		PxRigidActor* actorA = nullptr;
-		PxRigidActor* actorB = nullptr;
-
-		mJoint->getActors(actorA, actorB);
-
-		PxRigidActor* actor = nullptr;
-		if (value != nullptr)
-			actor = static_cast<PhysXRigidbody*>(value)->_getInternal();
-
-		if (body == JointBody::A)
-			actorA = actor;
-		else
-			actorB = actor;
-
-		mJoint->setActors(actorA, actorB);
-	}
-
-	Vector3 FPhysXJoint::getPosition(JointBody body) const
-	{
-		PxVec3 position = mJoint->getLocalPose(toJointActor(body)).p;
-
-		return fromPxVector(position);
-	}
-
-	Quaternion FPhysXJoint::getRotation(JointBody body) const
-	{
-		PxQuat rotation = mJoint->getLocalPose(toJointActor(body)).q;
-
-		return fromPxQuaternion(rotation);
-	}
-
-	void FPhysXJoint::setTransform(JointBody body, const Vector3& position, const Quaternion& rotation)
-	{
-		PxTransform transform = toPxTransform(position, rotation);
-
-		mJoint->setLocalPose(toJointActor(body), transform);
-	}
-
-	float FPhysXJoint::getBreakForce() const
-	{
-		float force = 0.0f;
-		float torque = 0.0f;
-
-		mJoint->getBreakForce(force, torque);
-		return force;
-	}
-
-	void FPhysXJoint::setBreakForce(float force)
-	{
-		float dummy = 0.0f;
-		float torque = 0.0f;
-
-		mJoint->getBreakForce(dummy, torque);
-		mJoint->setBreakForce(force, torque);
-	}
-
-	float FPhysXJoint::getBreakTorque() const
-	{
-		float force = 0.0f;
-		float torque = 0.0f;
-
-		mJoint->getBreakForce(force, torque);
-		return torque;
-	}
-
-	void FPhysXJoint::setBreakTorque(float torque)
-	{
-		float force = 0.0f;
-		float dummy = 0.0f;
-
-		mJoint->getBreakForce(force, dummy);
-		mJoint->setBreakForce(force, torque);
-	}
-
-	bool FPhysXJoint::getEnableCollision() const
-	{
-		return mJoint->getConstraintFlags() & PxConstraintFlag::eCOLLISION_ENABLED;
-	}
-
-	void FPhysXJoint::setEnableCollision(bool value)
-	{
-		mJoint->setConstraintFlag(PxConstraintFlag::eCOLLISION_ENABLED, value);
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsFPhysXJoint.h"
+#include "BsPhysXRigidbody.h"
+#include "PxRigidDynamic.h"
+
+using namespace physx;
+
+namespace BansheeEngine
+{
+	PxJointActorIndex::Enum toJointActor(JointBody body)
+	{
+		if (body == JointBody::A)
+			return PxJointActorIndex::eACTOR0;
+
+		return PxJointActorIndex::eACTOR1;
+	}
+
+	FPhysXJoint::FPhysXJoint(physx::PxJoint* joint)
+		:mJoint(joint)
+	{
+		
+	}
+
+	FPhysXJoint::~FPhysXJoint()
+	{
+		mJoint->userData = nullptr;
+		mJoint->release();
+	}
+
+	Rigidbody* FPhysXJoint::getBody(JointBody body) const
+	{
+		PxRigidActor* actorA = nullptr;
+		PxRigidActor* actorB = nullptr;
+
+		mJoint->getActors(actorA, actorB);
+
+		PxRigidActor* wantedActor = body == JointBody::A ? actorA : actorB;
+		if (wantedActor == nullptr)
+			return nullptr;
+
+		return (Rigidbody*)wantedActor->userData;
+	}
+
+	void FPhysXJoint::setBody(JointBody body, Rigidbody* value)
+	{
+		PxRigidActor* actorA = nullptr;
+		PxRigidActor* actorB = nullptr;
+
+		mJoint->getActors(actorA, actorB);
+
+		PxRigidActor* actor = nullptr;
+		if (value != nullptr)
+			actor = static_cast<PhysXRigidbody*>(value)->_getInternal();
+
+		if (body == JointBody::A)
+			actorA = actor;
+		else
+			actorB = actor;
+
+		mJoint->setActors(actorA, actorB);
+	}
+
+	Vector3 FPhysXJoint::getPosition(JointBody body) const
+	{
+		PxVec3 position = mJoint->getLocalPose(toJointActor(body)).p;
+
+		return fromPxVector(position);
+	}
+
+	Quaternion FPhysXJoint::getRotation(JointBody body) const
+	{
+		PxQuat rotation = mJoint->getLocalPose(toJointActor(body)).q;
+
+		return fromPxQuaternion(rotation);
+	}
+
+	void FPhysXJoint::setTransform(JointBody body, const Vector3& position, const Quaternion& rotation)
+	{
+		PxTransform transform = toPxTransform(position, rotation);
+
+		mJoint->setLocalPose(toJointActor(body), transform);
+	}
+
+	float FPhysXJoint::getBreakForce() const
+	{
+		float force = 0.0f;
+		float torque = 0.0f;
+
+		mJoint->getBreakForce(force, torque);
+		return force;
+	}
+
+	void FPhysXJoint::setBreakForce(float force)
+	{
+		float dummy = 0.0f;
+		float torque = 0.0f;
+
+		mJoint->getBreakForce(dummy, torque);
+		mJoint->setBreakForce(force, torque);
+	}
+
+	float FPhysXJoint::getBreakTorque() const
+	{
+		float force = 0.0f;
+		float torque = 0.0f;
+
+		mJoint->getBreakForce(force, torque);
+		return torque;
+	}
+
+	void FPhysXJoint::setBreakTorque(float torque)
+	{
+		float force = 0.0f;
+		float dummy = 0.0f;
+
+		mJoint->getBreakForce(force, dummy);
+		mJoint->setBreakForce(force, torque);
+	}
+
+	bool FPhysXJoint::getEnableCollision() const
+	{
+		return mJoint->getConstraintFlags() & PxConstraintFlag::eCOLLISION_ENABLED;
+	}
+
+	void FPhysXJoint::setEnableCollision(bool value)
+	{
+		mJoint->setConstraintFlag(PxConstraintFlag::eCOLLISION_ENABLED, value);
+	}
 }
 }

+ 23 - 12
Source/BansheePhysX/Source/BsPhysX.cpp

@@ -132,6 +132,8 @@ namespace BansheeEngine
 			for (PxU32 i = 0; i < count; i++)
 			for (PxU32 i = 0; i < count; i++)
 			{
 			{
 				const PxTriggerPair& pair = pairs[i];
 				const PxTriggerPair& pair = pairs[i];
+				if (pair.triggerShape->userData == nullptr)
+					continue;
 				
 				
 				PhysX::ContactEventType type;
 				PhysX::ContactEventType type;
 				bool ignoreContact = false;
 				bool ignoreContact = false;
@@ -270,9 +272,12 @@ namespace BansheeEngine
 					continue;
 					continue;
 
 
 				PxJoint* pxJoint = (PxJoint*)constraintInfo.externalReference;
 				PxJoint* pxJoint = (PxJoint*)constraintInfo.externalReference;
-				Joint* joint = (Joint*)pxJoint->userData;
 
 
-				
+				PhysX::JointBreakEvent event;
+				event.joint = (Joint*)pxJoint->userData;
+
+				if(event.joint != nullptr)
+					gPhysX()._reportJointBreakEvent(event);
 			}
 			}
 		}
 		}
 	};
 	};
@@ -675,19 +680,25 @@ namespace BansheeEngine
 
 
 		for (auto& entry : mContactEvents)
 		for (auto& entry : mContactEvents)
 		{
 		{
-			CollisionReportMode reportModeA = entry.colliderA->getCollisionReportMode();
+			if (entry.colliderA != nullptr)
+			{
+				CollisionReportMode reportModeA = entry.colliderA->getCollisionReportMode();
 
 
-			if (reportModeA == CollisionReportMode::ReportPersistent)
-				notifyContact(entry.colliderA, entry.colliderB, entry.type, entry.points, true);
-			else if (reportModeA == CollisionReportMode::Report && entry.type != ContactEventType::ContactStay)
-				notifyContact(entry.colliderA, entry.colliderB, entry.type, entry.points, true);
+				if (reportModeA == CollisionReportMode::ReportPersistent)
+					notifyContact(entry.colliderA, entry.colliderB, entry.type, entry.points, true);
+				else if (reportModeA == CollisionReportMode::Report && entry.type != ContactEventType::ContactStay)
+					notifyContact(entry.colliderA, entry.colliderB, entry.type, entry.points, true);
+			}
 
 
-			CollisionReportMode reportModeB = entry.colliderB->getCollisionReportMode();
+			if (entry.colliderB != nullptr)
+			{
+				CollisionReportMode reportModeB = entry.colliderB->getCollisionReportMode();
 
 
-			if (reportModeB == CollisionReportMode::ReportPersistent)
-				notifyContact(entry.colliderB, entry.colliderA, entry.type, entry.points, false);
-			else if (reportModeB == CollisionReportMode::Report && entry.type != ContactEventType::ContactStay)
-				notifyContact(entry.colliderB, entry.colliderA, entry.type, entry.points, false);
+				if (reportModeB == CollisionReportMode::ReportPersistent)
+					notifyContact(entry.colliderB, entry.colliderA, entry.type, entry.points, false);
+				else if (reportModeB == CollisionReportMode::Report && entry.type != ContactEventType::ContactStay)
+					notifyContact(entry.colliderB, entry.colliderA, entry.type, entry.points, false);
+			}
 		}
 		}
 
 
 		for(auto& entry : mJointBreakEvents)
 		for(auto& entry : mJointBreakEvents)

+ 277 - 276
Source/BansheePhysX/Source/BsPhysXCharacterController.cpp

@@ -1,277 +1,278 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsPhysXCharacterController.h"
-#include "BsTime.h"
-#include "BsPhysX.h"
-#include "BsCCollider.h"
-#include "characterkinematic\PxControllerManager.h"
-
-using namespace physx;
-
-namespace BansheeEngine
-{
-	PxExtendedVec3 toPxExtVector(const Vector3& input)
-	{
-		return PxExtendedVec3(input.x, input.y, input.z);
-	}
-
-	Vector3 fromPxExtVector(const PxExtendedVec3& input)
-	{
-		return Vector3((float)input.x, (float)input.y, (float)input.z);
-	}
-
-	PxCapsuleClimbingMode::Enum toPxEnum(CharacterClimbingMode value)
-	{
-		return value == CharacterClimbingMode::Normal
-			? PxCapsuleClimbingMode::eEASY
-			: PxCapsuleClimbingMode::eCONSTRAINED;
-	}
-
-	PxControllerNonWalkableMode::Enum toPxEnum(CharacterNonWalkableMode value)
-	{
-		return value == CharacterNonWalkableMode::Prevent
-			? PxControllerNonWalkableMode::ePREVENT_CLIMBING
-			: PxControllerNonWalkableMode::ePREVENT_CLIMBING_AND_FORCE_SLIDING;
-	}
-
-	CharacterClimbingMode fromPxEnum(PxCapsuleClimbingMode::Enum value)
-	{
-		return value == PxCapsuleClimbingMode::eEASY
-			? CharacterClimbingMode::Normal
-			: CharacterClimbingMode::Constrained;
-	}
-
-	CharacterNonWalkableMode fromPxEnum(PxControllerNonWalkableMode::Enum value)
-	{
-		return value == PxControllerNonWalkableMode::ePREVENT_CLIMBING
-			? CharacterNonWalkableMode::Prevent
-			: CharacterNonWalkableMode::PreventAndSlide;
-	}
-
-	PxCapsuleControllerDesc toPxDesc(const CHAR_CONTROLLER_DESC& desc)
-	{
-		PxCapsuleControllerDesc output;
-		output.climbingMode = toPxEnum(desc.climbingMode);
-		output.nonWalkableMode = toPxEnum(desc.nonWalkableMode);
-		output.contactOffset = desc.contactOffset;
-		output.stepOffset = desc.stepOffset;
-		output.slopeLimit = desc.slopeLimit.valueRadians();
-		output.height = desc.height;
-		output.radius = desc.radius;
-		output.upDirection = toPxVector(desc.up);
-		output.position = toPxExtVector(desc.position);
-
-		return output;
-	}
-
-	PhysXCharacterController::PhysXCharacterController(PxControllerManager* manager, const CHAR_CONTROLLER_DESC& desc)
-		:CharacterController(desc)
-	{
-		PxCapsuleControllerDesc pxDesc = toPxDesc(desc);
-		pxDesc.reportCallback = this;
-
-		mController = static_cast<PxCapsuleController*>(manager->createController(pxDesc));
-		mController->setUserData(this);
-	}
-
-	PhysXCharacterController::~PhysXCharacterController()
-	{
-		mController->release();
-	}
-
-	CharacterCollisionFlags PhysXCharacterController::move(const Vector3& displacement)
-	{
-		PxControllerFilters filters;
-		filters.mFilterCallback = this;
-		filters.mFilterFlags = PxQueryFlag::eANY_HIT | PxQueryFlag::eSTATIC | PxQueryFlag::eDYNAMIC | PxQueryFlag::ePREFILTER;
-		filters.mCCTFilterCallback = this;
-
-		float curTime = gTime().getTime();
-		float delta = curTime - mLastMoveCall;
-		mLastMoveCall = curTime;
-
-		PxControllerCollisionFlags collisionFlag = mController->move(toPxVector(displacement), mMinMoveDistance, delta, filters);
-
-		CharacterCollisionFlags output;
-		if (collisionFlag.isSet(PxControllerCollisionFlag::eCOLLISION_DOWN))
-			output.set(CharacterCollisionFlag::Down);
-
-		if (collisionFlag.isSet(PxControllerCollisionFlag::eCOLLISION_UP))
-			output.set(CharacterCollisionFlag::Up);
-
-		if (collisionFlag.isSet(PxControllerCollisionFlag::eCOLLISION_SIDES))
-			output.set(CharacterCollisionFlag::Sides);
-
-		return output;
-	}
-
-	Vector3 PhysXCharacterController::getPosition() const
-	{
-		return fromPxExtVector(mController->getPosition());
-	}
-
-	void PhysXCharacterController::setPosition(const Vector3& position)
-	{
-		mController->setPosition(toPxExtVector(position));
-	}
-
-	Vector3 PhysXCharacterController::getFootPosition() const
-	{
-		return fromPxExtVector(mController->getFootPosition());
-	}
-
-	void PhysXCharacterController::setFootPosition(const Vector3& position)
-	{
-		mController->setFootPosition(toPxExtVector(position));
-	}
-
-	float PhysXCharacterController::getRadius() const
-	{
-		return mController->getRadius();
-	}
-
-	void PhysXCharacterController::setRadius(float radius)
-	{
-		mController->setRadius(radius);
-	}
-
-	float PhysXCharacterController::getHeight() const
-	{
-		return mController->getHeight();
-	}
-
-	void PhysXCharacterController::setHeight(float height)
-	{
-		mController->setHeight(height);
-	}
-
-	Vector3 PhysXCharacterController::getUp() const
-	{
-		return fromPxVector(mController->getUpDirection());
-	}
-
-	void PhysXCharacterController::setUp(const Vector3& up)
-	{
-		mController->setUpDirection(toPxVector(up));
-	}
-
-	CharacterClimbingMode PhysXCharacterController::getClimbingMode() const
-	{
-		return fromPxEnum(mController->getClimbingMode());
-	}
-
-	void PhysXCharacterController::setClimbingMode(CharacterClimbingMode mode)
-	{
-		mController->setClimbingMode(toPxEnum(mode));
-	}
-
-	CharacterNonWalkableMode PhysXCharacterController::getNonWalkableMode() const
-	{
-		return fromPxEnum(mController->getNonWalkableMode());
-	}
-
-	void PhysXCharacterController::setNonWalkableMode(CharacterNonWalkableMode mode)
-	{
-		mController->setNonWalkableMode(toPxEnum(mode));
-	}
-
-	float PhysXCharacterController::getMinMoveDistance() const
-	{
-		return mMinMoveDistance;
-	}
-
-	void PhysXCharacterController::setMinMoveDistance(float value)
-	{
-		mMinMoveDistance = value;
-	}
-
-	float PhysXCharacterController::getContactOffset() const
-	{
-		return mController->getContactOffset();
-	}
-
-	void PhysXCharacterController::setContactOffset(float value)
-	{
-		mController->setContactOffset(value);
-	}
-
-	float PhysXCharacterController::getStepOffset() const
-	{
-		return mController->getStepOffset();
-	}
-
-	void PhysXCharacterController::setStepOffset(float value)
-	{
-		mController->setStepOffset(value);
-	}
-
-	Radian PhysXCharacterController::getSlopeLimit() const
-	{
-		return Radian(mController->getSlopeLimit());
-	}
-
-	void PhysXCharacterController::setSlopeLimit(Radian value)
-	{
-		mController->setSlopeLimit(value.valueRadians());
-	}
-
-	void PhysXCharacterController::onShapeHit(const PxControllerShapeHit& hit)
-	{
-		if (onColliderHit.empty())
-			return;
-
-		ControllerColliderCollision collision;
-		collision.position = fromPxExtVector(hit.worldPos);
-		collision.normal = fromPxVector(hit.worldNormal);
-		collision.motionDir = fromPxVector(hit.dir);
-		collision.motionAmount = hit.length;
-		collision.triangleIndex = hit.triangleIndex;
-		collision.colliderRaw = (Collider*)hit.shape->userData;
-
-		onColliderHit(collision);
-	}
-
-	void PhysXCharacterController::onControllerHit(const PxControllersHit& hit)
-	{
-		if (CharacterController::onControllerHit.empty())
-			return;
-
-		ControllerControllerCollision collision;
-		collision.position = fromPxExtVector(hit.worldPos);
-		collision.normal = fromPxVector(hit.worldNormal);
-		collision.motionDir = fromPxVector(hit.dir);
-		collision.motionAmount = hit.length;
-		collision.controllerRaw = (CharacterController*)hit.controller->getUserData();
-
-		CharacterController::onControllerHit(collision);
-	}
-
-	PxQueryHitType::Enum PhysXCharacterController::preFilter(const PxFilterData& filterData, const PxShape* shape,
-		const PxRigidActor* actor, PxHitFlags& queryFlags)
-	{
-		PxFilterData colliderFilterData = shape->getSimulationFilterData();
-		UINT64 colliderLayer = *(UINT64*)&colliderFilterData.word0;
-
-		bool canCollide = gPhysics().isCollisionEnabled(colliderLayer, getLayer());
-
-		if(canCollide)
-			return PxSceneQueryHitType::eBLOCK;
-
-		return PxSceneQueryHitType::eNONE;
-	}
-
-	PxQueryHitType::Enum PhysXCharacterController::postFilter(const PxFilterData& filterData,
-		const PxQueryHit& hit)
-	{
-		return PxSceneQueryHitType::eBLOCK;
-	}
-
-	bool PhysXCharacterController::filter(const PxController& a, const PxController& b)
-	{
-		CharacterController* controllerA = (CharacterController*)a.getUserData();
-		CharacterController* controllerB = (CharacterController*)b.getUserData();
-
-		bool canCollide = gPhysics().isCollisionEnabled(controllerA->getLayer(), controllerB->getLayer());
-		return canCollide;
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsPhysXCharacterController.h"
+#include "BsTime.h"
+#include "BsPhysX.h"
+#include "BsCCollider.h"
+#include "characterkinematic\PxControllerManager.h"
+
+using namespace physx;
+
+namespace BansheeEngine
+{
+	PxExtendedVec3 toPxExtVector(const Vector3& input)
+	{
+		return PxExtendedVec3(input.x, input.y, input.z);
+	}
+
+	Vector3 fromPxExtVector(const PxExtendedVec3& input)
+	{
+		return Vector3((float)input.x, (float)input.y, (float)input.z);
+	}
+
+	PxCapsuleClimbingMode::Enum toPxEnum(CharacterClimbingMode value)
+	{
+		return value == CharacterClimbingMode::Normal
+			? PxCapsuleClimbingMode::eEASY
+			: PxCapsuleClimbingMode::eCONSTRAINED;
+	}
+
+	PxControllerNonWalkableMode::Enum toPxEnum(CharacterNonWalkableMode value)
+	{
+		return value == CharacterNonWalkableMode::Prevent
+			? PxControllerNonWalkableMode::ePREVENT_CLIMBING
+			: PxControllerNonWalkableMode::ePREVENT_CLIMBING_AND_FORCE_SLIDING;
+	}
+
+	CharacterClimbingMode fromPxEnum(PxCapsuleClimbingMode::Enum value)
+	{
+		return value == PxCapsuleClimbingMode::eEASY
+			? CharacterClimbingMode::Normal
+			: CharacterClimbingMode::Constrained;
+	}
+
+	CharacterNonWalkableMode fromPxEnum(PxControllerNonWalkableMode::Enum value)
+	{
+		return value == PxControllerNonWalkableMode::ePREVENT_CLIMBING
+			? CharacterNonWalkableMode::Prevent
+			: CharacterNonWalkableMode::PreventAndSlide;
+	}
+
+	PxCapsuleControllerDesc toPxDesc(const CHAR_CONTROLLER_DESC& desc)
+	{
+		PxCapsuleControllerDesc output;
+		output.climbingMode = toPxEnum(desc.climbingMode);
+		output.nonWalkableMode = toPxEnum(desc.nonWalkableMode);
+		output.contactOffset = desc.contactOffset;
+		output.stepOffset = desc.stepOffset;
+		output.slopeLimit = desc.slopeLimit.valueRadians();
+		output.height = desc.height;
+		output.radius = desc.radius;
+		output.upDirection = toPxVector(desc.up);
+		output.position = toPxExtVector(desc.position);
+
+		return output;
+	}
+
+	PhysXCharacterController::PhysXCharacterController(PxControllerManager* manager, const CHAR_CONTROLLER_DESC& desc)
+		:CharacterController(desc)
+	{
+		PxCapsuleControllerDesc pxDesc = toPxDesc(desc);
+		pxDesc.reportCallback = this;
+
+		mController = static_cast<PxCapsuleController*>(manager->createController(pxDesc));
+		mController->setUserData(this);
+	}
+
+	PhysXCharacterController::~PhysXCharacterController()
+	{
+		mController->setUserData(nullptr);
+		mController->release();
+	}
+
+	CharacterCollisionFlags PhysXCharacterController::move(const Vector3& displacement)
+	{
+		PxControllerFilters filters;
+		filters.mFilterCallback = this;
+		filters.mFilterFlags = PxQueryFlag::eANY_HIT | PxQueryFlag::eSTATIC | PxQueryFlag::eDYNAMIC | PxQueryFlag::ePREFILTER;
+		filters.mCCTFilterCallback = this;
+
+		float curTime = gTime().getTime();
+		float delta = curTime - mLastMoveCall;
+		mLastMoveCall = curTime;
+
+		PxControllerCollisionFlags collisionFlag = mController->move(toPxVector(displacement), mMinMoveDistance, delta, filters);
+
+		CharacterCollisionFlags output;
+		if (collisionFlag.isSet(PxControllerCollisionFlag::eCOLLISION_DOWN))
+			output.set(CharacterCollisionFlag::Down);
+
+		if (collisionFlag.isSet(PxControllerCollisionFlag::eCOLLISION_UP))
+			output.set(CharacterCollisionFlag::Up);
+
+		if (collisionFlag.isSet(PxControllerCollisionFlag::eCOLLISION_SIDES))
+			output.set(CharacterCollisionFlag::Sides);
+
+		return output;
+	}
+
+	Vector3 PhysXCharacterController::getPosition() const
+	{
+		return fromPxExtVector(mController->getPosition());
+	}
+
+	void PhysXCharacterController::setPosition(const Vector3& position)
+	{
+		mController->setPosition(toPxExtVector(position));
+	}
+
+	Vector3 PhysXCharacterController::getFootPosition() const
+	{
+		return fromPxExtVector(mController->getFootPosition());
+	}
+
+	void PhysXCharacterController::setFootPosition(const Vector3& position)
+	{
+		mController->setFootPosition(toPxExtVector(position));
+	}
+
+	float PhysXCharacterController::getRadius() const
+	{
+		return mController->getRadius();
+	}
+
+	void PhysXCharacterController::setRadius(float radius)
+	{
+		mController->setRadius(radius);
+	}
+
+	float PhysXCharacterController::getHeight() const
+	{
+		return mController->getHeight();
+	}
+
+	void PhysXCharacterController::setHeight(float height)
+	{
+		mController->setHeight(height);
+	}
+
+	Vector3 PhysXCharacterController::getUp() const
+	{
+		return fromPxVector(mController->getUpDirection());
+	}
+
+	void PhysXCharacterController::setUp(const Vector3& up)
+	{
+		mController->setUpDirection(toPxVector(up));
+	}
+
+	CharacterClimbingMode PhysXCharacterController::getClimbingMode() const
+	{
+		return fromPxEnum(mController->getClimbingMode());
+	}
+
+	void PhysXCharacterController::setClimbingMode(CharacterClimbingMode mode)
+	{
+		mController->setClimbingMode(toPxEnum(mode));
+	}
+
+	CharacterNonWalkableMode PhysXCharacterController::getNonWalkableMode() const
+	{
+		return fromPxEnum(mController->getNonWalkableMode());
+	}
+
+	void PhysXCharacterController::setNonWalkableMode(CharacterNonWalkableMode mode)
+	{
+		mController->setNonWalkableMode(toPxEnum(mode));
+	}
+
+	float PhysXCharacterController::getMinMoveDistance() const
+	{
+		return mMinMoveDistance;
+	}
+
+	void PhysXCharacterController::setMinMoveDistance(float value)
+	{
+		mMinMoveDistance = value;
+	}
+
+	float PhysXCharacterController::getContactOffset() const
+	{
+		return mController->getContactOffset();
+	}
+
+	void PhysXCharacterController::setContactOffset(float value)
+	{
+		mController->setContactOffset(value);
+	}
+
+	float PhysXCharacterController::getStepOffset() const
+	{
+		return mController->getStepOffset();
+	}
+
+	void PhysXCharacterController::setStepOffset(float value)
+	{
+		mController->setStepOffset(value);
+	}
+
+	Radian PhysXCharacterController::getSlopeLimit() const
+	{
+		return Radian(mController->getSlopeLimit());
+	}
+
+	void PhysXCharacterController::setSlopeLimit(Radian value)
+	{
+		mController->setSlopeLimit(value.valueRadians());
+	}
+
+	void PhysXCharacterController::onShapeHit(const PxControllerShapeHit& hit)
+	{
+		if (onColliderHit.empty())
+			return;
+
+		ControllerColliderCollision collision;
+		collision.position = fromPxExtVector(hit.worldPos);
+		collision.normal = fromPxVector(hit.worldNormal);
+		collision.motionDir = fromPxVector(hit.dir);
+		collision.motionAmount = hit.length;
+		collision.triangleIndex = hit.triangleIndex;
+		collision.colliderRaw = (Collider*)hit.shape->userData;
+
+		onColliderHit(collision);
+	}
+
+	void PhysXCharacterController::onControllerHit(const PxControllersHit& hit)
+	{
+		if (CharacterController::onControllerHit.empty())
+			return;
+
+		ControllerControllerCollision collision;
+		collision.position = fromPxExtVector(hit.worldPos);
+		collision.normal = fromPxVector(hit.worldNormal);
+		collision.motionDir = fromPxVector(hit.dir);
+		collision.motionAmount = hit.length;
+		collision.controllerRaw = (CharacterController*)hit.controller->getUserData();
+
+		CharacterController::onControllerHit(collision);
+	}
+
+	PxQueryHitType::Enum PhysXCharacterController::preFilter(const PxFilterData& filterData, const PxShape* shape,
+		const PxRigidActor* actor, PxHitFlags& queryFlags)
+	{
+		PxFilterData colliderFilterData = shape->getSimulationFilterData();
+		UINT64 colliderLayer = *(UINT64*)&colliderFilterData.word0;
+
+		bool canCollide = gPhysics().isCollisionEnabled(colliderLayer, getLayer());
+
+		if(canCollide)
+			return PxSceneQueryHitType::eBLOCK;
+
+		return PxSceneQueryHitType::eNONE;
+	}
+
+	PxQueryHitType::Enum PhysXCharacterController::postFilter(const PxFilterData& filterData,
+		const PxQueryHit& hit)
+	{
+		return PxSceneQueryHitType::eBLOCK;
+	}
+
+	bool PhysXCharacterController::filter(const PxController& a, const PxController& b)
+	{
+		CharacterController* controllerA = (CharacterController*)a.getUserData();
+		CharacterController* controllerB = (CharacterController*)b.getUserData();
+
+		bool canCollide = gPhysics().isCollisionEnabled(controllerA->getLayer(), controllerB->getLayer());
+		return canCollide;
+	}
 }
 }

+ 1 - 0
Source/MBansheeEngine/Physics/Joint.cs

@@ -247,6 +247,7 @@ namespace BansheeEngine
         private void RestoreNative()
         private void RestoreNative()
 	    {
 	    {
             native = CreateNative();
             native = CreateNative();
+            native.Component = this;
 
 
             // Note: Merge into one call to avoid many virtual function calls
             // Note: Merge into one call to avoid many virtual function calls
             Rigidbody[] bodies = new Rigidbody[2];
             Rigidbody[] bodies = new Rigidbody[2];

+ 187 - 179
Source/MBansheeEngine/Physics/NativeCharacterController.cs

@@ -1,179 +1,187 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-using System;
-using System.Runtime.CompilerServices;
-
-namespace BansheeEngine
-{
-    /// <summary>
-    /// Wrapper around the native CharacterController class.
-    /// <see cref="CharacterController"/>
-    /// </summary>
-    internal class NativeCharacterController : ScriptObject
-    {
-        private CharacterController component;
-
-        /// <summary>
-        /// Component that owns the native character controller object.
-        /// </summary>
-        public CharacterController Component
-        {
-            get { return component; }
-            set { component = value; }
-        }
-
-        public Vector3 Position
-        {
-            get { Vector3 pos; Internal_GetPosition(mCachedPtr, out pos); return pos; }
-            set { Internal_SetPosition(mCachedPtr, ref value); }
-        }
-
-        public Vector3 FootPosition
-        {
-            get { Vector3 pos; Internal_GetFootPosition(mCachedPtr, out pos); return pos; }
-            set { Internal_SetFootPosition(mCachedPtr, ref value); }
-        }
-
-        public float Radius
-        {
-            set { Internal_SetRadius(mCachedPtr, value); }
-        }
-
-        public float Height
-        {
-            set { Internal_SetHeight(mCachedPtr, value); }
-        }
-
-        public Vector3 Up
-        {
-            set { Internal_SetUp(mCachedPtr, ref value); }
-        }
-
-        public CharacterClimbingMode ClimbingMode
-        {
-            set { Internal_SetClimbingMode(mCachedPtr, value); }
-        }
-
-        public CharacterNonWalkableMode NonWalkableMode
-        {
-            set { Internal_SetNonWalkableMode(mCachedPtr, value); }
-        }
-
-        public float MinMoveDistance
-        {
-            set { Internal_SetMinMoveDistance(mCachedPtr, value); }
-        }
-
-        public float ContactOffset
-        {
-            set { Internal_SetContactOffset(mCachedPtr, value); }
-        }
-
-        public float StepOffset
-        {
-            set { Internal_SetStepOffset(mCachedPtr, value); }
-        }
-
-        public Radian SlopeLimit
-        {
-            set { Internal_SetSlopeLimit(mCachedPtr, value.Radians); }
-        }
-
-        public ulong Layer
-        {
-            set { Internal_SetLayer(mCachedPtr, value); }
-        }
-
-        public NativeCharacterController(ScriptCharacterControllerData initData)
-        {
-            Internal_CreateInstance(this, ref initData);
-        }
-
-        public void Destroy()
-        {
-            Internal_Destroy(mCachedPtr);
-        }
-
-        public void Move(Vector3 position)
-        {
-            Internal_Move(mCachedPtr, ref position);
-        }
-
-        private void Internal_DoOnColliderHit(ScriptControllerCollision scriptCollisionData)
-        {
-            ControllerColliderCollision collisionData = new ControllerColliderCollision();
-            collisionData.position = scriptCollisionData.position;
-            collisionData.normal = scriptCollisionData.normal;
-            collisionData.motionDir = scriptCollisionData.motionDir;
-            collisionData.motionAmount = scriptCollisionData.motionAmount;
-            collisionData.triangleIndex = scriptCollisionData.triangleIndex;
-            collisionData.collider = scriptCollisionData.collider.Component;
-
-            Component.DoOnColliderHit(collisionData);
-        }
-
-        private void Internal_DoOnControllerHit(ScriptControllerCollision scriptCollisionData)
-        {
-            ControllerControllerCollision collisionData = new ControllerControllerCollision();
-            collisionData.position = scriptCollisionData.position;
-            collisionData.normal = scriptCollisionData.normal;
-            collisionData.motionDir = scriptCollisionData.motionDir;
-            collisionData.motionAmount = scriptCollisionData.motionAmount;
-            collisionData.controller = scriptCollisionData.controller.Component;
-
-            Component.DoOnControllerHit(collisionData);
-        }
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_CreateInstance(NativeCharacterController instance, 
-            ref ScriptCharacterControllerData initData);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_Destroy(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_Move(IntPtr thisPtr, ref Vector3 position);
-        
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetPosition(IntPtr thisPtr, out Vector3 position);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetPosition(IntPtr thisPtr, ref Vector3 position);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetFootPosition(IntPtr thisPtr, out Vector3 position);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetFootPosition(IntPtr thisPtr, ref Vector3 position);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetRadius(IntPtr thisPtr, float radius);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetHeight(IntPtr thisPtr, float height);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetUp(IntPtr thisPtr, ref Vector3 up);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetClimbingMode(IntPtr thisPtr, CharacterClimbingMode mode);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetNonWalkableMode(IntPtr thisPtr, CharacterNonWalkableMode mode);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetMinMoveDistance(IntPtr thisPtr, float value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetContactOffset(IntPtr thisPtr, float value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetStepOffset(IntPtr thisPtr, float value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetSlopeLimit(IntPtr thisPtr, float value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetLayer(IntPtr thisPtr, ulong layer);
-    }
-}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System;
+using System.Runtime.CompilerServices;
+
+namespace BansheeEngine
+{
+    /// <summary>
+    /// Wrapper around the native CharacterController class.
+    /// <see cref="CharacterController"/>
+    /// </summary>
+    internal class NativeCharacterController : ScriptObject
+    {
+        private CharacterController component;
+
+        /// <summary>
+        /// Component that owns the native character controller object.
+        /// </summary>
+        public CharacterController Component
+        {
+            get { return component; }
+            set { component = value; }
+        }
+
+        public Vector3 Position
+        {
+            get { Vector3 pos; Internal_GetPosition(mCachedPtr, out pos); return pos; }
+            set { Internal_SetPosition(mCachedPtr, ref value); }
+        }
+
+        public Vector3 FootPosition
+        {
+            get { Vector3 pos; Internal_GetFootPosition(mCachedPtr, out pos); return pos; }
+            set { Internal_SetFootPosition(mCachedPtr, ref value); }
+        }
+
+        public float Radius
+        {
+            set { Internal_SetRadius(mCachedPtr, value); }
+        }
+
+        public float Height
+        {
+            set { Internal_SetHeight(mCachedPtr, value); }
+        }
+
+        public Vector3 Up
+        {
+            set { Internal_SetUp(mCachedPtr, ref value); }
+        }
+
+        public CharacterClimbingMode ClimbingMode
+        {
+            set { Internal_SetClimbingMode(mCachedPtr, value); }
+        }
+
+        public CharacterNonWalkableMode NonWalkableMode
+        {
+            set { Internal_SetNonWalkableMode(mCachedPtr, value); }
+        }
+
+        public float MinMoveDistance
+        {
+            set { Internal_SetMinMoveDistance(mCachedPtr, value); }
+        }
+
+        public float ContactOffset
+        {
+            set { Internal_SetContactOffset(mCachedPtr, value); }
+        }
+
+        public float StepOffset
+        {
+            set { Internal_SetStepOffset(mCachedPtr, value); }
+        }
+
+        public Radian SlopeLimit
+        {
+            set { Internal_SetSlopeLimit(mCachedPtr, value.Radians); }
+        }
+
+        public ulong Layer
+        {
+            set { Internal_SetLayer(mCachedPtr, value); }
+        }
+
+        public NativeCharacterController(ScriptCharacterControllerData initData)
+        {
+            Internal_CreateInstance(this, ref initData);
+        }
+
+        public void Destroy()
+        {
+            Internal_Destroy(mCachedPtr);
+        }
+
+        public void Move(Vector3 position)
+        {
+            Internal_Move(mCachedPtr, ref position);
+        }
+
+        private void Internal_DoOnColliderHit(ScriptControllerCollision scriptCollisionData)
+        {
+            ControllerColliderCollision collisionData = new ControllerColliderCollision();
+            collisionData.position = scriptCollisionData.position;
+            collisionData.normal = scriptCollisionData.normal;
+            collisionData.motionDir = scriptCollisionData.motionDir;
+            collisionData.motionAmount = scriptCollisionData.motionAmount;
+            collisionData.triangleIndex = scriptCollisionData.triangleIndex;
+
+            if(scriptCollisionData.collider != null)
+                collisionData.collider = scriptCollisionData.collider.Component;
+            else
+                collisionData.collider = null;
+
+            Component.DoOnColliderHit(collisionData);
+        }
+
+        private void Internal_DoOnControllerHit(ScriptControllerCollision scriptCollisionData)
+        {
+            ControllerControllerCollision collisionData = new ControllerControllerCollision();
+            collisionData.position = scriptCollisionData.position;
+            collisionData.normal = scriptCollisionData.normal;
+            collisionData.motionDir = scriptCollisionData.motionDir;
+            collisionData.motionAmount = scriptCollisionData.motionAmount;
+
+            if (scriptCollisionData.controller != null)
+                collisionData.controller = scriptCollisionData.controller.Component;
+            else
+                collisionData.controller = null;
+
+            Component.DoOnControllerHit(collisionData);
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_CreateInstance(NativeCharacterController instance, 
+            ref ScriptCharacterControllerData initData);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Destroy(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Move(IntPtr thisPtr, ref Vector3 position);
+        
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetPosition(IntPtr thisPtr, out Vector3 position);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetPosition(IntPtr thisPtr, ref Vector3 position);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetFootPosition(IntPtr thisPtr, out Vector3 position);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetFootPosition(IntPtr thisPtr, ref Vector3 position);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetRadius(IntPtr thisPtr, float radius);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetHeight(IntPtr thisPtr, float height);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetUp(IntPtr thisPtr, ref Vector3 up);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetClimbingMode(IntPtr thisPtr, CharacterClimbingMode mode);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetNonWalkableMode(IntPtr thisPtr, CharacterNonWalkableMode mode);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetMinMoveDistance(IntPtr thisPtr, float value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetContactOffset(IntPtr thisPtr, float value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetStepOffset(IntPtr thisPtr, float value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetSlopeLimit(IntPtr thisPtr, float value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetLayer(IntPtr thisPtr, ulong layer);
+    }
+}

+ 200 - 215
Source/MBansheeEngine/Physics/NativeCollider.cs

@@ -1,215 +1,200 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-using System;
-using System.Runtime.CompilerServices;
-
-namespace BansheeEngine
-{
-    /// <summary>
-    /// Wrapper around the native Collider class.
-    /// <see cref="Collider"/>
-    /// </summary>
-    internal class NativeCollider : ScriptObject
-    {
-        private Collider component;
-
-        /// <summary>
-        /// Component that owns the native collider object.
-        /// </summary>
-        public Collider Component
-        {
-            get { return component; }
-            set { component = value; }
-        }
-
-        public Vector3 Position
-        {
-            get { Vector3 pos; Internal_GetPosition(mCachedPtr, out pos); return pos; }
-            set { Quaternion rot = Rotation; Internal_SetTransform(mCachedPtr, ref value, ref rot); }
-        }
-
-        public Quaternion Rotation
-        {
-            get { Quaternion rot; Internal_GetRotation(mCachedPtr, out rot); return rot; }
-            set { Vector3 pos = Position; Internal_SetTransform(mCachedPtr, ref pos, ref value); }
-        }
-
-        public Vector3 Scale
-        {
-            get { Vector3 scale; Internal_GetScale(mCachedPtr, out scale); return scale; }
-            set { Internal_SetScale(mCachedPtr, ref value); }
-        }
-
-        public bool IsTrigger
-        {
-            get { return Internal_GetIsTrigger(mCachedPtr); }
-            set { Internal_SetIsTrigger(mCachedPtr, value); }
-        }
-
-        public NativeRigidbody Rigidbody
-        {
-            get { return Internal_GetRigidbody(mCachedPtr); }
-            set
-            {
-                IntPtr rigidbodyPtr = IntPtr.Zero;
-                if (value != null)
-                    rigidbodyPtr = value.GetCachedPtr();
-
-                Internal_SetRigidbody(mCachedPtr, rigidbodyPtr);
-            }
-        }
-
-        public float Mass
-        {
-            get { return Internal_GetMass(mCachedPtr); }
-            set { Internal_SetMass(mCachedPtr, value); }
-        }
-
-        public PhysicsMaterial Material
-        {
-            get { return Internal_GetMaterial(mCachedPtr); }
-            set
-            {
-                IntPtr materialPtr = IntPtr.Zero;
-                if (value != null)
-                    materialPtr = value.GetCachedPtr();
-
-                Internal_SetMaterial(mCachedPtr, materialPtr);
-            }
-        }
-
-        public float ContactOffset
-        {
-            get { return Internal_GetContactOffset(mCachedPtr); }
-            set { Internal_SetContactOffset(mCachedPtr, value); }
-        }
-
-        public float RestOffset
-        {
-            get { return Internal_GetRestOffset(mCachedPtr); }
-            set { Internal_SetRestOffset(mCachedPtr, value); }
-        }
-
-        public ulong Layer
-        {
-            get { return Internal_GetLayer(mCachedPtr); }
-            set { Internal_SetLayer(mCachedPtr, value); }
-        }
-
-        public CollisionReportMode CollisionReportMode
-        {
-            get { return Internal_GetCollisionReportMode(mCachedPtr); }
-            set { Internal_SetCollisionReportMode(mCachedPtr, value); }
-        }
-
-        public bool Raycast(Vector3 origin, Vector3 unitDir, out ScriptPhysicsQueryHit hit, float maxDist)
-        {
-            return Internal_RayCast(mCachedPtr, ref origin, ref unitDir, out hit, maxDist);
-        }
-
-        public void Destroy()
-        {
-            Internal_Destroy(mCachedPtr);
-        }
-
-        private void Internal_DoOnCollisionBegin(ScriptCollisionData scriptCollisionData)
-        {
-            CollisionData collisionData;
-            collisionData.colliderA = scriptCollisionData.colliderA.Component;
-            collisionData.colliderB = scriptCollisionData.colliderB.Component;
-            collisionData.contactPoints = scriptCollisionData.contactPoints;
-
-            Component.DoOnCollisionBegin(collisionData);
-        }
-
-        private void Internal_DoOnCollisionStay(ScriptCollisionData scriptCollisionData)
-        {
-            CollisionData collisionData;
-            collisionData.colliderA = scriptCollisionData.colliderA.Component;
-            collisionData.colliderB = scriptCollisionData.colliderB.Component;
-            collisionData.contactPoints = scriptCollisionData.contactPoints;
-
-            Component.DoOnCollisionStay(collisionData);
-        }
-
-        private void Internal_DoOnCollisionEnd(ScriptCollisionData scriptCollisionData)
-        {
-            CollisionData collisionData;
-            collisionData.colliderA = scriptCollisionData.colliderA.Component;
-            collisionData.colliderB = scriptCollisionData.colliderB.Component;
-            collisionData.contactPoints = scriptCollisionData.contactPoints;
-
-            Component.DoOnCollisionEnd(collisionData);
-        }
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_Destroy(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetPosition(IntPtr thisPtr, out Vector3 pos);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetRotation(IntPtr thisPtr, out Quaternion rot);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetTransform(IntPtr thisPtr, ref Vector3 pos, ref Quaternion rot);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetScale(IntPtr thisPtr, ref Vector3 scale);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetScale(IntPtr thisPtr, out Vector3 scale);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetIsTrigger(IntPtr thisPtr, bool value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_GetIsTrigger(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetRigidbody(IntPtr thisPtr, IntPtr rigidbody);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern NativeRigidbody Internal_GetRigidbody(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetMass(IntPtr thisPtr, float mass);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern float Internal_GetMass(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetMaterial(IntPtr thisPtr, IntPtr physicsMaterial);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern PhysicsMaterial Internal_GetMaterial(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetContactOffset(IntPtr thisPtr, float value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern float Internal_GetContactOffset(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetRestOffset(IntPtr thisPtr, float value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern float Internal_GetRestOffset(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetLayer(IntPtr thisPtr, ulong layer);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern ulong Internal_GetLayer(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetCollisionReportMode(IntPtr thisPtr, CollisionReportMode mode);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern CollisionReportMode Internal_GetCollisionReportMode(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern bool Internal_RayCast(IntPtr thisPtr, ref Vector3 origin, ref Vector3 unitDir, 
-            out ScriptPhysicsQueryHit hit, float maxDist);
-    }
-}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System;
+using System.Runtime.CompilerServices;
+
+namespace BansheeEngine
+{
+    /// <summary>
+    /// Wrapper around the native Collider class.
+    /// <see cref="Collider"/>
+    /// </summary>
+    internal class NativeCollider : ScriptObject
+    {
+        private Collider component;
+
+        /// <summary>
+        /// Component that owns the native collider object.
+        /// </summary>
+        public Collider Component
+        {
+            get { return component; }
+            set { component = value; }
+        }
+
+        public Vector3 Position
+        {
+            get { Vector3 pos; Internal_GetPosition(mCachedPtr, out pos); return pos; }
+            set { Quaternion rot = Rotation; Internal_SetTransform(mCachedPtr, ref value, ref rot); }
+        }
+
+        public Quaternion Rotation
+        {
+            get { Quaternion rot; Internal_GetRotation(mCachedPtr, out rot); return rot; }
+            set { Vector3 pos = Position; Internal_SetTransform(mCachedPtr, ref pos, ref value); }
+        }
+
+        public Vector3 Scale
+        {
+            get { Vector3 scale; Internal_GetScale(mCachedPtr, out scale); return scale; }
+            set { Internal_SetScale(mCachedPtr, ref value); }
+        }
+
+        public bool IsTrigger
+        {
+            get { return Internal_GetIsTrigger(mCachedPtr); }
+            set { Internal_SetIsTrigger(mCachedPtr, value); }
+        }
+
+        public NativeRigidbody Rigidbody
+        {
+            get { return Internal_GetRigidbody(mCachedPtr); }
+            set
+            {
+                IntPtr rigidbodyPtr = IntPtr.Zero;
+                if (value != null)
+                    rigidbodyPtr = value.GetCachedPtr();
+
+                Internal_SetRigidbody(mCachedPtr, rigidbodyPtr);
+            }
+        }
+
+        public float Mass
+        {
+            get { return Internal_GetMass(mCachedPtr); }
+            set { Internal_SetMass(mCachedPtr, value); }
+        }
+
+        public PhysicsMaterial Material
+        {
+            get { return Internal_GetMaterial(mCachedPtr); }
+            set
+            {
+                IntPtr materialPtr = IntPtr.Zero;
+                if (value != null)
+                    materialPtr = value.GetCachedPtr();
+
+                Internal_SetMaterial(mCachedPtr, materialPtr);
+            }
+        }
+
+        public float ContactOffset
+        {
+            get { return Internal_GetContactOffset(mCachedPtr); }
+            set { Internal_SetContactOffset(mCachedPtr, value); }
+        }
+
+        public float RestOffset
+        {
+            get { return Internal_GetRestOffset(mCachedPtr); }
+            set { Internal_SetRestOffset(mCachedPtr, value); }
+        }
+
+        public ulong Layer
+        {
+            get { return Internal_GetLayer(mCachedPtr); }
+            set { Internal_SetLayer(mCachedPtr, value); }
+        }
+
+        public CollisionReportMode CollisionReportMode
+        {
+            get { return Internal_GetCollisionReportMode(mCachedPtr); }
+            set { Internal_SetCollisionReportMode(mCachedPtr, value); }
+        }
+
+        public bool Raycast(Vector3 origin, Vector3 unitDir, out ScriptPhysicsQueryHit hit, float maxDist)
+        {
+            return Internal_RayCast(mCachedPtr, ref origin, ref unitDir, out hit, maxDist);
+        }
+
+        public void Destroy()
+        {
+            Internal_Destroy(mCachedPtr);
+        }
+
+        private void Internal_DoOnCollisionBegin(ScriptCollisionData scriptCollisionData)
+        {
+            Component.DoOnCollisionBegin(new CollisionData(scriptCollisionData));
+        }
+
+        private void Internal_DoOnCollisionStay(ScriptCollisionData scriptCollisionData)
+        {
+            Component.DoOnCollisionStay(new CollisionData(scriptCollisionData));
+        }
+
+        private void Internal_DoOnCollisionEnd(ScriptCollisionData scriptCollisionData)
+        {
+            Component.DoOnCollisionEnd(new CollisionData(scriptCollisionData));
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Destroy(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetPosition(IntPtr thisPtr, out Vector3 pos);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetRotation(IntPtr thisPtr, out Quaternion rot);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetTransform(IntPtr thisPtr, ref Vector3 pos, ref Quaternion rot);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetScale(IntPtr thisPtr, ref Vector3 scale);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetScale(IntPtr thisPtr, out Vector3 scale);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetIsTrigger(IntPtr thisPtr, bool value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_GetIsTrigger(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetRigidbody(IntPtr thisPtr, IntPtr rigidbody);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern NativeRigidbody Internal_GetRigidbody(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetMass(IntPtr thisPtr, float mass);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_GetMass(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetMaterial(IntPtr thisPtr, IntPtr physicsMaterial);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern PhysicsMaterial Internal_GetMaterial(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetContactOffset(IntPtr thisPtr, float value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_GetContactOffset(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetRestOffset(IntPtr thisPtr, float value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_GetRestOffset(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetLayer(IntPtr thisPtr, ulong layer);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern ulong Internal_GetLayer(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetCollisionReportMode(IntPtr thisPtr, CollisionReportMode mode);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern CollisionReportMode Internal_GetCollisionReportMode(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_RayCast(IntPtr thisPtr, ref Vector3 origin, ref Vector3 unitDir, 
+            out ScriptPhysicsQueryHit hit, float maxDist);
+    }
+}

+ 3 - 18
Source/MBansheeEngine/Physics/NativeRigidbody.cs

@@ -218,32 +218,17 @@ namespace BansheeEngine
 
 
         private void Internal_DoOnCollisionBegin(ScriptCollisionData scriptCollisionData)
         private void Internal_DoOnCollisionBegin(ScriptCollisionData scriptCollisionData)
         {
         {
-            CollisionData collisionData;
-            collisionData.colliderA = scriptCollisionData.colliderA.Component;
-            collisionData.colliderB = scriptCollisionData.colliderB.Component;
-            collisionData.contactPoints = scriptCollisionData.contactPoints;
-
-            Component.DoOnCollisionBegin(collisionData);
+            Component.DoOnCollisionBegin(new CollisionData(scriptCollisionData));
         }
         }
 
 
         private void Internal_DoOnCollisionStay(ScriptCollisionData scriptCollisionData)
         private void Internal_DoOnCollisionStay(ScriptCollisionData scriptCollisionData)
         {
         {
-            CollisionData collisionData;
-            collisionData.colliderA = scriptCollisionData.colliderA.Component;
-            collisionData.colliderB = scriptCollisionData.colliderB.Component;
-            collisionData.contactPoints = scriptCollisionData.contactPoints;
-
-            Component.DoOnCollisionStay(collisionData);
+            Component.DoOnCollisionStay(new CollisionData(scriptCollisionData));
         }
         }
 
 
         private void Internal_DoOnCollisionEnd(ScriptCollisionData scriptCollisionData)
         private void Internal_DoOnCollisionEnd(ScriptCollisionData scriptCollisionData)
         {
         {
-            CollisionData collisionData;
-            collisionData.colliderA = scriptCollisionData.colliderA.Component;
-            collisionData.colliderB = scriptCollisionData.colliderB.Component;
-            collisionData.contactPoints = scriptCollisionData.contactPoints;
-
-            Component.DoOnCollisionEnd(collisionData);
+            Component.DoOnCollisionEnd(new CollisionData(scriptCollisionData));
         }
         }
 
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]

+ 150 - 135
Source/MBansheeEngine/Physics/PhysicsCommon.cs

@@ -1,135 +1,150 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-using System.Runtime.InteropServices;
-
-namespace BansheeEngine
-{
-    /// <summary>
-    /// Hit information from a physics query.
-    /// </summary>
-    public struct PhysicsQueryHit
-    {
-        /// <summary>
-        /// Position of the hit in world space.
-        /// </summary>
-        public Vector3 point;
-
-        /// <summary>
-        /// Normal to the surface that was hit. 
-        /// </summary>
-        public Vector3 normal;
-
-        /// <summary>
-        /// UV coordinates of the triangle that was hit (only applicable when triangle meshes are hit).
-        /// </summary>
-        public Vector2 uv;
-
-        /// <summary>
-        /// Distance from the query origin to the hit position.
-        /// </summary>
-        public float distance;
-
-        /// <summary>
-        /// Index of the triangle that was hit (only applicable when triangle meshes are hit).
-        /// </summary>
-        public int triangleIdx;
-
-        /// <summary>
-        /// Collider that was hit.
-        /// </summary>
-        public Collider collider;
-    }
-
-    /// <summary>
-    /// Information about a single contact point during physics collision.
-    /// </summary>
-    [StructLayout(LayoutKind.Sequential)]
-    public struct ContactPoint // Note: Must match C++ ContactPoint struct
-    {
-        /// <summary>
-        /// Contact point in world space.
-        /// </summary>
-        public Vector3 position;
-
-        /// <summary>
-        /// Normal pointing from the second shape to the first shape.
-        /// </summary>
-        public Vector3 normal;
-
-        /// <summary>
-        /// Impulse applied to the objects to keep them from penetrating. Divide by simulation step to get the force.
-        /// </summary>
-        public float impulse;
-
-        /// <summary>
-        /// Determines how far are the objects. Negative value denotes penetration.
-        /// </summary>
-        public float separation;
-    }
-
-    /// <summary>
-    /// Information about a collision between two physics objects.
-    /// </summary>
-    public struct CollisionData
-    {
-        /// <summary>
-        /// First of the colliders involved in the collision.
-        /// </summary>
-        public Collider colliderA;
-
-        /// <summary>
-        /// Second of the colliders involved in the collision.
-        /// </summary>
-        public Collider colliderB;
-
-        /// <summary>
-        /// Information about all the contact points for the hit. 
-        /// </summary>
-        public ContactPoint[] contactPoints;
-    }
-
-    /// <summary>
-    /// Interop class used for passing PhysicsQueryHit data from native to managed code. <see cref="PhysicsQueryHit"/>.
-    /// </summary>
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct ScriptPhysicsQueryHit // Note: Must match C++ struct ScriptPhysicsQueryHit
-    {
-        public Vector3 point;
-        public Vector3 normal;
-        public Vector2 uv;
-        public float distance;
-        public int triangleIdx;
-        public NativeCollider collider;
-    }
-
-    /// <summary>
-    /// Interop class used for passing CollisionData data from native to managed code. <see cref="CollisionData"/>.
-    /// </summary>
-    [StructLayout(LayoutKind.Sequential)]
-    internal struct ScriptCollisionData // Note: Must match C++ CollisionData struct
-    {
-        public NativeCollider colliderA;
-        public NativeCollider colliderB;
-        public ContactPoint[] contactPoints;
-    }
-
-    /// <summary>
-    /// Determines which collision events will be reported by physics objects.
-    /// </summary>
-    public enum CollisionReportMode
-    {
-        /// <summary>
-        /// No collision events will be triggered.
-        /// </summary>
-        None,
-        /// <summary>
-        /// Collision events will be triggered when object enters and/or leaves collision.
-        /// </summary>
-		Report,
-		/// <summary>
-        /// Collision events will be triggered when object enters and/or leaves collision, but also every frame the object 
-        /// remains in collision. 
-        /// </summary>
-		ReportPersistent, 
-	}
-}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System.Runtime.InteropServices;
+
+namespace BansheeEngine
+{
+    /// <summary>
+    /// Hit information from a physics query.
+    /// </summary>
+    public struct PhysicsQueryHit
+    {
+        /// <summary>
+        /// Position of the hit in world space.
+        /// </summary>
+        public Vector3 point;
+
+        /// <summary>
+        /// Normal to the surface that was hit. 
+        /// </summary>
+        public Vector3 normal;
+
+        /// <summary>
+        /// UV coordinates of the triangle that was hit (only applicable when triangle meshes are hit).
+        /// </summary>
+        public Vector2 uv;
+
+        /// <summary>
+        /// Distance from the query origin to the hit position.
+        /// </summary>
+        public float distance;
+
+        /// <summary>
+        /// Index of the triangle that was hit (only applicable when triangle meshes are hit).
+        /// </summary>
+        public int triangleIdx;
+
+        /// <summary>
+        /// Collider that was hit.
+        /// </summary>
+        public Collider collider;
+    }
+
+    /// <summary>
+    /// Information about a single contact point during physics collision.
+    /// </summary>
+    [StructLayout(LayoutKind.Sequential)]
+    public struct ContactPoint // Note: Must match C++ ContactPoint struct
+    {
+        /// <summary>
+        /// Contact point in world space.
+        /// </summary>
+        public Vector3 position;
+
+        /// <summary>
+        /// Normal pointing from the second shape to the first shape.
+        /// </summary>
+        public Vector3 normal;
+
+        /// <summary>
+        /// Impulse applied to the objects to keep them from penetrating. Divide by simulation step to get the force.
+        /// </summary>
+        public float impulse;
+
+        /// <summary>
+        /// Determines how far are the objects. Negative value denotes penetration.
+        /// </summary>
+        public float separation;
+    }
+
+    /// <summary>
+    /// Information about a collision between two physics objects.
+    /// </summary>
+    public struct CollisionData
+    {
+        internal CollisionData(ScriptCollisionData data)
+        {
+            if (data.colliderA != null)
+                colliderA = data.colliderA.Component;
+            else
+                colliderA = null;
+
+            if (data.colliderB != null)
+                colliderB = data.colliderB.Component;
+            else
+                colliderB = null;
+
+            contactPoints = data.contactPoints;
+        }
+
+        /// <summary>
+        /// First of the colliders involved in the collision.
+        /// </summary>
+        public Collider colliderA;
+
+        /// <summary>
+        /// Second of the colliders involved in the collision.
+        /// </summary>
+        public Collider colliderB;
+
+        /// <summary>
+        /// Information about all the contact points for the hit. 
+        /// </summary>
+        public ContactPoint[] contactPoints;
+    }
+
+    /// <summary>
+    /// Interop class used for passing PhysicsQueryHit data from native to managed code. <see cref="PhysicsQueryHit"/>.
+    /// </summary>
+    [StructLayout(LayoutKind.Sequential)]
+    internal struct ScriptPhysicsQueryHit // Note: Must match C++ struct ScriptPhysicsQueryHit
+    {
+        public Vector3 point;
+        public Vector3 normal;
+        public Vector2 uv;
+        public float distance;
+        public int triangleIdx;
+        public NativeCollider collider;
+    }
+
+    /// <summary>
+    /// Interop class used for passing CollisionData data from native to managed code. <see cref="CollisionData"/>.
+    /// </summary>
+    [StructLayout(LayoutKind.Sequential)]
+    internal struct ScriptCollisionData // Note: Must match C++ CollisionData struct
+    {
+        public NativeCollider colliderA;
+        public NativeCollider colliderB;
+        public ContactPoint[] contactPoints;
+    }
+
+    /// <summary>
+    /// Determines which collision events will be reported by physics objects.
+    /// </summary>
+    public enum CollisionReportMode
+    {
+        /// <summary>
+        /// No collision events will be triggered.
+        /// </summary>
+        None,
+        /// <summary>
+        /// Collision events will be triggered when object enters and/or leaves collision.
+        /// </summary>
+		Report,
+		/// <summary>
+        /// Collision events will be triggered when object enters and/or leaves collision, but also every frame the object 
+        /// remains in collision. 
+        /// </summary>
+		ReportPersistent, 
+	}
+}

+ 1 - 0
Source/MBansheeEngine/Physics/Rigidbody.cs

@@ -647,6 +647,7 @@ namespace BansheeEngine
         private void RestoreNative()
         private void RestoreNative()
         {
         {
             native = new NativeRigidbody(SceneObject);
             native = new NativeRigidbody(SceneObject);
+            native.Component = this;
 
 
             UpdateColliders();
             UpdateColliders();