summaryrefslogtreecommitdiff
path: root/Runtime/Mono/MonoScript.cpp
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/Mono/MonoScript.cpp
+Unity Runtime codeHEADmaster
Diffstat (limited to 'Runtime/Mono/MonoScript.cpp')
-rw-r--r--Runtime/Mono/MonoScript.cpp443
1 files changed, 443 insertions, 0 deletions
diff --git a/Runtime/Mono/MonoScript.cpp b/Runtime/Mono/MonoScript.cpp
new file mode 100644
index 0000000..75b7c30
--- /dev/null
+++ b/Runtime/Mono/MonoScript.cpp
@@ -0,0 +1,443 @@
+#include "UnityPrefix.h"
+#if ENABLE_SCRIPTING
+#include "MonoScript.h"
+#include "Runtime/Serialize/TransferFunctions/SerializeTransfer.h"
+#include "Runtime/Serialize/TransferUtility.h"
+#include "MonoManager.h"
+#include "Runtime/Scripting/Backend/ScriptingBackendApi.h"
+#include "MonoScriptCache.h"
+#include "MonoBehaviour.h"
+
+#if UNITY_FLASH || UNITY_WINRT
+#include "Runtime/Scripting/Backend/ScriptingTypeRegistry.h"
+#endif
+
+const char* kBuildLogicGraphDllFile = "Temp/StagingArea/Data/Managed/LogicGraphs.dll";
+
+string GetGeneratedLogicGraphsDllName()
+{
+ return GetLastPathNameComponent(kBuildLogicGraphDllFile);
+}
+
+
+using namespace std;
+
+
+#if UNITY_EDITOR
+static UInt32 ComputeTypeTreeHashForScriptClass (MonoScript* script)
+{
+ if (script->GetClass () == NULL
+ || !IsValidScriptType (script->GetScriptType ())
+ || script->IsEditorScript ())
+ return 0;
+
+ // We don't want to call the constructor as that may run user code and
+ // may have all kinds of side-effects. All we need is an instance for
+ // running the TypeTree generation/serialization code on.
+ ScriptingObjectPtr instance = scripting_object_new (script->GetClass ());
+ if (!instance)
+ return 0;
+
+ // Create a temporary MonoBehaviour that we can run ProxyTransfer on.
+ MonoBehaviour* dummyInstance = NEW_OBJECT (MonoBehaviour);
+ dummyInstance->Reset ();
+ dummyInstance->HackSetAwakeWasCalled ();
+
+ // Connect MonoBehaviour to script class and to the object instance
+ // we have created.
+ dummyInstance->SetScript (script, instance);
+
+ // Generate type tree.
+ TypeTree typeTree;
+ GenerateTypeTree (*dummyInstance, &typeTree);
+ DestroySingleObject (dummyInstance);
+
+ // Compute hash of tree.
+ return HashTypeTree (typeTree);
+}
+#endif // UNITY_EDITOR
+
+
+MonoScript::MonoScript (MemLabelId label, ObjectCreationMode mode)
+: Super(label, mode)
+{
+ m_PropertiesHash = 0;
+
+ m_ScriptCache = NULL;
+ m_IsEditorScript = false;
+ m_ExecutionOrder = 0;
+}
+
+MonoScript::~MonoScript ()
+{
+ CleanupScriptCache();
+}
+
+UInt32 MonoScript::GetPropertiesHash ()
+{
+ // In the editor, compute the property hash on demand based on the type
+ // tree generated by the MonoBehaviour serialization code.
+ #if UNITY_EDITOR
+ if (m_PropertiesHash == 0)
+ m_PropertiesHash = ComputeTypeTreeHashForScriptClass (this);
+ #endif
+
+ return m_PropertiesHash;
+}
+
+UnityStr MonoScript::GetScriptFullClassName () const
+{
+ if (m_Namespace.empty())
+ return m_ClassName;
+ else
+ return m_Namespace + "." + m_ClassName;
+}
+
+ScriptingClassPtr MonoScript::GetClass ()
+{
+ if (m_ScriptCache)
+ return m_ScriptCache->klass;
+ else
+ return NULL;
+}
+
+ScriptingMethodPtr MonoScript::FindMethod (const char* name)
+{
+ if (m_ScriptCache)
+ return ::FindMethod(*m_ScriptCache, name);
+ else
+ return NULL;
+}
+
+MonoScriptType MonoScript::GetScriptType() const
+{
+ if (m_ScriptCache == NULL)
+ return kScriptTypeNotInitialized;
+ else
+ return m_ScriptCache->scriptType;
+}
+
+
+void MonoScript::CleanupScriptCache ()
+{
+ if (m_ScriptCache != NULL)
+ {
+ const_cast<MonoScriptCache*> (m_ScriptCache)->Release();
+ m_ScriptCache = NULL;
+ }
+}
+
+#if ENABLE_SCRIPTING
+
+void MonoScript::Rebuild (ScriptingTypePtr klass)
+{
+ CleanupScriptCache ();
+
+ #if UNITY_EDITOR
+ m_PropertiesHash = 0;
+ #endif
+
+ m_ScriptCache = CreateMonoScriptCache (klass, m_IsEditorScript, this);
+}
+#endif
+
+void MonoScript::RebuildFromAwake()
+{
+#if ENABLE_MONO
+ Rebuild (GetMonoManager().GetMonoClassWithAssemblyName (GetScriptClassName (), GetNameSpace(), GetAssemblyName ()));
+#elif UNITY_FLASH || UNITY_WINRT
+ ScriptingTypePtr t = GetScriptingTypeRegistry().GetType(GetNameSpace().c_str(), GetScriptClassName().c_str());
+ Rebuild(t);
+#endif
+
+}
+
+// Used by WinRT & Flash
+UnityStr MonoScript::GetScriptName()
+{
+ UnityStr s = GetNameSpace();
+ if (s.size() > 0)
+ s += "." + GetScriptClassName();
+ else
+ s = GetScriptClassName();
+ return s;
+}
+
+void MonoScript::AwakeFromLoad (AwakeFromLoadMode awakeMode)
+{
+ Super::AwakeFromLoad (awakeMode);
+ if ((awakeMode & kDidLoadThreaded) == 0)
+ {
+ RebuildFromAwake();
+ }
+}
+
+void MonoScript::AwakeFromLoadThreaded ()
+{
+ Super::AwakeFromLoadThreaded();
+ RebuildFromAwake();
+}
+
+template<class TransferFunction>
+void MonoScript::TransferPropertiesHash (TransferFunction& transfer)
+{
+ #if UNITY_EDITOR
+ if (transfer.IsWritingGameReleaseData())
+ {
+ // Force building the properties hash
+ GetPropertiesHash();
+ }
+ #endif
+
+ // When reading or writing for game release
+ // Transfer properties hash
+ if (transfer.IsSerializingForGameRelease ())
+ transfer.Transfer (m_PropertiesHash, "m_PropertiesHash", kNotEditableMask);
+}
+
+#if UNITY_EDITOR
+// Temporarily (When building the player during the write operation).
+// Sets the correct assembly of the MonoScript, and restores it afterwards.
+struct RemapAssemblyDuringBuild
+{
+ MonoScript* m_Script;
+ string m_AssemblyName;
+ string m_Namespace;
+ string m_ClassName;
+
+ RemapAssemblyDuringBuild (MonoScript& inScript, bool logicGraphRelease)
+ : m_Script (NULL)
+ {
+ if (!logicGraphRelease)
+ return;
+
+ m_Script = &inScript;
+
+ m_AssemblyName = m_Script->GetAssemblyName();
+ m_Namespace = m_Script->GetNameSpace();
+ m_ClassName = m_Script->GetScriptClassName();
+
+ m_Script->m_AssemblyName = GetGeneratedLogicGraphsDllName();
+ m_Script->m_Namespace = "";
+
+ m_Script->m_ClassName = m_Script->m_EditorGraphData->GetName();
+ }
+
+ ~RemapAssemblyDuringBuild ()
+ {
+ if (m_Script == NULL)
+ return;
+
+ m_Script->m_AssemblyName = m_AssemblyName;
+ m_Script->m_Namespace = m_Namespace;
+ m_Script->m_ClassName = m_ClassName;
+ }
+};
+#endif
+
+template<class TransferFunction>
+void MonoScript::Transfer (TransferFunction& transfer)
+{
+ // Don't transfer script class since we already transfer the script property ourselves.
+ Super::Super::Transfer (transfer);
+
+ transfer.SetVersion(4);
+
+ #if UNITY_EDITOR
+
+ bool logicGraphRelease = transfer.IsWritingGameReleaseData() && !m_EditorGraphData.IsNull();
+ RemapAssemblyDuringBuild remap (*this, logicGraphRelease);
+
+ if (!transfer.IsSerializingForGameRelease ())
+ {
+ transfer.Transfer (m_Script, "m_Script", kHideInEditorMask);
+ transfer.Transfer (m_DefaultReferences, "m_DefaultReferences", kHideInEditorMask);
+ transfer.Transfer (m_Icon, "m_Icon", kNoTransferFlags);
+ TRANSFER (m_EditorGraphData);
+ }
+
+ #endif
+
+
+ transfer.Transfer (m_ExecutionOrder, "m_ExecutionOrder", kNotEditableMask);
+ TransferPropertiesHash (transfer);
+
+ transfer.Transfer (m_ClassName, "m_ClassName", kNotEditableMask);
+ transfer.Transfer (m_Namespace, "m_Namespace", kNotEditableMask);
+ transfer.Transfer (m_AssemblyName, "m_AssemblyName", kNotEditableMask);
+ transfer.Transfer (m_IsEditorScript, "m_IsEditorScript", kHideInEditorMask);
+
+ // AssemblyIdentifier has been removed and is now simply the dll name
+ if (transfer.IsVersionSmallerOrEqual(1))
+ {
+ transfer.Transfer (m_AssemblyName, "m_AssemblyIdentifier", kNotEditableMask);
+
+ if (m_AssemblyName == "Unity Engine Special")
+ {
+ m_AssemblyName = "UnityEngine.dll";
+ m_Namespace = "UnityEngine";
+ }
+ else if (m_AssemblyName == "Unity Editor Special")
+ {
+ m_AssemblyName = "UnityEditor.dll";
+ m_Namespace = "UnityEditor";
+ }
+ else
+ {
+ m_AssemblyName = "Assembly - " + m_AssemblyName + ".dll";
+ }
+ }
+
+ #if UNITY_EDITOR
+ // In 2.x Assemblies compiled by Unity had spaces in the name.
+ // In 3.0 we are removing all spaces, since this makes loading assemblies easier and fixes issue on xbox where the filename is too long.
+ // ("Assembly - UnityScript.dll" -> "Assembly-UnityScript.dll")
+ if (transfer.IsVersionSmallerOrEqual(2))
+ {
+ if (BeginsWith(m_AssemblyName, "Assembly - "))
+ replace_string(m_AssemblyName, " ", "");
+ }
+ #endif
+}
+
+bool MonoScript::ShouldIgnoreInGarbageDependencyTracking ()
+{
+ // MonoScript can have referenced
+ // But it's ok to ignore them eg. references to default references, icons and editor graph
+ return true;
+}
+
+void MonoScript::Init (const ScriptString& script, const string& className, const std::string& nameSpace, const string& identifier, bool isEditorScript)
+{
+ SetScript(script);
+ m_ClassName = className;
+ m_Namespace = nameSpace;
+ m_AssemblyName = identifier;
+ m_PropertiesHash = 0;
+ m_IsEditorScript = isEditorScript;
+
+ SetDirty ();
+}
+
+#if ENABLE_SCRIPTING
+
+void MonoScript::Init (MonoClass* scriptType)
+{
+ m_ClassName = scripting_class_get_name(scriptType);
+ m_Namespace = scripting_class_get_namespace(scriptType);
+ m_PropertiesHash = 0;
+ #if ENABLE_MONO
+ MonoImage* image = mono_class_get_image(scriptType);
+ MonoAssemblyName name;
+ bool success = mono_assembly_fill_assembly_name(image, &name);
+ if (success)
+ m_AssemblyName = mono_stringify_assembly_name(&name);
+ #endif
+ m_IsEditorScript = 0;
+ SetDirty ();
+}
+#endif
+
+std::string MonoScript::GetNameSpace ()const
+{
+ return m_Namespace;
+}
+
+#if ENABLE_SCRIPTING
+MonoScript* CreateMonoScriptFromScriptingType(ScriptingTypePtr klass)
+{
+ MonoScript* result = NEW_OBJECT(MonoScript);
+ result->Reset ();
+ result->Init(klass);
+ GetMonoScriptManager().RegisterRuntimeScript (*result);
+ result->AwakeFromLoad(kInstantiateOrCreateFromCodeAwakeFromLoad);
+ return result;
+}
+#endif
+
+void MonoScript::SetExecutionOrder (SInt32 executionOrder)
+{
+ m_ExecutionOrder = executionOrder;
+ SetDirty();
+}
+
+#if UNITY_EDITOR
+bool MonoScript::IsBuiltinScript() const
+{
+ return m_AssemblyName == "UnityEngine.dll" || m_AssemblyName == "UnityEditor.dll";
+}
+
+void MonoScript::SetIcon (PPtr<Object> icon)
+{
+ m_Icon = icon;
+ // We do not call SetDirty() since MonoScript is generated data (MonoImporter holds the icon state)
+}
+
+PPtr<Object> MonoScript::GetIcon () const
+{
+ return m_Icon;
+}
+
+void MonoScript::SetEditorGraphData(Object* data)
+{
+ if (m_EditorGraphData != PPtr<Object> (data))
+ {
+ m_EditorGraphData = data;
+ SetDirty();
+ }
+}
+
+PPtr<Object> MonoScript::GetEditorGraphData()
+{
+ return m_EditorGraphData;
+}
+
+bool MonoScript::GetScriptTypeWasJustCreatedFromComponentMenu ()
+{
+ if (m_ScriptCache)
+ return m_ScriptCache->scriptTypeWasJustCreatedFromComponentMenu;
+ else
+ return false;
+}
+
+void MonoScript::SetScriptTypeWasJustCreatedFromComponentMenu ()
+{
+ if (m_ScriptCache == NULL)
+ Rebuild(NULL);
+
+ const_cast<MonoScriptCache*> (m_ScriptCache)->scriptTypeWasJustCreatedFromComponentMenu = true;
+}
+
+std::string BuildScriptClassId(const std::string& assembly, const std::string& ns, const std::string& klass)
+{
+ return assembly + ":" + ns + ":" + klass;
+}
+
+void GetScriptClassIdComponents(const std::string& scriptClassId, std::string& assembly, std::string& ns, std::string& klass)
+{
+ std::vector<std::string> parts;
+ Split(scriptClassId, ":", parts);
+
+ assembly = parts[0];
+ AssertIf(parts.size() != 2 && parts.size() != 3);
+ // empty namespace
+ if (parts.size() == 2)
+ {
+ ns.clear();
+ klass = parts[1];
+ }
+ else if (parts.size() == 3)
+ {
+ ns = parts[1];
+ klass = parts[2];
+ }
+}
+
+#endif
+
+#if ENABLE_SCRIPTING
+IMPLEMENT_CLASS (MonoScript)
+IMPLEMENT_OBJECT_SERIALIZE (MonoScript)
+#endif
+
+#endif