diff options
Diffstat (limited to 'Runtime/Scripting')
59 files changed, 7183 insertions, 0 deletions
diff --git a/Runtime/Scripting/AS3Utility.cpp b/Runtime/Scripting/AS3Utility.cpp new file mode 100644 index 0000000..8c93499 --- /dev/null +++ b/Runtime/Scripting/AS3Utility.cpp @@ -0,0 +1,31 @@ +#include "UnityPrefix.h" +#include "ScriptingUtility.h" +#include "Runtime/Utilities/LogAssert.h" +#include "Runtime/Scripting/ScriptingManager.h" +#include "Runtime/Scripting/Backend/ScriptingArguments.h" +#include "Runtime/Scripting/Backend/ScriptingBackendApi.h" + +extern "C" bool NativeExt_SendMessage(ScriptingStringPtr path, ScriptingStringPtr method, ScriptingObjectPtr value) +{ + Transform* transform = FindActiveTransformWithPath( (const char*) path ); + if( transform != NULL) + { + return Scripting::SendScriptingMessage( transform->GetGameObject(), (const char*) method, value ); + } + return false; +} + +bool ReadStringFromFile (TEMP_STRING* outData, const string& path) +{ + const char* outDataFlash = Ext_FileContainer_ReadStringFromFile(path.c_str()); + if(outDataFlash != NULL){ + *outData = outDataFlash; + return true; + } + return false; +} + +ScriptingObjectPtr ScriptingInstantiateObjectFromClassName(const char* name) +{ + return Ext_GetNewMonoBehaviour(name); +} diff --git a/Runtime/Scripting/AS3Utility.h b/Runtime/Scripting/AS3Utility.h new file mode 100644 index 0000000..31dd7fc --- /dev/null +++ b/Runtime/Scripting/AS3Utility.h @@ -0,0 +1,144 @@ +#ifndef AS3UTILITY_H +#define AS3UTILITY_H + +#if !defined(SCRIPTINGUTILITY_H) +#error "Don't include AS3Utility.h, include ScriptingUtility.h instead" +#endif + +typedef UInt32 AS3Handle; +struct UTF16String; + +#include "Runtime/Scripting/Backend/ScriptingTypes.h" +#include "Runtime/Graphics/Transform.h" +#include "Runtime/Scripting/Backend/ScriptingBackendApi.h" + +#include "Scripting.h" + +using namespace std; + +#define htons(A) (A) +#define htonl(A) (A) +#define ntohs htons +#define ntohl htohl + +#define SCRIPTINGAPI_THREAD_CHECK(NAME) +#define SCRIPTINGAPI_CONSTRUCTOR_CHECK(NAME) +#define SCRIPTINGAPI_DEFINE_REF_ARG(t, n) t n +#define SCRIPTINGAPI_FIX_REF_ARG(t, n) + +extern "C" void Ext_FileContainer_MakeFilesAvailable(); +extern "C" int Ext_FileContainer_GetFileLength(const char* filename); +extern "C" char* Ext_Flash_GetNameFromClass(ScriptingType* handle); +extern "C" void Ext_Stack_Store(void* ptr); +extern "C" void Ext_Flash_LogCallstack(); +extern "C" void Ext_Flash_ThrowError(const char*) __attribute__((noreturn)); + +extern "C" int Ext_MarshallTo(ScriptingObjectPtr obj, void* dest); +extern "C" int Ext_UnmarshallFrom(ScriptingObjectPtr obj, void* src); +//extern "C" void Ext_SetNativePtr(ScriptingObjectPtr obj, void* ptr); +//extern "C" void* Ext_GetNativePtr(ScriptingObjectPtr obj); + +//ScriptingArray* MonoFindObjectsOfType (ScriptingType* reflectionTypeObject, int mode); + +namespace Unity { class GameObject; class Component; } +using namespace Unity; + +extern "C" const char* Ext_FileContainer_ReadStringFromFile(const char* filename); + +//Used by MonoBehaviourSerialization +extern "C" void Ext_SerializeMonoBehaviour(ScriptingObjectPtr behaviour); +extern "C" UInt8* Ext_DeserializeMonoBehaviour(ScriptingObjectPtr behaviour); +extern "C" void Ext_RemapPPtrs(ScriptingObjectPtr behaviour); + +extern "C" ScriptingObjectPtr Ext_Scripting_InstantiateScriptingWrapperForClassWithName(const char* name); + +extern "C" bool Ext_FileContainer_IsFileCreatedAt(const char* filename); +extern "C" void Ext_WriteTextAndToolTipIntoUTF16Strings(ScriptingObject* obj, UTF16String* text, UTF16String* tooltip); + +extern "C" bool Ext_Trace(const char* msg); +extern "C" ScriptingObjectPtr Ext_GetNewMonoBehaviour(const char* name); + +//External interface / openurl / application. +extern "C" void Ext_OpenURL(const char* url); +extern "C" ScriptingString* Ext_ExternalCall(const char* function, ScriptingObjectPtr args); + +extern "C" ScriptingObjectPtr Ext_Flash_getProperty(ScriptingObjectPtr object, const char* property); + +template<class T> +ScriptingObjectPtr Flash_CreateScriptingObjectFromNativeStruct(ScriptingClass* klass, T& thestruct); + +template<class T> inline +ScriptingObjectPtr CreateScriptingObjectFromNativeStruct(ScriptingClass* klass, T& thestruct) +{ + //printf_console("creating instance of klass: %d",klass); + ScriptingObjectPtr obj = scripting_object_new(klass); + //printf_console("populating it with native data stored at %d",&thestruct); + Ext_UnmarshallFrom(obj, &thestruct); + return obj; +} + +inline void RaiseIfNull(ScriptingObjectPtr o) {} + +inline int GetScriptingArraySize(ScriptingArray* a) +{ + if(a == NULL) + return 0; + + //POD arrays are encoded by the as3 glue as a memoryblob: one int describing the size, following the actual bytes. + return *(int*)(a); +} + +extern "C" int Ext_MarshallTo(ScriptingObjectPtr obj, void* dest); +extern "C" int Ext_UnmarshallFrom(ScriptingObjectPtr obj, void* src); + +template<class T> inline +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, T* dest) +{ + Ext_MarshallTo(so,(void*)dest); +} + +template<class T> inline +void MarshallNativeStructIntoManaged(T& src, ScriptingObjectPtr dest) +{ + Ext_UnmarshallFrom(dest,(void*)&src); +} + +template<class T> +inline T* ScriptingObjectToObject(ScriptingObjectPtr so) +{ + //todo: create the optimized path where we directly grab the cachedptr + PPtr<T> p; + p.SetInstanceID(Scripting::GetInstanceIDFromScriptingWrapper(so)); + return p; +} + +ScriptingObjectPtr ScriptingInstantiateObjectFromClassName(const char* name); + +inline +char* ScriptingStringToAllocatedChars(const ICallString& str) +{ + return strdup(str.utf8stream); +} + +inline void ScriptingStringToAllocatedChars_Free(const char* str) +{ + free((void*)str); +} + +template<class T> +inline ScriptingObjectPtr ScriptingGetObjectReference(PPtr<T> object) +{ + return Scripting::ScriptingWrapperFor(object); +} +template<class T> +inline ScriptingObjectPtr ScriptingGetObjectReference(T* object) +{ + return Scripting::ScriptingWrapperFor(object); +} + +#define CreateScriptingParams(VariableName, ParamCount) ScriptingParams VariableName[ParamCount]; +// Don't use if Value is ScriptingObjectPtr!!! +#define SetScriptingParam(VariableName, Index, Value) VariableName[Index] = &Value; +#define GetSafeString(ClassName, Getter) Getter + +#endif
\ No newline at end of file diff --git a/Runtime/Scripting/Backend/Flash/ScriptingBackendApi_Flash.cpp b/Runtime/Scripting/Backend/Flash/ScriptingBackendApi_Flash.cpp new file mode 100644 index 0000000..8022f96 --- /dev/null +++ b/Runtime/Scripting/Backend/Flash/ScriptingBackendApi_Flash.cpp @@ -0,0 +1,287 @@ +#include "UnityPrefix.h" + +#include "../ScriptingTypes.h" +#include "ScriptingBackendApi_Flash.h" +#include "../ScriptingTypeRegistry.h" +#include "../ScriptingMethodRegistry.h" +#include <string> +#include "../ScriptingArguments.h" +#include "PlatformDependent\FlashSupport\cpp\FlashUtils.h" + +std::string scripting_cpp_string_for(ScriptingStringPtr str) +{ + return std::string((const char*)str); +} + +//implemented in raw actionscript +extern "C" ScriptingClass* Ext_Flash_GetBaseClassFromScriptingClass(ScriptingClass* klass); +bool scripting_method_is_instance(ScriptingMethodPtr method) +{ + //not implemented on flash yet. + return true; +} + +ScriptingStringPtr scripting_string_new(const char* str) +{ + __asm __volatile__("returnString = strFromPtr(%0);" : : "r" (str) ); + return (ScriptingStringPtr)str; +} + +ScriptingStringPtr scripting_string_new(const std::string& str) +{ + return scripting_string_new(str.c_str()); +} + +extern "C" int Ext_Flash_ScriptingGetMethodParamCount(ScriptingObjectPtr object, AS3String as3String); +int scripting_method_get_argument_count(ScriptingMethodPtr method, ScriptingTypeRegistry& typeRegistry) +{ + ScriptingObjectPtr methodInfo = method->GetSystemReflectionMethodInfo(); + if (methodInfo==NULL) + return 0; + + int result; + FLASH_ASM_WITH_NEWSP("%0 = ScriptingMethodHelper.NumberOfArgumentsOf(marshallmap.getObjectWithId(%1));" : "=r"(result) : "r"(methodInfo)); + + return result; +} + +ScriptingTypePtr scripting_method_get_nth_argumenttype(ScriptingMethodPtr method, int index, ScriptingTypeRegistry& typeRegistry) +{ + ScriptingObjectPtr methodInfo = method->GetSystemReflectionMethodInfo(); + if (methodInfo==NULL) + return NULL; + + ScriptingTypePtr result; + FLASH_ASM_WITH_NEWSP("scratch_object = ScriptingMethodHelper.NthArgumentType(marshallmap.getObjectWithId(%0), %1)" : : "r"(methodInfo), "r"(index)); + FLASH_ASM_WITH_NEWSP("if (scratch_object!=null) %0 = marshallmap.getIdForObject(scratch_object.GetClass()); else %0 = 0;" : "=r"(result)); + return result; +} + +const char* scripting_method_get_name(ScriptingMethodPtr method) +{ + return method->GetName(); +} + +bool scripting_method_has_attribute (ScriptingMethodPtr method, ScriptingClassPtr attribute) +{ + //not implemented on flash yet + return false; +} + +ScriptingTypePtr scripting_class_get_parent(ScriptingTypePtr type, ScriptingTypeRegistry& typeRegistry) +{ + return Ext_Flash_GetBaseClassFromScriptingClass(type); +} + +bool scripting_class_is_enum(ScriptingTypePtr type) +{ + //todo: implement + return false; +} + +extern "C" const char* Ext_Flash_GetNameFromClass(ScriptingClassPtr klass); +const char* scripting_class_get_name(ScriptingClassPtr klass) +{ + //Horrible, we can only clean this up once we create a struct ScriptingClass for flash. + std::string* s = new std::string(Ext_Flash_GetNameFromClass(klass)); + return s->c_str(); +} + +extern "C" const char* Ext_Flash_GetNameSpaceFromScriptingType(ScriptingType* scriptingType); +const char* scripting_class_get_namespace(ScriptingClassPtr klass) +{ + //Horrible, we can only clean this up once we create a struct ScriptingClass for flash. + std::string* s = new std::string(Ext_Flash_GetNameSpaceFromScriptingType(klass)); + return s->c_str(); +} + +extern "C" bool Ext_Flash_ScriptingClassIsSubclassOf(ScriptingTypePtr t1, ScriptingTypePtr t2); +bool scripting_class_is_subclass_of(ScriptingTypePtr t1, ScriptingTypePtr t2) +{ + return Ext_Flash_ScriptingClassIsSubclassOf(t1,t2); +} + +ScriptingTypePtr scripting_method_get_returntype(ScriptingMethodPtr method, ScriptingTypeRegistry& typeRegistry) +{ + return method->GetReturnType(); +} + +extern "C" ScriptingObjectPtr Ext_Flash_InvokeMethodOnObject(void* object, AS3String as3String, ScriptingException** exception); +ScriptingObjectPtr scripting_method_invoke(ScriptingMethodPtr method, ScriptingObjectPtr object, ScriptingArguments& arguments, ScriptingExceptionPtr* exception) +{ + void* objectToInvokeOn = object; + *exception = NULL; + if (object==NULL) + { + objectToInvokeOn = method->m_Class; + if (objectToInvokeOn == NULL) + ErrorString("flash_invoke_method called with NULL object, and scriptmethod->m_Class is NULL too."); + } + + __asm __volatile__("invocation_arguments.length = 0;\n"); + + for (int i=0; i!=arguments.GetCount(); i++) + { + switch (arguments.GetTypeAt(i)) + { + case ScriptingArguments::ARGTYPE_BOOLEAN: + __asm __volatile__("invocation_arguments.push(%0 ? true : false);" : : "r"(arguments.GetBooleanAt(i))); + break; + case ScriptingArguments::ARGTYPE_INT: + __asm __volatile__("invocation_arguments.push(%0);" : : "r"(arguments.GetIntAt(i))); + break; + case ScriptingArguments::ARGTYPE_FLOAT: + __asm __volatile__("invocation_arguments.push(%0);" : : "f"(arguments.GetFloatAt(i))); + break; + case ScriptingArguments::ARGTYPE_STRING: + __asm __volatile__("invocation_arguments.push(strFromPtr(%0));" : : "r"(arguments.GetStringAt(i))); + break; + case ScriptingArguments::ARGTYPE_OBJECT: + __asm __volatile__("invocation_arguments.push(marshallmap.getObjectWithId(%0));" : : "r"(arguments.GetObjectAt(i))); + break; + default: + ErrorString(Format("Flash does not support calling managed methods with this type of argument: %d",arguments.GetTypeAt(i))); + break; + } + } + return Ext_Flash_InvokeMethodOnObject(objectToInvokeOn, method->m_As3String,exception); +} + +ScriptingTypePtr scripting_class_from_systemtypeinstance(ScriptingObjectPtr systemTypeInstance, ScriptingTypeRegistry& typeRegistry) +{ + //todo: think about if this is actually correct. + return (ScriptingClassPtr)systemTypeInstance; +} + +extern "C" ScriptingObjectPtr Ext_Flash_CreateInstance(ScriptingClass* klass); +ScriptingObjectPtr scripting_object_new(ScriptingTypePtr t) +{ + return Ext_Flash_CreateInstance(t); +} + +extern "C" ScriptingClassPtr Ext_Flash_GetScriptingTypeOfScriptingObject(ScriptingObjectPtr); +ScriptingTypePtr scripting_object_get_class(ScriptingObjectPtr o, ScriptingTypeRegistry& typeRegistry) +{ + return Ext_Flash_GetScriptingTypeOfScriptingObject(o); +} + +ScriptingMethodPtr scripting_object_get_virtual_method(ScriptingObjectPtr o, ScriptingMethodPtr method, ScriptingMethodRegistry& methodRegistry) +{ + return method; +} + +void scripting_object_invoke_default_constructor(ScriptingObjectPtr o, ScriptingExceptionPtr* exc) +{ + *exc = NULL; + //todo: properly deal with exception. + FLASH_ASM_WITH_NEWSP("marshallmap.getObjectWithId(%0).cil2as_DefaultConstructor()" : : "r"(o)); +} + +int scripting_gchandle_new(ScriptingObjectPtr o) +{ + __asm __volatile__("marshallmap.gcHandle(%0);" : : "r" (o)); + return (int)o; +} + +int scripting_gchandle_weak_new(ScriptingObjectPtr o) +{ + FatalErrorMsg("ToDo"); + return 0; +} + +void scripting_gchandle_free(int handle) +{ + __asm __volatile__("marshallmap.gcFree(%0);" : : "r" (handle)); +} + +ScriptingObjectPtr scripting_gchandle_get_target(int handle) +{ + return (ScriptingObjectPtr) handle; +} + +int scripting_gc_maxgeneration() +{ + return 0; +} + +void scripting_gc_collect(int maxGeneration) +{ + FatalErrorMsg("ToDo"); +} + +void ScriptingMethod::Init(const char* name, const char* mappedName, const char* sig, ScriptingClass* klass) +{ + m_Name = strcpy(new char[strlen(name) + 1],name); + m_Mappedname = strcpy(new char[strlen(mappedName) + 1],mappedName); + __asm __volatile__("%0 = getAS3StringForPtr(%1);\n" : "=r" (m_As3String) : "r" (m_Mappedname)); + + m_Signature = strcpy(new char[strlen(sig) + 1],sig); + m_Class = klass; + m_MethodInfo = NULL; + FLASH_ASM_WITH_NEWSP("%0 = marshallmap.getIdForObject(System.Type.ForClass(marshallmap.getObjectWithId(%1)));\n" : "=r" (m_SystemType) : "r"(m_Class) ); + scripting_gchandle_new(m_SystemType); +} + +extern "C" const char* Ext_GetMappedMethodName(const char* name, ScriptingType* klass); +ScriptingMethod::ScriptingMethod(const char* name, ScriptingClass* klass) +{ + const char* mappedName = Ext_GetMappedMethodName(name,klass); + Init(name,mappedName,"",klass); +} + +ScriptingMethod::ScriptingMethod(const char* name, const char* mappedName, const char* sig, ScriptingClass* klass) +{ + Init(name,mappedName,sig,klass); +} + +extern "C" ScriptingClass* Ext_Flash_GetMethodReturnType(const char* methodname, ScriptingClass* klass); +ScriptingClass* ScriptingMethod::GetReturnType() +{ + return Ext_Flash_GetMethodReturnType(m_Mappedname, m_Class); +} + +ScriptingObjectPtr ScriptingMethod::GetSystemReflectionMethodInfo() +{ + if (m_MethodInfo) + return m_MethodInfo; + + FLASH_ASM_WITH_NEWSP("%0 = marshallmap.getIdForObject(ScriptingMethodHelper.GetMethodInfo(marshallmap.getObjectWithId(%1), strFromPtr(%2)));" : "=r"(m_MethodInfo) : "r"(m_SystemType),"r"(m_Name) ); + + scripting_gchandle_new(m_MethodInfo); + return m_MethodInfo; +} + +ScriptingObjectPtr scripting_class_get_object(ScriptingClassPtr klass) +{ + FatalErrorMsg("ToDo"); + return SCRIPTING_NULL; +} + +ScriptingArrayPtr scripting_cast_object_to_array(ScriptingObjectPtr o) +{ + FatalErrorMsg("ToDo"); + return SCRIPTING_NULL; +} + +void scripting_stack_trace_info_for(ScriptingExceptionPtr exception, StackTraceInfo& info) +{ + AssertIf (exception == NULL); + + __asm __volatile__("var errorStr:String = marshallmap.getObjectWithId(%0) as String;"::"r"(exception)); + int length; + __asm __volatile__("%0=getStringMarshallingLength(errorStr);":"=r"(length)); + char* errorStrPtr = (char*)alloca(length); + __asm __volatile__("var ptr:int = placeStringAtPtr(errorStr,%0);"::"r"(errorStrPtr)); + + info.condition = errorStrPtr; + info.strippedStacktrace = ""; + info.stacktrace = ""; + info.errorNum = 0; + info.file = ""; + info.line = 0; +} + +void* scripting_array_element_ptr(ScriptingArrayPtr array, int i, size_t element_size) +{ + return (UInt8*)array + sizeof(int) + i * element_size; +}
\ No newline at end of file diff --git a/Runtime/Scripting/Backend/Flash/ScriptingBackendApi_Flash.h b/Runtime/Scripting/Backend/Flash/ScriptingBackendApi_Flash.h new file mode 100644 index 0000000..c2372a2 --- /dev/null +++ b/Runtime/Scripting/Backend/Flash/ScriptingBackendApi_Flash.h @@ -0,0 +1,45 @@ +#ifndef _SCRIPTINGBACKENDAPI_FLASH_H_ +#define _SCRIPTINGBACKENDAPI_FLASH_H_ + +#include <string> + +#include "../ScriptingTypes.h" +#include "../ScriptingBackendApi.h" + +//todo: remove +typedef ScriptingObject* (*FastMonoMethod) (void* thiz, ScriptingException** ex); +typedef int AS3String; + +struct ScriptingMethod +{ + const char* m_Name; + const char* m_Mappedname; + const char* m_Signature; + AS3String m_As3String; + + ScriptingClass* m_Class; + ScriptingObject* m_SystemType; + ScriptingObject* m_MethodInfo; + + ScriptingMethod(const char* name, ScriptingClass* klass); + ScriptingMethod(const char* name, const char* mappedName, const char* sig, ScriptingClass* klass); + void Init(const char* name, const char* mappedName, const char* sig, ScriptingClass* klass); + ScriptingClass* GetReturnType(); + const char* GetName() { return m_Name; } + ScriptingObjectPtr GetSystemReflectionMethodInfo(); +}; + +struct ScriptingField +{ + ScriptingField(const char* name,const char* type) + : m_name(name) + , m_type(type) + { + + } + + std::string m_name; + std::string m_type; +}; + +#endif diff --git a/Runtime/Scripting/Backend/Flash/ScriptingMethodFactory_Flash.h b/Runtime/Scripting/Backend/Flash/ScriptingMethodFactory_Flash.h new file mode 100644 index 0000000..35b7015 --- /dev/null +++ b/Runtime/Scripting/Backend/Flash/ScriptingMethodFactory_Flash.h @@ -0,0 +1,40 @@ +#ifndef _SCRIPTINGMETHODFACTORY_FLASH_ +#define _SCRIPTINGMETHODFACTORY_FLASH_ + +#include "../ScriptingMethodFactory.h" +#include "Runtime/Scripting/ScriptingUtility.h" +#include "ScriptingBackendApi_Flash.h" + +#if UNITY_FLASH + +extern "C" const char* Ext_GetMappedMethodName(const char* name, ScriptingType* klass); + +class ScriptingMethodFactory_Flash : public IScriptingMethodFactory +{ +public: + virtual ScriptingMethodPtr Produce(ScriptingTypePtr klass, const char* name, int searchFilter) + { + //todo: respect the searchfilter + std::string mappedName(Ext_GetMappedMethodName(name,klass)); + + //remove this hack when interfaces contain mapping information + if (mappedName.size()==0 && strcmp(name,"MoveNext")==0) + mappedName.assign("IEnumerator_MoveNext"); + return new ScriptingMethod(name, mappedName.c_str(), "",klass); + } + + virtual ScriptingMethodPtr Produce(void* nativeMethod) + { + //not implemented for flash. + return NULL; + } + + virtual void Release(ScriptingMethodPtr method) + { + delete method; + } +}; + +#endif + +#endif diff --git a/Runtime/Scripting/Backend/Flash/ScriptingTypeProvider_Flash.h b/Runtime/Scripting/Backend/Flash/ScriptingTypeProvider_Flash.h new file mode 100644 index 0000000..eb2142c --- /dev/null +++ b/Runtime/Scripting/Backend/Flash/ScriptingTypeProvider_Flash.h @@ -0,0 +1,53 @@ +#ifndef _SCRIPTINGTYPEPROVIDER_FLASH +#define _SCRIPTINGTYPEPROVIDER_FLASH + +#include "../IScriptingTypeProvider.h" +//#include "Runtime/Scripting/ScriptingUtility.h" + +#if UNITY_FLASH + +extern "C" ScriptingTypePtr Ext_Flash_GetScriptingTypeFromName(const char* name); + +class ScriptingTypeProvider_Flash : public IScriptingTypeProvider +{ +public: + virtual BackendNativeType NativeTypeFor(const char* namespaze, const char* name) + { + if (strcmp(name,"Object") == 0) + name = "_Object"; + + if (strcmp(namespaze,"System")==0) + { + if (strcmp(name,"String")==0) + return Ext_Flash_GetScriptingTypeFromName("String"); + if (strcmp(name,"Int32")==0) + return Ext_Flash_GetScriptingTypeFromName("int"); + if (strcmp(name,"Single")==0) + return Ext_Flash_GetScriptingTypeFromName("Number"); + if (strcmp(name,"Double")==0) + return Ext_Flash_GetScriptingTypeFromName("Number"); + if (strcmp(name,"Byte")==0) + return Ext_Flash_GetScriptingTypeFromName("int"); + } + + std::string combined(namespaze); + if (combined.size() > 0) + combined+="."; + combined+=name; + + return Ext_Flash_GetScriptingTypeFromName(combined.c_str()); + } + + virtual ScriptingTypePtr Provide(BackendNativeType nativePtr) + { + return (ScriptingTypePtr)nativePtr; + } + + virtual void Release(ScriptingTypePtr t) + { + } +}; + +#endif + +#endif diff --git a/Runtime/Scripting/Backend/IScriptingTypeProvider.h b/Runtime/Scripting/Backend/IScriptingTypeProvider.h new file mode 100644 index 0000000..c8a9fe7 --- /dev/null +++ b/Runtime/Scripting/Backend/IScriptingTypeProvider.h @@ -0,0 +1,16 @@ +#ifndef _ISCRIPTINGTYPEPROVIDER_H_ +#define _ISCRIPTINGTYPEPROVIDER_H_ + +#include "ScriptingTypes.h" +#include "Runtime/Modules/ExportModules.h" + +class EXPORT_COREMODULE IScriptingTypeProvider +{ +public: + virtual ~IScriptingTypeProvider() {} + virtual BackendNativeType NativeTypeFor(const char* namespaze, const char* name) = 0; + virtual ScriptingTypePtr Provide(BackendNativeType nativeType) = 0; + virtual void Release(ScriptingTypePtr t) = 0; +}; + +#endif diff --git a/Runtime/Scripting/Backend/Mono/ScriptingBackendApi_Mono.cpp b/Runtime/Scripting/Backend/Mono/ScriptingBackendApi_Mono.cpp new file mode 100644 index 0000000..b27269b --- /dev/null +++ b/Runtime/Scripting/Backend/Mono/ScriptingBackendApi_Mono.cpp @@ -0,0 +1,280 @@ +#include "UnityPrefix.h" + +#include "../ScriptingTypes.h" +#include "Runtime/Mono/MonoIncludes.h" +#include "ScriptingBackendApi_Mono.h" +#include "../ScriptingMethodRegistry.h" +#include "../ScriptingTypeRegistry.h" +#include "Runtime/Scripting/ScriptingUtility.h" //required for ExtractMonoobjectData, todo: see if we can remove that. + +std::string scripting_cpp_string_for(ScriptingStringPtr str) +{ + return MonoStringToCpp(str); +} + +bool scripting_method_is_instance(ScriptingMethodPtr method) +{ + return method->isInstance; +} + +const char* scripting_method_get_name(ScriptingMethodPtr method) +{ + return mono_method_get_name(method->monoMethod); +} + +int scripting_method_get_argument_count(ScriptingMethodPtr method, ScriptingTypeRegistry& typeRegistry) +{ + MonoMethodSignature* sig = mono_method_signature(method->monoMethod); + Assert(sig); + return mono_signature_get_param_count(sig); +} + +ScriptingTypePtr scripting_method_get_returntype(ScriptingMethodPtr method, ScriptingTypeRegistry& registry) +{ + MonoMethodSignature* sig = mono_method_signature (method->monoMethod); + MonoType* returnType = mono_signature_get_return_type (sig); + if (returnType == NULL) + return NULL; + + return mono_class_from_mono_type (returnType); +} + +ScriptingTypePtr scripting_method_get_nth_argumenttype(ScriptingMethodPtr method, int index, ScriptingTypeRegistry& typeRegistry) +{ + MonoMethodSignature* sig = mono_method_signature (method->monoMethod); + void* iterator = NULL; + MonoType* type = mono_signature_get_params (sig, &iterator); + if (type == NULL) + return NULL; + MonoClass* methodClass = mono_class_from_mono_type (type); + return typeRegistry.GetType(methodClass); +} + +bool scripting_method_has_attribute(ScriptingMethodPtr method, ScriptingClassPtr attribute) +{ + bool hasAttribute = false; + MonoCustomAttrInfo* attrInfo = mono_custom_attrs_from_method (method->monoMethod); + if (attrInfo != NULL && mono_custom_attrs_has_attr (attrInfo, attribute)) + hasAttribute = true; + + if (attrInfo) + mono_custom_attrs_free(attrInfo); + + return hasAttribute; +} + +ScriptingTypePtr scripting_class_get_parent(ScriptingTypePtr t, ScriptingTypeRegistry& registry) +{ + return mono_class_get_parent(t); +} + +void scripting_class_get_methods(ScriptingTypePtr t, ScriptingMethodRegistry& registry, std::vector<ScriptingMethodPtr>& result) +{ + void* iterator = NULL; + ScriptingMethodPtr scriptingMethod = NULL; + while (MonoMethod* method = mono_class_get_methods(t, &iterator)) + if ((scriptingMethod = registry.GetMethod (method))) + result.push_back(scriptingMethod); +} + +ScriptingTypePtr scripting_class_from_systemtypeinstance(ScriptingObjectPtr systemTypeInstance, ScriptingTypeRegistry& typeRegistry) +{ + if (!systemTypeInstance) + return NULL; + + MonoClass* klass = mono_class_from_mono_type(ExtractMonoObjectData<MonoType*>(systemTypeInstance)); + return typeRegistry.GetType(klass); +} + +const char* scripting_class_get_name(ScriptingClassPtr klass) +{ + return mono_class_get_name(klass); +} + +const char* scripting_class_get_namespace(ScriptingClassPtr klass) +{ + return mono_class_get_namespace(klass); +} + +bool scripting_class_is_subclass_of(ScriptingClassPtr c1, ScriptingClassPtr c2) +{ + return mono_class_is_subclass_of(c1,c2,true); +} + +bool scripting_class_is_enum(ScriptingClassPtr klass) +{ + return mono_class_is_enum (klass); +} + +ScriptingTypePtr scripting_object_get_class(ScriptingObjectPtr t, ScriptingTypeRegistry& registry) +{ + return mono_object_get_class(t); +} + +void scripting_object_invoke_default_constructor(ScriptingObjectPtr t, ScriptingExceptionPtr* exc) +{ + mono_runtime_object_init_exception(t,exc); +} + +ScriptingMethodPtr scripting_object_get_virtual_method(ScriptingObjectPtr o, ScriptingMethodPtr method, ScriptingMethodRegistry& methodRegistry) +{ + return methodRegistry.GetMethod(mono_object_get_virtual_method(o,method->monoMethod)); +} + +ScriptingObjectPtr scripting_object_new(ScriptingTypePtr t) +{ +#if UNITY_EDITOR + if (mono_unity_class_is_abstract (t)) { + // Cannot instantiate abstract class + return SCRIPTING_NULL; + } +#endif + return mono_object_new(mono_domain_get(), t); +} + +int scripting_gchandle_new(ScriptingObjectPtr o) +{ + return mono_gchandle_new(o,1); +} + +int scripting_gchandle_weak_new(ScriptingObjectPtr o) +{ + return mono_gchandle_new_weakref(o, 1); +} + +void scripting_gchandle_free(int handle) +{ + mono_gchandle_free(handle); +} + +ScriptingObjectPtr scripting_gchandle_get_target(int handle) +{ + return mono_gchandle_get_target(handle); +} + +int scripting_gc_maxgeneration() +{ + return mono_gc_max_generation(); +} + +void scripting_gc_collect(int maxGeneration) +{ + mono_gc_collect(maxGeneration); +} + +ScriptingObjectPtr scripting_method_invoke(ScriptingMethodPtr method, ScriptingObjectPtr object, ScriptingArguments& arguments, ScriptingExceptionPtr* exception) +{ +#if UNITY_EDITOR + bool IsStackLargeEnough (); + if (!IsStackLargeEnough ()) + { + *exception = mono_exception_from_name_msg (mono_get_corlib (), "System", "StackOverflowException", ""); + return NULL; + } +#endif + + if (method->fastMonoMethod) + { + Assert(arguments.GetCount()==0); + Assert(object); + return method->fastMonoMethod(object,exception); + } + + return mono_runtime_invoke(method->monoMethod, object, arguments.InMonoFormat(), exception); +} + +ScriptingObjectPtr scripting_class_get_object(ScriptingClassPtr klass) +{ + return mono_class_get_object(klass); +} + +ScriptingArrayPtr scripting_cast_object_to_array(ScriptingObjectPtr o) +{ + return (ScriptingArrayPtr)o; +} + +ScriptingStringPtr scripting_string_new(const std::string& str) +{ + return scripting_string_new(str.c_str()); +} + +ScriptingStringPtr scripting_string_new(const UnityStr& str) +{ + return scripting_string_new(str.c_str()); +} + +ScriptingStringPtr scripting_string_new(const char* str) +{ + return MonoStringNew(str); +} + +ScriptingStringPtr scripting_string_new(const wchar_t* str) +{ + return MonoStringNewUTF16(str); +} + +ScriptingStringPtr scripting_string_new(const char* str, unsigned int length) +{ + return MonoStringNewLength(str, length); +} + +void scripting_stack_trace_info_for(ScriptingExceptionPtr exception, StackTraceInfo& info) +{ + AssertIf (exception == NULL); + + MonoException* tempException = NULL; + MonoString* monoStringMessage = NULL; + MonoString* monoStringTrace = NULL; + void* args[] = { exception, &monoStringMessage, &monoStringTrace }; + + if (GetMonoManagerPtr () && GetMonoManager ().GetCommonClasses ().extractStringFromException) + { + // Call mono_runtime_invoke directly to avoid our stack size check in mono_runtime_invoke_profiled. + // We *should* have enough stack here to make this call, and a stack trace would be useful for the user. + mono_runtime_invoke (GetMonoManager ().GetCommonClasses ().extractStringFromException->monoMethod, (MonoObject*)exception, args, &tempException); + } + + if (tempException) + { + char const* exceptionClassName = mono_class_get_name(mono_object_get_class((MonoObject*)tempException)); + ErrorString ("Couldn't extract exception string from exception (another exception of class '" + + std::string (exceptionClassName) + "' was thrown while processing the stack trace)"); + return; + } + + // Log returned string + string message; + + char* extractedMessage = NULL; + if (monoStringMessage) + message = extractedMessage = mono_string_to_utf8 (monoStringMessage); + + char* extractedTrace = NULL; + if (monoStringTrace) + extractedTrace = mono_string_to_utf8 (monoStringTrace); + + string processedStackTrace; + int line = -1; + string path; + + if (extractedTrace && *extractedTrace != 0) + { + PostprocessStacktrace(extractedTrace, processedStackTrace); + ExceptionToLineAndPath (processedStackTrace, line, path); + } + + info.condition = message; + info.strippedStacktrace = processedStackTrace; + info.stacktrace = extractedTrace; + info.errorNum = 0; + info.file = path; + info.line = line; + + g_free (extractedMessage); + g_free (extractedTrace); +} + +void* scripting_array_element_ptr(ScriptingArrayPtr array, int i, size_t element_size) +{ + return kMonoArrayOffset + i * element_size + (char*)array; +}
\ No newline at end of file diff --git a/Runtime/Scripting/Backend/Mono/ScriptingBackendApi_Mono.h b/Runtime/Scripting/Backend/Mono/ScriptingBackendApi_Mono.h new file mode 100644 index 0000000..e6ae12a --- /dev/null +++ b/Runtime/Scripting/Backend/Mono/ScriptingBackendApi_Mono.h @@ -0,0 +1,15 @@ +#ifndef _SCRIPTINGBACKENDAPI_MONO_H_ +#define _SCRIPTINGBACKENDAPI_MONO_H_ + +#include "../ScriptingTypes.h" + +typedef MonoObject* (*FastMonoMethod) (void* thiz, MonoException** ex); + +struct ScriptingMethod +{ + MonoMethod* monoMethod; + FastMonoMethod fastMonoMethod; + bool isInstance; +}; + +#endif diff --git a/Runtime/Scripting/Backend/Mono/ScriptingMethodFactory_Mono.h b/Runtime/Scripting/Backend/Mono/ScriptingMethodFactory_Mono.h new file mode 100644 index 0000000..a7519f8 --- /dev/null +++ b/Runtime/Scripting/Backend/Mono/ScriptingMethodFactory_Mono.h @@ -0,0 +1,83 @@ +#ifndef _SCRIPTINGMETHODFACTORY_MONO_ +#define _SCRIPTINGMETHODFACTORY_MONO_ + +#include "../ScriptingMethodFactory.h" +#include "Runtime/Mono/MonoIncludes.h" +#include "../ScriptingMethodRegistry.h" +#if ENABLE_MONO + + +// Flag defined in mono, when AOT libraries are built with -ficall option +// But that is not available in mono/consoles +extern "C" int mono_ficall_flag; + +FastMonoMethod FastMonoMethodPtrFor(MonoMethod* method) +{ +#if USE_MONO_AOT && !(UNITY_XENON || UNITY_PS3) + return mono_ficall_flag && method ? (FastMonoMethod) mono_aot_get_method(mono_domain_get(), method) : NULL; +#else + return NULL; +#endif +} + +static bool MethodMatchesSearchFilter(MonoMethod* method, int searchFilter) +{ + MonoMethodSignature* sig = mono_method_signature(method); + return MethodDescriptionMatchesSearchFilter(searchFilter, mono_signature_is_instance(sig), mono_signature_get_param_count(sig)); +} + +class ScriptingMethodFactory_Mono : public IScriptingMethodFactory +{ +public: + virtual ScriptingMethodPtr Produce(ScriptingTypePtr klass, const char* name, int searchFilter) + { + void* iterator = NULL; + while (MonoMethod* method = mono_class_get_methods(klass, &iterator)) + { + if (!method) + return NULL; + + if (strcmp(mono_method_get_name(method), name)!=0) + continue; + + if (MethodMatchesSearchFilter(method,searchFilter)) + return Produce(method); + } + return NULL; + } + + virtual ScriptingMethodPtr Produce(BackendNativeMethod nativeMethod) + { + ScriptingMethodPtr result = new ScriptingMethod(); + result->monoMethod = nativeMethod; + MonoMethodSignature* sig = mono_method_signature(nativeMethod); +#if UNITY_EDITOR + if (!sig) { + // Loader error - usually missing reference + Scripting::LogException(mono_loader_error_prepare_exception (mono_loader_get_last_error ()), 0); + return NULL; + } +#endif + result->isInstance = mono_signature_is_instance(sig); + result->fastMonoMethod = IsSignatureSupportedForFastAotCalls(sig) ? FastMonoMethodPtrFor(nativeMethod) : NULL; + return result; + } + + virtual void Release(ScriptingMethodPtr method) + { + delete method; + } + +private: + bool IsSignatureSupportedForFastAotCalls(MonoMethodSignature* sig) + { + if (!mono_signature_is_instance(sig)) + return false; + + return mono_signature_get_param_count(sig) == 0; + } +}; + +#endif + +#endif diff --git a/Runtime/Scripting/Backend/ScriptingArguments.cpp b/Runtime/Scripting/Backend/ScriptingArguments.cpp new file mode 100644 index 0000000..9fcbaad --- /dev/null +++ b/Runtime/Scripting/Backend/ScriptingArguments.cpp @@ -0,0 +1,218 @@ +#include "UnityPrefix.h" +#include "ScriptingTypes.h" + +#if ENABLE_SCRIPTING + +#include "ScriptingArguments.h" +#include "Runtime/Scripting/ScriptingUtility.h" + +ScriptingArguments::ScriptingArguments() + : m_Count(0) +{ +#if UNITY_WINRT + m_StringArguments = ref new Platform::Array<Platform::String^>(MAXARGS); +#else + memset(m_Arguments, 0, sizeof(m_Arguments)); +#endif + memset(&m_PrimitiveStorage, 0, sizeof(m_PrimitiveStorage)); + memset(m_ArgumentTypes, 0, sizeof(m_ArgumentTypes)); +} + +void ScriptingArguments::AddBoolean(bool value) +{ + m_PrimitiveStorage.ints[m_Count] = value ? 1 : 0; +#if UNITY_WINRT + m_Arguments[m_Count] = m_PrimitiveStorage.ints[m_Count]; +#else + m_Arguments[m_Count] = &m_PrimitiveStorage.ints[m_Count]; +#endif + m_ArgumentTypes[m_Count] = ARGTYPE_BOOLEAN; + m_Count++; +} + +void ScriptingArguments::AddInt(int value) +{ + m_PrimitiveStorage.ints[m_Count] = value; +#if UNITY_WINRT + m_Arguments[m_Count] = *(long long*)&value; +#else + m_Arguments[m_Count] = &m_PrimitiveStorage.ints[m_Count]; +#endif + m_ArgumentTypes[m_Count] = ARGTYPE_INT; + m_Count++; +} + +void ScriptingArguments::AddFloat(float value) +{ + m_PrimitiveStorage.floats[m_Count] = value; +#if UNITY_WINRT + m_Arguments[m_Count] = *(long long*)&value; +#else + m_Arguments[m_Count] = &m_PrimitiveStorage.floats[m_Count]; +#endif + m_ArgumentTypes[m_Count] = ARGTYPE_FLOAT; + m_Count++; +} + +void ScriptingArguments::AddString(const char* str) +{ +#if ENABLE_MONO + m_Arguments[m_Count] = MonoStringNew(str); +#elif UNITY_FLASH + m_Arguments[m_Count] = str; +#elif UNITY_WINRT + m_StringArguments[m_Count] = ConvertUtf8ToString(str); + m_Arguments[m_Count] = (long long)m_StringArguments[m_Count]->Data(); +#endif + m_ArgumentTypes[m_Count] = ARGTYPE_STRING; + m_Count++; +} + +void ScriptingArguments::AddString(std::string& str) +{ + AddString(str.c_str()); +} + +void ScriptingArguments::AddObject(ScriptingObjectPtr scriptingObject) +{ +#if UNITY_WINRT + m_Arguments[m_Count] = scriptingObject.GetHandle(); +#else + m_Arguments[m_Count] = scriptingObject; +#endif + m_ArgumentTypes[m_Count] = ARGTYPE_OBJECT; + m_Count++; +} + +void ScriptingArguments::AddStruct(void* pointerToStruct) +{ +#if UNITY_WINRT + // We need to pass struct size, and ScriptingType here, to set the struct for metro + FatalErrorMsg("ToDo"); +#else + m_Arguments[m_Count] = pointerToStruct; +#endif + m_ArgumentTypes[m_Count] = ARGTYPE_STRUCT; + m_Count++; +} + +void ScriptingArguments::AddArray(ScriptingArrayPtr arr) +{ +#if UNITY_WINRT + m_Arguments[m_Count] = arr.GetHandle(); +#elif UNITY_FLASH + FatalErrorMsg("ToDo"); +#else + m_Arguments[m_Count] = arr; +#endif + m_ArgumentTypes[m_Count] = ARGTYPE_ARRAY; + m_Count++; +} + +void ScriptingArguments::AddEnum(int value) +{ + AddInt(value); + m_ArgumentTypes[m_Count-1] = ARGTYPE_ENUM; +} + +bool ScriptingArguments::GetBooleanAt(int index) +{ + return m_PrimitiveStorage.ints[index] == 1; +} + +int ScriptingArguments::GetIntAt(int index) +{ + return m_PrimitiveStorage.ints[index]; +} + +float ScriptingArguments::GetFloatAt(int index) +{ + return m_PrimitiveStorage.floats[index]; +} + +const void* ScriptingArguments::GetStringAt(int index) +{ +#if UNITY_WINRT + return m_StringArguments[index]->Data(); +#else + return m_Arguments[index]; +#endif +} + +ScriptingObjectPtr ScriptingArguments::GetObjectAt(int index) +{ +#if UNITY_WINRT + return ScriptingObjectPtr(safe_cast<long long>(m_Arguments[index])); +#else + return (ScriptingObjectPtr) m_Arguments[index]; +#endif +} + +void** ScriptingArguments::InMonoFormat() +{ + return (void**) &m_Arguments[0]; +} + +int ScriptingArguments::GetTypeAt(int index) +{ + return m_ArgumentTypes[index]; +} + +int ScriptingArguments::GetCount() +{ + return m_Count; +} + +void ScriptingArguments::AdjustArgumentsToMatchMethod(ScriptingMethodPtr method) +{ +#if ENABLE_MONO + MonoMethodSignature* sig = mono_method_signature (method->monoMethod); + int methodCount = mono_signature_get_param_count (sig); + if (methodCount < m_Count) + m_Count = methodCount; +#endif +} + +bool ScriptingArguments::CheckArgumentsAgainstMethod(ScriptingMethodPtr method) +{ +#if !ENABLE_MONO + return true; +#else + + MonoMethodSignature* sig = mono_method_signature (method->monoMethod); + int argCount = mono_signature_get_param_count (sig); + if (argCount != GetCount()) + return false; + + void* iterator = NULL; + int argIndex = -1; + while(true) + { + argIndex++; + MonoType* methodType = mono_signature_get_params (sig, &iterator); + if (methodType == NULL) + return true; + + if (GetTypeAt(argIndex) != ScriptingArguments::ARGTYPE_OBJECT) + continue; + + MonoClass* invokingArgument = mono_object_get_class(GetObjectAt(argIndex)); + MonoClass* receivingArgument = mono_class_from_mono_type (methodType); + + if (!mono_class_is_subclass_of (invokingArgument, receivingArgument, false)) + return false; + } + return true; +#endif +} + + +#if UNITY_WINRT +ScriptingParamsPtr ScriptingArguments::InMetroFormat() +{ + if (m_Count <= 0) return SCRIPTING_NULL; + return &m_Arguments[0]; +} +#endif + +#endif diff --git a/Runtime/Scripting/Backend/ScriptingArguments.h b/Runtime/Scripting/Backend/ScriptingArguments.h new file mode 100644 index 0000000..9ea823f --- /dev/null +++ b/Runtime/Scripting/Backend/ScriptingArguments.h @@ -0,0 +1,79 @@ +#ifndef _SCRIPTINGARGUMENTS_H_ +#define _SCRIPTINGARGUMENTS_H_ + +#if ENABLE_SCRIPTING +#include "ScriptingTypes.h" +#include <string> +#include "Runtime/Modules/ExportModules.h" + + +struct EXPORT_COREMODULE ScriptingArguments +{ + enum Constants + { + MAXARGS=10 + }; + + enum ArgType + { + ARGTYPE_BOOLEAN, + ARGTYPE_INT, + ARGTYPE_FLOAT, + ARGTYPE_STRING, + ARGTYPE_OBJECT, + ARGTYPE_STRUCT, + ARGTYPE_ARRAY, + ARGTYPE_ENUM + }; + + //this setup is kind of weird. some types of arguments just need to be stuffed in m_Arguments, + //however for ints and floats, instead of stuffing them in, mono actually excepts a pointer to one. + //to make it happy, we store the actual int in a field, and store a pointer to it in the ScriptingParam. + union + { + int ints[MAXARGS]; + float floats[MAXARGS]; + } m_PrimitiveStorage; + +#if UNITY_WINRT + Platform::Array<Platform::String^>^ m_StringArguments; + ScriptingParams m_Arguments[MAXARGS]; +#else + const void* m_Arguments[MAXARGS]; +#endif + int m_ArgumentTypes[MAXARGS]; + int m_Count; + + ScriptingArguments(); + + void AddBoolean(bool value); + void AddInt(int value); + void AddFloat(float value); + void AddString(const char* str); + void AddString(std::string& str); + void AddObject(ScriptingObjectPtr scriptingObject); + void AddStruct(void* pointerToStruct); + void AddEnum(int value); + void AddArray(ScriptingArrayPtr arr); + + bool GetBooleanAt(int index); + int GetIntAt(int index); + float GetFloatAt(int index); + const void* GetStringAt(int index); + ScriptingObjectPtr GetObjectAt(int index); + + void** InMonoFormat(); + + void AdjustArgumentsToMatchMethod(ScriptingMethodPtr method); + bool CheckArgumentsAgainstMethod(ScriptingMethodPtr method); +#if UNITY_WINRT + ScriptingParamsPtr InMetroFormat(); +#endif + + int GetTypeAt(int index); + int GetCount(); +}; + +#endif + +#endif diff --git a/Runtime/Scripting/Backend/ScriptingBackendApi.h b/Runtime/Scripting/Backend/ScriptingBackendApi.h new file mode 100644 index 0000000..1e729b7 --- /dev/null +++ b/Runtime/Scripting/Backend/ScriptingBackendApi.h @@ -0,0 +1,72 @@ +#ifndef _SCRIPTINGBACKEND_API_H_ +#define _SCRIPTINGBACKEND_API_H_ + +#include <string> + +#include "ScriptingTypes.h" +class ScriptingMethodRegistry; +class ScriptingTypeRegistry; +struct ScriptingArguments; + +struct StackTraceInfo +{ + std::string condition; + std::string strippedStacktrace; + std::string stacktrace; + int errorNum; + std::string file; + int line; +}; + +bool scripting_method_is_instance(ScriptingMethodPtr method); +const char* scripting_method_get_name(ScriptingMethodPtr method); +int scripting_method_get_argument_count(ScriptingMethodPtr method, ScriptingTypeRegistry& typeRegistry); +ScriptingTypePtr scripting_method_get_returntype(ScriptingMethodPtr method, ScriptingTypeRegistry& typeRegistry); +bool scripting_method_has_attribute(ScriptingMethodPtr method, ScriptingClassPtr attribute); +ScriptingTypePtr scripting_method_get_nth_argumenttype(ScriptingMethodPtr method, int index, ScriptingTypeRegistry& typeRegistry); +ScriptingObjectPtr scripting_method_invoke(ScriptingMethodPtr method, ScriptingObjectPtr object, ScriptingArguments& arguments, ScriptingExceptionPtr* exception); + +ScriptingTypePtr scripting_class_get_parent(ScriptingTypePtr t, ScriptingTypeRegistry& typeRegistry); +void scripting_class_get_methods(ScriptingTypePtr t, ScriptingMethodRegistry& registry, std::vector<ScriptingMethodPtr>& result); +const char* scripting_class_get_name(ScriptingTypePtr t); +const char* scripting_class_get_namespace(ScriptingTypePtr t); +bool scripting_class_is_subclass_of(ScriptingTypePtr t1, ScriptingTypePtr t2); +bool scripting_class_is_enum(ScriptingTypePtr t); +ScriptingObjectPtr scripting_object_new(ScriptingTypePtr t); +void scripting_object_invoke_default_constructor(ScriptingObjectPtr o, ScriptingExceptionPtr* exc); +ScriptingTypePtr scripting_object_get_class(ScriptingObjectPtr t, ScriptingTypeRegistry& typeRegistry); +ScriptingMethodPtr scripting_object_get_virtual_method(ScriptingObjectPtr o, ScriptingMethodPtr method, ScriptingMethodRegistry& methodRegistry); + +ScriptingTypePtr scripting_class_from_systemtypeinstance(ScriptingObjectPtr systemTypeInstance, ScriptingTypeRegistry& typeRegistry); + +EXPORT_COREMODULE int scripting_gchandle_new(ScriptingObjectPtr o); +EXPORT_COREMODULE int scripting_gchandle_weak_new(ScriptingObjectPtr o); +EXPORT_COREMODULE void scripting_gchandle_free(int handle); +EXPORT_COREMODULE ScriptingObjectPtr scripting_gchandle_get_target(int handle); + +int scripting_gc_maxgeneration(); +void scripting_gc_collect(int maxGeneration); + +ScriptingObjectPtr scripting_class_get_object(ScriptingClassPtr klass); +ScriptingArrayPtr scripting_cast_object_to_array(ScriptingObjectPtr o); + +ScriptingStringPtr scripting_string_new(const char* str); +ScriptingStringPtr scripting_string_new(const std::string& str); +ScriptingStringPtr scripting_string_new(const wchar_t* str); +ScriptingStringPtr scripting_string_new(const char* str, unsigned int length); + +void scripting_stack_trace_info_for(ScriptingExceptionPtr exception, StackTraceInfo& info); +EXPORT_COREMODULE std::string scripting_cpp_string_for(ScriptingStringPtr ptr); + +void* scripting_array_element_ptr(ScriptingArrayPtr array, int i, size_t element_size); + +// TODO: temporary, these includes are going to disappear very soon + +#if UNITY_FLASH +#include "Runtime/Scripting/Backend/Flash/ScriptingBackendApi_Flash.h" +#elif UNITY_WINRT +#elif ENABLE_MONO +#include "Runtime/Scripting/Backend/Mono/ScriptingBackendApi_Mono.h" +#endif + +#endif diff --git a/Runtime/Scripting/Backend/ScriptingInvocation.cpp b/Runtime/Scripting/Backend/ScriptingInvocation.cpp new file mode 100644 index 0000000..71ead05 --- /dev/null +++ b/Runtime/Scripting/Backend/ScriptingInvocation.cpp @@ -0,0 +1,223 @@ +#include "UnityPrefix.h" + +#if ENABLE_SCRIPTING + +#include "ScriptingInvocation.h" +#include "Runtime/Utilities/LogAssert.h" +#include "Runtime/Scripting/ScriptingUtility.h" +#include "ScriptingArguments.h" +#include "ScriptingMethodRegistry.h" +#include "Runtime/Scripting/Backend/ScriptingBackendApi.h" +#include "Runtime/Profiler/Profiler.h" +#include "Runtime/Scripting/ScriptingManager.h" + +#if ENABLE_MONO +#include "Runtime/Mono/MonoIncludes.h" +#include "Runtime/Mono/MonoManager.h" +#include "Runtime/Mono/MonoUtility.h" +#include "Runtime/Mono/MonoScript.h" +#endif + +ScriptingInvocation::ScriptingInvocation() +{ +} + +ScriptingInvocation::ScriptingInvocation(ScriptingMethodPtr in_method) + : ScriptingInvocationNoArgs(in_method) +{ +} + +#if ENABLE_MONO || UNITY_WINRT +ScriptingInvocation::ScriptingInvocation(const char* namespaze, const char* klassName, const char* methodName) +{ + method = GetScriptingMethodRegistry().GetMethod(namespaze, klassName, methodName); +} + +ScriptingInvocation::ScriptingInvocation(ScriptingClassPtr klass, const char* methodName) +{ + method = GetScriptingMethodRegistry().GetMethod(klass, methodName); +} + +ScriptingInvocation::ScriptingInvocation(BackendNativeMethod monoMethod) +{ + method = GetScriptingMethodRegistry().GetMethod(monoMethod); +} +#endif + +bool ScriptingInvocation::Check() +{ +#if !ENABLE_MONO + return true; +#else + return ScriptingInvocationNoArgs::Check() && arguments.CheckArgumentsAgainstMethod(method); +#endif +} + +template<class T> +T ScriptingInvocation::Invoke() +{ + ScriptingExceptionPtr ex = NULL; + return Invoke<T>(&ex); +} + +template<> +ScriptingObjectPtr ScriptingInvocation::Invoke<ScriptingObjectPtr>() +{ + return Invoke(); +} + +template<> +bool ScriptingInvocation::Invoke<bool>(ScriptingExceptionPtr* exception) +{ + ScriptingObjectPtr o = Invoke(exception); + if (*exception != NULL) + return false; + + #if ENABLE_MONO + if (method->fastMonoMethod) + return (bool)o; + else + return ExtractMonoObjectData<char>(o); + #elif UNITY_FLASH + bool boolResult; + __asm __volatile__("%0 = marshallmap.getObjectWithId(%1);" : "=r"(boolResult) : "r"(o)); + return boolResult; + #elif UNITY_WINRT + return o != SCRIPTING_NULL ? o.ToBool() : false; + #endif +} + +ScriptingObjectPtr ScriptingInvocation::Invoke() +{ + ScriptingExceptionPtr ex = NULL; + return Invoke(&ex); +} + +ScriptingObjectPtr ScriptingInvocation::Invoke(ScriptingExceptionPtr* exception) +{ + return Invoke(exception, false); +} + +ScriptingObjectPtr ScriptingInvocation::Invoke(ScriptingExceptionPtr* exception, bool convertArguments) +{ + ScriptingObjectPtr returnValue; + + *exception = NULL; + +#if ENABLE_MONO || UNITY_FLASH || UNITY_WINRT + MONO_PROFILER_BEGIN (method, classContextForProfiler, object) +#if UNITY_WINRT + ScriptingObjectPtr metro_invoke_method(ScriptingMethodPtr method, ScriptingObjectPtr object, ScriptingArguments* arguments, ScriptingExceptionPtr* exception, bool convertArgs); + returnValue = metro_invoke_method(method, object, &arguments, exception, convertArguments); +#else + returnValue = scripting_method_invoke(method, object, arguments, exception); +#endif + MONO_PROFILER_END +#elif !UNITY_EXTERNAL_TOOL + ErrorString("Invoke() not implemented on this platform"); +#else + return NULL; +#endif + + if (! *exception) return returnValue; + + this->exception = *exception; +#if !UNITY_EXTERNAL_TOOL + if (logException) + Scripting::LogException(*exception, objectInstanceIDContextForException ); +#endif + + return SCRIPTING_NULL; +} + +void ScriptingInvocation::AdjustArgumentsToMatchMethod() +{ + arguments.AdjustArgumentsToMatchMethod(method); +} + + +#if ENABLE_MONO + +MonoObject* CallStaticMonoMethod (MonoClass* klass , const char* methodName, void** parameters) +{ + MonoException* exception = NULL; + return CallStaticMonoMethod(klass, methodName, parameters, &exception); +} + + +static MonoObject* CallStaticMonoMethod (MonoMethod* method, void** parameters, MonoException** exception) +{ + MonoObject* returnValue = mono_runtime_invoke_profiled (method, NULL, parameters, exception); + if (! *exception) return returnValue; + + Scripting::LogException(*exception, 0); + return NULL; +} + + +static MonoObject* CallStaticMonoMethod (MonoMethod* method, void** parameters) +{ + MonoException* exception = NULL; + return CallStaticMonoMethod(method, parameters, &exception); +} + +MonoObject* CallStaticMonoMethod (const char* className, const char* methodName, void** parameters) +{ + MonoException* exception = NULL; + return CallStaticMonoMethod(className, methodName, parameters, &exception); +} + +MonoObject* CallStaticMonoMethod (MonoClass* klass , const char* methodName, void** parameters, MonoException** exception) +{ + MonoMethod* method = mono_class_get_method_from_name (klass, methodName, -1); + + if (!method) + { + ErrorString (Format ("Couldn't call method %s in class %s because it wasn't found.", methodName, mono_class_get_name(klass))); + return NULL; + } + + return CallStaticMonoMethod(method, parameters, exception); +} + +MonoObject* CallStaticMonoMethod (const char* className, const char* methodName, void** parameters, MonoException** exception) +{ + MonoMethod* m = FindStaticMonoMethod(className, methodName); + if (!m) + { + ErrorString (Format ("Couldn't call method %s because the class %s couldn't be found.", methodName, className)); + return NULL; + } + + return CallStaticMonoMethod(m, parameters, exception); +} + +MonoObject* CallStaticMonoMethod (const char* className, const char* nameSpace, const char* methodName, void** parameters) +{ + MonoException* exception = NULL; + MonoMethod* m = FindStaticMonoMethod(nameSpace, className, methodName); + if (!m) + { + ErrorString (Format ("Couldn't call method %s because the class %s couldn't be found.", methodName, className)); + return NULL; + } + + return CallStaticMonoMethod(m, parameters, &exception); +} + +MonoObject* CallStaticMonoMethod (const char* className, const char* nameSpace, const char* methodName, void** parameters, MonoException** exception) +{ + MonoMethod* m = FindStaticMonoMethod(nameSpace, className, methodName); + if (!m) + { + ErrorString (Format ("Couldn't call method %s because the class %s couldn't be found.", methodName, className)); + return NULL; + } + + return CallStaticMonoMethod(m, parameters, exception); +} + + +#endif + +#endif diff --git a/Runtime/Scripting/Backend/ScriptingInvocation.h b/Runtime/Scripting/Backend/ScriptingInvocation.h new file mode 100644 index 0000000..2bad02c --- /dev/null +++ b/Runtime/Scripting/Backend/ScriptingInvocation.h @@ -0,0 +1,73 @@ +#ifndef _SCRIPTINGINVOCATION_H_ +#define _SCRIPTINGINVOCATION_H_ + +#if ENABLE_SCRIPTING + +#include "ScriptingInvocationNoArgs.h" +#include "ScriptingArguments.h" + + +/// ScriptingInvocation invocation (scriptingMethod); // Slow alternative (Don't use this in runtime code) ScriptingInvocation invocation ("MyNameSpace", "MyClassName", "MyMethod"); +/// invocation.AddInt(5); +/// invocation.Invoke (); // < you are certain that the bound method accepts those exact parameters +/// invocation.InvokeChecked(); // < you cant guarantee that the bound method has the passed parameters + +/// By default logs the exception (Can be turned off via invocation.logException = false;) +/// Parameters are setup AddInt, AddFloat, AddStruct functions below +class ScriptingInvocation : public ScriptingInvocationNoArgs +{ +public: + ScriptingInvocation(); + ScriptingInvocation(ScriptingMethodPtr in_method); +#if ENABLE_MONO || UNITY_WINRT + ScriptingInvocation(const char* namespaze, const char* klass, const char* name); + ScriptingInvocation(ScriptingClassPtr klass, const char* name); + ScriptingInvocation(BackendNativeMethod method); +#endif + + //convenience forwarders to arguments + void AddBoolean(bool value) { arguments.AddBoolean(value); } + void AddInt(int value) { arguments.AddInt(value); } + void AddFloat(float value) { arguments.AddFloat(value); } + void AddString(const char* str) { arguments.AddString(str); } + void AddString(std::string& str) { arguments.AddString(str); } + void AddObject(ScriptingObjectPtr scriptingObject) { arguments.AddObject(scriptingObject); } + void AddStruct(void* pointerToStruct) { arguments.AddStruct(pointerToStruct); } + void AddEnum(int value) { arguments.AddEnum(value); } + void AddArray(ScriptingArrayPtr arr) { arguments.AddArray(arr); } + + void AdjustArgumentsToMatchMethod(); + + template<class T> T Invoke(); + template<class T> T Invoke(ScriptingException**); + ScriptingObjectPtr Invoke(); + ScriptingObjectPtr Invoke(ScriptingException**); + ScriptingObjectPtr Invoke(ScriptingExceptionPtr*, bool); + + ScriptingArguments& Arguments() { return arguments; } +protected: + ScriptingArguments arguments; + virtual bool Check(); +}; + + +#if ENABLE_MONO + +struct MonoObject; +struct MonoException; +class Object; +struct MonoMethod; +struct MonoClass; +class MonoScript; + +MonoObject* CallStaticMonoMethod (const char* className, const char* methodName, void** parameters = NULL); +MonoObject* CallStaticMonoMethod (const char* className, const char* methodName, void** parameters, MonoException** exception); +MonoObject* CallStaticMonoMethod (const char* className, const char* nameSpace, const char* methodName, void** paramenters = NULL); +MonoObject* CallStaticMonoMethod (const char* className, const char* nameSpace, const char* methodName, void** paramenters, MonoException** exception); +MonoObject* CallStaticMonoMethod (MonoClass* klass , const char* methodName, void** parameters = NULL); +MonoObject* CallStaticMonoMethod (MonoClass* klass , const char* methodName, void** parameters, MonoException** exception); +#endif + +#endif + +#endif diff --git a/Runtime/Scripting/Backend/ScriptingInvocationNoArgs.cpp b/Runtime/Scripting/Backend/ScriptingInvocationNoArgs.cpp new file mode 100644 index 0000000..19ab0f0 --- /dev/null +++ b/Runtime/Scripting/Backend/ScriptingInvocationNoArgs.cpp @@ -0,0 +1,123 @@ +#include "UnityPrefix.h" + +#if ENABLE_SCRIPTING + +#include "ScriptingInvocationNoArgs.h" +#include "Runtime/Utilities/LogAssert.h" +#include "Runtime/Scripting/ScriptingUtility.h" +#include "ScriptingMethodRegistry.h" +#include "Runtime/Scripting/Backend/ScriptingBackendApi.h" +#include "Runtime/Profiler/Profiler.h" + +#if ENABLE_MONO +#include "Runtime/Mono/MonoIncludes.h" +#include "Runtime/Mono/MonoManager.h" +#include "Runtime/Mono/MonoUtility.h" +#include "Runtime/Mono/MonoScript.h" +#endif + +ScriptingInvocationNoArgs::ScriptingInvocationNoArgs() +{ + SetDefaults(); +} + +ScriptingInvocationNoArgs::ScriptingInvocationNoArgs(ScriptingMethodPtr in_method) +{ + SetDefaults(); + method = in_method; +} + +void ScriptingInvocationNoArgs::SetDefaults() +{ + object = SCRIPTING_NULL; + method = SCRIPTING_NULL; + classContextForProfiler = NULL; + logException = true; + objectInstanceIDContextForException = 0; + exception = SCRIPTING_NULL; +} + +bool ScriptingInvocationNoArgs::Check() +{ +#if !ENABLE_MONO + return true; +#else + + // Check method + if (method == NULL) + { + ErrorString("Failed to call function because it was null"); + return false; + } + + bool methodIsInstance = mono_signature_is_instance (mono_method_signature(method->monoMethod)); + bool invokingInstance = object != NULL; + + if (methodIsInstance && !invokingInstance) + { + DebugStringToFile (Format("Failed to call instance function %s because the no object was provided", mono_method_get_name (method->monoMethod)), 0, __FILE_STRIPPED__, __LINE__, + kError, objectInstanceIDContextForException); + return false; + } + + if (!methodIsInstance && invokingInstance) + { + DebugStringToFile (Format("Failed to call static function %s because an object was provided", mono_method_get_name (method->monoMethod)), 0, __FILE_STRIPPED__, __LINE__, + kError, objectInstanceIDContextForException); + return false; + } + + return true; + +#endif +} + + +ScriptingObjectPtr ScriptingInvocationNoArgs::Invoke() +{ + ScriptingExceptionPtr ex = NULL; + return Invoke(&ex); +} + +ScriptingObjectPtr ScriptingInvocationNoArgs::Invoke(ScriptingExceptionPtr* exception) +{ + ScriptingObjectPtr returnValue; + + *exception = NULL; + +#if ENABLE_MONO || UNITY_FLASH || UNITY_WINRT + ScriptingArguments arguments; + MONO_PROFILER_BEGIN (method, classContextForProfiler, object) +#if UNITY_WINRT + ScriptingObjectPtr metro_invoke_method(ScriptingMethodPtr method, ScriptingObjectPtr object, ScriptingArguments* arguments, ScriptingExceptionPtr* exception, bool convertArgs); + returnValue = metro_invoke_method(method, object, NULL, exception, false); +#else + returnValue = scripting_method_invoke(method, object, arguments, exception); +#endif + MONO_PROFILER_END +#elif !UNITY_EXTERNAL_TOOL + ErrorString("Invoke() not implemented on this platform"); +#else + return NULL; +#endif + + if (! *exception) return returnValue; + + this->exception = *exception; +#if !UNITY_EXTERNAL_TOOL + if (logException) + Scripting::LogException(*exception, objectInstanceIDContextForException); +#endif + + return SCRIPTING_NULL; +} + +ScriptingObjectPtr ScriptingInvocationNoArgs::InvokeChecked() +{ + if (!Check()) + return SCRIPTING_NULL; + + return Invoke(); +} + +#endif diff --git a/Runtime/Scripting/Backend/ScriptingInvocationNoArgs.h b/Runtime/Scripting/Backend/ScriptingInvocationNoArgs.h new file mode 100644 index 0000000..ece7010 --- /dev/null +++ b/Runtime/Scripting/Backend/ScriptingInvocationNoArgs.h @@ -0,0 +1,31 @@ +#ifndef _SCRIPTINGINVOCATIONNOARGS_H_ +#define _SCRIPTINGINVOCATIONNOARGS_H_ + +#if ENABLE_SCRIPTING + +#include "ScriptingTypes.h" + +class ScriptingInvocationNoArgs +{ +public: + ScriptingInvocationNoArgs(); + ScriptingInvocationNoArgs(ScriptingMethodPtr in_method); + + ScriptingMethodPtr method; + ScriptingObjectPtr object; + int objectInstanceIDContextForException; + ScriptingTypePtr classContextForProfiler; + bool logException; + ScriptingExceptionPtr exception; + + ScriptingObjectPtr Invoke(); + virtual ScriptingObjectPtr Invoke(ScriptingException**); + ScriptingObjectPtr InvokeChecked(); +protected: + void SetDefaults(); + virtual bool Check(); +}; + +#endif + +#endif diff --git a/Runtime/Scripting/Backend/ScriptingMethodFactory.h b/Runtime/Scripting/Backend/ScriptingMethodFactory.h new file mode 100644 index 0000000..a497d62 --- /dev/null +++ b/Runtime/Scripting/Backend/ScriptingMethodFactory.h @@ -0,0 +1,18 @@ +#ifndef _SCRIPTINGMETHODFACTORY_H_ +#define _SCRIPTINGMETHODFACTORY_H_ + +#include "ScriptingTypes.h" + + +// !!TODO: ScriptingMethodPtr Produce(ScriptingTypePtr klass, const char* name, int searchFilter) & ScriptingMethodPtr Produce(BackendNativeMethod nativeMethod) must return the same +// method if internally method is the same !!! +class IScriptingMethodFactory +{ +public: + virtual ~IScriptingMethodFactory() {} + virtual ScriptingMethodPtr Produce(ScriptingTypePtr klass, const char* name, int searchFilter) = 0; + virtual ScriptingMethodPtr Produce(BackendNativeMethod nativeMethod) = 0; + virtual void Release(ScriptingMethodPtr) = 0; +}; + +#endif diff --git a/Runtime/Scripting/Backend/ScriptingMethodRegistry.cpp b/Runtime/Scripting/Backend/ScriptingMethodRegistry.cpp new file mode 100644 index 0000000..e9df7fd --- /dev/null +++ b/Runtime/Scripting/Backend/ScriptingMethodRegistry.cpp @@ -0,0 +1,165 @@ +#include "UnityPrefix.h" +#if ENABLE_SCRIPTING +#include "ScriptingMethodRegistry.h" +#include "ScriptingMethodFactory.h" +#include "ScriptingTypeRegistry.h" +#include "Runtime/Mono/MonoIncludes.h" +#include "ScriptingBackendApi.h" +#include "Runtime/Scripting/ScriptingManager.h" + +using std::vector; + + +ScriptingMethodRegistry::ScriptingMethodRegistry(IScriptingMethodFactory* scriptingMethodFactory, ScriptingTypeRegistry* scriptingTypeRegistry) + : m_ScriptingMethodFactory(scriptingMethodFactory), + m_ScriptingTypeRegistry(scriptingTypeRegistry) +{ +} + +ScriptingMethodPtr ScriptingMethodRegistry::GetMethod(const char* namespaze, const char* className, const char* methodName, int searchOptions) +{ + ScriptingTypePtr klass = m_ScriptingTypeRegistry->GetType(namespaze,className); + if (klass==SCRIPTING_NULL) + return SCRIPTING_NULL; + return GetMethod(klass,methodName,searchOptions); +} + +ScriptingMethodPtr ScriptingMethodRegistry::GetMethod(BackendNativeMethod nativeMethod) +{ + NativeMethodToScriptingMethod::iterator i = m_NativeMethodToScriptingMethod.find(nativeMethod); + if (i != m_NativeMethodToScriptingMethod.end()) + return i->second; + + ScriptingMethodPtr scriptingMethod = m_ScriptingMethodFactory->Produce(nativeMethod); + m_NativeMethodToScriptingMethod[nativeMethod] = scriptingMethod; + return scriptingMethod; +} + +ScriptingMethodPtr ScriptingMethodRegistry::GetMethod(ScriptingTypePtr klass, const char* methodName, int searchOptions) +{ + bool found; + ScriptingMethodPtr cached = FindInCache(klass,methodName,searchOptions,&found); + if (found) + return cached; + + ScriptingMethodPtr scriptingMethod = m_ScriptingMethodFactory->Produce(klass,methodName, searchOptions); + + if (!scriptingMethod && (!(searchOptions & kDontSearchBaseTypes))) + { + ScriptingTypePtr baseClass = scripting_class_get_parent (klass, *m_ScriptingTypeRegistry); + if (baseClass) + scriptingMethod = GetMethod(baseClass, methodName, searchOptions); + } + + PlaceInCache(klass,methodName,scriptingMethod); + + return scriptingMethod; +} + +bool MethodDescriptionMatchesSearchFilter(int searchFilter, bool isInstance, int argCount) +{ + if ((searchFilter & ScriptingMethodRegistry::kStaticOnly) && isInstance) + return false; + + if ((searchFilter & ScriptingMethodRegistry::kInstanceOnly) && !isInstance) + return false; + + if ((searchFilter & ScriptingMethodRegistry::kWithoutArguments) && argCount>0) + return false; + + return true; +} + +static bool MethodMatchesSearchFilter(ScriptingMethodPtr method, int searchFilter) +{ + return MethodDescriptionMatchesSearchFilter(searchFilter, scripting_method_is_instance(method), scripting_method_get_argument_count(method, GetScriptingTypeRegistry())); +} + +void ScriptingMethodRegistry::AllMethodsIn(ScriptingTypePtr klass, vector<ScriptingMethodPtr>& result, int searchOptions) +{ + vector<ScriptingMethodPtr> methods; + scripting_class_get_methods(klass, *this, methods); + for (vector<ScriptingMethodPtr>::iterator item = methods.begin(); + item != methods.end(); + item++) + { + if (!MethodMatchesSearchFilter(*item, searchOptions)) + continue; + + result.push_back(*item); + } + + if (searchOptions & kDontSearchBaseTypes) + return; + + ScriptingTypePtr baseClass = scripting_class_get_parent(klass, *m_ScriptingTypeRegistry); + if (baseClass == SCRIPTING_NULL) + return; + + return AllMethodsIn(baseClass, result, searchOptions); +} + +void ScriptingMethodRegistry::InvalidateCache() +{ + //make sure to not delete a scriptingmethod twice, as it could be in the cache in multiple places. (in case of classes implementing interfaces & virtual methods) + MethodsSet todelete; + for (ClassToMethodsByName::iterator cci = m_Cache.begin(); cci != m_Cache.end(); cci++) + for (MethodsByName::iterator mbni = cci->second.begin(); mbni != cci->second.end(); mbni++) + for (VectorOfMethods::iterator smpi = mbni->second.begin(); smpi != mbni->second.end(); smpi++) + todelete.insert(*smpi); + + for (NativeMethodToScriptingMethod::iterator i = m_NativeMethodToScriptingMethod.begin(); i != m_NativeMethodToScriptingMethod.end(); i++) + todelete.insert(i->second); + + for (MethodsSet::iterator i = todelete.begin(); i != todelete.end(); i++) + m_ScriptingMethodFactory->Release(*i); + + m_Cache.clear(); + m_NativeMethodToScriptingMethod.clear(); +} + +ScriptingMethodPtr ScriptingMethodRegistry::FindInCache(ScriptingTypePtr klass, const char* name, int searchFilter, bool* found) +{ + *found = false; + MethodsByName* cc = FindMethodsByNameFor(klass); + if (cc == NULL) + return SCRIPTING_NULL; + + MethodsByName::iterator mbni = cc->find(name); + if (mbni == cc->end()) + return SCRIPTING_NULL; + + for (VectorOfMethods::iterator i = mbni->second.begin(); i != mbni->second.end(); i++) + { + if (*i == NULL || MethodMatchesSearchFilter(*i, searchFilter)) + { + *found = true; + return *i; + } + } + return SCRIPTING_NULL; +} + +void ScriptingMethodRegistry::PlaceInCache(ScriptingTypePtr klass, const char* name, ScriptingMethodPtr method) +{ + MethodsByName* mbn = FindMethodsByNameFor(klass); + if (mbn == NULL) + { + m_Cache.insert(std::make_pair(klass, MethodsByName())); + mbn = FindMethodsByNameFor(klass); + } + + VectorOfMethods vom; + vom.push_back(method); + mbn->insert(std::make_pair(name,vom)); +} + +ScriptingMethodRegistry::MethodsByName* ScriptingMethodRegistry::FindMethodsByNameFor(ScriptingTypePtr klass) +{ + ClassToMethodsByName::iterator cc = m_Cache.find(klass); + if (cc == m_Cache.end()) + return NULL; + return &cc->second; +} + +#endif diff --git a/Runtime/Scripting/Backend/ScriptingMethodRegistry.h b/Runtime/Scripting/Backend/ScriptingMethodRegistry.h new file mode 100644 index 0000000..82d7e40 --- /dev/null +++ b/Runtime/Scripting/Backend/ScriptingMethodRegistry.h @@ -0,0 +1,60 @@ +#ifndef _SCRIPTINGMETHODREGISTRY_H_ +#define _SCRIPTINGMETHODREGISTRY_H_ + +#if ENABLE_SCRIPTING +#include "ScriptingTypes.h" + +#include <map> +#include <string> +#include <vector> + +class IScriptingMethodFactory; +class ScriptingTypeRegistry; + +class ScriptingMethodRegistry +{ +public: + ScriptingMethodRegistry(IScriptingMethodFactory* scriptingMethodFactory, ScriptingTypeRegistry* scriptingTypeRegistry); + ~ScriptingMethodRegistry() {InvalidateCache();} + + enum SearchFilter + { + kNone = 0, + kInstanceOnly = 1, + kStaticOnly = 2, + kWithoutArguments = 4, + kDontSearchBaseTypes = 8, + }; + + ScriptingMethodPtr GetMethod(const char* namespaze, const char* klassName, const char* methodName, int searchOptions=kNone); + ScriptingMethodPtr GetMethod(ScriptingTypePtr klass, const char* methodName, int searchOptions=kNone); + ScriptingMethodPtr GetMethod(BackendNativeMethod nativeMathod); + + void AllMethodsIn(ScriptingTypePtr klass, std::vector<ScriptingMethodPtr>& result, int searchOptions=kNone); + + void InvalidateCache(); + +private: + typedef std::vector<ScriptingMethodPtr> VectorOfMethods; + typedef std::map< std::string,VectorOfMethods > MethodsByName; + typedef std::map<ScriptingTypePtr, MethodsByName> ClassToMethodsByName; + typedef std::map<BackendNativeMethod, ScriptingMethodPtr> NativeMethodToScriptingMethod; + typedef std::set<ScriptingMethodPtr> MethodsSet; + + ClassToMethodsByName m_Cache; + + + NativeMethodToScriptingMethod m_NativeMethodToScriptingMethod; + + IScriptingMethodFactory* m_ScriptingMethodFactory; + ScriptingTypeRegistry* m_ScriptingTypeRegistry; + + ScriptingMethodPtr FindInCache(ScriptingTypePtr klass, const char* name, int searchFilter, bool* out_found); + void PlaceInCache(ScriptingTypePtr klass, const char* name, ScriptingMethodPtr method); + MethodsByName* FindMethodsByNameFor(ScriptingTypePtr klass); +}; + +bool MethodDescriptionMatchesSearchFilter(int searchFilter, bool isInstance, int argCount); +#endif + +#endif
\ No newline at end of file diff --git a/Runtime/Scripting/Backend/ScriptingMethodRegistryTests.cpp b/Runtime/Scripting/Backend/ScriptingMethodRegistryTests.cpp new file mode 100644 index 0000000..e3735b0 --- /dev/null +++ b/Runtime/Scripting/Backend/ScriptingMethodRegistryTests.cpp @@ -0,0 +1,237 @@ +#include "UnityPrefix.h" +#if DEDICATED_UNIT_TEST_BUILD +#include "ScriptingMethodRegistry.h" +#include "External/UnitTest++/src/UnitTest++.h" +#include "ScriptingMethodFactory.h" +#include "Tests/ScriptingBackendApi_Tests.h" +#include <queue> +#include <set> +#include <vector> +using std::queue; +using std::vector; + +class ScriptingMethodFactory_Dummy : public IScriptingMethodFactory +{ +public: + queue<ScriptingMethodPtr> produceThis; + ScriptingTypePtr returnNullForRequestson; + int produceCallCount; + + ScriptingMethodFactory_Dummy() : produceCallCount(0) {} + + virtual ScriptingMethodPtr Produce(ScriptingTypePtr klass, const char* name, int searchFilter) + { + produceCallCount++; + + if (returnNullForRequestson == klass) + return NULL; + + if (produceThis.size()==0) + return NULL; + + ScriptingMethodPtr result = produceThis.front(); + + if (result && !MethodDescriptionMatchesSearchFilter(searchFilter, result->instance, result->args)) + return NULL; + + produceThis.pop(); + return result; + } + + virtual ScriptingMethodPtr Produce(void* nativePtr) + { + return Produce(NULL,NULL, 0); + } + + virtual void Release(ScriptingMethodPtr method) + { + } +}; + +struct Fixture +{ + ScriptingMethodFactory_Dummy methodFactory; + ScriptingMethodRegistry registry; + + ScriptingType normalType; + + ScriptingMethod method1; + ScriptingMethod method2; + + Fixture() : registry(&methodFactory,NULL) + { + } +}; + +TEST_FIXTURE(Fixture,RegistryProducesNullForNonExistingMethod) +{ + CHECK_EQUAL((ScriptingMethodPtr)NULL,registry.GetMethod(&normalType,"Method1")); +} + +TEST_FIXTURE(Fixture,RegistryProducesMethod) +{ + methodFactory.produceThis.push(&method1); + CHECK_EQUAL(&method1,registry.GetMethod(&normalType,"Method1")); +} + +TEST_FIXTURE(Fixture,RegistryReturnsSameMethodWhenQueriedTwiceWithSameArguments) +{ + methodFactory.produceThis.push(&method1); + + CHECK_EQUAL(&method1,registry.GetMethod(&normalType,"Method1")); + CHECK_EQUAL(&method1,registry.GetMethod(&normalType,"Method1")); +} + +TEST_FIXTURE(Fixture,RegistryReturnsDifferentMethodsWhenQueriedForTwoDifferentClasses) +{ + methodFactory.produceThis.push(&method1); + methodFactory.produceThis.push(&method2); + + CHECK_EQUAL(&method1,registry.GetMethod(&normalType,"Method1")); + CHECK_EQUAL(&method2,registry.GetMethod((ScriptingTypePtr)124,"Method1")); +} + +TEST_FIXTURE(Fixture,RegistryReturnsDifferentMethodsForDifferentSearchFilters) +{ + methodFactory.produceThis.push(&method1); + methodFactory.produceThis.push(&method2); + method1.instance = false; + method2.instance = true; + + CHECK_EQUAL(&method1,registry.GetMethod(&normalType,"Method1", ScriptingMethodRegistry::kStaticOnly)); + CHECK_EQUAL(&method2,registry.GetMethod(&normalType,"Method1", ScriptingMethodRegistry::kInstanceOnly)); +} + +TEST_FIXTURE(Fixture,RegistryDoesNotFindMethodsNotMatchingSearchFilter) +{ + methodFactory.produceThis.push(&method1); + method1.instance = true; + + ScriptingMethodPtr found = registry.GetMethod(&normalType,"Method1", ScriptingMethodRegistry::kStaticOnly); + if (found==NULL) + CHECK_EQUAL(1,1); + else + CHECK_EQUAL(1,0); +} + +TEST_FIXTURE(Fixture,RegistryRemembersNonFoundMethods) +{ + methodFactory.produceThis.push(NULL); + methodFactory.produceThis.push(NULL); + + registry.GetMethod(&normalType,"NonExisting"); + registry.GetMethod(&normalType,"NonExisting"); + + CHECK_EQUAL(1,methodFactory.produceCallCount); +} + + + +TEST_FIXTURE(Fixture,InvalidateCacheCausesNewMethodToBeProduced) +{ + methodFactory.produceThis.push(&method1); + methodFactory.produceThis.push(&method2); + + CHECK_EQUAL(&method1,registry.GetMethod(&normalType,"Method1")); + registry.InvalidateCache(); + CHECK_EQUAL(&method2,registry.GetMethod(&normalType,"Method1")); +} + +struct FixtureWithBaseTypeHavingMethod : public Fixture +{ + ScriptingType normalType; + ScriptingType baseType; + + FixtureWithBaseTypeHavingMethod() + { + normalType.baseType = &baseType; + methodFactory.produceThis.push(&method1); + methodFactory.returnNullForRequestson = &normalType; + } +}; + +TEST_FIXTURE(FixtureWithBaseTypeHavingMethod,RegistryWillSearchBaseTypesIfRequested) +{ + CHECK_EQUAL(&method1,registry.GetMethod(&normalType,"Method1")); +} + +TEST_FIXTURE(FixtureWithBaseTypeHavingMethod, RegistryWillNotSearchBaseTypesIfNotRequested) +{ + CHECK_EQUAL((ScriptingMethodPtr)NULL,registry.GetMethod(&normalType,"Method1", ScriptingMethodRegistry::kDontSearchBaseTypes)); +} + +TEST_FIXTURE(Fixture, CanGetMethodFromNativeMethodPointer) +{ + int nativeMethod; + methodFactory.produceThis.push(&method1); + CHECK_EQUAL(&method1,registry.GetMethod( &nativeMethod)); +} + +TEST_FIXTURE(Fixture, CanGetSameMethodFromNativeMethodTwice) +{ + int nativeMethod; + methodFactory.produceThis.push(&method1); + CHECK_EQUAL(&method1,registry.GetMethod(&nativeMethod)); + CHECK_EQUAL(&method1,registry.GetMethod(&nativeMethod)); +} + +TEST_FIXTURE(Fixture, InvalidateCacheClearsNativeMethodWrappers) +{ + int nativeMethod; + methodFactory.produceThis.push(&method1); + methodFactory.produceThis.push(&method2); + CHECK_EQUAL(&method1,registry.GetMethod(&nativeMethod)); + registry.InvalidateCache(); + CHECK_EQUAL(&method2,registry.GetMethod(&nativeMethod)); +} + +TEST_FIXTURE(Fixture, AllMethodsInType) +{ + normalType.methods.push_back(&method1); + + vector<ScriptingMethodPtr> result; + registry.AllMethodsIn(&normalType, result); + CHECK_EQUAL(1, result.size()); + CHECK_EQUAL(&method1, result[0]); +} + +TEST_FIXTURE(Fixture, AllMethodsInTypeWillSearchBaseTypes) +{ + ScriptingType baseType; + baseType.methods.push_back(&method1); + normalType.baseType = &baseType; + + vector<ScriptingMethodPtr> result; + registry.AllMethodsIn(&normalType, result); + CHECK_EQUAL(1, result.size()); + CHECK_EQUAL(&method1, result[0]); +} + +TEST_FIXTURE(Fixture, AllMethodsInTypeCanSkipStaticMethods) +{ + normalType.methods.push_back(&method1); + normalType.methods.push_back(&method2); + + method2.instance = true; + + vector<ScriptingMethodPtr> result; + registry.AllMethodsIn(&normalType, result, ScriptingMethodRegistry::kInstanceOnly); + CHECK_EQUAL(1, result.size()); + CHECK_EQUAL(&method2, result[0]); +} + +TEST_FIXTURE(Fixture, SearchFilterCanSkipMethodsWithArguments) +{ + normalType.methods.push_back(&method1); + normalType.methods.push_back(&method2); + + method1.args=0; + method2.args=2; + + vector<ScriptingMethodPtr> result; + registry.AllMethodsIn(&normalType, result, ScriptingMethodRegistry::kWithoutArguments ); + CHECK_EQUAL(1, result.size()); + CHECK_EQUAL(&method1, result[0]); +} + +#endif diff --git a/Runtime/Scripting/Backend/ScriptingTypeRegistry.cpp b/Runtime/Scripting/Backend/ScriptingTypeRegistry.cpp new file mode 100644 index 0000000..0e4fcbd --- /dev/null +++ b/Runtime/Scripting/Backend/ScriptingTypeRegistry.cpp @@ -0,0 +1,214 @@ +#include "UnityPrefix.h" +#if ENABLE_SCRIPTING +#include "ScriptingTypeRegistry.h" +#include "ScriptingBackendApi.h" + +ScriptingTypeRegistry::ScriptingTypeRegistry(IScriptingTypeProvider* scriptingTypeProvider) + : m_ScriptingTypeProvider(scriptingTypeProvider) +{ +} + +ScriptingTypePtr ScriptingTypeRegistry::GetType(const char* namespaze, const char* name) +{ + NameSpaceAndNamePair key = std::make_pair(namespaze,name); + + Cache::iterator i = m_Cache.find(key); + if (i != m_Cache.end()) + return i->second; + + BackendNativeType nativetype = m_ScriptingTypeProvider->NativeTypeFor(namespaze, name); + ScriptingTypePtr type = m_ScriptingTypeProvider->Provide(nativetype); + + m_Cache.insert(std::make_pair(key,type)); + return type; +} + +ScriptingTypePtr ScriptingTypeRegistry::GetType(BackendNativeType nativeType) +{ + NativeTypeCache::iterator i = m_NativeTypeCache.find(ScriptingObjectToComPtr(nativeType)); + if (i != m_NativeTypeCache.end()) + return i->second; + + ScriptingTypePtr type = m_ScriptingTypeProvider->Provide(nativeType); + + m_NativeTypeCache.insert(std::make_pair(ScriptingObjectToComPtr(nativeType), type)); + return type; +} + +ScriptingTypePtr ScriptingTypeRegistry::GetType(ScriptingObjectPtr systemTypeInstance) +{ + return scripting_class_from_systemtypeinstance(systemTypeInstance, *this); +} + +void ScriptingTypeRegistry::InvalidateCache() +{ + m_Cache.clear(); + m_NativeTypeCache.clear(); +} + +#if DEDICATED_UNIT_TEST_BUILD +#include "External/UnitTest++/src/UnitTest++.h" +#include <queue> +#include "Tests/ScriptingBackendApi_Tests.h" +using std::queue; + +class ScriptingTypeProvider_test : public IScriptingTypeProvider +{ +public: + BackendNativeType NativeTypeFor(const char* namespaze, const char* name) + { + BackendNativeType ptr = provideThis.front(); + provideThis.pop(); + return ptr; + } + + ScriptingTypePtr Provide(BackendNativeType nativeType) + { + return (ScriptingTypePtr)nativeType; + } + + void Release(ScriptingTypePtr ptr) {} + + queue<BackendNativeType> provideThis; +}; + +struct MyFixture +{ + ScriptingTypeProvider_test typeProvider; + + ScriptingType type1; + ScriptingType type2; + int nativeType1; + int nativeType2; + FakeSystemTypeInstance systemTypeInstance1; + FakeSystemTypeInstance systemTypeInstance2; +}; + +TEST_FIXTURE(MyFixture,ScriptingTypeRegistryReturnsSameTypeWhenAskedForSameName) +{ + typeProvider.provideThis.push(&type1); + + ScriptingTypeRegistry registry(&typeProvider); + ScriptingTypePtr t1 = registry.GetType("mynamespace","mytype"); + ScriptingTypePtr t2 = registry.GetType("mynamespace","mytype"); + CHECK_EQUAL(&type1,t1); + CHECK_EQUAL(&type1,t2); +} + +TEST_FIXTURE(MyFixture,ScriptingTypeRegistryReturnsDifferentTypeWhenAskedForDifferentName) +{ + typeProvider.provideThis.push(&type1); + typeProvider.provideThis.push(&type2); + + ScriptingTypeRegistry registry(&typeProvider); + ScriptingTypePtr t1 = registry.GetType("mynamespace", "mytype"); + ScriptingTypePtr t2 = registry.GetType("mynamespace", "myothertype"); + CHECK_EQUAL(&type1,t1); + CHECK_EQUAL(&type2,t2); +} + +TEST_FIXTURE(MyFixture,ScriptingTypeRegistryReturnsDifferentTypeWhenAskedForTypesWithDifferentNamespace) +{ + typeProvider.provideThis.push(&type1); + typeProvider.provideThis.push(&type2); + + ScriptingTypeRegistry registry(&typeProvider); + ScriptingTypePtr t1 = registry.GetType("mynamespace", "mytype"); + ScriptingTypePtr t2 = registry.GetType("myothernamespace", "mytype"); + CHECK_EQUAL(&type1,t1); + CHECK_EQUAL(&type2,t2); +} + +TEST_FIXTURE(MyFixture,ScriptingTypeRegistryInvalidateCacheCausesNewTypeBeingProduced) +{ + typeProvider.provideThis.push(&type1); + typeProvider.provideThis.push(&type2); + + ScriptingTypeRegistry registry(&typeProvider); + ScriptingTypePtr t1 = registry.GetType("mynamespace","mytype"); + registry.InvalidateCache(); + ScriptingTypePtr t2 = registry.GetType("mynamespace", "mytype"); + CHECK_EQUAL(&type1,t1); + CHECK_EQUAL(&type2,t2); +} + +TEST_FIXTURE(MyFixture,AskingForTheSameNativeTypeTwiceReturnsSameScriptingTypeTwice) +{ + typeProvider.provideThis.push(&type1); + + ScriptingTypeRegistry registry(&typeProvider); + + ScriptingTypePtr t1 = registry.GetType(&nativeType1); + ScriptingTypePtr t2 = registry.GetType(&nativeType1); + CHECK_EQUAL(&type1,t1); + CHECK_EQUAL(&type1,t2); +} + +TEST_FIXTURE(MyFixture,AskingForTwoDifferentNativeTypesReturnsDifferentScriptingTypes) +{ + typeProvider.provideThis.push(&type1); + typeProvider.provideThis.push(&type2); + + ScriptingTypeRegistry registry(&typeProvider); + ScriptingTypePtr t1 = registry.GetType(&nativeType1); + ScriptingTypePtr t2 = registry.GetType(&nativeType2); + CHECK_EQUAL(&type1,t1); + CHECK_EQUAL(&type2,t2); +} + +TEST_FIXTURE(MyFixture,InvalidateCacheCausesNewTypeToBeReturned) +{ + typeProvider.provideThis.push(&type1); + typeProvider.provideThis.push(&type2); + + ScriptingTypeRegistry registry(&typeProvider); + + ScriptingTypePtr t1 = registry.GetType(&nativeType1); + registry.InvalidateCache(); + ScriptingTypePtr t2 = registry.GetType(&nativeType1); + CHECK_EQUAL(&type1,t1); + CHECK_EQUAL(&type2,t2); +} + +TEST_FIXTURE(MyFixture,AskingForTypeOfSystemTypeInstanceTwiceReturnsSameType) +{ + typeProvider.provideThis.push(&type1); + ScriptingTypeRegistry registry(&typeProvider); + + systemTypeInstance1.nativeType = &nativeType1; + ScriptingTypePtr t1 = registry.GetType((ScriptingObjectPtr) &systemTypeInstance1); + ScriptingTypePtr t2 = registry.GetType((ScriptingObjectPtr) &systemTypeInstance1); + CHECK_EQUAL(&type1,t1); + CHECK_EQUAL(&type1,t2); +} +/* +TEST_FIXTURE(MyFixture,AskingForDifferentSystemTypeInstancesReturnsDifferentTypes) +{ + typeProvider.provideThis.push(&type1); + typeProvider.provideThis.push(&type2); + ScriptingTypeRegistry registry(&typeProvider); + + systemTypeInstance1.nativeType = &nativeType1; + systemTypeInstance1.nativeType = &nativeType2; + ScriptingTypePtr t1 = registry.GetType((ScriptingObjectPtr) &systemTypeInstance1); + ScriptingTypePtr t2 = registry.GetType((ScriptingObjectPtr) &systemTypeInstance2); + CHECK_EQUAL(&type1,t1); + CHECK_EQUAL(&type2,t2); +} +*/ +TEST_FIXTURE(MyFixture,InvalidateCacheCausesSystemTypeInstanceQueryToProvideNewType) +{ + typeProvider.provideThis.push(&type1); + typeProvider.provideThis.push(&type2); + ScriptingTypeRegistry registry(&typeProvider); + + systemTypeInstance1.nativeType = &nativeType1; + ScriptingTypePtr t1 = registry.GetType((ScriptingObjectPtr) &systemTypeInstance1); + registry.InvalidateCache(); + ScriptingTypePtr t2 = registry.GetType((ScriptingObjectPtr) &systemTypeInstance1); + CHECK_EQUAL(&type1,t1); + CHECK_EQUAL(&type2,t2); +} + +#endif +#endif diff --git a/Runtime/Scripting/Backend/ScriptingTypeRegistry.h b/Runtime/Scripting/Backend/ScriptingTypeRegistry.h new file mode 100644 index 0000000..be2328f --- /dev/null +++ b/Runtime/Scripting/Backend/ScriptingTypeRegistry.h @@ -0,0 +1,33 @@ +#ifndef _SCRIPTINGTYPEREGISTRY_Y_ +#define _SCRIPTINGTYPEREGISTRY_Y_ + +#if ENABLE_SCRIPTING + +#include <map> +#include <string> +#include "ScriptingTypes.h" +#include "IScriptingTypeProvider.h" + +class ScriptingTypeRegistry +{ +public: + ScriptingTypeRegistry(IScriptingTypeProvider* scriptingTypeProvider); + ScriptingTypePtr GetType(const char* namespaze, const char* name); + ScriptingTypePtr GetType(BackendNativeType nativeType); + ScriptingTypePtr GetType(ScriptingObjectPtr systemTypeInstance); + void InvalidateCache(); + +private: + typedef std::pair<std::string,std::string> NameSpaceAndNamePair; + typedef std::map<NameSpaceAndNamePair, ScriptingTypePtr> Cache; + Cache m_Cache; + + typedef std::map<void*, ScriptingTypePtr> NativeTypeCache; + NativeTypeCache m_NativeTypeCache; + + IScriptingTypeProvider* m_ScriptingTypeProvider; +}; + +#endif + +#endif diff --git a/Runtime/Scripting/Backend/ScriptingTypes.h b/Runtime/Scripting/Backend/ScriptingTypes.h new file mode 100644 index 0000000..45911b0 --- /dev/null +++ b/Runtime/Scripting/Backend/ScriptingTypes.h @@ -0,0 +1,202 @@ +#ifndef _SCRIPTINGTYPES_H_ +#define _SCRIPTINGTYPES_H_ + +#if ENABLE_MONO +struct MonoObject; +struct MonoString; +struct MonoArray; +struct MonoType; +struct MonoClass; +struct MonoException; +struct MonoMethod; +struct MonoClassField; +typedef MonoObject ScriptingObject; +typedef MonoString ScriptingString; +typedef MonoArray ScriptingArray; +typedef MonoClass ScriptingType; +typedef MonoClass ScriptingClass; +typedef MonoException ScriptingException; +typedef MonoClassField ScriptingField; +struct ScriptingMethod; +typedef MonoMethod* BackendNativeMethod; +typedef MonoClass* BackendNativeType; + +#elif UNITY_FLASH +struct ScriptingObject; +struct ScriptingString; +struct ScriptingArray; +struct ScriptingClass; +typedef ScriptingClass ScriptingType; +struct ScriptingException; + +struct ScriptingMethod; +struct ScriptingField; +struct MonoImage; + +//hack to not have to change everything in one go. +struct MonoMethod; +struct MonoObject; +typedef ScriptingType MonoClass; +typedef void* BackendNativeType; +typedef void* BackendNativeMethod; +#elif UNITY_WINRT && ENABLE_SCRIPTING +struct WinRTNullPtrImplementation +{ + inline operator long long() + { + return -1; + } + inline operator decltype(__nullptr)() + { + return nullptr; + } +}; + +// Implemented in WinRTUtility.cpp +class WinRTScriptingObjectWrapper +{ +public: + // Must be in sync with WinRTBridge\GCHandledObjects.cs, would be nice to somehow get those values directly... + static const int kMaxHandlesShift = 11; + static const int kMaxHandlesPerBlock = 1 << kMaxHandlesShift; + static const int kHandleMask = kMaxHandlesPerBlock - 1; +public: + WinRTScriptingObjectWrapper(); + WinRTScriptingObjectWrapper(decltype(__nullptr)); + WinRTScriptingObjectWrapper(long long handleId); + WinRTScriptingObjectWrapper(const WinRTNullPtrImplementation& interopParam); + WinRTScriptingObjectWrapper(const WinRTScriptingObjectWrapper& handleId); + ~WinRTScriptingObjectWrapper(); + + const WinRTScriptingObjectWrapper &operator = (const WinRTScriptingObjectWrapper &ptr); + WinRTScriptingObjectWrapper& operator=(decltype(__nullptr)); + WinRTScriptingObjectWrapper& operator=(const WinRTNullPtrImplementation& nullptrimpl); + inline operator bool () const + { + return m_Handle != -1; + } + inline operator long long() const + { + return m_Handle; + } + int GetReferenceCount() const; + + // Converters + bool ToBool(); + + inline long long GetHandle() const { return m_Handle;} + inline int GetBlockId() const {return m_BlockId; } + inline int GetHandleInBlock() const { return m_HandleInBlock; } + + void Validate(); + + static void FreeHandles(); + static void ClearCache(); + static void ValidateCache(); +private: + friend bool operator == (const WinRTScriptingObjectWrapper& a, decltype(__nullptr)); + friend bool operator != (const WinRTScriptingObjectWrapper& a, decltype(__nullptr)); + friend bool operator == (const WinRTScriptingObjectWrapper& a, const WinRTNullPtrImplementation& b); + friend bool operator != (const WinRTScriptingObjectWrapper& a, const WinRTNullPtrImplementation& b); + static int* GetPtrToReferences(int blockId); + + void Init(long long handleId); + void InternalAddRef(); + void InternalRelease(); + + long long m_Handle; + int m_BlockId; + int m_HandleInBlock; + int* m_PtrToReferences; + + static const int kMaxCachedPtrToReferences = 4096; + static int* m_CachedPtrToReferences[kMaxCachedPtrToReferences]; + static int m_CachedBlockCount; +}; + +bool operator == (const WinRTScriptingObjectWrapper& a, decltype(__nullptr)); +bool operator != (const WinRTScriptingObjectWrapper& a, decltype(__nullptr)); +bool operator == (const WinRTScriptingObjectWrapper& a, const WinRTNullPtrImplementation& b); +bool operator != (const WinRTScriptingObjectWrapper& a, const WinRTNullPtrImplementation& b); +// Don't implement this, as same objects can have different handle ids, so currently there's no way of effectively comparing them +//bool operator == (const WinRTScriptingObjectWrapper& a, const WinRTScriptingObjectWrapper& b); + +struct ScriptingObject; +struct ScriptingString; +typedef Platform::Object ScriptingArray; +//struct ScriptingArray; +struct ScriptingType; +typedef ScriptingType ScriptingClass; +struct ScriptingException; + +typedef int BackendNativeMethod; +typedef BridgeInterface::IScriptingClassWrapper^ BackendNativeType; + +struct ScriptingMethod; +struct ScriptingField; +struct MonoImage; + +//hack to not have to change everything in one go. +struct MonoMethod; +struct MonoObject; +typedef ScriptingType MonoClass; +#else +struct ScriptingObject; +struct ScriptingString; +struct ScriptingException; +struct ScriptingMethod; +struct ScriptingField; +struct ScriptingString; +struct ScriptingClass; +struct ScriptingType; +struct ScriptingArray; +struct ScriptingString; +struct MonoMethod; +struct MonoObject; +struct MonoClass; +typedef void* BackendNativeType; +typedef void* BackendNativeMethod; +#endif + + +#if UNITY_WINRT && ENABLE_SCRIPTING +typedef WinRTScriptingObjectWrapper ScriptingObjectPtr; +typedef Platform::Object^ ScriptingStringPtr; +typedef WinRTScriptingObjectWrapper ScriptingArrayPtr; +typedef WinRTScriptingObjectWrapper ScriptingPinnedArrayPtr; +typedef WinRTScriptingObjectWrapper const ScriptingArrayConstPtr; +typedef WinRTScriptingObjectWrapper ScriptingPinnedArrayConstPtr; +typedef ScriptingType* ScriptingTypePtr; +typedef ScriptingClass* ScriptingClassPtr; +typedef ScriptingException* ScriptingExceptionPtr; +typedef ScriptingMethod* ScriptingMethodPtr; +typedef ScriptingField* ScriptingFieldPtr; +//typedef Platform::Array<Platform::Object^> ScriptingParams; +//typedef ScriptingParams^ ScriptingParamsPtr; +typedef long long ScriptingParams; +typedef long long* ScriptingParamsPtr; +#define ScriptingBool bool +#define SCRIPTING_NULL WinRTNullPtrImplementation() +#define ScriptingObjectComPtr(Type) Microsoft::WRL::ComPtr<IInspectable> +#define ScriptingObjectToComPtr(Object) reinterpret_cast<IInspectable*>(Object) +#define ScriptingComPtrToObject(Type, Object) reinterpret_cast<Type>((Object).Get()) +#else +typedef ScriptingObject* ScriptingObjectPtr; +typedef ScriptingString* ScriptingStringPtr; +typedef ScriptingArray* ScriptingArrayPtr; +typedef ScriptingType* ScriptingTypePtr; +typedef ScriptingClass* ScriptingClassPtr; +typedef ScriptingException* ScriptingExceptionPtr; +typedef ScriptingMethod* ScriptingMethodPtr; +typedef ScriptingField* ScriptingFieldPtr; +typedef void* ScriptingParams; +typedef ScriptingParams* ScriptingParamsPtr; +#define ScriptingBool short +#define SCRIPTING_NULL NULL +#define ScriptingObjectComPtr(Type) Type +#define ScriptingObjectToComPtr(Object) Object +#define ScriptingComPtrToObject(Type, Object) Object +#endif + + +#endif diff --git a/Runtime/Scripting/Backend/Tests/ScriptingBackendApi_Tests.cpp b/Runtime/Scripting/Backend/Tests/ScriptingBackendApi_Tests.cpp new file mode 100644 index 0000000..c8c0122 --- /dev/null +++ b/Runtime/Scripting/Backend/Tests/ScriptingBackendApi_Tests.cpp @@ -0,0 +1,35 @@ +#include "UnityPrefix.h" + +#if DEDICATED_UNIT_TEST_BUILD +#include "Runtime/Scripting/Backend/ScriptingTypes.h" +#include "Runtime/Scripting/Backend/Tests/ScriptingBackendApi_Tests.h" +#include "Runtime/Scripting/Backend/ScriptingMethodRegistry.h" +#include "Runtime/Scripting/Backend/ScriptingTypeRegistry.h" + +bool scripting_method_is_instance(ScriptingMethodPtr method) +{ + return method->instance; +} + +int scripting_method_get_argument_count(ScriptingMethodPtr method) +{ + return method->args; +} + +ScriptingTypePtr scripting_class_get_parent(ScriptingTypePtr type, ScriptingTypeRegistry& typeRegistry) +{ + return type->baseType; +} + +void scripting_class_get_methods(ScriptingTypePtr type, ScriptingMethodRegistry& registry, std::vector<ScriptingMethodPtr>& result) +{ + result = type->methods; +} + +ScriptingTypePtr scripting_class_from_systemtypeinstance(ScriptingObjectPtr type, ScriptingTypeRegistry& typeRegistry) +{ + FakeSystemTypeInstance* sti = (FakeSystemTypeInstance*) type; + return typeRegistry.GetType(sti->nativeType); +} + +#endif diff --git a/Runtime/Scripting/Backend/Tests/ScriptingBackendApi_Tests.h b/Runtime/Scripting/Backend/Tests/ScriptingBackendApi_Tests.h new file mode 100644 index 0000000..2ab7765 --- /dev/null +++ b/Runtime/Scripting/Backend/Tests/ScriptingBackendApi_Tests.h @@ -0,0 +1,30 @@ +#ifndef _SCRIPTINGBACKENDAPI_TESTS_H_ +#define _SCRIPTINGBACKENDAPI_TESTS_H_ + +#if DEDICATED_UNIT_TEST_BUILD +#include "Runtime/Scripting/Backend/ScriptingTypes.h" +#include <vector> + +struct ScriptingType +{ + ScriptingTypePtr baseType; + ScriptingType() : baseType(NULL) {} + + std::vector<ScriptingMethodPtr> methods; +}; + +struct ScriptingMethod +{ + bool instance; + int args; + + ScriptingMethod() : instance(false), args(0) {} +}; + +struct FakeSystemTypeInstance +{ + void* nativeType; +}; + +#endif +#endif diff --git a/Runtime/Scripting/CommonScriptingClasses.cpp b/Runtime/Scripting/CommonScriptingClasses.cpp new file mode 100644 index 0000000..6a7d266 --- /dev/null +++ b/Runtime/Scripting/CommonScriptingClasses.cpp @@ -0,0 +1,268 @@ +#include "UnityPrefix.h" +#if ENABLE_SCRIPTING +#include "CommonScriptingClasses.h" +#include "Runtime/Mono/MonoIncludes.h" +#include "Runtime/Scripting/ScriptingUtility.h" +#include "Runtime/Mono/MonoManager.h" +#include "Runtime/Scripting/Backend/ScriptingTypeRegistry.h" +#include "Runtime/Scripting/Backend/ScriptingMethodRegistry.h" +#include "Runtime/Scripting/Backend/ScriptingBackendApi.h" + +static ScriptingMethodPtr OptionalMethod(const char* namespaze, const char* klass, const char* name) +{ + return GetScriptingManager().GetScriptingMethodRegistry().GetMethod(namespaze,klass,name); +} + +static ScriptingMethodPtr RequireMethod(const char* namespaze, const char* klass, const char* name) +{ + ScriptingMethodPtr method = GetScriptingManager().GetScriptingMethodRegistry().GetMethod(namespaze,klass,name); + if (!method) + ErrorString(Format("Unable to find method %s in %s",name,klass)); + return method; +} + + +static ScriptingTypePtr OptionalType(const char* namespaze, const char* name) +{ + return GetScriptingTypeRegistry().GetType(namespaze,name); +} + +static ScriptingTypePtr RequireType(const char* namespaze, const char* name) +{ + ScriptingTypePtr t = OptionalType(namespaze,name); + if (!t) + ErrorString(Format("Unable to find type %s.%s",namespaze,name)); + return t; +} + +static ScriptingTypePtr RequireUnityEngineType(const char* name) +{ + return RequireType("UnityEngine",name); +} + +static ScriptingTypePtr OptionalUnityEngineType(const char* name) +{ + return OptionalType("UnityEngine",name); +} + +void FillCommonScriptingClasses(CommonScriptingClasses& commonScriptingClasses) +{ + ScriptingTypeRegistry& typeRegistry = GetScriptingManager().GetScriptingTypeRegistry(); + +#if ENABLE_SCRIPTING + commonScriptingClasses.monoBehaviour = RequireUnityEngineType ("MonoBehaviour"); + commonScriptingClasses.component = RequireUnityEngineType ("Component"); + commonScriptingClasses.scriptableObject = RequireUnityEngineType ("ScriptableObject"); + commonScriptingClasses.vector2 = RequireUnityEngineType ("Vector2"); + commonScriptingClasses.vector3 = RequireUnityEngineType ("Vector3"); + commonScriptingClasses.vector4 = RequireUnityEngineType ("Vector4"); + commonScriptingClasses.rect = RequireUnityEngineType ("Rect"); + commonScriptingClasses.rectOffset = RequireUnityEngineType ("RectOffset"); + commonScriptingClasses.quaternion = RequireUnityEngineType ("Quaternion"); + commonScriptingClasses.matrix4x4 = RequireUnityEngineType ("Matrix4x4"); + commonScriptingClasses.bounds = RequireUnityEngineType ("Bounds"); + commonScriptingClasses.resolution = RequireUnityEngineType ("Resolution"); + commonScriptingClasses.particle = RequireUnityEngineType ("Particle"); + commonScriptingClasses.color = RequireUnityEngineType ("Color"); + commonScriptingClasses.color32 = RequireUnityEngineType ("Color32"); + commonScriptingClasses.raycastHit = OptionalUnityEngineType ("RaycastHit"); + commonScriptingClasses.raycastHit2D = OptionalUnityEngineType ("RaycastHit2D"); + commonScriptingClasses.animationState = OptionalUnityEngineType ("AnimationState"); + commonScriptingClasses.collider = OptionalUnityEngineType ("Collider"); + commonScriptingClasses.camera = RequireUnityEngineType ("Camera"); + commonScriptingClasses.renderTexture = RequireUnityEngineType ("RenderTexture"); + commonScriptingClasses.layerMask = RequireUnityEngineType ("LayerMask"); + commonScriptingClasses.waitForSeconds = RequireUnityEngineType ("WaitForSeconds"); + commonScriptingClasses.waitForFixedUpdate = RequireUnityEngineType ("WaitForFixedUpdate"); + commonScriptingClasses.waitForEndOfFrame = RequireUnityEngineType ("WaitForEndOfFrame"); + commonScriptingClasses.characterInfo = RequireUnityEngineType ("CharacterInfo"); + commonScriptingClasses.font_InvokeFontTextureRebuildCallback_Internal = RequireMethod ("UnityEngine","Font","InvokeFontTextureRebuildCallback_Internal"); +#if ENABLE_WWW + commonScriptingClasses.www = OptionalUnityEngineType ("WWW"); +#endif +#if UNITY_WII + commonScriptingClasses.waitAsyncOperationFinish = GetBuiltinScriptingClass ("WaitAsyncOperationFinish"); +#endif + commonScriptingClasses.lodMesh = OptionalUnityEngineType ("Mesh"); + commonScriptingClasses.coroutine = RequireUnityEngineType ("Coroutine"); + commonScriptingClasses.collision = OptionalUnityEngineType ("Collision"); + commonScriptingClasses.contactPoint = OptionalUnityEngineType ("ContactPoint"); + commonScriptingClasses.controllerColliderHit = OptionalUnityEngineType ("ControllerColliderHit"); + commonScriptingClasses.collision2D = OptionalUnityEngineType ("Collision2D"); + commonScriptingClasses.contactPoint2D = OptionalUnityEngineType ("ContactPoint2D"); + commonScriptingClasses.unityEngineObject = RequireUnityEngineType ("Object"); + commonScriptingClasses.event = RequireUnityEngineType ("Event"); +#if ENABLE_MONO + commonScriptingClasses.serializeField = RequireUnityEngineType ("SerializeField"); + commonScriptingClasses.serializePrivateVariables = GetBuiltinScriptingClass ("SerializePrivateVariables"); + commonScriptingClasses.hideInInspector = GetBuiltinScriptingClass ("HideInInspector"); +#endif +#if ENABLE_NETWORK + commonScriptingClasses.RPC = OptionalUnityEngineType ("RPC"); + commonScriptingClasses.hostData = OptionalUnityEngineType ("HostData"); + commonScriptingClasses.bitStream = OptionalUnityEngineType ("BitStream"); + commonScriptingClasses.networkPlayer = OptionalUnityEngineType ("NetworkPlayer"); + commonScriptingClasses.networkViewID = OptionalUnityEngineType ("NetworkViewID"); + commonScriptingClasses.networkMessageInfo = OptionalUnityEngineType ("NetworkMessageInfo"); +#endif // ENABLE_NETWORK + commonScriptingClasses.guiStyle = RequireUnityEngineType ("GUIStyle"); + commonScriptingClasses.animationCurve = RequireUnityEngineType ("AnimationCurve"); + commonScriptingClasses.boneWeight = RequireUnityEngineType ("BoneWeight"); +#if ENABLE_TERRAIN + commonScriptingClasses.terrain = OptionalUnityEngineType("Terrain"); + commonScriptingClasses.detailPrototype = OptionalUnityEngineType ("DetailPrototype"); + commonScriptingClasses.treePrototype = OptionalUnityEngineType ("TreePrototype"); + commonScriptingClasses.treeInstance = OptionalUnityEngineType ("TreeInstance"); + commonScriptingClasses.splatPrototype = OptionalUnityEngineType ("SplatPrototype"); +#endif + commonScriptingClasses.animationEvent = RequireUnityEngineType ("AnimationEvent"); + commonScriptingClasses.assetBundleRequest = RequireUnityEngineType ("AssetBundleRequest"); + commonScriptingClasses.asyncOperation = RequireUnityEngineType ("AsyncOperation"); +#if ENABLE_WWW + commonScriptingClasses.assetBundleCreateRequest = RequireUnityEngineType ("AssetBundleCreateRequest"); + // Stop scaring the customers and only load this when it's needed and available + commonScriptingClasses.cacheIndex = RequireUnityEngineType ("CacheIndex"); +#else + commonScriptingClasses.cacheIndex = SCRIPTING_NULL; +#endif + commonScriptingClasses.cachedFile = OptionalUnityEngineType ("CachedFile"); + + commonScriptingClasses.keyframe = RequireUnityEngineType ("Keyframe"); + commonScriptingClasses.inputEvent = RequireUnityEngineType ("Event"); + commonScriptingClasses.imageEffectOpaque = OptionalUnityEngineType ("ImageEffectOpaque"); + commonScriptingClasses.imageEffectTransformsToLDR = OptionalUnityEngineType ("ImageEffectTransformsToLDR"); + commonScriptingClasses.iEnumerator = typeRegistry.GetType("System.Collections", "IEnumerator"); + commonScriptingClasses.systemObject = typeRegistry.GetType("System","Object"); + + + commonScriptingClasses.string = typeRegistry.GetType("System", "String"); + commonScriptingClasses.int_32 = typeRegistry.GetType("System", "Int32"); + commonScriptingClasses.floatSingle = typeRegistry.GetType("System", "Single"); + commonScriptingClasses.floatDouble = typeRegistry.GetType("System", "Double"); + commonScriptingClasses.byte = typeRegistry.GetType("System", "Byte"); + +#if ENABLE_MONO || UNITY_WINRT + commonScriptingClasses.intptr = typeRegistry.GetType("System", "IntPtr"); + commonScriptingClasses.uInt_16 = typeRegistry.GetType("System", "UInt16"); + commonScriptingClasses.uInt_32 = typeRegistry.GetType("System", "UInt32"); + commonScriptingClasses.int_16 = typeRegistry.GetType("System", "Int16"); + commonScriptingClasses.multicastDelegate = typeRegistry.GetType("System", "MulticastDelegate"); + commonScriptingClasses.extractRequiredComponents = RequireMethod ("UnityEngine","AttributeHelperEngine", "GetRequiredComponents"); +#endif + +#if ENABLE_MONO || UNITY_WP8 + commonScriptingClasses.invokeMember = RequireMethod ("UnityEngine","SetupCoroutine", "InvokeMember"); + commonScriptingClasses.invokeStatic = RequireMethod ("UnityEngine","SetupCoroutine", "InvokeStatic"); +#endif +#if ENABLE_MONO + commonScriptingClasses.checkIsEditMode = RequireMethod ("UnityEngine","AttributeHelperEngine", "CheckIsEditorScript"); + commonScriptingClasses.extractStacktrace = RequireMethod ("UnityEngine","StackTraceUtility", "ExtractStackTrace"); + commonScriptingClasses.extractStringFromException = RequireMethod ("UnityEngine","StackTraceUtility", "ExtractStringFromExceptionInternal"); + commonScriptingClasses.postprocessStacktrace = RequireMethod ("UnityEngine","StackTraceUtility", "PostprocessStacktrace"); +#endif + + commonScriptingClasses.IEnumerator_MoveNext = RequireMethod("System.Collections", "IEnumerator","MoveNext"); +#if ENABLE_MONO || UNITY_WINRT + commonScriptingClasses.callLogCallback = RequireMethod ("UnityEngine", "Application", "CallLogCallback"); + commonScriptingClasses.IEnumerator_Current = GetScriptingMethodRegistry().GetMethod("System.Collections", "IEnumerator","get_Current"); + commonScriptingClasses.IDisposable_Dispose = GetScriptingMethodRegistry().GetMethod("System", "IDisposable","Dispose"); +#endif + + commonScriptingClasses.beginGUI = RequireMethod ("UnityEngine", "GUIUtility", "BeginGUI"); + commonScriptingClasses.endGUI = RequireMethod ("UnityEngine", "GUIUtility", "EndGUI"); + commonScriptingClasses.callGUIWindowDelegate = RequireMethod ("UnityEngine", "GUI", "CallWindowDelegate"); + commonScriptingClasses.makeMasterEventCurrent = RequireMethod ("UnityEngine", "Event", "Internal_MakeMasterEventCurrent"); + commonScriptingClasses.doSendMouseEvents = RequireMethod ("UnityEngine", "SendMouseEvents", "DoSendMouseEvents"); + +#if ENABLE_MONO + commonScriptingClasses.stackTraceUtilitySetProjectFolder = RequireMethod ("UnityEngine", "StackTraceUtility", "SetProjectFolder"); +#endif + +#if ENABLE_MONO + commonScriptingClasses.enumClass = mono_get_enum_class (); + commonScriptingClasses.floatSingleArray = mono_array_class_get(commonScriptingClasses.floatSingle, 1); +#endif // ENABLE_MONO + + +#if UNITY_EDITOR + commonScriptingClasses.monoReloadableIntPtr = GetMonoManager().GetBuiltinEditorMonoClass ("MonoReloadableIntPtr"); + commonScriptingClasses.monoReloadableIntPtrClear = GetMonoManager().GetBuiltinEditorMonoClass ("MonoReloadableIntPtrClear"); + commonScriptingClasses.gameViewStatsGUI = RequireMethod ("UnityEditor", "GameViewGUI", "GameViewStatsGUI"); + commonScriptingClasses.beginHandles = RequireMethod ("UnityEditor", "HandleUtility", "BeginHandles"); + commonScriptingClasses.endHandles = RequireMethod ("UnityEditor", "HandleUtility", "EndHandles"); + commonScriptingClasses.setViewInfo = RequireMethod ("UnityEditor", "HandleUtility", "SetViewInfo"); + commonScriptingClasses.handleControlID = RequireMethod ("UnityEditor","EditorGUIUtility","HandleControlID"); + commonScriptingClasses.callGlobalEventHandler = RequireMethod ("UnityEditor", "EditorApplication", "Internal_CallGlobalEventHandler"); + commonScriptingClasses.callAnimationClipAwake = RequireMethod ("UnityEditor", "AnimationUtility", "Internal_CallAnimationClipAwake"); + commonScriptingClasses.statusBarChanged = RequireMethod ("UnityEditor", "AppStatusBar", "StatusChanged"); + commonScriptingClasses.lightmappingDone = RequireMethod ("UnityEditor", "LightmappingWindow", "LightmappingDone"); + commonScriptingClasses.consoleLogChanged = RequireMethod ("UnityEditor", "ConsoleWindow", "LogChanged"); + commonScriptingClasses.clearUndoSnapshotTarget = RequireMethod ("UnityEditor", "Undo", "ClearSnapshotTarget"); + commonScriptingClasses.repaintAllProfilerWindows = RequireMethod ("UnityEditor", "ProfilerWindow", "RepaintAllProfilerWindows"); + commonScriptingClasses.getGameViewAspectRatio = RequireMethod ("UnityEditor", "CameraEditor", "GetGameViewAspectRatio"); + commonScriptingClasses.substanceMaterialInformation = RequireType("UnityEditor", "ProceduralMaterialInformation" ); + commonScriptingClasses.propertyModification = RequireType("UnityEditor", "PropertyModification" ); + commonScriptingClasses.undoPropertyModification = RequireType("UnityEditor", "UndoPropertyModification" ); + commonScriptingClasses.callbackOrderAttribute = RequireType("UnityEditor", "CallbackOrderAttribute" ); + commonScriptingClasses.postProcessBuildAttribute = RequireType ("UnityEditor.Callbacks", "PostProcessBuildAttribute"); + commonScriptingClasses.postProcessSceneAttribute = RequireType ("UnityEditor.Callbacks", "PostProcessSceneAttribute"); + commonScriptingClasses.didReloadScripts = RequireType ("UnityEditor.Callbacks", "DidReloadScripts"); + commonScriptingClasses.onOpenAssetAttribute = RequireType ("UnityEditor.Callbacks", "OnOpenAssetAttribute"); + + commonScriptingClasses.animationClipSettings = RequireType ("UnityEditor","AnimationClipSettings"); + commonScriptingClasses.muscleClipQualityInfo = RequireType ("UnityEditor","MuscleClipQualityInfo"); +#endif // UNITY_EDITOR + + commonScriptingClasses.gradient = RequireUnityEngineType ("Gradient"); + commonScriptingClasses.gradientColorKey = RequireUnityEngineType ("GradientColorKey"); + commonScriptingClasses.gradientAlphaKey = RequireUnityEngineType ("GradientAlphaKey"); + +#if ENABLE_SUBSTANCE + commonScriptingClasses.substancePropertyDescription = OptionalUnityEngineType ("ProceduralPropertyDescription"); +#endif + + commonScriptingClasses.animatorStateInfo= RequireUnityEngineType ("AnimatorStateInfo"); + commonScriptingClasses.animatorTransitionInfo= RequireUnityEngineType ("AnimatorTransitionInfo"); + commonScriptingClasses.animationInfo= RequireUnityEngineType ("AnimationInfo"); + commonScriptingClasses.skeletonBone = RequireUnityEngineType ("SkeletonBone"); + commonScriptingClasses.humanBone = RequireUnityEngineType ("HumanBone"); + +#if ENABLE_GAMECENTER + commonScriptingClasses.gameCenter = GetMonoManager().GetMonoClass("GameCenterPlatform", "UnityEngine.SocialPlatforms.GameCenter"); + commonScriptingClasses.gcAchievement = GetMonoManager().GetMonoClass("GcAchievementData", "UnityEngine.SocialPlatforms.GameCenter"); + commonScriptingClasses.gcAchievementDescription = GetMonoManager().GetMonoClass("GcAchievementDescriptionData", "UnityEngine.SocialPlatforms.GameCenter"); + commonScriptingClasses.gcScore = GetMonoManager().GetMonoClass("GcScoreData", "UnityEngine.SocialPlatforms.GameCenter"); + commonScriptingClasses.gcUserProfile = GetMonoManager().GetMonoClass("GcUserProfileData", "UnityEngine.SocialPlatforms.GameCenter"); +#endif + +#if ENABLE_WEBCAM + // We support stripping there + #if UNITY_IPHONE || UNITY_ANDROID || UNITY_BB10 || UNITY_TIZEN + commonScriptingClasses.webCamDevice = OptionalUnityEngineType("WebCamDevice"); + #else + commonScriptingClasses.webCamDevice = RequireUnityEngineType("WebCamDevice"); + #endif +#endif + + commonScriptingClasses.display = RequireUnityEngineType("Display"); + commonScriptingClasses.displayRecreateDisplayList = RequireMethod("UnityEngine","Display","RecreateDisplayList"); + commonScriptingClasses.displayFireDisplaysUpdated = RequireMethod("UnityEngine","Display","FireDisplaysUpdated"); + +#if UNITY_IPHONE + commonScriptingClasses.adBannerView = OptionalUnityEngineType("ADBannerView"); + commonScriptingClasses.adInterstitialAd = OptionalUnityEngineType("ADInterstitialAd"); + commonScriptingClasses.adFireBannerWasClicked = OptionalMethod ("UnityEngine", "ADBannerView", "FireBannerWasClicked"); + commonScriptingClasses.adFireBannerWasLoaded = OptionalMethod ("UnityEngine", "ADBannerView", "FireBannerWasLoaded"); + commonScriptingClasses.adFireInterstitialWasLoaded = OptionalMethod ("UnityEngine", "ADInterstitialAd", "FireInterstitialWasLoaded"); +#endif + + +#endif +} + +void ClearCommonScriptingClasses(CommonScriptingClasses& commonScriptingClasses) +{ + memset(&commonScriptingClasses, 0, sizeof(commonScriptingClasses)); +} + +#endif diff --git a/Runtime/Scripting/CommonScriptingClasses.h b/Runtime/Scripting/CommonScriptingClasses.h new file mode 100644 index 0000000..6699706 --- /dev/null +++ b/Runtime/Scripting/CommonScriptingClasses.h @@ -0,0 +1,206 @@ +#pragma once +#if ENABLE_SCRIPTING +#include "Runtime/Mono/MonoTypes.h" +#include "Runtime/Scripting/Backend/ScriptingTypes.h" + +struct CommonScriptingClasses +{ + ScriptingClassPtr monoBehaviour; + ScriptingClassPtr component; + ScriptingClassPtr scriptableObject; + ScriptingClassPtr vector2; + ScriptingClassPtr vector3; + ScriptingClassPtr vector4; + ScriptingClassPtr rect; + ScriptingClassPtr rectOffset; + ScriptingClassPtr quaternion; + ScriptingClassPtr matrix4x4; + ScriptingClassPtr bounds; + ScriptingClassPtr resolution; + ScriptingClassPtr particle; + ScriptingClassPtr color; + ScriptingClassPtr color32; + ScriptingClassPtr raycastHit; + ScriptingClassPtr raycastHit2D; + ScriptingClassPtr animationState; + ScriptingClassPtr collider; + ScriptingClassPtr camera; + ScriptingClassPtr renderTexture; + ScriptingClassPtr layerMask; + ScriptingClassPtr serializeField; + ScriptingClassPtr enumClass; + ScriptingClassPtr iEnumerator; + ScriptingClassPtr systemObject; + +#if !UNITY_FLASH + ScriptingClassPtr intptr; + ScriptingClassPtr uInt_16; + ScriptingClassPtr uInt_32; + ScriptingClassPtr int_16; + ScriptingClassPtr multicastDelegate; +#endif + + ScriptingClassPtr byte; + ScriptingClassPtr int_32; + ScriptingClassPtr string; + ScriptingClassPtr floatSingle; + ScriptingClassPtr floatDouble; + ScriptingClassPtr waitForSeconds; + ScriptingClassPtr waitForFixedUpdate; + ScriptingClassPtr waitForEndOfFrame; + + ScriptingClassPtr characterInfo; + ScriptingMethodPtr font_InvokeFontTextureRebuildCallback_Internal; +#if ENABLE_WWW + ScriptingClassPtr assetBundleCreateRequest; + ScriptingClassPtr www; +#endif +#if UNITY_WII || UNITY_PS3 || UNITY_XENON + ScriptingClassPtr waitAsyncOperationFinish; +#endif + ScriptingClassPtr meshData; + ScriptingClassPtr lodMesh; + ScriptingClassPtr coroutine; + ScriptingClassPtr collision; + ScriptingClassPtr contactPoint; + ScriptingClassPtr controllerColliderHit; + ScriptingClassPtr collision2D; + ScriptingClassPtr contactPoint2D; + ScriptingClassPtr event; + ScriptingClassPtr unityEngineObject; + ScriptingClassPtr hideInInspector; + ScriptingClassPtr serializePrivateVariables; +#if ENABLE_NETWORK + ScriptingClassPtr RPC; + ScriptingClassPtr hostData; + ScriptingClassPtr bitStream; + ScriptingClassPtr networkPlayer; + ScriptingClassPtr networkViewID; + ScriptingClassPtr networkMessageInfo; +#endif + + ScriptingClassPtr guiStyle; + ScriptingClassPtr animationCurve; + ScriptingClassPtr keyframe; + ScriptingClassPtr boneWeight; + +#if ENABLE_MONO || UNITY_WP8 + ScriptingMethodPtr invokeMember; + ScriptingMethodPtr invokeStatic; +#endif +#if ENABLE_MONO + ScriptingMethodPtr checkIsEditMode; + ScriptingMethodPtr extractStacktrace; + ScriptingMethodPtr extractStringFromException; + ScriptingMethodPtr postprocessStacktrace; +#endif + ScriptingMethodPtr IEnumerator_MoveNext; +#if ENABLE_MONO || UNITY_WINRT + ScriptingMethodPtr callLogCallback; + ScriptingMethodPtr IEnumerator_Current; + ScriptingMethodPtr IDisposable_Dispose; + ScriptingMethodPtr extractRequiredComponents; +#endif + + ScriptingMethodPtr beginGUI; + ScriptingMethodPtr endGUI; + ScriptingMethodPtr callGUIWindowDelegate; + +#if ENABLE_TERRAIN + ScriptingClassPtr terrain; + ScriptingClassPtr detailPrototype; + ScriptingClassPtr treePrototype; + ScriptingClassPtr treeInstance; + ScriptingClassPtr splatPrototype; +#endif + ScriptingClassPtr animationEvent; + ScriptingClassPtr assetBundleRequest; + ScriptingClassPtr asyncOperation; + ScriptingClassPtr cacheIndex; + ScriptingClassPtr cachedFile; + ScriptingClassPtr inputEvent; + ScriptingClassPtr imageEffectOpaque; + ScriptingClassPtr muscleBoneInfo; + ScriptingClassPtr animationClipSettings; + ScriptingClassPtr muscleClipQualityInfo; + ScriptingClassPtr imageEffectTransformsToLDR; + + ScriptingMethodPtr makeMasterEventCurrent; + ScriptingMethodPtr doSendMouseEvents; + ScriptingMethodPtr stackTraceUtilitySetProjectFolder; + + + +#if UNITY_EDITOR + ScriptingClassPtr monoReloadableIntPtr; + ScriptingClassPtr monoReloadableIntPtrClear; + ScriptingMethodPtr gameViewStatsGUI; + ScriptingMethodPtr beginHandles; + ScriptingMethodPtr endHandles; + ScriptingMethodPtr setViewInfo; + ScriptingMethodPtr handleControlID; + ScriptingMethodPtr callGlobalEventHandler; + ScriptingMethodPtr callAnimationClipAwake; + ScriptingMethodPtr statusBarChanged; + ScriptingMethodPtr lightmappingDone; + ScriptingMethodPtr consoleLogChanged; + ScriptingMethodPtr clearUndoSnapshotTarget; + ScriptingMethodPtr repaintAllProfilerWindows; + ScriptingMethodPtr getGameViewAspectRatio; + ScriptingClassPtr substanceMaterialInformation; + ScriptingClassPtr propertyModification; + ScriptingClassPtr undoPropertyModification; + ScriptingClassPtr exportExtensionClassAttribute; +#endif // #if UNITY_EDITOR + + ScriptingClassPtr gradient; + ScriptingClassPtr gradientColorKey; + ScriptingClassPtr gradientAlphaKey; + ScriptingClassPtr callbackOrderAttribute; + ScriptingClassPtr postProcessBuildAttribute; + ScriptingClassPtr postProcessSceneAttribute; + ScriptingClassPtr didReloadScripts; + ScriptingClassPtr onOpenAssetAttribute; + +#if ENABLE_SUBSTANCE + ScriptingClassPtr substancePropertyDescription; +#endif + + ScriptingClassPtr animatorStateInfo; + ScriptingClassPtr animatorTransitionInfo; + ScriptingClassPtr animationInfo; + ScriptingClassPtr floatSingleArray; + ScriptingClassPtr skeletonBone; + ScriptingClassPtr humanBone; + +#if ENABLE_GAMECENTER + ScriptingClassPtr gameCenter; + ScriptingClassPtr gcScore; + ScriptingClassPtr gcAchievement; + ScriptingClassPtr gcAchievementDescription; + ScriptingClassPtr gcUserProfile; +#endif + +#if ENABLE_WEBCAM + ScriptingClassPtr webCamDevice; +#endif + + ScriptingClassPtr display; + ScriptingMethodPtr displayRecreateDisplayList; + ScriptingMethodPtr displayFireDisplaysUpdated; + +#if UNITY_IPHONE + ScriptingClassPtr adBannerView; + ScriptingClassPtr adInterstitialAd; + ScriptingMethodPtr adFireBannerWasClicked; + ScriptingMethodPtr adFireBannerWasLoaded; + ScriptingMethodPtr adFireInterstitialWasLoaded; +#endif +}; + +void FillCommonScriptingClasses(CommonScriptingClasses& commonScriptingClasses); +void ClearCommonScriptingClasses(CommonScriptingClasses& commonScriptingClasses); + +#define MONO_COMMON GetScriptingManager().GetCommonClasses() + +#endif diff --git a/Runtime/Scripting/DelayedCallUtility.cpp b/Runtime/Scripting/DelayedCallUtility.cpp new file mode 100644 index 0000000..5e7d9f0 --- /dev/null +++ b/Runtime/Scripting/DelayedCallUtility.cpp @@ -0,0 +1,73 @@ +#include "UnityPrefix.h" + +#if ENABLE_SCRIPTING + +#include "Runtime/Scripting/DelayedCallUtility.h" +#include "Runtime/Scripting/ScriptingUtility.h" +#include "Runtime/GameCode/CallDelayed.h" +#include "Runtime/Mono/MonoBehaviour.h" +#include "Runtime/Mono/MonoScript.h" + +static void ForwardInvokeDelayed (Object* o, void* userData) +{ + const char* methodName = (const char*)userData; + MonoBehaviour* behaviour = static_cast<MonoBehaviour*> (o); + if (behaviour->GetInstance ()) + { + bool didCall = behaviour->CallMethodInactive (methodName); + #if !DEPLOY_OPTIMIZED + if (!didCall) + LogStringObject ("Trying to Invoke method: " + behaviour->GetScript ()->GetScriptClassName () + "." + methodName + " couldn't be called.", o); + #else + UNUSED(didCall); + #endif + + } +} + +static void ForwardInvokeDelayedCleanup (void* userData) +{ + ScriptingStringToAllocatedChars_Free ((char*)userData); +} + +void InvokeDelayed (MonoBehaviour& behaviour, ICallString& monoMethodName, float time, float repeatRate) +{ + char* methodName = ScriptingStringToAllocatedChars (monoMethodName); + if (repeatRate > 0.00001F || repeatRate == 0.0F) + CallDelayed (&ForwardInvokeDelayed, &behaviour, time, methodName, repeatRate, &ForwardInvokeDelayedCleanup); + else + Scripting::RaiseMonoException ("Invoke repeat rate has to be larger than 0.00001F)"); +} + + +static bool ShouldCancelInvoke (void* lhs, void* rhs) +{ + return strcmp ((char*)lhs, (char*)rhs) == 0; +} + +void CancelInvoke (MonoBehaviour& behaviour, ICallString& monoMethodName) +{ + char* methodName = ScriptingStringToAllocatedChars (monoMethodName); + GetDelayedCallManager ().CancelCallDelayed (&behaviour, &ForwardInvokeDelayed, &ShouldCancelInvoke, methodName); + ScriptingStringToAllocatedChars_Free (methodName); +} + +void CancelInvoke (MonoBehaviour& behaviour) +{ + GetDelayedCallManager ().CancelCallDelayed (&behaviour, &ForwardInvokeDelayed, NULL, NULL); +} + +bool IsInvoking (MonoBehaviour& behaviour) +{ + return GetDelayedCallManager ().HasDelayedCall (&behaviour, &ForwardInvokeDelayed, NULL, NULL); +} + +bool IsInvoking (MonoBehaviour& behaviour, ICallString& monoMethodName) +{ + char* methodName = ScriptingStringToAllocatedChars (monoMethodName); + bool result = GetDelayedCallManager ().HasDelayedCall (&behaviour, &ForwardInvokeDelayed, &ShouldCancelInvoke, methodName); + ScriptingStringToAllocatedChars_Free (methodName); + return result; +} + +#endif diff --git a/Runtime/Scripting/DelayedCallUtility.h b/Runtime/Scripting/DelayedCallUtility.h new file mode 100644 index 0000000..aae493d --- /dev/null +++ b/Runtime/Scripting/DelayedCallUtility.h @@ -0,0 +1,16 @@ +#ifndef _DELAYEDCALLUTILITYH_ +#define _DELAYEDCALLUTILITYH_ + +#if ENABLE_SCRIPTING +#include "Runtime/Scripting/Backend/ScriptingTypes.h" +#include "Runtime/Scripting/ICallString.h" + +class MonoBehaviour; + +void InvokeDelayed (MonoBehaviour& behaviour, ICallString& monoMethodName, float time, float repeatRate); +void CancelInvoke (MonoBehaviour& behaviour, ICallString& monoMethodName); +void CancelInvoke (MonoBehaviour& behaviour); +bool IsInvoking (MonoBehaviour& behaviour, ICallString& monoMethodName); +bool IsInvoking (MonoBehaviour& behaviour); +#endif +#endif diff --git a/Runtime/Scripting/GetComponent.cpp b/Runtime/Scripting/GetComponent.cpp new file mode 100644 index 0000000..d30bb41 --- /dev/null +++ b/Runtime/Scripting/GetComponent.cpp @@ -0,0 +1,260 @@ +#include "UnityPrefix.h" +#if ENABLE_SCRIPTING +#include "ScriptingUtility.h" +#include "Runtime/Mono/MonoBehaviour.h" +#include "Runtime/Mono/MonoManager.h" +#include "Runtime/Graphics/Transform.h" +#include "Runtime/Misc/GameObjectUtility.h" +#include "Runtime/Scripting/ScriptingUtility.h" +#include "Runtime/Scripting/ScriptingExportUtility.h" +#include "Runtime/Animation/Animation.h" +#include "Runtime/Camera/Camera.h" +#include "Runtime/Utilities/dense_hash_map.h" +#include "Runtime/Scripting/Backend/ScriptingBackendApi.h" +#include "Runtime/Scripting/Backend/ScriptingTypeRegistry.h" +#include "Runtime/Scripting/ScriptingUtility.h" +#include "Runtime/Scripting/Scripting.h" + +inline static bool ComponentMatchesRequirement_ByScriptingClass(Unity::GameObject& go, int componentIndex, ScriptingClassPtr compareClass) +{ + int classID = go.GetComponentClassIDAtIndex(componentIndex); + if (classID != ClassID (MonoBehaviour)) + return false; + + Unity::Component& component = go.GetComponentAtIndex(componentIndex); + MonoBehaviour& behaviour = static_cast<MonoBehaviour&> (component); + ScriptingClassPtr klass = behaviour.GetClass (); + if (klass == SCRIPTING_NULL) + return false; + + if (klass == compareClass) + return true; + + return scripting_class_is_subclass_of (klass, compareClass); +} + +inline static bool ComponentMatchesRequirement_ByClassID(Unity::GameObject& go, int componentIndex, int compareClassID, bool isCompareClassSealed) +{ + int classID = go.GetComponentClassIDAtIndex(componentIndex); + + if (classID == compareClassID) + return true; + + if (isCompareClassSealed) + return false; + + return Object::IsDerivedFromClassID(classID,compareClassID); +} + +namespace SearchMethod +{ + enum { + ByClassID, + ByScriptingClass, + DontEvenStart + }; +} + +template<bool getOnlyOne, int searchMethod> +static bool GetComponentsImplementation (GameObject& go, bool includeInactive, void* compareData, void* output) +{ + if (!includeInactive && !go.IsActive()) + return false; + + bool foundAtLeastOne = false; + + bool isSealed; + UInt64 compareClassID = (UInt64)(uintptr_t)(compareData); + if (searchMethod == SearchMethod::ByClassID) + { + Assert(Transform::IsSealedClass()); + Assert(Animation::IsSealedClass()); + Assert(Camera::IsSealedClass()); + isSealed = compareClassID == ClassID(Transform) || compareClassID == ClassID(Animation) || compareClassID == ClassID(Camera); + } + + int count = go.GetComponentCount (); + for (int i = 0; i < count; i++) + { + if (searchMethod == SearchMethod::ByClassID && !ComponentMatchesRequirement_ByClassID(go,i,compareClassID,isSealed)) + continue; + + if (searchMethod == SearchMethod::ByScriptingClass && !ComponentMatchesRequirement_ByScriptingClass(go,i, reinterpret_cast<ScriptingClassPtr>(compareData))) + continue; + + Unity::Component* component = &go.GetComponentAtIndex(i); + if (getOnlyOne) + { + *((Unity::Component**) output) = component; + return true; + } + + dynamic_array<Unity::Component*>* manyResults = (dynamic_array<Unity::Component*>*) output; + if (manyResults->empty()) + manyResults->reserve(10); + manyResults->push_back(component); + foundAtLeastOne = true; + } + + return foundAtLeastOne; +} + +template<bool getOnlyOne, int searchMethod> +static bool GetComponentsImplementationRecurse (GameObject& go, bool includeInactive, void* compareData, void* output) +{ + bool foundAtLeastOne = GetComponentsImplementation<getOnlyOne, searchMethod>(go,includeInactive,compareData,output); + if (foundAtLeastOne && getOnlyOne) + return true; + + // Recurse Transform hierarchy + Transform& transform = go.GetComponentT<Transform> (ClassID (Transform)); + int count = transform.GetChildrenCount(); + for (int i = 0; i < count; i++) + { + Transform& child = transform.GetChild(i); + foundAtLeastOne = GetComponentsImplementationRecurse<getOnlyOne,searchMethod>(child.GetGameObject(), includeInactive, compareData,output); + if (foundAtLeastOne && getOnlyOne) + return true; + } + return false; +} + +#if MONO_QUALITY_ERRORS +static bool ScriptingClassIsValidGetComponentArgument(ScriptingClass* compareClass) +{ + if (mono_class_is_subclass_of(compareClass, GetMonoManager().GetCommonClasses().component, true)) + return true; + + if (mono_unity_class_is_interface(compareClass)) + return true; + + return false; +} + + +static void VerifyGetComponentsOfTypeFromGameObjectArgument(GameObject& go, ScriptingClassPtr compareKlass) +{ + if (compareKlass == NULL) + { + ScriptWarning("GetComponent asking for invalid type", &go); + return; + } + + if (ScriptingClassIsValidGetComponentArgument(compareKlass)) + return; + + const char* klassName = mono_class_get_name (compareKlass); + ScriptWarning(Format("GetComponent requires that the requested component '%s' derives from MonoBehaviour or Component or is an interface.", klassName), &go); +} +#endif + +static void DetermineSearchMethod(ScriptingClassPtr klass, int* outputSearchMethod, void** outputCompareData) +{ + int classid = GetScriptingManager().ClassIDForScriptingClass(klass); + if (classid == -1) + { + *outputSearchMethod = SearchMethod::ByScriptingClass; + *outputCompareData = (void*)klass; + return; + } + + *outputCompareData = (void*) classid; + *outputSearchMethod = SearchMethod::ByClassID; +} + +typedef bool GetComponentsFunction (GameObject& go, bool includeInactive, void* compareData, void* output); + +template<bool getOnlyOne> +static GetComponentsFunction* DetermineGetComponentsImplementationFunction(int searchMethod,bool recursive) +{ + if (searchMethod == SearchMethod::ByClassID && recursive) + return GetComponentsImplementationRecurse<getOnlyOne,SearchMethod::ByClassID>; + + if (searchMethod == SearchMethod::ByClassID && !recursive) + return GetComponentsImplementation<getOnlyOne,SearchMethod::ByClassID>; + + if (searchMethod == SearchMethod::ByScriptingClass && recursive) + return GetComponentsImplementationRecurse<getOnlyOne,SearchMethod::ByScriptingClass>; + + if (searchMethod == SearchMethod::ByScriptingClass && !recursive) + return GetComponentsImplementation<getOnlyOne,SearchMethod::ByScriptingClass>; + + if (searchMethod == SearchMethod::DontEvenStart) + return NULL; + + return NULL; +} + +template<bool getOnlyOne> +static void GetComponentsOfTypeFromGameObject(GameObject& go, ScriptingClassPtr compareKlass, bool generateErrors, bool recursive, bool includeInactive, void* results) +{ +#if MONO_QUALITY_ERRORS + if (generateErrors) + VerifyGetComponentsOfTypeFromGameObjectArgument(go,compareKlass); +#endif + + if (compareKlass == SCRIPTING_NULL) + return; + + int searchMethod; + void* compareData; + + DetermineSearchMethod(compareKlass,&searchMethod,&compareData); + + GetComponentsFunction* getComponents = DetermineGetComponentsImplementationFunction<getOnlyOne>(searchMethod,recursive); + if (getComponents) + getComponents(go,includeInactive,compareData,results); +} + +ScriptingArrayPtr ScriptingGetComponentsOfType (GameObject& go, ScriptingObjectPtr systemTypeInstance, bool useSearchTypeAsArrayReturnType, bool recursive, bool includeInactive) +{ + dynamic_array<Unity::Component*> components(kMemTempAlloc); + ScriptingClassPtr compareKlass = GetScriptingTypeRegistry().GetType (systemTypeInstance); + GetComponentsOfTypeFromGameObject<false>(go,compareKlass, true, recursive, includeInactive, &components); + +#if ENABLE_MONO || UNITY_WINRT + ScriptingClassPtr componentClass = GetMonoManager ().ClassIDToScriptingClass (ClassID (Component)); + ScriptingClassPtr classForArray = useSearchTypeAsArrayReturnType ? compareKlass : componentClass; + // ToDo: why aren't we using useSearchTypeAsArrayReturnType for flash ?! Lucas, Ralph? +#elif UNITY_FLASH + ScriptingClassPtr classForArray = compareKlass; +#endif + return CreateScriptingArrayFromUnityObjects(components,classForArray); +} + +ScriptingObjectPtr ScriptingGetComponentOfType (GameObject& go, ScriptingObjectPtr systemTypeInstance, bool generateErrors) +{ + if (systemTypeInstance == SCRIPTING_NULL) + { + Scripting::RaiseArgumentException ("Type can not be null."); + return SCRIPTING_NULL; + } + + ScriptingClassPtr compareKlass = GetScriptingTypeRegistry().GetType (systemTypeInstance); + Unity::Component* result = NULL; + + GetComponentsOfTypeFromGameObject<true>(go,compareKlass, generateErrors, false, true, &result); + + if (result != NULL) + return Scripting::ScriptingWrapperFor(result); + +#if MONO_QUALITY_ERRORS + if(generateErrors) + return MonoObjectNULL(compareKlass, MissingComponentString(go,compareKlass)); +#endif + + return SCRIPTING_NULL; +} + +ScriptingObjectPtr ScriptingGetComponentOfType (GameObject& go, ScriptingClassPtr systemTypeInstance) +{ + Unity::Component* result = NULL; + GetComponentsOfTypeFromGameObject<true>(go, systemTypeInstance, false, false, true, &result); + if (result) + return Scripting::ScriptingWrapperFor(result); + + return SCRIPTING_NULL; +} + + +#endif diff --git a/Runtime/Scripting/GetComponent.h b/Runtime/Scripting/GetComponent.h new file mode 100644 index 0000000..f9aff0a --- /dev/null +++ b/Runtime/Scripting/GetComponent.h @@ -0,0 +1,16 @@ +#ifndef GETCOMPONENT_H +#define GETCOMPONENT_H + +#include "Runtime/Scripting/Backend/ScriptingTypes.h" +#include "Runtime/BaseClasses/BaseObject.h" +#include "Runtime/Mono/MonoIncludes.h" + +#if ENABLE_SCRIPTING + +ScriptingArrayPtr ScriptingGetComponentsOfType (Unity::GameObject& go, ScriptingObjectPtr reflectionTypeObject, bool useSearchTypeAsArrayReturnType, bool recursive, bool includeInactive); +ScriptingObjectPtr ScriptingGetComponentOfType (Unity::GameObject& go, ScriptingObjectPtr reflectionTypeObject, bool generateErrors = true); +ScriptingObjectPtr ScriptingGetComponentOfType (GameObject& go, ScriptingClassPtr systemTypeInstance); + +#endif + +#endif diff --git a/Runtime/Scripting/ICallString.cpp b/Runtime/Scripting/ICallString.cpp new file mode 100644 index 0000000..ad1cceb --- /dev/null +++ b/Runtime/Scripting/ICallString.cpp @@ -0,0 +1,40 @@ +#include "UnityPrefix.h" + +#if ENABLE_SCRIPTING + +#if !UNITY_FLASH +#include "ICallString.h" +#include "Runtime/Scripting/Backend/ScriptingBackendApi.h" + + +#if ENABLE_MONO +std::string ICallString::AsUTF8() const +{ + return scripting_cpp_string_for(str).c_str(); +} +#elif UNITY_WINRT +#include "PlatformDependent/MetroPlayer/MetroUtils.h" +std::string ICallString::AsUTF8() const +{ + return ConvertStringToUtf8(str); +} +#endif + +#if ENABLE_MONO +// todo: remove this useless include once we figure out where to take mono_string_length from. +#include "Runtime/Scripting/ScriptingUtility.h" +#endif + +int ICallString::Length() +{ +#if ENABLE_MONO + return mono_string_length(str); +#elif UNITY_WINRT + return wcslen(str); + //return safe_cast<Platform::String^>(str)->Length(); +#endif +} +#endif + +#endif + diff --git a/Runtime/Scripting/ICallString.h b/Runtime/Scripting/ICallString.h new file mode 100644 index 0000000..6c096d2 --- /dev/null +++ b/Runtime/Scripting/ICallString.h @@ -0,0 +1,91 @@ +#pragma once + +#if ENABLE_SCRIPTING + +#include "Runtime/Scripting/Backend/ScriptingTypes.h" +#include <string> + +#if ENABLE_MONO +struct ICallString +{ + MonoString* str; + + EXPORT_COREMODULE std::string AsUTF8() const; + operator std::string () const { return AsUTF8(); } + int Length(); + bool IsNull () {return !str;} + + MonoString* GetNativeString() {return str;} +}; +#endif + +#if UNITY_FLASH +struct ICallString +{ + const char* utf8stream; + + std::string AsUTF8() const { return utf8stream; } + operator std::string () const { return AsUTF8(); } + + int Length() { return strlen(utf8stream); } + bool IsNull () {return !utf8stream;} + const char* GetNativeString() {return utf8stream;} +}; +#endif + +#if UNITY_WINRT +struct ICallString +{ +private: + const wchar_t* str; + //Platform::Object^ str; + + ICallString(const ICallString& other){} + ICallString& operator = (const ICallString& rhs) + { + return *this; + } +public: + ICallString(){} + ICallString(const wchar_t* _str) + : str(_str) + { + } + std::string AsUTF8() const; + operator std::string () const { return AsUTF8(); } + + int Length(); + bool IsNull () {return (str == SCRIPTING_NULL);} + + ScriptingStringPtr GetNativeString() {return ref new Platform::String(str);} +}; +#endif + +/* +//For the next step + +struct structwithsomename +{ +char buf[256]; +char* fallback; + +structwithsomename(ICallString& ics) +{ + + +} + +~structwithsomename() +{ +delete fallback; +} + +const char* Get() +{ +fastutf8into(buf); +} + +const char* operator () { return Get(); } +};*/ + +#endif diff --git a/Runtime/Scripting/MonoManager_Flash.cpp b/Runtime/Scripting/MonoManager_Flash.cpp new file mode 100644 index 0000000..22cc7f4 --- /dev/null +++ b/Runtime/Scripting/MonoManager_Flash.cpp @@ -0,0 +1,41 @@ +#include "UnityPrefix.h" + +#include "MonoManager_Flash.h" +#include "Runtime/Serialize/TransferFunctions/SerializeTransfer.h" +#include "Runtime/Mono/MonoScript.h" +#include "Runtime/BaseClasses/ManagerContext.h" +#include "Runtime/Scripting/CommonScriptingClasses.h" +#include "Runtime/Scripting/ScriptingUtility.h" +#include "Runtime/Scripting/Backend/ScriptingBackendApi.h" + +#include "Runtime/Scripting/Backend/Flash/ScriptingTypeProvider_Flash.h" +#include "Runtime/Scripting/Backend/Flash/ScriptingMethodFactory_Flash.h" + +#include "Runtime/Scripting/Backend/ScriptingMethodRegistry.h" + +#include "Runtime/Mono/MonoBehaviourSerialization_ByCodeGeneration.h" + +MonoManager::MonoManager (MemLabelId label, ObjectCreationMode mode) + : ScriptingManager(label, mode, UNITY_NEW( ScriptingTypeProvider_Flash(), kMemManager), UNITY_NEW( ScriptingMethodFactory_Flash(), kMemManager)) +{ + FillCommonScriptingClasses(m_CommonScriptingClasses); +} + +MonoManager::~MonoManager () +{ + +} + +template<class TransferFunction> +void MonoManager::Transfer (TransferFunction& transfer) +{ + Super::Transfer (transfer); + transfer.SetVersion(2); + transfer.Transfer (m_MonoScriptManager.m_RuntimeScripts, "m_Scripts"); +} + + +IMPLEMENT_OBJECT_SERIALIZE (MonoManager) +IMPLEMENT_CLASS (MonoManager) +GET_MANAGER (MonoManager) +GET_MANAGER_PTR (MonoManager) diff --git a/Runtime/Scripting/MonoManager_Flash.h b/Runtime/Scripting/MonoManager_Flash.h new file mode 100644 index 0000000..2367fbd --- /dev/null +++ b/Runtime/Scripting/MonoManager_Flash.h @@ -0,0 +1,27 @@ +#ifndef MONOMANAGER_FLASH_H +#define MONOMANAGER_FLASH_H + +#include "Runtime/BaseClasses/GameManager.h" +#include "Runtime/Mono/MonoScriptManager.h" +#include "Runtime/Scripting/CommonScriptingClasses.h" +#include "Runtime/Scripting/ScriptingManager.h" + +class MonoManager : public ScriptingManager +{ +public: + REGISTER_DERIVED_CLASS (MonoManager, GlobalGameManager) + DECLARE_OBJECT_SERIALIZE (MonoManager) + + MonoManager (MemLabelId label, ObjectCreationMode mode); + // virtual ~MonoManager (); declared-by-macro + + ScriptingObjectPtr CreateInstance(ScriptingClassPtr klass); + +private: + +}; + +MonoManager& GetMonoManager (); +MonoManager* GetMonoManagerPtr (); + +#endif diff --git a/Runtime/Scripting/MonoManager_WinRT.cpp b/Runtime/Scripting/MonoManager_WinRT.cpp new file mode 100644 index 0000000..7719478 --- /dev/null +++ b/Runtime/Scripting/MonoManager_WinRT.cpp @@ -0,0 +1,105 @@ +#include "UnityPrefix.h" + +#include "MonoManager_WinRT.h" +#include "Runtime/Serialize/TransferFunctions/SerializeTransfer.h" +#include "Runtime/Mono/MonoScript.h" +#include "Runtime/BaseClasses/ManagerContext.h" +#include "Runtime/Scripting/CommonScriptingClasses.h" +#include "Runtime/Scripting/ScriptingUtility.h" +#include "Runtime/Scripting/Backend/ScriptingBackendApi.h" + +#include "Runtime/Scripting/Backend/Metro/ScriptingTypeProvider_Metro.h" +#include "Runtime/Scripting/Backend/Metro/ScriptingMethodFactory_Metro.h" + +#include "Runtime/Scripting/Backend/ScriptingMethodRegistry.h" + +#include "Runtime/Mono/MonoBehaviourSerialization_ByCodeGeneration.h" + +#include "PlatformDependent/MetroPlayer/MetroUtils.h" + +MonoManager::MonoManager (MemLabelId label, ObjectCreationMode mode) + : ScriptingManager(label, mode, UNITY_NEW( ScriptingTypeProvider_Metro(), kMemManager), UNITY_NEW( ScriptingMethodFactory_Metro(), kMemManager)) +{ + METRO_DBG_MARK_TIME("MonoManager::ctor"); + InputString data; + const char* managedAssemblies = "managedAssemblies.txt"; + if (ReadStringFromFile(&data, PathToAbsolutePath(managedAssemblies))) + { + GetWinRTUtils()->LoadAssemblies(ConvertUtf8ToString(data.c_str())); + } + else + { + FatalErrorMsg("Failed to load %s", managedAssemblies); + } + METRO_DBG_MARK_TIME("MonoManager::FillCommonScriptingClasses begin..."); + FillCommonScriptingClasses(m_CommonScriptingClasses); + METRO_DBG_MARK_TIME("MonoManager::FillCommonScriptingClasses end..."); + SetupExceptionHandler(); + SetupMarshalCallbacks(); + void RegisterAllInternalCalls(); + RegisterAllInternalCalls(); + +# if ENABLE_SERIALIZATION_BY_CODEGENERATION + + s_WinRTBridge->SetupSerializationReader( + (long long)(NativeExt_MonoBehaviourSerialization_ReaderAlign), + (long long)(NativeExt_MonoBehaviourSerialization_ReadBuffer), + (long long)(NativeExt_MonoBehaviourSerialization_ReadUnityEngineObject), + (long long)(NativeExt_MonoBehaviourSerialization_ReadGUIStyle), + (long long)(NativeExt_MonoBehaviourSerialization_ReadRectOffset), + (long long)(NativeExt_MonoBehaviourSerialization_ReadAnimationCurve), + (long long)(NativeExt_MonoBehaviourSerialization_ReadGradient)); + + s_WinRTBridge->SetupSerializationWriter( + (long long)(NativeExt_MonoBehaviourSerialization_WriterAlign), + (long long)(NativeExt_MonoBehaviourSerialization_WriteBuffer), + (long long)(NativeExt_MonoBehaviourSerialization_WriteUnityEngineObject), + (long long)(NativeExt_MonoBehaviourSerialization_WriteGUIStyle), + (long long)(NativeExt_MonoBehaviourSerialization_WriteRectOffset), + (long long)(NativeExt_MonoBehaviourSerialization_WriteAnimationCurve), + (long long)(NativeExt_MonoBehaviourSerialization_WriteGradient)); + + s_WinRTBridge->SetupSerializationRemapper( + (long long)(NativeExt_MonoBehaviourSerialization_GetNewInstanceToReplaceOldInstance)); + + ScriptingInvocation initManagedAnalysis(GetScriptingMethodRegistry().GetMethod("UnityEngine.Serialization","ManagedLivenessAnalysis","Init")); + initManagedAnalysis.Invoke(); +# endif + // It tries to get classes like LevelGameManager which doesn't exist in managed land, is this intended? + RebuildClassIDToScriptingClass(); + +# if !ENABLE_WINRT_PINVOKE + METRO_DBG_MARK_TIME("MonoManager::SetupDelegates begin..."); + GetWinRTUtils()->SetupDelegates(); + METRO_DBG_MARK_TIME("MonoManager::SetupDelegates end..."); +# else + if (GetWinRTUtils()->IsPlatformInvokeSupported() == false) + FatalErrorMsg("WinRTBridge: Platform Invoke should be supported on this platform."); + if (UnityEngineDelegates::PlatformInvoke::IsSupported() == false) + FatalErrorMsg("UnityEngineDelegates: Platform Invoke should be supported on this platform."); +# endif + +} + +MonoManager::~MonoManager () +{ + +} + +template<class TransferFunction> +void MonoManager::Transfer (TransferFunction& transfer) +{ + Super::Transfer (transfer); + transfer.SetVersion(2); + transfer.Transfer (m_MonoScriptManager.m_RuntimeScripts, "m_Scripts"); + + // ToDo: Temporary fix if we're deserializing for metro see MonoManager::Transfer function + std::vector<UnityStr> assemblyNames; + transfer.Transfer (assemblyNames, "m_AssemblyNames"); +} + + +IMPLEMENT_OBJECT_SERIALIZE (MonoManager) +IMPLEMENT_CLASS (MonoManager) +GET_MANAGER (MonoManager) +GET_MANAGER_PTR (MonoManager) diff --git a/Runtime/Scripting/MonoManager_WinRT.h b/Runtime/Scripting/MonoManager_WinRT.h new file mode 100644 index 0000000..cc43c8e --- /dev/null +++ b/Runtime/Scripting/MonoManager_WinRT.h @@ -0,0 +1,27 @@ +#ifndef MONOMANAGER_WINRT_H +#define MONOMANAGER_WINRT_H + +#include "Runtime/BaseClasses/GameManager.h" +#include "Runtime/Mono/MonoScriptManager.h" +#include "Runtime/Scripting/CommonScriptingClasses.h" +#include "Runtime/Scripting/ScriptingManager.h" + +class MonoManager : public ScriptingManager +{ +public: + REGISTER_DERIVED_CLASS (MonoManager, GlobalGameManager) + DECLARE_OBJECT_SERIALIZE (MonoManager) + + MonoManager (MemLabelId label, ObjectCreationMode mode); + // virtual ~MonoManager (); declared-by-macro + + ScriptingObjectPtr CreateInstance(ScriptingClassPtr klass); + +private: + +}; + +MonoManager& GetMonoManager (); +MonoManager* GetMonoManagerPtr (); + +#endif diff --git a/Runtime/Scripting/ReadOnlyScriptingObjectOfType.h b/Runtime/Scripting/ReadOnlyScriptingObjectOfType.h new file mode 100644 index 0000000..2a837e6 --- /dev/null +++ b/Runtime/Scripting/ReadOnlyScriptingObjectOfType.h @@ -0,0 +1,151 @@ +#pragma once + +#include "Runtime/Scripting/Backend/ScriptingTypes.h" +#include "Scripting.h" + +#define SUPPORT_DIRECT_CACHEDPTR_PASSING_FOR_READONLY_OBJECTS UNITY_WINRT + +#if !SUPPORT_DIRECT_CACHEDPTR_PASSING_FOR_READONLY_OBJECTS +template<class T> +struct ReadOnlyScriptingObjectOfType +{ +private: + ScriptingObjectPtr object; +public: + ReadOnlyScriptingObjectOfType(ScriptingObjectPtr object) + { + this->object = object; + } + + T& GetReference () const + { + T* ptr = GetPtr(); + + if (ptr != NULL) + return *ptr; + + Scripting::RaiseNullExceptionObject (object); + return *(T*)NULL; + } + + T& operator * () const + { + return GetReference (); + } + + operator T* () const + { + return GetPtr (); + } + + T* operator -> () const + { + return &GetReference (); + } + + bool IsNull() const + { + return object == SCRIPTING_NULL; + } + + operator PPtr<T> () const + { + if (IsNull()) + return PPtr<T> (); + + return PPtr<T> (GetInstanceID()); + } + +private: +#if UNITY_EDITOR +public: + // ToDo: Fix this later, ask TomasD or Lucas + inline ScriptingObjectPtr GetScriptingObject() const + { + return object; + } +#endif + + inline int GetInstanceID() const + { + return Scripting::GetInstanceIDFromScriptingWrapper(object); + } + T* GetPtr () const + { + if (IsNull()) + return NULL; + + void* cachedPtr = GetCachedPtr(); + if (cachedPtr != NULL) + { + AssertIf(reinterpret_cast<Object*> (cachedPtr)->GetInstanceID() != GetInstanceID()); + return (T*)cachedPtr; + } + + T* temp = dynamic_instanceID_cast<T*> (GetInstanceID()); + return temp; + } + + inline void* GetCachedPtr() const + { + return Scripting::GetCachedPtrFromScriptingWrapper(object); + } +}; + +#else + +template<class T> +struct ReadOnlyScriptingObjectOfType +{ +private: + T* cachedPtr; +public: + ReadOnlyScriptingObjectOfType(void* p) + { + this->cachedPtr = (T*)p; + } + + T& GetReference () const + { + if (cachedPtr != NULL) + return *(T*)cachedPtr; + + Scripting::RaiseNullExceptionObject (SCRIPTING_NULL); + return *(T*)NULL; + } + + T& operator * () const + { + return GetReference (); + } + + operator T* () const + { + return cachedPtr; + } + + T* operator -> () const + { + return &GetReference (); + } + + bool IsNull() const + { + return cachedPtr == NULL; + } + + operator PPtr<T> () const + { + if (IsNull()) + return PPtr<T> (); + + return PPtr<T> (cachedPtr->GetInstanceID()); + } + +}; + +#endif + + + + diff --git a/Runtime/Scripting/ScriptLanguagePortUtility.cpp b/Runtime/Scripting/ScriptLanguagePortUtility.cpp new file mode 100644 index 0000000..7f53640 --- /dev/null +++ b/Runtime/Scripting/ScriptLanguagePortUtility.cpp @@ -0,0 +1,11 @@ +#include "UnityPrefix.h" +#if UNITY_FLASH + +#include "ScriptLanguagePortUtility.h" + +bool IsFileCreated(const std::string& path) +{ + return Ext_FileContainer_IsFileCreatedAt(path.c_str()); +} + +#endif
\ No newline at end of file diff --git a/Runtime/Scripting/ScriptLanguagePortUtility.h b/Runtime/Scripting/ScriptLanguagePortUtility.h new file mode 100644 index 0000000..913aab4 --- /dev/null +++ b/Runtime/Scripting/ScriptLanguagePortUtility.h @@ -0,0 +1,10 @@ +#ifndef SCRIPTLANGUAGEPORTUTILITY_H +#define SCRIPTLANGUAGEPORTUTILITY_H + +#if UNITY_FLASH || UNITY_WEBGL + +extern "C" bool Ext_FileContainer_IsFileCreatedAt(const char* filename); +extern "C" bool Ext_LogCallstack(); + +#endif +#endif diff --git a/Runtime/Scripting/ScriptPopupMenus.cpp b/Runtime/Scripting/ScriptPopupMenus.cpp new file mode 100644 index 0000000..fdc3c1d --- /dev/null +++ b/Runtime/Scripting/ScriptPopupMenus.cpp @@ -0,0 +1,142 @@ +#include "UnityPrefix.h" +#include "Runtime/Mono/MonoManager.h" +#include "Runtime/Scripting/ScriptPopupMenus.h" +#include "Runtime/Mono/tabledefs.h" +#include "Runtime/Serialize/TypeTree.h" +#include "Runtime/Mono/MonoBehaviour.h" +#include "Runtime/Serialize/IterateTypeTree.h" +#include "Runtime/Scripting/ScriptingUtility.h" + +using namespace std; + +#if UNITY_EDITOR + +static void ExtractPopupFromEnum (MonoClass* klass, map<string, int>& popup) +{ + MonoVTable * vtable = mono_class_vtable (mono_domain_get (), klass); + MonoClassField *field; + void* iter = NULL; + + MonoType* enumMonoType = mono_class_enum_basetype (klass); + int enumType = mono_type_get_type (enumMonoType); + + while ((field = mono_class_get_fields (klass, &iter))) + { + int value; + const char* name = mono_field_get_name (field); + int flags = mono_field_get_flags (field); + if (flags & FIELD_ATTRIBUTE_STATIC) + { + switch (enumType) + { + case MONO_TYPE_I4: + mono_field_static_get_value (vtable, field, &value); + break; + case MONO_TYPE_U1: + UInt8 byteValue; + mono_field_static_get_value (vtable, field, &byteValue); + value = byteValue; + break; + default: + ErrorString (Format("Unsupported enum type: %s", name)); + break; + } + popup[name] = value; + } + } +} + +const string GetFieldIdentifierForEnum(const TypeTree* typeTree) +{ + string identifier; + while (typeTree != NULL && typeTree->m_Father != NULL) + { + // Skip the extra arary type injected by the serialization system + if (typeTree->m_Father->m_Father && IsTypeTreeArray(*typeTree->m_Father)) + typeTree = typeTree->m_Father->m_Father; + + if (identifier.empty()) + identifier = typeTree->m_Name; + else + identifier = Format("%s.%s", typeTree->m_Name.c_str(), identifier.c_str()); + + typeTree = typeTree->m_Father; + } + + return identifier; +} + +static const string AppendName(const std::string& previous, MonoClassField* field) +{ + const char* name = mono_field_get_name(field); + + if (previous.empty()) + return name; + else + return Format("%s.%s", previous.c_str(), name); +} + +static void BuildScriptPopupMenus (MonoClass* klass, const std::string& parentName, std::map<std::string, std::map<std::string, int> >& popups, std::set<MonoClass*> collected) +{ + const CommonScriptingClasses& commonClasses = GetMonoManager ().GetCommonClasses (); + MonoClass* unityEngineObject = GetMonoManager().ClassIDToScriptingClass(ClassID(Object)); + + while (klass && klass != commonClasses.monoBehaviour && klass != commonClasses.scriptableObject) + { + // Only collect classes once + if (!collected.insert (klass).second) + return; + + MonoClassField *field; + void* iter = NULL; + while ((field = mono_class_get_fields (klass, &iter))) + { + MonoType* monoType = mono_field_get_type (field); + int typeType = mono_type_get_type (monoType); + MonoClass* elementClass; + + int flags = mono_field_get_flags (field); + if (flags & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_INIT_ONLY | FIELD_ATTRIBUTE_NOT_SERIALIZED)) + continue; + + // Extract the array field from the generic list + MonoClassField* arrayField = GetMonoArrayFieldFromList(typeType, monoType, field); + if (arrayField) + { + monoType = mono_field_get_type(arrayField); + typeType = mono_type_get_type (monoType); + } + + if (typeType == MONO_TYPE_VALUETYPE || typeType == MONO_TYPE_SZARRAY) + { + elementClass = mono_type_get_class_or_element_class (monoType); + if (mono_class_is_enum (elementClass)) + { + string name = AppendName(parentName, field); + map<string, int>& items = popups[name]; + items.clear (); + ExtractPopupFromEnum (elementClass, items); + continue; + } + } + if (typeType == MONO_TYPE_CLASS || typeType == MONO_TYPE_SZARRAY) + { + elementClass = mono_type_get_class_or_element_class (monoType); + MonoImage* image = mono_class_get_image(elementClass); + int classflags = mono_class_get_flags(elementClass); + + if ((classflags & TYPE_ATTRIBUTE_SERIALIZABLE) && image != mono_get_corlib() && GetMonoManager().GetAssemblyIndexFromImage(image) != -1 && !mono_class_is_subclass_of(elementClass, unityEngineObject, false)) + BuildScriptPopupMenus(elementClass, AppendName(parentName, field), popups, collected); + } + } + + klass = mono_class_get_parent (klass); + } +} + +void BuildScriptPopupMenus (MonoBehaviour& behaviour, std::map<string, std::map<std::string, int> >& popups) +{ + std::set<MonoClass*> collected; + BuildScriptPopupMenus(behaviour.GetClass (), "", popups, collected); +} +#endif
\ No newline at end of file diff --git a/Runtime/Scripting/ScriptPopupMenus.h b/Runtime/Scripting/ScriptPopupMenus.h new file mode 100644 index 0000000..2c2f3e0 --- /dev/null +++ b/Runtime/Scripting/ScriptPopupMenus.h @@ -0,0 +1,11 @@ +#ifndef __SCRIPTPOPUPMENUSH__ +#define __SCRIPTPOPUPMENUSH__ + +#include <map> + +class TypeTree; +class MonoBehaviour; + +void BuildScriptPopupMenus (MonoBehaviour& behaviour, std::map<std::string, std::map<std::string, int> >& popups); +const std::string GetFieldIdentifierForEnum(const TypeTree* typeTree); +#endif
\ No newline at end of file diff --git a/Runtime/Scripting/Scripting.cpp b/Runtime/Scripting/Scripting.cpp new file mode 100644 index 0000000..5e01feb --- /dev/null +++ b/Runtime/Scripting/Scripting.cpp @@ -0,0 +1,768 @@ +#include "UnityPrefix.h" + +#include "Scripting.h" + +#include "Runtime/BaseClasses/IsPlaying.h" +#include "Runtime/BaseClasses/RefCounted.h" +#include "Runtime/GameCode/DestroyDelayed.h" +#include "Runtime/Graphics/Transform.h" +#include "Runtime/Misc/GameObjectUtility.h" +#include "Runtime/Mono/MonoBehaviour.h" +#include "Runtime/Mono/MonoScriptCache.h" +#include "Runtime/Scripting/ScriptingObjectOfType.h" +#include "Runtime/Scripting/ScriptingManager.h" +#include "Runtime/Scripting/ScriptingObjectWithIntPtrField.h" +#include "Runtime/Scripting/Backend/ScriptingTypeRegistry.h" +#include "Runtime/Scripting/ScriptingExportUtility.h" + +#if UNITY_EDITOR +# include "Editor/Src/AssetPipeline/MonoCompilationPipeline.h" +#endif + +namespace Scripting +{ + +ScriptingObjectPtr ScriptingWrapperFor(Object* o) +{ +#if !ENABLE_SCRIPTING + return 0; +#else + if(!o) + return SCRIPTING_NULL; + + ScriptingObjectPtr cachedInstance = o->GetCachedScriptingObject(); + if(cachedInstance != SCRIPTING_NULL) + return cachedInstance; + + int classID = o->GetClassID(); + if(classID == ClassID(MonoBehaviour)) + { + AssertIf(static_cast<MonoBehaviour*> (o)->GetInstance()); + return SCRIPTING_NULL; + } + + ScriptingObjectPtr object = InstantiateScriptingWrapperForClassID(classID); + return (object != SCRIPTING_NULL) ? ConnectScriptingWrapperToObject(object, o) : SCRIPTING_NULL; +#endif +} + +ScriptingObjectPtr ConnectScriptingWrapperToObject(ScriptingObjectPtr object, Object* ptr) +{ +#if !ENABLE_SCRIPTING + return 0; +#else + // ConnectScriptingWrapperToObject might get called from different threads + // - References to objects are setup from loading thread. + // The Object could already be loaded in memory and in that case it is possible that the main thread might asign a MonoObject* while the loader thread is doing the same. + // - @TODO: If this is a performance bottleneck we could ensure that the loader thread calls ConnectScriptingWrapperToObject only during safe places. + + LockObjectCreation(); + + AssertIf(object == SCRIPTING_NULL); + AssertIf(ptr == NULL); + + if(ptr->GetCachedScriptingObject() != SCRIPTING_NULL) + { + ScriptingObjectPtr res = ptr->GetCachedScriptingObject(); + UnlockObjectCreation(); + + return res; + } + + ScriptingObjectOfType<Object> wrapper(object); + +#if DEBUGMODE && !UNITY_FLASH && !UNITY_WINRT //in flash, we do not yet initialize chachedPtr to 0 + AssertIf(wrapper.GetCachedPtr() != NULL); +#endif + + wrapper.SetCachedPtr(ptr); + wrapper.SetInstanceID(ptr->GetInstanceID()); + +#if MONO_QUALITY_ERRORS + wrapper.SetError(NULL); +#endif + + AssertIf(ptr->GetCachedScriptingObject() != SCRIPTING_NULL); + ptr->SetCachedScriptingObject(object); + + UnlockObjectCreation(); + + return object; +#endif +} + +bool BroadcastScriptingMessage(GameObject& go, const char* name, ScriptingObjectPtr param) +{ + bool didSend = SendScriptingMessage(go, name, param); + + Transform* transform = go.QueryComponent(Transform); + if(transform) + { + for(int i = 0; i < transform->GetChildrenCount(); i++ ) + didSend |= BroadcastScriptingMessage(transform->GetChild(i).GetGameObject(), name, param); + } + + return didSend; +} + + +bool SendScriptingMessageUpwards(GameObject& go, const char* name, ScriptingObjectPtr param) +{ + bool didSend = SendScriptingMessage(go, name, param); + + Transform* transform = go.QueryComponent(Transform); + if (transform) + transform = transform->GetParent(); + + while(transform) + { + didSend |= SendScriptingMessage(transform->GetGameObject(), name, param); + transform = transform->GetParent(); + } + + return didSend; +} + +bool SendScriptingMessage(GameObject& go, const char* name, ScriptingObjectPtr param) +{ + bool didSend = false; + + if(!go.IsActive()) + return false; + + int instanceID = go.GetInstanceID(); + + for(int i = 0; i < go.GetComponentCount(); i++) + { + if(go.GetComponentClassIDAtIndex(i) == ClassID(MonoBehaviour)) + { + MonoBehaviour& behaviour = static_cast<MonoBehaviour&>(go.GetComponentAtIndex(i)); + + ScriptingObjectPtr instance = behaviour.GetInstance(); + if(instance) + { + ScriptingMethodPtr method = behaviour.FindMethod(name); + if(method == SCRIPTING_NULL) + continue; + + behaviour.InvokeMethodOrCoroutineChecked(method, param); + didSend = true; + + // Check if the gameObject was destroyed. + if(!PPtr<Object>(instanceID).IsValid()) + return didSend; + } + } + } + + return didSend; +} + +bool BroadcastScriptingMessage(GameObject& go, const std::string& methodName, ScriptingObjectPtr param, int options) +{ + bool didSend = BroadcastScriptingMessage(go, methodName.c_str(), param); + +#if !DEPLOY_OPTIMIZED + if(!didSend && options == 0) + ErrorStringObject(Format("BroadcastMessage %s has no receiver!", methodName.c_str()), &go); +#endif + + return didSend; +} + +bool SendScriptingMessageUpwards(GameObject& go, const std::string& methodName, ScriptingObjectPtr param, int options) +{ + bool didSend = SendScriptingMessageUpwards(go, methodName.c_str(), param); + +#if !DEPLOY_OPTIMIZED + if(!didSend && options == 0) + ErrorStringObject(Format("SendMessage %s has no receiver!", methodName.c_str()), &go); +#endif + + return didSend; +} + +bool SendScriptingMessage(GameObject& go, const std::string& methodName, ScriptingObjectPtr param, int options) +{ + bool didSend = SendScriptingMessage(go, methodName.c_str(), param); + +#if !DEPLOY_OPTIMIZED + if(!didSend && options == 0) + ErrorStringObject(Format("SendMessage %s has no receiver!", methodName.c_str()), &go); +#endif + + return didSend; +} + +/// Compares two Object classes. +/// Returns true if both have the same instance id +/// or both are NULL (Null can either mean that the object is gone or that the instanceID is 0) +bool CompareBaseObjects (ScriptingObjectPtr lhs, ScriptingObjectPtr rhs) +{ + int lhsInstanceID = 0; + int rhsInstanceID = 0; + bool isLhsNull = true, isRhsNull = true; + if (lhs) + { + lhsInstanceID = GetInstanceIDFromScriptingWrapper (lhs); + ScriptingObjectOfType<Object> lhsRef(lhs); + isLhsNull = !lhsRef.IsValidObjectReference(); + } + if (rhs) + { + rhsInstanceID = GetInstanceIDFromScriptingWrapper (rhs); + ScriptingObjectOfType<Object> rhsRef(rhs); + isRhsNull = !rhsRef.IsValidObjectReference(); + } + if (isLhsNull || isRhsNull) + return isLhsNull == isRhsNull; + else + return lhsInstanceID == rhsInstanceID; +} + +void DestroyObjectFromScriptingImmediate(Object* object, bool allowDestroyingAssets) +{ +#if !DEPLOY_OPTIMIZED + if(object && object->IsPersistent() && !allowDestroyingAssets) + { + ErrorStringObject ("Destroying assets is not permitted to avoid data loss.\nIf you really want to remove an asset use DestroyImmediate (theObject, true);", object); + return; + } +#endif + + DestroyObjectHighLevel(object); +} + +void UnloadAssetFromScripting(Object* object) +{ + if(object == NULL) + return; + +#if !DEPLOY_OPTIMIZED + if(!object->IsPersistent()) + { + ErrorStringObject ("UnloadAsset can only be used on assets;", object); + return; + } + + bool disallowedUnloadTypes = object->IsDerivedFrom(ClassID(Component)) || object->IsDerivedFrom(ClassID(GameObject)) || object->IsDerivedFrom(ClassID(AssetBundle)); + if(disallowedUnloadTypes) + { + ErrorStringObject ("UnloadAsset may only be used on individual assets and can not be used on GameObject's / Components or AssetBundles", object); + return; + } +#endif + + UnloadObject(object); +} + +static void DisableBehaviours( GameObject* target ) +{ + for ( unsigned compI = 0; compI < target->GetComponentCount(); ++compI ) + { + Behaviour* behaviour = dynamic_pptr_cast<Behaviour*> (&target->GetComponentAtIndex(compI)); + if (behaviour) + behaviour->SetEnabled(false); + } +} + +// @TODO: Test for DestroyImmediate from Destroy in OnDisable! +void DestroyObjectFromScripting (PPtr<Object> object, float t) +{ + if (!IsWorldPlaying()) + { + ErrorString("Destroy may not be called from edit mode! Use DestroyImmediate instead.\nAlso think twice if you really want to destroy something in edit mode. Since this will destroy objects permanently."); + return; + } + + if (object) + { +#if !DEPLOY_OPTIMIZED + if (object->IsPersistent ()) + { + ErrorStringObject ("Destroying assets is not permitted to avoid data loss.\nIf you really want to remove an asset use DestroyImmediate (theObject, true);", object); + return; + } +#endif + + // if we want to destroy it this frame (t <= 0.0) - we need to imitate "destroy right away" behaviour + if (t <= 0.0) + { + Behaviour* behaviour = dynamic_pptr_cast<Behaviour*> (object); + if (behaviour) + { + // if this Object is some kind of Behaviour, it is already in update queue. + // if it was updated before we can do nothing, but if not - just disable it + behaviour->SetEnabled(false); + } + + GameObject* go = dynamic_pptr_cast<GameObject*> (object); + if (go) + { + // if we destroy game object - disable all behaviours (children included) + DisableBehaviours(go); + + ////@TODO: This needs to be done recursively + + Transform& root = go->GetComponentT<Transform>(ClassID(Transform)); + for ( unsigned childI = 0; childI < root.GetChildrenCount(); ++childI ) + DisableBehaviours( root.GetChild(childI).GetGameObjectPtr() ); + } + } + + DestroyObjectDelayed (object, t); + } +} + +static MonoScript* FindScriptableObjectFromClass (ScriptingTypePtr klass, bool errorOnMissingScript = true) +{ + if (klass == SCRIPTING_NULL) + { + ErrorString ("Instance couldn't be created because type was null."); + return NULL; + } + + MonoScript* script = GetMonoScriptManager().FindRuntimeScript(klass); + if (script == NULL) + { + script = GetMonoScriptManager().FindEditorScript(klass); + if (script == NULL) + { + if (errorOnMissingScript) + { + ErrorString (Format ("Instance of %s couldn't be created because there is no script with that name.", scripting_class_get_name(klass))); + } + return NULL; + } + } + + if (script->GetScriptType() != kScriptTypeScriptableObjectDerived && script->GetScriptType() != kScriptTypeEditorScriptableObjectDerived) + { + ErrorString (Format ("Instance of %s couldn't be created. The the script class needs to derive from ScriptableObject.", scripting_class_get_name(klass))); + return NULL; + } + + if (script->GetClass() == SCRIPTING_NULL) + { + ErrorString (Format ("Instance of %s couldn't be created. All script needs to successfully compile first!", scripting_class_get_name(klass))); + return NULL; + } + + return script; +} + +ScriptingObjectPtr CreateScriptableObjectWithType (ScriptingObjectPtr systemTypeInstance) +{ + ScriptingTypePtr type = GetScriptingTypeRegistry().GetType(systemTypeInstance); + if(type == NULL) + return SCRIPTING_NULL; + + MonoBehaviour* behaviour = 0; + + bool errorOnMissingScript = UNITY_EDITOR ? false : true; + + MonoScript* script = FindScriptableObjectFromClass(type, errorOnMissingScript); + if(script == NULL) + { +#if UNITY_EDITOR + MonoImage* image = mono_class_get_image(type); + std::string imageFileName = mono_image_get_filename(image); + + if (IsEditorOnlyAssembly(imageFileName, true)) + { + std::string imageName = mono_image_get_name(image); + std::string id = BuildScriptClassId(imageName, mono_class_get_namespace(type), mono_class_get_name(type)); + + behaviour = NEW_OBJECT (MonoBehaviour); + behaviour->SetClassIdentifier(id); + } + else + return SCRIPTING_NULL; +#else + return SCRIPTING_NULL; +#endif + } else + { + behaviour = NEW_OBJECT (MonoBehaviour); + behaviour->SetScript(script); + } + + ResetAndApplyDefaultReferencesOnNewMonoBehaviour(*behaviour); + return behaviour->GetInstance(); +} + +ScriptingObjectPtr CreateScriptableObject(const std::string& name) +{ + MonoScript* script = GetMonoScriptManager().FindRuntimeScript(name); + +#if UNITY_EDITOR + if(script == NULL) + script = GetMonoScriptManager().FindEditorScript(name); +#endif + + if(script == NULL) + { + ErrorString(Format("Instance of %s couldn't be created because there is no script with that name.", name.c_str())); + return SCRIPTING_NULL; + } + + if( + script->GetScriptType() != kScriptTypeScriptableObjectDerived +#if UNITY_EDITOR + && script->GetScriptType() != kScriptTypeEditorScriptableObjectDerived +#endif + ) + { + ErrorString(Format("Instance of %s couldn't be created. The the script class needs to derive from ScriptableObject.", name.c_str())); + return SCRIPTING_NULL; + } + + if(script->GetClass() == SCRIPTING_NULL) + { + ErrorString(Format("Instance of %s couldn't be created. All script needs to successfully compile first!", name.c_str())); + return SCRIPTING_NULL; + } + + MonoBehaviour* behaviour = NEW_OBJECT(MonoBehaviour); + behaviour->SetScript(script); + + ResetAndApplyDefaultReferencesOnNewMonoBehaviour(*behaviour); + + return behaviour->GetInstance(); +} + +void CreateEngineScriptableObject(ScriptingObjectPtr object) +{ + // Avoid recursive loop. This object is already created from c++ + + if(GetInstanceIDFromScriptingWrapper(object) != 0) + return; + + SCRIPTINGAPI_THREAD_CHECK(ScriptableObject.ctor); + + ScriptingClassPtr klass = scripting_object_get_class(object, GetScriptingTypeRegistry()); + + const char *classNamespace = scripting_class_get_namespace(klass); + const char *className = scripting_class_get_name(klass); + + WarningStringMsg("%s%s%s must be instantiated using the ScriptableObject.CreateInstance method instead of new %s.", classNamespace, (classNamespace[0] ? "." : ""), className, className); + + MonoScript* script = FindScriptableObjectFromClass(klass); + if(script == NULL) + return; + + MonoBehaviour* behaviour = NEW_OBJECT(MonoBehaviour); + behaviour->SetScript(script, object); + +#if UNITY_EDITOR + if(script->GetScriptType() == kScriptTypeEditorScriptableObjectDerived) + behaviour->SetEditorHideFlags (MonoBehaviour::kHideScriptPPtr); +#endif + + ResetAndApplyDefaultReferencesOnNewMonoBehaviour(*behaviour); +} + +ScriptingObjectPtr GetScriptingWrapperForInstanceID(int instanceID) +{ + if(instanceID == 0) + return SCRIPTING_NULL; + + Object* object2 = PPtr<Object>(instanceID); + return ScriptingWrapperFor(object2); +} + +int GetClassIDFromScriptingClass(ScriptingClassPtr klass) +{ + int classID = 0; + + // Look up this classes classID + ScriptingClassPtr curClass = klass; + + const char* className = scripting_class_get_name(curClass); + const char* nameSpace = scripting_class_get_namespace(curClass); + const char* kEngineNameSpace = "UnityEngine"; + + if(strcmp(nameSpace, kEngineNameSpace) == 0) + { + if(strcmp(className, "ScriptableObject") == 0) + className = "MonoBehaviour"; + + classID = Object::StringToClassID(className); + if(classID != -1) + return classID; + } + + // It is not an engine class so check the parents + classID = -1; + + ScriptingClassPtr parentClass = scripting_class_get_parent(klass, GetScriptingTypeRegistry()); + if(parentClass) + classID = GetClassIDFromScriptingClass(parentClass); + + return classID; +} + +ScriptingTypePtr ClassIDToScriptingType(int classID) +{ + return GetScriptingManager().ClassIDToScriptingClass(classID); +} + +ScriptingObjectPtr GetScriptingWrapperOfComponentOfGameObject (GameObject& go, const std::string& name) +{ + int classID = Object::StringToClassID(name); + if (classID != -1 && Object::IsDerivedFromClassID(classID, ClassID(Component))) + { + Unity::Component* component = go.QueryComponentT<Unity::Component> (classID); + +#if MONO_QUALITY_ERRORS + if (component == NULL) + return MonoObjectNULL (classID, MissingComponentString(go, classID)); +#endif + return ScriptingWrapperFor (component); + } + + MonoScript* script = GetMonoScriptManager().FindRuntimeScript(name); + if (script == NULL) + { + +#if MONO_QUALITY_ERRORS + if (classID != -1) + ScriptWarning(Format("GetComponent requires that the requested component inherits from Component or MonoBehaviour.\nYou used GetComponent(%s) which does not inherit from Component.\n", name.c_str()), &go); +#endif + + return SCRIPTING_NULL; + } + + ScriptingTypePtr compareKlass = script->GetClass(); + if (compareKlass == SCRIPTING_NULL) + return SCRIPTING_NULL; + + int count = go.GetComponentCount (); + for (int i=0;i<count;i++) + { + // We are looking only for MonoBehaviours + int clsID = go.GetComponentClassIDAtIndex (i); + if (!Object::IsDerivedFromClassID (clsID, ClassID (MonoBehaviour))) + continue; + + MonoBehaviour& behaviour = static_cast<MonoBehaviour&> (go.GetComponentAtIndex (i)); + ScriptingObjectPtr object = behaviour.GetInstance (); + + if(!object) + continue; + + ScriptingTypePtr klass = scripting_object_get_class(object, GetScriptingTypeRegistry()); + if (scripting_class_is_subclass_of(klass, compareKlass)) + return object; + } + + return SCRIPTING_NULL; +} + +void LogException(ScriptingExceptionPtr exception, int instanceID, const std::string& error) +{ + StackTraceInfo info; + + scripting_stack_trace_info_for(exception, info); + + if (!error.empty()) + info.condition = error + info.condition; + + DebugStringToFilePostprocessedStacktrace(info.condition.c_str(), info.strippedStacktrace.c_str(), info.stacktrace.c_str(), info.errorNum, info.file.c_str(), info.line, kLog | kScriptingError | kScriptingException, instanceID, 0); +} + +static ScriptingArrayPtr CreateScriptingArrayFromScriptingObjects(ScriptingObjectPtr* objects, int size, ScriptingClassPtr typeForArray) +{ + // copy into array + ScriptingArrayPtr array = CreateScriptingArray<ScriptingObjectPtr> (typeForArray, size); + for (int i = 0; i < size; i++) + { + Scripting::SetScriptingArrayElement (array, i, objects[i]); + } + + return array; +} + +static bool IsActiveSceneObject (Object& o) +{ + if (o.IsPersistent ()) + return false; + + GameObject* go = dynamic_pptr_cast<GameObject*> (&o); + if (go) + return go->IsActive (); + + Unity::Component* com = dynamic_pptr_cast<Unity::Component*> (&o); + if (com) + { + MonoBehaviour* behaviour = dynamic_pptr_cast<MonoBehaviour*> (&o); + if (behaviour) + { + MonoScript* script = behaviour->GetScript(); + if (script && script->GetScriptType () == kScriptTypeScriptableObjectDerived) + return true; + else + return com->IsActive (); + } + else + return com->IsActive (); + } + + return true; +} + +ScriptingArrayPtr FindObjectsOfType(ScriptingObjectPtr systemTypeInstance, FindMode mode) +{ + ScriptingClassPtr compareKlass = GetScriptingTypeRegistry().GetType(systemTypeInstance); + + if(compareKlass == SCRIPTING_NULL) + { + ErrorString("FindAllObjectsOfType: Invalid Type"); + return SCRIPTING_NULL; + } + + int classID = GetClassIDFromScriptingClass(compareKlass); + if(classID == -1) + { + string klassName = scripting_class_get_name(compareKlass); + ErrorString("FindAllObjectsOfType: The type has to be derived from UnityEngine.Object. Type is " + klassName + "."); + return SCRIPTING_NULL; + } + + // Gather the derived objects + vector<SInt32> objects; + Object::FindAllDerivedObjects(classID, &objects); + + std::sort(objects.begin(), objects.end()); + + // We might need to ignore some objects which are not derived from the mono class but from MonoBehaviour + // so we store them in a buffer and then copy them into the mono array + + ScriptingObjectPtr* scriptingObjects; + +#if UNITY_WINRT + scriptingObjects = new ScriptingObjectPtr[objects.size ()]; +#else + ALLOC_TEMP(scriptingObjects, ScriptingObjectPtr, objects.size ()); +#endif + + int count = 0; + for(int i = 0;i < objects.size (); i++) + { + Object& object = *PPtr<Object>(objects[i]); + if(object.TestHideFlag (Object::kDontSave) && mode != Scripting::kFindAnything) + continue; + + if(mode == Scripting::kFindActiveSceneObjects && !IsActiveSceneObject (object)) + continue; + + ScriptingObjectPtr mono = ScriptingWrapperFor(&object); //Todo: this used to call ObjectToScriptingObject, but that + //hit a bug in the alchemy compiler + if(mono) + { + // Cubemap is derived from Texture2D in serialization, but not in Scripting + if (object.IsDerivedFrom (ClassID (MonoBehaviour)) || object.IsDerivedFrom (ClassID (Cubemap))) + { + ScriptingClassPtr klass = scripting_object_get_class (mono, GetScriptingTypeRegistry()); + if (scripting_class_is_subclass_of (klass, compareKlass)) + scriptingObjects[count++] = mono; + } + else + { + scriptingObjects[count++] = mono; + } + } + } + + ScriptingArrayPtr result = CreateScriptingArrayFromScriptingObjects(scriptingObjects,count,compareKlass); + +#if UNITY_WINRT + delete[]scriptingObjects; +#endif + + return result; +} + +ScriptingObjectPtr TrackedReferenceBaseToScriptingObjectImpl (TrackedReferenceBase* base, ScriptingClassPtr klass) +{ + if (base) + { + // In the editor a weak reference (for example animation state) + // might get leaked when reloading domains while in playmode + // in that case we just recycle it + #if UNITY_EDITOR + if (base->m_MonoObjectReference != 0 && !mono_gchandle_is_in_domain(base->m_MonoObjectReference, mono_domain_get())) + { + mono_gchandle_free(base->m_MonoObjectReference); + base->m_MonoObjectReference = 0; + } + #endif +#if ENABLE_MONO && !UNITY_PEPPER + AssertIf(base->m_MonoObjectReference != 0 && !mono_gchandle_is_in_domain(base->m_MonoObjectReference, mono_domain_get())); +#endif + + // Get cached mono object reference + ScriptingObjectPtr target = SCRIPTING_NULL; + if (base->m_MonoObjectReference != 0) + { + target = scripting_gchandle_get_target (base->m_MonoObjectReference); + if (target) + return target; + + AssertString("This should never happen"); + + scripting_gchandle_free(base->m_MonoObjectReference); + base->m_MonoObjectReference = 0; + } + + ScriptingObjectWithIntPtrField<TrackedReferenceBase> newTarget(scripting_object_new(klass)); + + base->m_MonoObjectReference = scripting_gchandle_new(newTarget.object); + newTarget.SetPtr(base); + + return newTarget.object; + } + else + { +#if DEPLOY_OPTIMIZED + return SCRIPTING_NULL; +#else + ScriptingObjectPtr object = scripting_object_new (klass); + void* nativePointer = 0; + MarshallNativeStructIntoManaged(nativePointer,object); + return object; +#endif + } +} + +template <class StringType> +ScriptingArrayPtr StringVectorToMono (const std::vector<StringType>& source) +{ + ScriptingArrayPtr arr = CreateScriptingArray<ScriptingObjectPtr>(MONO_COMMON.string, source.size()); + for (int i = 0; i < source.size();i++) + { + Scripting::SetScriptingArrayElement(arr, i, scripting_string_new(source[i])); + } + return arr; +} + +template ScriptingArrayPtr StringVectorToMono (const std::vector<std::string>& source); +template ScriptingArrayPtr StringVectorToMono (const std::vector<UnityStr>& source); + +ScriptingObjectPtr GetComponentObjectToScriptingObject(Unity::Component* com, Unity::GameObject& go, int classID) +{ + +#if MONO_QUALITY_ERRORS + if(com == NULL) + return MonoObjectNULL(classID, MissingComponentString(go, classID)); +#endif + + return ScriptingWrapperFor(com); +} + +ScriptingObjectPtr GetComponentObjectToScriptingObject(Object* com, Unity::GameObject& go, int classID) +{ + return ScriptingWrapperFor(com); +} + +} // namespace Scripting diff --git a/Runtime/Scripting/Scripting.h b/Runtime/Scripting/Scripting.h new file mode 100644 index 0000000..bdcdc91 --- /dev/null +++ b/Runtime/Scripting/Scripting.h @@ -0,0 +1,197 @@ +#pragma once + +#include "UnityPrefix.h" + +#include "Runtime/Modules/ExportModules.h" + +#include "Runtime/Scripting/Backend/ScriptingTypes.h" +#include "Runtime/Scripting/Backend/ScriptingBackendApi.h" + +#define SCRIPTINGAPI_STACK_CHECK(NAME) + +#if WEBPLUG +# undef DOES_NOT_RETURN +# define DOES_NOT_RETURN +#endif + +class Object; +class TrackedReferenceBase; + +namespace Unity +{ + class GameObject; + class Component; +} + +template<typename T> +class PPtr; + + +namespace Scripting +{ +ScriptingObjectPtr ScriptingObjectNULL(ScriptingClassPtr klass); +ScriptingObjectPtr ScriptingObjectNULL(ScriptingClassPtr klass, ScriptingStringPtr error); + +//Exception helpers, we'll need to move this again, later. +DOES_NOT_RETURN TAKES_PRINTF_ARGS(1,2) void RaiseMonoException(const char* format, ...); +DOES_NOT_RETURN TAKES_PRINTF_ARGS(1,2) EXPORT_COREMODULE void RaiseNullException(const char* format, ...); +DOES_NOT_RETURN TAKES_PRINTF_ARGS(1,2) EXPORT_COREMODULE void RaiseArgumentException(const char* format, ...); +DOES_NOT_RETURN TAKES_PRINTF_ARGS(1,2) void RaiseOutOfRangeException(const char* format, ...); +DOES_NOT_RETURN TAKES_PRINTF_ARGS(1,2) void RaiseSecurityException(const char* format, ...); +DOES_NOT_RETURN TAKES_PRINTF_ARGS(1,2) void RaiseInvalidOperationException(const char* format, ...); +DOES_NOT_RETURN TAKES_PRINTF_ARGS(3,4) void RaiseManagedException(const char* ns, const char* type, const char* format, ...); +DOES_NOT_RETURN EXPORT_COREMODULE void RaiseNullExceptionObject(ScriptingObjectPtr object); + +void RaiseIfNull(void* object); +void RaiseIfNull(ScriptingObjectPtr object); + +EXPORT_COREMODULE int GetInstanceIDFromScriptingWrapper(ScriptingObjectPtr wrapper); +EXPORT_COREMODULE void SetInstanceIDOnScriptingWrapper(ScriptingObjectPtr wrapper, int instanceID); +EXPORT_COREMODULE void* GetCachedPtrFromScriptingWrapper(ScriptingObjectPtr wrapper); +EXPORT_COREMODULE void SetCachedPtrOnScriptingWrapper(ScriptingObjectPtr wrapper, void* cachedPtr); +void SetErrorOnScriptingWrapper(ScriptingObjectPtr wrapper, ScriptingStringPtr error); + +ScriptingTypePtr ClassIDToScriptingType(int classiD); +ScriptingObjectPtr InstantiateScriptingWrapperForClassID(int classID); +ScriptingObjectPtr ConnectScriptingWrapperToObject(ScriptingObjectPtr object, Object* ptr); + +/**These don't belong here either**/ +bool SendScriptingMessage(Unity::GameObject& go, const char* name, ScriptingObjectPtr param); +bool BroadcastScriptingMessage(Unity::GameObject& go, const char* name, ScriptingObjectPtr param); +bool SendScriptingMessageUpwards(Unity::GameObject& go, const char* name, ScriptingObjectPtr param); +bool SendScriptingMessage(Unity::GameObject& go, const std::string& name, ScriptingObjectPtr param, int options); +bool BroadcastScriptingMessage(Unity::GameObject& go, const std::string& name, ScriptingObjectPtr param, int options); +bool SendScriptingMessageUpwards(Unity::GameObject& go, const std::string& name, ScriptingObjectPtr param, int options); +/** end **/ + +void DestroyObjectFromScripting(PPtr<Object> object, float t); +void DestroyObjectFromScriptingImmediate(Object* object, bool allowDestroyingAssets); +void UnloadAssetFromScripting(Object* object); + +ScriptingObjectPtr GetScriptingWrapperOfComponentOfGameObject (Unity::GameObject& go, const std::string& name); + +ScriptingObjectPtr GetScriptingWrapperForInstanceID(int instanceID); +ScriptingObjectPtr CreateScriptableObject(const std::string& name); +ScriptingObjectPtr CreateScriptableObjectWithType(ScriptingObjectPtr klassType); +void CreateEngineScriptableObject(ScriptingObjectPtr object); +int GetClassIDFromScriptingClass(ScriptingClassPtr klass); + +bool CompareBaseObjects(ScriptingObjectPtr lhs, ScriptingObjectPtr rhs); + +ScriptingObjectPtr EXPORT_COREMODULE ScriptingWrapperFor(Object* object); + +void LogException(ScriptingExceptionPtr exception, int instanceID, const std::string& error = std::string()); + +enum FindMode +{ + kFindAssets = 0, + kFindActiveSceneObjects = 1, + kFindAnything = 2 +}; + +ScriptingArrayPtr FindObjectsOfType(ScriptingObjectPtr reflectionTypeObject, FindMode mode); + +ScriptingObjectPtr GetComponentObjectToScriptingObject(Unity::Component* com, Unity::GameObject& go, int classID); +ScriptingObjectPtr GetComponentObjectToScriptingObject(Object* com, Unity::GameObject& go, int classID); + +//RH / GAB : Discuss with Joe what to do with this +/// Creates a MonoObject +/// object is a ptr to a RefCounted class. +/// type is the name MonoManager common classes +/// eg. animationState -> GetScriptingManager().GetCommonClasses().animationStates +#define TrackedReferenceBaseToScriptingObject(object, type) \ + Scripting::TrackedReferenceBaseToScriptingObjectImpl(object, GetScriptingManager().GetCommonClasses().type) + +ScriptingObjectPtr TrackedReferenceBaseToScriptingObjectImpl(TrackedReferenceBase* base, ScriptingClassPtr klass); + +template <class StringType> +ScriptingArrayPtr StringVectorToMono (const std::vector<StringType>& source); + +// Array handling + +void SetScriptingArrayObjectElementImpl(ScriptingArrayPtr a, int i, ScriptingObjectPtr value); +void SetScriptingArrayStringElementImpl(ScriptingArrayPtr a, int i, ScriptingStringPtr value); +ScriptingStringPtr* GetScriptingArrayStringElementImpl(ScriptingArrayPtr a, int i); +ScriptingObjectPtr* GetScriptingArrayObjectElementImpl(ScriptingArrayPtr a, int i); +ScriptingStringPtr* GetScriptingArrayStringStartImpl(ScriptingArrayPtr a); +ScriptingObjectPtr* GetScriptingArrayObjectStartImpl(ScriptingArrayPtr a); +ScriptingStringPtr GetScriptingArrayStringElementNoRefImpl(ScriptingArrayPtr a, int i); +ScriptingObjectPtr GetScriptingArrayObjectElementNoRefImpl(ScriptingArrayPtr a, int i); + +template<class T> +inline void SetScriptingArrayElement(ScriptingArrayPtr array, int i, T value) +{ + void* raw = scripting_array_element_ptr(array, i, sizeof(T)); + *(T*)raw = value; +} + +template<> +inline void SetScriptingArrayElement (ScriptingArrayPtr a, int i, ScriptingObjectPtr value) +{ + SetScriptingArrayObjectElementImpl(a, i, value); +} + +template<> +inline void SetScriptingArrayElement (ScriptingArrayPtr a, int i, ScriptingStringPtr value) +{ + SetScriptingArrayStringElementImpl(a, i, value); +} + + +template<class T> +inline T* GetScriptingArrayStart(ScriptingArrayPtr array) +{ + return (T*)scripting_array_element_ptr(array, 0, sizeof(T)); +} + +template<> +inline ScriptingStringPtr* GetScriptingArrayStart(ScriptingArrayPtr a) +{ + return GetScriptingArrayStringStartImpl(a); +} + +template<> +inline ScriptingObjectPtr* GetScriptingArrayStart(ScriptingArrayPtr a) +{ + return GetScriptingArrayObjectStartImpl(a); +} + + +template<class T> +inline T& GetScriptingArrayElement(ScriptingArrayPtr a, int i) +{ + return *((T*)scripting_array_element_ptr(a, i, sizeof(T))); +} + +template<> +inline ScriptingStringPtr& GetScriptingArrayElement(ScriptingArrayPtr a, int i) +{ + return *GetScriptingArrayStringElementImpl(a, i); +} + +template<> +inline ScriptingObjectPtr& GetScriptingArrayElement(ScriptingArrayPtr a, int i) +{ + return *GetScriptingArrayObjectElementImpl(a, i); +} + + +template<class T> +inline T GetScriptingArrayElementNoRef(ScriptingArrayPtr a, int i) +{ + return *((T*)scripting_array_element_ptr(a, i, sizeof(T))); +} + +template<> +inline ScriptingStringPtr GetScriptingArrayElementNoRef(ScriptingArrayPtr a, int i) +{ + return GetScriptingArrayStringElementNoRefImpl(a, i); +} + +template<> +inline ScriptingObjectPtr GetScriptingArrayElementNoRef(ScriptingArrayPtr a, int i) +{ + return GetScriptingArrayObjectElementNoRefImpl(a, i); +} + +}//namespace Scripting
\ No newline at end of file diff --git a/Runtime/Scripting/ScriptingExportUtility.h b/Runtime/Scripting/ScriptingExportUtility.h new file mode 100644 index 0000000..3061cfb --- /dev/null +++ b/Runtime/Scripting/ScriptingExportUtility.h @@ -0,0 +1,265 @@ +#ifndef _SCRIPTINGEXPORTUTILITY_H_ +#define _SCRIPTINGEXPORTUTILITY_H_ + +#if ENABLE_SCRIPTING + +#include "Runtime/Scripting/ScriptingManager.h" +#include "Runtime/Scripting/ScriptingUtility.h" +#include "Runtime/Scripting/ICallString.h" +#include "Runtime/Scripting/Scripting.h" + + +template<class T> +inline +ScriptingArrayPtr CreateScriptingArray (ScriptingClassPtr klass, int count) +{ +#if ENABLE_MONO + //here to force template argument being used on caller, so the callsite will be compatible + //with the flash version of CreateScriptingArray, which actually needs to know what will be in the array beforehand. + //TODO: find a cleaner way of enforcing usage: +# if DEBUGMODE + int nativeSize = sizeof(T); + int monoSize = mono_class_array_element_size(klass); + DebugAssert(nativeSize == monoSize || !count); + (void)monoSize; // silence unused variable warning + nativeSize++; +# endif + return mono_array_new(mono_domain_get(),klass,count); + +#elif UNITY_FLASH + UInt8* memoryblob = (UInt8*) malloc(sizeof(T) * count + sizeof(int)); + *(int*)memoryblob = count; + return (ScriptingArrayPtr) memoryblob; +#elif UNITY_WINRT + return ScriptingArrayPtr(GetWinRTObjectInstantiation()->CreateScriptingArrayGC(klass->metroType, count)); +#endif +} + +template<class T> +inline +ScriptingArrayPtr CreateScriptingArray2D (ScriptingClassPtr klass, int count1, int count2) +{ +#if ENABLE_MONO + return mono_array_new_2d (count1, count2, klass); +#elif UNITY_FLASH + FatalErrorMsg("ToDo:CreateScriptingArray2D"); +#elif UNITY_WINRT + return ScriptingArrayPtr(GetWinRTObjectInstantiation()->CreateScriptingArray2DGC(klass->metroType, count1, count2)); +#endif +} +template<class T> +inline +ScriptingArrayPtr CreateScriptingArray3D (ScriptingClassPtr klass, int count1, int count2, int count3) +{ +#if ENABLE_MONO + return mono_array_new_3d (count1, count2, count3, klass); +#elif UNITY_FLASH + FatalErrorMsg("ToDo:CreateScriptingArray3D"); +#elif UNITY_WINRT + return ScriptingArrayPtr(GetWinRTObjectInstantiation()->CreateScriptingArray3DGC(klass->metroType, count1, count2, count3)); +#endif +} + + +inline +ScriptingArrayPtr CreateEmptyStructArray (ScriptingClassPtr klass) +{ + return CreateScriptingArray<int>(klass,0); //using int as random template argument, as it doesn't matter, since size=0 +} + +template<class T> +inline +ScriptingArrayPtr CreateScriptingArray (const T* data, int count, ScriptingClassPtr klass) +{ + if (data == NULL) + count = 0; + + ScriptingArrayPtr array = CreateScriptingArray<T>(klass,count); + memcpy(Scripting::GetScriptingArrayStart<T>(array), data, sizeof(T) * count ); + return array; +} + +template<class T> +ScriptingArrayPtr CreateScriptingArrayFromUnityObjects (const T& container, int classID) +{ + ScriptingClassPtr klass = GetScriptingManager().ClassIDToScriptingClass (classID); + + ScriptingArrayPtr array = CreateScriptingArray<ScriptingObjectPtr>(klass,container.size()); + typename T::const_iterator j = container.begin(); + for (int i=0;i<container.size();i++, j++) + { + Scripting::SetScriptingArrayElement(array,i, Scripting::ScriptingWrapperFor(*j)); + } + return array; +} + +template<class T > inline +ScriptingArrayPtr CreateScriptingArrayFromUnityObjects(T& unityobjects,ScriptingClassPtr classForArray) +{ + ScriptingArrayPtr array = CreateScriptingArray<ScriptingObjectPtr> (classForArray , unityobjects.size ()); + for (int i=0;i<unityobjects.size ();i++) + Scripting::SetScriptingArrayElement (array, i, Scripting::ScriptingWrapperFor (unityobjects[i])); + return array; +} + +template<class T> +inline +ScriptingArrayPtr CreateScriptingArrayStride (const void* data, int count, ScriptingClassPtr klass, int inputStride) +{ + if (data == NULL) + count = 0; + + ScriptingArrayPtr array = CreateScriptingArray<T> (klass, count); + UInt8* src = (UInt8*)data; + UInt8* dst = (UInt8*)Scripting::GetScriptingArrayStart<T> (array); + for (int i=0; i<count; ++i, src += inputStride, dst += sizeof(T)) + memcpy(dst, src, sizeof(T)); + + return array; +} + +template<class T, class T2, class U, class TConverter> +void ScriptingStructArrayToVector (ScriptingArrayPtr source, U &dest, TConverter converter) +{ + dest.clear(); + if (source != SCRIPTING_NULL) + { + int len = GetScriptingArraySize(source); + dest.resize (len); + for (int i = 0; i < len;i++) + converter (Scripting::GetScriptingArrayElement<T2>(source, i), dest[i]); + } +} + +template<class T, class T2, class U, class TConverter> +void ScriptingStructArrayToDynamicArray (ScriptingArrayPtr source, U &dest, TConverter converter) +{ + dest.clear(); + if (source != SCRIPTING_NULL) + { + int len = GetScriptingArraySize(source); + dest.resize_initialized (len); + for (int i = 0; i < len;i++) + converter (Scripting::GetScriptingArrayElement<T2>(source, i), dest[i]); + } +} + +template<class T, class T2, class U> +void ScriptingClassArrayToVector (ScriptingArrayPtr source, U &dest, void (*converter) (T2 &source, T &dest)) +{ + dest.clear(); + if (source != SCRIPTING_NULL) + { + int len = GetScriptingArraySize(source); + dest.resize (len); + for (int i = 0; i < len;i++) + { + T2 nativeSourceObject; + ScriptingObjectPtr element = Scripting::GetScriptingArrayElementNoRef<ScriptingObjectPtr>(source, i); + Scripting::RaiseIfNull(element); + MarshallManagedStructIntoNative<T2>(element, &nativeSourceObject); + converter (nativeSourceObject, dest[i]); + } + } +} + +template<class T, class T2> +std::vector<T> ScriptingClassArrayToVector (ScriptingArrayPtr source, void (*converter) (T2 &source, T &dest)) +{ + std::vector<T> dest; + ScriptingClassArrayToVector (source, dest, converter); + return dest; +} + + +template<class T, class T2, class U> +ScriptingArrayPtr VectorToScriptingClassArray (const U &source, ScriptingClassPtr klass, void (*converter) (const T &source, T2 &dest)) +{ + // ToDo: if all good, remove mono pass, and use unified pass +#if ENABLE_MONO + return VectorToMonoClassArray<T, T2>(source, klass, converter); +#else + ScriptingArrayPtr arr = CreateScriptingArray<ScriptingObjectPtr>(klass, source.size()); + for (int i = 0; i < source.size();i++) + { + T2 obj; + converter (source[i], obj); + ScriptingObjectPtr managedObject = CreateScriptingObjectFromNativeStruct(klass, obj); + Scripting::SetScriptingArrayElement(arr, i, managedObject); + } + return arr; +#endif +} + +template<class T, class T2, class U, class TConverter> +ScriptingArrayPtr VectorToScriptingStructArray (const U &source, ScriptingClassPtr klass, TConverter converter) +{ + // ToDo: if all good, remove mono pass, and use unified pass +#if ENABLE_MONO + return VectorToMonoStructArray<T, T2>(source, klass, converter); +#else + ScriptingArrayPtr arr = CreateScriptingArray<ScriptingObjectPtr>(klass, source.size()); + for (int i = 0; i < source.size();i++) + { + T2 obj; + converter (source[i], obj); + Scripting::SetScriptingArrayElement(arr, i, obj); + } + return arr; +#endif +} + + +template<class T> +void ScriptingArrayToDynamicArray(ScriptingArrayPtr a, dynamic_array<T>& dest) +{ + Scripting::RaiseIfNull (a); + int len = GetScriptingArraySize(a); + dest.resize_uninitialized (len); + for (int i = 0; i < len; i++) + dest[i] = Scripting::GetScriptingArrayElement<T>(a, i); +} + +template<class T, class T2> +void ScriptingArrayToDynamicArray(ScriptingArrayPtr a, dynamic_array<T>& dest, void (*converter) (T2 &source, T &dest)) +{ + Scripting::RaiseIfNull (a); + int len = GetScriptingArraySize(a); + dest.resize_uninitialized (len); + for (int i = 0; i < len; i++) + converter (Scripting::GetScriptingArrayElement<T2> (a, i), dest[i]); +} + +template<class T, class T2> +ScriptingArrayPtr DynamicArrayToScriptingStructArray (const dynamic_array<T> &source, ScriptingClassPtr klass, void (*converter) (const T &source, T2 &dest)) { + ScriptingArrayPtr arr = CreateScriptingArray<T2> (klass, source.size()); + for (int i = 0; i < source.size();i++) + converter (source[i], Scripting::GetScriptingArrayElement<T2> (arr, i)); + return arr; +} + +inline +std::string GetStringFromArray(ScriptingArrayPtr a, int i) +{ +#if UNITY_WINRT + return ConvertStringToUtf8(safe_cast<Platform::String^>(Scripting::GetScriptingArrayStringElementNoRefImpl(a, i))); +#elif UNITY_FLASH + // not supported yet + return ""; +#else + return MonoStringToCpp(Scripting::GetScriptingArrayStringElementNoRefImpl(a, i)); +#endif +} + +inline +bool GetBoolFromArray(ScriptingArrayPtr a, int i) +{ +#if UNITY_WINRT + return safe_cast<Platform::Boolean>(Scripting::GetScriptingArrayObjectElementNoRefImpl(a, i)); +#else + return Scripting::GetScriptingArrayObjectElementNoRefImpl(a, i); +#endif +} + +#endif +#endif diff --git a/Runtime/Scripting/ScriptingManager.cpp b/Runtime/Scripting/ScriptingManager.cpp new file mode 100644 index 0000000..5dcfd5c --- /dev/null +++ b/Runtime/Scripting/ScriptingManager.cpp @@ -0,0 +1,150 @@ +#include "UnityPrefix.h" +#if ENABLE_SCRIPTING +#include "Runtime/Scripting/ScriptingManager.h" +#include "Runtime/BaseClasses/ManagerContext.h" +#include <vector> +#include <stdlib.h> +#include "Runtime/Scripting/ScriptingUtility.h" +#include "Runtime/IMGUI/GUIState.h" +#include "Runtime/Scripting/Backend/ScriptingMethodFactory.h" +#include "Runtime/Scripting/Backend/ScriptingMethodRegistry.h" +#include "Runtime/Scripting/Backend/ScriptingTypeRegistry.h" +#include "Runtime/Scripting/Backend/ScriptingBackendApi.h" + +const char* kEngineNameSpace = "UnityEngine"; +const char* kEditorNameSpace = "UnityEditor"; +const char* kEditorInternalNameSpace = "UnityEditorInternal"; + +ScriptingClassPtr gClassIDToClass = SCRIPTING_NULL; + +using namespace std; + +ScriptingManager::ScriptingManager (MemLabelId label, ObjectCreationMode mode, IScriptingTypeProvider* scriptingTypeProvider, IScriptingMethodFactory* scriptingMethodFactory) + : GlobalGameManager(label, mode) +{ + m_ScriptingMethodFactory = scriptingMethodFactory; + m_ScriptingTypeRegistry = UNITY_NEW(ScriptingTypeRegistry(scriptingTypeProvider), kMemManager); + m_ScriptingMethodRegistry = UNITY_NEW(ScriptingMethodRegistry(scriptingMethodFactory, m_ScriptingTypeRegistry), kMemManager); + + //Registering ourselves as the monomanager manually, so that during the execution of the constructor GetMonoManager() will work. + SetManagerPtrInContext(ManagerContext::kMonoManager, this); +} + +ScriptingManager::~ScriptingManager () +{ + UNITY_DELETE(m_ScriptingTypeRegistry, kMemManager); + UNITY_DELETE(m_ScriptingMethodRegistry, kMemManager); + + UNITY_DELETE(m_ScriptingMethodFactory, kMemManager); +} + +static ScriptingClassPtr FindScriptingClassForClassID(int classID, ScriptingClassPtr baseObject) +{ + const char* className_c; +#if UNITY_FLASH + if(classID == ClassID(Object)) + className_c = "_Object"; + else +#endif + className_c = Object::ClassIDToString (classID).c_str(); + + // Found a class? + // Also make sure it derives from object otherwise it's not valid (Eg. RenderSettings only has public accessors and doesn't inherit from Object) + + ScriptingTypeRegistry& typeRegistry = GetScriptingManager().GetScriptingTypeRegistry(); + + ScriptingTypePtr result = typeRegistry.GetType(kEngineNameSpace,className_c); + +#if UNITY_EDITOR + if (result== SCRIPTING_NULL) + result = typeRegistry.GetType (kEditorNameSpace, className_c); + if (result == SCRIPTING_NULL) + result = typeRegistry.GetType (kEditorInternalNameSpace, className_c); +#endif + + if (result != SCRIPTING_NULL && scripting_class_is_subclass_of (result, baseObject)) + return result; + + return SCRIPTING_NULL; +} + + +static ScriptingClassPtr FindScriptingClassForClassIDRecursive (int classID, ScriptingClassPtr baseObject) +{ + ScriptingClassPtr result = FindScriptingClassForClassID(classID,baseObject); + + if (result != SCRIPTING_NULL) + return result; + + if (classID == ClassID (Object)) + return SCRIPTING_NULL; + + return FindScriptingClassForClassIDRecursive (Object::GetSuperClassID (classID),baseObject); +} + +void ScriptingManager::RebuildClassIDToScriptingClass () +{ +#if ENABLE_SCRIPTING + // Collect all engine classes + vector<SInt32> allEngineClasses; + Object::FindAllDerivedClasses (ClassID (Object), &allEngineClasses, false); + + // Resize lookup table to fit all engine classes + SInt32 highest = 0; + for (int i=0;i<allEngineClasses.size ();i++) + highest = max (allEngineClasses[i], highest); + m_ClassIDToMonoClass.clear (); + m_ClassIDToMonoClass.resize (highest +1, SCRIPTING_NULL); + gClassIDToClass = m_ClassIDToMonoClass[0]; + + m_ScriptingClassToClassID.clear(); + // Get the mono class from the classID by looking up the mono class by name + // if a mono class can't be found check the super classes recursively + ScriptingClassPtr baseObject = GetScriptingTypeRegistry().GetType("UnityEngine","Object"); + for (int i=0;i<allEngineClasses.size ();i++) + { + int classID = allEngineClasses[i]; + + ScriptingClassPtr klass = FindScriptingClassForClassIDRecursive (classID,baseObject); + AssertIf(klass == SCRIPTING_NULL); + m_ClassIDToMonoClass[classID] = klass; + + //search again, but without searching basetypes. we need to do this because some enginetypes have no managed wrapper. (EllipsoidParticleEmitter), + //so they can return the baseclass type. we want that for m_ClassIDToMonoClass but we do not want that for m_ScriptingClassToClassID. + + klass = FindScriptingClassForClassID (classID,baseObject); + if (klass) + m_ScriptingClassToClassID[klass] = classID; + } +#endif +} + +ScriptingClassPtr ScriptingManager::ClassIDToScriptingClass (int classID) +{ + AssertIf (classID == -1); + AssertIf (m_ClassIDToMonoClass.size () <= classID); + return m_ClassIDToMonoClass[classID]; +} + +int ScriptingManager::ClassIDForScriptingClass (ScriptingClassPtr klass) +{ + ScriptingClassMap::iterator iterator = m_ScriptingClassToClassID.find(klass); + if (iterator == m_ScriptingClassToClassID.end()) + return -1; + + return iterator->second; +} + +ScriptingObjectPtr ScriptingManager::CreateInstance(ScriptingClassPtr klass) +{ + if (!klass) + return SCRIPTING_NULL; + + return scripting_object_new (klass); +} + +ScriptingManager& GetScriptingManager() +{ + return reinterpret_cast<ScriptingManager&> (GetManagerFromContext (ManagerContext::kMonoManager)); +} +#endif diff --git a/Runtime/Scripting/ScriptingManager.h b/Runtime/Scripting/ScriptingManager.h new file mode 100644 index 0000000..4c446f2 --- /dev/null +++ b/Runtime/Scripting/ScriptingManager.h @@ -0,0 +1,63 @@ +#ifndef _SCRIPTINGMANAGER_H_ +#define _SCRIPTINGMANAGER_H_ + +#if ENABLE_SCRIPTING + +#include "Runtime/BaseClasses/GameManager.h" +#include "Runtime/Mono/MonoScriptManager.h" +#include "Runtime/Scripting/CommonScriptingClasses.h" +#include "Runtime/Utilities/vector_map.h" +#include "Runtime/Scripting/Backend/ScriptingMethodRegistry.h" +#include "Runtime/Modules/ExportModules.h" + +class IScriptingTypeProvider; +class ScriptingMethodRegistry; +class ScriptingTypeRegistry; +class IScriptingMethodFactory; + +extern const char* kEngineNameSpace; +extern const char* kEditorNameSpace; +extern ScriptingClassPtr gClassIDToClass; + +class EXPORT_COREMODULE ScriptingManager : public GlobalGameManager +{ +public: + MonoScriptManager& GetMonoScriptManager() { return m_MonoScriptManager; } + ScriptingMethodRegistry& GetScriptingMethodRegistry() { return *m_ScriptingMethodRegistry; } + ScriptingTypeRegistry& GetScriptingTypeRegistry() { return *m_ScriptingTypeRegistry; } + const CommonScriptingClasses& GetCommonClasses () { return m_CommonScriptingClasses; } + ScriptingClassPtr ClassIDToScriptingClass (int classID); + int ClassIDForScriptingClass(ScriptingClassPtr klass); + virtual void RebuildClassIDToScriptingClass (); + ScriptingObjectPtr CreateInstance(ScriptingClassPtr klass); + virtual bool IsTrustedToken (const std::string& /*publicKeyToken*/){ return false; } + + ~ScriptingManager(); +protected: + ScriptingManager (MemLabelId label, ObjectCreationMode mode, IScriptingTypeProvider* scriptingTypeProvider, IScriptingMethodFactory* scriptingMethodFactory); + + MonoScriptManager m_MonoScriptManager; + CommonScriptingClasses m_CommonScriptingClasses; + typedef std::vector<ScriptingTypePtr> ClassIDToMonoClass; + ClassIDToMonoClass m_ClassIDToMonoClass; + + typedef vector_map<ScriptingTypePtr, int> ScriptingClassMap; + ScriptingClassMap m_ScriptingClassToClassID; + + ScriptingMethodRegistry* m_ScriptingMethodRegistry; + ScriptingTypeRegistry* m_ScriptingTypeRegistry; + IScriptingMethodFactory* m_ScriptingMethodFactory; +}; + +EXPORT_COREMODULE ScriptingManager& GetScriptingManager (); + +inline MonoScriptManager& GetMonoScriptManager() { return GetScriptingManager().GetMonoScriptManager(); } + +inline ScriptingMethodRegistry& GetScriptingMethodRegistry() { return GetScriptingManager().GetScriptingMethodRegistry(); } +inline ScriptingTypeRegistry& GetScriptingTypeRegistry() { return GetScriptingManager().GetScriptingTypeRegistry(); } + +#define ScriptingClassFor(x) GetScriptingManager().ClassIDToScriptingClass(CLASS_##x) + +#endif + +#endif diff --git a/Runtime/Scripting/ScriptingObjectOfType.h b/Runtime/Scripting/ScriptingObjectOfType.h new file mode 100644 index 0000000..cca6bde --- /dev/null +++ b/Runtime/Scripting/ScriptingObjectOfType.h @@ -0,0 +1,142 @@ +#pragma once + +#include "Runtime/Scripting/Backend/ScriptingTypes.h" +#include "Scripting.h" +#include "ScriptingUtility.h"//We need to go back and remove this. + +template<class T> +struct ScriptingObjectOfType +{ +private: + ScriptingObjectPtr object; +public: + ScriptingObjectOfType(ScriptingObjectPtr object) + { + this->object = object; + } + + T& GetReference () const + { + T* ptr = GetPtr(); + + if (ptr != NULL) + return *ptr; + + Scripting::RaiseNullExceptionObject (object); + return *(T*)NULL; + } + + T* GetPtr () const + { + if (IsNullPtr()) + return NULL; + + void* cachedPtr = GetCachedPtr(); + if (cachedPtr != NULL) + { + AssertIf(reinterpret_cast<Object*> (cachedPtr)->GetInstanceID() != GetInstanceID()); + return (T*)cachedPtr; + } + + T* temp = dynamic_instanceID_cast<T*> (GetInstanceID()); + return temp; + } + + bool IsValidObjectReference () const + { + if (IsNullPtr()) + return false; + + void* cachedPtr = GetCachedPtr(); + if (cachedPtr != NULL) + { + AssertIf(reinterpret_cast<Object*> (cachedPtr)->GetInstanceID() != GetInstanceID()); + return (T*)cachedPtr; + } + + T* temp = dynamic_instanceID_cast<T*> (GetInstanceID()); + if (temp == NULL) + return false; + + // MonoBheaviours are only allowed to be the instance themselves (cached pointer) + // otherwise they are dangling references who happen to have the same instanceID. + // Thus not a valid reference. + if (temp->GetClassID() == ClassID(MonoBehaviour)) + return false; + + return true; + } + + + operator T* () const + { + return GetPtr (); + } + + operator PPtr<T> () const + { + if (IsNullPtr()) + return PPtr<T> (); + + return PPtr<T> (GetInstanceID()); + } + + T& operator * () const + { + return GetReference (); + } + + T* operator -> () const + { + return &GetReference (); + } + + bool IsNullPtr() const + { + return object == SCRIPTING_NULL; + } + + inline int GetInstanceID() const + { + return Scripting::GetInstanceIDFromScriptingWrapper(object); + } + + inline void SetCachedPtr (void* cachedPtr) + { + Scripting::SetCachedPtrOnScriptingWrapper(object, cachedPtr); + } + + inline void SetInstanceID (int instanceID) + { + Scripting::SetInstanceIDOnScriptingWrapper(object, instanceID); + } + + inline void* GetCachedPtr() const + { + return Scripting::GetCachedPtrFromScriptingWrapper(object); + } + + #if MONO_QUALITY_ERRORS + inline void SetError (ScriptingStringPtr error) + { + Scripting::SetErrorOnScriptingWrapper(object, error); + } + #endif + +#if UNITY_WINRT + ScriptingObjectOfType<T>& operator = (decltype(__nullptr)) + { + object = nullptr; + return *this; + } +#endif + + inline ScriptingObjectPtr GetScriptingObject() const + { + return object; + } +}; + + + + diff --git a/Runtime/Scripting/ScriptingObjectWithIntPtrField.h b/Runtime/Scripting/ScriptingObjectWithIntPtrField.h new file mode 100644 index 0000000..e4cbf99 --- /dev/null +++ b/Runtime/Scripting/ScriptingObjectWithIntPtrField.h @@ -0,0 +1,139 @@ +#pragma once + +#include "Runtime/Scripting/ScriptingUtility.h" + +#if 1 //!UNITY_WINRT +#if ENABLE_MONO +extern int* s_MonoDomainContainer; +#endif +template<class T> +struct ScriptingObjectWithIntPtrField +{ + ScriptingObjectPtr object; + + ScriptingObjectWithIntPtrField(ScriptingObjectPtr o) : object(o) {} + + T& operator * () const + { + return GetReference (); + } + + T* operator -> () const + { + return &GetReference (); + } + + operator T* () const + { + return GetPtr (); + } + + inline T& GetReference () const + { + void* nativePointer = GetPtr(); + + if (nativePointer == NULL) + Scripting::RaiseNullException (""); + + return *reinterpret_cast<T*> (nativePointer); + } + + typedef void ExecuteOnManagedFinalizer(void* obj); + + inline void SetPtr(T* ptr, ExecuteOnManagedFinalizer* eomf = NULL) + { + #if ENABLE_MONO + Assert(ptr == NULL || GET_CURRENT_ALLOC_ROOT_HEADER() == NULL + || GET_CURRENT_ALLOC_ROOT_HEADER() == GET_ALLOC_HEADER(s_MonoDomainContainer, kMemMono)); + ExtractMonoObjectData<T*>(object) = ptr; + (void)eomf; + #elif UNITY_FLASH + + __asm __volatile__("obj_g0 = marshallmap.getObjectWithId(%0);"::"r"(object)); + __asm __volatile__("obj_g0.m_Ptr = %0;"::"r"(ptr)); + + //We only insert this if we actually have a way to clean it...if we don't then there's no point in inserting it in the finalizer map. + if(eomf == NULL) + return; + + __asm __volatile__("finalizePtrsMap[%0] = %1;" : : "r"(ptr),"r"(eomf)); + __asm __volatile__("finalizeMap[obj_g0] = %0;"::"r"(ptr)); + #elif UNITY_WINRT + static BridgeInterface::IMarshalling^ marshaller = s_WinRTBridge->Marshalling; + marshaller->MarshalNativePtrIntoFirstFieldGC(object.GetHandle(), (int)ptr); + //typedef void (__stdcall *TMarshalNativePtrIntoFirstField)(ScriptingObjectPtr, int); + //static TMarshalNativePtrIntoFirstField call = (TMarshalNativePtrIntoFirstField)GetWinRTMarshalling()->GetMarshalNativePtrIntoFirstFieldDelegatePtr(); + //call(object, (int)ptr); + #endif + } + + inline T* GetPtr() const + { + if (!object) + return NULL; + + #if ENABLE_MONO + return ExtractMonoObjectData<T*>(object); + #elif UNITY_FLASH + T* result; + __asm __volatile__("%0 = marshallmap.getObjectWithId(%1).m_Ptr;" : "=r"(result) : "r"(object)); + return result; + #elif UNITY_WINRT + static BridgeInterface::IMarshalling^ marshaller = s_WinRTBridge->Marshalling; + return (T*)marshaller->MarshalFirstFieldIntoNativePtrGC(object.GetHandle()); + //typedef int (__stdcall *TMarshalFirstFieldIntoNativePtr)(ScriptingObjectPtr); + //static TMarshalFirstFieldIntoNativePtr call = (TMarshalFirstFieldIntoNativePtr)GetWinRTMarshalling()->GetMarshalFirstFieldIntoNativePtrDelegatePtr(); + //return (T*)call(object); + #endif + } + + inline ScriptingObjectPtr GetScriptingObject() + { + return object; + } +}; +#else +// THIS WON'T WORK because cachedPtr doesn't derive from Object, thus we cannot extract ScriptingObjectPtr from cachedPtr +template<class T> +struct ScriptingObjectWithIntPtrField +{ + T* cachedPtr; + + ScriptingObjectWithIntPtrField(void* o) : cachedPtr((T*)o) {} + + T& operator * () const + { + return *cachedPtr; + } + + T* operator -> () const + { + return cachedPtr; + } + + operator T* () const + { + return cachedPtr; + } + + inline T& GetReference () const + { + return *cachedPtr; + } + + inline T* GetPtr() const + { + return cachedPtr; + } + + typedef void ExecuteOnManagedFinalizer(void* obj); + + inline void SetPtr(T* ptr, ExecuteOnManagedFinalizer* eomf = NULL) + { + if (cachedPtr != NULL) + { + s_WinRTBridge->Marshalling->MarshalNativePtrIntoFirstField(ObjectToScriptingObjectImpl(cachedPtr), (int)ptr); + } + } +}; +#endif diff --git a/Runtime/Scripting/ScriptingUtility.h b/Runtime/Scripting/ScriptingUtility.h new file mode 100644 index 0000000..7670d59 --- /dev/null +++ b/Runtime/Scripting/ScriptingUtility.h @@ -0,0 +1,48 @@ +#ifndef SCRIPTINGUTILITY_H +#define SCRIPTINGUTILITY_H + +#if ENABLE_SCRIPTING +#include "Runtime/Scripting/Backend/ScriptingTypes.h" + +#include "Runtime/BaseClasses/BaseObject.h" + +#include "Runtime/Scripting/Backend/ScriptingArguments.h" +#include "Runtime/Scripting/Backend/ScriptingInvocation.h" +#include "Runtime/Scripting/ICallString.h" + +#if ENABLE_MONO_API_THREAD_CHECK && ENABLE_MONO +# include "Runtime/Threads/Thread.h" +# define SCRIPTINGAPI_CONSTRUCTOR_CHECK(NAME) \ + if (GetMonoBehaviourInConstructor() == 0) ; else { \ + Scripting::RaiseArgumentException("You are not allowed to call " #NAME " when declaring a variable.\nMove it to the line after without a variable declaration.\nDon't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function."); \ + } + +# define SCRIPTINGAPI_THREAD_CHECK(NAME) \ + if ( Thread::CurrentThreadIsMainThread() ) ; else \ + {\ + ErrorString(#NAME " can only be called from the main thread.\nConstructors and field initializers will be executed from the loading thread when loading a scene.\nDon't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function."); \ + Scripting::RaiseArgumentException(#NAME " can only be called from the main thread.\nConstructors and field initializers will be executed from the loading thread when loading a scene.\nDon't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.");\ + } + +#else +# define SCRIPTINGAPI_THREAD_CHECK(NAME) +# define SCRIPTINGAPI_CONSTRUCTOR_CHECK(NAME) +#endif + +#if ENABLE_MONO +# include "Runtime/Mono/MonoIncludes.h" +# include "Runtime/Mono/MonoUtility.h" +#elif UNITY_WINRT +#elif UNITY_FLASH +# include "AS3Utility.h" +#endif + +#include "Scripting.h" + +//todo: put these back at the top when we've cleaned up the dependency mess +#include "Runtime/Scripting/ScriptingObjectOfType.h" +#include "Runtime/Scripting/ReadOnlyScriptingObjectOfType.h" + +#endif //ENABLE_SCRIPTING + +#endif diff --git a/Runtime/Scripting/Scripting_Flash.cpp b/Runtime/Scripting/Scripting_Flash.cpp new file mode 100644 index 0000000..a36a950 --- /dev/null +++ b/Runtime/Scripting/Scripting_Flash.cpp @@ -0,0 +1,176 @@ +#include "UnityPrefix.h" + +#include "Scripting.h" +#include "ScriptingUtility.h" +#include "Runtime/BaseClasses/BaseObject.h" + +namespace Scripting +{ + +void RaiseAS3NativeException(const char* type, const char* format, va_list list) +{ + va_list ap = list; + va_copy (ap, list); + char buffer[1024 * 5]; + vsnprintf (buffer, 1024 * 5, format, ap); + string typeString; + typeString += type; + typeString += ":"; + typeString += buffer; + //ErrorString(typeString); + Ext_Flash_ThrowError(typeString.c_str()); + va_end (ap); +} + +void RaiseArgumentException(const char* format, ...) +{ + va_list va; + va_start( va, format ); + RaiseAS3NativeException("RaiseArgumentException", format, va); +} + +void RaiseSecurityException(const char* format, ...) +{ + va_list va; + va_start( va, format ); + RaiseAS3NativeException("RaiseSecurityException", format, va); +} + +void RaiseNullException(const char* format, ...) +{ + va_list va; + va_start( va, format ); + RaiseAS3NativeException("NullReferenceException", format, va); +} + +void RaiseMonoException (const char* format, ...) +{ + va_list va; + va_start( va, format ); + RaiseAS3NativeException("RaiseMonoException", format, va); +} + +void RaiseNullExceptionObject(ScriptingObjectPtr object) +{ + ErrorString("RaiseNullExceptionObject not implemented"); + Ext_Flash_ThrowError("RaiseNullExceptionObject"); +} + +void RaiseOutOfRangeException(const char* format, ...) +{ + ErrorString("RaiseOutOfRangeException not implemented"); + Ext_Flash_ThrowError("RaiseOutOfRangeException"); +} + + +void* GetCachedPtrFromScriptingWrapper(ScriptingObjectPtr object) +{ + if(object == SCRIPTING_NULL) + return NULL; + + void* result; + __asm __volatile__("%0 = (marshallmap.getObjectWithId(%1) as UnityEngine._Object).m_CachedPtr;" : "=r"(result) : "r"(object)); + return result; +} + +void SetCachedPtrOnScriptingWrapper(ScriptingObjectPtr object, void* cachedPtr) +{ + __asm __volatile__("(marshallmap.getObjectWithId(%0) as UnityEngine._Object).m_CachedPtr = %1;" : : "r"(object), "r"(cachedPtr)); +} + +int GetInstanceIDFromScriptingWrapper(ScriptingObjectPtr object) +{ + if(object == SCRIPTING_NULL) + return 0; + + int result; + __asm __volatile__("%0 = (marshallmap.getObjectWithId(%1) as UnityEngine._Object).m_InstanceID;" : "=r"(result) : "r"(object)); + return result; +} + +void SetInstanceIDOnScriptingWrapper(ScriptingObjectPtr object, int instanceID) +{ + __asm __volatile__("(marshallmap.getObjectWithId(%0) as UnityEngine._Object).m_InstanceID = %1;" : : "r"(object), "r"(instanceID)); +} + +void SetErrorOnScriptingWrapper(ScriptingObjectPtr object, ScriptingStringPtr error) +{ + +} + +ScriptingObjectPtr InstantiateScriptingWrapperForClassID(int classID) +{ + const string& name = Object::ClassIDToString(classID); + const char* cname = name.c_str(); + + ScriptingObjectPtr result = Ext_Scripting_InstantiateScriptingWrapperForClassWithName(cname); + if(result != NULL) + return result; + + int superClassID = Object::GetSuperClassID(classID); + if(superClassID != ClassID(Object)) + return InstantiateScriptingWrapperForClassID(superClassID); + + return NULL; +} + +ScriptingObjectPtr ScriptingObjectNULL(ScriptingClassPtr klass) +{ + return SCRIPTING_NULL; +} + +void RaiseIfNull(ScriptingObjectPtr object) +{ + if(object == SCRIPTING_NULL) + RaiseNullException("(null)"); +} + +void RaiseIfNull(void* object) +{ + if(object == NULL) + RaiseNullException("(null)"); +} + +void SetScriptingArrayObjectElementImpl(ScriptingArrayPtr a, int i, ScriptingObjectPtr value) +{ + void* raw = scripting_array_element_ptr(a, i, sizeof(ScriptingObjectPtr)); + *(ScriptingObjectPtr*)raw = value; +} + +void SetScriptingArrayStringElementImpl(ScriptingArrayPtr a, int i, ScriptingStringPtr value) +{ + void* raw = scripting_array_element_ptr(a, i, sizeof(ScriptingStringPtr)); + *(ScriptingStringPtr*)raw = value; +} + +ScriptingStringPtr* GetScriptingArrayStringElementImpl(ScriptingArrayPtr a, int i) +{ + return (ScriptingStringPtr*)scripting_array_element_ptr(a, i, sizeof(ScriptingStringPtr)); +} + +ScriptingObjectPtr* GetScriptingArrayObjectElementImpl(ScriptingArrayPtr a, int i) +{ + return (ScriptingObjectPtr*)scripting_array_element_ptr(a, i, sizeof(ScriptingObjectPtr)); +} + +ScriptingStringPtr* GetScriptingArrayStringStartImpl(ScriptingArrayPtr a) +{ + return (ScriptingStringPtr*)scripting_array_element_ptr(a, 0, sizeof(ScriptingStringPtr)); +} + +ScriptingObjectPtr* GetScriptingArrayObjectStartImpl(ScriptingArrayPtr a) +{ + return (ScriptingObjectPtr*)scripting_array_element_ptr(a, 0, sizeof(ScriptingObjectPtr)); +} + +ScriptingStringPtr GetScriptingArrayStringElementNoRefImpl(ScriptingArrayPtr a, int i) +{ + return *((ScriptingStringPtr*)scripting_array_element_ptr(a, i, sizeof(ScriptingStringPtr))); +} + +ScriptingObjectPtr GetScriptingArrayObjectElementNoRefImpl(ScriptingArrayPtr a, int i) +{ + return *((ScriptingObjectPtr*)scripting_array_element_ptr(a, i, sizeof(ScriptingObjectPtr))); +} + +}//namespace Scripting
\ No newline at end of file diff --git a/Runtime/Scripting/Scripting_Mono.cpp b/Runtime/Scripting/Scripting_Mono.cpp new file mode 100644 index 0000000..848a6a0 --- /dev/null +++ b/Runtime/Scripting/Scripting_Mono.cpp @@ -0,0 +1,247 @@ +#include "UnityPrefix.h" + +#include <stdarg.h> +#include "Scripting.h" +#include "Runtime/Mono/MonoManager.h" + +#ifdef _MSC_VER +#define va_copy(a,z) ((void)((a)=(z))) +#endif + +static UnityEngineObjectMemoryLayout* GetUnityEngineObjectMemoryLayout(ScriptingObjectPtr object) +{ + return reinterpret_cast<UnityEngineObjectMemoryLayout*>(((char*)object) + kMonoObjectOffset); +} + +namespace Scripting +{ + +void* GetCachedPtrFromScriptingWrapper(ScriptingObjectPtr object) +{ + if(object == SCRIPTING_NULL) + return NULL; + + return GetUnityEngineObjectMemoryLayout(object)->cachedPtr; +} + +void SetCachedPtrOnScriptingWrapper(ScriptingObjectPtr object, void* cachedPtr) +{ + GetUnityEngineObjectMemoryLayout(object)->cachedPtr = cachedPtr; +} + +int GetInstanceIDFromScriptingWrapper(ScriptingObjectPtr object) +{ + if(object == SCRIPTING_NULL) + return 0; + + return GetUnityEngineObjectMemoryLayout(object)->instanceID; +} + +void SetInstanceIDOnScriptingWrapper(ScriptingObjectPtr object, int instanceID) +{ + GetUnityEngineObjectMemoryLayout(object)->instanceID = instanceID; +} + +void SetErrorOnScriptingWrapper(ScriptingObjectPtr object, ScriptingStringPtr error) +{ +#if MONO_QUALITY_ERRORS + GetUnityEngineObjectMemoryLayout(object)->error = error; +#endif +} + +ScriptingObjectPtr InstantiateScriptingWrapperForClassID(int classID) +{ + return (ScriptingObjectPtr)MonoInstantiateScriptingWrapperForClassID(classID); +} + +ScriptingObjectPtr ScriptingObjectNULL(ScriptingClassPtr klass) +{ + return MonoObjectNULL(klass); +} + +ScriptingObjectPtr ScriptingObjectNULL(ScriptingClassPtr klass, ScriptingStringPtr error) +{ +#if MONO_QUALITY_ERRORS + return MonoObjectNULL(klass,error); +#else + return MonoObjectNULL(klass); +#endif +} + + +DOES_NOT_RETURN void RaiseDotNetExceptionImpl (const char* ns, const char* type, const char* format, va_list list) +{ + va_list ap; + va_copy (ap, list); + + char buffer[1024 * 5]; + vsnprintf (buffer, 1024 * 5, format, ap); + va_end (ap); + + MonoException* exception = mono_exception_from_name_msg (mono_get_corlib (), ns, type, buffer); + mono_raise_exception (exception); + +} + +DOES_NOT_RETURN void RaiseSystemExceptionImpl (const char* type, const char* format, va_list list) +{ + va_list ap; + va_copy (ap, list); + RaiseDotNetExceptionImpl("System",type,format,ap); +} + +void RaiseManagedException (const char *ns, const char *type, const char *format, ...) +{ + va_list va; + va_start (va, format); + RaiseDotNetExceptionImpl (ns, type, format, va); +} + +void RaiseMonoException (const char* format, ...) +{ + va_list va; + va_start( va, format ); + + char buffer[1024 * 5]; + vsnprintf (buffer, 1024 * 5, format, va); + + MonoException* exception = mono_exception_from_name_msg (GetMonoManager ().GetEngineImage (), kEngineNameSpace, "UnityException", buffer); + mono_raise_exception (exception); +} + +void RaiseOutOfRangeException (const char* format, ...) +{ + va_list va; + va_start( va, format ); + RaiseSystemExceptionImpl("IndexOutOfRangeException", format, va); +} + +void RaiseNullException (const char* format, ...) +{ + va_list va; + va_start( va, format ); + RaiseSystemExceptionImpl("NullReferenceException", format, va); +} + +void RaiseArgumentException (const char* format, ...) +{ + va_list va; + va_start( va, format ); + RaiseSystemExceptionImpl("ArgumentException", format, va); +} + +void RaiseInvalidOperationException (const char* format, ...) +{ + va_list va; + va_start( va, format ); + RaiseSystemExceptionImpl("InvalidOperationException", format, va); +} + +void RaiseSecurityException (const char* format, ...) +{ + va_list va; + va_start( va, format ); + RaiseDotNetExceptionImpl("System.Security","SecurityException", format, va); +} + +void RaiseNullExceptionObject (MonoObject* object) +{ + #if MONO_QUALITY_ERRORS + if (object) + { + MonoClass* klass = mono_object_get_class(object); + if (mono_class_is_subclass_of (mono_object_get_class(object), GetMonoManager().ClassIDToScriptingClass(ClassID(Object)), false)) + { + UnityEngineObjectMemoryLayout& data = ExtractMonoObjectData<UnityEngineObjectMemoryLayout>(object); + string error = MonoStringToCpp(data.error); + + // The object was destroyed underneath us - but if we hit a MissingReferenceException then we show that instead! + if (data.instanceID != 0 && error.find ("MissingReferenceException:") != 0) + { + error = Format("The object of type '%s' has been destroyed but you are still trying to access it.\n" + "Your script should either check if it is null or you should not destroy the object.", mono_class_get_name(klass)); + + MonoException* exception = mono_exception_from_name_msg (GetMonoManager().GetEngineImage(), "UnityEngine", "MissingReferenceException", error.c_str()); + mono_raise_exception (exception); + } + + // We got an error message, parse it and throw it + if (data.error) + { + error = MonoStringToCpp(data.error); + string::size_type exceptionTypePos = error.find(':'); + if (exceptionTypePos != string::npos) + { + string type = string(error.begin(), error.begin() + exceptionTypePos); + error.erase(error.begin(), error.begin()+exceptionTypePos + 1); + + MonoException* exception = mono_exception_from_name_msg (GetMonoManager().GetEngineImage(), "UnityEngine", type.c_str(), error.c_str ()); + mono_raise_exception (exception); + } + } + } + } + + MonoException* exception = mono_exception_from_name_msg (mono_get_corlib (), "System", "NullReferenceException", ""); + mono_raise_exception (exception); + #else + MonoException* exception = mono_exception_from_name_msg (mono_get_corlib (), "System", "NullReferenceException", ""); + mono_raise_exception (exception); + #endif +} + +void RaiseIfNull(ScriptingObjectPtr object) +{ + if(object == SCRIPTING_NULL) + RaiseNullException("(null)"); +} + +void RaiseIfNull(void* object) +{ + if(object == NULL) + RaiseNullException("(null)"); +} + +void SetScriptingArrayObjectElementImpl(ScriptingArrayPtr a, int i, ScriptingObjectPtr value) +{ + void* raw = scripting_array_element_ptr(a, i, sizeof(ScriptingObjectPtr)); + *(ScriptingObjectPtr*)raw = value; +} + +void SetScriptingArrayStringElementImpl(ScriptingArrayPtr a, int i, ScriptingStringPtr value) +{ + void* raw = scripting_array_element_ptr(a, i, sizeof(ScriptingStringPtr)); + *(ScriptingStringPtr*)raw = value; +} + +ScriptingStringPtr* GetScriptingArrayStringElementImpl(ScriptingArrayPtr a, int i) +{ + return (ScriptingStringPtr*)scripting_array_element_ptr(a, i, sizeof(ScriptingStringPtr)); +} + +ScriptingObjectPtr* GetScriptingArrayObjectElementImpl(ScriptingArrayPtr a, int i) +{ + return (ScriptingObjectPtr*)scripting_array_element_ptr(a, i, sizeof(ScriptingObjectPtr)); +} + +ScriptingStringPtr* GetScriptingArrayStringStartImpl(ScriptingArrayPtr a) +{ + return (ScriptingStringPtr*)scripting_array_element_ptr(a, 0, sizeof(ScriptingStringPtr)); +} + +ScriptingObjectPtr* GetScriptingArrayObjectStartImpl(ScriptingArrayPtr a) +{ + return (ScriptingObjectPtr*)scripting_array_element_ptr(a, 0, sizeof(ScriptingObjectPtr)); +} + +ScriptingStringPtr GetScriptingArrayStringElementNoRefImpl(ScriptingArrayPtr a, int i) +{ + return *((ScriptingStringPtr*)scripting_array_element_ptr(a, i, sizeof(ScriptingStringPtr))); +} + +ScriptingObjectPtr GetScriptingArrayObjectElementNoRefImpl(ScriptingArrayPtr a, int i) +{ + return *((ScriptingObjectPtr*)scripting_array_element_ptr(a, i, sizeof(ScriptingObjectPtr))); +} + +}//namespace Scripting diff --git a/Runtime/Scripting/Scripting_WinRT.cpp b/Runtime/Scripting/Scripting_WinRT.cpp new file mode 100644 index 0000000..e995ca7 --- /dev/null +++ b/Runtime/Scripting/Scripting_WinRT.cpp @@ -0,0 +1,175 @@ +#include "UnityPrefix.h" + +#include "Scripting.h" +#include "ScriptingManager.h" +#include "Backend/ScriptingTypeRegistry.h" +#include "Backend/ScriptingBackendApi.h" +#include "PlatformDependent/MetroPlayer/MetroUtils.h" + +#include <wrl/wrappers/corewrappers.h> + +static BridgeInterface::IArrayTools^& GetWinRTArrayTools() +{ + static BridgeInterface::IArrayTools^ s_Cached = s_WinRTBridge->ArrayTools; + return s_Cached; +} + +static BridgeInterface::IUnityEngineObjectTools^& GetWinRTUnityEngineObjectTools() +{ + static BridgeInterface::IUnityEngineObjectTools^ s_Cached = s_WinRTBridge->UnityEngineObjectTools; + return s_Cached; +} + +namespace Scripting +{ + +void* GetCachedPtrFromScriptingWrapper(ScriptingObjectPtr object) +{ + if(object == SCRIPTING_NULL) + return NULL; + + return (void*)GetWinRTUnityEngineObjectTools()->ScriptingObjectGetReferenceDataCachedPtrGC(object.GetHandle()); +} + +void SetCachedPtrOnScriptingWrapper(ScriptingObjectPtr object, void* cachedPtr) +{ + GetWinRTUnityEngineObjectTools()->ScriptingObjectSetReferenceDataCachedPtrGC(object.GetHandle(), (int)cachedPtr); +} + +int GetInstanceIDFromScriptingWrapper(ScriptingObjectPtr object) +{ + if(object == SCRIPTING_NULL) + return 0; + + return GetWinRTUnityEngineObjectTools()->ScriptingObjectGetReferenceDataInstanceIDGC(object.GetHandle()); +} + +void SetInstanceIDOnScriptingWrapper(ScriptingObjectPtr object, int instanceID) +{ + GetWinRTUnityEngineObjectTools()->ScriptingObjectSetReferenceDataInstanceIDGC(object.GetHandle(), instanceID); +} + +void SetErrorOnScriptingWrapper(ScriptingObjectPtr object, ScriptingStringPtr error) +{ + +} + +#if !UNITY_EXTERNAL_TOOL +ScriptingObjectPtr InstantiateScriptingWrapperForClassID(int classID) +{ + const string& name = Object::ClassIDToString(classID); + + ScriptingClassPtr klass = GetScriptingTypeRegistry().GetType("UnityEngine", name.c_str()); + if (klass != SCRIPTING_NULL) + return scripting_object_new(klass); + + int superClassID = Object::GetSuperClassID(classID); + if(superClassID != ClassID(Object)) + return InstantiateScriptingWrapperForClassID(superClassID); + + return SCRIPTING_NULL; +} +#endif + +ScriptingObjectPtr ScriptingObjectNULL(ScriptingClassPtr klass) +{ + return SCRIPTING_NULL; +} + +void RaiseSecurityException(const char* format, ...) +{ + va_list va; + va_start(va, format); + throw ref new Platform::FailureException(ConvertUtf8ToString(VFormat(format, va))); +} + +void RaiseNullException(const char* format, ...) +{ + va_list va; + va_start(va, format); + throw ref new Platform::FailureException(ConvertUtf8ToString(VFormat(format, va))); +} + +void RaiseNullExceptionObject(ScriptingObjectPtr object) +{ + throw ref new Platform::NullReferenceException(); +} + +void RaiseMonoException (const char* format, ...) +{ + va_list va; + va_start(va, format); + throw ref new Platform::FailureException(ConvertUtf8ToString(VFormat(format, va))); +} + +void RaiseOutOfRangeException(const char* format, ...) +{ + va_list va; + va_start(va, format); + throw ref new Platform::OutOfBoundsException(ConvertUtf8ToString(VFormat(format, va))); +} + +void RaiseArgumentException (const char* format, ...) +{ + va_list va; + va_start(va, format); + throw ref new Platform::InvalidArgumentException(ConvertUtf8ToString(VFormat(format, va))); +} + +void RaiseIfNull(ScriptingObjectPtr object) +{ + if(object == SCRIPTING_NULL) + throw ref new Platform::NullReferenceException(); +} + +void RaiseIfNull(void* object) +{ + if(object == NULL) + RaiseNullException("(null)"); +} + +void SetScriptingArrayObjectElementImpl(ScriptingArrayPtr a, int i, ScriptingObjectPtr value) +{ + GetWinRTArrayTools()->SetArrayValue(a.GetHandle(), i, value.GetHandle()); +} + +void SetScriptingArrayStringElementImpl(ScriptingArrayPtr a, int i, ScriptingStringPtr value) +{ + GetWinRTArrayTools()->SetArrayStringValue(a.GetHandle(), i, value); +} + +ScriptingStringPtr* GetScriptingArrayStringElementImpl(ScriptingArrayPtr a, int i) +{ + FatalErrorMsg("Not allowed"); + return NULL; +} + +ScriptingObjectPtr* GetScriptingArrayObjectElementImpl(ScriptingArrayPtr a, int i) +{ + FatalErrorMsg("Not allowed"); + return NULL; +} + +ScriptingStringPtr* GetScriptingArrayStringStartImpl(ScriptingArrayPtr a) +{ + FatalErrorMsg("Not allowed"); + return NULL; +} + +ScriptingObjectPtr* GetScriptingArrayObjectStartImpl(ScriptingArrayPtr a) +{ + FatalErrorMsg("Not allowed"); + return NULL; +} + +ScriptingStringPtr GetScriptingArrayStringElementNoRefImpl(ScriptingArrayPtr a, int i) +{ + return GetWinRTArrayTools()->GetArrayStringValue(a.GetHandle(), i); +} + +ScriptingObjectPtr GetScriptingArrayObjectElementNoRefImpl(ScriptingArrayPtr a, int i) +{ + return WinRTScriptingObjectWrapper(GetWinRTArrayTools()->GetArrayValue(a.GetHandle(), i)); +} + +} // namespace Scripting
\ No newline at end of file diff --git a/Runtime/Scripting/TextAsset.cpp b/Runtime/Scripting/TextAsset.cpp new file mode 100644 index 0000000..f21b0e6 --- /dev/null +++ b/Runtime/Scripting/TextAsset.cpp @@ -0,0 +1,70 @@ +#include "UnityPrefix.h" +#include "TextAsset.h" +#include "Runtime/Serialize/TransferFunctions/SerializeTransfer.h" +#if ENABLE_MONO +#include "Runtime/Mono/MonoIncludes.h" +#endif + + +TextAsset::TextAsset(MemLabelId label, ObjectCreationMode mode) + : Super(label, mode) +{ +} + +TextAsset::~TextAsset () +{ +} + +template<class TransferFunction> +void TextAsset::Transfer (TransferFunction& transfer) +{ + Super::Transfer ( transfer); + transfer.Transfer (m_Script, "m_Script", kHideInEditorMask); + transfer.Transfer (m_PathName, "m_PathName", kHideInEditorMask); +} + +void TextAsset::AwakeFromLoad (AwakeFromLoadMode awakeMode) +{ + Super::AwakeFromLoad (awakeMode); +} + +void TextAsset::SetScriptDontDirty (const ScriptString& script) { + m_Script = script; +} + +bool TextAsset::SetScript (const ScriptString& script) { + return SetScript(script,false); +} + +bool TextAsset::SetScript (const ScriptString& script, bool actuallyContainsBinaryData) +{ + SET_ALLOC_OWNER(this); + m_Script = script; + + #if ENABLE_MONO + // Fallback. If mono doesn't accept the string, strip everything non-ASCII + if(mono_string_new_wrapper(script.c_str()) == NULL && !actuallyContainsBinaryData) + { + m_Script.clear(); + + for(int i=0; i<script.size(); i++) + { + if((unsigned char)script[i] < 0x7f) + m_Script += script[i]; + } + } + #endif + + SetDirty (); + return true; +} + +const UnityStr& TextAsset::GetScriptClassName() const { + static UnityStr sEmpty; + return sEmpty; +} + + +IMPLEMENT_CLASS (TextAsset) +IMPLEMENT_OBJECT_SERIALIZE (TextAsset) +INSTANTIATE_TEMPLATE_TRANSFER (TextAsset) diff --git a/Runtime/Scripting/TextAsset.h b/Runtime/Scripting/TextAsset.h new file mode 100644 index 0000000..5c42fb2 --- /dev/null +++ b/Runtime/Scripting/TextAsset.h @@ -0,0 +1,40 @@ +#pragma once + +#include "Runtime/BaseClasses/NamedObject.h" +#include "Configuration/UnityConfigure.h" + +#include "Runtime/Misc/Allocator.h" + + +class TextAsset : public NamedObject { +public: + + typedef UnityStr ScriptString; + + REGISTER_DERIVED_CLASS (TextAsset, NamedObject) + DECLARE_OBJECT_SERIALIZE (TextAsset) + + TextAsset(MemLabelId label, ObjectCreationMode mode); + + virtual void AwakeFromLoad (AwakeFromLoadMode awakeMode); + + // Set the script string. + // Subclasses override this in order to implement compiling, etc... + // @return whether the compilation succeeded + virtual bool SetScript (const ScriptString& script, bool actuallyContainsBinaryData); + virtual bool SetScript (const ScriptString& script); + + // Get the script string. + const ScriptString &GetScript () const { return m_Script; } + + void SetPathName (const std::string& path) { m_PathName = path; SetDirty (); } + const UnityStr& GetPathName () { return m_PathName; } + + virtual const UnityStr& GetScriptClassName() const; + void SetScriptDontDirty (const ScriptString& script); + +protected: + + UnityStr m_PathName; + ScriptString m_Script; +}; diff --git a/Runtime/Scripting/WinRTHelper.h b/Runtime/Scripting/WinRTHelper.h new file mode 100644 index 0000000..2fef260 --- /dev/null +++ b/Runtime/Scripting/WinRTHelper.h @@ -0,0 +1,29 @@ +#ifndef WINRTHELPER_H +#define WINRTHELPER_H + +#if UNITY_WINRT + +# if UNITY_METRO_VS2012 +# if defined(__arm__) +# include "build/temp/MetroSupport/metroARM/AutoGeneratedFuncDefs.h" +# else +# include "build/temp/MetroSupport/metro32/AutoGeneratedFuncDefs.h" +# endif +# elif UNITY_METRO_VS2013 +# if defined(__arm__) +# include "build/temp/MetroSupport/metroBlueARM/AutoGeneratedFuncDefs.h" +# else +# include "build/temp/MetroSupport/metroBlue32/AutoGeneratedFuncDefs.h" +# endif +# elif UNITY_WP8 +# include "build/temp/WP8Support/AutoGeneratedFuncDefs.h" +# endif +#endif + + +inline long long* GetWinRTFuncDefsPointers() +{ + return (long long*)UnityEngineDelegates::FunctionDefsDictionary::GetPointers(); +} + +#endif diff --git a/Runtime/Scripting/WinRTMarshalers.cpp b/Runtime/Scripting/WinRTMarshalers.cpp new file mode 100644 index 0000000..80d4d48 --- /dev/null +++ b/Runtime/Scripting/WinRTMarshalers.cpp @@ -0,0 +1,306 @@ +#include "UnityPrefix.h" + +#if UNITY_WINRT && ENABLE_SCRIPTING +#include "Runtime/Scripting/Backend/ScriptingTypes.h" +#include "Runtime/Scripting/ScriptingUtility.h" + + +#include "Runtime/Misc/AssetBundleUtility.h" +#include "Runtime/Camera/LODGroup.h" +#include "Runtime/NavMesh/NavMeshTypes.h" +#include "Runtime/Terrain/SplatDatabase.h" +#include "Runtime/Terrain/DetailDatabase.h" +#include "Runtime/Terrain/TreeDatabase.h" +#include "Runtime/IMGUI/GUIContent.h" +#include "Runtime/Mono/Coroutine.h" +#include "Runtime/Export/WWW.h" +#include "Runtime/Graphics/LightmapSettings.h" +#include "Runtime/Animation/AnimationEvent.h" + +#include "Runtime/Dynamics/CharacterController.h" +#include "Runtime/Misc/AsyncOperation.h" +#include "Runtime/Dynamics/Collider.h" +#include "Runtime/Physics2D/Collider2D.h" +#include "Runtime/Physics2D/CollisionListener2D.h" +#include "Runtime/Video/VideoTexture.h" +#include "Runtime/Threads/ThreadSpecificValue.h" +#include "Runtime/Filters/Misc/Font.h" + +UNITY_TLS_VALUE(void*) s_CurrentTarget; + +void _MarshalSetMonoLOD(float screenRelativeTransitionHeight, /*WinRTScriptingObjectWrapper*/long long renderers) +{ + MonoLOD* monoLOD = (MonoLOD*)s_CurrentTarget; + monoLOD->screenRelativeTransitionHeight = screenRelativeTransitionHeight; + monoLOD->renderers = renderers; +} +void _MarshalSetNavMeshPath(int ptr, /*WinRTScriptingObjectWrapper*/long long corners) +{ + MonoNavMeshPath* monoNavMeshPath = (MonoNavMeshPath*)s_CurrentTarget; + monoNavMeshPath->native = (NavMeshPath*)ptr; + monoNavMeshPath->corners = corners; +} +void _MarshalSetMonoGUIContent(Platform::String^ text, Platform::String^ tooltip, /*WinRTScriptingObjectWrapper*/long long image) +{ + MonoGUIContent* monoGUIContent = (MonoGUIContent*)s_CurrentTarget; + monoGUIContent->m_Text = text; + monoGUIContent->m_Tooltip = tooltip; + monoGUIContent->m_Image = image; +} +void _MarshalSetLightmapDataMono(/*WinRTScriptingObjectWrapper*/long long lightmap, /*WinRTScriptingObjectWrapper*/long long indirectLightmap) +{ + LightmapDataMono* monoLightmap = (LightmapDataMono*)s_CurrentTarget; + monoLightmap->m_Lightmap = lightmap; + monoLightmap->m_IndirectLightmap = indirectLightmap; +} +void _MarshalSetMonoTreePrototype(/*WinRTScriptingObjectWrapper*/long long prefab, float bendFactor) +{ + MonoTreePrototype* monoTreePrototype = (MonoTreePrototype*)s_CurrentTarget; + monoTreePrototype->prefab = prefab; + monoTreePrototype->bendFactor = bendFactor; +} + + +void _MarshalSetMonoDetailPrototype1(/*WinRTScriptingObjectWrapper*/long long prototype, /*WinRTScriptingObjectWrapper*/long long prototypeTexture, + float healthyColorR, float healthyColorG, float healthyColorB, float healthyColorA, + float dryColorR, float dryColorG, float dryColorB, float dryColorA) +{ + MonoDetailPrototype* monoDetailPrototype = (MonoDetailPrototype*)s_CurrentTarget; + monoDetailPrototype->prototype = prototype; + monoDetailPrototype->prototypeTexture = prototypeTexture; + + monoDetailPrototype->healthyColor = ColorRGBAf(healthyColorR, healthyColorG, healthyColorB, healthyColorA); + monoDetailPrototype->dryColor = ColorRGBAf(dryColorR, dryColorG, dryColorB, dryColorA); +} +void _MarshalSetMonoDetailPrototype2(float minWidth, float maxWidth, + float minHeight, float maxHeight, + float noiseSpread, + float bendFactor, + int renderMode, + int usePrototypeMesh) +{ + MonoDetailPrototype* monoDetailPrototype = (MonoDetailPrototype*)s_CurrentTarget; + + monoDetailPrototype->minWidth = minWidth; + monoDetailPrototype->maxWidth = maxWidth; + monoDetailPrototype->minHeight = minHeight; + monoDetailPrototype->maxHeight = maxHeight; + monoDetailPrototype->noiseSpread = noiseSpread; + monoDetailPrototype->bendFactor = bendFactor; + monoDetailPrototype->renderMode = renderMode; + monoDetailPrototype->usePrototypeMesh = usePrototypeMesh; +} +void _MarshalSetMonoSplatPrototype(/*WinRTScriptingObjectWrapper*/long long texture, /*WinRTScriptingObjectWrapper*/long long normalMap, + float tileSizeX, float tileSizeY, + float tileOffsetX, float tileOffsetY) +{ + MonoSplatPrototype* monoSplatPrototype = (MonoSplatPrototype*)s_CurrentTarget; + monoSplatPrototype->texture = texture; + monoSplatPrototype->normalMap = normalMap; + monoSplatPrototype->tileSize = Vector2f(tileSizeX, tileSizeY); + monoSplatPrototype->tileOffset = Vector2f(tileOffsetX, tileOffsetX); +} +void _MarshalSetScriptingCharacterInfo(int index, BridgeInterface::RectWrapper uv, BridgeInterface::RectWrapper vert, float width, int size, int style, bool flipped) +{ + ScriptingCharacterInfo* o = (ScriptingCharacterInfo*)s_CurrentTarget; + o->index = index; + o->uv = Rectf(uv.m_XMin, uv.m_YMin, uv.m_Width, uv.m_Height); + o->vert = Rectf(vert.m_XMin, vert.m_YMin, vert.m_Width, vert.m_Height); + o->width = width; + o->size = size; + o->style = style; + o->flipped = flipped; +} + +void SetupMarshalCallbacks() +{ + GetWinRTMarshalling()->SetupMarshalCallbacks( + ref new BridgeInterface::MarshalSetMonoLOD(_MarshalSetMonoLOD), + ref new BridgeInterface::MarshalSetNavMeshPath(_MarshalSetNavMeshPath), + ref new BridgeInterface::MarshalSetMonoGUIContent(_MarshalSetMonoGUIContent), + ref new BridgeInterface::MarshalSetLightmapDataMono(_MarshalSetLightmapDataMono), + ref new BridgeInterface::MarshalSetMonoTreePrototype(_MarshalSetMonoTreePrototype), + ref new BridgeInterface::MarshalSetMonoDetailPrototype1(_MarshalSetMonoDetailPrototype1), + ref new BridgeInterface::MarshalSetMonoDetailPrototype2(_MarshalSetMonoDetailPrototype2), + ref new BridgeInterface::MarshalSetMonoSplatPrototype(_MarshalSetMonoSplatPrototype), + ref new BridgeInterface::MarshalSetScriptingCharacterInfo(_MarshalSetScriptingCharacterInfo)); +} +// +// Marshalling: Managed - to - Native +// + +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, AssetBundleCreateRequest** dest) +{ + *dest = (AssetBundleCreateRequest*)GetWinRTMarshalling()->MarshalGetAssetBundleCreateRequestPtr(so.GetHandle()); +} +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, MonoLOD* dest) +{ + s_CurrentTarget = dest; + GetWinRTMarshalling()->MarshallManagedMonoLOD(so.GetHandle()); +} +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, MonoNavMeshPath* dest) +{ + s_CurrentTarget = dest; + GetWinRTMarshalling()->MarshallManagedMonoNavMeshPath(so.GetHandle()); +} +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, MonoGUIContent* dest) +{ + s_CurrentTarget = dest; + GetWinRTMarshalling()->MarshallManagedMonoGUIContent(so.GetHandle()); +} +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, float* dest) +{ + *dest = GetWinRTMarshalling()->MarshallGetManagedWaitForSecondsWait(so.GetHandle()); +} +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, Coroutine** dest) +{ + *dest = (Coroutine*)GetWinRTMarshalling()->MarshallGetManagedCoroutinePtr(so.GetHandle()); +} +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, WWW** dest) +{ + *dest = (WWW*)GetWinRTMarshalling()->MarshallGetManagedWWWPtr(so.GetHandle()); +} +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, LightmapDataMono* dest) +{ + s_CurrentTarget = dest; + GetWinRTMarshalling()->MarshallManagedLightmapDataMono(so.GetHandle()); +} +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, MonoTreePrototype* dest) +{ + s_CurrentTarget = dest; + GetWinRTMarshalling()->MarshallManagedMonoTreePrototype(so.GetHandle()); +} +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, MonoDetailPrototype* dest) +{ + s_CurrentTarget = dest; + GetWinRTMarshalling()->MarshallManagedMonoDetailPrototype(so.GetHandle()); +} +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, MonoSplatPrototype* dest) +{ + s_CurrentTarget = dest; + GetWinRTMarshalling()->MarshallManagedMonoSplatPrototype(so.GetHandle()); +} + +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, ScriptingCharacterInfo* dest) +{ + s_CurrentTarget = dest; + GetWinRTMarshalling()->MarshallManagedScriptingCharacterInfo(so.GetHandle()); +} + +// +// Marshalling: Native - to - Managed +// +void MarshallNativeStructIntoManaged(const AnimationEvent* src, ScriptingObjectPtr& dest) +{ + GetWinRTMarshalling()->MarshallNativeAnimationEventPtr((int)src, dest.GetHandle()); +} +void MarshallNativeStructIntoManaged(const AssetBundleRequestMono& src, ScriptingObjectPtr& dest) +{ + GetWinRTMarshalling()->MarshallNativeAssetBundleRequestTo((int)src.m_Result, src.m_AssetBundle, src.m_Path, src.m_Type, dest.GetHandle()); +} +void MarshallNativeStructIntoManaged(const MonoNavMeshPath& src, ScriptingObjectPtr& dest) +{ + GetWinRTMarshalling()->MarshallNativeNavMashPathTo((int)src.native, src.corners, dest.GetHandle()); +} +void MarshallNativeStructIntoManaged(const void* src, ScriptingObjectPtr& dest) +{ + GetWinRTMarshalling()->MarshallNativeVoidPtrTo((int)src, dest.GetHandle()); +} + +void MarshallNativeStructIntoManaged(const ControllerColliderHit& src, ScriptingObjectPtr& dest) +{ + GetWinRTMarshalling()->MarshallNativeControllerColliderHitTo(src.controller, src.collider, + src.point.x, src.point.y, src.point.z, + src.normal.x, src.normal.y, src.normal.z, + src.motionDirection.x, src.motionDirection.y, src.motionDirection.z, + src.motionLength, + src.push, + dest); +} +void MarshallNativeStructIntoManaged(const AsyncOperation* src, ScriptingObjectPtr& dest) +{ + GetWinRTMarshalling()->MarshallNativeAsyncOperationPtrTo((int)src, dest.GetHandle()); +} +void MarshallNativeStructIntoManaged(const MonoContactPoint& src, ScriptingObjectPtr& dest) +{ + dest = GetWinRTMarshalling()->MarshallNativeMonoContactPointTo(src.point.x, src.point.y, src.point.z, + src.normal.x, src.normal.y, src.normal.z, + src.thisCollider, + src.otherCollider); +} +void MarshallNativeStructIntoManaged(const MonoTreePrototype& src, ScriptingObjectPtr& dest) +{ + GetWinRTMarshalling()->MarshallNativeMonoTreePrototypeTo(src.prefab, src.bendFactor, dest.GetHandle()); +} + +#if ENABLE_WEBCAM +void MarshallNativeStructIntoManaged(const MonoWebCamDevice& src, ScriptingObjectPtr& dest) +{ + dest = GetWinRTMarshalling()->MarshallNativeMonoWebCamDeviceTo(src.name, src.flags); +} +#endif + +void MarshallNativeStructIntoManaged(const MonoCollision& src, ScriptingObjectPtr& dest) +{ + GetWinRTMarshalling()->MarshallNativeMonoCollisionTo(src.relativeVelocity.x, src.relativeVelocity.y, src.relativeVelocity.z, + src.rigidbody, src.collider, src.contacts.GetHandle(), dest.GetHandle()); +} +void MarshallNativeStructIntoManaged(const LightmapDataMono& src, ScriptingObjectPtr& dest) +{ + GetWinRTMarshalling()->MarshallNativeLightmapDataMonoTo(src.m_Lightmap, src.m_IndirectLightmap, dest.GetHandle()); +} + +void MarshallNativeStructIntoManaged(const MonoDetailPrototype& src, ScriptingObjectPtr& dest) +{ + GetWinRTMarshalling()->MarshallNativeMonoDetailPrototype1To( + src.prototype, src.prototypeTexture, + src.healthyColor.r, src.healthyColor.g, src.healthyColor.b, src.healthyColor.a, + src.dryColor.r, src.dryColor.g, src.dryColor.b, src.dryColor.a, + dest); + GetWinRTMarshalling()->MarshallNativeMonoDetailPrototype2To( + src.minWidth, src.maxWidth, + src.minHeight, src.maxHeight, + src.noiseSpread, src.bendFactor, + src.renderMode, src.usePrototypeMesh, + dest); +} +void MarshallNativeStructIntoManaged(const MonoSplatPrototype& src, ScriptingObjectPtr& dest) +{ + GetWinRTMarshalling()->MarshallNativeMonoSplatPrototypeTo(src.texture, src.normalMap, + src.tileSize.x, src.tileSize.y, + src.tileOffset.x, src.tileOffset.y, + dest); +} +#if ENABLE_2D_PHYSICS +void MarshallNativeStructIntoManaged(const ScriptingCollision2D& src, ScriptingObjectPtr& dest) +{ + GetWinRTMarshalling()->MarshallNativeCollision2DTo(src.rigidbody.GetHandle(), src.collider.GetHandle(), src.contacts.GetHandle(), dest.GetHandle()); +} + +void MarshallNativeStructIntoManaged(const ScriptingContactPoint2D& src, ScriptingObjectPtr& dest) +{ + dest = GetWinRTMarshalling()->MarshallNativeContactPoint2DTo( + src.point.x, src.point.y, + src.normal.x, src.normal.y, + src.collider, + src.otherCollider); +} +#endif +void MarshallNativeStructIntoManaged(const ScriptingCharacterInfo& src, ScriptingObjectPtr& dest) +{ + BridgeInterface::RectWrapper uv; + BridgeInterface::RectWrapper vert; + uv.m_XMin = src.uv.x; + uv.m_YMin = src.uv.y; + uv.m_Width = src.uv.width; + uv.m_Height = src.uv.height; + + vert.m_XMin = src.vert.x; + vert.m_YMin = src.vert.y; + vert.m_Width = src.vert.width; + vert.m_Height = src.vert.height; + dest = GetWinRTMarshalling()->MarshallNativeScriptingCharacterInfoTo(src.index, + uv, vert, + src.width, src.size, src.style, src.flipped); +} +#endif diff --git a/Runtime/Scripting/WinRTMarshalers.h b/Runtime/Scripting/WinRTMarshalers.h new file mode 100644 index 0000000..c125a22 --- /dev/null +++ b/Runtime/Scripting/WinRTMarshalers.h @@ -0,0 +1,66 @@ +#ifndef WINRTMARSHALERS_H +#define WINRTMARSHALERS_H + +#if UNITY_WINRT && ENABLE_SCRIPTING + +class AssetBundleCreateRequest; +struct AssetBundleRequestMono; +struct MonoLOD; +struct MonoNavMeshPath; +struct MonoGUIContent; +struct Coroutine; +class WWW; +struct LightmapDataMono; +struct MonoTreePrototype; +struct AnimationEvent; +struct ControllerColliderHit; +class AsyncOperation; +struct MonoContactPoint; +struct MonoWebCamDevice; +struct MonoCollision; +struct MonoDetailPrototype; +struct MonoSplatPrototype; +struct ScriptingCollision2D; +struct ScriptingContactPoint2D; +struct ScriptingCharacterInfo; + +void SetupMarshalCallbacks(); + +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, AssetBundleCreateRequest** dest); +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, MonoLOD* dest); +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, MonoNavMeshPath* dest); +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, MonoGUIContent* dest); +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, float* dest); +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, Coroutine** dest); +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, WWW** dest); +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, LightmapDataMono* dest); +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, MonoTreePrototype* dest); +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, MonoDetailPrototype* dest); +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, MonoSplatPrototype* dest); +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, ScriptingCharacterInfo* dest); + +template<class T> inline +void MarshallManagedStructIntoNative(ScriptingObjectPtr so, T* dest) +{ + MarshallManagedStructIntoNative(so, dest); +} + +void MarshallNativeStructIntoManaged(const AnimationEvent* src, ScriptingObjectPtr& dest); +void MarshallNativeStructIntoManaged(const AssetBundleRequestMono& src, ScriptingObjectPtr& dest); +void MarshallNativeStructIntoManaged(const MonoNavMeshPath& src, ScriptingObjectPtr& dest); +void MarshallNativeStructIntoManaged(const void* src, ScriptingObjectPtr& dest); +void MarshallNativeStructIntoManaged(const ControllerColliderHit& src, ScriptingObjectPtr& dest); +void MarshallNativeStructIntoManaged(const AsyncOperation* src, ScriptingObjectPtr& dest); +void MarshallNativeStructIntoManaged(const MonoContactPoint& src, ScriptingObjectPtr& dest); +void MarshallNativeStructIntoManaged(const MonoTreePrototype& src, ScriptingObjectPtr& dest); +void MarshallNativeStructIntoManaged(const MonoWebCamDevice& src, ScriptingObjectPtr& dest); +void MarshallNativeStructIntoManaged(const MonoCollision& src, ScriptingObjectPtr& dest); +void MarshallNativeStructIntoManaged(const LightmapDataMono& src, ScriptingObjectPtr& dest); +void MarshallNativeStructIntoManaged(const MonoDetailPrototype& src, ScriptingObjectPtr& dest); +void MarshallNativeStructIntoManaged(const MonoSplatPrototype& src, ScriptingObjectPtr& dest); +void MarshallNativeStructIntoManaged(const ScriptingCollision2D& src, ScriptingObjectPtr& dest); +void MarshallNativeStructIntoManaged(const ScriptingContactPoint2D& src, ScriptingObjectPtr& dest); +void MarshallNativeStructIntoManaged(const ScriptingCharacterInfo& src, ScriptingObjectPtr& dest); +#endif + +#endif |