diff options
Diffstat (limited to 'Runtime/Mono/MonoScript.cpp')
-rw-r--r-- | Runtime/Mono/MonoScript.cpp | 443 |
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 |