summaryrefslogtreecommitdiff
path: root/Runtime/BaseClasses
diff options
context:
space:
mode:
Diffstat (limited to 'Runtime/BaseClasses')
-rw-r--r--Runtime/BaseClasses/BaseObject.cpp1393
-rw-r--r--Runtime/BaseClasses/BaseObject.h1162
-rw-r--r--Runtime/BaseClasses/BitField.h26
-rw-r--r--Runtime/BaseClasses/ClassIDs.h240
-rw-r--r--Runtime/BaseClasses/ClassRegistration.cpp267
-rw-r--r--Runtime/BaseClasses/ClassRegistration.h22
-rw-r--r--Runtime/BaseClasses/CleanupManager.cpp65
-rw-r--r--Runtime/BaseClasses/CleanupManager.h37
-rw-r--r--Runtime/BaseClasses/Cursor.cpp152
-rw-r--r--Runtime/BaseClasses/Cursor.h105
-rw-r--r--Runtime/BaseClasses/EditorExtension.cpp95
-rw-r--r--Runtime/BaseClasses/EditorExtension.h58
-rw-r--r--Runtime/BaseClasses/EventIDs.h9
-rw-r--r--Runtime/BaseClasses/EventManager.cpp216
-rw-r--r--Runtime/BaseClasses/EventManager.h59
-rw-r--r--Runtime/BaseClasses/GameManager.cpp58
-rw-r--r--Runtime/BaseClasses/GameManager.h69
-rw-r--r--Runtime/BaseClasses/GameObject.cpp1189
-rw-r--r--Runtime/BaseClasses/GameObject.h535
-rw-r--r--Runtime/BaseClasses/GameObjectTests.cpp274
-rw-r--r--Runtime/BaseClasses/IsPlaying.cpp14
-rw-r--r--Runtime/BaseClasses/IsPlaying.h9
-rw-r--r--Runtime/BaseClasses/ManagerContext.cpp107
-rw-r--r--Runtime/BaseClasses/ManagerContext.h61
-rw-r--r--Runtime/BaseClasses/ManagerContextLoading.cpp285
-rw-r--r--Runtime/BaseClasses/ManagerContextLoading.h17
-rw-r--r--Runtime/BaseClasses/MessageHandler.cpp196
-rw-r--r--Runtime/BaseClasses/MessageHandler.h112
-rw-r--r--Runtime/BaseClasses/MessageIdentifier.cpp86
-rw-r--r--Runtime/BaseClasses/MessageIdentifier.h109
-rw-r--r--Runtime/BaseClasses/MessageIdentifiers.h86
-rw-r--r--Runtime/BaseClasses/NamedObject.cpp33
-rw-r--r--Runtime/BaseClasses/NamedObject.h23
-rw-r--r--Runtime/BaseClasses/ObjectDefines.h202
-rw-r--r--Runtime/BaseClasses/RefCounted.h36
-rw-r--r--Runtime/BaseClasses/SupportedMessageOptimization.h17
-rw-r--r--Runtime/BaseClasses/Tags.cpp604
-rw-r--r--Runtime/BaseClasses/Tags.h104
-rw-r--r--Runtime/BaseClasses/TagsTests.cpp109
39 files changed, 8241 insertions, 0 deletions
diff --git a/Runtime/BaseClasses/BaseObject.cpp b/Runtime/BaseClasses/BaseObject.cpp
new file mode 100644
index 0000000..1f4c88a
--- /dev/null
+++ b/Runtime/BaseClasses/BaseObject.cpp
@@ -0,0 +1,1393 @@
+#include "UnityPrefix.h"
+#include "Configuration/UnityConfigure.h"
+#include "BaseObject.h"
+#include "Runtime/Serialize/PersistentManager.h"
+#include "Runtime/Serialize/TransferFunctions/SerializeTransfer.h"
+#include "Runtime/Utilities/dynamic_bitset.h"
+#include "Runtime/Utilities/CStringHash.h"
+#include "Runtime/Utilities/InitializeAndCleanup.h"
+#include "Runtime/Scripting/ScriptingUtility.h"
+#include "Runtime/Profiler/MemoryProfilerStats.h"
+#include "Runtime/Scripting/Backend/ScriptingBackendApi.h"
+#include "EventManager.h"
+#include "EventIDs.h"
+#if ENABLE_MONO
+#include "Runtime/Mono/MonoIncludes.h"
+#endif
+
+#include "Runtime/Scripting/ScriptingUtility.h"
+
+#if defined(__MWERKS__)
+#include <hash_map>
+#endif
+
+#include "Configuration/UnityConfigure.h"
+#if THREADED_LOADING
+#include "Runtime/Threads/ThreadSpecificValue.h"
+#include "Runtime/Threads/ProfilerMutex.h"
+#endif
+
+#if !UNITY_EXTERNAL_TOOL
+#include "Runtime/Profiler/Profiler.h"
+#include "Runtime/Profiler/MemoryProfiler.h"
+#endif
+#include "Runtime/Allocator/MemoryManager.h"
+
+using namespace std;
+
+#define SHOW_REGISTERED_CLASS_INFO 0
+
+
+#if THREADED_LOADING
+#define CHECK_IN_MAIN_THREAD DebugAssertIf(!Thread::EqualsCurrentThreadID(GetPersistentManager().GetMainThreadID()));
+#define DEBUG_CHECK_IN_MAIN_THREAD AssertIf(!Thread::EqualsCurrentThreadID(GetPersistentManager().GetMainThreadID()));
+#else
+#define CHECK_IN_MAIN_THREAD
+#define DEBUG_CHECK_IN_MAIN_THREAD
+#endif
+
+
+static bool IsDerivedFromRTTI (const Object::RTTI* klass, const Object::RTTI* derivedFrom)
+{
+ const Object::RTTI* i = klass;
+ while (i)
+ {
+ if (derivedFrom == i)
+ return true;
+
+ i = i->base;
+ }
+ return false;
+}
+
+struct RegisterClassCallbackStruct
+{
+ RegisterClassCallback* registerClass;
+ RegisterClassCallback* initClassEarly;
+ RegisterClassCallback* initClass;
+ RegisterClassCallback* postInitClass;
+ RegisterClassCallback* cleanupClass;
+
+ RegisterClassCallbackStruct()
+ {
+ registerClass = initClassEarly = initClass = postInitClass = cleanupClass = NULL;
+ }
+};
+
+typedef UNITY_VECTOR(kMemPermanent, RegisterClassCallbackStruct) RegisterClassCallbacks;
+
+Object::IDToPointerMap* Object::ms_IDToPointer = NULL;
+UInt32* Object::ms_IsDerivedFromBitMap = NULL;
+unsigned Object::ms_MaxClassID = 0;
+#if USE_NEW_IS_DERIVED_FROM
+UInt32 gClassIDMask[32];
+UInt32* Object::ms_ClassIDMask = 0;
+UInt32* Object::ms_ClassIsDerivedFrom = 0;
+#endif
+
+static RegisterClassCallbacks* gRegisterClassCallbacks = NULL;
+
+#if defined(__MWERKS__)
+#error("Metrowerks should not be used")
+#endif
+
+#if DEBUGMODE
+RegisteredClassSet* gVerifyRegisteredClasses = NULL;
+#endif
+
+typedef map<char*, SInt32, smaller_cstring> StringToClassIDMap;
+typedef pair<const SInt32, Object::RTTI> SInt32RTTIPair;
+typedef map<SInt32, Object::RTTI, less<SInt32>, STL_ALLOCATOR(kMemPermanent, SInt32RTTIPair) > RTTIMap;
+
+static StringToClassIDMap* gStringToClassID = NULL;
+static RTTIMap* gRTTI = NULL;
+static dynamic_bitset* gRegisteredClassIDs = NULL;
+static dynamic_bitset* gIsDerivedFromBitMap = NULL;
+static Object::ObjectDestroyCallbackFunction* gDestroyedCallbackFunc = NULL;
+
+static int* gBaseObjectManagerContainer = NULL;
+
+namespace BaseObjectManager
+{
+ void StaticInitialize()
+ {
+ gBaseObjectManagerContainer = UNITY_NEW_AS_ROOT(int, kMemBaseObject, "Managers", "BaseObjectManager");
+ SET_ALLOC_OWNER(gBaseObjectManagerContainer);
+ gStringToClassID = UNITY_NEW(StringToClassIDMap, kMemBaseObject);
+ gRTTI = UNITY_NEW(RTTIMap, kMemBaseObject);
+ gRegisteredClassIDs = UNITY_NEW(dynamic_bitset, kMemBaseObject);
+ gIsDerivedFromBitMap = UNITY_NEW(dynamic_bitset, kMemBaseObject);
+ Object::StaticInitialize();
+ }
+ void StaticDestroy()
+ {
+ Object::StaticDestroy();
+ UNITY_DELETE(gStringToClassID, kMemBaseObject);
+ UNITY_DELETE(gRTTI, kMemBaseObject);
+ UNITY_DELETE(gRegisteredClassIDs, kMemBaseObject);
+ UNITY_DELETE(gIsDerivedFromBitMap, kMemBaseObject);
+#if DEBUGMODE
+ UNITY_DELETE(gVerifyRegisteredClasses, kMemBaseObject); // allocated on first access
+#endif
+ UNITY_DELETE(gBaseObjectManagerContainer, kMemBaseObject);
+ }
+}
+
+static RegisterRuntimeInitializeAndCleanup s_BaseObjectManagerCallbacks(BaseObjectManager::StaticInitialize, BaseObjectManager::StaticDestroy);
+
+#if UNITY_EDITOR
+static Object::ObjectDirtyCallbackFunction* gSetDirtyCallbackFunc = NULL;
+#endif
+
+PROFILER_INFORMATION (gObjectCreationMutexLockInfo, "Object.CreateObject mutex lock", kProfilerLoading)
+
+#if THREADED_LOADING
+Mutex gCreateObjectMutex;
+#if DEBUGMODE
+static UNITY_TLS_VALUE(int) gCheckObjectCreationMutex;
+#endif
+#endif
+
+void LockObjectCreation ()
+{
+ #if THREADED_LOADING
+ LOCK_MUTEX (gCreateObjectMutex, gObjectCreationMutexLockInfo);
+ #if DEBUGMODE
+ ++gCheckObjectCreationMutex;
+ #endif
+ #endif
+}
+
+void UnlockObjectCreation ()
+{
+ #if THREADED_LOADING
+ gCreateObjectMutex.Unlock();
+ #if DEBUGMODE
+ --gCheckObjectCreationMutex;
+ #endif
+ #endif
+}
+
+
+static SInt32 gLowestInstanceID = -10;
+static bool gDisableImmediateDestruction = false;
+
+#if UNITY_EDITOR
+InstanceIDResolveCallback* gInstanceIDResolveCallback = NULL;
+const void* gInstanceIDResolveContext = NULL;
+
+void SetInstanceIDResolveCallback (InstanceIDResolveCallback callback, const void* context)
+{
+ gInstanceIDResolveCallback = callback;
+ gInstanceIDResolveContext = context;
+}
+#endif
+
+void InstanceIDToLocalSerializedObjectIdentifier (SInt32 id, LocalSerializedObjectIdentifier& localIdentifier)
+{
+ #if UNITY_EDITOR
+ // Early out if referenced object is null
+ if (id == 0)
+ {
+ localIdentifier.localSerializedFileIndex = 0;
+ localIdentifier.localIdentifierInFile = 0;
+ return;
+ }
+
+ if (gInstanceIDResolveCallback == NULL)
+ {
+ GetPersistentManager ().InstanceIDToLocalSerializedObjectIdentifierInternal (id, localIdentifier);
+ return;
+ }
+ else
+ {
+ gInstanceIDResolveCallback (id, localIdentifier, const_cast<void*>(gInstanceIDResolveContext));
+ }
+ #else
+ GetPersistentManager ().InstanceIDToLocalSerializedObjectIdentifierInternal (id, localIdentifier);
+ #endif
+}
+
+void LocalSerializedObjectIdentifierToInstanceID (const LocalSerializedObjectIdentifier& localIdentifier, SInt32& instanceID)
+{
+ GetPersistentManager ().LocalSerializedObjectIdentifierToInstanceIDInternal (localIdentifier, instanceID);
+}
+
+Object* ReadObjectFromPersistentManager (int id)
+{
+ if (id == 0)
+ return NULL;
+ else
+ {
+ // In the Player it is not possible to call MakeObjectPersistent,
+ // thus instance id's that are positive are the only ones that can be loaded from disk
+ #if !UNITY_EDITOR
+ if (id < 0)
+ {
+ #if DEBUGMODE
+ //AssertIf(GetPersistentManager ().ReadObject (id));
+ #endif
+ return NULL;
+ }
+ #endif
+
+ Object* o = GetPersistentManager ().ReadObject (id);
+ return o;
+ }
+}
+
+void DestroyWithoutLoadingButDontDestroyFromFile (int instanceID)
+{
+ GetPersistentManager ().MakeObjectUnpersistent (instanceID, kDontDestroyFromFile);
+ UnloadObject(Object::IDToPointer(instanceID));
+}
+
+void DestroySingleObject (Object* o)
+{
+ if (o == NULL)
+ return;
+
+ if (o->IsPersistent())
+ GetPersistentManager ().MakeObjectUnpersistent (o->GetInstanceID (), kDestroyFromFile);
+
+ // Lock changes to IDToPointer so that we can safely lookup pointers using IDToPointerThreadSafe
+ LockObjectCreation();
+
+ delete_object_internal (o);
+
+ UnlockObjectCreation();
+}
+
+
+Object::Object (MemLabelId label, ObjectCreationMode mode)
+{
+ Assert(label.label < (1 << kMemLabelBits));
+ m_MemLabel = label.label;
+ m_InstanceID = 0;
+ m_EventIndex = NULL;
+
+ #if ENABLE_SCRIPTING
+ m_MonoReference = 0;
+ m_ScriptingObjectPointer = SCRIPTING_NULL;
+ #endif
+
+ #if !UNITY_RELEASE
+ m_AwakeCalled = 0;
+ m_ResetCalled = 0;
+ m_AwakeThreadedCalled = 0;
+ m_AwakeDidLoadThreadedCalled = 0;
+ #endif
+
+
+ #if UNITY_EDITOR
+ m_DirtyIndex = 0;
+ m_FileIDHint = 0;
+ #endif
+ m_HideFlags = 0;
+ m_TemporaryFlags = 0;
+ m_IsPersistent = false;
+
+ DebugAssert(GetMemoryManager().GetAllocator(GetMemoryLabel())->Contains(this));
+ m_IsRootOwner = GetMemoryManager().GetAllocator(GetMemoryLabel())->GetProfilerHeader(this) != NULL;
+ #if UNITY_WINRT
+ m_TemporaryUnusedAssetsFlags = 0;
+ #endif
+}
+
+void Object::CalculateCachedClassID (Object* obj)
+{
+ Assert(obj->GetClassIDVirtualInternal() < (1 << kCachedClassIDBits));
+ obj->m_CachedClassID = obj->GetClassIDVirtualInternal();
+}
+
+void Object::InsertObjectInMap( Object* obj )
+{
+ SET_ALLOC_OWNER(gBaseObjectManagerContainer);
+ Assert (ms_IDToPointer->find (obj->GetInstanceID ()) == ms_IDToPointer->end ());
+ ms_IDToPointer->insert (make_pair (obj->GetInstanceID (), obj));
+
+ PROFILER_REGISTER_OBJECT(obj);
+}
+
+void Object::RegisterInstanceID (Object* obj)
+{
+ CHECK_IN_MAIN_THREAD
+
+ LockObjectCreation();
+ Assert (obj != NULL);
+ AssertIf(obj->m_InstanceID == 0);
+ InsertObjectInMap (obj);
+
+ UnlockObjectCreation();
+}
+
+void Object::RegisterInstanceIDNoLock (Object* obj)
+{
+ CHECK_IN_MAIN_THREAD
+ Assert (obj != NULL);
+ AssertIf (obj->m_InstanceID == 0);
+ CalculateCachedClassID (obj);
+ InsertObjectInMap (obj);
+}
+
+
+Object* Object::AllocateAndAssignInstanceID (Object* obj)
+{
+ CHECK_IN_MAIN_THREAD
+ AssertIf(obj->m_InstanceID != 0);
+
+ LockObjectCreation();
+
+ // Create a new unique instanceID for this Object.
+ // The created id will be negative beginning with -1
+ // Ids loaded from a file will be positive beginning with 1
+ gLowestInstanceID-=2;
+ obj->SetInstanceID (gLowestInstanceID);
+ AssertIf (obj->GetInstanceID () & 1);
+
+ CalculateCachedClassID (obj);
+ InsertObjectInMap (obj);
+
+ UnlockObjectCreation();
+
+ obj->SetDirty();
+
+ return obj;
+}
+
+Object* Object::AllocateAndAssignInstanceIDNoLock (Object* obj)
+{
+ CHECK_IN_MAIN_THREAD
+ AssertIf(obj->m_InstanceID != 0);
+
+ // Create a new unique instanceID for this Object.
+ // The created id will be negative beginning with -1
+ // Ids loaded from a file will be positive beginning with 1
+ gLowestInstanceID-=2;
+ obj->SetInstanceID (gLowestInstanceID);
+ AssertIf (obj->GetInstanceID () & 1);
+
+ CalculateCachedClassID (obj);
+
+ InsertObjectInMap (obj);
+
+ obj->SetDirty();
+
+ return obj;
+}
+
+enum { kMonoObjectCachedPtrOffset = 12 };
+
+
+// This must be executed on the main thread
+void delete_object_internal_step1 (Object* object)
+{
+ PROFILER_UNREGISTER_OBJECT(object);
+
+#if !UNITY_RELEASE
+ object->CheckCorrectAwakeUsage();
+#endif
+
+#if THREADED_LOADING && DEBUGMODE
+ Assert(gCheckObjectCreationMutex >= 1);
+#endif
+
+ // Send destroy message & clear event index
+ if (object->m_EventIndex != NULL)
+ {
+ GetEventManager().InvokeEvent(object->m_EventIndex, object, kWillDestroyEvent);
+ GetEventManager().RemoveEvent(object->m_EventIndex);
+ object->m_EventIndex = NULL;
+ }
+
+ // Remove this objects instanceID from the table.
+ AssertIf (Object::ms_IDToPointer->find (object->GetInstanceID ()) == Object::ms_IDToPointer->end ());
+ Object::ms_IDToPointer->erase (object->GetInstanceID ());
+
+ if (gDestroyedCallbackFunc)
+ gDestroyedCallbackFunc (object->GetInstanceID ());
+
+ object->m_InstanceID = 0;
+}
+
+Object::~Object ()
+{
+ // Ensure PreCleanupObject was called
+ #if DEBUGMODE
+ Assert(m_InstanceID == 0);
+ #endif
+
+#if ENABLE_MONO //if unity3.5 succesfully shipped with this assert it may be removed. here to verify an assumption made in a refactor.
+ Assert((m_MonoReference==0) == (m_ScriptingObjectPointer==NULL));
+#endif
+
+#if ENABLE_SCRIPTING
+ if (m_ScriptingObjectPointer)
+ SetCachedScriptingObject(SCRIPTING_NULL);
+#endif
+}
+
+bool Object::MainThreadCleanup ()
+{
+ AssertString("MainThreadCleanup is not implemented for this class. See DoesClassRequireMainThreadDeallocation");
+ return false;
+}
+
+void Object::SetIsPersistent( bool p )
+{
+ PROFILER_CHANGE_PERSISTANCY(GetInstanceID(), m_IsPersistent, p);
+ m_IsPersistent = p;
+}
+
+#if ENABLE_SCRIPTING
+
+#if UNITY_PS3 || UNITY_XENON
+ extern "C" char* GC_clear_stack(char*);
+#endif
+
+void Object::SetupWeakHandle ()
+{
+ if (m_MonoReference != 0)
+ {
+ register ScriptingObjectPtr object = scripting_gchandle_get_target(m_MonoReference);
+ UInt32 weakref = scripting_gchandle_weak_new (object);
+ SetCachedScriptingObject(SCRIPTING_NULL);
+
+#if UNITY_PS3 || UNITY_XENON
+ // we need to make sure the object doesn't continue living on the stack. // fixes http://fogbugz.unity3d.com/default.asp?444901#1065992062
+ GC_clear_stack((char*)object);
+#endif
+ object = SCRIPTING_NULL;
+ m_MonoReference = weakref;
+ }
+}
+
+bool Object::RevertWeakHandle ()
+{
+ if (m_MonoReference != 0)
+ {
+ ScriptingObjectPtr target = scripting_gchandle_get_target (m_MonoReference);
+ scripting_gchandle_free(m_MonoReference);
+ m_MonoReference = 0;
+ if (target)
+ {
+ SetCachedScriptingObject(target);
+#if UNITY_WINRT
+ // Restore cached ptr for managed object, not sure why we don't do this for Mono as well, because we reset cachedPtr in SetupWeakHandle
+ // But on Mono it seems cachedPtr persists ?!
+ // Maybe it's related to cachedPtr optimization
+ register ScriptingObjectOfType<Object> instance(m_ScriptingObjectPointer);
+ instance.SetCachedPtr(this);
+#endif
+ }
+ return target != SCRIPTING_NULL;
+ }
+ else
+ return false;
+}
+
+
+void Object::SetCachedScriptingObject (ScriptingObjectPtr object)
+{
+ if (object)
+ {
+ AssertIf(m_MonoReference != 0);
+ m_MonoReference = scripting_gchandle_new (object);
+ m_ScriptingObjectPointer = object;
+ return;
+ }
+
+ if (m_ScriptingObjectPointer == SCRIPTING_NULL)
+ {
+ AssertString("Dont do this");
+ return;
+ }
+
+ register ScriptingObjectOfType<Object> instance(m_ScriptingObjectPointer);
+ instance.SetCachedPtr(0);
+
+ scripting_gchandle_free (m_MonoReference);
+ m_MonoReference = 0;
+
+ m_ScriptingObjectPointer = SCRIPTING_NULL;
+#if UNITY_WINRT
+ instance = ScriptingObjectPtr(SCRIPTING_NULL);
+#else
+ instance = SCRIPTING_NULL;
+#endif
+}
+#endif
+
+void Object::RegisterDestroyedCallback (ObjectDestroyCallbackFunction* callback)
+{
+ gDestroyedCallbackFunc = callback;
+}
+
+// Register base class
+void Object::RegisterClass ()
+{
+ RegisterClass (ClassID (Object), -1, "Object", sizeof (Object), NULL, true);
+}
+
+void Object::RegisterClass (int inClassID, int inBaseClass, const string& inName, int byteSize, FactoryFunction* inFunc, bool isAbstract)
+{
+ if (ClassIDToRTTI (inClassID))
+ return;
+
+ // Store ClassID -> RTTI
+ AssertIf (gRTTI->find (inClassID) != gRTTI->end ());
+ RTTIMap::iterator baseClass = gRTTI->find (inBaseClass);
+ AssertIf (baseClass == gRTTI->end () && inBaseClass != -1);
+ Object::RTTI& classInfo = (*gRTTI)[inClassID];
+ classInfo.base = baseClass == gRTTI->end () ? NULL : &baseClass->second;
+ classInfo.factory = inFunc;
+ classInfo.className = inName;
+ classInfo.classID = inClassID;
+ classInfo.isAbstract = isAbstract;
+ classInfo.size = byteSize;
+
+ // Store String -> ClassID
+ AssertIf (gStringToClassID->find (const_cast<char*> (inName.c_str ())) != gStringToClassID->end ());
+ (*gStringToClassID)[const_cast<char*> (classInfo.className.c_str ())] = inClassID;
+}
+
+Object* Object::Produce (int classID, int instanceID, MemLabelId memLabel, ObjectCreationMode mode)
+{
+ // Object is already loaded assert
+ AssertIf (mode == kCreateObjectDefault && IDToPointer (instanceID) != NULL);
+ AssertIf (instanceID == 0 && mode == kCreateObjectFromNonMainThread);
+ #if THREADED_LOADING
+ AssertIf (!Thread::EqualsCurrentThreadID(GetPersistentManager().GetMainThreadID()) && mode != kCreateObjectFromNonMainThread);
+ #endif
+ AssertIf (instanceID & 1);
+
+ // Find the appropriate Factory.
+ RTTIMap::iterator i;
+ i = gRTTI->find (classID);
+ if (i == gRTTI->end () || i->second.factory == NULL)
+ {
+ return NULL;
+ }
+
+ Object* o;
+ if (instanceID != 0)
+ {
+ o = i->second.factory (memLabel, mode);
+ if (o == NULL)
+ return NULL;
+ o->SetInstanceID(instanceID);
+ CalculateCachedClassID (o);
+
+ // Register instanceID and set dirty
+ if (mode == kCreateObjectDefault)
+ {
+ RegisterInstanceID(o);
+ o->SetDirty();
+ }
+ else if (mode == kCreateObjectDefaultNoLock)
+ {
+ RegisterInstanceIDNoLock(o);
+ o->SetDirty();
+ }
+
+ return o;
+ }
+ else
+ {
+ AssertIf(mode != kCreateObjectDefaultNoLock && mode != kCreateObjectDefault);
+ o = i->second.factory (memLabel, mode);
+
+ if (mode == kCreateObjectDefaultNoLock)
+ AllocateAndAssignInstanceIDNoLock(o);
+ else
+ AllocateAndAssignInstanceID(o);
+ return o;
+ }
+}
+
+void Object::CheckInstanceIDsLoaded (SInt32* instanceIDs, int size)
+{
+ for (int i=0;i<size;i++)
+ {
+ if (ms_IDToPointer->count (instanceIDs[i]))
+ instanceIDs[i] = 0;
+ }
+}
+
+#if !UNITY_RELEASE
+Object* Object::IDToPointer (int inInstanceID)
+{
+ DEBUG_CHECK_IN_MAIN_THREAD
+
+ return Object::IDToPointerNoThreadCheck (inInstanceID);
+}
+#endif
+
+Object* Object::IDToPointerThreadSafe (int inInstanceID)
+{
+ LockObjectCreation();
+ Object* obj = Object::IDToPointerNoThreadCheck (inInstanceID);
+ UnlockObjectCreation();
+ return obj;
+}
+
+Object* Object::IDToPointerNoThreadCheck (int inInstanceID)
+{
+ if( !ms_IDToPointer) return NULL;
+
+ IDToPointerMap::const_iterator i = ms_IDToPointer->find (inInstanceID);
+ if (i != ms_IDToPointer->end ())
+ {
+ return i->second;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+#if THREADED_LOADING
+Object* InstanceIDToObjectThreadSafe (int instanceID)
+{
+ if (Thread::EqualsCurrentThreadID (GetPersistentManager().GetMainThreadID()))
+ return PPtr<Object> (instanceID);
+ else
+ {
+ Object* obj = Object::IDToPointerThreadSafe(instanceID);
+ if (obj == NULL)
+ return GetPersistentManager().ReadObjectThreaded(instanceID);
+ else
+ return obj;
+ }
+}
+#endif
+
+void Object::FindAllDerivedClasses (int classID, vector<SInt32>* derivedClasses, bool onlyNonAbstract)
+{
+ AssertIf (derivedClasses == NULL);
+ RTTIMap::iterator i;
+ for (i=gRTTI->begin ();i!=gRTTI->end ();i++)
+ {
+ if (IsDerivedFromClassID (i->first, classID) && (!onlyNonAbstract || !i->second.isAbstract))
+ derivedClasses->push_back (i->first);
+ }
+}
+
+struct GetConstFirst
+{
+ template<typename T1, typename T2>
+ const T1& operator()(const std::pair<T1, T2>& p) const {
+ return p.first;
+ }
+};
+
+struct GetConstSecond
+{
+ template<typename T1, typename T2>
+ const T2& operator()(const std::pair<T1, T2>& p) const {
+ return p.second;
+ }
+};
+
+struct IsDerivedFromClass
+{
+ IsDerivedFromClass(int classID): m_ClassID(classID) {}
+ bool operator()(const Object::IDToPointerMap::value_type& el) const
+ {
+ return el.second->IsDerivedFrom (m_ClassID);
+ }
+private:
+ int m_ClassID;
+};
+
+inline int DerivedObjectCount(const Object::IDToPointerMap& objmap, int classID)
+{
+ return std::count_if(objmap.begin(), objmap.end(), IsDerivedFromClass(classID));
+}
+
+template<typename ObjectGetter, typename Container, typename Predicate>
+inline int FindAllDerivedObjectsImpl (const Object::IDToPointerMap& objmap, int classID,
+ ObjectGetter getter, Container* derivedObjects, bool sorted, Predicate pred)
+{
+ if (NULL == derivedObjects)
+ return DerivedObjectCount(objmap, classID);
+
+ int count = 0;
+ for (typename Object::IDToPointerMap::const_iterator i = objmap.begin();
+ i != objmap.end(); ++i)
+ {
+ if (i->second->IsDerivedFrom (classID))
+ {
+ derivedObjects->push_back (getter(*i));
+ count++;
+ }
+ }
+
+ if (sorted && count)
+ std::sort(derivedObjects->begin(), derivedObjects->end(), pred);
+
+ return count;
+}
+
+int Object::FindAllDerivedObjects (int classID, vector<SInt32>* derivedObjects, bool sorted)
+{
+ return FindAllDerivedObjectsImpl (*ms_IDToPointer, classID,
+ GetConstFirst(), derivedObjects, sorted, std::less<SInt32>());
+}
+
+struct CompareInstanceID
+{
+ bool operator () (const Object* lhs, const Object* rhs) const
+ {
+ return lhs->GetInstanceID() < rhs->GetInstanceID();
+ }
+};
+
+int Object::FindObjectsOfType (int classID, vector<Object*>* derivedObjects, bool sorted)
+{
+ return FindAllDerivedObjectsImpl (*ms_IDToPointer, classID,
+ GetConstSecond(), derivedObjects, sorted, CompareInstanceID());
+}
+
+int Object::FindObjectsOfType (int classID, dynamic_array<Object*>* derivedObjects, bool sorted)
+{
+ int count = 0;
+ IDToPointerMap::iterator i;
+ for (i=ms_IDToPointer->begin ();i!=ms_IDToPointer->end ();i++)
+ {
+ if (i->second->IsDerivedFrom (classID))
+ {
+ if (derivedObjects != NULL)
+ derivedObjects->push_back (i->second);
+ count++;
+ }
+ }
+
+
+ if (sorted && derivedObjects != NULL)
+ {
+ CompareInstanceID compare;
+ sort(derivedObjects->begin(), derivedObjects->end(), compare);
+ }
+
+
+ return count;
+}
+
+
+const std::string& Object::ClassIDToString (int ID)
+{
+ static std::string emptyString;
+ RTTIMap::iterator i = gRTTI->find (ID);
+ if (i == gRTTI->end ())
+ return emptyString;
+ else
+ return i->second.className;
+}
+
+int Object::StringToClassID (const string& classString)
+{
+ StringToClassIDMap::iterator i;
+ i = gStringToClassID->find (const_cast<char*> (classString.c_str ()));
+ if (i == gStringToClassID->end ())
+ return -1;
+ else
+ return i->second;
+}
+
+int Object::StringToClassIDCaseInsensitive (const string& classString)
+{
+ StringToClassIDMap::iterator i;
+ string lowerClass = ToLower(classString);
+ for (StringToClassIDMap::iterator i = gStringToClassID->begin(); i!=gStringToClassID->end(); i++)
+ {
+ if (ToLower(string(i->first)) == lowerClass)
+ return i->second;
+ }
+ return -1;
+}
+
+int Object::StringToClassID (const char* classString)
+{
+ StringToClassIDMap::iterator i;
+ i = gStringToClassID->find (const_cast<char*> (classString));
+ if (i == gStringToClassID->end ())
+ return -1;
+ else
+ return i->second;
+}
+
+const std::string& Object::GetClassName () const
+{
+ return Object::ClassIDToString (GetClassID ());
+}
+
+int Object::GetSuperClassID (int classID)
+{
+ RTTIMap::iterator i = gRTTI->find (classID);
+ AssertIf (i == gRTTI->end ());
+ if (i->second.base)
+ return i->second.base->classID;
+ else
+ return ClassID (Object);
+}
+
+Object::RTTI* Object::ClassIDToRTTI (int classID)
+{
+ RTTIMap::iterator i = gRTTI->find (classID);
+ if (i == gRTTI->end ())
+ return NULL;
+ else
+ return &i->second;
+}
+
+struct BuildClassInfo
+{
+ Object::RTTI* klass;
+ Object::RTTI* base;
+ UInt32 id;
+ UInt32 subclasses;
+ UInt32 level;
+ UInt32 newId;
+ UInt32 subClassIdAssign;
+ void Clear(){
+ base = 0;
+ klass = 0;
+ id = (UInt32)-1;
+ subclasses = 0;
+ level = 0xffffffff;
+ newId = -1;
+ subClassIdAssign = 0;
+ }
+ void Init(Object::RTTI* klass, Object::RTTI* base)
+ {
+ this->klass = klass;
+ this->base = base;
+ }
+ bool operator <( const BuildClassInfo& o) const
+ {
+ return level < o.level;
+ }
+};
+int bitsRequired(int subclasses)
+{
+ int r = 0;
+ while(subclasses)
+ {
+ r++;
+ subclasses >>= 1;
+ }
+ return r;
+}
+
+void Object::StaticInitialize()
+{
+ SET_ALLOC_OWNER(gBaseObjectManagerContainer);
+ Object::ms_IDToPointer = UNITY_NEW(Object::IDToPointerMap (1024 * 128), kMemBaseObject);
+}
+
+void Object::StaticDestroy()
+{
+ UNITY_DELETE(Object::ms_IDToPointer,kMemBaseObject);
+}
+
+void Object::InitializeAllClasses ()
+{
+ SET_ALLOC_OWNER(gBaseObjectManagerContainer);
+
+ if (gRegisterClassCallbacks == NULL)
+ return;
+
+#if SHOW_REGISTERED_CLASS_INFO
+ int registeredClasses = 0;
+#endif
+
+ RegisterClassCallbacks& callbacks = *gRegisterClassCallbacks;
+ // The callback is the RegisterClass function defined in ObjectDefines.h
+ // It calls the static Object::RegisterClass function which sets up the rtti system
+ for (int i=0;i<callbacks.size ();i++)
+ {
+ if (callbacks[i].registerClass)
+ {
+ callbacks[i].registerClass ();
+#if SHOW_REGISTERED_CLASS_INFO
+ ++registeredClasses;
+#endif
+ }
+ }
+
+#if SHOW_REGISTERED_CLASS_INFO
+ printf_console ("Object::InitializeAllClasses: %d total, %d registered\n", callbacks.size(), registeredClasses);
+#endif
+
+ AssertIf (gRTTI->empty ());
+
+ // Setup ms_IsDerivedFrom lookup bitmap
+ if (UNITY_EDITOR)
+ {
+ ms_MaxClassID = (--gRTTI->end ())->first + 1;
+ Assert(kLargestEditorClassID == ms_MaxClassID);
+ }
+ else
+ {
+ ms_MaxClassID = kLargestRuntimeClassID;
+ }
+
+ gIsDerivedFromBitMap->resize (ms_MaxClassID * ms_MaxClassID, false);
+ ms_IsDerivedFromBitMap = (UInt32*) gIsDerivedFromBitMap->m_bits;
+ gRegisteredClassIDs->resize (ms_MaxClassID, false);
+ for (int i=0;i<ms_MaxClassID;i++)
+ {
+ RTTIMap::iterator iRTTI = gRTTI->find (i);
+ (*gRegisteredClassIDs)[i] = iRTTI != gRTTI->end ();
+ if ((*gRegisteredClassIDs)[i])
+ {
+ for (int j=0;j<ms_MaxClassID;j++)
+ {
+ RTTIMap::iterator jRTTI = gRTTI->find (j);
+ if (jRTTI != gRTTI->end ())
+ (*gIsDerivedFromBitMap)[i * ms_MaxClassID + j] = IsDerivedFromRTTI (&iRTTI->second, &jRTTI->second);
+ }
+ }
+ }
+
+#if USE_NEW_IS_DERIVED_FROM
+ ms_ClassIDMask = &gClassIDMask[0];
+ ms_ClassIsDerivedFrom = new UInt32[ms_MaxClassID];
+ memset(ms_ClassIsDerivedFrom, 0xffffffff, sizeof(UInt32) * ms_MaxClassID);
+ ms_ClassIsDerivedFrom[0] = 1;
+ BuildClassInfo* info = (BuildClassInfo*)alloca(sizeof(BuildClassInfo) * ms_MaxClassID);
+ for(int i = 0; i < ms_MaxClassID; ++i)
+ info[i].Clear();
+ int maxSubClasses[32];
+ int bitShift[32];
+ memset(maxSubClasses, 0, sizeof(maxSubClasses));
+ memset(bitShift, 0, sizeof(bitShift));
+ //search for the base class
+ typedef RTTIMap::iterator itr;
+ for(itr i = gRTTI->begin(); i != gRTTI->end(); ++i)
+ {
+ Object::RTTI& r = i->second;
+ SInt32 oldId = i->first;
+ info[oldId].Init(&r, r.base);
+ info[oldId].id = oldId;
+ int level = 0;
+ Object::RTTI* base = r.base;
+ while(base)
+ {
+ ++level;
+ base = base->base;
+ }
+ info[oldId].level = level;
+ if(r.base)
+ info[r.base->classID].subclasses++;
+ }
+ std::sort(&info[0], ms_MaxClassID + &info[0]);
+ for(int i = 0; i < ms_MaxClassID; ++i)
+ {
+ int level = info[i].level;
+ maxSubClasses[level] = info[i].subclasses > maxSubClasses[level] ? info[i].subclasses : maxSubClasses[level];
+ }
+ int totalBits = 1;
+ UInt32 mask = 1;
+ bitShift[0] = 0;
+ gClassIDMask[0] = 1;
+ for(int i = 1; i < 32; ++i)
+ {
+ int bitsReq = bitsRequired(maxSubClasses[i-1]);
+ int bitsReq1 = bitsReq;
+ while(bitsReq--)
+ mask = (mask<<1) | 1;
+
+ bitShift[i] = totalBits;
+ totalBits += bitsReq1;
+ AssertIf(totalBits > 32 - CLASS_ID_MASK_BITS); //OUT OF BITS
+ gClassIDMask[i] = mask;
+ }
+#define VERIFY_CLASS_IDS 0
+#if VERIFY_CLASS_IDS
+ std::set<UInt32> ClassIdSet;
+#endif
+ int lastIndex = 0;
+ for(int i = 0; i < ms_MaxClassID; ++i)
+ {
+ Object::RTTI* klass = info[i].klass;
+ Object::RTTI* base = info[i].base;
+ int level = info[i].level;
+ int parentId = 0;
+ int parentIndex = -1;
+ int parentSubIndex = 1;
+ if(base)
+ {
+ for(int j = 0; j < ms_MaxClassID; ++j)
+ {
+ if(info[j].klass == base)
+ {
+ parentIndex = j;
+ break;
+ }
+ }
+ AssertIf(parentIndex >= i);
+ parentId = info[parentIndex].newId & CLASS_ID_MASK_IDS;
+ AssertIf(-1 == parentId);
+ parentSubIndex = info[parentIndex].subClassIdAssign++;
+ }
+ else
+ {
+ parentSubIndex = 1;
+ if(i != 0)
+ {
+ lastIndex = i;
+ break;
+ }
+ }
+ int shift = bitShift[level];
+ int id = (parentSubIndex << shift) | parentId;
+ int fullId = id | (level<<(32-CLASS_ID_MASK_BITS));
+#if VERIFY_CLASS_IDS
+ AssertIf(ClassIdSet.find(fullId) != ClassIdSet.end() || ClassIdSet.find(id) != ClassIdSet.end() ); // DUPE CLASSID. should never happen
+ ClassIdSet.insert(id);
+ ClassIdSet.insert(fullId);
+#endif
+ info[i].newId = fullId;
+ ms_ClassIsDerivedFrom[info[i].id] = fullId;
+ AssertIf(info[i].subClassIdAssign != 0);
+ info[i].subClassIdAssign = 1;
+ }
+#endif
+}
+
+void Object::CallInitializeClass()
+{
+ RegisterClassCallbacks& callbacks = *gRegisterClassCallbacks;
+
+ // Call the IntializeClass function for classes that registered for it (IMPLEMENT_CLASS_HAS_INIT)
+ // This is done after all classes are registered and the rtti setup
+ // so that the rtti system can be used insie InitializeClass ()
+ for (int i=0;i<callbacks.size ();i++)
+ {
+ if (callbacks[i].initClass)
+ {
+ callbacks[i].initClass ();
+ }
+ }
+}
+
+void Object::CallPostInitializeClass()
+{
+ RegisterClassCallbacks& callbacks = *gRegisterClassCallbacks;
+
+ // Call the PostIntializeClass function for classes that registered for it (IMPLEMENT_CLASS_HAS_POSTINIT)
+ // This is done after all classes are registered and the rtti setup
+ // so that the rtti system can be used inside PostInitializeClass ()
+ for (int i=0;i<callbacks.size ();i++)
+ {
+ if (callbacks[i].postInitClass)
+ {
+ callbacks[i].postInitClass ();
+ }
+ }
+}
+
+void Object::AddEvent (EventCallback* callback, void* userData)
+{
+ m_EventIndex = GetEventManager().AddEvent(callback, userData, m_EventIndex);
+}
+
+void Object::RemoveEvent (EventCallback* callback, void* userData)
+{
+ m_EventIndex = GetEventManager().RemoveEvent(m_EventIndex, callback, userData);
+}
+
+bool Object::HasEvent (EventCallback* callback, const void* userData) const
+{
+ return EventManager::HasEvent(m_EventIndex, callback, userData);
+}
+
+void Object::InvokeEvent (int eventType)
+{
+ EventManager::InvokeEvent(m_EventIndex, this, eventType);
+}
+
+bool IsObjectAvailable (int instanceID)
+{
+ Object* temp = Object::IDToPointer (instanceID);
+ if (temp != NULL)
+ return true;
+
+ return GetPersistentManager ().IsObjectAvailable (instanceID);
+}
+#if !USE_NEW_IS_DERIVED_FROM
+#if !UNITY_RELEASE
+
+bool Object::IsDerivedFromClassID (int classID, int compareClass)
+{
+ if (classID >= ms_MaxClassID || classID < 0)
+ {
+ char buffy[512];
+ sprintf (buffy, "The class with classID: %d out of bounds", classID);
+ AssertString (buffy);
+ return false;
+ }
+ if (compareClass >= ms_MaxClassID || compareClass < 0)
+ {
+ /*
+ char buffy[512];
+ sprintf (buffy, "The compare class with classID: %d out of bounds", compareClass);
+ AssertString (buffy);
+ */
+ return false;
+ }
+
+ AssertIf (classID >= ms_MaxClassID || classID < 0);
+ AssertIf (compareClass >= ms_MaxClassID || compareClass < 0);
+
+
+ if (!(*gRegisteredClassIDs)[classID])
+ {
+ char buffy[512];
+ sprintf (buffy, "The class with classID: %d is not registered (see ClassIDs.h)", classID);
+ AssertString (buffy);
+
+ }
+
+ // When doing classID stripping
+ #if !ALLOW_CLASS_ID_STRIPPING
+ if (!(*gRegisteredClassIDs)[compareClass])
+ {
+ char buffy[512];
+ sprintf (buffy, "The class with classID: %d is not registered (see ClassIDs.h)", compareClass);
+ AssertString (buffy);
+ }
+ #endif
+
+ int index = classID * ms_MaxClassID + compareClass;
+ int block = index >> 5;
+ int bit = index - (block << 5);
+ return (ms_IsDerivedFromBitMap[block]) & (1 << bit);
+}
+
+#endif
+#endif
+
+INSTANTIATE_TEMPLATE_TRANSFER_WITH_DECL (Object, EXPORTDLL);
+
+template<class TransferFunction>
+void Object::Transfer (TransferFunction& transfer)
+{
+#if UNITY_EDITOR
+ if (!transfer.IsSerializingForGameRelease() && SerializePrefabIgnoreProperties(transfer))
+ {
+ UInt32 flags = m_HideFlags;
+ transfer.Transfer(flags, "m_ObjectHideFlags", kHideInEditorMask);
+ m_HideFlags = flags;
+ }
+
+ if (transfer.GetFlags () & kSerializeDebugProperties)
+ {
+ SInt32 instanceID = GetInstanceID ();
+ transfer.Transfer (instanceID, "m_InstanceID");
+
+ LocalIdentifierInFileType fileID;
+ if (IsPersistent ())
+ fileID = GetPersistentManager ().GetLocalFileID (instanceID);
+ else
+ fileID = GetFileIDHint ();
+
+ transfer.Transfer (fileID, "m_LocalIdentfierInFile");
+ }
+#endif
+}
+
+#if UNITY_EDITOR
+
+void Object::RegisterDirtyCallback (ObjectDirtyCallbackFunction* callback)
+{
+ gSetDirtyCallbackFunc = callback;
+}
+
+Object::ObjectDirtyCallbackFunction* Object::GetDirtyCallback ()
+{
+ return gSetDirtyCallbackFunc;
+}
+
+void Object::SetDirty ()
+{
+ // When we run out of dirty indices, make sure it stays at 1
+ m_DirtyIndex++;
+ if (m_DirtyIndex == 0)
+ m_DirtyIndex = 1;
+
+ if (gSetDirtyCallbackFunc)
+ gSetDirtyCallbackFunc (this);
+
+ #if !UNITY_RELEASE
+ m_DEBUGCLASSID = GetClassID ();
+ #endif
+}
+
+void Object::ClearPersistentDirty ()
+{
+ m_DirtyIndex = 0;
+}
+
+void Object::SetPersistentDirtyIndex (UInt32 dirtyValue)
+{
+ m_DirtyIndex = dirtyValue;
+}
+
+
+#endif
+
+#if DEBUGMODE
+void AddVerifyClassRegistration (int classID)
+{
+ if (gVerifyRegisteredClasses == NULL)
+ {
+ SET_ALLOC_OWNER(gBaseObjectManagerContainer);
+ gVerifyRegisteredClasses = UNITY_NEW(RegisteredClassSet, kMemManager)();
+ }
+ gVerifyRegisteredClasses->insert(classID);
+}
+const RegisteredClassSet& GetVerifyClassRegistration ()
+{
+ if (gVerifyRegisteredClasses == NULL)
+ {
+ SET_ALLOC_OWNER(gBaseObjectManagerContainer);
+ gVerifyRegisteredClasses = UNITY_NEW(RegisteredClassSet, kMemManager)();
+ }
+ return *gVerifyRegisteredClasses;
+}
+
+#endif
+
+
+void RegisterInitializeClassCallback (int classID,
+ RegisterClassCallback* registerClass,
+ RegisterClassCallback* initClass,
+ RegisterClassCallback* postInitClass,
+ RegisterClassCallback* cleanupClass)
+{
+ if (gRegisterClassCallbacks == NULL)
+ {
+ SET_ALLOC_OWNER(gBaseObjectManagerContainer);
+ gRegisterClassCallbacks = UNITY_NEW(RegisterClassCallbacks,kMemBaseObject);
+ }
+ if (gRegisterClassCallbacks->size () <= classID)
+ gRegisterClassCallbacks->resize (classID + 1);
+
+ RegisterClassCallbacks& callbacks = *gRegisterClassCallbacks;
+ if (callbacks[classID].registerClass != NULL || callbacks[classID].initClass != NULL || callbacks[classID].postInitClass != NULL || callbacks[classID].cleanupClass != NULL)
+ {
+ char buffer[512];
+ sprintf (buffer, "ClassID: %d is already registered. ClassID's have to be unique", classID);
+ FatalErrorString (buffer);
+ AssertBreak(false);
+ }
+ callbacks[classID].registerClass = registerClass;
+ callbacks[classID].initClass = initClass;
+ callbacks[classID].postInitClass = postInitClass;
+ callbacks[classID].cleanupClass = cleanupClass;
+}
+
+void Object::CleanupAllClasses ()
+{
+ AssertIf(!ms_IDToPointer->empty());
+
+ if (!gRegisterClassCallbacks)
+ return;
+
+ RegisterClassCallbacks& callbacks = *gRegisterClassCallbacks;
+ for (int i=0;i<callbacks.size ();i++)
+ {
+ if (callbacks[i].cleanupClass)
+ callbacks[i].cleanupClass ();
+ }
+
+ UNITY_DELETE(gRegisterClassCallbacks, kMemBaseObject);
+}
+
+void SetDisableImmediateDestruction (bool disable)
+{
+ gDisableImmediateDestruction = disable;
+}
+
+bool GetDisableImmediateDestruction ()
+{
+ return gDisableImmediateDestruction;
+}
+
+void delete_object_internal (Object* p)
+{
+ if (!p)
+ return;
+
+ delete_object_internal_step1 (p);
+ delete_object_internal_step2 (p);
+}
+
+// This can be execute on any thread.
+void delete_object_internal_step2 (Object* p)
+{
+ MemLabelId label = p->GetMemoryLabel();
+ p->~Object ();
+ UNITY_FREE(label, p);
+}
+
+void UnloadObject (Object* p)
+{
+ if (!p)
+ return;
+
+ LockObjectCreation();
+ delete_object_internal(p);
+ UnlockObjectCreation();
+}
+
+void Object::DoneLoadingManagers()
+{
+ // We are done loading managers. Start instance IDs from a high constant value here,
+ // so new managers and built-in resources can be added without changed instanceIDs
+ // used by the content.
+ if (gLowestInstanceID > -10000)
+ {
+ gLowestInstanceID = -10000;
+ }
+}
+
+MemLabelId Object::GetMemoryLabel() const
+{
+ MemLabelIdentifier id = (MemLabelIdentifier)m_MemLabel;
+ MemLabelId label(id, NULL);
+ if(m_IsRootOwner)
+ label.SetRootHeader(GET_ALLOC_HEADER((void*)this, label));
+ return label;
+}
+
+int Object::GetRuntimeMemorySize() const
+{
+#if ENABLE_MEM_PROFILER
+ return GetMemoryProfiler()->GetRelatedMemorySize((void*)this);
+#else
+ return 0;
+#endif
+}
+
+
+#if !UNITY_RELEASE
+
+void Object::CheckCorrectAwakeUsage()
+{
+ // check only if saw that object already to allow delayed awake and immediate destroy
+ if ( m_AwakeCalled == 0 )
+ AssertStringObject(Format("Awake has not been called '%s' (%s). Figure out where the object gets created and call AwakeFromLoad correctly.", GetName(), GetClassName().c_str()), this);
+
+ if ( m_ResetCalled == 0 )
+ AssertStringObject(Format("Reset has not been called '%s' (%s). Figure out where the object gets created and call Reset correctly.", GetName(), GetClassName().c_str()), this);
+
+ if ( m_AwakeThreadedCalled && !m_AwakeDidLoadThreadedCalled )
+ AssertStringObject(Format("AwakeFromLoadThreaded has not been called '%s' (%s). Figure out where the object gets created and call AwakeFromLoadThreaded correctly.", GetName(), GetClassName().c_str()), this);
+}
+
+
+#endif // !UNITY_RELEASE
diff --git a/Runtime/BaseClasses/BaseObject.h b/Runtime/BaseClasses/BaseObject.h
new file mode 100644
index 0000000..52613be
--- /dev/null
+++ b/Runtime/BaseClasses/BaseObject.h
@@ -0,0 +1,1162 @@
+#ifndef BASEOBJECT_H
+#define BASEOBJECT_H
+
+#include "Runtime/Utilities/LogAssert.h"
+#include "Runtime/Serialize/SerializeUtility.h"
+#include "Runtime/Serialize/SerializationMetaFlags.h"
+#include "Configuration/UnityConfigure.h"
+#include "Runtime/Utilities/Prefetch.h"
+#include "Runtime/Scripting/Backend/ScriptingTypes.h"
+#include "Runtime/Misc/Allocator.h"
+#include "Runtime/Utilities/dynamic_array.h"
+
+#include <string>
+#include <vector>
+
+#include "Runtime/Utilities/dense_hash_map.h"
+#include "Runtime/Utilities/HashFunctions.h"
+
+#include "Runtime/BaseClasses/ClassIDs.h"
+
+class ProxyTransfer;
+class SafeBinaryRead;
+template<bool kSwap>
+class StreamedBinaryRead;
+template<bool kSwap>
+class StreamedBinaryWrite;
+class RemapPPtrTransfer;
+class TypeTree;
+class Object;
+struct EventEntry;
+#if SUPPORT_TEXT_SERIALIZATION
+class YAMLRead;
+class YAMLWrite;
+#endif
+
+#include "ObjectDefines.h"
+#include <string>
+#include <typeinfo>
+
+//#define DefineClassID( x, classID )
+//#define ClassID( x )
+
+// Every non-abstract class that is derived from object has to place this inside the class Declaration
+// (REGISTER_DERIVED_CLASS (Foo, Object))
+
+// Every abstract class that is derived from object has to place this inside the class Declaration
+// (REGISTER_DERIVED_ABSTRACT_CLASS (Foo, Object))
+
+//In the cpp file of every object derived class you have to place eg. IMPLEMENT_CLASS (Foo)
+//#define IMPLEMENT_CLASS(x)
+// or IMPLEMENT_CLASS_HAS_INIT (x) which will call the static class Function InitializeClass (); on startup.
+
+using std::string;
+
+template<class T>
+class PPtr
+{
+ SInt32 m_InstanceID;
+ #if !UNITY_RELEASE
+ mutable T* m_DEBUGPtr;
+ #endif
+
+ protected:
+
+ inline void AssignObject (const Object* o);
+
+ private:
+ static string s_TypeString;
+
+ public:
+
+ static const char* GetTypeString ();
+ static bool IsAnimationChannel () { return false; }
+ static bool MightContainPPtr () { return true; }
+ static bool AllowTransferOptimization () { return false; }
+
+ template<class TransferFunction>
+ void Transfer (TransferFunction& transfer);
+
+ // Assignment
+ explicit PPtr (int instanceID)
+ {
+ m_InstanceID = instanceID;
+ #if !UNITY_RELEASE
+ m_DEBUGPtr = NULL;
+ #endif
+ }
+ PPtr (const T* o) { AssignObject (o); }
+ PPtr (const PPtr<T>& o)
+ {
+ m_InstanceID = o.m_InstanceID;
+ #if !UNITY_RELEASE
+ m_DEBUGPtr = NULL;
+ #endif
+ }
+
+ PPtr ()
+ {
+ #if !UNITY_RELEASE
+ m_DEBUGPtr = NULL;
+ #endif
+ m_InstanceID = 0;
+ }
+
+ PPtr& operator = (const T* o) { AssignObject (o); return *this; }
+ PPtr& operator = (const PPtr<T>& o)
+ {
+ #if !UNITY_RELEASE
+ m_DEBUGPtr = NULL;
+ #endif
+ m_InstanceID = o.m_InstanceID; return *this;
+ }
+
+ void SetInstanceID (int instanceID) { m_InstanceID = instanceID; }
+ int GetInstanceID ()const { return m_InstanceID; }
+
+ // Comparison
+ bool operator < (const PPtr& p)const { return m_InstanceID < p.m_InstanceID; }
+ bool operator == (const PPtr& p)const { return m_InstanceID == p.m_InstanceID; }
+ bool operator != (const PPtr& p)const { return m_InstanceID != p.m_InstanceID; }
+
+ // MSVC gets confused whether it should use operator bool(), or operator T* with implicit
+ // comparison to NULL. So we add explicit functions and use them instead.
+ bool IsNull() const;
+ bool IsValid() const;
+
+ operator T* () const;
+ T* operator -> () const;
+ T& operator * () const;
+};
+
+template<class T>
+class ImmediatePtr
+{
+ mutable intptr_t m_Ptr;
+ #if !UNITY_RELEASE
+ mutable T* m_DEBUGPtr;
+ #endif
+
+ void AssignInstanceID (int instanceID)
+ {
+ AssertIf (instanceID & 1); m_Ptr = instanceID | 1; AssertIf ((m_Ptr & 1) == 0);
+ #if !UNITY_RELEASE
+ m_DEBUGPtr = NULL;
+ #endif
+ }
+ void AssignObject (const T* o)
+ {
+ m_Ptr = (intptr_t)o; AssertIf (m_Ptr & 1);
+ #if !UNITY_RELEASE
+ m_DEBUGPtr = const_cast<T*>(o);
+ #endif
+ }
+ void Load () const
+ {
+ AssertIf ((m_Ptr & 1) == 0);
+ T* loaded = PPtr<T> (m_Ptr & (~1));
+ m_Ptr = (intptr_t)(loaded);
+ AssertIf (m_Ptr & 1);
+ #if !UNITY_RELEASE
+ m_DEBUGPtr = loaded;
+ #endif
+ }
+
+ inline T* GetPtr () const
+ {
+ if ((m_Ptr & 1) == 0)
+ {
+ return (T*)(m_Ptr);
+ }
+ else
+ {
+ Load ();
+ return (T*)(m_Ptr);
+ }
+ }
+
+ static string s_TypeString;
+
+ public:
+
+ bool IsLoaded () const;
+
+ static const char* GetTypeString ();
+ static bool IsAnimationChannel () { return false; }
+ static bool MightContainPPtr () { return true; }
+ static bool AllowTransferOptimization () { return false; }
+
+ template<class TransferFunction>
+ void Transfer (TransferFunction& transfer);
+
+ // Assignment
+ ImmediatePtr (const T* o) { AssignObject (o); }
+ ImmediatePtr (const ImmediatePtr<T>& o) { m_Ptr = o.m_Ptr; }
+ ImmediatePtr () { m_Ptr = 0; }
+
+ ImmediatePtr& operator = (const T* o) { AssignObject (o); return *this; }
+
+ void SetInstanceID (int instanceID) { AssignInstanceID (instanceID); }
+ int GetInstanceID ()const
+ {
+ if ((m_Ptr & 1) == 0 && m_Ptr != 0)
+ {
+ T* o = (T*)(m_Ptr);
+ SInt32 instanceID = o->GetInstanceID ();
+ AssertIf (instanceID & 1);
+ return instanceID;
+ }
+ else
+ return m_Ptr & (~1);
+ }
+
+ inline bool operator == (const T* p)const { return GetPtr () == p; }
+ inline bool operator != (const T* p)const { return GetPtr () != p; }
+
+ inline operator T* () const { return GetPtr (); }
+ inline T* operator -> () const { T* o = GetPtr (); AssertIf (o == NULL); return o; }
+ inline T& operator * () const { T* o = GetPtr (); AssertIf (o == NULL); ANALYSIS_ASSUME(o); return *o; }
+};
+
+template<typename T> class PtrToType;
+template<typename T> class PtrToType<T*>
+{
+public:
+ typedef T value_type;
+};
+
+template<class T, class U>
+T dynamic_pptr_cast (U* ptr)
+{
+ typedef typename PtrToType<T>::value_type Type;
+ T castedPtr = (T)(ptr);
+ if (castedPtr && castedPtr->IsDerivedFrom ( Type::GetClassIDStatic ()))
+ return castedPtr;
+ else
+ return NULL;
+}
+
+template<class T, class U>
+T dynamic_pptr_cast (const PPtr<U>& ptr)
+{
+ U* o = ptr;
+ return dynamic_pptr_cast<T> (o);
+}
+
+template<class T> inline
+T dynamic_instanceID_cast (int instanceID)
+{
+ Object* o = PPtr<Object> (instanceID);
+ return dynamic_pptr_cast<T> (o);
+}
+
+template<class T, class U>
+PPtr<T> assert_pptr_cast (const PPtr<U>& ptr)
+{
+ #if DEBUGMODE
+ U* u = ptr;
+ AssertIf (dynamic_pptr_cast<U*> (u) == NULL && u != NULL);
+ #endif
+ return PPtr<T> (ptr.GetInstanceID ());
+}
+
+// Enables boost::mem_fn to use PPtr properly, needed for boost::bind
+template<typename T> inline T * get_pointer(PPtr<T> const & p)
+{
+ return p;
+}
+
+
+enum ObjectCreationMode
+{
+ // Create the object from the main thread in a perfectly normal way
+ kCreateObjectDefault = 0,
+ // Create the object from another thread. Might assign an instance ID but will not register with IDToPointer map.
+ // Objects created like this, need to call, AwakeFromLoadThraded, and Object::RegisterInstanceID and AwakeFromLoad (kDidLoadThreaded); from the main thread
+ kCreateObjectFromNonMainThread = 1,
+ // Create the object and register the instance id but do not lock the object
+ // creation mutex because the code calling it already called LockObjectCreation mutex.
+ kCreateObjectDefaultNoLock = 2
+};
+
+
+enum AwakeFromLoadMode
+{
+ // This is the default, usually called from the inspector or various serialization methods
+ kDefaultAwakeFromLoad = 0,
+ // The object was loaded from disk
+ kDidLoadFromDisk = 1 << 0,
+ // The object was loaded from a loading thread (in almost all cases through loading from disk asynchronously)
+ kDidLoadThreaded = 1 << 1,
+ // Object was instantiated and is now gettings it's first Awake function or it was created from code and gets the Awake function called
+ kInstantiateOrCreateFromCodeAwakeFromLoad = 1 << 2,
+ // GameObject was made active or a component was added to an active game object
+ kActivateAwakeFromLoad = 1 << 3,
+
+ kDefaultAwakeFromLoadInvalid = -1
+};
+
+class BaseAllocator;
+
+enum ObjectDeleteMode
+{
+ kUnknownMode = 0
+};
+
+class EXPORT_COREMODULE Object
+{
+ protected:
+ virtual ~Object ();
+
+ public:
+
+ Object (MemLabelId label, ObjectCreationMode mode);
+
+
+ /// By default the destructor might get executed on another thread.
+ /// This lets us distribute large level unloads to another thread and thus avoid hiccups.
+ /// Some classes need to deallocate resources on the main thread.
+ /// You can implement this function to delete the resources.
+ ///
+ /// The destructor will still be called in this case, thus you need to ensure that values are set to NULL.
+ /// MainThreadCleanup is only called if the deallocations are done on another thread.
+ /// Thus the destructor needs to handle the case where it is not called correctly.
+ ///
+ /// If you override the function return true, since it indicates that the class requires the function to be called.
+ /// SA: DoesClassRequireMainThreadDeallocation
+ virtual bool MainThreadCleanup ();
+
+ /// To destroy objects use delete_object instead of delete operator
+ /// The default way to destroy objects is using the DestroyObject Function, which also destroys the object from it's file
+ /// Must be protected by LockObjectCreation / UnlockObjectCreation
+ friend void delete_object_internal_step1 (Object* p);
+ friend void delete_object_internal_step2 (Object* p);
+
+ /// AwakeFromLoad is called after an object was read using Transfer (Either from disk or a vector)
+ /// This means it is called after the inspector has been updated, after it is loaded from disk, after a prefab has been modified or
+ /// the animation system has changed values behind your back.
+ virtual void AwakeFromLoad (AwakeFromLoadMode awakeMode)
+ {
+ #if !UNITY_RELEASE
+ m_AwakeCalled = 1;
+
+ if( awakeMode & kDidLoadThreaded )
+ m_AwakeDidLoadThreadedCalled = 1;
+ #endif
+ }
+
+ virtual void AwakeFromLoadThreaded ()
+ {
+ #if !UNITY_RELEASE
+ m_AwakeThreadedCalled = 1;
+ m_AwakeCalled = 0;
+ m_AwakeDidLoadThreadedCalled = 0;
+ #endif
+ }
+
+ /// For Subclasses: Makes sure that persistent variables are correct and if not corrects them
+ /// It is called after Prefab propagation, SafeBinaryRead and PropertyEditor changes.
+ /// It is called before AwakeFromLoad
+ virtual void CheckConsistency () { }
+
+ /// Override Reset in order to setup default values for the Object
+
+ /// The difference between setting up default values in the constructor
+ /// and Reset is that Reset is only called when the editor creates a new object
+ /// or when the object uses SerializeSafeBinary read.
+ /// Thus Reset can be used as a performance optimization for touching variables which are serialized only once during load.
+ /// * All variables that are serialized and Reset in the Reset function, do not have to be initialized in the constructor*
+ /// Reset functions might get called from different threads during loading, thus they may not derefence other objects, in that case use SmartReset.
+ /// You can always rely on that AwakeFromLoad is called after Reset has been called.
+ virtual void Reset ()
+ {
+ #if !UNITY_RELEASE
+ m_ResetCalled = 1;
+ m_AwakeCalled = 0;
+ m_AwakeThreadedCalled = 0;
+ m_AwakeDidLoadThreadedCalled = 0;
+ #endif
+ }
+
+ // Smart Reset is called when Reset is selected or when AddComponent is called and a new ScriptableObject is created.
+ // If you want to for example adjust a collider bounding volume by the renderers mesh, use SmartReset, you can not use Reset for this!
+ virtual void SmartReset ()
+ {
+ #if !UNITY_RELEASE
+ m_ResetCalled = 1;
+ m_AwakeCalled = 0;
+ m_AwakeThreadedCalled = 0;
+ m_AwakeDidLoadThreadedCalled = 0;
+ #endif
+ }
+
+#if !UNITY_RELEASE
+ // use it to check AwakeFromLoad/AwakeFromLoadThreaded/Reset/SmartReset were correctly called
+ void CheckCorrectAwakeUsage();
+
+ // hacks to set debug flags in cases you REALLY know what you are doing
+
+ // call when you don't want to Reset in case of object fully inited and don't need to be reset to default state
+ // e.g. if you de-serialize object - you don't need reset
+ inline void HackSetResetWasCalled() { m_ResetCalled = 1; }
+
+ // call when AwakeFromLoad has some side-effects so you need to postpone that call for indefinite time
+ // e.g. AudioClip will try to load sound in AwakeFromLoad, so you better do this only when needed
+ inline void HackSetAwakeWasCalled() { m_AwakeCalled = 1; }
+
+ // same as HackSetAwakeWasCalled but for Awake with kDidLoadThreaded param
+ inline void HackSetAwakeDidLoadThreadedWasCalled () { m_AwakeDidLoadThreadedCalled = true; }
+ #else
+ inline void HackSetResetWasCalled() {}
+ inline void HackSetAwakeWasCalled() {}
+ inline void HackSetAwakeDidLoadThreadedWasCalled() {}
+ #endif
+
+ /// Get and set the name
+ virtual char const* GetName () const { return ""; };
+ virtual void SetName (char const* /*name*/) { }
+ void SetNameCpp (const std::string& name) { SetName(name.c_str()); }
+
+ #if UNITY_EDITOR
+ /// Return true if you want the inspector to automatically refresh without SetDirty being called.
+ virtual bool HasDebugmodeAutoRefreshInspector () { return false; }
+ virtual void WarnInstantiateDisallowed () {}
+ #endif
+
+ /// Returns the classID of the class
+ static int GetClassIDStatic () { return ClassID (Object); }
+
+ // Is the class sealed (No other class can inherit from it)
+ // A sealed class can perform a GetComponent call faster,
+ // since it can compare the ClassID directly instead of using the RTTI system.
+ static bool IsSealedClass () { return false; }
+
+ /// Returns true if the class is abstract
+ static bool IsAbstract () { return true; }
+
+ /// Creates an object of type classID.
+ /// if instanceID is 0 a unique id will be generated if its non 0 the object will have the specified instanceID
+ static Object* Produce (int classID, int instanceID = 0, MemLabelId = kMemBaseObject, ObjectCreationMode mode = kCreateObjectDefault);
+
+
+ // Static initializa and destroy for BaseObject
+ static void StaticInitialize();
+ static void StaticDestroy();
+
+ /// Registers instance id with IDToPointerMap
+ /// useful for thread loading with delayed activation from main thread
+ /// Can only be called from main thead
+ static void RegisterInstanceID (Object* obj);
+ static void RegisterInstanceIDNoLock (Object* obj);
+
+ /// Allocates new instanceID and registers it with IDToPointerMap
+ /// Can only be called from main thead
+ static Object* AllocateAndAssignInstanceID (Object* obj);
+ static Object* AllocateAndAssignInstanceIDNoLock (Object* obj);
+
+ #if UNITY_EDITOR
+ virtual void CloneAdditionalEditorProperties (Object& /*source*/) { }
+
+ /// Can assign variable allows you to do additional type checking when assiging a variable
+ /// in the property inspector.
+ /// Eg. MonoBehaviours checks if a monobehaviour can be assigned based on the actual Mono class
+ virtual bool CanAssignMonoVariable (const char* /*property*/, Object* /*object*/) { return false; }
+
+ #endif
+
+ virtual bool ShouldIgnoreInGarbageDependencyTracking () { return false; }
+
+ /// Gets the class ID
+ ClassIDType GetClassID () const { Assert(m_CachedClassID != 0); return (ClassIDType)m_CachedClassID; }
+ /// Gets the instance ID
+ int GetInstanceID () const { AssertIf(m_InstanceID == 0); return m_InstanceID; }
+ bool IsInstanceIDCreated () const { return m_InstanceID != 0; }
+
+ /// Is this instance derived from compareClassID
+ bool IsDerivedFrom (int compareClassID)const { return IsDerivedFromClassID (GetClassID (), compareClassID); }
+
+ #if UNITY_EDITOR
+
+ /// Has this object been synced with the PersistentManager
+ bool IsPersistentDirty () const { return m_DirtyIndex != 0; }
+
+ void SetPersistentDirtyIndex (UInt32 dirtyIndex);
+ UInt32 GetPersistentDirtyIndex () { return m_DirtyIndex; }
+
+ ////@TODO: Rename this to SetPersistentDirty
+
+ /// Whenever variables that are being serialized in Transfer change, SetDirty () should be called
+ /// This will allow tracking of objects that have changed since the last saving to disk or over the network
+ void SetDirty ();
+
+ /// This method can be called if you need to unload an object from memory even if it's dirty.
+ void ClearPersistentDirty ();
+
+ // Callback support for callbacks when SetDirty is called
+ typedef void ObjectDirtyCallbackFunction (Object* ptr);
+ static void RegisterDirtyCallback (ObjectDirtyCallbackFunction* callback);
+ static ObjectDirtyCallbackFunction* GetDirtyCallback ();
+
+ void SetFileIDHint (LocalIdentifierInFileType hint) { m_FileIDHint = hint; }
+ LocalIdentifierInFileType GetFileIDHint () const { return m_FileIDHint; }
+
+ #else
+ void SetDirty () { }
+ void ClearPersistentDirty () { }
+
+ #endif
+
+
+ // The name of the class
+ const std::string& GetClassName () const;
+
+ enum
+ {
+ kHideInHierarchy = 1 << 0,
+ kHideInspector = 1 << 1,
+ kDontSave = 1 << 2,
+ kNotEditable = 1 << 3,
+ kHideAndDontSave = kDontSave | kHideInHierarchy | kNotEditable
+ };
+
+ int GetHideFlags () const { return m_HideFlags; }
+ bool TestHideFlag (int mask) const { return (m_HideFlags & mask) == mask; }
+ bool TestHideFlagAny (int mask) const { return (m_HideFlags & mask) != 0; }
+
+ virtual void SetHideFlags (int flags) { m_HideFlags = flags; }
+ void SetHideFlagsObjectOnly (int flags) { Assert(flags < (1 << kHideFlagsBits)); m_HideFlags = flags; }
+
+ /// You must document all usage here in order to provide clear overview and avoid overlaps
+ /// - Transform root calculation for animation component, when binding animation states (Runtime only)
+ void SetTemporaryFlags (int flags) { Assert(flags < (1 << kTemporaryFlagsBits)); m_TemporaryFlags = flags; }
+ int GetTemporaryFlags () const { return m_TemporaryFlags; }
+#if UNITY_WINRT
+ /// Used by WinRT's GarbageCollectSharedAssets
+ void SetTemporaryUnusedAssetsFlags (int flags) { m_TemporaryUnusedAssetsFlags = flags; }
+ int GetTemporaryUnusedAssetsFlags () const { return m_TemporaryUnusedAssetsFlags; }
+#endif
+
+#if ENABLE_SCRIPTING
+ int GetGCHandle () const { return m_MonoReference; }
+#endif
+
+ /// Overall memory allocated for this object. Should calculate any memory allocated by other subystems as well.
+ /// For example if OpenGL allocates memory for a texture it must return how much memory we "think" OpenGL will allocate for the texture.
+ virtual int GetRuntimeMemorySize () const;
+
+ /// Is this object persistent?
+ bool IsPersistent () const { return m_IsPersistent; }
+
+ typedef InstanceIdToObjectPtrHashMap IDToPointerMap;
+
+ /// How many objects are there in memory?
+ static IDToPointerMap::size_type GetLoadedObjectCount () { return ms_IDToPointer->size (); }
+
+ // Finds the pointer to the object referenced by instanceID (NULL if none found in memory)
+ static Object* IDToPointer (int inInstanceID);
+ static Object* IDToPointerThreadSafe (int inInstanceID);
+
+ /// This function may not be called unless you use LockObjectCreation / UnlockObjectCreation from another thread first...
+ /// If you don't know 100% what you are doing use: IDToPointerThreadSafe instead
+ static Object* IDToPointerNoThreadCheck (int inInstanceID);
+
+ /// Finds out if classID is derived from compareClassID
+ static bool IsDerivedFromClassID (int classID, int derivedFromClassID);
+
+ /// Returns the super Class ID of classID.
+ /// if classID doesnt have any super Class it will return ClassID (Object)
+ static int GetSuperClassID (int classID);
+
+ /// Returns all classIDs that are derived from ClassID
+ static void FindAllDerivedClasses (int classID, std::vector<SInt32>* allDerivedClasses, bool returnOnlyNonAbstractClasses = true);
+ /// Returns how many objects are derived from classID
+ /// If allDerivedObjects != NULL, adds all derived object instanceIDs to the container
+ static int FindAllDerivedObjects (int classID, std::vector<SInt32>* derivedObjects, bool sorted = false);
+
+ static int FindObjectsOfType (int classID, std::vector<Object*>* derivedObjects, bool sorted = false);
+ template<class T>
+ static int FindObjectsOfType (std::vector<T*>* derivedObjects)
+ {
+ std::vector<Object*>* casted = reinterpret_cast<std::vector<Object*>*> (derivedObjects);
+ return FindObjectsOfType (T::GetClassIDStatic (), casted);
+ }
+
+ static int FindObjectsOfType (int classID, dynamic_array<Object*>* derivedObjects, bool sorted = false);
+ template<class T>
+ static int FindObjectsOfType (dynamic_array<T*>* derivedObjects)
+ {
+ dynamic_array<Object*>* casted = reinterpret_cast<dynamic_array<Object*>*> (derivedObjects);
+ return FindObjectsOfType (T::GetClassIDStatic (), casted);
+ }
+
+ template<class T>
+ static int FindObjectsOfTypeSorted (std::vector<T*>* derivedObjects)
+ {
+ std::vector<Object*>* casted = reinterpret_cast<std::vector<Object*>*> (derivedObjects);
+ return FindObjectsOfType (T::GetClassIDStatic (), casted, true);
+ }
+
+
+
+ /// Get the class name from the classID
+ static const std::string& ClassIDToString (int classID);
+ /// Get the classID from the class name, returns -1 if no classID was found
+ static int StringToClassID (const std::string& classString);
+ static int StringToClassIDCaseInsensitive (const std::string& classString);
+ static int StringToClassID (const char* classString);
+
+ /// Callback support for callbacks when an object is destroyed
+ typedef void ObjectDestroyCallbackFunction (int instanceID);
+ static void RegisterDestroyedCallback (ObjectDestroyCallbackFunction* callback);
+
+ /// Sets up the rtti for all classes that are derived from Object and
+ /// use the macro IMPLEMENT_CLASS or IMPLEMENT_CLASS_HAS_INIT
+ /// Calls the static function InitializeClass on every class that used
+ /// IMPLEMENT_CLASS_HAS_INIT instead of IMPLEMENT_CLASS
+ static void InitializeAllClasses ();
+ static void CallInitializeClassEarly();
+ static void CallInitializeClass();
+ static void CallPostInitializeClass();
+
+ static void CleanupAllClasses ();
+
+ /// Checks if an array of instance id's are loaded.
+ /// If an instanceID is loaded it is set to 0.
+ static void CheckInstanceIDsLoaded (SInt32* instanceIDs, int size);
+
+
+ typedef Object* FactoryFunction (MemLabelId label, ObjectCreationMode mode);
+ struct RTTI
+ {
+ RTTI* base;// super rtti class
+ Object::FactoryFunction* factory;// the factory function of the class
+ int classID;// the class ID of the class
+ std::string className;// the name of the class
+ int size;// sizeof (Class)
+ bool isAbstract;// is the class Abstract?
+ };
+
+ /// Returns the RTTI information for a classID
+ static RTTI* ClassIDToRTTI (int classID);
+
+ MemLabelId GetMemoryLabel () const;
+
+ static void DoneLoadingManagers ();
+
+ static IDToPointerMap& GetIDToPointerMapInternal () { return *ms_IDToPointer; }
+
+ virtual int GetClassIDVirtualInternal () const { AssertString("Bad"); return ClassID(Object); }
+ void PreCleanupObject ();
+
+ // Generic Event callback support.
+ typedef void EventCallback (void* userData, void* sender, int eventType);
+
+ void AddEvent (EventCallback* callback, void* userData);
+ void RemoveEvent (EventCallback* callback, void* userData);
+ bool HasEvent (EventCallback* callback, const void* userData) const;
+ void InvokeEvent (int eventType);
+
+private:
+
+ static UInt32* ms_IsDerivedFromBitMap;
+ static unsigned ms_MaxClassID;
+ static IDToPointerMap* ms_IDToPointer;
+ static UInt32* ms_ClassIDMask;
+ static UInt32* ms_ClassIsDerivedFrom;
+
+ SInt32 m_InstanceID;
+
+ enum Bits
+ {
+ kMemLabelBits = 13,
+ kIsRootOwnerBits = 1,
+ kTemporaryFlagsBits = 1,
+ kHideFlagsBits = 4,
+ kIsPersistentBits = 1,
+ kCachedClassIDBits = 12
+ };
+
+
+ UInt32 m_MemLabel : kMemLabelBits; // 13 bits
+ UInt32 m_IsRootOwner : kIsRootOwnerBits; // 14 bits
+ UInt32 m_TemporaryFlags: kTemporaryFlagsBits; // 15 bits
+ UInt32 m_HideFlags : kHideFlagsBits; // 19 bits
+ UInt32 m_IsPersistent : kIsPersistentBits; // 20 bits
+ UInt32 m_CachedClassID : kCachedClassIDBits; // 32 bits
+
+ EventEntry* m_EventIndex;
+
+
+ #if !UNITY_RELEASE
+ UInt32 m_DEBUGCLASSID:16;
+ UInt32 m_AwakeCalled:1;
+ UInt32 m_ResetCalled:1;
+ UInt32 m_AwakeThreadedCalled:1;
+ UInt32 m_AwakeDidLoadThreadedCalled:1;
+ #endif
+
+ #if ENABLE_MONO
+ UInt32 m_MonoReference;
+ #elif UNITY_FLASH
+ SInt32 m_MonoReference;
+ #elif UNITY_WINRT
+ SInt32 m_MonoReference;
+ UInt32 m_TemporaryUnusedAssetsFlags;
+ #endif
+ #if ENABLE_SCRIPTING
+ ScriptingObjectPtr m_ScriptingObjectPointer;
+ #endif
+
+ #if UNITY_EDITOR
+ UInt32 m_DirtyIndex;
+ LocalIdentifierInFileType m_FileIDHint;
+ #endif
+
+ public:
+
+ #if ENABLE_SCRIPTING
+ void SetupWeakHandle ();
+ bool RevertWeakHandle ();
+
+ void SetCachedScriptingObject (ScriptingObjectPtr cachedPointer);
+ ScriptingObjectPtr GetCachedScriptingObject () { return m_ScriptingObjectPointer; }
+ #endif
+
+private:
+
+ static void CalculateCachedClassID (Object* obj);
+ static void InsertObjectInMap (Object* obj);
+
+ void SetIsPersistent (bool p);
+
+ Object (const Object& o); // Disallow copy constructor
+ Object& operator = (const Object& o); // Disallow assignment
+
+ void SetInstanceID (int inID) { m_InstanceID = inID; }
+
+ protected:
+
+ static void RegisterClass (int inClassID, int inBaseClass, const std::string& inName, int size, FactoryFunction* inFunc, bool isAbstract);
+
+ static Object* PRODUCE (MemLabelId /*label*/, ObjectCreationMode /*mode*/) { AssertString ("Can't produce abstract class"); return NULL; }
+
+ template<class TransferFunction>
+ void Transfer (TransferFunction& transfer);
+
+ public:
+
+ /// Returns whether or not the class needs one typetree per object, not per classID
+ /// Having a per object typetree makes serialization considerably slower because safeBinaryTransfer is always used
+ /// Since no TypeTree can be generated before reading the object.
+ /// The File size will also increase because the typetree is not shared among the same classes.
+ /// It is used for example in PythonBehaviour
+ /// Also for one class you have to always returns true or always false.
+ virtual bool GetNeedsPerObjectTypeTree () const { return false; }
+
+ // Sets up RTTI, the object factory (Produce) and string <-> classID
+ // conversion. RegisterClass() has to be called once for every class
+ // derived from object, before any Objects are allocated
+ static void RegisterClass ();
+
+ // Required by serialization
+ virtual void VirtualRedirectTransfer (StreamedBinaryWrite<false>&){ AssertString ("Serialization not implemented for type " + Object::ClassIDToString (GetClassID ())); }
+ virtual void VirtualRedirectTransfer (StreamedBinaryRead<false>&) { AssertString ("Serialization not implemented for type " + Object::ClassIDToString (GetClassID ())); }
+ virtual void VirtualRedirectTransfer (RemapPPtrTransfer&) { AssertString ("Serialization not implemented for type " + Object::ClassIDToString (GetClassID ())); }
+ virtual void VirtualRedirectTransfer (ProxyTransfer&) { AssertString ("Serialization not implemented for type " + Object::ClassIDToString (GetClassID ())); }
+#if SUPPORT_SERIALIZED_TYPETREES
+ virtual void VirtualRedirectTransfer (StreamedBinaryRead<true>&) { AssertString ("Serialization not implemented for type " + Object::ClassIDToString (GetClassID ())); }
+ virtual void VirtualRedirectTransfer (SafeBinaryRead&) { AssertString ("Serialization not implemented for type " + Object::ClassIDToString (GetClassID ())); }
+ virtual void VirtualRedirectTransfer (StreamedBinaryWrite<true>&){ AssertString ("Serialization not implemented for type " + Object::ClassIDToString (GetClassID ())); }
+#endif
+#if SUPPORT_TEXT_SERIALIZATION
+ virtual void VirtualRedirectTransfer (YAMLRead&) { AssertString ("Serialization not implemented for type " + Object::ClassIDToString (GetClassID ())); }
+ virtual void VirtualRedirectTransfer (YAMLWrite&) { AssertString ("Serialization not implemented for type " + Object::ClassIDToString (GetClassID ())); }
+ virtual void VirtualStrippedRedirectTransfer (YAMLWrite& t) { VirtualRedirectTransfer(t); }
+#endif
+#if ENABLE_SERIALIZATION_BY_CODEGENERATION
+ virtual void DoLivenessCheck (RemapPPtrTransfer&) { AssertString ("DoLivenessCheck not implemented for type " + Object::ClassIDToString (GetClassID ())); }
+#endif
+ static const char* GetClassStringStatic (){ return "Object"; }
+ static const char* GetPPtrTypeString (){ return "PPtr<Object>"; }
+
+ friend class PersistentManager;
+ friend class SerializedFile;
+};
+
+struct LocalSerializedObjectIdentifier
+{
+ SInt32 localSerializedFileIndex;
+ #if LOCAL_IDENTIFIER_IN_FILE_SIZE == 64
+ UInt64 localIdentifierInFile;
+ #else
+ SInt32 localIdentifierInFile;
+ #endif
+
+ LocalSerializedObjectIdentifier()
+ {
+ localIdentifierInFile = 0;
+ localSerializedFileIndex = 0;
+ }
+};
+
+typedef void InstanceIDResolveCallback (SInt32 id, LocalSerializedObjectIdentifier& localIdentifier, void* context);
+void SetInstanceIDResolveCallback (InstanceIDResolveCallback* callback, const void* context = NULL);
+
+void EXPORT_COREMODULE InstanceIDToLocalSerializedObjectIdentifier (SInt32 id, LocalSerializedObjectIdentifier& localIdentifier);
+void EXPORT_COREMODULE LocalSerializedObjectIdentifierToInstanceID (const LocalSerializedObjectIdentifier& fileID, SInt32& memoryID);
+EXPORT_COREMODULE Object* ReadObjectFromPersistentManager (int instanceID);
+
+#if THREADED_LOADING
+EXPORT_COREMODULE Object* InstanceIDToObjectThreadSafe (int instanceID);
+#else
+# define InstanceIDToObjectThreadSafe PPtr<Object>
+#endif
+
+// This is used by the build game process. When writing for game release
+// we want to null all pptrs that can't be loaded anymore.
+// And when building default resources (culls all external references)
+enum { kWriteNULLWhenNotLoaded = 1 << 0, kConstrainedExternalReferences = 1 << 1 };
+void SetSerializeWritePPtrFlags (int flags, const std::set<string>& paths);
+
+void EXPORT_COREMODULE SetDisableImmediateDestruction (bool disable);
+bool EXPORT_COREMODULE GetDisableImmediateDestruction ();
+
+
+/// Returns if the object can possibly be loaded or is already in memory, without actually performing the loading.
+bool IsObjectAvailable (int instanceID);
+
+//Implementation
+#if UNITY_RELEASE
+# if UNITY_PS3
+ __attribute__((always_inline)) inline Object* Object::IDToPointer (int inInstanceID)
+#else
+ inline Object* Object::IDToPointer (int inInstanceID)
+# endif
+{
+ if( !ms_IDToPointer ) return NULL;
+ IDToPointerMap::const_iterator i = ms_IDToPointer->find (inInstanceID);
+ if (i != ms_IDToPointer->end ())
+ return i->second;
+ else
+ return NULL;
+}
+#endif
+
+template<class T>
+inline void PPtr<T>::AssignObject (const Object* o)
+{
+ if (o == NULL)
+ m_InstanceID = 0;
+ else
+ m_InstanceID = o->GetInstanceID ();
+ #if !UNITY_RELEASE
+ m_DEBUGPtr = (T*) (o);
+ #endif
+}
+
+template<class T> inline
+PPtr<T>::operator T* () const
+{
+ if (GetInstanceID () == 0)
+ return NULL;
+
+ Object* temp = Object::IDToPointer (GetInstanceID ());
+ if (temp == NULL)
+ temp = ReadObjectFromPersistentManager (GetInstanceID ());
+
+ #if !UNITY_RELEASE
+ m_DEBUGPtr = (T*) (temp);
+ #endif
+
+ #if DEBUGMODE || UNITY_EDITOR
+ T* casted = dynamic_pptr_cast<T*> (temp);
+ if (casted == temp)
+ return casted;
+ else
+ {
+ ErrorStringObject ("PPtr cast failed when dereferencing! Casting from " + temp->GetClassName () + " to " + T::GetClassStringStatic () + "!", temp);
+ return casted;
+ }
+ #else
+ return static_cast<T*> (temp);
+ #endif
+}
+
+template<class T> inline
+T* PPtr<T>::operator -> () const
+{
+ Object* temp = Object::IDToPointer (GetInstanceID ());
+ if (temp == NULL)
+ temp = ReadObjectFromPersistentManager (GetInstanceID ());
+
+ #if !UNITY_RELEASE
+ m_DEBUGPtr = (T*) (temp);
+ #endif
+
+ #if DEBUGMODE || !GAMERELEASE
+ T* casted = dynamic_pptr_cast<T*> (temp);
+ if (casted != NULL)
+ return casted;
+ else
+ {
+ if (temp != NULL)
+ {
+ ErrorStringObject ("PPtr cast failed when dereferencing! Casting from " + temp->GetClassName () + " to " + T::GetClassStringStatic () + "!", temp);
+ }
+ else
+ {
+ ErrorString ("Dereferencing NULL PPtr!");
+ }
+ return casted;
+ }
+ #else
+ return static_cast<T*> (temp);
+ #endif
+}
+
+template<class T> inline
+T& PPtr<T>::operator * () const
+{
+ Object* temp = Object::IDToPointer (GetInstanceID ());
+ if (temp == NULL)
+ temp = ReadObjectFromPersistentManager (GetInstanceID ());
+
+ #if !UNITY_RELEASE
+ m_DEBUGPtr = (T*) (temp);
+ #endif
+
+ #if DEBUGMODE || !GAMERELEASE
+ T* casted = dynamic_pptr_cast<T*> (temp);
+ if (casted != NULL)
+ return *casted;
+ else
+ {
+ if (temp != NULL)
+ {
+ ErrorStringObject ("PPtr cast failed when dereferencing! Casting from " + temp->GetClassName () + " to " + T::GetClassStringStatic () + "!", temp);
+ }
+ else
+ {
+ ErrorString ("Dereferencing NULL PPtr!");
+ }
+ ANALYSIS_ASSUME(casted);
+ return *casted;
+ }
+ #else
+ return *static_cast<T*> (temp);
+ #endif
+}
+
+template<class T> inline
+bool PPtr<T>::IsNull() const
+{
+ T* casted = *this;
+ return casted == NULL;
+}
+
+template<class T> inline
+bool PPtr<T>::IsValid() const
+{
+ T* casted = *this;
+ return casted != NULL;
+}
+
+template<class T>
+string PPtr<T>::s_TypeString;
+
+template<class T> inline
+const char* PPtr<T>::GetTypeString ()
+{
+ return T::GetPPtrTypeString ();
+}
+
+template<class T>
+template<class TransferFunction> inline
+void PPtr<T>::Transfer (TransferFunction& transfer)
+{
+ LocalSerializedObjectIdentifier localIdentifier;
+
+ if (transfer.NeedsInstanceIDRemapping ())
+ {
+ AssertIf (!transfer.IsWriting () && !transfer.IsReading ());
+
+ if (transfer.IsReading ())
+ {
+ transfer.Transfer (localIdentifier.localSerializedFileIndex, "m_FileID", kHideInEditorMask);
+ transfer.Transfer (localIdentifier.localIdentifierInFile, "m_PathID", kHideInEditorMask);
+ LocalSerializedObjectIdentifierToInstanceID (localIdentifier, m_InstanceID);
+ }
+ else if (transfer.IsWriting ())
+ {
+ InstanceIDToLocalSerializedObjectIdentifier (m_InstanceID, localIdentifier);
+ transfer.Transfer (localIdentifier.localSerializedFileIndex, "m_FileID", kHideInEditorMask);
+ transfer.Transfer (localIdentifier.localIdentifierInFile, "m_PathID", kHideInEditorMask);
+ }
+ else
+ {
+ transfer.Transfer (localIdentifier.localSerializedFileIndex, "m_FileID", kHideInEditorMask);
+ transfer.Transfer (localIdentifier.localIdentifierInFile, "m_PathID", kHideInEditorMask);
+ }
+ }
+ else
+ {
+ transfer.Transfer (m_InstanceID, "m_FileID", kHideInEditorMask);
+ transfer.Transfer (localIdentifier.localIdentifierInFile, "m_PathID", kHideInEditorMask);
+ }
+}
+
+template<class T> inline
+bool ImmediatePtr<T>::IsLoaded () const
+{
+ if (m_Ptr & 1)
+ {
+ return Object::IDToPointer(m_Ptr & (~1)) != NULL;
+ }
+ else
+ {
+ AssertIf(Object::IDToPointer(GetInstanceID()) == NULL);
+ return true;
+ }
+}
+template<class T>
+string ImmediatePtr<T>::s_TypeString;
+
+template<class T> inline
+const char* ImmediatePtr<T>::GetTypeString ()
+{
+ if(s_TypeString.empty())
+ {
+ SET_ALLOC_OWNER(NULL);
+ s_TypeString = string ("PPtr<") + T::GetClassStringStatic () + ">";
+ }
+ return s_TypeString.c_str ();
+}
+
+template<class T>
+template<class TransferFunction> inline
+void ImmediatePtr<T>::Transfer (TransferFunction& transfer)
+{
+ LocalSerializedObjectIdentifier localIdentifier;
+
+ if (transfer.NeedsInstanceIDRemapping ())
+ {
+ AssertIf (!transfer.IsWriting () && !transfer.IsReading ());
+
+ if (transfer.IsReading ())
+ {
+ transfer.Transfer (localIdentifier.localSerializedFileIndex, "m_FileID", kHideInEditorMask);
+ transfer.Transfer (localIdentifier.localIdentifierInFile, "m_PathID", kHideInEditorMask);
+ SInt32 instanceID;
+ LocalSerializedObjectIdentifierToInstanceID (localIdentifier, instanceID);
+ AssignInstanceID (instanceID);
+ }
+ else if (transfer.IsWriting ())
+ {
+ InstanceIDToLocalSerializedObjectIdentifier (GetInstanceID (), localIdentifier);
+ transfer.Transfer (localIdentifier.localSerializedFileIndex, "m_FileID", kHideInEditorMask);
+ transfer.Transfer (localIdentifier.localIdentifierInFile, "m_PathID", kHideInEditorMask);
+ }
+ else
+ {
+ transfer.Transfer (localIdentifier.localSerializedFileIndex, "m_FileID", kHideInEditorMask);
+ transfer.Transfer (localIdentifier.localIdentifierInFile, "m_PathID", kHideInEditorMask);
+ }
+ }
+ else
+ {
+ if (transfer.IsReading ())
+ {
+ transfer.Transfer (localIdentifier.localSerializedFileIndex, "m_FileID", kHideInEditorMask);
+ transfer.Transfer (localIdentifier.localIdentifierInFile, "m_PathID", kHideInEditorMask);
+ SetInstanceID (localIdentifier.localSerializedFileIndex);
+ }
+ else if (transfer.IsWriting ())
+ {
+ localIdentifier.localSerializedFileIndex = GetInstanceID ();
+ localIdentifier.localIdentifierInFile = 0;
+ transfer.Transfer (localIdentifier.localSerializedFileIndex, "m_FileID", kHideInEditorMask);
+ transfer.Transfer (localIdentifier.localIdentifierInFile, "m_PathID", kHideInEditorMask);
+ AssertIf (localIdentifier.localSerializedFileIndex != GetInstanceID ());
+ }
+ else
+ {
+ transfer.Transfer (localIdentifier.localSerializedFileIndex, "m_FileID", kHideInEditorMask);
+ transfer.Transfer (localIdentifier.localIdentifierInFile, "m_PathID", kHideInEditorMask);
+ }
+ }
+}
+#if UNITY_PS3
+#define USE_NEW_IS_DERIVED_FROM 1
+#else
+#define USE_NEW_IS_DERIVED_FROM 0
+#endif
+
+#if !USE_NEW_IS_DERIVED_FROM
+#if UNITY_RELEASE
+inline bool Object::IsDerivedFromClassID (int classID, int compareClass)
+{
+ AssertIf (classID >= ms_MaxClassID || classID < 0);
+ AssertIf (compareClass >= ms_MaxClassID || compareClass < 0);
+ int index = classID * ms_MaxClassID + compareClass;
+ int block = index >> 5;
+ int bit = index - (block << 5);
+ return (ms_IsDerivedFromBitMap[block]) & (1 << bit);
+}
+#endif
+#else
+#define CLASS_ID_MASK_BITS 4
+#define CLASS_ID_MASK_IDS 0x0fffffff
+inline bool Object::IsDerivedFromClassID(int klass, int base)
+{
+ int klassId = ms_ClassIsDerivedFrom[klass];
+ int baseId = ms_ClassIsDerivedFrom[base];
+ int mask = ms_ClassIDMask[ 0xf&(baseId >> (32-CLASS_ID_MASK_BITS))];
+ return (klassId&mask) == (baseId&CLASS_ID_MASK_IDS);
+}
+#endif
+
+void LockObjectCreation ();
+void UnlockObjectCreation ();
+
+// Destroys a Object removing from memory and disk when needed.
+// Might load the object as part of destruction which is probably unwanted.
+// @TODO: Refactor code to not do that
+void EXPORT_COREMODULE DestroySingleObject (Object* o);
+void UnloadObject (Object* o);
+
+/// Destroys the object if it is loaded. (Will not load the object from disk if it is not loaded at the moment)
+/// Will remove it from any remapping tables
+/// Will not removed it from the actual serialized file, with the assumption that the file will be unloaded from disk later.
+void DestroyWithoutLoadingButDontDestroyFromFile (int instanceID);
+
+#if DEBUGMODE
+typedef std::set<int, std::less<int>, STL_ALLOCATOR(kMemPermanent,int) > VerifyRegisteredClass;
+void EXPORT_COREMODULE AddVerifyClassRegistration (int classID);
+typedef std::set<int, std::less<int>, STL_ALLOCATOR(kMemBaseObject, int) > RegisteredClassSet;
+const RegisteredClassSet& GetVerifyClassRegistration ();
+#endif
+
+/// Helper to create object correctly from code. Will call Reset and AwakeFromLoad
+template <typename T> T* CreateObjectFromCode( AwakeFromLoadMode awakeMode=kInstantiateOrCreateFromCodeAwakeFromLoad, MemLabelId label = kMemBaseObject )
+{
+ Assert(Object::ClassIDToRTTI(T::GetClassIDStatic()) != NULL);
+ T* obj = NEW_OBJECT_USING_MEMLABEL(T, label);
+ SET_ALLOC_OWNER(obj);
+ obj->Reset();
+ obj->AwakeFromLoad(awakeMode);
+ return obj;
+}
+
+template<typename T>
+inline T* ResetAndAwake (T* object)
+{
+ object->Reset();
+ object->AwakeFromLoad (kDefaultAwakeFromLoad);
+ return object;
+}
+
+void delete_object_internal (Object* p);
+void delete_object_internal_step1 (Object* object);
+void delete_object_internal_step2 (Object* object);
+
+#endif
diff --git a/Runtime/BaseClasses/BitField.h b/Runtime/BaseClasses/BitField.h
new file mode 100644
index 0000000..1ead092
--- /dev/null
+++ b/Runtime/BaseClasses/BitField.h
@@ -0,0 +1,26 @@
+#ifndef BITFIELD_H
+#define BITFIELD_H
+#include "Runtime/Serialize/SerializeUtility.h"
+
+struct BitField
+{
+ DECLARE_SERIALIZE_OPTIMIZE_TRANSFER (BitField)
+ UInt32 m_Bits;
+};
+
+enum { kPreUnity2UnusedLayerMask = 1 << 5 };
+
+template<class TransferFunc>
+void BitField::Transfer (TransferFunc& transfer)
+{
+ transfer.SetVersion (2);
+ transfer.Transfer (m_Bits, "m_Bits", kHideInEditorMask | kGenerateBitwiseDifferences);
+
+ if (transfer.IsOldVersion(1))
+ {
+ if (m_Bits & kPreUnity2UnusedLayerMask)
+ m_Bits |= 0xFFFF << 16;
+ }
+}
+
+#endif
diff --git a/Runtime/BaseClasses/ClassIDs.h b/Runtime/BaseClasses/ClassIDs.h
new file mode 100644
index 0000000..aa991e2
--- /dev/null
+++ b/Runtime/BaseClasses/ClassIDs.h
@@ -0,0 +1,240 @@
+#ifndef CLASSIDS_H_
+#define CLASSIDS_H_
+
+#define ClassID(x) CLASS_##x
+#define DefineClassID(x,classID) ClassID(x) = classID,
+
+// Runtime classIDs are kept intentionally small.
+enum ClassIDType
+{
+DefineClassID (Undefined, -1)
+DefineClassID (Object, 0)
+DefineClassID (GameObject, 1)
+DefineClassID (Component, 2)
+DefineClassID (LevelGameManager, 3)
+DefineClassID (Transform, 4)
+DefineClassID (TimeManager, 5)
+DefineClassID (GlobalGameManager, 6)
+DefineClassID (Behaviour, 8)
+DefineClassID (GameManager, 9)
+DefineClassID (AudioManager, 11)
+DefineClassID (ParticleAnimator, 12)
+DefineClassID (InputManager, 13)
+DefineClassID (EllipsoidParticleEmitter, 15)
+DefineClassID (Pipeline, 17)
+DefineClassID (EditorExtension, 18)
+DefineClassID (Physics2DSettings, 19)
+DefineClassID (Camera, 20)
+DefineClassID (Material, 21)
+DefineClassID (MeshRenderer, 23)
+DefineClassID (Renderer, 25)
+DefineClassID (ParticleRenderer, 26)
+DefineClassID (Texture, 27)
+DefineClassID (Texture2D, 28)
+DefineClassID (SceneSettings, 29)
+DefineClassID (GraphicsSettings, 30)
+DefineClassID (MeshFilter, 33)
+DefineClassID (OcclusionPortal, 41)
+DefineClassID (Mesh, 43)
+DefineClassID (Skybox, 45)
+DefineClassID (QualitySettings, 47)
+DefineClassID (Shader, 48)
+DefineClassID (TextAsset, 49)
+DefineClassID (Rigidbody2D, 50)
+DefineClassID (Physics2DManager, 51)
+DefineClassID (Collider2D, 53)
+DefineClassID (Rigidbody, 54)
+DefineClassID (PhysicsManager, 55)
+DefineClassID (Collider, 56)
+DefineClassID (Joint, 57)
+DefineClassID (CircleCollider2D, 58)
+DefineClassID (HingeJoint, 59)
+DefineClassID (PolygonCollider2D, 60)
+DefineClassID (BoxCollider2D, 61)
+DefineClassID (PhysicsMaterial2D, 62)
+DefineClassID (MeshCollider, 64)
+DefineClassID (BoxCollider, 65)
+DefineClassID (SpriteCollider2D, 66)
+DefineClassID (EdgeCollider2D, 68)
+DefineClassID (PolygonColliderBase2D, 69)
+DefineClassID (ComputeShader, 72)
+DefineClassID (AnimationClip, 74)
+DefineClassID (ConstantForce, 75)
+DefineClassID (WorldParticleCollider, 76)
+DefineClassID (TagManager, 78)
+DefineClassID (AudioListener, 81)
+DefineClassID (AudioSource, 82)
+DefineClassID (AudioClip, 83)
+DefineClassID (RenderTexture, 84)
+DefineClassID (MeshParticleEmitter, 87)
+DefineClassID (ParticleEmitter, 88)
+DefineClassID (Cubemap, 89)
+DefineClassID (Avatar, 90)
+DefineClassID (AnimatorController, 91)
+DefineClassID (GUILayer, 92)
+DefineClassID (RuntimeAnimatorController, 93)
+DefineClassID (ScriptMapper, 94)
+DefineClassID (Animator, 95)
+DefineClassID (TrailRenderer, 96)
+DefineClassID (DelayedCallManager, 98)
+DefineClassID (TextMesh, 102)
+DefineClassID (RenderSettings, 104)
+DefineClassID (Light, 108)
+DefineClassID (CGProgram, 109)
+DefineClassID (BaseAnimationTrack, 110)
+DefineClassID (Animation, 111)
+DefineClassID (MonoBehaviour, 114)
+DefineClassID (MonoScript, 115)
+DefineClassID (MonoManager, 116)
+DefineClassID (Texture3D, 117)
+DefineClassID (NewAnimationTrack, 118)
+DefineClassID (Projector, 119)
+DefineClassID (LineRenderer, 120)
+DefineClassID (Flare, 121)
+DefineClassID (Halo, 122)
+DefineClassID (LensFlare, 123)
+DefineClassID (FlareLayer, 124)
+DefineClassID (HaloLayer, 125)
+DefineClassID (NavMeshLayers, 126)
+DefineClassID (HaloManager, 127)
+DefineClassID (Font, 128)
+DefineClassID (PlayerSettings, 129)
+DefineClassID (NamedObject, 130)
+DefineClassID (GUITexture, 131)
+DefineClassID (GUIText, 132)
+DefineClassID (GUIElement, 133)
+DefineClassID (PhysicMaterial, 134)
+DefineClassID (SphereCollider, 135)
+DefineClassID (CapsuleCollider, 136)
+DefineClassID (SkinnedMeshRenderer, 137)
+DefineClassID (FixedJoint, 138)
+DefineClassID (RaycastCollider, 140)
+DefineClassID (BuildSettings, 141)
+DefineClassID (AssetBundle, 142)
+DefineClassID (CharacterController, 143)
+DefineClassID (CharacterJoint, 144)
+DefineClassID (SpringJoint, 145)
+DefineClassID (WheelCollider, 146)
+DefineClassID (ResourceManager, 147)
+DefineClassID (NetworkView, 148)
+DefineClassID (NetworkManager, 149)
+DefineClassID (PreloadData, 150)
+DefineClassID (MovieTexture, 152)
+DefineClassID (ConfigurableJoint, 153)
+DefineClassID (TerrainCollider, 154)
+DefineClassID (MasterServerInterface, 155)
+DefineClassID (TerrainData, 156)
+DefineClassID (LightmapSettings, 157)
+DefineClassID (WebCamTexture, 158)
+DefineClassID (EditorSettings, 159)
+DefineClassID (InteractiveCloth, 160)
+DefineClassID (ClothRenderer, 161)
+DefineClassID (EditorUserSettings, 162)
+DefineClassID (SkinnedCloth, 163)
+DefineClassID (AudioReverbFilter, 164)
+DefineClassID (AudioHighPassFilter, 165)
+DefineClassID (AudioChorusFilter, 166)
+DefineClassID (AudioReverbZone, 167)
+DefineClassID (AudioEchoFilter, 168)
+DefineClassID (AudioLowPassFilter, 169)
+DefineClassID (AudioDistortionFilter, 170)
+DefineClassID (AudioBehaviour, 180)
+DefineClassID (AudioFilter, 181)
+DefineClassID (WindZone, 182)
+DefineClassID (Cloth, 183)
+DefineClassID (SubstanceArchive, 184)
+DefineClassID (ProceduralMaterial, 185)
+DefineClassID (ProceduralTexture, 186)
+DefineClassID (OffMeshLink, 191)
+DefineClassID (OcclusionArea, 192)
+DefineClassID (Tree, 193)
+DefineClassID (NavMesh, 194)
+DefineClassID (NavMeshAgent, 195)
+DefineClassID (NavMeshSettings, 196)
+DefineClassID (LightProbes, 197)
+DefineClassID (ParticleSystem, 198)
+DefineClassID (ParticleSystemRenderer, 199)
+DefineClassID (LODGroup, 205)
+DefineClassID (BlendTree, 206)
+DefineClassID (Motion, 207)
+DefineClassID (NavMeshObstacle, 208)
+DefineClassID (TerrainInstance, 210)
+
+DefineClassID (SpriteRenderer, 212)
+DefineClassID (Sprite, 213)
+DefineClassID (CachedSpriteAtlas, 214)
+
+DefineClassID (LightProbeGroup, 220)
+DefineClassID (AnimatorOverrideController, 221)
+
+DefineClassID (Joint2D, 230)
+DefineClassID (SpringJoint2D, 231)
+DefineClassID (DistanceJoint2D, 232)
+DefineClassID (HingeJoint2D, 233)
+DefineClassID (SliderJoint2D, 234)
+// Reserved 235-238 for new joints.
+//DefineClassID (WheelJoint2D, 235)
+//DefineClassID (FrictionJoint2D, 236)
+//DefineClassID (PulleyJoint2D, 237)
+//DefineClassID (GearJoint2D, 238)
+
+kLargestRuntimeClassID,
+
+DefineClassID (SmallestEditorClassID, 1000)
+DefineClassID (Prefab, 1001)
+DefineClassID (EditorExtensionImpl, 1002)
+DefineClassID (AssetImporter, 1003)
+DefineClassID (AssetDatabase, 1004)
+DefineClassID (Mesh3DSImporter, 1005)
+DefineClassID (TextureImporter, 1006)
+DefineClassID (ShaderImporter, 1007)
+DefineClassID (ComputeShaderImporter, 1008)
+DefineClassID (AvatarMask, 1011)
+DefineClassID (AudioImporter, 1020)
+DefineClassID (HierarchyState, 1026)
+DefineClassID (GUIDSerializer, 1027)
+DefineClassID (AssetMetaData, 1028)
+DefineClassID (DefaultAsset, 1029)
+DefineClassID (DefaultImporter, 1030)
+DefineClassID (TextScriptImporter, 1031)
+DefineClassID (SceneAsset, 1032)
+DefineClassID (NativeFormatImporter, 1034)
+DefineClassID (MonoImporter, 1035)
+DefineClassID (AssetServerCache, 1037)
+DefineClassID (LibraryAssetImporter, 1038)
+DefineClassID (ModelImporter, 1040)
+DefineClassID (FBXImporter, 1041)
+DefineClassID (TrueTypeFontImporter, 1042)
+DefineClassID (MovieImporter, 1044)
+DefineClassID (EditorBuildSettings, 1045)
+DefineClassID (DDSImporter, 1046)
+DefineClassID (InspectorExpandedState, 1048)
+DefineClassID (AnnotationManager, 1049)
+DefineClassID (MonoAssemblyImporter, 1050)
+DefineClassID (EditorUserBuildSettings, 1051)
+DefineClassID (PVRImporter, 1052)
+DefineClassID (Transition, 1101)
+DefineClassID (State, 1102)
+DefineClassID (HumanTemplate, 1105)
+DefineClassID (StateMachine, 1107)
+DefineClassID (PreviewAssetType, 1108)
+DefineClassID (SubstanceImporter, 1112)
+
+kLargestEditorClassID,
+
+kClassIdOutOfHierarchy = 100000,
+
+DefineClassID (int, kClassIdOutOfHierarchy)
+DefineClassID (bool, kClassIdOutOfHierarchy + 1)
+DefineClassID (float, kClassIdOutOfHierarchy + 2)
+DefineClassID (MonoObject, kClassIdOutOfHierarchy + 3)
+DefineClassID (Collision, kClassIdOutOfHierarchy + 4)
+DefineClassID (Vector3f, kClassIdOutOfHierarchy + 5)
+DefineClassID (RootMotionData, kClassIdOutOfHierarchy + 6)
+DefineClassID (Collision2D, kClassIdOutOfHierarchy + 7)
+};
+
+//make sure people dont accidentally define classids in other files:
+#undef DefineClassID
+
+#endif
diff --git a/Runtime/BaseClasses/ClassRegistration.cpp b/Runtime/BaseClasses/ClassRegistration.cpp
new file mode 100644
index 0000000..80b44ec
--- /dev/null
+++ b/Runtime/BaseClasses/ClassRegistration.cpp
@@ -0,0 +1,267 @@
+#include "UnityPrefix.h"
+#include "ClassRegistration.h"
+#include "Runtime/BaseClasses/BaseObject.h"
+#include "Runtime/Modules/ModuleRegistration.h"
+
+// IPhone platform with stripping overwrites the "RegisterAllClasses" function.
+// See GenerateRegisterClassesForStripping in MonoInternalCallGenerator.cs.
+// This is why the iPhone builds overwrite the function name here.
+#if UNITY_IPHONE
+#define RegisterAllClasses RegisterAllClassesIPhone
+#endif
+
+using namespace std;
+#if DEBUGMODE
+static void VerifyThatAllClassesHaveBeenRegistered(const RegisteredClassSet& explicitlyRegistered);
+#endif
+
+#define RESERVE_CLASSID(klass,classID) ValidateRegisteredClassID (context,classID, #klass);
+#define RESERVE_DEPRECATED_CLASSID(klass,classID) ValidateRegisteredClassID (context,classID, #klass);
+
+void ValidateRegisteredClassID (ClassRegistrationContext& context, int classID, const char* className)
+{
+#if DEBUGMODE
+ RegisteredClassSet& explicitlyRegistered = *reinterpret_cast<RegisteredClassSet*> (context.explicitlyRegistered);
+ bool didNotExist = explicitlyRegistered.insert(classID).second;
+
+ if (!didNotExist) FatalErrorString(Format("ClassID %d conflicts with that of another class. Please resolve the conflict. (%s)", classID, className));
+#endif
+}
+
+
+#if DEBUGMODE
+void RegisterDeprecatedClassIDs (ClassRegistrationContext& context)
+{
+ /// DO NOT REMOVE CLASS IDS FROM THIS LIST TO MAKE ROOM FOR A NEW ONE. IT WILL RESULT IN CLASSID CONFLICTS ON OLD PROJECTS
+
+ RESERVE_DEPRECATED_CLASSID (BehaviourManager, 7) // Removed in Unity 3.2
+ RESERVE_DEPRECATED_CLASSID (Filter, 16) // Removed ages ago
+ RESERVE_DEPRECATED_CLASSID (PipelineManager, 31) // Removed in Unity 3.2
+ RESERVE_DEPRECATED_CLASSID (BaseBehaviourManager, 34) // Removed in Unity 3.2
+ RESERVE_DEPRECATED_CLASSID (LateBehaviourManager, 35) // Removed in Unity 3.2
+ RESERVE_DEPRECATED_CLASSID (FixedBehaviourManager, 46) // Removed in Unity 3.2
+ RESERVE_DEPRECATED_CLASSID (UpdateManager, 63) // Removed in Unity 3.2
+ RESERVE_DEPRECATED_CLASSID (RenderLayer, 67) // Intermediate abstract class refactored away post-Unity 3.2
+ RESERVE_DEPRECATED_CLASSID (AnimationTrack2, 112)
+ RESERVE_DEPRECATED_CLASSID (ResourceManagerOLD, 113)
+ RESERVE_DEPRECATED_CLASSID (GooballCollider, 77)
+ RESERVE_DEPRECATED_CLASSID (VertexSnapper, 79)
+ RESERVE_DEPRECATED_CLASSID (LightManager, 85) // -> changed id DO NOT REUSE
+ //RESERVE_DEPRECATED_CLASSID (PreloadManager, 90) // Now used by Avatar
+ //RESERVE_DEPRECATED_CLASSID (ScaleFilter, 91) // deprecated pre 1.0, now used by AnimatorController
+ //RESERVE_DEPRECATED_CLASSID (TextureRect, 93) // Now used by RuntimeAnimatorController
+ //RESERVE_DEPRECATED_CLASSID (MotorJoint, 95) // Now used by Animator
+ RESERVE_DEPRECATED_CLASSID (Decal, 97) // Pre 1.0
+ RESERVE_DEPRECATED_CLASSID (EulerRotationMotor, 139)
+ RESERVE_DEPRECATED_CLASSID (ParticleCloudColor, 103) // Pre 1.0
+ RESERVE_DEPRECATED_CLASSID (TextScript, 105)
+ RESERVE_DEPRECATED_CLASSID (VertexProgram, 106)
+ RESERVE_DEPRECATED_CLASSID (FragmentProgram, 107)
+ RESERVE_DEPRECATED_CLASSID (GooStickyness, 151)
+ RESERVE_DEPRECATED_CLASSID (ClothAnimator, 99) // PRE 1.0
+ RESERVE_DEPRECATED_CLASSID (PatchRenderer, 100) // PRE 1.0
+ RESERVE_DEPRECATED_CLASSID (Stretcher, 101) // PRE 1.0
+ RESERVE_DEPRECATED_CLASSID (AudioManager, 80) // -> changed id DO NOT REUSE
+ //RESERVE_DEPRECATED_CLASSID (AxisRenderer, 1008) // REMOVED in 2.0, now used by ComputeShaderImporter
+ RESERVE_DEPRECATED_CLASSID (BBoxRenderer, 1009) // REMOVED in 2.0
+ RESERVE_DEPRECATED_CLASSID (CopyTransform, 1010) // REMOVED in 2.1
+ //RESERVE_DEPRECATED_CLASSID (DotRenderer, 1011) // REMOVED in 2.0, now used by AvatarMask
+ RESERVE_DEPRECATED_CLASSID (SphereRenderer, 1012) // Not here anymore
+ RESERVE_DEPRECATED_CLASSID (WireRenderer, 1024) // Removed in 2.0
+ RESERVE_DEPRECATED_CLASSID (AnimationManager, 71) // Removed in 4.3
+}
+
+void RegisterReservedClassIDs (ClassRegistrationContext& context)
+{
+ RESERVE_CLASSID (PreviewAssetType, 1108);
+ RESERVE_CLASSID (GUITransform, 187)
+ RESERVE_CLASSID (GUIButton, 188)
+ RESERVE_CLASSID (GUIGroup, 189)
+ RESERVE_CLASSID (GUIComponent, 190)
+ RESERVE_CLASSID (GUICanvas, 219)
+ RESERVE_CLASSID (GUIToggle, 200)
+ RESERVE_CLASSID (GUIImage, 201)
+ RESERVE_CLASSID (GUILabel, 202)
+ RESERVE_CLASSID (GUISlider, 211)
+ RESERVE_CLASSID (GUITextField, 204)
+ RESERVE_CLASSID (GUIKeyboardControl, 210)
+ RESERVE_CLASSID (InWorldGUI, 209)
+ RESERVE_CLASSID (GUICamera, 217)
+ RESERVE_CLASSID (TextureAtlas, 203)
+}
+
+static void VerifyThatAllClassesHaveBeenRegistered(const RegisteredClassSet& explicitlyRegistered)
+{
+ const RegisteredClassSet& classes = GetVerifyClassRegistration ();
+
+ for (RegisteredClassSet::const_iterator i=classes.begin();i != classes.end();++i)
+ {
+ if (explicitlyRegistered.count (*i) == 0)
+ {
+ FatalErrorString(Format("ClassID %d has not been registered but is included in the build. You must add the class to RegisterAllClasses.", *i));
+ }
+ }
+
+ Assert(classes == explicitlyRegistered);
+}
+#endif
+
+void RegisterAllClasses()
+{
+ ClassRegistrationContext context;
+#if DEBUGMODE
+ RegisteredClassSet explicitlyRegistered;
+ context.explicitlyRegistered = &explicitlyRegistered;
+#endif
+
+ REGISTER_CLASS (GameObject)
+ REGISTER_CLASS (Component)
+ REGISTER_CLASS (LevelGameManager)
+ REGISTER_CLASS (Transform)
+ REGISTER_CLASS (TimeManager)
+ REGISTER_CLASS (GlobalGameManager)
+ REGISTER_CLASS (Behaviour)
+ REGISTER_CLASS (GameManager)
+ REGISTER_CLASS (ParticleAnimator)
+ REGISTER_CLASS (InputManager)
+ REGISTER_CLASS (EllipsoidParticleEmitter)
+ REGISTER_CLASS (Pipeline)
+ REGISTER_CLASS (EditorExtension)
+ REGISTER_CLASS (Camera)
+ REGISTER_CLASS (Material)
+ REGISTER_CLASS (Mesh)
+ REGISTER_CLASS (MeshRenderer)
+ REGISTER_CLASS (MeshFilter)
+ REGISTER_CLASS (Renderer)
+ REGISTER_CLASS (ParticleRenderer)
+ REGISTER_CLASS (Texture)
+ REGISTER_CLASS (Texture2D)
+ REGISTER_CLASS (SceneSettings)
+ REGISTER_CLASS (OcclusionPortal)
+ REGISTER_CLASS (Skybox)
+ REGISTER_CLASS (QualitySettings)
+ REGISTER_CLASS (Shader)
+ REGISTER_CLASS (TextAsset)
+ REGISTER_CLASS (ComputeShader)
+ REGISTER_CLASS (WorldParticleCollider)
+ REGISTER_CLASS (TagManager)
+ REGISTER_CLASS (RenderTexture)
+ REGISTER_CLASS (MeshParticleEmitter)
+ REGISTER_CLASS (ParticleEmitter)
+ REGISTER_CLASS (Cubemap)
+ REGISTER_CLASS (GUILayer)
+ REGISTER_CLASS (ScriptMapper)
+ REGISTER_CLASS (TrailRenderer)
+ REGISTER_CLASS (DelayedCallManager)
+ REGISTER_CLASS (TextMesh)
+ REGISTER_CLASS (Light)
+ REGISTER_CLASS (CGProgram)
+ REGISTER_CLASS (LightProbes)
+ REGISTER_CLASS (ResourceManager)
+ REGISTER_CLASS (Texture3D)
+ REGISTER_CLASS (Projector)
+ REGISTER_CLASS (LineRenderer)
+ REGISTER_CLASS (Flare)
+ REGISTER_CLASS (Halo)
+ REGISTER_CLASS (LensFlare)
+ REGISTER_CLASS (FlareLayer)
+ REGISTER_CLASS (HaloLayer)
+ REGISTER_CLASS (HaloManager)
+ REGISTER_CLASS (PreloadData)
+ REGISTER_CLASS (LightmapSettings)
+ REGISTER_CLASS (RenderSettings)
+ REGISTER_CLASS (NamedObject)
+ REGISTER_CLASS (GUIText)
+ REGISTER_CLASS (GUITexture)
+ REGISTER_CLASS (Font)
+ REGISTER_CLASS (GUIElement)
+ REGISTER_CLASS (SkinnedMeshRenderer)
+ REGISTER_CLASS (BuildSettings)
+ REGISTER_CLASS (AssetBundle)
+ REGISTER_CLASS (OcclusionArea)
+ REGISTER_CLASS (ParticleSystem)
+ REGISTER_CLASS (ParticleSystemRenderer)
+ REGISTER_CLASS (GraphicsSettings)
+ REGISTER_CLASS (PlayerSettings)
+ REGISTER_CLASS (SubstanceArchive)
+ REGISTER_CLASS (ProceduralMaterial)
+ REGISTER_CLASS (ProceduralTexture)
+ REGISTER_CLASS (LODGroup)
+ REGISTER_CLASS (LightProbeGroup)
+ REGISTER_CLASS (WindZone)
+
+#if ENABLE_SCRIPTING
+ REGISTER_CLASS (MonoScript)
+ REGISTER_CLASS (MonoManager)
+ REGISTER_CLASS (MonoBehaviour)
+#endif
+
+#if ENABLE_NETWORK
+ REGISTER_CLASS (NetworkView)
+ REGISTER_CLASS (NetworkManager)
+ REGISTER_CLASS (MasterServerInterface)
+#endif
+
+#if ENABLE_SPRITES
+ REGISTER_CLASS (SpriteRenderer)
+ REGISTER_CLASS (Sprite)
+ #if UNITY_EDITOR
+ REGISTER_CLASS (CachedSpriteAtlas)
+ #endif
+#endif
+
+ RegisterAllAvailableModuleClasses (context);
+
+ // Editor Only classes following:
+#if UNITY_EDITOR
+ REGISTER_CLASS (EditorSettings)
+ REGISTER_CLASS (EditorUserSettings)
+ REGISTER_CLASS (Prefab)
+ REGISTER_CLASS (EditorExtensionImpl)
+ REGISTER_CLASS (AssetImporter)
+ REGISTER_CLASS (AssetDatabase)
+ REGISTER_CLASS (Mesh3DSImporter)
+ REGISTER_CLASS (TextureImporter)
+ REGISTER_CLASS (ShaderImporter)
+ REGISTER_CLASS (ComputeShaderImporter)
+ REGISTER_CLASS (AudioImporter)
+ REGISTER_CLASS (GUIDSerializer)
+ REGISTER_CLASS (AssetMetaData)
+ REGISTER_CLASS (DefaultAsset)
+ REGISTER_CLASS (DefaultImporter)
+ REGISTER_CLASS (TextScriptImporter)
+ REGISTER_CLASS (SceneAsset)
+ REGISTER_CLASS (NativeFormatImporter)
+ REGISTER_CLASS (MonoImporter)
+ REGISTER_CLASS (MonoAssemblyImporter)
+ REGISTER_CLASS (AssetServerCache)
+ REGISTER_CLASS (LibraryAssetImporter)
+ REGISTER_CLASS (ModelImporter)
+ REGISTER_CLASS (FBXImporter)
+ REGISTER_CLASS (TrueTypeFontImporter)
+ REGISTER_CLASS (EditorBuildSettings)
+ REGISTER_CLASS (DDSImporter)
+ REGISTER_CLASS (InspectorExpandedState)
+ REGISTER_CLASS (AnnotationManager)
+ REGISTER_CLASS (EditorUserBuildSettings)
+ REGISTER_CLASS (PVRImporter)
+ REGISTER_CLASS (HierarchyState)
+ REGISTER_CLASS (Transition)
+ REGISTER_CLASS (State)
+ REGISTER_CLASS (HumanTemplate)
+ REGISTER_CLASS (StateMachine)
+ REGISTER_CLASS (AvatarMask)
+ REGISTER_CLASS (BlendTree)
+ REGISTER_CLASS (SubstanceImporter)
+
+#if !UNITY_LINUX
+ REGISTER_CLASS (MovieImporter)
+#endif
+#endif // UNITY_EDITOR
+
+#if DEBUGMODE
+ VerifyThatAllClassesHaveBeenRegistered(explicitlyRegistered);
+ RegisterDeprecatedClassIDs(context);
+ RegisterReservedClassIDs(context);
+#endif
+}
diff --git a/Runtime/BaseClasses/ClassRegistration.h b/Runtime/BaseClasses/ClassRegistration.h
new file mode 100644
index 0000000..cf016db
--- /dev/null
+++ b/Runtime/BaseClasses/ClassRegistration.h
@@ -0,0 +1,22 @@
+#pragma once
+#include "ClassIDs.h"
+
+struct ClassRegistrationContext
+{
+ void* explicitlyRegistered;
+};
+
+#if DEBUGMODE
+#define REGISTER_CLASS(x) \
+{ \
+ extern void RegisterClass_##x(); \
+ RegisterClass_##x(); \
+ ValidateRegisteredClassID(context, ClassID(x), #x); \
+}
+#else
+#define REGISTER_CLASS(x) \
+{ extern void RegisterClass_##x(); RegisterClass_##x(); }
+#endif
+
+
+EXPORT_COREMODULE void ValidateRegisteredClassID (ClassRegistrationContext& context, int classID, const char* className);
diff --git a/Runtime/BaseClasses/CleanupManager.cpp b/Runtime/BaseClasses/CleanupManager.cpp
new file mode 100644
index 0000000..7adb1e7
--- /dev/null
+++ b/Runtime/BaseClasses/CleanupManager.cpp
@@ -0,0 +1,65 @@
+#include "UnityPrefix.h"
+#if UNITY_EDITOR
+#include "CleanupManager.h"
+#include "Runtime/Misc/GameObjectUtility.h"
+#include "Runtime/Graphics/Transform.h"
+#include <algorithm>
+
+using namespace std;
+
+void CleanupManager::MarkForDeletion( PPtr<Unity::Component> comp, std::string const& reason )
+{
+ // Ignore component that is already marked for deletion
+ list<struct MarkedComponent>::iterator a = std::find(m_markedComponents.begin(), m_markedComponents.end(), static_cast<Unity::Component*>(comp));
+ if (a != m_markedComponents.end())
+ return;
+
+ struct MarkedComponent marker;
+ m_markedComponents.push_back (marker);
+ m_markedComponents.back ().component = comp;
+ m_markedComponents.back ().reason = reason;
+}
+
+void CleanupManager::Flush()
+{
+ while (m_markedComponents.size() > 0)
+ {
+ struct MarkedComponent& marked_component = m_markedComponents.front ();
+ PPtr<Unity::Component> comp = marked_component.component;
+
+ Unity::Component* compPtr = comp;
+ if (compPtr)
+ {
+ LogString(Format("%s component deleted: %s", comp->GetClassName ().c_str (), marked_component.reason.c_str()));
+ if (marked_component.component->GetGameObjectPtr () != NULL)
+ {
+ DestroyObjectHighLevel (comp);
+ }
+ else
+ {
+ // if the component is a transform remove the references
+ if (comp->GetClassID () == ClassID(Transform))
+ {
+ DestroyTransformComponentAndChildHierarchy(static_cast<Transform&>(*comp));
+ }
+
+ DestroySingleObject (comp);
+ }
+ }
+
+ m_markedComponents.pop_front ();
+ }
+}
+
+static CleanupManager* singleton = NULL;
+CleanupManager& GetCleanupManager ()
+{
+ if (singleton == NULL)
+ {
+ singleton = new CleanupManager();
+ }
+
+ return *singleton;
+}
+
+#endif \ No newline at end of file
diff --git a/Runtime/BaseClasses/CleanupManager.h b/Runtime/BaseClasses/CleanupManager.h
new file mode 100644
index 0000000..23c76c8
--- /dev/null
+++ b/Runtime/BaseClasses/CleanupManager.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#if UNITY_EDITOR
+
+#include "Runtime/BaseClasses/GameObject.h"
+
+#include <string>
+#include <list>
+
+class CleanupManager
+{
+private:
+ struct MarkedComponent {
+ PPtr<Unity::Component> component;
+ std::string reason;
+
+ bool operator==(PPtr<Unity::Component> const& comp)
+ {
+ return this->component == comp;
+ }
+ };
+
+public:
+ CleanupManager() {}
+
+ void MarkForDeletion(PPtr<Unity::Component> comp, std::string const& reason);
+ void Flush();
+
+ static void DidDestroyObjectNotification (Object* comp, void* userData);
+
+private:
+ std::list<struct MarkedComponent> m_markedComponents;
+};
+
+CleanupManager& GetCleanupManager ();
+
+#endif \ No newline at end of file
diff --git a/Runtime/BaseClasses/Cursor.cpp b/Runtime/BaseClasses/Cursor.cpp
new file mode 100644
index 0000000..3fb45ca
--- /dev/null
+++ b/Runtime/BaseClasses/Cursor.cpp
@@ -0,0 +1,152 @@
+#include "Cursor.h"
+
+#include "Runtime/GfxDevice/GfxDevice.h"
+#include "Runtime/Graphics/RenderTexture.h"
+#include "Runtime/Graphics/RenderBufferManager.h"
+#include "Runtime/Camera/ImageFilters.h"
+#include "Runtime/Graphics/ScreenManager.h"
+#include "Runtime/Graphics/Image.h"
+#include "Runtime/Camera/RenderManager.h"
+#include "Runtime/Camera/CameraUtil.h"
+#include "Runtime/Camera/RenderLayers/GUITexture.h"
+#include "Runtime/Input/InputManager.h"
+#include "Runtime/Misc/PlayerSettings.h"
+
+namespace Cursors
+{
+void RenderSoftwareCursor ()
+{
+ Texture2D* softCursor = GetSoftwareCursor();
+ if (softCursor && GetScreenManager().GetShowCursor())
+ {
+ DeviceMVPMatricesState preserveMVP;
+ SetupPixelCorrectCoordinates();
+
+ Vector2f pos = GetInputManager().GetMousePosition();
+ Vector2f hotSpotOffset = GetCursorHotspot();
+
+ pos.x -= hotSpotOffset.x;
+ pos.y += hotSpotOffset.y;
+
+ // the color is set to 0.5f because the gui-texture shader multiplies the vertex color by 2 for some reason
+ // pos is floored to match the behaviour of the hardware cursors
+ DrawGUITexture (Rectf ((int)pos.x, (int)pos.y, softCursor->GetGLWidth(), -softCursor->GetGLHeight()), softCursor, ColorRGBAf(0.5f, 0.5f, 0.5f, 0.5f));
+ }
+}
+
+#if !PLATFORM_SUPPORTS_HARDWARE_CURSORS
+
+
+typedef UnityCursor<int> SoftCursor;
+typedef CursorManager<SoftCursor> SoftCursorManager;
+
+template<> SoftCursorManager* SoftCursorManager::s_CursorManager = NULL;
+
+static SoftCursor GenerateCursor (Texture2D* texture, Vector2f hotSpot)
+{
+ // if this is null you are doing it wrong
+ assert(texture);
+
+ SoftCursor c;
+ c.sCursor = texture;
+ c.hotspot = hotSpot;
+ return c;
+}
+
+void SetCursor (Texture2D* texture, Vector2f hotSpot, CursorMode forceHardware)
+{
+ SoftCursorManager& manager = SoftCursorManager::Instance();
+ if (!texture)
+ {
+ manager.m_CurrentCursor = manager.m_DefaultCursor;
+ return;
+ }
+
+ // try and find the cursor in the cache
+ SoftCursorManager::CursorCache::iterator found = manager.m_CursorCache.find (texture->GetTextureID());
+ SoftCursor cursorToSet;
+ bool shouldGenerateCursor = true;
+ if (manager.m_CursorCache.end() != found)
+ {
+ // see if old hotspot
+ // is the same as the one requested now...
+ // if it's not then delete the old cursor and recreate it!
+ cursorToSet = found->second;
+
+ if (!CompareApproximately (hotSpot.x, cursorToSet.hotspot.x)
+ || !CompareApproximately (hotSpot.y, cursorToSet.hotspot.y))
+ {
+ manager.m_CursorCache.erase(found);
+ }
+ else
+ {
+ shouldGenerateCursor = false;
+ }
+ }
+
+ if (shouldGenerateCursor)
+ {
+ cursorToSet = GenerateCursor (texture, hotSpot);
+ manager.m_CursorCache[texture->GetTextureID()] = cursorToSet;
+ }
+
+ manager.m_CurrentCursor = cursorToSet;
+}
+
+Texture2D* GetSoftwareCursor()
+{
+ return SoftCursorManager::Instance().m_CurrentCursor.sCursor;
+}
+
+Vector2f GetCursorHotspot()
+{
+ return SoftCursorManager::Instance().m_CurrentCursor.hotspot;
+}
+
+void InitializeCursors(Texture2D* defaultCursorTexture, Vector2f defaultCursorHotSpot)
+{
+ SoftCursorManager& manager = SoftCursorManager::Instance ();
+ if (defaultCursorTexture)
+ {
+ manager.m_DefaultCursor = GenerateCursor (defaultCursorTexture, defaultCursorHotSpot);
+ manager.m_CurrentCursor = manager.m_DefaultCursor;
+ manager.m_UsingBuiltinDefaultCursor = true;
+ }
+}
+
+void CleanupCursors()
+{
+ SoftCursorManager::Instance().Cleanup ();
+}
+
+// needed for windows linkage with hardware cursors disabled
+#if UNITY_WIN
+void ResetCursor ()
+{}
+
+bool HandleMouseCursor (UINT message, LPARAM lParam)
+{
+ return false;
+}
+
+HCURSOR GetHardwareCursor ()
+{
+ return NULL;
+}
+#endif
+
+// needed for osx linkage with hardware cursors disabled
+#if UNITY_OSX
+void ResetCursor ()
+{}
+
+NSCursor* GetCurrentCursor ()
+{
+ return NULL;
+}
+#endif
+
+#endif //!PLATFORM_SUPPORTS_HARDWARE_CURSORS
+
+}; //namespace
+
diff --git a/Runtime/BaseClasses/Cursor.h b/Runtime/BaseClasses/Cursor.h
new file mode 100644
index 0000000..b0072fb
--- /dev/null
+++ b/Runtime/BaseClasses/Cursor.h
@@ -0,0 +1,105 @@
+#pragma once
+
+#include "UnityPrefix.h"
+#include "Runtime/Graphics/Texture2D.h"
+#include "Runtime/Math/Vector2.h"
+
+#include <string>
+
+#define PLATFORM_SUPPORTS_HARDWARE_CURSORS (!UNITY_PEPPER && ((UNITY_WIN && !UNITY_WINRT) || UNITY_OSX || UNITY_LINUX || UNITY_FLASH))
+
+enum CursorMode
+{
+ kAutoHardwareCursor = 0,
+ kHardwareCursorOff = 1
+};
+
+#if UNITY_OSX
+ #ifdef __OBJC__
+ @class NSCursor;
+ #else
+ typedef struct objc_object NSCursor;
+ #endif
+#endif
+
+namespace Cursors
+{
+
+template <typename T>
+struct UnityCursor
+{
+ UnityCursor ()
+ {
+ hCursor = NULL;
+ sCursor = NULL;
+ }
+ T hCursor;
+ PPtr<Texture2D> sCursor;
+ Vector2f hotspot;
+
+ typedef T HCursorType;
+};
+
+template <typename T>
+struct CursorManager
+{
+ T m_DefaultCursor;
+ T m_CurrentCursor;
+
+ bool m_UsingBuiltinDefaultCursor;
+
+ typedef std::map<TextureID, T > CursorCache;
+ CursorCache m_CursorCache;
+
+ Texture2D* GetSoftwareCursor ()
+ {
+ return m_CurrentCursor.sCursor;
+ }
+
+ Vector2f GetCursorHotspot ()
+ {
+ return m_CurrentCursor.hotspot;
+ }
+
+ typename T::HCursorType GetHardwareCursor ()
+ {
+ return m_CurrentCursor.hCursor;
+ }
+
+ static CursorManager<T>* s_CursorManager;
+ static CursorManager<T>& Instance ()
+ {
+ if (s_CursorManager == NULL)
+ {
+ s_CursorManager = new CursorManager<T>();
+ }
+
+ return *s_CursorManager;
+ }
+
+ static void Cleanup ()
+ {
+ delete s_CursorManager;
+ s_CursorManager = NULL;
+ }
+};
+
+void SetCursor (Texture2D* texture, Vector2f hotSpot, CursorMode forceHardware);
+void RenderSoftwareCursor ();
+Texture2D* GetSoftwareCursor ();
+Vector2f GetCursorHotspot ();
+void InitializeCursors (Texture2D* defaultCursorTexture, Vector2f defaultCursorHotSpot);
+void CleanupCursors ();
+
+#if UNITY_WIN
+void ResetCursor ();
+// returns true if the event is 'handled' WM_SETCURSOR in this case
+bool HandleMouseCursor (UINT message, LPARAM lParam);
+HCURSOR GetHardwareCursor ();
+#endif
+
+#if UNITY_OSX
+void ResetCursor ();
+NSCursor* GetHardwareCursor ();
+#endif
+};
diff --git a/Runtime/BaseClasses/EditorExtension.cpp b/Runtime/BaseClasses/EditorExtension.cpp
new file mode 100644
index 0000000..a55c92b
--- /dev/null
+++ b/Runtime/BaseClasses/EditorExtension.cpp
@@ -0,0 +1,95 @@
+#include "UnityPrefix.h"
+#include "EditorExtension.h"
+
+#if !GAMERELEASE
+
+#include "Editor/Src/EditorExtensionImpl.h"
+#include "Runtime/Serialize/TransferFunctions/SerializeTransfer.h"
+#include "Runtime/Serialize/TransferUtility.h"
+#include "Runtime/Serialize/SerializationMetaFlags.h"
+#include "Runtime/Utilities/dynamic_bitset.h"
+#include "Editor/Src/Prefabs/Prefab.h"
+#include "Editor/Src/Prefabs/PrefabBackwardsCompatibility.h"
+
+EditorExtension::EditorExtension (MemLabelId label, ObjectCreationMode mode)
+: Super(label, mode)
+{
+}
+
+EditorExtension::~EditorExtension ()
+{
+ Assert(m_DeprecatedExtensionPtr.GetInstanceID() == 0);
+}
+
+bool EditorExtension::IsPrefabParent () const
+{
+ Prefab* prefab = m_Prefab;
+ return prefab != NULL && prefab->IsPrefabParent();
+}
+
+template<class TransferFunction>
+void EditorExtension::Transfer (TransferFunction& transfer)
+{
+ Super::Transfer (transfer);
+ if (!transfer.IsSerializingForGameRelease ())
+ {
+ if (SerializePrefabIgnoreProperties(transfer))
+ {
+ transfer.Transfer (m_PrefabParentObject, "m_PrefabParentObject", kHideInEditorMask | kIgnoreWithInspectorUndoMask);
+ transfer.Transfer (m_Prefab, "m_PrefabInternal", kHideInEditorMask | kIgnoreWithInspectorUndoMask);
+ }
+
+ if (transfer.IsReadingBackwardsCompatible())
+ transfer.Transfer (m_DeprecatedExtensionPtr, "m_ExtensionPtr", kHideInEditorMask | kIgnoreWithInspectorUndoMask);
+ }
+}
+
+PPtr<EditorExtensionImpl> GetDeprecatedExtensionPtrIfExists (const Object& o)
+{
+ EditorExtension* extension = dynamic_pptr_cast<EditorExtension*> (&o);
+ if (extension)
+ return extension->m_DeprecatedExtensionPtr;
+ else
+ return NULL;
+}
+
+void EditorExtension::PatchPrefabBackwardsCompatibility ()
+{
+ if (m_DeprecatedExtensionPtr.IsValid ())
+ {
+ m_Prefab = m_DeprecatedExtensionPtr->m_DataTemplate;
+ if (m_DeprecatedExtensionPtr->m_TemplateFather.IsValid())
+ m_PrefabParentObject = m_DeprecatedExtensionPtr->m_TemplateFather;
+
+ if (m_Prefab.IsValid() && m_PrefabParentObject.IsValid() && m_DeprecatedExtensionPtr->m_Object == PPtr<EditorExtension> (this))
+ ReadOldPrefabFormat (*m_Prefab, *this, *m_PrefabParentObject, *m_DeprecatedExtensionPtr);
+
+ ///@TODO: DESTROY!!!
+ /// DestroyObject(m_DeprecatedExtensionPtr)
+ }
+ m_DeprecatedExtensionPtr = NULL;
+
+}
+
+
+void EditorExtension::AwakeFromLoad (AwakeFromLoadMode mode)
+{
+ Super::AwakeFromLoad(mode);
+ PatchPrefabBackwardsCompatibility ();
+}
+
+IMPLEMENT_OBJECT_SERIALIZE (EditorExtension)
+IMPLEMENT_CLASS (EditorExtension)
+INSTANTIATE_TEMPLATE_TRANSFER (EditorExtension)
+
+#else
+
+IMPLEMENT_CLASS (EditorExtension)
+
+EditorExtension::~EditorExtension ()
+{
+
+}
+
+#endif
+
diff --git a/Runtime/BaseClasses/EditorExtension.h b/Runtime/BaseClasses/EditorExtension.h
new file mode 100644
index 0000000..5e2830a
--- /dev/null
+++ b/Runtime/BaseClasses/EditorExtension.h
@@ -0,0 +1,58 @@
+#ifndef EDITOREXTENSION_H
+#define EDITOREXTENSION_H
+
+#include "BaseObject.h"
+class TypeTree;
+class Prefab;
+class EditorExtensionImpl;
+
+#if UNITY_EDITOR
+
+class EXPORT_COREMODULE EditorExtension : public Object
+{
+ public:
+
+ PPtr<EditorExtension> m_PrefabParentObject;
+ PPtr<Prefab> m_Prefab;
+
+ PPtr<EditorExtensionImpl> m_DeprecatedExtensionPtr;
+
+ REGISTER_DERIVED_ABSTRACT_CLASS (EditorExtension, Object)
+ DECLARE_OBJECT_SERIALIZE (EditorExtension)
+
+ EditorExtension (MemLabelId label, ObjectCreationMode mode);
+ // ~EditorExtension (); declared-by-macro
+
+ friend PPtr<EditorExtensionImpl> GetDeprecatedExtensionPtrIfExists (const Object& o);
+
+ virtual bool IsPrefabParent () const;
+
+ PPtr<Prefab> GetPrefab () { return m_Prefab; }
+ PPtr<EditorExtension> GetPrefabParentObject () { return m_PrefabParentObject; }
+
+ virtual void AwakeFromLoad (AwakeFromLoadMode mode);
+
+ void PatchPrefabBackwardsCompatibility ();
+
+
+ //std::string ExtractDeprecatedNameString ();
+};
+
+#else
+
+class EXPORT_COREMODULE EditorExtension : public Object
+{
+ public:
+
+ EditorExtension (MemLabelId label, ObjectCreationMode mode) : Super(label, mode) {}
+ // virtual ~EditorExtension (); declared-by-macro
+
+ REGISTER_DERIVED_CLASS (EditorExtension, Object)
+
+ virtual bool IsPrefabParent () const { return false; }
+};
+
+
+#endif
+
+#endif
diff --git a/Runtime/BaseClasses/EventIDs.h b/Runtime/BaseClasses/EventIDs.h
new file mode 100644
index 0000000..a37acdb
--- /dev/null
+++ b/Runtime/BaseClasses/EventIDs.h
@@ -0,0 +1,9 @@
+#pragma once
+
+enum EventIDs
+{
+ kBecameVisibleEvent,
+ kBecameInvisibleEvent,
+ kWillDestroyEvent,
+ kAnimatorClearEvent,
+}; \ No newline at end of file
diff --git a/Runtime/BaseClasses/EventManager.cpp b/Runtime/BaseClasses/EventManager.cpp
new file mode 100644
index 0000000..365faf0
--- /dev/null
+++ b/Runtime/BaseClasses/EventManager.cpp
@@ -0,0 +1,216 @@
+#include "UnityPrefix.h"
+#include "EventManager.h"
+#include "Runtime/Utilities/InitializeAndCleanup.h"
+
+////@TODO: Assert on recursive calls...
+
+EventManager* EventManager::s_Instance = NULL;
+
+EventManager& GetEventManager ()
+{
+ return *EventManager::s_Instance;
+}
+
+void EventManager::StaticInitialize()
+{
+ s_Instance = UNITY_NEW(EventManager,kMemManager);
+}
+
+void EventManager::StaticDestroy()
+{
+ UNITY_DELETE(s_Instance, kMemManager);
+}
+
+static RegisterRuntimeInitializeAndCleanup s_EventManagerCallbacks(EventManager::StaticInitialize, EventManager::StaticDestroy);
+
+EventManager::EventManager ()
+: m_EventPool (false, "EventManager", sizeof(EventEntry), 1024 * 4)
+#if DEBUGMODE
+, m_InvokingEventList(NULL)
+, m_InvokingEventActiveNode(NULL)
+#endif
+{
+}
+
+EventManager::EventIndex EventManager::AddEvent (EventCallback* callback, void* userData, EventIndex previousIndex)
+{
+ if (previousIndex == NULL)
+ {
+ EventIndex event = (EventIndex)m_EventPool.Allocate();
+ event->userData = userData;
+ event->callback = callback;
+ event->next = NULL;
+
+ return event;
+ }
+ else
+ {
+ EventIndex event = (EventIndex)m_EventPool.Allocate();
+ event->callback = callback;
+ event->userData = userData;
+ event->next = previousIndex;
+
+ return event;
+ }
+}
+
+/// Removes all events with the event index.
+void EventManager::RemoveEvent (EventIndex index)
+{
+ #if DEBUGMODE
+ // We can not delete the event which we are currently invoking
+ Assert (m_InvokingEventList != index);
+ #endif
+
+ while (index != NULL)
+ {
+ EventIndex next = index->next;
+ m_EventPool.Deallocate(index);
+ index = next;
+ }
+}
+
+bool EventManager::HasEvent (const EventIndex index, EventCallback* callback, const void* userData)
+{
+ EventIndex curIndex = index;
+ while (curIndex != NULL)
+ {
+ if (curIndex->callback == callback && curIndex->userData == userData)
+ return true;
+
+ curIndex = curIndex->next;
+ }
+ return false;
+}
+
+
+/// Removes an event with a specific callback & userData
+/// Returns the new event or null if no events in that index exist anymore.
+EventManager::EventIndex EventManager::RemoveEvent (EventIndex index, EventCallback* callback, void* userData)
+{
+ EventIndex previousIndex = NULL;
+ EventIndex curEvent = index;
+ while (curEvent != NULL)
+ {
+ if (curEvent->callback == callback && curEvent->userData == userData)
+ {
+ // While invoking we are allowed to remove the event being invoked itself but no other events on the same chain.
+ #if DEBUGMODE
+ Assert (m_InvokingEventList != index || m_InvokingEventActiveNode == curEvent);
+ #endif
+
+ EventIndex nextEvent = curEvent->next;
+ m_EventPool.Deallocate(curEvent);
+
+ if (previousIndex)
+ previousIndex->next = nextEvent;
+
+ if (index == curEvent)
+ return nextEvent;
+ else
+ return index;
+ }
+
+ previousIndex = curEvent;
+
+ curEvent = curEvent->next;
+ }
+
+ return index;
+}
+
+void EventManager::InvokeEvent (EventIndex index, void* senderUserData, int eventType)
+{
+ #if DEBUGMODE
+ GetEventManager().m_InvokingEventList = index;
+ #endif
+
+ while (index != NULL)
+ {
+ EventIndex next = index->next;
+
+ #if DEBUGMODE
+ GetEventManager().m_InvokingEventActiveNode = index;
+ #endif
+
+ index->callback(index->userData, senderUserData, eventType);
+ index = next;
+ }
+
+ #if DEBUGMODE
+ GetEventManager().m_InvokingEventList = NULL;
+ GetEventManager().m_InvokingEventActiveNode = NULL;
+ #endif
+}
+
+
+#if ENABLE_UNIT_TESTS
+
+#include "External/UnitTest++/src/UnitTest++.h"
+
+
+struct LoggingCounter
+{
+ int counter;
+};
+
+void LoggingCallback (void* userData, void* sender, int type)
+{
+ LoggingCounter* logging = (LoggingCounter*)userData;
+
+ logging->counter++;
+}
+
+SUITE (EventsManagerTest)
+{
+TEST (EventsManager_EventsSimple)
+{
+ EventManager manager;
+
+ LoggingCounter counter1;
+ counter1.counter = 0;
+
+ EventManager::EventIndex index = manager.AddEvent (LoggingCallback, &counter1, NULL);
+ manager.InvokeEvent(index, NULL, 0);
+ CHECK_EQUAL(1, counter1.counter);
+}
+
+// Test chaining (But not duplicating)
+TEST (EventsManager_EventsChaining)
+{
+ EventManager manager;
+
+ LoggingCounter counter1;
+ counter1.counter = 0;
+ LoggingCounter counter2;
+ counter2.counter = 0;
+ LoggingCounter counter3;
+ counter3.counter = 0;
+
+ EventManager::EventIndex index;
+
+ // Add chained event (add one duplicate which should not be added or invoked)
+ index = manager.AddEvent (LoggingCallback, &counter1, NULL);
+ index = manager.AddEvent (LoggingCallback, &counter2, index);
+ index = manager.AddEvent (LoggingCallback, &counter3, index);
+
+ manager.InvokeEvent(index, NULL, 0);
+ CHECK_EQUAL(1, counter1.counter);
+ CHECK_EQUAL(1, counter2.counter);
+ CHECK_EQUAL(1, counter3.counter);
+
+ // Remove 1 chained event
+ index = manager.RemoveEvent (index, LoggingCallback, &counter2);
+ counter1.counter = 0;
+ counter2.counter = 0;
+ counter3.counter = 0;
+
+ manager.InvokeEvent(index, NULL, 0);
+ CHECK_EQUAL(1, counter1.counter);
+ CHECK_EQUAL(0, counter2.counter);
+ CHECK_EQUAL(1, counter3.counter);
+}
+}
+
+#endif
+
diff --git a/Runtime/BaseClasses/EventManager.h b/Runtime/BaseClasses/EventManager.h
new file mode 100644
index 0000000..2f0b813
--- /dev/null
+++ b/Runtime/BaseClasses/EventManager.h
@@ -0,0 +1,59 @@
+#pragma once
+
+#include "Runtime/Utilities/MemoryPool.h"
+
+typedef void EventCallback (void* userData, void* sender, int eventType);
+
+
+// Small event entry. Keep this tight.
+struct EventEntry
+{
+ void* userData;
+ EventEntry* next;
+ EventCallback* callback;
+};
+
+class EventManager
+{
+public:
+ typedef EventEntry* EventIndex;
+
+private:
+ ////@TODO: Memory pool has a minimum size of 32 bytes. This one fits in 12. WTF???
+ MemoryPool m_EventPool;
+
+ static EventManager* s_Instance;
+ friend EventManager& GetEventManager ();
+
+ #if DEBUGMODE
+ EventIndex m_InvokingEventList;
+ EventIndex m_InvokingEventActiveNode;
+ #endif
+
+public:
+ EventManager ();
+
+ static void StaticInitialize ();
+ static void StaticDestroy ();
+
+ /// Adds an event
+ /// If there is already a previous event registered, it will chain them.
+ /// The reference to the event is the returned eventIndex
+ EventIndex AddEvent (EventCallback* callback, void* userData, EventIndex previousIndex);
+
+ /// Removes all events with the event index.
+ void RemoveEvent (EventIndex index);
+
+ /// Removes an event with a specific callback & userData
+ /// Returns the new event or null if no events in that index exist anymore.
+ /// AddEvent and RemoveEvent calls must be balanced.
+ EventIndex RemoveEvent (EventIndex index, EventCallback* callback, void* userData);
+
+ /// Does the event with that specific callback and userData exist?
+ static bool HasEvent (const EventIndex index, EventCallback* callback, const void* userData);
+
+ static void InvokeEvent (EventIndex index, void* sender, int eventType);
+};
+
+EventManager& GetEventManager ();
+
diff --git a/Runtime/BaseClasses/GameManager.cpp b/Runtime/BaseClasses/GameManager.cpp
new file mode 100644
index 0000000..0003b1f
--- /dev/null
+++ b/Runtime/BaseClasses/GameManager.cpp
@@ -0,0 +1,58 @@
+#include "UnityPrefix.h"
+#include "GameManager.h"
+#include "Runtime/Serialize/TransferFunctions/SerializeTransfer.h"
+#include "ManagerContext.h"
+
+GameManager::~GameManager ()
+{
+ for (int i=0;i<ManagerContext::kManagerCount;i++)
+ {
+ if (GetManagerContext().m_Managers[i] == this)
+ SetManagerPtrInContext(i, NULL);
+ }
+}
+
+LevelGameManager::~LevelGameManager () { }
+GlobalGameManager::~GlobalGameManager () { }
+
+template<class TransferFunction>
+void LevelGameManager::Transfer (TransferFunction& transfer)
+{
+ Super::Transfer (transfer);
+}
+
+template<class TransferFunction>
+void GlobalGameManager::Transfer (TransferFunction& transfer)
+{
+ Super::Transfer (transfer);
+}
+
+char const* GlobalGameManager::GetName () const
+{
+ return GetClassName ().c_str ();
+}
+
+GameManager* GetGameManagerIfExists (int index)
+{
+ GameManager* manager = static_cast<GameManager*> (GetManagerPtrFromContext(index));
+ Assert(manager == dynamic_pptr_cast<GameManager*> (GetManagerPtrFromContext(index)));
+ return manager;
+}
+
+LevelGameManager::LevelGameManager(MemLabelId label, ObjectCreationMode mode) : Super(label, mode)
+{ }
+
+GlobalGameManager::GlobalGameManager(MemLabelId label, ObjectCreationMode mode) : Super(label, mode)
+{ }
+
+
+
+IMPLEMENT_CLASS (LevelGameManager)
+IMPLEMENT_CLASS (GlobalGameManager)
+IMPLEMENT_CLASS (GameManager)
+
+IMPLEMENT_OBJECT_SERIALIZE (LevelGameManager)
+IMPLEMENT_OBJECT_SERIALIZE (GlobalGameManager)
+
+INSTANTIATE_TEMPLATE_TRANSFER_EXPORTED (LevelGameManager)
+INSTANTIATE_TEMPLATE_TRANSFER_EXPORTED (GlobalGameManager)
diff --git a/Runtime/BaseClasses/GameManager.h b/Runtime/BaseClasses/GameManager.h
new file mode 100644
index 0000000..8d194c3
--- /dev/null
+++ b/Runtime/BaseClasses/GameManager.h
@@ -0,0 +1,69 @@
+#ifndef GAMEMANAGER_H
+#define GAMEMANAGER_H
+
+#include "EditorExtension.h"
+
+/// Any game manager (eg. AudioManager, dynamicsmanager) that needs serialization
+/// has to derive from either LevelGameManager or GlobalGameManager.
+/// Every level contains its own GameManager for that Level (eg. Scene, PhysicsManager)
+/// LevelGameManagers are destroyed and reloaded from the new scene when loading a new scene.
+/// GlobalGameManagers are singletons and loaded on
+/// startup of the gameplayer/editor (eg. InputManager, TagManager)
+
+class EXPORT_COREMODULE GameManager : public Object
+{
+ public:
+
+ REGISTER_DERIVED_ABSTRACT_CLASS (GameManager, Object)
+ GameManager(MemLabelId label, ObjectCreationMode mode) : Super(label, mode) { }
+// virtual ~GameManager ();
+
+ ///@TODO: Get rid of this. I am not sure why this is not just done in the destructor / cleanup class
+ virtual void NetworkOnApplicationQuit () { AssertString("not implemented"); }
+ virtual void NetworkUpdate () { AssertString("not implemented"); }
+};
+
+
+class EXPORT_COREMODULE LevelGameManager : public GameManager
+{
+ public:
+
+ virtual char const* GetName () const { return GetClassName().c_str (); }
+
+ REGISTER_DERIVED_ABSTRACT_CLASS (LevelGameManager, GameManager)
+ DECLARE_OBJECT_SERIALIZE (GameManager)
+
+ LevelGameManager(MemLabelId label, ObjectCreationMode mode);
+
+// virtual ~LevelGameManager ();
+};
+
+
+class EXPORT_COREMODULE GlobalGameManager : public GameManager
+{
+ public:
+
+ REGISTER_DERIVED_ABSTRACT_CLASS (GlobalGameManager, GameManager)
+ DECLARE_OBJECT_SERIALIZE (GlobalGameManager)
+
+ GlobalGameManager(MemLabelId label, ObjectCreationMode mode);
+
+// virtual ~GlobalGameManager ();
+
+ virtual char const* GetName () const;
+};
+
+GameManager* GetGameManagerIfExists (int index);
+
+inline GameManager* CreateGameManager (int classID)
+{
+ Object* o = Object::Produce (classID);
+ o->Reset ();
+ o->AwakeFromLoad(kDefaultAwakeFromLoad);
+ o->SetNameCpp (Object::ClassIDToString (classID));
+ return static_cast<GameManager*> (o);
+}
+
+#define CALL_MANAGER_IF_EXISTS(x,func) { GameManager* _manager = GetGameManagerIfExists(x); if (_manager) _manager->func; }
+
+#endif
diff --git a/Runtime/BaseClasses/GameObject.cpp b/Runtime/BaseClasses/GameObject.cpp
new file mode 100644
index 0000000..833052a
--- /dev/null
+++ b/Runtime/BaseClasses/GameObject.cpp
@@ -0,0 +1,1189 @@
+#include "UnityPrefix.h"
+#include "GameObject.h"
+#include "CleanupManager.h"
+#include "Runtime/Serialize/AwakeFromLoadQueue.h"
+#include "Runtime/Serialize/TransferFunctions/SerializeTransfer.h"
+#include "Runtime/Serialize/SerializationMetaFlags.h"
+#include "Tags.h"
+#include "MessageHandler.h"
+#include "Runtime/Misc/ReproductionLog.h"
+#include "Runtime/Utilities/Utility.h"
+#include "Runtime/Misc/BuildSettings.h"
+#include "Runtime/Graphics/Texture2D.h"
+#include "Runtime/Graphics/Transform.h"
+#include "Runtime/Misc/GameObjectUtility.h"
+#include "Runtime/Misc/ComponentRequirement.h"
+#include "Runtime/Mono/MonoBehaviour.h"
+#include "Runtime/Containers/ConstantStringSerialization.h"
+#include "Runtime/Profiler/Profiler.h"
+#if UNITY_EDITOR
+#include "Editor/Src/BuildPipeline/BuildTargetPlatformSpecific.h"
+#include "Editor/Src/Utility/StaticEditorFlags.h"
+#endif
+#if UNITY_WII
+#include <rvlaux/clib.h>
+#endif
+
+using namespace std;
+
+namespace Unity
+{
+
+PROFILER_INFORMATION (gActivateGameObjectProfiler, "GameObject.Activate", kProfilerScripts)
+PROFILER_INFORMATION (gDeactivateGameObjectProfiler, "GameObject.Deactivate", kProfilerScripts)
+
+Unity::GameObject::DestroyGOCallbackFunction* Unity::GameObject::s_GameObjectDestroyedCallback = NULL;
+Unity::GameObject::SetGONameFunction* Unity::GameObject::s_SetGONameCallback = NULL;
+MessageForwarders* Unity::GameObject::s_RegisteredMessageForwarders = NULL;
+MessageHandler* Unity::GameObject::s_MessageHandler = NULL;
+
+GameObject::GameObject (MemLabelId label, ObjectCreationMode mode)
+ : Super(label, mode),
+// m_Component (GameObject::Container::allocator_type (*baseAllocator)),
+ m_ActiveGONode (this)
+{
+ m_SupportedMessages = 0;
+ m_IsDestroying = false;
+ m_IsActivating = false;
+ m_Tag = 0;
+ m_IsActive = false;
+ m_IsActiveCached = -1;
+
+ #if UNITY_EDITOR
+ m_IsOldVersion = false;
+ m_StaticEditorFlags = 0;
+ m_IsMarkedVisible = kSelfVisible;
+ #endif
+}
+
+void GameObject::Reset ()
+{
+ Super::Reset ();
+ m_Layer = kDefaultLayer;
+ m_Tag = 0;
+ #if UNITY_EDITOR
+ m_StaticEditorFlags = 0;
+ m_TagString = TagToString (m_Tag);
+ m_NavMeshLayer = 0;
+ #endif
+}
+
+GameObject::~GameObject ()
+{
+ Assert(!m_ActiveGONode.IsInList());
+}
+
+void GameObject::WillDestroyGameObject ()
+{
+ Assert(!m_IsDestroying);
+ m_IsDestroying = true;
+
+ // Find a component with the requested ID
+ Container::const_iterator i;
+ Container::const_iterator end = m_Component.end ();
+ for (i=m_Component.begin ();i != end; ++i)
+ {
+ Component& com = *i->second;
+ com.WillDestroyComponent();
+ }
+}
+
+void GameObject::AwakeFromLoad(AwakeFromLoadMode awakeMode)
+{
+ #if SUPPORT_LOG_ORDER_TRACE
+ if (IsActive() && RunningReproduction())
+ {
+ if (SUPPORT_LOG_ORDER_TRACE == 2)
+ {
+ LogString(Format("AwakeFromLoad %s (%s) [%d]", GetName(), GetClassName().c_str(), GetInstanceID()));
+ }
+ else
+ {
+ LogString(Format("AwakeFromLoad %s (%s)", GetName(), GetClassName().c_str()));
+ }
+ }
+ #endif
+
+ Super::AwakeFromLoad (awakeMode);
+ SetSupportedMessagesDirty ();
+ UpdateActiveGONode ();
+
+ if (s_SetGONameCallback)
+ s_SetGONameCallback(this);
+
+ #if UNITY_EDITOR
+ // When we are modifying the game object active state from the inspector
+ // We need to Activate / Deactivate the relevant components
+ // This never happens in the player.
+ if (awakeMode == kDefaultAwakeFromLoad)
+ ActivateAwakeRecursively();
+ #endif
+
+}
+
+int GameObject::CountDerivedComponents (int compareClassID)const
+{
+ int count = 0;
+ Container::const_iterator i;
+ for (i=m_Component.begin ();i != m_Component.end (); ++i)
+ count += Object::IsDerivedFromClassID (i->first, compareClassID);
+ return count;
+}
+
+
+Component* GameObject::FindConflictingComponentPtr (int classID) const
+{
+ const vector_set<int>& conflicts = FindConflictingComponents(classID);
+ if (conflicts.empty())
+ return NULL;
+
+ for (Container::const_iterator i = m_Component.begin(); i != m_Component.end(); ++i)
+ {
+ for (vector_set<int>::const_iterator c = conflicts.begin(); c != conflicts.end(); ++c)
+ {
+ if (Object::IsDerivedFromClassID(i->first, *c))
+ return i->second;
+ }
+ }
+
+ return NULL;
+}
+
+
+void GameObject::SetName (char const* name)
+{
+ m_Name.assign(name, GetMemoryLabel());
+ if (s_SetGONameCallback)
+ s_SetGONameCallback(this);
+ SetDirty ();
+}
+
+void GameObject::UpdateActiveGONode()
+{
+ m_ActiveGONode.RemoveFromList();
+ if (IsActive())
+ {
+ if (m_Tag != 0)
+ GetGameObjectManager().m_TaggedNodes.push_back(m_ActiveGONode);
+ else
+ GetGameObjectManager().m_ActiveNodes.push_back(m_ActiveGONode);
+ }
+}
+
+void GameObject::MarkActiveRecursively (bool state)
+{
+ Transform &transform = GetComponent (Transform);
+ for (Transform::iterator i=transform.begin ();i != transform.end ();i++)
+ (*i)->GetGameObject().MarkActiveRecursively (state);
+
+ m_IsActive = state;
+ SetDirty();
+}
+
+void GameObject::ActivateAwakeRecursivelyInternal (DeactivateOperation deactivateOperation, AwakeFromLoadQueue &queue)
+{
+ if (m_IsActivating)
+ {
+ ErrorStringObject("GameObject is already being activated or deactivated.", this);
+ return;
+ }
+ bool state;
+ bool changed;
+ m_IsActivating = true;
+ if (m_IsActiveCached != -1)
+ {
+ bool oldState = m_IsActiveCached;
+ m_IsActiveCached = -1;
+ state = IsActive();
+ changed = oldState != state;
+ }
+ else
+ {
+ state = IsActive();
+ changed = true;
+ }
+
+ Transform *transform = QueryComponent (Transform);
+ if (transform)
+ {
+ // use a loop by index rather than a iterator, as the children can adjust
+ // the child list during the Awake call, and invalidate the iterator
+ for (int i = 0; i < transform->GetChildrenCount(); i++)
+ transform->GetChild(i).GetGameObject().ActivateAwakeRecursivelyInternal (deactivateOperation, queue);
+ }
+
+ if (changed)
+ {
+ for (int i=0;i<m_Component.size ();i++)
+ {
+ Component& component = *m_Component[i].second;
+ if (state)
+ {
+ AssertIf (&*component.m_GameObject != this);
+ component.SetGameObjectInternal (this);
+ if (IS_CONTENT_NEWER_OR_SAME (kUnityVersion4_0_a1))
+ queue.Add(*m_Component[i].second);
+ else
+ component.AwakeFromLoad (kActivateAwakeFromLoad);
+ }
+ else
+ component.Deactivate (deactivateOperation);
+ }
+
+ if (state)
+ UpdateActiveGONode ();
+ else
+ m_ActiveGONode.RemoveFromList();
+ }
+ m_IsActivating = false;
+}
+
+void GameObject::ActivateAwakeRecursively (DeactivateOperation deactivateOperation)
+{
+ AwakeFromLoadQueue queue (kMemTempAlloc);
+ ActivateAwakeRecursivelyInternal (deactivateOperation, queue);
+ queue.AwakeFromLoad (kActivateAwakeFromLoad);
+}
+
+void GameObject::SetActiveRecursivelyDeprecated (bool state)
+{
+ if (IS_CONTENT_NEWER_OR_SAME (kUnityVersion3_5_a1))
+ {
+ if (IsPrefabParent ())
+ {
+ ErrorString(Format("Prefab GameObject's can not be made active! (%s)", GetName()));
+ return;
+ }
+
+ // First Mark all objects as active
+ MarkActiveRecursively (state);
+
+ // Then awake them.
+ ActivateAwakeRecursively ();
+ }
+ else
+ {
+ // Old versions used to mark active and awake each object after another.
+ // That would cause problems with colliders being created twice, once without the active
+ // parent rigibdodies, and once with, thus causing the unnecessary creation and destruction
+ // of static colliders (slow). So we fixed it (see above), but we keep the old behaviour for
+ // legacy content.
+ Transform &transform = GetComponent (Transform);
+ for (Transform::iterator i=transform.begin ();i != transform.end ();i++)
+ (*i)->GetGameObject().SetActiveRecursivelyDeprecated (state);
+
+ if (state)
+ Activate();
+ else
+ Deactivate();
+ }
+}
+
+void GameObject::AddComponentInternal (Component* com)
+{
+ AssertIf (com == NULL);
+ {
+ m_Component.push_back (std::make_pair (com->GetClassID (), ImmediatePtr<Component> (com)));
+ }
+ // Make sure it isn't already added to another GO
+ Assert ( com->m_GameObject.GetInstanceID() == 0 || com->GetGameObjectPtr() == this );
+
+ com->SetHideFlags(GetHideFlags());
+ com->m_GameObject = this;
+
+ if (IsActive ())
+ com->AwakeFromLoad (kActivateAwakeFromLoad);
+ else
+ com->AwakeFromLoad (kDefaultAwakeFromLoad);
+
+ com->SetDirty ();
+ SetDirty ();
+
+ SendMessage(kDidAddComponent, com, ClassID (Component));
+
+ SetSupportedMessagesDirty ();
+}
+
+Component* GameObject::QueryComponentExactTypeImplementation (int classID) const
+{
+ // Find a component with the requested ID
+ Container::const_iterator i;
+ Container::const_iterator end = m_Component.end ();
+ for (i=m_Component.begin ();i != end; ++i)
+ {
+ if (i->first == classID)
+ return i->second;
+ }
+
+ return NULL;
+}
+
+
+Component* GameObject::QueryComponentImplementation (int classID) const
+{
+ // Find a component with the requested ID
+ Container::const_iterator i;
+ Container::const_iterator end = m_Component.end ();
+ for (i=m_Component.begin ();i != end; ++i)
+ {
+ if (Object::IsDerivedFromClassID (i->first, classID))
+ return i->second;
+ }
+
+ return NULL;
+}
+
+void GameObject::RemoveComponentAtIndex (int index)
+{
+ Container::iterator i = m_Component.begin () + index;
+
+ Component* com = i->second;
+ AssertIf (com == NULL);
+
+ m_Component.erase (i);
+ com->m_GameObject = NULL;
+
+ com->SetDirty ();
+ SetDirty ();
+ SetSupportedMessagesDirty ();
+}
+
+void GameObject::SetComponentAtIndexInternal (PPtr<Component> component, int index)
+{
+ m_Component[index].first = component->GetClassID();
+ m_Component[index].second.SetInstanceID(component.GetInstanceID());
+}
+
+
+void GameObject::SetSupportedMessagesDirty ()
+{
+ Assert(!IsDestroying());
+
+ int oldSupportedMessage = m_SupportedMessages;
+ m_SupportedMessages = 0;
+ if (IsDestroying ())
+ return;
+
+ GetSupportedMessagesRecalculate ();
+ if (oldSupportedMessage != m_SupportedMessages)
+ {
+ for (Container::iterator i=m_Component.begin ();i != m_Component.end (); ++i)
+ if (i->second)
+ i->second->SupportedMessagesDidChange (m_SupportedMessages);
+ }
+}
+
+void GameObject::GetSupportedMessagesRecalculate ()
+{
+ Assert(!IsDestroying());
+
+ m_SupportedMessages = 0;
+ for (Container::iterator i=m_Component.begin ();i != m_Component.end (); ++i)
+ if (i->second)
+ m_SupportedMessages |= i->second->CalculateSupportedMessages ();
+}
+
+Component* GameObject::GetComponentPtrAtIndex (int i)const
+{
+ return m_Component[i].second;
+}
+
+int GameObject::GetComponentIndex (Component *component)
+{
+ Assert(!IsDestroying());
+
+ for (int i = 0; i < GetComponentCount (); i++)
+ {
+ if (&GetComponentAtIndex (i) == component)
+ return i;
+ }
+
+ return -1;
+}
+
+
+void GameObject::SwapComponents (int index1, int index2)
+{
+ AssertIf (index1 > m_Component.size() || index1 < 0);
+ AssertIf (index2 > m_Component.size() || index2 < 0);
+
+ ComponentPair tmp = m_Component[index1];
+ m_Component[index1] = m_Component[index2];
+ m_Component[index2] = tmp;
+
+ Component* comp1 = m_Component[index1].second;
+ Component* comp2 = m_Component[index2].second;
+ if (comp1 && comp1->IsDerivedFrom(ClassID(Behaviour)))
+ {
+ Behaviour* beh = static_cast<Behaviour*>(comp1);
+ if (beh->GetEnabled())
+ {
+ beh->SetEnabled (false);
+ beh->SetEnabled (true);
+ }
+ }
+ if (comp2 && comp2->IsDerivedFrom(ClassID(Behaviour)))
+ {
+ Behaviour* beh = static_cast<Behaviour*>(comp2);
+ if (beh->GetEnabled())
+ {
+ beh->SetEnabled (false);
+ beh->SetEnabled (true);
+ }
+ }
+ SetDirty();
+}
+
+bool GameObject::IsActive () const
+{
+ if (m_IsActiveCached != -1)
+ return m_IsActiveCached;
+
+ // For pre 4.0 content activate state is the same as m_IsActive.
+ if (!IS_CONTENT_NEWER_OR_SAME (kUnityVersion4_0_a1))
+ m_IsActiveCached = m_IsActive;
+ else
+ {
+ // Calculate active state based on the hierarchy
+ m_IsActiveCached = m_IsActive && !(IsPersistent() || IsPrefabParent());
+ Transform *trs = QueryComponent (Transform);
+ if (trs)
+ {
+ Transform *parent = GetComponent (Transform).GetParent();
+ if (parent)
+ m_IsActiveCached = m_IsActiveCached && parent->GetGameObject().IsActive();
+ }
+ }
+
+ return m_IsActiveCached;
+}
+
+bool GameObject::IsActiveIgnoreImplicitPrefab ()
+{
+ // This function does not make sense to be called for old content.
+ Assert (IS_CONTENT_NEWER_OR_SAME (kUnityVersion4_0_a1));
+
+ Transform *trs = QueryComponent (Transform);
+ if (trs)
+ {
+ Transform *parent = GetComponent (Transform).GetParent();
+ if (parent)
+ return m_IsActive && parent->GetGameObject().IsActiveIgnoreImplicitPrefab();
+ }
+
+ return m_IsActive;
+}
+
+void GameObject::Activate ()
+{
+ if (IsActive())
+ return;
+
+ PROFILER_AUTO(gActivateGameObjectProfiler, this);
+
+ SetDirty ();
+
+ if (IS_CONTENT_NEWER_OR_SAME (kUnityVersion4_0_a1))
+ {
+ m_IsActive = true;
+ ActivateAwakeRecursively ();
+ // After AwakeFromLoad, 'this' could have been destroyed (if user is Destroying in OnEnable or Awake)
+ // So do not access it any further
+ }
+ else
+ {
+ if (IsPrefabParent ())
+ {
+ ErrorString(Format("Prefab GameObject's can not be made active! (%s)", GetName()));
+ return;
+ }
+
+ if (IS_CONTENT_NEWER_OR_SAME(kUnityVersion3_3_a1) && IsPersistent ())
+ {
+ ErrorString(Format("GameObjects stored in assets can not be made active! (%s)", GetName()));
+ return;
+ }
+
+ m_IsActive = true;
+ m_IsActiveCached = m_IsActive;
+ for (int i=0;i<m_Component.size ();i++)
+ {
+ Component& component = *m_Component[i].second;
+ AssertIf (&*component.m_GameObject != this);
+ component.m_GameObject = this;
+ component.AwakeFromLoad (kActivateAwakeFromLoad);
+ }
+
+ UpdateActiveGONode ();
+ }
+
+}
+
+void GameObject::Deactivate (DeactivateOperation operation)
+{
+ PROFILER_AUTO(gDeactivateGameObjectProfiler, this)
+
+ if (!IsActive())
+ {
+ if (m_IsActive)
+ {
+ m_IsActive = false;
+ SetDirty ();
+ }
+ return;
+ }
+
+ m_IsActive = false;
+
+ if (IS_CONTENT_NEWER_OR_SAME (kUnityVersion4_0_a1))
+ ActivateAwakeRecursively (operation);
+ else
+ {
+ m_IsActiveCached = m_IsActive;
+ for (int i=0;i<m_Component.size ();i++)
+ {
+ Component& com = *m_Component[i].second;
+ com.Deactivate (operation);
+ }
+
+ m_ActiveGONode.RemoveFromList();
+ }
+
+ SetDirty ();
+}
+
+void GameObject::SetSelfActive (bool state)
+{
+ if (state)
+ Activate();
+ else
+ Deactivate(kNormalDeactivate);
+}
+
+void GameObject::AddComponentInternal (GameObject& gameObject, Component& clone)
+{
+ SET_ALLOC_OWNER(&gameObject);
+ Assert(clone.m_GameObject == NULL);
+ gameObject.m_Component.push_back(make_pair(clone.GetClassID(), &clone));
+ clone.m_GameObject = &gameObject;
+}
+
+void GameObject::RemoveComponentFromGameObjectInternal (Component& clone)
+{
+ GameObject* go = clone.GetGameObjectPtr();
+ if (go == NULL)
+ return;
+
+ int index = go->GetComponentIndex(&clone);
+ if (index == -1)
+ return;
+
+ go->m_Component.erase(go->m_Component.begin() + index);
+ clone.m_GameObject = NULL;
+}
+
+void GameObject::CheckConsistency ()
+{
+ Super::CheckConsistency ();
+
+
+ // Remove Components from m_Component if they vanished without deactivating.
+ // (eg. class hierarchy changed and the class doesn't exist anymore when loading from disk)
+ int i = 0;
+ while (i < m_Component.size ())
+ {
+ // Use is object available instead of normal comparison so that we dont load the object
+ // which might already trigger the component to query for other components.
+ int CurComponentInstanceID = m_Component[i].second.GetInstanceID ();
+ if (!IsObjectAvailable (CurComponentInstanceID))
+ {
+ ErrorStringObject (Format("Component %s could not be loaded when loading game object. Cleaning up!", ClassIDToString(m_Component[i].first).c_str()), this);
+ m_Component.erase (m_Component.begin () + i);
+ }
+ else
+ i++;
+ }
+
+ // Preload all the components!
+ // This is necessary to avoid recursion and awake functions calling remove component,
+ // When we are removing the wrong ones anyway.
+ i = 0;
+ while (i < m_Component.size ())
+ {
+ Component* com = m_Component[i].second;
+ UNUSED(com);
+ i++;
+ }
+
+ // Remove Components with wrong gameobject ptrs
+ i = 0;
+ while (i < m_Component.size ())
+ {
+ Component* com = m_Component[i].second;
+ if (com && com->GetGameObjectPtr () == this)
+ {
+ i++;
+ continue;
+ }
+
+ if (com)
+ {
+ if (com->GetGameObjectPtr () == NULL)
+ {
+ com->SetGameObjectInternal (this);
+ ErrorStringObject ("Component (" + com->GetClassName () + ") has a broken GameObject reference. Fixing!", this);
+ continue;
+ }
+ else
+ {
+ ErrorStringObject ("Failed to load component (" + com->GetClassName () + ")! Removing it!", this);
+ com->SetHideFlags(kHideAndDontSave);
+ }
+ }
+ else
+ {
+ ErrorStringObject ("Failed to load component (" + Object::ClassIDToString (m_Component[i].first) + ")! Removing it!", this);
+ }
+
+ m_Component.erase (m_Component.begin () + i);
+ }
+
+ // make sure we always have at least one transform on a gameobject
+ int transformCount = 0;
+ for (int i = 0; i < m_Component.size (); ++i)
+ {
+ if(m_Component[i].first == ClassID (Transform))
+ transformCount++;
+
+ if (transformCount > 1)
+ {
+ // More than one transform on object. If it's a scene object (transient),
+ // remove the extraneous transform. For prefabs (persistent), touching the
+ // transform hierarchy will lead to all kinds of troubles so we just leave
+ // it be.
+ if (!IsPersistent ())
+ {
+ Transform* com = static_cast<Transform*> (&*m_Component[i].second);
+ com->SetParent (NULL);
+
+ RemoveComponentAtIndex (i);
+ --i;
+
+ GameObject* dummyObject = CreateObjectFromCode<GameObject> ();
+ dummyObject->SetName ("!! ORPHAN TRANSFORM !!");
+ dummyObject->AddComponentInternal (com);
+
+ ErrorStringObject ("Object has multiple transform components. Created dummy GameObject and added transform to it!", this);
+ }
+ else
+ {
+ ErrorStringObject ("Object has multiple transform components!", this);
+ }
+ }
+ }
+ if(transformCount == 0)
+ {
+ ErrorStringObject (Format("Transform component could not be found on game object. Adding one!"), this);
+ AddComponentUnchecked(*this,ClassID(Transform), NULL, NULL);
+ }
+
+#if UNITY_EDITOR
+ if (m_IsOldVersion && m_IsActive && !IsPersistent() && !IsActiveIgnoreImplicitPrefab())
+ WarningStringObject ("GameObject is active but a parent is inactive. Active state is now inherited. Change the parenting to get back the old behaviour!", this);
+#endif
+
+ SetSupportedMessagesDirty ();
+}
+
+void GameObject::SetLayer (int layer)
+{
+ if (layer >= 0 && layer < 32)
+ {
+ m_Layer = layer;
+ MessageData data;
+ SendMessageAny (kLayerChanged, data);
+ SetDirty ();
+ }
+ else
+ ErrorString ("A game object can only be in one layer. The layer needs to be in the range [0...31]");
+}
+
+void GameObject::SetTag (UInt32 tag)
+{
+ #if UNITY_EDITOR
+ m_TagString = TagToString (tag);
+ #endif
+
+ m_Tag = tag;
+ UpdateActiveGONode();
+
+ AssertIf (tag != -1 && tag != m_Tag);
+ AssertIf (tag == -1 && m_Tag != 0xFFFF);
+ MessageData data;
+ SendMessageAny (kLayerChanged, data);
+ SetDirty ();
+}
+
+void GameObject::SetHideFlags (int flags)
+{
+ SetHideFlagsObjectOnly(flags);
+ for (int i=0;i<m_Component.size ();i++)
+ {
+ Component& com = *m_Component[i].second;
+ com.SetHideFlags(flags);
+ }
+}
+
+template<class TransferFunction>
+void GameObject::TransferComponents (TransferFunction& transfer)
+{
+ Container* components_to_serialize = &m_Component;
+
+ // When cloning objects for prefabs and instantiate, we don't use serialization to duplicate the hierarchy,
+ // we duplicate the hierarchy directly
+ if (!SerializePrefabIgnoreProperties(transfer))
+ return;
+
+#if UNITY_EDITOR
+ Container filtered_components;
+ if (transfer.IsWritingGameReleaseData ())
+ {
+ components_to_serialize = &filtered_components;
+ for (Container::iterator i = m_Component.begin(); i != m_Component.end(); i++)
+ {
+ if (IsClassSupportedOnBuildTarget(i->first, transfer.GetBuildingTarget().platform))
+ filtered_components.push_back (*i);
+ }
+ }
+#endif
+
+ transfer.Transfer (*components_to_serialize, "m_Component", kHideInEditorMask | kStrongPPtrMask | kIgnoreWithInspectorUndoMask);
+}
+
+
+
+
+
+template<class TransferFunction>
+void GameObject::Transfer (TransferFunction& transfer)
+{
+ Super::Transfer (transfer);
+ transfer.SetVersion (4);
+ TransferComponents(transfer);
+
+ TRANSFER (m_Layer);
+
+ #if GAMERELEASE
+ TransferConstantString(m_Name, "m_Name", kNoTransferFlags, GetMemoryLabel(), transfer);
+ TRANSFER (m_Tag);
+ transfer.Transfer (m_IsActive, "m_IsActive");
+ #else
+
+ #if UNITY_EDITOR
+ if (transfer.IsVersionSmallerOrEqual (3))
+ m_IsOldVersion = true;
+ #endif
+
+ if (transfer.IsOldVersion (3) || transfer.IsCurrentVersion ())
+ {
+ TransferConstantString(m_Name, "m_Name", kNoTransferFlags, GetMemoryLabel(), transfer);
+
+ if (transfer.IsSerializingForGameRelease ())
+ {
+ TRANSFER (m_Tag);
+ if (transfer.IsReading ())
+ m_TagString = TagToString (m_Tag);
+
+ transfer.Transfer (m_IsActive, "m_IsActive");
+ }
+ else
+ {
+ transfer.Transfer (m_TagString, "m_TagString");
+ if (transfer.IsReading ())
+ m_Tag = StringToTagAddIfUnavailable (m_TagString);
+
+ transfer.Transfer (m_Icon, "m_Icon", kNoTransferFlags);
+ transfer.Transfer (m_NavMeshLayer, "m_NavMeshLayer", kHideInEditorMask);
+
+ transfer.Transfer (m_StaticEditorFlags, "m_StaticEditorFlags", kNoTransferFlags | kGenerateBitwiseDifferences);
+
+ // Read deprecated static flag and set it up as m_StaticEditorFlags
+ if (transfer.IsReadingBackwardsCompatible ())
+ {
+ bool isStatic = false;
+ transfer.Transfer (isStatic, "m_IsStatic", kNoTransferFlags);
+ if (isStatic)
+ m_StaticEditorFlags = 0xFFFFFFFF;
+ }
+ transfer.Transfer (m_IsActive, "m_IsActive", kHideInEditorMask);
+ }
+ }
+ else if (transfer.IsOldVersion (2))
+ {
+ TRANSFER (m_TagString);
+ m_Tag = StringToTag (m_TagString);
+ transfer.Transfer (m_IsActive, "m_IsActive");
+ }
+ else if (transfer.IsOldVersion (1))
+ {
+ TRANSFER (m_Tag);
+ m_TagString = TagToString (m_Tag);
+ transfer.Transfer (m_IsActive, "m_IsActive");
+ }
+ #endif
+
+ // Make sure that old prefabs are always active.
+ if (transfer.IsVersionSmallerOrEqual (3) && IsPersistent() && IS_CONTENT_NEWER_OR_SAME (kUnityVersion4_0_a1))
+ m_IsActive = true;
+}
+
+bool GameObject::GetIsStaticDeprecated ()
+{
+#if UNITY_EDITOR
+ return m_StaticEditorFlags != 0;
+#else
+ return false;
+#endif
+}
+
+void GameObject::SetIsStaticDeprecated(bool s)
+{
+#if UNITY_EDITOR
+ m_StaticEditorFlags = s ? 0xFFFFFFFF : 0;
+ SetDirty();
+#endif
+}
+
+bool GameObject::IsStaticBatchable () const
+{
+#if UNITY_EDITOR
+ return AreStaticEditorFlagsSet (kBatchingStatic);
+#else
+ return false;
+#endif
+}
+
+#if UNITY_EDITOR
+
+bool GameObject::AreStaticEditorFlagsSet (StaticEditorFlags flags) const
+{
+ return (m_StaticEditorFlags & (UInt32)flags) != 0;
+}
+
+StaticEditorFlags GameObject::GetStaticEditorFlags () const
+{
+ return (StaticEditorFlags)m_StaticEditorFlags;
+}
+
+void GameObject::SetStaticEditorFlags (StaticEditorFlags flags)
+{
+ m_StaticEditorFlags = (UInt32)flags;
+ SetDirty();
+}
+
+void GameObject::SetIcon (PPtr<Texture2D> icon)
+{
+ if (m_Icon != icon)
+ {
+ m_Icon = icon;
+ SetDirty ();
+ }
+}
+
+PPtr<Texture2D> GameObject::GetIcon () const
+{
+ return m_Icon;
+}
+#endif
+
+void GameObject::RegisterDestroyedCallback (DestroyGOCallbackFunction* callback)
+{
+ s_GameObjectDestroyedCallback = callback;
+}
+
+void GameObject::InvokeDestroyedCallback (GameObject* go)
+{
+ if (s_GameObjectDestroyedCallback)
+ s_GameObjectDestroyedCallback (go);
+}
+
+void GameObject::RegisterSetGONameCallback (SetGONameFunction* callback)
+{
+ s_SetGONameCallback = callback;
+}
+
+static int GetHighestGOComponentClassID ()
+{
+ static int highestGOComponentClassID = 0;
+ if (highestGOComponentClassID != 0)
+ return highestGOComponentClassID;
+
+ vector<SInt32> classes;
+ Object::FindAllDerivedClasses (ClassID (Component), &classes, false);
+ for (int i=0;i<classes.size ();i++)
+ highestGOComponentClassID = max<int> (highestGOComponentClassID, classes[i]);
+
+ return highestGOComponentClassID;
+}
+
+void GameObject::RegisterMessageHandler (int classID, const MessageIdentifier& messageIdentifier,
+ MessagePtr message, int typeId)
+{
+ Assert(s_RegisteredMessageForwarders);
+ s_RegisteredMessageForwarders->resize (max(classID, GetHighestGOComponentClassID ()) + 1);
+ (*s_RegisteredMessageForwarders)[classID].RegisterMessageCallback (messageIdentifier.messageID, message, typeId);
+}
+
+void GameObject::RegisterAllMessagesHandler (int classID, MessagePtr message, CanHandleMessagePtr canHandleNotification)
+{
+ Assert(s_RegisteredMessageForwarders);
+ s_RegisteredMessageForwarders->resize (max(classID, GetHighestGOComponentClassID ()) + 1);
+ (*s_RegisteredMessageForwarders)[classID].RegisterAllMessagesCallback (message, canHandleNotification);
+}
+
+static void PropagateNotificationsToDerivedClasses (MessageForwarders& notifications)
+{
+ vector<SInt32> classes;
+ Object::FindAllDerivedClasses (ClassID (Object), &classes, false);
+ int highestClassID = 0;
+ for (unsigned i=0;i<classes.size ();i++)
+ highestClassID = max<int> (classes[i], highestClassID);
+
+ notifications.resize (highestClassID + 1);
+
+ for (int classID=0;classID<notifications.size ();classID++)
+ {
+ if (Object::ClassIDToRTTI (classID) == NULL)
+ continue;
+
+ int superClassID = Object::GetSuperClassID (classID);
+ while (superClassID != ClassID (Object))
+ {
+ notifications[classID].AddBaseMessages (notifications[superClassID]);
+ superClassID = Object::GetSuperClassID (superClassID);
+ }
+ }
+}
+
+void GameObject::InitializeMessageHandlers ()
+{
+ Assert(s_MessageHandler && s_RegisteredMessageForwarders);
+ PropagateNotificationsToDerivedClasses (*s_RegisteredMessageForwarders);
+ s_MessageHandler->Initialize (*s_RegisteredMessageForwarders);
+ s_RegisteredMessageForwarders->clear ();
+}
+
+void GameObject::InitializeMessageIdentifiers ()
+{
+ Assert(s_MessageHandler == NULL);
+ s_MessageHandler = UNITY_NEW(MessageHandler,kMemNewDelete);
+ s_RegisteredMessageForwarders = UNITY_NEW(MessageForwarders,kMemNewDelete);
+ GetMessageHandler ().InitializeMessageIdentifiers ();
+}
+
+void GameObject::InitializeClass ()
+{
+ GameObjectManager::StaticInitialize();
+}
+
+void GameObject::CleanupClass ()
+{
+ GameObjectManager::StaticDestroy();
+ UNITY_DELETE(s_MessageHandler,kMemNewDelete);
+ UNITY_DELETE(s_RegisteredMessageForwarders,kMemNewDelete);
+}
+
+bool CheckMessageDataType (int messageIdentifier, MessageData& data)
+{
+ return GameObject::GetMessageHandler ().MessageIDToParameter (messageIdentifier) == data.type;
+}
+
+void GameObject::SendMessageAny (const MessageIdentifier& messageIdentifier, MessageData& messageData)
+{
+ int messageID = messageIdentifier.messageID;
+ AssertIf (messageIdentifier.messageID == -1);
+ #if DEBUGMODE
+ if (!CheckMessageDataType (messageID, messageData))
+ AssertString ("The messageData sent has an incorrect type.");
+ #endif
+
+ for (int i=0;i<m_Component.size ();i++)
+ {
+ int classID = m_Component[i].first;
+ if (s_MessageHandler->HasMessageCallback (classID, messageID))
+ {
+ Component& component = *m_Component[i].second;
+ s_MessageHandler->HandleMessage (&component, classID, messageID, messageData);
+ }
+ }
+}
+
+bool GameObject::WillHandleMessage (const MessageIdentifier& messageIdentifier)
+{
+ int messageID = messageIdentifier.messageID;
+ AssertIf (messageIdentifier.messageID == -1);
+
+ for (Container::iterator i=m_Component.begin ();i != m_Component.end ();i++)
+ {
+ int classID = i->first;
+ if (s_MessageHandler->HasMessageCallback (classID, messageID))
+ {
+ Component& component = *i->second;
+ if (s_MessageHandler->WillHandleMessage (&component, classID, messageID))
+ return true;
+ }
+ }
+ return false;
+}
+
+void GameObject::TransformParentHasChanged ()
+{
+ // Reactivate transform hieararchy, but only if it has been activated before,
+ // otherwise we change activation order.
+ if (m_IsActiveCached != -1)
+ ActivateAwakeRecursively ();
+}
+
+void SendMessageDirect (Object& target, const MessageIdentifier& messageIdentifier, MessageData& messageData)
+{
+ int classID = target.GetClassID();
+ if (GameObject::GetMessageHandler ().HasMessageCallback (classID, messageIdentifier.messageID))
+ {
+ GameObject::GetMessageHandler ().HandleMessage (&target, classID, messageIdentifier.messageID, messageData);
+ }
+}
+
+MessageHandler& GameObject::GetMessageHandler ()
+{
+ Assert(s_MessageHandler);
+ return *s_MessageHandler;
+}
+
+
+char const* Component::GetName () const
+{
+ if (m_GameObject)
+ return m_GameObject->m_Name.c_str();
+ else
+ return GetClassName().c_str();
+}
+
+void Component::SetName (char const* name)
+{
+ if (m_GameObject)
+ m_GameObject->SetName (name);
+}
+
+Component::Component (MemLabelId label, ObjectCreationMode mode) : Super(label, mode)
+{
+ m_GameObject = NULL;
+}
+
+Component::~Component ()
+{
+}
+
+void Component::SendMessageAny (const MessageIdentifier& messageID, MessageData& messageData)
+{
+ GameObject* go = GetGameObjectPtr ();
+ if (go)
+ go->SendMessageAny (messageID, messageData);
+}
+
+void Component::AwakeFromLoad (AwakeFromLoadMode awakeMode)
+{
+ Super::AwakeFromLoad(awakeMode);
+ #if SUPPORT_LOG_ORDER_TRACE
+ if (IsActive() && RunningReproduction())
+ {
+ if (SUPPORT_LOG_ORDER_TRACE == 2)
+ {
+ LogString(Format("AwakeFromLoad %s (%s) [%d]", GetName(), GetClassName().c_str(), GetInstanceID()));
+ }
+ else
+ {
+ LogString(Format("AwakeFromLoad %s (%s)", GetName(), GetClassName().c_str()));
+ }
+ }
+ #endif
+
+ // Force load the game object. This is in order to prevent ImmediatePtrs not being dereferenced after loading.
+ // Which can cause a crash in Resources.UnloadUnusedAssets()
+ // Resources.Load used to store incorrect preload data which made this trigger.
+ GameObject* dereferenceGameObject = m_GameObject;
+ UNUSED(dereferenceGameObject);
+}
+
+template<class TransferFunction>
+void Component::Transfer (TransferFunction& transfer)
+{
+ Super::Transfer (transfer);
+
+ if (SerializePrefabIgnoreProperties(transfer))
+ transfer.Transfer (m_GameObject, "m_GameObject", kHideInEditorMask | kStrongPPtrMask | kIgnoreWithInspectorUndoMask);
+}
+
+void Component::CheckConsistency ()
+{
+ Super::CheckConsistency ();
+ GameObject* go = GetGameObjectPtr ();
+ if (go)
+ {
+ for (int i = 0; i < go->GetComponentCount(); i++)
+ {
+ if (&go->GetComponentAtIndex(i) == this)
+ return;
+ }
+
+ ErrorStringObject (Format("CheckConsistency: GameObject does not reference component %s. Fixing.", GetClassName().c_str()), go);
+ go->AddComponentInternal (this);
+ }
+
+ // MonoBehaviours are allowed to exists without a game object
+ if (IsDerivedFrom(ClassID(Behaviour)))
+ {
+ return;
+ }
+
+ #if UNITY_EDITOR
+ if (m_GameObject == NULL)
+ {
+ GetCleanupManager ().MarkForDeletion (this, "GameObject pointer is invalid");
+ }
+ #endif
+}
+
+GameObjectManager* GameObjectManager::s_Instance = NULL;
+void GameObjectManager::StaticInitialize()
+{
+ Assert(GameObjectManager::s_Instance == NULL);
+ GameObjectManager::s_Instance = UNITY_NEW(GameObjectManager,kMemBaseObject);
+}
+
+void GameObjectManager::StaticDestroy()
+{
+ Assert(GameObjectManager::s_Instance);
+ UNITY_DELETE(GameObjectManager::s_Instance,kMemBaseObject);
+}
+
+GameObjectManager& GetGameObjectManager()
+{
+ Assert(GameObjectManager::s_Instance);
+ return *GameObjectManager::s_Instance;
+}
+
+IMPLEMENT_OBJECT_SERIALIZE (GameObject)
+IMPLEMENT_OBJECT_SERIALIZE (Component)
+
+IMPLEMENT_CLASS_HAS_INIT (GameObject)
+IMPLEMENT_CLASS (Component)
+
+INSTANTIATE_TEMPLATE_TRANSFER_EXPORTED(GameObject)
+INSTANTIATE_TEMPLATE_TRANSFER_EXPORTED(Component)
+
+}
+
+// Hack to make register class work with name spaces. Optimally IMPLEMENT_CLASS / IMPLEMENT_OBJECT_SERIALIZE
+// could be moved out of the namespace but that gives compile errors on gcc
+void RegisterClass_Component () { Unity::RegisterClass_Component(); }
+void RegisterClass_GameObject () { Unity::RegisterClass_GameObject(); }
diff --git a/Runtime/BaseClasses/GameObject.h b/Runtime/BaseClasses/GameObject.h
new file mode 100644
index 0000000..ca4d376
--- /dev/null
+++ b/Runtime/BaseClasses/GameObject.h
@@ -0,0 +1,535 @@
+#ifndef GAMEOBJECT_H
+#define GAMEOBJECT_H
+
+#include <vector>
+#include "EditorExtension.h"
+#include "Runtime/Utilities/LogAssert.h"
+#include "MessageIdentifier.h"
+#include "MessageHandler.h"
+#include "BitField.h"
+#include "Runtime/Utilities/LinkedList.h"
+#include "Runtime/Containers/ConstantString.h"
+
+#if UNITY_EDITOR
+#include "Editor/Src/Utility/StaticEditorFlags.h"
+#endif
+
+class GameManager;
+class MessageHandler;
+class Texture2D;
+class AwakeFromLoadQueue;
+typedef UNITY_SET(kMemTempAlloc, Object*) TempSelectionSet;
+
+namespace Unity
+{
+
+/// A GameObject is basically a bag of GOComponents.
+/// GOComponents are added and removed at runtime.
+/// This allows GameObject to be composed of an arbitrary amount of GOComponents.
+
+/// You can query for any GOCOmponents using
+/// QueryComponent and GetComponent
+/// This will Ask every of the component in the GO if it is derived from the wanted class
+/// eg. from inside a Component you can query for a Transform:
+/// Transform* t = QueryComponent (Transform);
+/// If there is no Transform inside the GameObject, NULL is returned.
+/// The difference between QueryComponent and GetComponent is that
+/// QueryComponent returns a ptr, GetComponent returns a reference
+/// but asserts if no matching component could be found
+/// Also you are not allowed to Query for Component classes
+/// that are in the GameObject more than once.
+
+/// Querys for a component class, aksing every component if it is derived from wanted class
+#define QueryComponent(x) GetGameObject ().QueryComponentT<x> (ClassID (x))
+/// Same as above only that it returns a reference and asserts if no component derived from x can be found
+#define GetComponent(x) GetGameObject ().GetComponentT<x> (ClassID (x))
+
+/// Also GameObjects support messaging.
+/// MessageIdentifier kTransformChanged ("TransformChanged");
+/// MessageIdentifier kTestMessage ("Test", ClassID (float));
+/// In order to receive a message
+/// Register the notification inside the InitializeClass of the class
+/// Renderer::InitializeClass ()
+/// {
+/// REGISTER_NOTIFICATION_VOID (Renderer, kTransformChanged, TransformChanged);
+/// REGISTER_NOTIFICATION (Renderer, kTestMessage, TestMessage, float);
+/// }
+/// bool Renderer::TransformChanged () { ... }
+/// bool Renderer::TestMessage (float f) { ... }
+
+/// In order to send a message use:
+/// SendMessage (kTransformChanged);
+/// SendMessage (kTestMessage, 0.1f, ClassID (float));
+
+class Component;
+class GameObject;
+
+
+enum DeactivateOperation
+{
+ kNormalDeactivate = 0,
+ // Deactivate was called
+ kDeprecatedDeactivateToggleForLevelLoad = 1,
+
+ // Deactivate was called because the component will be destroyed
+ kWillDestroySingleComponentDeactivate = 2,
+ // Deactivate was called because the entire game object will be destroyed
+ kWillDestroyGameObjectDeactivate = 3
+};
+
+class EXPORT_COREMODULE GameObject : public EditorExtension
+{
+ public:
+
+ typedef std::pair<SInt32, ImmediatePtr<Component> > ComponentPair;
+ typedef UNITY_VECTOR(kMemBaseObject, ComponentPair) Container;
+
+ GameObject (MemLabelId label, ObjectCreationMode mode);
+ // ~GameObject (); declared-by-macro
+
+ REGISTER_DERIVED_CLASS (GameObject, EditorExtension)
+ DECLARE_OBJECT_SERIALIZE (GameObject)
+
+ /// An GameObject can either be active or inactive (Template GameObjects are always inactive)
+ /// If an GameObject is active/inactive all its components have the same state as well.
+ /// (Components that are not added to a gameobject are always inactive)
+ /// Querying and messaging still works for inactive GameObjects and Components
+ void Activate ();
+
+ /// Deactiates the game object and thus all it's components.
+ void Deactivate (DeactivateOperation operation = kNormalDeactivate);
+
+ bool IsActiveIgnoreImplicitPrefab ();
+ bool IsActive () const;
+ bool IsSelfActive () const { return m_IsActive; }
+ void SetSelfActive (bool state);
+
+ /// Set the GameObject Layer.
+ /// This is used for collisions and messaging
+ void SetLayer (int layerIndex);
+ int GetLayer () const { return m_Layer; }
+ UInt32 GetLayerMask () const { return 1 << m_Layer; }
+
+ /// Set the Tag of the gameobject
+ UInt32 GetTag () const { return m_Tag; }
+ void SetTag (UInt32 tag);
+
+ // Adds a new Component to the GameObject.
+ // Using the PersistentObject interface so that Components,
+ // which are not loaded at the moment can be added.
+ // Use GameObjectUtility instead, you must invoke specific callbacks etc.
+ void AddComponentInternal (Component* component);
+
+ // Removes a Component from the GameObject.
+ void RemoveComponentAtIndex (int index);
+
+ int GetComponentCount () const { return m_Component.size (); }
+ Component& GetComponentAtIndex (int i) const;
+ Component* GetComponentPtrAtIndex (int i) const;
+ bool GetComponentAtIndexIsLoaded (int i) const;
+ int GetComponentClassIDAtIndex (int i) const;
+ int CountDerivedComponents (int compareClassID)const;
+
+ /// Checks if GameObject has any components conflicting with the specified classID.
+ bool HasConflictingComponents (int classID) const { return FindConflictingComponentPtr (classID) != NULL; }
+
+ /// Find the first conflicting component classID for the specified classID.
+ Component* FindConflictingComponentPtr (int classID) const;
+
+ /// Swap two components in the vector.
+ void SwapComponents (int index1, int index2);
+
+ /// Get the index of a component.
+ int GetComponentIndex (Component *component);
+
+ /// Send a message identified by messageName to all components if they can handle it
+ void SendMessageAny (const MessageIdentifier& messageID, MessageData& messageData);
+
+ /// Send a message identified by messageName to all components if they can handle it
+ template<class T>
+ void SendMessage (const MessageIdentifier& messageID, T messageData, int classId);
+
+ /// Will this message be handled by any component in the gameobject?
+ bool WillHandleMessage (const MessageIdentifier& messageID);
+
+ // Use the QueryComponent macro
+ // Gives back a component by its classID.
+ // If the GameObject doesnt have such a Component, NULL is returned.
+ template<class T>
+ T* QueryComponentT (int inClassID) const;
+
+ // Use the GetComponent macro
+ // Gives back a component by its classID.
+ // If the GameObject doesnt have such a Component, the function will assert
+ template<class T>
+ T& GetComponentT (int inClassID) const;
+
+ // Use the GetComponent macro
+ // Gives back a component by its classID.
+ // If the GameObject doesnt have such a Component, the function will assert
+ template<class T>
+ T& GetComponentExactTypeT (int inClassID) const;
+
+ const GameObject& GetGameObject ()const { return *this; }
+ GameObject& GetGameObject () { return *this; }
+
+ virtual char const* GetName () const { return m_Name.c_str(); }
+ virtual void SetName (char const* name);
+
+ // Deprecated
+ void SetActiveRecursivelyDeprecated (bool state);
+ bool GetIsStaticDeprecated ();
+ void SetIsStaticDeprecated (bool s);
+
+ #if UNITY_EDITOR
+ bool AreStaticEditorFlagsSet (StaticEditorFlags flags) const;
+ StaticEditorFlags GetStaticEditorFlags () const;
+ void SetStaticEditorFlags (StaticEditorFlags flags);
+ #endif
+
+ //@TODO: When we rewrite static batching in C++ fix this up
+ bool IsStaticBatchable () const;
+
+ // Callback functions
+ typedef void DestroyGOCallbackFunction (GameObject* go);
+ static void RegisterDestroyedCallback (DestroyGOCallbackFunction* callback);
+ static void InvokeDestroyedCallback (GameObject* go);
+
+ typedef void SetGONameFunction (GameObject* go);
+ static void RegisterSetGONameCallback (SetGONameFunction* callback);
+
+ /// Registers an message callback. Used by the REGISTER_NOTIFICATION macros
+ typedef void (*MessagePtr)(void* receiver, int messageIndex, MessageData& data);
+ typedef bool (*CanHandleMessagePtr)(void* receiver, int messageIndex, MessageData& data);
+ static void RegisterMessageHandler (int classID, const MessageIdentifier& messageIdentifier, MessagePtr functor, int typeId);
+ static void RegisterAllMessagesHandler (int classID, MessagePtr message, CanHandleMessagePtr canHandleNotification);
+
+ virtual void Reset ();
+
+ static void InitializeClass ();
+ static void CleanupClass ();
+
+ // Initializes the message system
+ static void InitializeMessageHandlers ();
+ static void InitializeMessageIdentifiers ();
+ // Returns the message handler
+ static class MessageHandler& GetMessageHandler ();
+
+ // Internally used during object destruction to prevent double deletion etc.
+ bool IsDestroying () const { return m_IsDestroying; }
+ bool IsActivating () const { return m_IsActivating; }
+
+ void WillDestroyGameObject ();
+
+
+ inline UInt32 GetSupportedMessages ();
+ void SetSupportedMessagesDirty ();
+
+ virtual void AwakeFromLoad(AwakeFromLoadMode mode);
+
+ virtual void SetHideFlags (int flags);
+
+ virtual void CheckConsistency ();
+
+
+ static void AddComponentInternal (GameObject& gameObject, Component& clone);
+ static void RemoveComponentFromGameObjectInternal (Component& clone);
+
+ #if UNITY_EDITOR
+ enum
+ {
+ kNotVisible = 0,
+ kSelfVisible = 1,
+ kVisibleAsChild = 2,
+ };
+ int IsMarkedVisible () const { return m_IsMarkedVisible; }
+ void SetMarkedVisible (int marked) { m_IsMarkedVisible = marked; }
+ void SetIcon (PPtr<Texture2D> icon);
+
+ // Get the custom icon for this gameobject. Does not scan components for their icons.
+ PPtr<Texture2D> GetIcon () const;
+
+ UInt32 GetNavMeshLayer () const { return m_NavMeshLayer; }
+ void SetNavMeshLayer (UInt32 layer) { m_NavMeshLayer = layer; SetDirty(); }
+ #endif
+
+ // Internal functions that you should never call unless you really understand all side effects.
+ void SetActiveBitInternal (bool value) { m_IsActive = value; }
+
+ void SetComponentAtIndexInternal (PPtr<Component> component, int index);
+
+ void UpdateActiveGONode();
+
+ void TransformParentHasChanged ();
+
+ Container& GetComponentContainerInternal () { return m_Component; }
+
+ void ActivateAwakeRecursively (DeactivateOperation deactivateOperation = kNormalDeactivate);
+ void ActivateAwakeRecursivelyInternal (DeactivateOperation deactivateOperation, AwakeFromLoadQueue &queue);
+
+ Component* QueryComponentImplementation (int classID) const;
+ Component* QueryComponentExactTypeImplementation (int classID) const;
+
+private:
+ void GetSupportedMessagesRecalculate ();
+
+ void MarkActiveRecursively (bool state);
+
+ template <class TransferFunction>
+ void TransferComponents(TransferFunction& transfer);
+
+ Container m_Component;
+
+ UInt32 m_Layer;
+ UInt16 m_Tag;
+ bool m_IsActive;
+ mutable SInt8 m_IsActiveCached;
+ UInt8 m_IsDestroying; //// OPTIMIZE THIS INTO A COMMON BITMASK!
+ UInt8 m_IsActivating;
+
+ UInt32 m_SupportedMessages;
+
+ ConstantString m_Name;
+
+ #if UNITY_EDITOR
+ UInt32 m_StaticEditorFlags;
+ UnityStr m_TagString;
+ int m_IsMarkedVisible;
+ PPtr<Texture2D> m_Icon;
+ UInt32 m_NavMeshLayer;
+ bool m_IsOldVersion;
+ #endif
+
+ ListNode<GameObject> m_ActiveGONode;
+
+ static DestroyGOCallbackFunction* s_GameObjectDestroyedCallback;
+ static SetGONameFunction* s_SetGONameCallback;
+ static MessageForwarders* s_RegisteredMessageForwarders;
+ static MessageHandler* s_MessageHandler;
+
+ friend class Component;
+};
+
+class EXPORT_COREMODULE Component : public EditorExtension
+{
+ private:
+
+ ImmediatePtr<GameObject> m_GameObject;
+
+ public:
+
+
+ DECLARE_OBJECT_SERIALIZE (Component)
+ REGISTER_DERIVED_CLASS (Component, EditorExtension)
+
+ Component (MemLabelId label, ObjectCreationMode mode);
+ // ~Component (); declared-by-macro
+
+ // Returns a reference to the GameObject holding this component
+ GameObject& GetGameObject () { return *m_GameObject; }
+ const GameObject& GetGameObject () const { return *m_GameObject; }
+ GameObject* GetGameObjectPtr () { return m_GameObject; }
+ GameObject* GetGameObjectPtr () const { return m_GameObject; }
+
+ /// Send a message identified by messageName to every components of the gameobject
+ /// that can handle it
+ void SendMessageAny (const MessageIdentifier& messageID, MessageData& messageData);
+
+ template<class T>
+ void SendMessage (const MessageIdentifier& messageID, T messageData, int classId);
+ void SendMessage (const MessageIdentifier& messageID);
+
+ /// Is this component active?
+ /// A component is always inactive if its not attached to a gameobject
+ /// A component is always inactive if its gameobject is inactive
+ /// If its a datatemplate, the gameobject and its components are always set to be inactive
+ bool IsActive () const;
+
+ virtual char const* GetName () const;
+ virtual void SetName (char const* name);
+
+ virtual UInt32 CalculateSupportedMessages () { return 0; }
+ virtual void SupportedMessagesDidChange (int /*newMask*/) { }
+
+ virtual void AwakeFromLoad (AwakeFromLoadMode awakeMode);
+
+ // Invoke any callbacks prior to component destruction.
+ virtual void WillDestroyComponent () { }
+
+ /// Deactivate will be called just before the Component is going to be removed from a GameObject
+ /// It can still communicate with other components at this point.
+ /// Deactivate will only be called when the component is remove from the GameObject,
+ /// not if the object is persistet to disk and removed from memory
+ /// Deactivate will only be called if the GameObject the Component is being removed from is active
+ /// YOU CAN NOT RELY ON IsActive returning false inside Deactivate
+ virtual void Deactivate (DeactivateOperation /*operation*/) { }
+
+ virtual void CheckConsistency ();
+
+ #if UNITY_EDITOR
+ // Some components always go together, e.g. when removing one you have
+ // to remove other. Example, ParticleSystem and ParticleSystemRenderer.
+ // Override and return class ID of that "dependent" component.
+ virtual int GetCoupledComponentClassID() const { return -1; }
+ #endif
+
+ public:
+
+ int GetGameObjectInstanceID () const { return m_GameObject.GetInstanceID(); }
+
+ /// SetGameObject is called whenever the GameObject of a component changes.
+ void SetGameObjectInternal (const GameObject* go) { m_GameObject = go; }
+
+ friend class GameObject;
+};
+
+typedef List< ListNode<GameObject> > GameObjectList;
+
+// A fast lookup for all tagged and active game objects
+class GameObjectManager
+{
+public:
+ static void StaticInitialize();
+ static void StaticDestroy();
+ // Nodes that are tagged and active
+ GameObjectList m_TaggedNodes;
+ // Nodes that are just active
+ // (If you want to get all active nodes you need to go through tagged and active nodes)
+ GameObjectList m_ActiveNodes;
+
+ static GameObjectManager* s_Instance;
+};
+GameObjectManager& GetGameObjectManager();
+
+
+template<class T> inline
+T* GameObject::QueryComponentT (int compareClassID) const
+{
+ Component* com;
+ if (T::IsSealedClass())
+ com = QueryComponentExactTypeImplementation(compareClassID);
+ else
+ com = QueryComponentImplementation (compareClassID);
+ DebugAssertIf (com != dynamic_pptr_cast<Component*> (com));
+ return static_cast<T*> (com);
+}
+
+template<class T> inline
+T& GameObject::GetComponentT (int compareClassID) const
+{
+ Component* com;
+ if (T::IsSealedClass())
+ com = QueryComponentExactTypeImplementation(compareClassID);
+ else
+ com = QueryComponentImplementation (compareClassID);
+ DebugAssertIf (dynamic_pptr_cast<T*> (com) == NULL);
+ return *static_cast<T*> (com);
+}
+
+inline Component& GameObject::GetComponentAtIndex (int i)const
+{
+ return *m_Component[i].second;
+}
+
+inline bool GameObject::GetComponentAtIndexIsLoaded (int i)const
+{
+ return m_Component[i].second.IsLoaded();
+}
+
+inline int GameObject::GetComponentClassIDAtIndex (int i) const
+{
+ return m_Component[i].first;
+}
+
+inline bool Component::IsActive () const
+{
+ GameObject* go = m_GameObject;
+ return go != NULL && go->IsActive ();
+}
+
+#define IMPLEMENT_SENDMESSAGE_FOR_CLASS(ClassName) \
+ template<class T> inline \
+ void ClassName::SendMessage (const MessageIdentifier& messageID, \
+ T messageData, int classId) \
+ { \
+ MessageData data; \
+ data.SetData (messageData, classId); \
+ SendMessageAny (messageID, data); \
+ }
+
+IMPLEMENT_SENDMESSAGE_FOR_CLASS (Component)
+IMPLEMENT_SENDMESSAGE_FOR_CLASS (GameObject)
+
+inline UInt32 GameObject::GetSupportedMessages ()
+{
+ return m_SupportedMessages;
+}
+
+inline void Component::SendMessage (const MessageIdentifier& messageID)
+{
+ MessageData data;
+ SendMessageAny (messageID, data);
+}
+
+void SendMessageDirect (Object& target, const MessageIdentifier& messageIdentifier, MessageData& messageData);
+
+// Compares the MessageData's type with the method signatures expected parameter type
+bool EXPORT_COREMODULE CheckMessageDataType (int messageIdentifier, MessageData& data);
+
+/// Creates a wrapper that calls a function with no parameter
+#define REGISTER_MESSAGE_VOID(ClassType,NotificationName,Function) \
+struct FunctorImpl_##ClassType##_##NotificationName { \
+ static void Call (void* object, int, MessageData&) { \
+ ClassType* castedObject = reinterpret_cast<ClassType*> (object); \
+ castedObject->Function (); \
+ } \
+}; \
+GameObject::RegisterMessageHandler (ClassID (ClassType), NotificationName, \
+ FunctorImpl_##ClassType##_##NotificationName::Call, 0)
+
+#if DEBUGMODE
+#define CHECK_MSG_DATA_TYPE \
+if (!CheckMessageDataType (messageID, messageData)) \
+ DebugStringToFile ("Check message data", 0, __FILE__, 0, kAssert);
+#else
+#define CHECK_MSG_DATA_TYPE
+#endif
+
+/// Creates a wrapper thats sends the specified DataType to the member functions
+#define REGISTER_MESSAGE(ClassType,NotificationName,Function,DataType) \
+struct FunctorImpl_##ClassType##_##NotificationName { \
+ static void Call (void* object, int messageID, MessageData& messageData) { \
+ CHECK_MSG_DATA_TYPE \
+ DataType data = messageData.GetData<DataType> (); \
+ ClassType* castedObject = reinterpret_cast<ClassType*> (object); \
+ castedObject->Function (data); \
+ } \
+}; \
+GameObject::RegisterMessageHandler (ClassID (ClassType), \
+ NotificationName, \
+ FunctorImpl_##ClassType##_##NotificationName::Call, \
+ ClassID (DataType))
+
+
+/// Creates a wrapper thats sends the specified DataType to the member functions
+#define REGISTER_MESSAGE_PTR(ClassType,NotificationName,Function,DataType) \
+struct FunctorImpl_##ClassType##_##NotificationName { \
+ static void Call (void* object, int messageID, MessageData& messageData) { \
+ CHECK_MSG_DATA_TYPE \
+ DataType* data = messageData.GetData<DataType*> (); \
+ ClassType* castedObject = reinterpret_cast<ClassType*> (object); \
+ castedObject->Function (data); \
+ } \
+}; \
+GameObject::RegisterMessageHandler (ClassID (ClassType), \
+ NotificationName, \
+ FunctorImpl_##ClassType##_##NotificationName::Call, \
+ ClassID (DataType))
+
+
+}
+
+using namespace Unity;
+
+#endif
+
diff --git a/Runtime/BaseClasses/GameObjectTests.cpp b/Runtime/BaseClasses/GameObjectTests.cpp
new file mode 100644
index 0000000..9c0362f
--- /dev/null
+++ b/Runtime/BaseClasses/GameObjectTests.cpp
@@ -0,0 +1,274 @@
+#include "UnityPrefix.h"
+
+#if ENABLE_UNIT_TESTS
+#include "External/UnitTest++/src/UnitTest++.h"
+#include "Runtime/Misc/GameObjectUtility.h"
+#include "Runtime/BaseClasses/SupportedMessageOptimization.h"
+#include "Runtime/Testing/Testing.h"
+
+class GameObjectFixture
+{
+protected:
+ GameObject* NewGameObject()
+ {
+ return NEW_OBJECT_RESET_AND_AWAKE(GameObject);
+ }
+
+ Unity::Component* NewComponent()
+ {
+ return NEW_OBJECT_RESET_AND_AWAKE(Unity::Component);
+ }
+};
+
+SUITE (GameObjectTests)
+{
+ TEST_FIXTURE (GameObjectFixture, AddandRemoveComponentTest)
+ {
+ GameObject* go = NewGameObject();
+
+ Unity::Component* component = NewComponent();
+ go->AddComponentInternal(component);
+ CHECK_EQUAL (go->GetComponentCount(), 1);
+
+ // Delete by RemoveComponentFromGameObjectInternal().
+ go->RemoveComponentFromGameObjectInternal(*component);
+ CHECK_EQUAL (go->GetComponentCount(), 0);
+
+ go->AddComponentInternal(component);
+ CHECK_EQUAL (go->GetComponentCount(), 1);
+
+ // Delete by RemoveComponentAtIndex().
+ go->RemoveComponentAtIndex(0);
+ CHECK_EQUAL (go->GetComponentCount(), 0);
+
+ go->AddComponentInternal(component);
+ go->AwakeFromLoad (kDefaultAwakeFromLoad);
+ DestroyObjectHighLevel(go);
+ }
+
+ TEST_FIXTURE (GameObjectFixture, HideFlagTest)
+ {
+ GameObject* go = NewGameObject();
+
+ Unity::Component* component = NewComponent();
+ go->AddComponentInternal(component);
+ CHECK_EQUAL (go->GetComponentCount(), 1);
+
+ int hideFlag = 2;
+ go->SetHideFlags(hideFlag);
+
+ CHECK_EQUAL (go->GetHideFlags(), hideFlag);
+
+ for(int i = 0; i < go->GetComponentCount() ; i++)
+ {
+ CHECK_EQUAL (go->GetComponentAtIndex(i).GetHideFlags(), hideFlag);
+ }
+
+ // Add another component, it should have the same hide flag as the game object.
+ Unity::Component* component1 = NewComponent();
+ go->AddComponentInternal(component1);
+ CHECK_EQUAL (go->GetComponentCount(), 2);
+
+ for(int i = 0; i < go->GetComponentCount() ; i++)
+ {
+ CHECK_EQUAL (go->GetComponentAtIndex(i).GetHideFlags(), hideFlag);
+ }
+
+ DestroyObjectHighLevel(go);
+ }
+
+ TEST_FIXTURE (GameObjectFixture, NameTest)
+ {
+ GameObject* go = NewGameObject();
+
+ AddComponents(*go, "Transform", "MeshRenderer", "MeshFilter", NULL);
+
+ const char* name = "Test";
+ go->SetName(name);
+
+ CHECK_EQUAL (go->GetName(), name);
+
+ for(int i = 0; i < go->GetComponentCount() ; i++)
+ {
+ CHECK_EQUAL (go->GetComponentAtIndex(i).GetName(), name);
+ }
+
+ // Set invalid value.
+ // We will not test NULL as it's rejected by UI.
+ go->SetName("");
+
+ CHECK_EQUAL (go->GetName(), "");
+
+ for(int i = 0; i < go->GetComponentCount() ; i++)
+ {
+ CHECK_EQUAL (go->GetComponentAtIndex(i).GetName(), "");
+ }
+
+ DestroyObjectHighLevel(go);
+ }
+
+ TEST_FIXTURE (GameObjectFixture, QueryComponentTest)
+ {
+ GameObject* go = NewGameObject();
+
+ AddComponents(*go, "Transform", "MeshRenderer", "MeshFilter", NULL);
+
+ // Go for QueryComponentExactTypeImplementation().
+ Transform* transform = go->QueryComponentT<Transform>(ClassID(Transform));
+ CHECK (transform != NULL);
+
+ // Go for QueryComponentImplementation().
+ Unity::Component* component = go->QueryComponentT<Unity::Component>(ClassID(Component));
+ CHECK (component != NULL);
+
+ DestroyObjectHighLevel(go);
+ }
+
+ TEST_FIXTURE (GameObjectFixture, SwapComponentTest)
+ {
+ GameObject* go = NewGameObject();
+
+ AddComponents(*go, "Transform", "MeshRenderer", "MeshFilter", NULL);
+
+ Unity::Component* component = go->GetComponentPtrAtIndex(0);
+ go->SwapComponents(0, 1);
+
+ CHECK_EQUAL (go->GetComponentIndex(component), 1);
+
+ DestroyObjectHighLevel(go);
+ }
+}
+
+SUITE (ComponentTests)
+{
+ TEST (GameObjectTest)
+ {
+ GameObject& go = CreateGameObject ("TestGameObject", "Transform", "MeshRenderer", NULL);
+
+ Unity::Component& component = go.GetComponentAtIndex(0);
+
+ CHECK(component.GetGameObjectPtr() == &go);
+ }
+
+ TEST_FIXTURE (GameObjectFixture, ActiveTest)
+ {
+ GameObject* go = NewGameObject();
+ go->Activate();
+
+ Unity::Component* component = NewComponent();
+ CHECK (!component->IsActive());
+
+ go->AddComponentInternal(component);
+ CHECK (component->IsActive());
+ }
+
+ TEST_FIXTURE (GameObjectFixture, NameTest)
+ {
+ GameObject* go = NewGameObject();
+
+ Unity::Component* component = NewComponent();
+ CHECK_EQUAL (component->GetName(), component->GetClassName());
+
+ go->AddComponentInternal(component);
+ CHECK_EQUAL (component->GetName(), go->GetName());
+
+ const char* name = "TestComponent";
+ component->SetName(name);
+
+ CHECK_EQUAL(go->GetName(), name);
+ }
+
+ TEST_FIXTURE (GameObjectFixture, CheckConsistencyTest)
+ {
+ GameObject* go = NewGameObject();
+
+ Unity::Component* component = NewComponent();
+ component->SetGameObjectInternal(go);
+
+ CHECK_EQUAL(go->GetComponentCount(), 0);
+
+ EXPECT (Error, "GameObject does not reference component");
+ component->CheckConsistency();
+
+ CHECK_EQUAL(go->GetComponentCount(), 1);
+ }
+
+ TEST (GameObjectMessagesCheckTest)
+ {
+#if !UNITY_RELEASE
+ {
+ GameObject& go = CreateGameObject ("test", "Transform", NULL);
+ CHECK_EQUAL(go.GetSupportedMessages(), 0);
+
+ //Add a Tree component
+ Unity::Component *cmp1 = AddComponentUnchecked (go, 193, NULL, NULL);
+ CHECK_EQUAL(go.GetSupportedMessages(), (int) kHasOnWillRenderObject);
+
+ go.Deactivate();
+ CHECK_EQUAL(go.GetSupportedMessages(), (int) kHasOnWillRenderObject);
+
+ //Add a NavMeshObstablce component
+ Unity::Component *cmp2 = AddComponentUnchecked (go, 208, NULL, NULL);
+ CHECK_EQUAL(go.GetSupportedMessages(), (kHasOnWillRenderObject | kSupportsVelocityChanged | kSupportsTransformChanged));
+ go.Activate();
+ CHECK_EQUAL(go.GetSupportedMessages(), (kHasOnWillRenderObject | kSupportsVelocityChanged | kSupportsTransformChanged));
+ DestroyObjectHighLevel(cmp1);
+ CHECK_EQUAL(go.GetSupportedMessages(), (kSupportsVelocityChanged | kSupportsTransformChanged));
+ go.Deactivate();
+ DestroyObjectHighLevel(cmp2);
+
+ CHECK_EQUAL(go.GetSupportedMessages(), 0);
+ DestroyObjectHighLevel(&go);
+ }
+#endif
+ }
+
+ TEST (AwakeFromLoadCheckTest)
+ {
+ // tests to check if checks of AwakeFromLoad behavior are working
+ // uncomment them when in doubt
+ #if !UNITY_RELEASE
+ // 1. simple object creation
+ /*
+ {
+ GameObject* obj = NEW_OBJECT(GameObject);
+ obj->CheckCorrectAwakeUsage();
+ obj->CheckCorrectAwakeUsage();
+ }
+ */
+
+ // 2. enforce awake after reset
+ /*
+ {
+ GameObject* obj = NEW_OBJECT(GameObject);
+ obj->AwakeFromLoad(kDefaultAwakeFromLoad);
+ obj->CheckCorrectAwakeUsage();
+ obj->CheckCorrectAwakeUsage();
+ obj->Reset();
+ obj->CheckCorrectAwakeUsage();
+ obj->CheckCorrectAwakeUsage();
+ }
+ */
+
+ // 3. check hacks are working
+ {
+ GameObject* obj = NEW_OBJECT(GameObject);
+ obj->Reset();
+ obj->HackSetAwakeWasCalled();
+ obj->CheckCorrectAwakeUsage();
+ obj->CheckCorrectAwakeUsage();
+ DestroyObjectHighLevel(obj);
+ }
+
+ {
+ GameObject* obj = NEW_OBJECT(GameObject);
+ obj->Reset();
+ obj->AwakeFromLoad(kInstantiateOrCreateFromCodeAwakeFromLoad);
+ obj->CheckCorrectAwakeUsage();
+ DestroyObjectHighLevel(obj);
+ }
+#endif
+ }
+}
+
+#endif
diff --git a/Runtime/BaseClasses/IsPlaying.cpp b/Runtime/BaseClasses/IsPlaying.cpp
new file mode 100644
index 0000000..184e830
--- /dev/null
+++ b/Runtime/BaseClasses/IsPlaying.cpp
@@ -0,0 +1,14 @@
+#include "UnityPrefix.h"
+#include "IsPlaying.h"
+
+#if GAMERELEASE
+static bool gIsWorldPlaying = true;
+#else
+static bool gIsWorldPlaying = false;
+#endif
+
+bool IsWorldPlaying () { return gIsWorldPlaying; }
+void SetIsWorldPlaying (bool isPlaying)
+{
+ gIsWorldPlaying = isPlaying;
+}
diff --git a/Runtime/BaseClasses/IsPlaying.h b/Runtime/BaseClasses/IsPlaying.h
new file mode 100644
index 0000000..740ffb8
--- /dev/null
+++ b/Runtime/BaseClasses/IsPlaying.h
@@ -0,0 +1,9 @@
+#ifndef ISPLAYING_H
+#define ISPLAYING_H
+
+/// Is the world playmode? (Otherwise we are in editor mode)
+bool EXPORT_COREMODULE IsWorldPlaying ();
+
+void SetIsWorldPlaying (bool isPlaying);
+
+#endif
diff --git a/Runtime/BaseClasses/ManagerContext.cpp b/Runtime/BaseClasses/ManagerContext.cpp
new file mode 100644
index 0000000..1824a84
--- /dev/null
+++ b/Runtime/BaseClasses/ManagerContext.cpp
@@ -0,0 +1,107 @@
+#include "UnityPrefix.h"
+#include "ManagerContext.h"
+#include "BaseObject.h"
+#include "Configuration/UnityConfigure.h"
+
+ManagerContext::ManagerContext ()
+{
+ for (int i=0;i<kManagerCount;i++)
+ m_Managers[i] = NULL;
+}
+
+void ManagerContext::InitializeClasses ()
+{
+ for (int i=0;i<kManagerCount;i++)
+ {
+ m_ManagerClassIDs[i] = -1;
+ #if DEBUGMODE
+ m_ManagerNames[i] = "Not initialized";
+ #endif
+ }
+
+#if DEBUGMODE
+ #define INIT_MANAGER_CLASS(x) Assert(m_ManagerClassIDs[k##x] == -1); m_ManagerClassIDs[k##x] = Object::StringToClassID (#x); m_ManagerNames[k##x] = #x;
+#else
+ #define INIT_MANAGER_CLASS(x) m_ManagerClassIDs[k##x] = Object::StringToClassID (#x);
+#endif
+
+ INIT_MANAGER_CLASS (PlayerSettings)
+ INIT_MANAGER_CLASS (InputManager)
+ INIT_MANAGER_CLASS (TagManager)
+ INIT_MANAGER_CLASS (AudioManager)
+ INIT_MANAGER_CLASS (ScriptMapper)
+ INIT_MANAGER_CLASS (MonoManager)
+ INIT_MANAGER_CLASS (GraphicsSettings)
+ INIT_MANAGER_CLASS (TimeManager)
+ INIT_MANAGER_CLASS (DelayedCallManager)
+ INIT_MANAGER_CLASS (PhysicsManager)
+ INIT_MANAGER_CLASS (BuildSettings)
+ INIT_MANAGER_CLASS (QualitySettings)
+ INIT_MANAGER_CLASS (ResourceManager)
+ INIT_MANAGER_CLASS (NetworkManager)
+ INIT_MANAGER_CLASS (MasterServerInterface)
+ INIT_MANAGER_CLASS (NavMeshLayers)
+ #if ENABLE_2D_PHYSICS
+ INIT_MANAGER_CLASS (Physics2DSettings)
+ #endif
+
+ INIT_MANAGER_CLASS (SceneSettings)
+ INIT_MANAGER_CLASS (RenderSettings)
+ INIT_MANAGER_CLASS (HaloManager)
+ INIT_MANAGER_CLASS (LightmapSettings)
+ INIT_MANAGER_CLASS (NavMeshSettings)
+
+#if UNITY_EDITOR
+ for (int i=0;i<kManagerCount;i++)
+ {
+ Assert (m_ManagerClassIDs[i] != -1);
+ }
+
+ std::vector<SInt32> allDerivedClasses;
+ Object::FindAllDerivedClasses(Object::StringToClassID("GameManager"), &allDerivedClasses);
+ if (allDerivedClasses.size() != kManagerCount)
+ {
+ ErrorString("Number of GameManager classes does not match number of game managers registered.");
+ }
+#endif
+
+}
+
+static ManagerContext gContext;
+
+Object& GetManagerFromContext (int index)
+{
+#if DEBUGMODE
+
+ if( index >= ManagerContext::kManagerCount )
+ FatalErrorString( "GetManagerFromContext: index for managers table is out of bounds" );
+
+ if( gContext.m_Managers[index] == NULL )
+ {
+ char const* managerName = gContext.m_ManagerNames[ index ];
+ FatalErrorString( Format("GetManagerFromContext: pointer to object of manager '%s' is NULL (table index %d)", managerName, index) );
+ }
+#endif
+
+ return *gContext.m_Managers[index];
+}
+
+void ManagerContextInitializeClasses()
+{
+ gContext.InitializeClasses();
+}
+
+Object* GetManagerPtrFromContext (int index)
+{
+ return gContext.m_Managers[index];
+}
+
+void SetManagerPtrInContext(int index, Object* ptr)
+{
+ gContext.m_Managers[index] = ptr;
+}
+
+const ManagerContext& GetManagerContext ()
+{
+ return gContext;
+}
diff --git a/Runtime/BaseClasses/ManagerContext.h b/Runtime/BaseClasses/ManagerContext.h
new file mode 100644
index 0000000..af4de7b
--- /dev/null
+++ b/Runtime/BaseClasses/ManagerContext.h
@@ -0,0 +1,61 @@
+#ifndef MANAGERCONTEXT_H
+#define MANAGERCONTEXT_H
+
+class Object;
+struct ManagerContext;
+
+EXPORT_COREMODULE Object& GetManagerFromContext (int index);
+EXPORT_COREMODULE Object* GetManagerPtrFromContext (int index);
+void SetManagerPtrInContext(int index, Object* ptr);
+void ManagerContextInitializeClasses();
+
+#define GET_MANAGER(x) x& Get##x () { return reinterpret_cast<x&> (GetManagerFromContext (ManagerContext::k##x)); }
+#define GET_MANAGER_PTR(x) x* Get##x##Ptr () { return reinterpret_cast<x*> (GetManagerPtrFromContext (ManagerContext::k##x)); }
+
+const ManagerContext& GetManagerContext ();
+
+struct ManagerContext
+{
+ enum Managers
+ {
+ // Global managers
+ kPlayerSettings = 0,
+ kInputManager,
+ kTagManager,
+ kAudioManager,
+ kScriptMapper,
+ kMonoManager,
+ kGraphicsSettings,
+ kTimeManager,
+ kDelayedCallManager,
+ kPhysicsManager,
+ kBuildSettings,
+ kQualitySettings,
+ kResourceManager,
+ kNetworkManager,
+ kMasterServerInterface,
+ kNavMeshLayers,
+ #if ENABLE_2D_PHYSICS
+ kPhysics2DSettings,
+ #endif
+ kGlobalManagerCount,
+
+ // Level managers
+ kSceneSettings = kGlobalManagerCount,
+ kRenderSettings,
+ kHaloManager,
+ kLightmapSettings,
+ kNavMeshSettings,
+ kManagerCount
+ };
+
+ ManagerContext ();
+ Object* m_Managers[kManagerCount];
+ int m_ManagerClassIDs[kManagerCount];
+ #if DEBUGMODE
+ const char* m_ManagerNames[kManagerCount];
+ #endif
+ void InitializeClasses ();
+};
+
+#endif
diff --git a/Runtime/BaseClasses/ManagerContextLoading.cpp b/Runtime/BaseClasses/ManagerContextLoading.cpp
new file mode 100644
index 0000000..76345d3
--- /dev/null
+++ b/Runtime/BaseClasses/ManagerContextLoading.cpp
@@ -0,0 +1,285 @@
+#include "UnityPrefix.h"
+#include "ManagerContextLoading.h"
+#include "Runtime/Profiler/Profiler.h"
+#include "Runtime/Serialize/PersistentManager.h"
+#include "Runtime/Serialize/SerializedFile.h"
+#include "Runtime/Misc/GameObjectUtility.h"
+#include "Runtime/BaseClasses/ManagerContext.h"
+#include "Runtime/Serialize/AwakeFromLoadQueue.h"
+#include "Runtime/BaseClasses/GameManager.h"
+#include "Runtime/Utilities/vector_map.h"
+#include "Runtime/Core/Callbacks/GlobalCallbacks.h"
+
+
+PROFILER_INFORMATION(gCollectGameManagers, "CollectGameManagers", kProfilerLoading)
+
+void CollectLevelGameManagers (InstanceIDArray& outputObjects)
+{
+ PROFILER_AUTO(gCollectGameManagers,NULL);
+ const ManagerContext& context = GetManagerContext ();
+ for (int i=0;i<ManagerContext::kManagerCount;i++)
+ {
+ #if !UNITY_EDITOR
+ // In players we might have stripped all managers
+ if (!context.m_Managers[i])
+ continue;
+ #endif
+
+ Object& object = *context.m_Managers[i];
+ if (object.IsDerivedFrom (ClassID (LevelGameManager)))
+ {
+ AssertIf (object.IsPersistent () || object.TestHideFlag (Object::kDontSave));
+ outputObjects.push_back(object.GetInstanceID ());
+ }
+ }
+}
+
+void DestroyLevelManagers ()
+{
+ InstanceIDArray loadedLevelManagers;
+ CollectLevelGameManagers (loadedLevelManagers);
+ for (InstanceIDArray::iterator i=loadedLevelManagers.begin ();i != loadedLevelManagers.end ();++i)
+ {
+ Object* o = Object::IDToPointer (*i);
+ AssertIf (o == NULL || o->IsPersistent ());
+ DestroyObjectHighLevel (o);
+ }
+}
+
+
+/// Setup all managers to be called for a given mode.
+/// When we're in edit mode, the Input, Dynamics, Fixed, Animation & Behaviour managers don't get
+/// Updated. In Play mode, everything runs.
+/// @param mode kPlayMode or kEditMode
+
+
+
+void RemoveDuplicateGameManagers ()
+{
+ const ManagerContext& context = GetManagerContext ();
+
+ for (int i=0;i<ManagerContext::kManagerCount;i++)
+ {
+ Assert(GetManagerPtrFromContext(i) != NULL);
+ }
+
+ vector<GameManager*> managers;
+ Object::FindObjectsOfType (&managers);
+
+ // Remove all managers that are not in the manager context!
+ for (int m=0;m<managers.size ();m++)
+ {
+ bool isUsed = false;
+ for (int i=0;i<ManagerContext::kManagerCount;i++)
+ {
+ if ((Object*)managers[m] == context.m_Managers[i])
+ isUsed = true;
+ }
+
+ if (!isUsed)
+ {
+ Object* obj = managers[m];
+ FatalErrorIf (obj->IsPersistent ());
+ ErrorString (Format("Removing duplicate game manager (%s)!", obj->GetClassName().c_str()));
+ FatalErrorIf (PPtr<Object> (managers[m])->IsPersistent ());
+ DestroyObjectHighLevel (managers[m]);
+ }
+ }
+
+ ErrorIf (Object::FindAllDerivedObjects (ClassID (GameManager), NULL) != ManagerContext::kManagerCount);
+}
+
+
+typedef vector_map<SInt32, SInt32> ClassIDToInstanceID;
+static void ExtractGlobalManagers (const std::string& path, ClassIDToInstanceID& managers)
+{
+ GetPersistentManager ().Lock();
+ SerializedFile* stream = GetPersistentManager ().GetSerializedFileInternal(path);
+ if (stream == NULL)
+ {
+ GetPersistentManager ().Unlock();
+ return;
+ }
+
+ vector<LocalIdentifierInFileType> sourceFileIDs;
+ stream->GetAllFileIDs(&sourceFileIDs);
+
+ for (int i=0;i<sourceFileIDs.size ();i++)
+ {
+ LocalIdentifierInFileType fileID = sourceFileIDs[i];
+ SInt32 classID = stream->GetClassID (fileID);
+
+ if (Object::IsDerivedFromClassID (classID, ClassID (GlobalGameManager)))
+ {
+ SInt32 instanceID = GetPersistentManager().GetInstanceIDFromPathAndFileID (path, fileID);
+ managers.push_unsorted (classID, instanceID);
+ }
+ }
+
+ managers.sort();
+
+ GetPersistentManager ().Unlock();
+}
+
+static Object* LoadManager (const ClassIDToInstanceID& managers, int classID)
+{
+ ClassIDToInstanceID::const_iterator i = managers.find(classID);
+ if (i == managers.end())
+ return NULL;
+
+ Object* obj = dynamic_instanceID_cast<Object*> (i->second);
+ Assert(dynamic_pptr_cast<GlobalGameManager*> (obj) != NULL);
+
+ return obj;
+}
+
+
+string PlayerLoadSettingsAndInput(const std::string& dataFile)
+{
+ ClassIDToInstanceID managers;
+ ExtractGlobalManagers (dataFile, managers);
+
+ ManagerContext::Managers loadManagers[] =
+ {
+ ManagerContext::kPlayerSettings,
+ ManagerContext::kInputManager,
+ ManagerContext::kBuildSettings,
+ ManagerContext::kGraphicsSettings,
+ ManagerContext::kQualitySettings,
+ };
+
+ const ManagerContext& ctx = GetManagerContext();
+ for( int i = 0; i < sizeof(loadManagers)/sizeof(loadManagers[0]); ++i )
+ {
+ int index = loadManagers[i];
+ int classID = ctx.m_ManagerClassIDs[index];
+ SetManagerPtrInContext(index, LoadManager(managers, classID));
+ if (ctx.m_Managers[index] == NULL || !ctx.m_Managers[index]->IsDerivedFrom(classID))
+ return Format("Could..... not preload global game manager #%i i=%i", index,i);
+ }
+
+ return string();
+}
+
+string PlayerLoadGlobalManagers (const char* dataFile)
+{
+ ClassIDToInstanceID managers;
+ ExtractGlobalManagers (dataFile, managers);
+
+ // Load all game managers! All global game managers are coming first in the main data
+ // (Global game managers have to be loaded before selecting the screen resolution.
+ // ProjectSettings i used by screen selector and RenderManager, InputManager by screen switching)
+ for (int i=0;i<ManagerContext::kGlobalManagerCount;i++)
+ {
+ int classID = GetManagerContext().m_ManagerClassIDs[i];
+
+ Object* manager = NULL;
+
+ // Manager is dead-code stripped
+ if (classID != -1)
+ {
+ // Try to load manager
+ manager = LoadManager(managers, classID);
+
+ // Manager could not be loaded, create it from code instead
+ if (classID != -1 && manager == NULL)
+ {
+ manager = CreateGameManager (classID);
+ printf_console("Loading manager failed, creating from code %d\n", classID);
+ }
+ }
+
+ // Assign manager as soon as it is created.
+ SetManagerPtrInContext(i, manager);
+ }
+
+ std::string resetError = ResetManagerContextFromLoaded();
+ if( !resetError.empty() )
+ return Format("PlayerLoadGlobalManagers: %s\n", resetError.c_str());
+
+ GetPersistentManager().DoneLoadingManagers();
+
+ return string();
+}
+
+string ResetManagerContextFromLoaded ()
+{
+ GlobalCallbacks::Get().managersWillBeReloadedHack.Invoke();
+
+ string error;
+ const ManagerContext& context = GetManagerContext ();
+
+ vector<GameManager*> allManagers;
+ Object::FindObjectsOfType (&allManagers);
+
+ for (int i=0;i<ManagerContext::kManagerCount;i++)
+ {
+ SetManagerPtrInContext(i, NULL);
+
+ if (context.m_ManagerClassIDs[i] == -1)
+ continue;
+
+ vector<GameManager*> specificManagers;
+ for (int j=0;j<allManagers.size();j++)
+ {
+ if (allManagers[j]->IsDerivedFrom(context.m_ManagerClassIDs[i]))
+ {
+ specificManagers.push_back(allManagers[j]);
+ }
+ }
+
+ if (specificManagers.size () == 1)
+ SetManagerPtrInContext(i, specificManagers[0]);
+ else if (specificManagers.size () == 0)
+ {
+ // missing global managers are serious errors
+ if( i < ManagerContext::kGlobalManagerCount )
+ error += " Missing " + Object::ClassIDToString (context.m_ManagerClassIDs[i]);
+ }
+ else
+ {
+ // missing global managers are serious errors
+ if( i < ManagerContext::kGlobalManagerCount )
+ error += " Too many instances of " + Object::ClassIDToString (context.m_ManagerClassIDs[i]);
+ }
+ }
+ return error;
+}
+
+void LoadManagers (AwakeFromLoadQueue& awakeFromLoadQueue)
+{
+ AwakeFromLoadMode awakeMode = (AwakeFromLoadMode)(kDidLoadFromDisk | kDidLoadThreaded);
+
+ awakeFromLoadQueue.PersistentManagerAwakeFromLoad(kManagersQueue, awakeMode, NULL);
+ awakeFromLoadQueue.ClearQueue(kManagersQueue);
+
+ // Get all managers that are in memory
+ map<int, set<GameManager*> > managers;
+ vector<GameManager*> temp;
+ Object::FindObjectsOfType (&temp);
+ for (int i=0;i<temp.size ();i++)
+ managers[temp[i]->GetClassID ()].insert (temp[i]);
+
+ const ManagerContext& context = GetManagerContext();
+ // Load the managers in the order defined by the context.
+ // Create new managers if necessary.
+ for (int i=0;i<ManagerContext::kManagerCount;i++)
+ {
+ SetManagerPtrInContext(i, NULL);
+
+ if (context.m_ManagerClassIDs[i] == -1)
+ continue;
+
+ const set<GameManager*>& manager = managers[context.m_ManagerClassIDs[i]];
+
+ if (manager.size () == 1)
+ SetManagerPtrInContext(i, *manager.begin ());
+ else if (manager.size () == 0)
+ SetManagerPtrInContext(i, CreateGameManager (context.m_ManagerClassIDs[i]));
+ else
+ {
+ ErrorString("Multiple managers are loaded of type: " + Object::ClassIDToString(context.m_ManagerClassIDs[i]));
+ SetManagerPtrInContext(i, *manager.begin ());
+ }
+ }
+}
diff --git a/Runtime/BaseClasses/ManagerContextLoading.h b/Runtime/BaseClasses/ManagerContextLoading.h
new file mode 100644
index 0000000..f8187d7
--- /dev/null
+++ b/Runtime/BaseClasses/ManagerContextLoading.h
@@ -0,0 +1,17 @@
+#ifndef _MANAGERCONTEXT_LOADING_H_
+#define _MANAGERCONTEXT_LOADING_H_
+
+#include "Runtime/Utilities/dynamic_array.h"
+
+typedef dynamic_array<int> InstanceIDArray;
+class AwakeFromLoadQueue;
+
+void CollectLevelGameManagers (InstanceIDArray& outputObjects);
+void DestroyLevelManagers ();
+void RemoveDuplicateGameManagers ();
+std::string PlayerLoadSettingsAndInput(const std::string& dataFile);
+std::string PlayerLoadGlobalManagers (const char* dataFile);
+std::string ResetManagerContextFromLoaded ();
+void LoadManagers (AwakeFromLoadQueue& awakeFromLoadQueue);
+
+#endif \ No newline at end of file
diff --git a/Runtime/BaseClasses/MessageHandler.cpp b/Runtime/BaseClasses/MessageHandler.cpp
new file mode 100644
index 0000000..71ef06e
--- /dev/null
+++ b/Runtime/BaseClasses/MessageHandler.cpp
@@ -0,0 +1,196 @@
+#include "UnityPrefix.h"
+#include "MessageHandler.h"
+#include "Runtime/Utilities/LogAssert.h"
+#include <map>
+#include <list>
+
+using namespace std;
+
+MessageForwarder::MessageForwarder ()
+{
+ m_GeneralMessage = NULL;
+ m_CanHandleGeneralMessage = NULL;
+}
+
+void MessageForwarder::HandleMessage (void* receiver, int messageID, MessageData& messageData)
+{
+ MessageCallback messagePtr = m_GeneralMessage;
+ if (messageID < m_SupportedMessages.size () && m_SupportedMessages[messageID] != NULL)
+ messagePtr = m_SupportedMessages[messageID];
+
+ AssertIf (messagePtr == NULL);
+ messagePtr (receiver, messageID, messageData);
+}
+
+bool MessageForwarder::HasMessageCallback (const MessageIdentifier& identifier)
+{
+ if (identifier.messageID < m_SupportedMessages.size () && m_SupportedMessages[identifier.messageID])
+ return true;
+ else
+ return m_GeneralMessage != NULL && (identifier.options & MessageIdentifier::kSendToScripts);
+}
+
+bool MessageForwarder::WillHandleMessage (void* receiver, const MessageIdentifier& identifier)
+{
+ if (identifier.messageID < m_SupportedMessages.size () && m_SupportedMessages[identifier.messageID])
+ return true;
+
+ if (m_GeneralMessage && (identifier.options & MessageIdentifier::kSendToScripts))
+ {
+ AssertIf (m_CanHandleGeneralMessage == NULL);
+ MessageData data;
+ return m_CanHandleGeneralMessage (receiver, identifier.messageID, data);
+ }
+ return false;
+}
+
+int MessageForwarder::GetExpectedParameter (int messageID)
+{
+ if (messageID < m_SupportedMessages.size ())
+ return m_SupportedMessagesParameter[messageID];
+ else
+ return 0;
+}
+
+void MessageForwarder::RegisterMessageCallback (int messageID, MessageCallback message, int classId)
+{
+ AssertIf (messageID == -1);
+ if (messageID >= m_SupportedMessages.size ())
+ {
+ m_SupportedMessages.resize (messageID + 1, NULL);
+ m_SupportedMessagesParameter.resize (messageID + 1, 0);
+ }
+ m_SupportedMessages[messageID] = message;
+ m_SupportedMessagesParameter[messageID] = classId;
+}
+
+void MessageForwarder::RegisterAllMessagesCallback (MessageCallback message, CanHandleMessageCallback canHandle)
+{
+ m_GeneralMessage = message;
+ m_CanHandleGeneralMessage = canHandle;
+}
+
+void MessageForwarder::AddBaseMessages (const MessageForwarder& baseClass)
+{
+ int maxsize = max (m_SupportedMessages.size (), baseClass.m_SupportedMessages.size ());
+ m_SupportedMessages.resize (maxsize, NULL);
+ m_SupportedMessagesParameter.resize (maxsize, 0);
+ for (int i=0;i<m_SupportedMessages.size ();i++)
+ {
+ if (m_SupportedMessages[i] == NULL && i < baseClass.m_SupportedMessages.size ())
+ {
+ m_SupportedMessages[i] = baseClass.m_SupportedMessages[i];
+ m_SupportedMessagesParameter[i] = baseClass.m_SupportedMessagesParameter[i];
+ }
+ }
+
+ if (m_GeneralMessage == NULL)
+ m_GeneralMessage = baseClass.m_GeneralMessage;
+}
+
+void MessageHandler::InitializeMessageIdentifiers ()
+{
+ MessageIdentifier::RegisteredMessages& identifiers = MessageIdentifier::GetRegisteredMessages ();
+ MessageIdentifier::SortedMessages sortedMessages = MessageIdentifier::GetSortedMessages(false);
+
+ m_MessageIDToIdentifier.clear ();
+ m_MessageNameToIndex.clear ();
+
+ // Build m_MessageIDToName and m_MessageNameToIndex
+ // by copying the data from the sorted messages map
+ m_MessageIDToIdentifier.resize (sortedMessages.size ());
+ int index = 0;
+ MessageIdentifier::SortedMessages::iterator i;
+ for (i = sortedMessages.begin ();i != sortedMessages.end ();i++)
+ {
+ m_MessageNameToIndex[i->first] = index;
+ m_MessageIDToIdentifier[index] = i->second;
+ m_MessageIDToIdentifier[index].messageID = index;
+ index++;
+ }
+
+
+ // Setup the messageIDs of all registered message Identifiers
+ MessageIdentifier::RegisteredMessages::iterator j;
+ for (j = identifiers.begin ();j != identifiers.end ();j++)
+ {
+ AssertIf (*j == NULL);
+ MessageIdentifier& identifier = **j;
+ if (m_MessageNameToIndex.count (identifier.messageName))
+ {
+ identifier.messageID = m_MessageNameToIndex[identifier.messageName];
+ }
+ }
+}
+
+void MessageHandler::Initialize (const MessageForwarders& receivers)
+{
+ m_Forwarder = receivers;
+ m_MessageCount = m_MessageNameToIndex.size ();
+ m_ClassCount = receivers.size ();
+
+ // Precalculate supported messages
+ m_SupportedMessages.resize (m_ClassCount * m_MessageCount);
+ for (int c=0;c<m_ClassCount;c++)
+ {
+ for (int m=0;m<m_MessageCount;m++)
+ {
+ bool hasCallback = m_Forwarder[c].HasMessageCallback (m_MessageIDToIdentifier[m]);
+ if (hasCallback)
+ {
+ // Check if the parameter is correct and print an error if they dont match
+ int wantedParameter = m_Forwarder[c].GetExpectedParameter (m);
+ int messageParameter = m_MessageIDToIdentifier[m].parameterClassId;
+ if (wantedParameter != 0 && messageParameter != wantedParameter)
+ {
+ char buffy[4096];
+ char const format[] = "The message: %s in the class with "
+ "classID: %d uses a parameter type "
+ "that is different from the "
+ "message's parameter type: %d != %d.";
+ sprintf (buffy, format, m_MessageIDToIdentifier[m].messageName,
+ c, wantedParameter, messageParameter);
+ ErrorString (buffy);
+ hasCallback = false;
+ }
+ }
+ m_SupportedMessages[m * m_ClassCount + c] = hasCallback;
+ }
+ }
+}
+
+bool MessageHandler::WillHandleMessage (void* receiver, int classID, int messageID)
+{
+ AssertIf (!HasMessageCallback (classID, messageID));
+ return m_Forwarder[classID].WillHandleMessage (receiver, m_MessageIDToIdentifier[messageID]);
+}
+
+int MessageHandler::MessageNameToID (const string& name)
+{
+ MessageNameToIndex::iterator i = m_MessageNameToIndex.find (name);
+ if (i == m_MessageNameToIndex.end ())
+ return -1;
+ else
+ return i->second;
+}
+
+const char* MessageHandler::MessageIDToName (int messageID)
+{
+ AssertIf (messageID < 0);
+ AssertIf (messageID >= m_MessageIDToIdentifier.size ());
+ return m_MessageIDToIdentifier[messageID].messageName;
+}
+
+int MessageHandler::MessageIDToParameter (int messageID)
+{
+ AssertIf (messageID < 0);
+ AssertIf (messageID >= m_MessageIDToIdentifier.size ());
+ return m_MessageIDToIdentifier[messageID].parameterClassId;
+}
+
+MessageIdentifier MessageHandler::MessageIDToMessageIdentifier (int messageID)
+{
+ AssertIf (messageID < 0);
+ AssertIf (messageID >= m_MessageIDToIdentifier.size ());
+ return m_MessageIDToIdentifier[messageID];
+}
diff --git a/Runtime/BaseClasses/MessageHandler.h b/Runtime/BaseClasses/MessageHandler.h
new file mode 100644
index 0000000..5d0fa46
--- /dev/null
+++ b/Runtime/BaseClasses/MessageHandler.h
@@ -0,0 +1,112 @@
+#ifndef MESSAGEHANDLER_H
+#define MESSAGEHANDLER_H
+
+#include <vector>
+#include <map>
+#include <string>
+#include "Runtime/Utilities/dynamic_bitset.h"
+#include "Runtime/Misc/Allocator.h"
+#include "MessageIdentifier.h"
+
+/*
+ DOCUMENT_______________________________________
+*/
+
+class MessageForwarder
+{
+ typedef void (*MessageCallback)(void* Receiver, int messageID, MessageData& data);
+ typedef bool (*CanHandleMessageCallback)(void* Receiver, int messageID, MessageData& data);
+ std::vector<MessageCallback> m_SupportedMessages;
+ std::vector<int> m_SupportedMessagesParameter;
+ MessageCallback m_GeneralMessage;
+ CanHandleMessageCallback m_CanHandleGeneralMessage;
+
+ public:
+
+ MessageForwarder ();
+
+ // Returns true if a message callback exists for the class and the messageID
+ bool HasMessageCallback (const MessageIdentifier& messageID);
+
+ // Returns true a message callback exists and the message will actually be handled.
+ // This is used to find out if a message will *actually* be forwared, eg. HasMessageCallback will always return true
+ // for eg. ScriptBehaviours which checks at runtime if the message is supported by the script.
+ bool WillHandleMessage (void* receiver, const MessageIdentifier& messageID);
+
+ /// Calls the message
+ /// the notification can be handled using CanHandleNotification
+ void HandleMessage (void* receiver, int messageID, MessageData& notificationData);
+
+ void RegisterMessageCallback (int messageID, MessageCallback message, int classId);
+ void RegisterAllMessagesCallback (MessageCallback message, CanHandleMessageCallback canHandleMessage);
+
+ /// Returns the parameter that the receiver expects from a message. If
+ /// the method doesn't expect a parameter, is not supported, or uses a
+ /// general message handler, 0 is returned.
+ int GetExpectedParameter (int messageID);
+
+ /// Adds all messages that baseMessages contains but this MessageReceiver does not handle yet.
+ /// AddBaseNotifications is used to implement derivation by calling AddBaseNotifications for all base classes.
+ void AddBaseMessages (const MessageForwarder& baseMessages);
+};
+
+typedef std::vector<MessageForwarder, STL_ALLOCATOR_ALIGNED(kMemPermanent, MessageForwarder, 8) > MessageForwarders;
+
+class MessageHandler
+{
+ dynamic_bitset m_SupportedMessages;
+ MessageForwarders m_Forwarder;
+ int m_ClassCount;
+ int m_MessageCount;
+
+ typedef std::vector<MessageIdentifier> MessageIDToIdentifier;
+ MessageIDToIdentifier m_MessageIDToIdentifier;
+ typedef std::map<std::string, int> MessageNameToIndex;
+ MessageNameToIndex m_MessageNameToIndex;
+
+ public:
+
+ /// Initializes all message forwarders and precalculates the supporetedmessages bit array
+ void Initialize (const MessageForwarders& receivers);
+
+ // Generates the messageIndices for all MessageIdentifier's
+ // Gets the list of all message identifiers which are created by constructor of MessageIdentifier
+ // Sorts the messages by name and builds the MessageNameToIndex and m_MessageIDToIdentifier maps.
+ void InitializeMessageIdentifiers ();
+
+ // Returns true if a message callback exists for the class and the messageID
+ bool HasMessageCallback (int classID, int messageID) { return m_SupportedMessages.test (messageID * m_ClassCount + classID); }
+
+ // Returns true a message callback exists and the message will actually be handled.
+ // This is used to find out if a message will *actually* be forwared, eg. HasMessageCallback will always return true
+ // for eg. ScriptBehaviours which checks at runtime if the message is supported by the script.
+ bool WillHandleMessage (void* receiver, int classID, int messageID);
+
+ /// Forwards a message to the appropriate MessageForwarder
+ void HandleMessage (void* receiver, int classID, int messageID, MessageData& messageData)
+ {
+ AssertIf (classID >= m_ClassCount);
+ SET_ALLOC_OWNER(NULL);
+ m_Forwarder[classID].HandleMessage (receiver, messageID, messageData);
+ }
+
+ void SetMessageEnabled (int classID, int messageID, bool enabled)
+ {
+ // You are probably doing something wrong if you enable/disable a message twice
+ DebugAssertIf(m_SupportedMessages[messageID * m_ClassCount + classID] == enabled);
+ m_SupportedMessages[messageID * m_ClassCount + classID] = enabled;
+ }
+
+ // Converts a message name to an ID if the name is not registered returns -1
+ int MessageNameToID (const std::string& name);
+ // Converts a messageID to its message name. The messageID has to exist
+ const char* MessageIDToName (int messageID);
+ // Converts a messageID to its parameter eg. ClassID (float). The messageID has to exist
+ int MessageIDToParameter (int messageID);
+ MessageIdentifier MessageIDToMessageIdentifier (int messageID);
+
+ // Returns the number of registered messages
+ int GetMessageCount () { return m_MessageCount; }
+};
+
+#endif
diff --git a/Runtime/BaseClasses/MessageIdentifier.cpp b/Runtime/BaseClasses/MessageIdentifier.cpp
new file mode 100644
index 0000000..fc55509
--- /dev/null
+++ b/Runtime/BaseClasses/MessageIdentifier.cpp
@@ -0,0 +1,86 @@
+#include "UnityPrefix.h"
+#include "MessageIdentifier.h"
+using namespace std;
+
+MessageIdentifier::RegisteredMessages* gRegisteredMessageIdentifiers = NULL;
+
+MessageIdentifier::MessageIdentifier (const char* name, Options opts, int classId, const char* scriptParamName)
+{
+ AssertIf (name == NULL);
+
+ messageName = name;
+ parameterClassId = classId;
+ scriptParameterName = scriptParamName;
+ messageID = -1;
+ options = (int)opts;
+ if (gRegisteredMessageIdentifiers == NULL)
+ gRegisteredMessageIdentifiers = new RegisteredMessages();
+
+ gRegisteredMessageIdentifiers->push_back (this);
+}
+
+MessageIdentifier::RegisteredMessages& MessageIdentifier::GetRegisteredMessages ()
+{
+ AssertIf (gRegisteredMessageIdentifiers == NULL);
+ return *gRegisteredMessageIdentifiers;
+}
+
+MessageIdentifier::SortedMessages MessageIdentifier::GetSortedMessages (bool notificationMessages)
+{
+ // Build sorted Messages map. Which contains all messages sorted by name.
+ SortedMessages sortedMessages;
+ RegisteredMessages& messages = GetRegisteredMessages();
+ RegisteredMessages::iterator j;
+ for (j = messages.begin ();j != messages.end ();j++)
+ {
+ MessageIdentifier& identifier = **j;
+ AssertIf (identifier.messageName == NULL);
+
+ bool usesNotifications = identifier.options & kUseNotificationManager;
+ if (usesNotifications != notificationMessages)
+ continue;
+
+ SortedMessages::iterator found = sortedMessages.find (identifier.messageName);
+ if (found == sortedMessages.end ())
+ {
+ sortedMessages.insert (make_pair (string (identifier.messageName), identifier));
+ }
+ else
+ {
+ if (identifier.parameterClassId != found->second.parameterClassId)
+ {
+ string error = "There are conflicting definitions of the message: ";
+ error += identifier.messageName;
+ error += ". The parameter of one message has to be the same across all definitions of that message.";
+ ErrorString (error);
+ }
+
+ if (identifier.scriptParameterName != found->second.scriptParameterName)
+ {
+ string error = "There are conflicting definitions of the message: ";
+ error += identifier.messageName;
+ error += ". The parameter of one message has to be the same across all definitions of that message.";
+ ErrorString (error);
+ }
+
+ if (identifier.options != found->second.options)
+ {
+ string error = "There are conflicting options of the message: ";
+ error += identifier.messageName;
+ ErrorString (error);
+ }
+ }
+ }
+ return sortedMessages;
+}
+
+void MessageIdentifier::Cleanup ()
+{
+ delete gRegisteredMessageIdentifiers;
+}
+
+#include "Runtime/Dynamics/Collider.h"
+#undef MESSAGE_IDENTIFIER
+#define MESSAGE_IDENTIFIER(n,p) const EXPORT_COREMODULE MessageIdentifier n p
+#include "MessageIdentifiers.h"
+
diff --git a/Runtime/BaseClasses/MessageIdentifier.h b/Runtime/BaseClasses/MessageIdentifier.h
new file mode 100644
index 0000000..9469ef8
--- /dev/null
+++ b/Runtime/BaseClasses/MessageIdentifier.h
@@ -0,0 +1,109 @@
+#ifndef MESSAGEIDENTIFIER_H
+#define MESSAGEIDENTIFIER_H
+
+#include <list>
+#include <typeinfo>
+#include "Runtime/Utilities/LogAssert.h"
+#include "Runtime/Misc/Allocator.h"
+#include <map>
+#include "Runtime/Allocator/MemoryMacros.h"
+#include "Runtime/Scripting/Backend/ScriptingTypes.h"
+#include "Runtime/BaseClasses/ObjectDefines.h"
+#include "Runtime/BaseClasses/ClassIDs.h"
+
+struct MessageData
+{
+ int type;
+private:
+ // Note: on Metro WinRT types cannot be located in union, so don't use union!
+ intptr_t data;
+ ScriptingObjectPtr scriptingObjectData;
+public:
+ MessageData () : scriptingObjectData(SCRIPTING_NULL)
+ {
+ data = 0; type = 0;
+ }
+
+ template<class T>
+ void SetData (T inData, int classId)
+ {
+ // Check if SetData is used instead of SetScriptingObjectData
+ Assert (type != ClassID (MonoObject));
+ AssertIf (sizeof (T) > sizeof (data)); // increase the data size
+ *reinterpret_cast<T*> (&data) = *reinterpret_cast<T*> (&inData);
+ type = classId;
+ }
+
+ template<class T>
+ T GetData ()
+ {
+ // Check if GetData is used instead of GetScriptingObjectData
+ Assert (type != ClassID (MonoObject));
+ return *reinterpret_cast<T*> (&data);
+ }
+
+ intptr_t& GetGenericDataRef ()
+ {
+ // Check if GetGenericDataRef is used instead of GetScriptingObjectData
+ Assert (type != ClassID (MonoObject));
+ return data;
+ }
+
+ void SetScriptingObjectData (ScriptingObjectPtr inData)
+ {
+ scriptingObjectData = inData;
+ type = ClassID (MonoObject);
+ }
+
+ ScriptingObjectPtr GetScriptingObjectData ()
+ {
+ Assert (type == ClassID (MonoObject));
+ return scriptingObjectData;
+ }
+
+};
+
+// usage:
+// MessageIdentifier kOnTransformChanged ("OnTransformChanged", MessageIdentifier::kDontSendToScripts);
+// MessageIdentifier kOnTransformChanged ("OnTransformChanged", MessageIdentifier::kDontSendToScripts, ClassID (int));
+
+
+class MessageIdentifier
+{
+ public:
+
+ enum Options { kDontSendToScripts = 0, kSendToScripts = 1 << 0, kUseNotificationManager = 1 << 1, kDontSendToDisabled = 1 << 2 };
+
+ const char* messageName;
+ const char* scriptParameterName;
+ int messageID;
+ int parameterClassId;
+ int options;
+
+ /// Place the MessageIdentifier as a global variable!
+ /// The constructor must be called before InitializeEngine
+ explicit MessageIdentifier (const char* name, Options opt, int classId = 0, const char* scriptParamName = NULL);
+
+ typedef std::list<MessageIdentifier*, STL_ALLOCATOR(kMemPermanent, MessageIdentifier*) > RegisteredMessages;
+ typedef std::map<std::string, MessageIdentifier> SortedMessages;
+
+ // All registered message identifiers
+ static RegisteredMessages& GetRegisteredMessages ();
+ // Sorted list of message identifiers
+ // - Duplicate message identifiers are ignored
+ // - Only notification messages are returned if onlyNotificationMessages otherwise only normal messages are returned (See kUseNotificationManager)
+ static SortedMessages GetSortedMessages (bool onlyNotificationMessages);
+
+ static void Cleanup ();
+
+ // Only to be used by subclasses
+ MessageIdentifier ()
+ {
+ messageID = -1; scriptParameterName = NULL; messageName = NULL;
+ options = kSendToScripts;
+ }
+};
+
+#include "MessageIdentifiers.h"
+
+#endif
diff --git a/Runtime/BaseClasses/MessageIdentifiers.h b/Runtime/BaseClasses/MessageIdentifiers.h
new file mode 100644
index 0000000..3d285ce
--- /dev/null
+++ b/Runtime/BaseClasses/MessageIdentifiers.h
@@ -0,0 +1,86 @@
+#ifndef MESSAGE_IDENTIFIER
+#define MESSAGE_IDENTIFIER(n,p) const extern EXPORT_COREMODULE MessageIdentifier n
+#endif
+
+// NOTE: Whether messages are sent to scripts at all or sent to disabled scripts is determined on a per callback basis here,
+// make sure you set MessageIdentifier::Options appropriately for your message, leaving out kDontSendToDisabled will
+// mean that script code in the callback function will be executed regardless of whether the script is enabled or not.
+
+MESSAGE_IDENTIFIER(kEnterTrigger, ("OnTriggerEnter", MessageIdentifier::kSendToScripts, ClassID (Collider)));
+MESSAGE_IDENTIFIER(kExitTrigger, ("OnTriggerExit", MessageIdentifier::kSendToScripts, ClassID (Collider)));
+MESSAGE_IDENTIFIER(kStayTrigger, ("OnTriggerStay", MessageIdentifier::kSendToScripts, ClassID (Collider)));
+MESSAGE_IDENTIFIER(kEnterContact, ("OnCollisionEnter", MessageIdentifier::kSendToScripts, ClassID (Collision)));
+MESSAGE_IDENTIFIER(kExitContact, ("OnCollisionExit", MessageIdentifier::kSendToScripts, ClassID (Collision)));
+MESSAGE_IDENTIFIER(kStayContact, ("OnCollisionStay", MessageIdentifier::kSendToScripts, ClassID (Collision)));
+MESSAGE_IDENTIFIER(kCollisionEnter2D, ("OnCollisionEnter2D", MessageIdentifier::kSendToScripts, ClassID (Collision2D)));
+MESSAGE_IDENTIFIER(kCollisionExit2D, ("OnCollisionExit2D", MessageIdentifier::kSendToScripts, ClassID (Collision2D)));
+MESSAGE_IDENTIFIER(kCollisionStay2D, ("OnCollisionStay2D", MessageIdentifier::kSendToScripts, ClassID (Collision2D)));
+MESSAGE_IDENTIFIER(kTriggerEnter2D, ("OnTriggerEnter2D", MessageIdentifier::kSendToScripts, ClassID (Collider2D)));
+MESSAGE_IDENTIFIER(kTriggerExit2D, ("OnTriggerExit2D", MessageIdentifier::kSendToScripts, ClassID (Collider2D)));
+MESSAGE_IDENTIFIER(kTriggerStay2D, ("OnTriggerStay2D", MessageIdentifier::kSendToScripts, ClassID (Collider2D)));
+MESSAGE_IDENTIFIER(kJointBreak, ("OnJointBreak", MessageIdentifier::kSendToScripts, ClassID (float)));
+MESSAGE_IDENTIFIER(kTransformChanged, ("OnTransformChanged", MessageIdentifier::kDontSendToScripts, ClassID (int)));
+MESSAGE_IDENTIFIER(kParticleCollisionEvent, ("OnParticleCollision", MessageIdentifier::kSendToScripts, ClassID (GameObject)));
+MESSAGE_IDENTIFIER(kDidModifyValidity, ("OnDidModifyMeshValidity", MessageIdentifier::kDontSendToScripts));
+MESSAGE_IDENTIFIER(kDidDeleteMesh, ("OnDidModifyMeshDelete", MessageIdentifier::kDontSendToScripts, ClassID (Mesh)));
+MESSAGE_IDENTIFIER(kDidModifyBounds, ("OnDidModifyMeshBounds", MessageIdentifier::kDontSendToScripts));
+MESSAGE_IDENTIFIER(kDidModifyMesh, ("OnDidModifyMesh", MessageIdentifier::kDontSendToScripts));
+MESSAGE_IDENTIFIER(kLayerChanged, ("OnLayersChanged", MessageIdentifier::kDontSendToScripts));
+MESSAGE_IDENTIFIER(kDestroyedComponentNotification, ("OnDestroyedComponent", MessageIdentifier::kUseNotificationManager));
+MESSAGE_IDENTIFIER(kDidAddComponent , ("OnDidAddComponent", MessageIdentifier::kDontSendToScripts, ClassID (Component)));
+MESSAGE_IDENTIFIER(kBecameVisible, ("OnBecameVisible", MessageIdentifier::kSendToScripts));
+MESSAGE_IDENTIFIER(kBecameInvisible, ("OnBecameInvisible", MessageIdentifier::kSendToScripts));
+MESSAGE_IDENTIFIER(kOnWillRenderObject, ("OnWillRenderObject", (MessageIdentifier::Options)(MessageIdentifier::kSendToScripts|MessageIdentifier::kDontSendToDisabled)));
+MESSAGE_IDENTIFIER(kPreCull, ("OnPreCull", (MessageIdentifier::Options)(MessageIdentifier::kSendToScripts|MessageIdentifier::kDontSendToDisabled)));
+MESSAGE_IDENTIFIER(kPostRender, ("OnPostRender", (MessageIdentifier::Options)(MessageIdentifier::kSendToScripts|MessageIdentifier::kDontSendToDisabled)));
+MESSAGE_IDENTIFIER(kPreRender, ("OnPreRender", (MessageIdentifier::Options)(MessageIdentifier::kSendToScripts|MessageIdentifier::kDontSendToDisabled)));
+MESSAGE_IDENTIFIER(kControllerColliderHit, ("OnControllerColliderHit", MessageIdentifier::kSendToScripts, ClassID (MonoObject)));
+MESSAGE_IDENTIFIER(kAnimatorMove, ("OnAnimatorMove", (MessageIdentifier::Options)(MessageIdentifier::kSendToScripts|MessageIdentifier::kDontSendToDisabled)));
+MESSAGE_IDENTIFIER(kAnimatorMoveBuiltin, ("OnAnimatorMoveBuiltin", MessageIdentifier::kDontSendToScripts, ClassID(RootMotionData)));
+MESSAGE_IDENTIFIER(kAnimatorIK, ("OnAnimatorIK", (MessageIdentifier::Options)(MessageIdentifier::kSendToScripts|MessageIdentifier::kDontSendToDisabled), ClassID (int)));
+MESSAGE_IDENTIFIER(kForceRecreateCollider, ("ForceRecreateCollider", MessageIdentifier::kDontSendToScripts));
+MESSAGE_IDENTIFIER(kRecreateRigidBodyDependencies2D, ("RecreateRigidBodyDependencies2D", MessageIdentifier::kDontSendToScripts, ClassID (Rigidbody2D)));
+MESSAGE_IDENTIFIER(kServerInitialized, ("OnServerInitialized", MessageIdentifier::kSendToScripts, ClassID (int), "NetworkPlayer"));
+MESSAGE_IDENTIFIER(kPlayerConnected, ("OnPlayerConnected", MessageIdentifier::kSendToScripts, ClassID (int), "NetworkPlayer"));
+MESSAGE_IDENTIFIER(kConnectedToServer, ("OnConnectedToServer", MessageIdentifier::kSendToScripts));
+MESSAGE_IDENTIFIER(kPlayerDisconnected, ("OnPlayerDisconnected", MessageIdentifier::kSendToScripts, ClassID (int), "NetworkPlayer"));
+MESSAGE_IDENTIFIER(kDisconnectedFromServer, ("OnDisconnectedFromServer", MessageIdentifier::kSendToScripts, ClassID (int), "NetworkDisconnection"));
+MESSAGE_IDENTIFIER(kConnectionAttemptFailed, ("OnFailedToConnect", MessageIdentifier::kSendToScripts, ClassID (int), "NetworkConnectionError"));
+MESSAGE_IDENTIFIER(kMasterServerConnectionAttemptFailed, ("OnFailedToConnectToMasterServer", MessageIdentifier::kSendToScripts, ClassID (int), "NetworkConnectionError"));
+MESSAGE_IDENTIFIER(kDisconnectedFromMasterServer, ("OnDisconnectedFromMasterServer", MessageIdentifier::kSendToScripts, ClassID (int), "NetworkDisconnection"));
+MESSAGE_IDENTIFIER(kMasterServerEvent, ("OnMasterServerEvent", MessageIdentifier::kSendToScripts, ClassID (int), "MasterServerEvent"));
+MESSAGE_IDENTIFIER(kLevelWasLoaded, ("OnLevelWasLoaded", MessageIdentifier::kSendToScripts, ClassID (int)));
+MESSAGE_IDENTIFIER(kPlayerPause, ("OnApplicationPause", MessageIdentifier::kSendToScripts, ClassID (bool)));
+MESSAGE_IDENTIFIER(kPlayerFocus, ("OnApplicationFocus", MessageIdentifier::kSendToScripts, ClassID (bool)));
+MESSAGE_IDENTIFIER(kPlayerQuit, ("OnApplicationQuit", MessageIdentifier::kSendToScripts));
+MESSAGE_IDENTIFIER(kTerrainChanged, ("OnTerrainChanged", MessageIdentifier::kSendToScripts, ClassID (int), "TerrainChangedFlags")); // Investigate getting rid of these
+MESSAGE_IDENTIFIER(kSetLightmapIndex, ("SetLightmapIndex", MessageIdentifier::kSendToScripts, ClassID (int))); //
+MESSAGE_IDENTIFIER(kShiftLightmapIndex, ("ShiftLightmapIndex", MessageIdentifier::kSendToScripts, ClassID (int))); //
+MESSAGE_IDENTIFIER(kDidModifyAnimatorController, ("OnDidModifyAnimatorController", MessageIdentifier::kDontSendToScripts));
+MESSAGE_IDENTIFIER(kDidModifyMotion, ("OnDidModifyMotion", MessageIdentifier::kDontSendToScripts));
+MESSAGE_IDENTIFIER(kDidVelocityChange, ("OnDidVelocityChange", MessageIdentifier::kDontSendToDisabled, ClassID (Vector3f)));
+MESSAGE_IDENTIFIER(kDidModifyAvatar, ("OnDidModifyAvatar", MessageIdentifier::kDontSendToScripts));
+
+#if ENABLE_NEW_EVENT_SYSTEM
+
+#ifndef SEND_TO_SCRIPTS
+#define SEND_TO_SCRIPTS (MessageIdentifier::Options)(MessageIdentifier::kSendToScripts | MessageIdentifier::kDontSendToDisabled)
+#endif
+
+MESSAGE_IDENTIFIER(kOnMouseEnterEvent, ("OnMouseEnterEvent", SEND_TO_SCRIPTS));
+MESSAGE_IDENTIFIER(kOnMouseExitEvent, ("OnMouseExitEvent", SEND_TO_SCRIPTS));
+MESSAGE_IDENTIFIER(kOnMouseMoveEvent, ("OnMouseMoveEvent", SEND_TO_SCRIPTS));
+MESSAGE_IDENTIFIER(kOnPressEvent, ("OnPressEvent", SEND_TO_SCRIPTS));
+MESSAGE_IDENTIFIER(kOnReleaseEvent, ("OnReleaseEvent", SEND_TO_SCRIPTS));
+MESSAGE_IDENTIFIER(kOnDragEvent, ("OnDragEvent", SEND_TO_SCRIPTS));
+MESSAGE_IDENTIFIER(kOnDropEvent, ("OnDropEvent", SEND_TO_SCRIPTS));
+MESSAGE_IDENTIFIER(kOnDragEnterEvent, ("OnDragEnterEvent", SEND_TO_SCRIPTS));
+MESSAGE_IDENTIFIER(kOnDragExitEvent, ("OnDragExitEvent", SEND_TO_SCRIPTS));
+MESSAGE_IDENTIFIER(kOnClickEvent, ("OnClickEvent", SEND_TO_SCRIPTS));
+MESSAGE_IDENTIFIER(kOnKeyEvent, ("OnKeyEvent", SEND_TO_SCRIPTS));
+MESSAGE_IDENTIFIER(kOnSelectEvent, ("OnSelectEvent", SEND_TO_SCRIPTS));
+MESSAGE_IDENTIFIER(kOnDeselectEvent, ("OnDeselectEvent", SEND_TO_SCRIPTS));
+MESSAGE_IDENTIFIER(kOnScrollEvent, ("OnScrollEvent", SEND_TO_SCRIPTS));
+//MESSAGE_IDENTIFIER(kOnShowTooltip, ("OnShowTooltip", SEND_TO_SCRIPTS));
+//MESSAGE_IDENTIFIER(kOnHideTooltip, ("OnHideTooltip", SEND_TO_SCRIPTS));
+#endif
diff --git a/Runtime/BaseClasses/NamedObject.cpp b/Runtime/BaseClasses/NamedObject.cpp
new file mode 100644
index 0000000..41acc3a
--- /dev/null
+++ b/Runtime/BaseClasses/NamedObject.cpp
@@ -0,0 +1,33 @@
+#include "UnityPrefix.h"
+#include "Runtime/Serialize/TransferFunctions/SerializeTransfer.h"
+#include "NamedObject.h"
+#include "Runtime/Containers/ConstantStringSerialization.h"
+
+NamedObject::NamedObject (MemLabelId label, ObjectCreationMode mode)
+: Super(label, mode)
+{
+}
+
+NamedObject::~NamedObject ()
+{
+}
+
+template<class TransferFunction>
+void NamedObject::Transfer (TransferFunction& transfer)
+{
+ Super::Transfer (transfer);
+ TransferConstantString(m_Name, "m_Name", kHideInEditorMask, GetMemoryLabel(), transfer);
+}
+
+void NamedObject::SetName (char const* name)
+{
+ if (strcmp (m_Name.c_str (), name) != 0)
+ {
+ m_Name.assign (name, GetMemoryLabel());
+ SetDirty ();
+ }
+}
+
+IMPLEMENT_CLASS (NamedObject)
+IMPLEMENT_OBJECT_SERIALIZE (NamedObject)
+INSTANTIATE_TEMPLATE_TRANSFER_EXPORTED(NamedObject) \ No newline at end of file
diff --git a/Runtime/BaseClasses/NamedObject.h b/Runtime/BaseClasses/NamedObject.h
new file mode 100644
index 0000000..7355dbc
--- /dev/null
+++ b/Runtime/BaseClasses/NamedObject.h
@@ -0,0 +1,23 @@
+#ifndef NAMEDOBJECT_H
+#define NAMEDOBJECT_H
+
+#include "EditorExtension.h"
+#include "Runtime/Containers/ConstantString.h"
+
+class EXPORT_COREMODULE NamedObject : public EditorExtension
+{
+ public:
+
+ virtual char const* GetName () const { return m_Name.c_str (); }
+ virtual void SetName (char const* name);
+
+ REGISTER_DERIVED_ABSTRACT_CLASS (NamedObject, EditorExtension)
+ DECLARE_OBJECT_SERIALIZE (NamedObject)
+
+ NamedObject (MemLabelId label, ObjectCreationMode mode);
+ protected:
+
+ ConstantString m_Name;
+};
+
+#endif
diff --git a/Runtime/BaseClasses/ObjectDefines.h b/Runtime/BaseClasses/ObjectDefines.h
new file mode 100644
index 0000000..71550e0
--- /dev/null
+++ b/Runtime/BaseClasses/ObjectDefines.h
@@ -0,0 +1,202 @@
+#ifndef OBJECTDEFINES_H
+#define OBJECTDEFINES_H
+
+#include "Runtime/Allocator/BaseAllocator.h"
+#include "Configuration/UnityConfigure.h"
+#include "Runtime/Allocator/MemoryMacros.h"
+
+#define NEW_OBJECT(class_) reinterpret_cast<class_*> (::Object::AllocateAndAssignInstanceID( UNITY_NEW_AS_ROOT ( class_(kMemBaseObject, kCreateObjectDefault), kMemBaseObject, NULL, NULL) ))
+#define NEW_OBJECT_USING_MEMLABEL(class_, memlabel_) reinterpret_cast<class_*> (::Object::AllocateAndAssignInstanceID( UNITY_NEW_AS_ROOT ( class_(memlabel_, kCreateObjectDefault), memlabel_, NULL, NULL) ))
+#define NEW_OBJECT_MAIN_THREAD(class_) reinterpret_cast<class_*> (::Object::AllocateAndAssignInstanceID(UNITY_NEW_AS_ROOT ( class_(kMemBaseObject, kCreateObjectDefault), kMemBaseObject, NULL, NULL) ))
+#define NEW_OBJECT_FULL(class_,param) UNITY_NEW_AS_ROOT( class_(kMemBaseObject, param), kMemBaseObject, NULL, NULL)
+
+#define NEW_OBJECT_RESET_AND_AWAKE(class_) ResetAndAwake (NEW_OBJECT (class_))
+
+// Every non-abstract class that is derived from object has to place this inside the class Declaration
+// (REGISTER_DERIVED_CLASS (Foo, Object))
+#define REGISTER_DERIVED_CLASS(x, d) \
+public: \
+ virtual int GetClassIDVirtualInternal () const; \
+ static int GetClassIDStatic () { return ClassID (x); } \
+ static const char* GetClassStringStatic (){ return #x; } \
+ static const char* GetPPtrTypeString () { return "PPtr<"#x">"; } \
+ static bool IsAbstract () { return false; }\
+ static Object* PRODUCE (MemLabelId label, ObjectCreationMode mode) { return UNITY_NEW_AS_ROOT( x (label, mode), label, NULL, NULL); } \
+ typedef d Super; \
+ static void RegisterClass (); \
+ protected: \
+ ~x (); \
+ public:
+
+
+// Every abstract class that is derived from object has to place this inside the class Declaration
+// (REGISTER_DERIVED_ABSTRACT_CLASS (Foo, Object))
+#define REGISTER_DERIVED_ABSTRACT_CLASS(x, d) \
+ public: \
+ virtual int GetClassIDVirtualInternal () const; \
+ static int GetClassIDStatic () { return ClassID (x); } \
+ static Object* PRODUCE (MemLabelId, ObjectCreationMode) { AssertString ("Can't produce abstract class"); return NULL; } \
+ static bool IsAbstract () { return true; }\
+ static const char* GetClassStringStatic (){ return #x; } \
+ static const char* GetPPtrTypeString () { return "PPtr<"#x">"; } \
+ typedef d Super; \
+ static void RegisterClass (); \
+ protected: \
+ ~x (); \
+ public:
+
+typedef void RegisterClassCallback ();
+void EXPORT_COREMODULE RegisterInitializeClassCallback (int classID,
+ RegisterClassCallback* registerClass,
+ RegisterClassCallback* initClass,
+ RegisterClassCallback* postInitClass,
+ RegisterClassCallback* cleanupClass);
+
+
+#if DEBUGMODE
+#define VERIFY_OBJECT_IS_REGISTERED(x) \
+struct IMPLEMENT_CONSTRUCTOR_CLASS##x { IMPLEMENT_CONSTRUCTOR_CLASS##x () { AddVerifyClassRegistration (ClassID (x)); } }; \
+IMPLEMENT_CONSTRUCTOR_CLASS##x gVAR_CONSTRUCTOR_CLASS##x;
+
+#else
+#define VERIFY_OBJECT_IS_REGISTERED(x)
+#endif
+
+#define IMPLEMENT_CLASS_FULL(x, INIT, POSTINIT, CLEANUP) \
+VERIFY_OBJECT_IS_REGISTERED(x) \
+void RegisterClass_##x () { RegisterInitializeClassCallback (ClassID (x), x::RegisterClass, INIT, POSTINIT, CLEANUP); } \
+void x::RegisterClass () \
+{ \
+ Assert(!Super::IsSealedClass ()); \
+ if (Object::ClassIDToRTTI (Super::GetClassIDStatic ()) == NULL) \
+ Super::RegisterClass (); \
+ Object::RegisterClass (ClassID (x), Super::GetClassIDStatic (), #x, sizeof (x), PRODUCE, IsAbstract ()); \
+} \
+int x::GetClassIDVirtualInternal () const { return ClassID (x); }
+
+#define IMPLEMENT_CLASS(x) IMPLEMENT_CLASS_FULL(x, NULL, NULL, NULL)
+#define IMPLEMENT_CLASS_HAS_INIT(x) IMPLEMENT_CLASS_FULL(x, x::InitializeClass, NULL, x::CleanupClass)
+#define IMPLEMENT_CLASS_HAS_POSTINIT(x) IMPLEMENT_CLASS_FULL(x, x::InitializeClass, x::PostInitializeClass, x::CleanupClass)
+#define IMPLEMENT_CLASS_INIT_ONLY(x) IMPLEMENT_CLASS_FULL(x, x::InitializeClass, NULL, NULL)
+
+// Should be placed in every serializable object derived class (DECLARE_OBJECT_SERIALIZE (Transform))
+#if UNITY_EDITOR
+ #define DECLARE_OBJECT_SERIALIZE(x) \
+ static const char* GetTypeString () { return GetClassStringStatic(); } \
+ static bool IsAnimationChannel () { return false; } \
+ static bool MightContainPPtr () { return true; } \
+ static bool AllowTransferOptimization () { return false; } \
+ template<class TransferFunction> void Transfer (TransferFunction& transfer); \
+ virtual void VirtualRedirectTransfer (ProxyTransfer& transfer); \
+ virtual void VirtualRedirectTransfer (SafeBinaryRead& transfer); \
+ virtual void VirtualRedirectTransfer (StreamedBinaryWrite<false>& transfer);\
+ virtual void VirtualRedirectTransfer (StreamedBinaryWrite<true>& transfer);\
+ virtual void VirtualRedirectTransfer (StreamedBinaryRead<false>& transfer); \
+ virtual void VirtualRedirectTransfer (StreamedBinaryRead<true>& transfer); \
+ virtual void VirtualRedirectTransfer (RemapPPtrTransfer& transfer); \
+ virtual void VirtualRedirectTransfer (YAMLRead& transfer); \
+ virtual void VirtualRedirectTransfer (YAMLWrite& transfer);
+#elif SUPPORT_SERIALIZED_TYPETREES
+ #define DECLARE_OBJECT_SERIALIZE(x) \
+ static const char* GetTypeString () { return GetClassStringStatic(); } \
+ static bool IsAnimationChannel () { return false; } \
+ static bool MightContainPPtr () { return true; } \
+ static bool AllowTransferOptimization () { return false; } \
+ template<class TransferFunction> void Transfer (TransferFunction& transfer); \
+ virtual void VirtualRedirectTransfer (ProxyTransfer& transfer); \
+ virtual void VirtualRedirectTransfer (SafeBinaryRead& transfer); \
+ virtual void VirtualRedirectTransfer (StreamedBinaryRead<false>& transfer); \
+ virtual void VirtualRedirectTransfer (StreamedBinaryRead<true>& transfer); \
+ virtual void VirtualRedirectTransfer (StreamedBinaryWrite<false>& transfer); \
+ virtual void VirtualRedirectTransfer (RemapPPtrTransfer& transfer);
+#else
+ #define DECLARE_OBJECT_SERIALIZE(x) \
+ static const char* GetTypeString () { return GetClassStringStatic(); } \
+ static bool IsAnimationChannel () { return false; } \
+ static bool MightContainPPtr () { return true; } \
+ static bool AllowTransferOptimization () { return false; } \
+ template<class TransferFunction> void Transfer (TransferFunction& transfer); \
+ virtual void VirtualRedirectTransfer (ProxyTransfer& transfer); \
+ virtual void VirtualRedirectTransfer (StreamedBinaryRead<false>& transfer); \
+ virtual void VirtualRedirectTransfer (StreamedBinaryWrite<false>& transfer); \
+ virtual void VirtualRedirectTransfer (RemapPPtrTransfer& transfer);
+#endif
+
+// Has to be placed in the cpp file of a serializable class (IMPLEMENT_OBJECT_SERIALIZE (Transform))
+// you also have to #include "Runtime/Serialize/TransferFunctions/SerializeTransfer.h"
+
+#if UNITY_EDITOR // Editor needs to support swapped endian writing, player doesnt.
+
+#define INSTANTIATE_TEMPLATE_TRANSFER_WITH_DECL(x, decl) \
+template decl void x::Transfer(ProxyTransfer& transfer); \
+template decl void x::Transfer(SafeBinaryRead& transfer); \
+template decl void x::Transfer(StreamedBinaryRead<false>& transfer); \
+template decl void x::Transfer(StreamedBinaryRead<true>& transfer); \
+template decl void x::Transfer(StreamedBinaryWrite<false>& transfer); \
+template decl void x::Transfer(StreamedBinaryWrite<true>& transfer); \
+template decl void x::Transfer(RemapPPtrTransfer& transfer); \
+template decl void x::Transfer(YAMLRead& transfer); \
+template decl void x::Transfer(YAMLWrite& transfer);
+
+#define IMPLEMENT_OBJECT_SERIALIZE(x) \
+void x::VirtualRedirectTransfer (ProxyTransfer& transfer) { transfer.Transfer (*this, "Base"); } \
+void x::VirtualRedirectTransfer (SafeBinaryRead& transfer) { SET_ALLOC_OWNER(this); transfer.Transfer (*this, "Base"); } \
+void x::VirtualRedirectTransfer (StreamedBinaryRead<false>& transfer) { SET_ALLOC_OWNER(this); transfer.Transfer (*this, "Base"); } \
+void x::VirtualRedirectTransfer (StreamedBinaryRead<true>& transfer) { SET_ALLOC_OWNER(this); transfer.Transfer (*this, "Base"); } \
+void x::VirtualRedirectTransfer (RemapPPtrTransfer& transfer) { transfer.Transfer (*this, "Base"); } \
+void x::VirtualRedirectTransfer (StreamedBinaryWrite<false>& transfer) { transfer.Transfer (*this, "Base"); } \
+void x::VirtualRedirectTransfer (StreamedBinaryWrite<true>& transfer) { transfer.Transfer (*this, "Base"); } \
+void x::VirtualRedirectTransfer (YAMLRead& transfer) { SET_ALLOC_OWNER(this); transfer.Transfer (*this, "Base"); } \
+void x::VirtualRedirectTransfer (YAMLWrite& transfer) { transfer.Transfer (*this, "Base"); } \
+
+#elif SUPPORT_SERIALIZED_TYPETREES
+#define INSTANTIATE_TEMPLATE_TRANSFER_WITH_DECL(x, decl) \
+template decl void x::Transfer(ProxyTransfer& transfer); \
+template decl void x::Transfer(SafeBinaryRead& transfer); \
+template decl void x::Transfer(StreamedBinaryRead<false>& transfer); \
+template decl void x::Transfer(StreamedBinaryRead<true>& transfer); \
+template decl void x::Transfer(StreamedBinaryWrite<false>& transfer); \
+template decl void x::Transfer(RemapPPtrTransfer& transfer);
+
+ #define IMPLEMENT_OBJECT_SERIALIZE(x) \
+ void x::VirtualRedirectTransfer (ProxyTransfer& transfer) { transfer.Transfer (*this, "Base"); } \
+ void x::VirtualRedirectTransfer (SafeBinaryRead& transfer) { SET_ALLOC_OWNER(this); transfer.Transfer (*this, "Base"); } \
+ void x::VirtualRedirectTransfer (StreamedBinaryRead<false>& transfer) { SET_ALLOC_OWNER(this); transfer.Transfer (*this, "Base"); } \
+ void x::VirtualRedirectTransfer (StreamedBinaryRead<true>& transfer) { SET_ALLOC_OWNER(this); transfer.Transfer (*this, "Base"); } \
+ void x::VirtualRedirectTransfer (StreamedBinaryWrite<false>& transfer) { transfer.Transfer (*this, "Base"); } \
+ void x::VirtualRedirectTransfer (RemapPPtrTransfer& transfer) { transfer.Transfer (*this, "Base"); } \
+
+#else
+#define INSTANTIATE_TEMPLATE_TRANSFER_WITH_DECL(x, decl) \
+template decl void x::Transfer(ProxyTransfer& transfer); \
+template decl void x::Transfer(StreamedBinaryRead<false>& transfer); \
+template decl void x::Transfer(StreamedBinaryWrite<false>& transfer); \
+template decl void x::Transfer(RemapPPtrTransfer& transfer);
+
+ #define IMPLEMENT_OBJECT_SERIALIZE(x) \
+ void x::VirtualRedirectTransfer (ProxyTransfer& transfer) { transfer.Transfer (*this, "Base"); } \
+ void x::VirtualRedirectTransfer (StreamedBinaryRead<false>& transfer) { SET_ALLOC_OWNER(this); transfer.Transfer (*this, "Base"); } \
+ void x::VirtualRedirectTransfer (StreamedBinaryWrite<false>& transfer) { transfer.Transfer (*this, "Base"); } \
+ void x::VirtualRedirectTransfer (RemapPPtrTransfer& transfer) { transfer.Transfer (*this, "Base"); } \
+
+#endif
+
+#if UNITY_WIN
+#define EXPORTDLL __declspec(dllexport)
+#elif UNITY_OSX
+#define EXPORTDLL __attribute__((visibility("default")))
+#else
+#define EXPORTDLL
+#endif
+
+#define INSTANTIATE_TEMPLATE_TRANSFER(x) INSTANTIATE_TEMPLATE_TRANSFER_WITH_DECL(x, )
+#define INSTANTIATE_TEMPLATE_TRANSFER_EXPORTED(x) INSTANTIATE_TEMPLATE_TRANSFER_WITH_DECL(x, EXPORTDLL)
+
+
+// Use this to make a Generic C++ GET/SET function: GET_SET (float, Velocity, m_Velocity)
+// Implements GetVelocity, SetVelocity
+#define GET_SET(TYPE,PROP_NAME,VAR_NAME) void Set##PROP_NAME (TYPE val) { VAR_NAME = val; } const TYPE Get##PROP_NAME () const {return (const TYPE)VAR_NAME; }
+#define GET_SET_DIRTY(TYPE,PROP_NAME,VAR_NAME) void Set##PROP_NAME (TYPE val) { VAR_NAME = val; SetDirty(); } const TYPE Get##PROP_NAME () const {return (const TYPE)VAR_NAME; }
+#define GET_SET_COMPARE_DIRTY(TYPE,PROP_NAME,VAR_NAME) void Set##PROP_NAME (TYPE val) { if ((TYPE)VAR_NAME == val) return; VAR_NAME = val; SetDirty(); } const TYPE Get##PROP_NAME () const {return (const TYPE)VAR_NAME; }
+
+#endif
diff --git a/Runtime/BaseClasses/RefCounted.h b/Runtime/BaseClasses/RefCounted.h
new file mode 100644
index 0000000..cbe2934
--- /dev/null
+++ b/Runtime/BaseClasses/RefCounted.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include "Configuration/UnityConfigure.h"
+#include "Runtime/Mono/MonoIncludes.h"
+#include "Runtime/Scripting/ScriptingUtility.h"
+#include "Runtime/Scripting/Backend/ScriptingBackendApi.h"
+
+class TrackedReferenceBase
+{
+public:
+ int m_MonoObjectReference;
+
+ TrackedReferenceBase ()
+ {
+ m_MonoObjectReference = 0;
+ }
+
+ ~TrackedReferenceBase ()
+ {
+#if ENABLE_SCRIPTING
+ if (m_MonoObjectReference)
+ {
+ ScriptingObjectPtr target = scripting_gchandle_get_target (m_MonoObjectReference);
+ if (target)
+ {
+ void* nativePointer = 0;
+ MarshallNativeStructIntoManaged(nativePointer,target);
+ target = SCRIPTING_NULL;
+ }
+
+ scripting_gchandle_free (m_MonoObjectReference);
+ m_MonoObjectReference = 0;
+ }
+#endif
+ }
+};
diff --git a/Runtime/BaseClasses/SupportedMessageOptimization.h b/Runtime/BaseClasses/SupportedMessageOptimization.h
new file mode 100644
index 0000000..b5a6501
--- /dev/null
+++ b/Runtime/BaseClasses/SupportedMessageOptimization.h
@@ -0,0 +1,17 @@
+#ifndef SUPPORTEDMESSAGEOPTIMIZATION_H
+#define SUPPORTEDMESSAGEOPTIMIZATION_H
+
+enum
+{
+ kHasCollisionStay = 1 << 0,
+ kHasCollisionEnterExit = 1 << 1,
+ kWantsCollisionData = 1 << 2,
+ kSupportsTransformChanged = 1 << 3,
+ kHasOnWillRenderObject = 1 << 4,
+ kSupportsVelocityChanged = 1 << 5,
+ kHasOnAnimatorMove = 1 << 6,
+ kHasOnAnimatorIK = 1 << 7,
+ kHasCollision2D = 1 << 8
+};
+
+#endif
diff --git a/Runtime/BaseClasses/Tags.cpp b/Runtime/BaseClasses/Tags.cpp
new file mode 100644
index 0000000..3a56c6f
--- /dev/null
+++ b/Runtime/BaseClasses/Tags.cpp
@@ -0,0 +1,604 @@
+#include "UnityPrefix.h"
+#include "Tags.h"
+#include "ManagerContext.h"
+#include "GameManager.h"
+#include "Runtime/Filters/Renderer.h"
+#include "Runtime/Serialize/TransferFunctions/SerializeTransfer.h"
+#include "Runtime/Threads/Mutex.h"
+#include "Runtime/Utilities/algorithm_utility.h"
+#include "Runtime/Utilities/BitUtility.h"
+#include "Runtime/Utilities/InitializeAndCleanup.h"
+#include "Runtime/Utilities/LogAssert.h"
+#include "Runtime/Utilities/GUID.h"
+#include "External/MurmurHash/MurmurHash2.h"
+#include <vector>
+
+static const char* kDefaultSortingLayerName = "Default";
+
+// -------------------------------------------------------------------
+
+
+static Object* GetTagManagerPtr ();
+
+
+typedef std::pair<const std::string, UInt32> StringUInt32Pair;
+typedef std::map<std::string, UInt32, std::less<std::string>, STL_ALLOCATOR(kMemPermanent, StringUInt32Pair) > StringToUnsigned;
+
+
+static StringToUnsigned* gStringToTag;
+static UnsignedToString* gTagToString;
+static int* gTagManagerContainer;
+
+static StringToUnsigned* gStringToMask;
+static std::string gMaskToString[32];
+static std::string gEmpty;
+
+namespace LayerTagManager
+{
+ void StaticInitialize()
+ {
+ gTagManagerContainer = UNITY_NEW_AS_ROOT(int, kMemResource, "LayerTagManager", "");
+ SET_ALLOC_OWNER(gTagManagerContainer);
+ gStringToTag = UNITY_NEW(StringToUnsigned,kMemResource);
+ gTagToString = UNITY_NEW(UnsignedToString,kMemResource);
+ gStringToMask = UNITY_NEW(StringToUnsigned,kMemResource);
+ }
+ void StaticDestroy()
+ {
+ UNITY_DELETE(gStringToTag, kMemResource);
+ UNITY_DELETE(gTagToString, kMemResource);
+ UNITY_DELETE(gStringToMask, kMemResource);
+ for(int i = 0; i < 32; i++)
+ gMaskToString[i] = std::string();
+ gEmpty = std::string();
+ UNITY_DELETE(gTagManagerContainer, kMemResource);
+ }
+}
+
+static RegisterRuntimeInitializeAndCleanup s_LayerTagManagerCallbacks(LayerTagManager::StaticInitialize, LayerTagManager::StaticDestroy);
+
+
+static void RegisterTag (UInt32 tag, const std::string& name);
+
+
+void RegisterTag (UInt32 tag, const std::string& name)
+{
+ SET_ALLOC_OWNER(gTagManagerContainer);
+ if (!gStringToTag->insert (make_pair (name, tag)).second && !name.empty ())
+ LogStringObject ("Default GameObject Tag: " + name + " already registered", GetTagManagerPtr ());
+
+ if (!gTagToString->insert (make_pair (tag, name)).second)
+ LogStringObject ("Default GameObject Tag for name: " + name + " already registered", GetTagManagerPtr ());
+}
+
+// In the editor we might add / remove tags from the gStringToTag array.
+// And we might do this from the loading thread and main thread at the same time.
+
+// In the player this map is completely fixed, thus it even if two threads access the data at the same time, the data always stays constant
+#if UNITY_EDITOR
+
+Mutex gTagToStringMutex;
+
+UInt32 StringToTagAddIfUnavailable (const std::string& tag)
+{
+ Mutex::AutoLock lock(gTagToStringMutex);
+ StringToUnsigned::iterator i = gStringToTag->find (tag);
+ if (i == gStringToTag->end ())
+ {
+ SET_ALLOC_OWNER(gTagManagerContainer);
+ int nextTagID = last_iterator(*gTagToString)->first + 1;
+ gTagToString->insert(make_pair(nextTagID, tag));
+ gStringToTag->insert(make_pair(tag, nextTagID));
+ return nextTagID;
+ }
+ else
+ return i->second;
+}
+
+#endif
+
+
+UInt32 StringToTag (const std::string& tag)
+{
+ #if UNITY_EDITOR
+ Mutex::AutoLock lock(gTagToStringMutex);
+ #endif
+
+ StringToUnsigned::iterator i = gStringToTag->find (tag);
+ if (i == gStringToTag->end ())
+ return -1;
+ else
+ return i->second;
+}
+
+const std::string& TagToString (UInt32 tag)
+{
+ #if UNITY_EDITOR
+ Mutex::AutoLock lock(gTagToStringMutex);
+ #endif
+ UnsignedToString::iterator i = gTagToString->find (tag);
+ if (i == gTagToString->end ())
+ {
+ static std::string empty;
+ return empty;
+ }
+ else
+ return i->second;
+}
+
+UInt32 StringToLayerMask (const std::string& tag)
+{
+ StringToUnsigned::iterator i = gStringToMask->find (tag);
+ if (i == gStringToMask->end ())
+ return 0;
+ else
+ return 1 << i->second;
+}
+
+UInt32 StringToLayer (const std::string& tag)
+{
+ StringToUnsigned::iterator i = gStringToMask->find (tag);
+ if (i == gStringToMask->end ())
+ return -1;
+ else
+ return i->second;
+}
+
+const std::string& LayerToString (UInt32 layer)
+{
+ if (layer >= 32)
+ {
+ ErrorString("Layer index out of bounds");
+ return gEmpty;
+ }
+ return gMaskToString[layer];
+}
+
+const std::string& LayerMaskToString (UInt32 layerMask)
+{
+ Assert (IsPowerOfTwo (layerMask));
+ if (layerMask == 0)
+ return gEmpty;
+ int layer = AnyBitFromMask (layerMask);
+ return gMaskToString[layer];
+}
+
+void RegisterLayer (UInt32 tag, const std::string& name)
+{
+ SET_ALLOC_OWNER(gTagManagerContainer);
+ if (!gStringToMask->insert (make_pair (name, tag)).second && !name.empty ())
+ LogStringObject ("Default GameObject BitMask: " + name + " already registered", GetTagManagerPtr ());
+
+ if (gMaskToString[tag].empty ())
+ gMaskToString[tag] = name;
+ else
+ LogStringObject ("Default GameObject BitMask for name: " + name + " already registered", GetTagManagerPtr ());
+}
+
+UnsignedToString GetTags ()
+{
+ // Cull out all empty string tags. (The user is allowed to add those but we dont want them to show up!)
+ UnsignedToString tags;
+ for (UnsignedToString::iterator i=gTagToString->begin ();i != gTagToString->end ();i++)
+ {
+ if (!i->second.empty ())
+ tags.insert (make_pair (i->first, i->second));
+ }
+ return tags;
+}
+
+
+// -------------------------------------------------------------------
+
+struct SortingLayerEntry
+{
+ DECLARE_SERIALIZE_NO_PPTR (SortingLayerEntry)
+
+ SortingLayerEntry() : userID(1), uniqueID(1), locked(false) { }
+ UnityStr name;
+ UInt32 userID;
+ UInt32 uniqueID;
+ bool locked;
+};
+
+template<class TransferFunc>
+void SortingLayerEntry::Transfer (TransferFunc& transfer)
+{
+ TRANSFER (name);
+ TRANSFER (userID);
+ TRANSFER (uniqueID);
+ TRANSFER_EDITOR_ONLY (locked);
+ transfer.Align();
+}
+
+class TagManager : public GlobalGameManager
+{
+public:
+ DECLARE_OBJECT_SERIALIZE (TagManager)
+ REGISTER_DERIVED_CLASS (TagManager, GlobalGameManager)
+
+ TagManager (MemLabelId label, ObjectCreationMode mode) : Super(label, mode), m_DefaultLayerIndex(0) {}
+
+ bool ShouldIgnoreInGarbageDependencyTracking () { return true; }
+
+ virtual void Update () { }
+ // virtual ~TagManager () { } declared-by-macro
+
+ void AddDefaultLayerIfNeeded();
+ void FindDefaultLayerIndex();
+
+ std::vector<SortingLayerEntry> m_SortingLayers;
+ int m_DefaultLayerIndex;
+};
+
+TagManager::~TagManager ()
+{
+}
+
+void TagManager::FindDefaultLayerIndex()
+{
+ m_DefaultLayerIndex = 0;
+ for (size_t i = 0, n = m_SortingLayers.size(); i != n; ++i)
+ {
+ if (m_SortingLayers[i].userID == 0)
+ {
+ m_DefaultLayerIndex = i;
+ break;
+ }
+ }
+}
+
+void TagManager::AddDefaultLayerIfNeeded()
+{
+ // do we have a default layer?
+ for (size_t i = 0, n = m_SortingLayers.size(); i != n; ++i)
+ {
+ if (m_SortingLayers[i].userID == 0)
+ return;
+ }
+
+ // no default layer, add one in front
+ SortingLayerEntry layer;
+ layer.name = kDefaultSortingLayerName;
+ layer.uniqueID = 0;
+ layer.userID = 0;
+ m_SortingLayers.insert(m_SortingLayers.begin(), layer);
+ m_DefaultLayerIndex = 0;
+}
+
+
+
+void RegisterDefaultTagsAndLayerMasks ()
+{
+ SET_ALLOC_OWNER(gTagManagerContainer);
+ gStringToTag->clear (); gTagToString->clear ();
+ gStringToMask->clear ();
+ for (int i=0;i<32;i++)
+ gMaskToString[i].clear ();
+ if (GetTagManagerPtr())
+ {
+ TagManager& tags = (TagManager&)GetTagManager();
+ tags.m_SortingLayers.clear();
+ // add "Default" sorting layer
+ tags.m_SortingLayers.push_back(SortingLayerEntry());
+ SortingLayerEntry& layer = tags.m_SortingLayers[0];
+ layer.name = kDefaultSortingLayerName;
+ layer.userID = 0;
+ layer.uniqueID = 0;
+ tags.m_DefaultLayerIndex = 0;
+ }
+
+ RegisterTag (kUntagged, "Untagged");
+ RegisterTag (kRespawnTag, "Respawn");
+ RegisterTag (kFinishTag, "Finish");
+ RegisterTag (kEditorOnlyTag, "EditorOnly");
+ RegisterTag (kMainCameraTag, "MainCamera");
+ RegisterTag (kGameControllerTag, "GameController");
+ RegisterTag (kPlayerTag, "Player");
+
+ RegisterLayer (kDefaultLayer, "Default");
+ RegisterLayer (kNoFXLayer, "TransparentFX");
+ RegisterLayer (kIgnoreRaycastLayer, "Ignore Raycast");
+ RegisterLayer (kWaterLayer, "Water");
+}
+
+template<class TransferFunction>
+void TagManager::Transfer (TransferFunction& transfer)
+{
+ std::vector<UnityStr> tags;
+
+ // Build tags array
+ if (transfer.IsWriting ())
+ {
+ UnsignedToString::iterator begin = gTagToString->lower_bound (kFirstUserTag);
+ UnsignedToString::iterator end = gTagToString->upper_bound (kLastUserTag);
+ for (UnsignedToString::iterator i=begin;i != end;i++)
+ tags.push_back (i->second);
+ if (tags.empty () || !tags.back ().empty ())
+ tags.push_back ("");
+ }
+ else if (transfer.IsReading ())
+ {
+ RegisterDefaultTagsAndLayerMasks ();
+ }
+
+ TRANSFER_SIMPLE (tags);
+
+ // Register tags we've read (if there actually was tag data in the stream).
+ if (transfer.DidReadLastProperty ())
+ {
+ for (int i=0;i<tags.size ();i++)
+ RegisterTag (kFirstUserTag + i, tags[i]);
+ }
+
+ // Build bitnames array
+ UnityStr bitnames[32];
+ for (int i=0;i<32;i++)
+ {
+ char name[64];
+ bool editable = i >= kUserLayer;
+ if (editable)
+ sprintf (name, "User Layer %d", i);
+ else
+ sprintf (name, "Builtin Layer %d", i);
+
+ bitnames[i] = LayerToString (i);
+ transfer.Transfer (bitnames[i], name, editable ? kNoTransferFlags : kNotEditableMask);
+
+ if (transfer.DidReadLastProperty ())
+ {
+ if (i >= kUserLayer)
+ RegisterLayer (i, bitnames[i]);
+ }
+ }
+
+ // Sorting layers
+ TRANSFER (m_SortingLayers);
+ if (!transfer.IsWriting () && transfer.IsReading())
+ {
+ AddDefaultLayerIfNeeded();
+ FindDefaultLayerIndex();
+ }
+}
+
+IMPLEMENT_CLASS (TagManager)
+IMPLEMENT_OBJECT_SERIALIZE (TagManager)
+
+Object& GetTagManager ()
+{
+ return GetManagerFromContext (ManagerContext::kTagManager);
+}
+
+static Object* GetTagManagerPtr ()
+{
+ return GetManagerPtrFromContext (ManagerContext::kTagManager);
+}
+
+
+
+// -------------------------------------------------------------------
+
+
+
+UnityStr GetSortingLayerName(int index)
+{
+ TagManager& tags = (TagManager&)GetTagManager();
+ if (index < 0 || index >= tags.m_SortingLayers.size())
+ return UnityStr();
+ return tags.m_SortingLayers[index].name;
+}
+
+UnityStr GetSortingLayerNameFromValue(int layerValue)
+{
+ TagManager& tags = (TagManager&)GetTagManager();
+ int index = tags.m_DefaultLayerIndex + layerValue;
+ if (index < 0 || index >= tags.m_SortingLayers.size())
+ return UnityStr();
+ return tags.m_SortingLayers[index].name;
+}
+
+
+int GetSortingLayerUserID(int index)
+{
+ TagManager& tags = (TagManager&)GetTagManager();
+ if (index < 0 || index >= tags.m_SortingLayers.size())
+ return 0;
+ return tags.m_SortingLayers[index].userID;
+}
+
+int GetSortingLayerUniqueIDFromValue(int layerValue)
+{
+ TagManager& tags = (TagManager&)GetTagManager();
+ int index = tags.m_DefaultLayerIndex + layerValue;
+ if (index < 0 || index >= tags.m_SortingLayers.size())
+ return 0;
+ return tags.m_SortingLayers[index].uniqueID;
+}
+
+
+int GetSortingLayerUserIDFromValue(int layerValue)
+{
+ TagManager& tags = (TagManager&)GetTagManager();
+ int index = tags.m_DefaultLayerIndex + layerValue;
+ if (index < 0 || index >= tags.m_SortingLayers.size())
+ return 0;
+ return tags.m_SortingLayers[index].userID;
+}
+
+int GetSortingLayerIndexFromValue(int layerValue)
+{
+ TagManager& tags = (TagManager&)GetTagManager();
+ int index = tags.m_DefaultLayerIndex + layerValue;
+ if (index < 0 || index >= tags.m_SortingLayers.size())
+ index = 0;
+ return index;
+}
+
+
+
+int GetSortingLayerUniqueID(int index)
+{
+ TagManager& tags = (TagManager&)GetTagManager();
+ Assert (index >= 0 && index < tags.m_SortingLayers.size());
+ return tags.m_SortingLayers[index].uniqueID;
+}
+
+UnityStr GetSortingLayerNameFromUniqueID(int id)
+{
+ if (id == 0)
+ return UnityStr(kDefaultSortingLayerName);
+
+ TagManager& tags = (TagManager&)GetTagManager();
+ for (size_t i = 0; i < tags.m_SortingLayers.size(); ++i)
+ if (tags.m_SortingLayers[i].uniqueID == id)
+ return tags.m_SortingLayers[i].name;
+
+ return "<unknown layer>";
+}
+
+int GetSortingLayerValueFromUniqueID(int id)
+{
+ if (id == 0)
+ return 0;
+
+ TagManager& tags = (TagManager&)GetTagManager();
+ for (size_t i = 0; i < tags.m_SortingLayers.size(); ++i)
+ if (tags.m_SortingLayers[i].uniqueID == id)
+ return i - tags.m_DefaultLayerIndex;
+
+ return 0; // unknown layer: treat as if no layer is assigned
+}
+
+int GetSortingLayerValueFromUserID(int id)
+{
+ if (id == 0)
+ return 0;
+
+ TagManager& tags = (TagManager&)GetTagManager();
+ for (size_t i = 0; i < tags.m_SortingLayers.size(); ++i)
+ if (tags.m_SortingLayers[i].userID == id)
+ return i - tags.m_DefaultLayerIndex;
+
+ return 0; // unknown layer: treat as if no layer is assigned
+}
+
+int GetSortingLayerValueFromName(const UnityStr& name)
+{
+ TagManager& tags = (TagManager&)GetTagManager();
+ if (name.empty())
+ return 0;
+
+ for (size_t i = 0; i < tags.m_SortingLayers.size(); ++i)
+ if (tags.m_SortingLayers[i].name == name)
+ return i - tags.m_DefaultLayerIndex;
+
+ return 0; // unknown layer: treat as default layer
+}
+
+
+#if UNITY_EDITOR
+void AddSortingLayer()
+{
+ TagManager& tags = (TagManager&)GetTagManager();
+ SortingLayerEntry s;
+
+ // internal ID should be quite unique; generate a GUID and hash to and integer
+ UnityGUID guid;
+ guid.Init();
+ s.uniqueID = MurmurHash2A(&guid.data, sizeof(guid.data), 0x8f37154b);
+ s.uniqueID |= 1; // make sure it's never zero
+
+ // user-visible ID: smallest unused one
+ int id = 1;
+ while (true)
+ {
+ bool gotIt = false;
+ for (size_t i = 0; i < tags.m_SortingLayers.size(); ++i)
+ {
+ if (tags.m_SortingLayers[i].userID == id)
+ {
+ gotIt = true;
+ break;
+ }
+ }
+ if (!gotIt)
+ break;
+ ++id;
+ }
+
+ s.name = Format("New Layer %d", id);
+ s.userID = id;
+ s.locked = false;
+
+ tags.m_SortingLayers.push_back (s);
+ tags.SetDirty();
+}
+
+
+void UpdateSortingLayersOrder()
+{
+ TagManager& tags = (TagManager&)GetTagManager();
+ tags.FindDefaultLayerIndex();
+
+ vector<SInt32> objs;
+ Object::FindAllDerivedObjects (ClassID (Renderer), &objs);
+ for (size_t i = 0, n = objs.size(); i != n; ++i)
+ {
+ Renderer* r = PPtr<Renderer> (objs[i]);
+ r->SetupSortingOverride();
+ }
+}
+
+
+void SetSortingLayerName(int index, const std::string& name)
+{
+ TagManager& tags = (TagManager&)GetTagManager();
+ Assert (index >= 0 && index < tags.m_SortingLayers.size());
+ tags.m_SortingLayers[index].name = name;
+ tags.SetDirty();
+}
+
+void SwapSortingLayers(int idx1, int idx2)
+{
+ TagManager& tags = (TagManager&)GetTagManager();
+ Assert (idx1 >= 0 && idx1 < tags.m_SortingLayers.size());
+ Assert (idx2 >= 0 && idx2 < tags.m_SortingLayers.size());
+ std::swap(tags.m_SortingLayers[idx1], tags.m_SortingLayers[idx2]);
+ UpdateSortingLayersOrder();
+ tags.SetDirty();
+}
+
+
+void SetSortingLayerLocked(int index, bool locked)
+{
+ TagManager& tags = (TagManager&)GetTagManager();
+ Assert (index >= 0 && index < tags.m_SortingLayers.size());
+ tags.m_SortingLayers[index].locked = locked;
+ tags.SetDirty();
+}
+
+bool GetSortingLayerLocked(int index)
+{
+ TagManager& tags = (TagManager&)GetTagManager();
+ if (index < 0 || index >= tags.m_SortingLayers.size())
+ return false;
+ return tags.m_SortingLayers[index].locked;
+}
+
+bool IsSortingLayerDefault(int index)
+{
+ TagManager& tags = (TagManager&)GetTagManager();
+ return index == tags.m_DefaultLayerIndex;
+}
+
+
+int g_LockedPickingLayers = 0;
+
+#endif // #if UNITY_EDITOR
+
+
+int GetSortingLayerCount()
+{
+ TagManager& tags = (TagManager&)GetTagManager();
+ return tags.m_SortingLayers.size();
+}
diff --git a/Runtime/BaseClasses/Tags.h b/Runtime/BaseClasses/Tags.h
new file mode 100644
index 0000000..9d790a9
--- /dev/null
+++ b/Runtime/BaseClasses/Tags.h
@@ -0,0 +1,104 @@
+#pragma once
+
+#include <map>
+#include <string>
+#include "Runtime/Misc/Allocator.h"
+
+class Object;
+
+enum BitMasks
+{
+ // Can't modify these without breaking backwards compatibility!
+ kDefaultLayer = 0,
+ kNoFXLayer = 1,
+ kIgnoreRaycastLayer = 2,
+ kIgnoreCollisionLayer = 3,
+ kWaterLayer = 4,
+ kNumLayers = 32,
+
+ kDefaultLayerMask = 1 << kDefaultLayer,
+ kNoFXLayerMask = 1 << kNoFXLayer,
+ kIgnoreRaycastMask = 1 << kIgnoreRaycastLayer,
+ kIgnoreCollisionMask = 1 << kIgnoreCollisionLayer,
+ kPreUnity2UnusedLayer = 1 << 5,
+
+ kUserLayer = 8,
+};
+
+enum Tags
+{
+ kUntagged = 0,
+ kRespawnTag = 1,
+ kFinishTag = 2,
+ kEditorOnlyTag = 3,
+ kMainCameraTag = 5,
+ kPlayerTag = 6,
+ kGameControllerTag = 7,
+ kFirstUserTag = 20000,
+ kLastUserTag = 30000,
+ kUndefinedTag = -1
+};
+
+// converts tag to string
+UInt32 StringToTag (const std::string& tag);
+UInt32 StringToTagAddIfUnavailable (const std::string& name);
+const std::string& TagToString (UInt32 tag);
+
+// Converts between layer [0..31] and string
+UInt32 StringToLayerMask (const std::string& layerName);
+const std::string& LayerToString (UInt32 layer);
+UInt32 StringToLayer (const std::string& layer);
+// Converts a layer mask (1 << [0..31]) to a string
+const std::string& LayerMaskToString (UInt32 mask);
+
+void RegisterLayer (UInt32 layer, const std::string& name);
+
+typedef std::pair<const UInt32, std::string> UInt32StringPair;
+typedef std::map<UInt32, std::string, std::less<UInt32>, STL_ALLOCATOR(kMemPermanent, UInt32StringPair) > UnsignedToString;
+UnsignedToString GetTags ();
+
+void RegisterDefaultTagsAndLayerMasks ();
+
+Object& GetTagManager ();
+
+
+// -------------------------------------------------------------------
+// Global sorting layers:
+//
+// Defined globally, and can be reordered in the inspector. The drawing order is as shown in the inspector.
+// Internally each global sorting layer has "unique ID" (GUID hashed into an int), and in-editor Renderers that want to
+// use them refer to the layer by this ID.
+//
+// @TODO:
+// * Do we need this "user friendly ID"?
+
+int GetSortingLayerCount();
+UnityStr GetSortingLayerName(int index);
+UnityStr GetSortingLayerNameFromUniqueID(int id);
+int GetSortingLayerUniqueID(int index);
+int GetSortingLayerUserID(int index);
+
+UnityStr GetSortingLayerNameFromValue(int layerValue);
+int GetSortingLayerUserIDFromValue(int layerValue);
+int GetSortingLayerUniqueIDFromValue(int layerValue);
+int GetSortingLayerIndexFromValue(int layerValue);
+
+// these return final sorting layer values
+// (i.e. zero is always "default" - the returned value can be negative or positive)
+int GetSortingLayerValueFromUniqueID(int id);
+int GetSortingLayerValueFromUserID(int id);
+int GetSortingLayerValueFromName(const UnityStr& name);
+
+
+#if UNITY_EDITOR
+void SetSortingLayerName(int index, const std::string& name);
+void AddSortingLayer();
+void UpdateSortingLayersOrder();
+void SetSortingLayerLocked(int index, bool locked);
+bool GetSortingLayerLocked(int index);
+bool IsSortingLayerDefault(int index);
+void SwapSortingLayers(int idx1, int idx2);
+
+extern int g_LockedPickingLayers;
+
+#endif // #if UNITY_EDITOR
diff --git a/Runtime/BaseClasses/TagsTests.cpp b/Runtime/BaseClasses/TagsTests.cpp
new file mode 100644
index 0000000..38085d4
--- /dev/null
+++ b/Runtime/BaseClasses/TagsTests.cpp
@@ -0,0 +1,109 @@
+#include "UnityPrefix.h"
+
+#if ENABLE_UNIT_TESTS
+
+#include "Tags.h"
+#include "Runtime/Testing/Testing.h"
+
+SUITE (TagsTests)
+{
+ TEST (StringToTag_TagToString_WithEmptyString_IsIdentityOperation)
+ {
+ CHECK_EQUAL ("", TagToString (StringToTag ("")));
+ }
+
+ TEST (StringToTag_TagToString_WithDefaultTag_IsIdentityOperation)
+ {
+ CHECK_EQUAL ("Untagged", TagToString (StringToTag ("Untagged")));
+ }
+
+# if UNITY_EDITOR
+ TEST (SortingLayer_UserID_Works)
+ {
+ CHECK_EQUAL (1, GetSortingLayerCount()); // only default layer initially
+
+ // add 3 layers
+ AddSortingLayer();
+ AddSortingLayer();
+ AddSortingLayer();
+ SetSortingLayerName(1, "A");
+ SetSortingLayerName(2, "B");
+ SetSortingLayerName(3, "C");
+ const int idA = GetSortingLayerUniqueID(1);
+ const int idB = GetSortingLayerUniqueID(2);
+ const int idC = GetSortingLayerUniqueID(3);
+
+ // now the order is: Default, A, B, C
+
+ // they should get 1,2,3 user IDs assigned
+ CHECK_EQUAL(1, GetSortingLayerUserID(1));
+ CHECK_EQUAL(2, GetSortingLayerUserID(2));
+ CHECK_EQUAL(3, GetSortingLayerUserID(3));
+ CHECK_EQUAL(0, GetSortingLayerUserIDFromValue(0));
+ CHECK_EQUAL(1, GetSortingLayerUserIDFromValue(1));
+ CHECK_EQUAL(2, GetSortingLayerUserIDFromValue(2));
+ CHECK_EQUAL(3, GetSortingLayerUserIDFromValue(3));
+
+ // find their values by user IDs
+ CHECK_EQUAL(1, GetSortingLayerValueFromUserID(1));
+ CHECK_EQUAL(2, GetSortingLayerValueFromUserID(2));
+ CHECK_EQUAL(3, GetSortingLayerValueFromUserID(3));
+
+ // find their values by names
+ CHECK_EQUAL(1, GetSortingLayerValueFromName("A"));
+ CHECK_EQUAL(2, GetSortingLayerValueFromName("B"));
+ CHECK_EQUAL(3, GetSortingLayerValueFromName("C"));
+
+ // check all the above for default layer
+ CHECK_EQUAL(0, GetSortingLayerUserID(0));
+ CHECK_EQUAL(0, GetSortingLayerValueFromUserID(0));
+ CHECK_EQUAL(0, GetSortingLayerValueFromName(""));
+ CHECK_EQUAL(0, GetSortingLayerValueFromName("Default"));
+ CHECK_EQUAL(0, GetSortingLayerValueFromUniqueID(0));
+
+ // reorder layers into: B, A, Default, C
+ SwapSortingLayers (0, 2);
+
+ // check user IDs
+ CHECK_EQUAL(2, GetSortingLayerUserID(0)); // B
+ CHECK_EQUAL(1, GetSortingLayerUserID(1));
+ CHECK_EQUAL(3, GetSortingLayerUserID(3));
+
+ CHECK_EQUAL(2, GetSortingLayerUserIDFromValue(-2)); // B
+ CHECK_EQUAL(1, GetSortingLayerUserIDFromValue(-1)); // A
+ CHECK_EQUAL(0, GetSortingLayerUserIDFromValue(0)); // Default
+ CHECK_EQUAL(3, GetSortingLayerUserIDFromValue(1)); // C
+
+ // find values by names
+ CHECK_EQUAL(-2, GetSortingLayerValueFromName("B"));
+ CHECK_EQUAL(-1, GetSortingLayerValueFromName("A"));
+ CHECK_EQUAL(1, GetSortingLayerValueFromName("C"));
+
+ // check all the above for default layer
+ CHECK_EQUAL(0, GetSortingLayerUserID(2));
+ CHECK_EQUAL(0, GetSortingLayerValueFromUserID(0));
+ CHECK_EQUAL(0, GetSortingLayerValueFromName(""));
+ CHECK_EQUAL(0, GetSortingLayerValueFromName("Default"));
+ CHECK_EQUAL(0, GetSortingLayerValueFromUniqueID(0));
+
+ RegisterDefaultTagsAndLayerMasks (); // cleanup
+ }
+# endif // if UNITY_EDITOR
+
+#if UNITY_EDITOR
+
+ TEST (StringToTagAddIfUnavailable_WithNewTag_SetsUpMappings)
+ {
+ UInt32 tag = StringToTagAddIfUnavailable ("foobar");
+
+ CHECK_EQUAL (tag, StringToTag ("foobar"));
+ CHECK_EQUAL ("foobar", TagToString (tag));
+
+ // Cleanup.
+ RegisterDefaultTagsAndLayerMasks ();
+ }
+
+#endif // UNITY_EDITOR
+}
+
+#endif // ENABLE_UNIT_TESTS