Exemple #1
0
        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();
        }