summaryrefslogtreecommitdiff
path: root/Runtime/BaseClasses/GameObject.h
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2019-08-14 22:50:43 +0800
committerchai <chaifix@163.com>2019-08-14 22:50:43 +0800
commit15740faf9fe9fe4be08965098bbf2947e096aeeb (patch)
treea730ec236656cc8cab5b13f088adfaed6bb218fb /Runtime/BaseClasses/GameObject.h
+Unity Runtime codeHEADmaster
Diffstat (limited to 'Runtime/BaseClasses/GameObject.h')
-rw-r--r--Runtime/BaseClasses/GameObject.h535
1 files changed, 535 insertions, 0 deletions
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
+