public override void Init(Builder.BuildData buildData) { base.Init(buildData); // Internal base types are usually hidden from bindings (used in core-only internally) IsBaseTypeHidden = BaseTypeInheritance == AccessLevel.Private || BaseType == null; // Cache if it it Scripting Object type if (InBuildScriptingObjectTypes.Contains(Name)) { _isScriptingObject = true; } else if (BaseType == null) { _isScriptingObject = false; } else if (InBuildScriptingObjectTypes.Contains(BaseType.Name)) { _isScriptingObject = true; } else { _isScriptingObject = BaseType != null && BaseType.IsScriptingObject; } if (UniqueFunctionNames == null) { UniqueFunctionNames = new HashSet <string>(); } foreach (var fieldInfo in Fields) { if (fieldInfo.Access == AccessLevel.Private) { continue; } fieldInfo.Getter = new FunctionInfo { Name = "Get" + fieldInfo.Name, Comment = fieldInfo.Comment, IsStatic = fieldInfo.IsStatic, Access = fieldInfo.Access, Attributes = fieldInfo.Attributes, ReturnType = fieldInfo.Type, Parameters = new List <FunctionInfo.ParameterInfo>(), IsVirtual = false, IsConst = true, Glue = new FunctionInfo.GlueInfo() }; ProcessAndValidate(fieldInfo.Getter); fieldInfo.Getter.Name = fieldInfo.Name; if (!fieldInfo.IsReadOnly) { fieldInfo.Setter = new FunctionInfo { Name = "Set" + fieldInfo.Name, Comment = fieldInfo.Comment, IsStatic = fieldInfo.IsStatic, Access = fieldInfo.Access, Attributes = fieldInfo.Attributes, ReturnType = new TypeInfo { Type = "void", }, Parameters = new List <FunctionInfo.ParameterInfo> { new FunctionInfo.ParameterInfo { Name = "value", Type = fieldInfo.Type, }, }, IsVirtual = false, IsConst = true, Glue = new FunctionInfo.GlueInfo() }; ProcessAndValidate(fieldInfo.Setter); fieldInfo.Setter.Name = fieldInfo.Name; } } foreach (var propertyInfo in Properties) { if (propertyInfo.Getter != null) { ProcessAndValidate(propertyInfo.Getter); } if (propertyInfo.Setter != null) { ProcessAndValidate(propertyInfo.Setter); } } foreach (var functionInfo in Functions) { ProcessAndValidate(functionInfo); } }
private void OnGenerateCppScriptWrapperFunction(Builder.BuildData buildData, VirtualClassInfo classInfo, FunctionInfo functionInfo, int scriptVTableSize, int scriptVTableIndex, StringBuilder contents) { // Generate C++ wrapper function to invoke Visual Script instead of overridden native function (with support for base method callback) BindingsGenerator.CppIncludeFiles.Add("Engine/Content/Assets/VisualScript.h"); contents.AppendFormat(" {0} {1}_VisualScriptWrapper(", functionInfo.ReturnType, functionInfo.UniqueName); var separator = false; for (var i = 0; i < functionInfo.Parameters.Count; i++) { var parameterInfo = functionInfo.Parameters[i]; if (separator) { contents.Append(", "); } separator = true; contents.Append(parameterInfo.Type); contents.Append(' '); contents.Append(parameterInfo.Name); } contents.Append(')'); contents.AppendLine(); contents.AppendLine(" {"); string scriptVTableOffset; if (classInfo.IsInterface) { contents.AppendLine($" auto object = ScriptingObject::FromInterface(this, {classInfo.NativeName}::TypeInitializer);"); contents.AppendLine(" if (object == nullptr)"); contents.AppendLine(" {"); contents.AppendLine($" LOG(Error, \"Failed to cast interface {{0}} to scripting object\", TEXT(\"{classInfo.Name}\"));"); BindingsGenerator.GenerateCppReturn(buildData, contents, " ", functionInfo.ReturnType); contents.AppendLine(" }"); contents.AppendLine($" const int32 scriptVTableOffset = {scriptVTableIndex} + object->GetType().GetInterface({classInfo.NativeName}::TypeInitializer)->ScriptVTableOffset;"); scriptVTableOffset = "scriptVTableOffset"; } else { contents.AppendLine($" auto object = ({classInfo.NativeName}*)this;"); scriptVTableOffset = scriptVTableIndex.ToString(); } contents.AppendLine(" static THREADLOCAL void* WrapperCallInstance = nullptr;"); contents.AppendLine(" if (WrapperCallInstance == object)"); contents.AppendLine(" {"); contents.AppendLine(" // Prevent stack overflow by calling base method"); contents.AppendLine(" const auto scriptVTableBase = object->GetType().Script.ScriptVTableBase;"); contents.Append($" return (this->**({functionInfo.UniqueName}_Internal_Signature*)&scriptVTableBase[{scriptVTableOffset} + 2])("); separator = false; for (var i = 0; i < functionInfo.Parameters.Count; i++) { var parameterInfo = functionInfo.Parameters[i]; if (separator) { contents.Append(", "); } separator = true; contents.Append(parameterInfo.Name); } contents.AppendLine(");"); contents.AppendLine(" }"); contents.AppendLine(" auto scriptVTable = (VisualScript::Method**)object->GetType().Script.ScriptVTable;"); contents.AppendLine($" ASSERT(scriptVTable && scriptVTable[{scriptVTableOffset}]);"); if (functionInfo.Parameters.Count != 0) { contents.AppendLine($" Variant parameters[{functionInfo.Parameters.Count}];"); for (var i = 0; i < functionInfo.Parameters.Count; i++) { var parameterInfo = functionInfo.Parameters[i]; contents.AppendLine($" parameters[{i}] = {BindingsGenerator.GenerateCppWrapperNativeToVariant(buildData, parameterInfo.Type, classInfo, parameterInfo.Name)};"); } } else { contents.AppendLine(" Variant* parameters = nullptr;"); } contents.AppendLine(" auto prevWrapperCallInstance = WrapperCallInstance;"); contents.AppendLine(" WrapperCallInstance = object;"); contents.AppendLine($" auto __result = VisualScripting::Invoke(scriptVTable[{scriptVTableOffset}], object, Span<Variant>(parameters, {functionInfo.Parameters.Count}));"); contents.AppendLine(" WrapperCallInstance = prevWrapperCallInstance;"); if (!functionInfo.ReturnType.IsVoid) { contents.AppendLine($" return {BindingsGenerator.GenerateCppWrapperVariantToNative(buildData, functionInfo.ReturnType, classInfo, "__result")};"); } contents.AppendLine(" }"); contents.AppendLine(); }