“初始化俯视角工程,带puerts,未编过”

This commit is contained in:
2024-12-01 02:11:25 +08:00
parent 04698dd585
commit 850d76173c
1491 changed files with 271579 additions and 0 deletions
@@ -0,0 +1,162 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may be subject to their corresponding license terms.
* This file is subject to the terms and conditions defined in file 'LICENSE', which is part of this source code package.
*/
using System;
using EpicGames.UHT.Tables;
using EpicGames.UHT.Types;
using EpicGames.UHT.Utils;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using EpicGames.Core;
namespace CSharpParamDefaultValueMetas
{
[UnrealHeaderTool]
class CSharpParamDefaultValueMetas
{
[UhtExporter(Name = "Puerts", Description = "Puerts Default Values Collector", Options = UhtExporterOptions.Default, ModuleName = "JsEnv")]
private static void UnLuaDefaultParamCollectorUbtPluginExporter(IUhtExportFactory factory)
{
var paramDefaultValueMetas = new CSharpParamDefaultValueMetas(factory);
paramDefaultValueMetas.Generate();
bool bHasGameRuntime = (from package in factory.Session.Packages where package.Module.ModuleType == UHTModuleType.GameRuntime select package).Any();
paramDefaultValueMetas.OutputIfNeeded(bHasGameRuntime);
}
private IUhtExportFactory Factory;
private BorrowStringBuilder BSB;
private StringBuilder GeneratedContentBuilder => BSB.StringBuilder;
public CSharpParamDefaultValueMetas(IUhtExportFactory factory)
{
Factory = factory;
BSB = new BorrowStringBuilder(StringBuilderCache.Big);
}
IEnumerable<UhtType> TraverseTree(UhtType parentNode)
{
yield return parentNode;
if (parentNode.Children != null)
{
foreach (UhtType childNode in parentNode.Children.SelectMany(TraverseTree))
{
yield return childNode;
}
}
}
private void Generate()
{
GeneratedContentBuilder.Append("// Generated By C# UbtPlugin\r\n");
var packages = (from package in Factory.Session.Packages
where (package.Module.ModuleType == UHTModuleType.EngineRuntime || package.Module.ModuleType == UHTModuleType.GameRuntime)
select package);
var classes = packages
.SelectMany(TraverseTree)
.Where(t => t is UhtClass).Cast<UhtClass>()
.Where(c => !c.ClassFlags.HasAnyFlags(EClassFlags.Interface));
classes.Distinct().OrderBy(c => c.SourceName).ToList().ForEach(ExportClass);
}
private void ExportClass(UhtClass uhtClass)
{
bool declared = false;
Action declareOnce = () => {
if (!declared)
{
GeneratedContentBuilder.AppendFormat("PC = &ParamDefaultMetas.Add(TEXT(\"{0}\"));\r\n", uhtClass.EngineName);
declared = true;
}
};
foreach (UhtFunction uhtFunction in uhtClass.Functions.OrderBy(Func => Func.SourceName))
{
if (!uhtFunction.MetaData.IsEmpty())
{
ExportFunction(uhtFunction, declareOnce);
}
}
if (declared)
{
GeneratedContentBuilder.Append("\r\n");
}
}
private static bool TryGetDefaultValue(UhtMetaData metaData, UhtProperty property, out string value)
{
var hasValue = metaData.TryGetValue(property.SourceName, out string? tempValue);
if (!hasValue)
{
var cppKey = "CPP_Default_" + property.SourceName;
hasValue = metaData.TryGetValue(cppKey, out tempValue);
}
value = tempValue ?? string.Empty;
return hasValue;
}
private void ExportFunction(UhtFunction uhtFunction, Action declareClassOnce)
{
bool declared = false;
var properties = uhtFunction.Children
.Where(c => c is UhtProperty)
.Cast<UhtProperty>()
.Where(p => p.PropertyFlags.HasAnyFlags(EPropertyFlags.Parm) && !p.PropertyFlags.HasAnyFlags(EPropertyFlags.ReturnParm));
foreach (var property in properties.OrderBy(Property => Property.SourceName))
{
if (TryGetDefaultValue(uhtFunction.MetaData, property, out string defaultValue))
{
declareClassOnce();
if (!declared)
{
GeneratedContentBuilder.AppendFormat("PF = &PC->Add(TEXT(\"{0}\"));\r\n", uhtFunction.SourceName);
declared = true;
}
string escapeDefaultValue = defaultValue.Replace("\"", "\\\"");
if (property is UhtBoolProperty)
{
escapeDefaultValue = escapeDefaultValue.Replace("true", "True").Replace("false", "False");
}
GeneratedContentBuilder.AppendFormat("PF->Add(TEXT(\"{0}\"), TEXT(\"{1}\"));\r\n", property.SourceName, escapeDefaultValue);
}
}
}
private void OutputIfNeeded(bool bHasGameRuntime)
{
string filePath = Factory.MakePath("InitParamDefaultMetas", ".inl");
if (File.Exists(filePath))
{
var fileContent = File.ReadAllText(filePath);
if (bHasGameRuntime ? (!fileContent.Equals(GeneratedContentBuilder.ToString())) : (fileContent.Length != 0))
{
Factory.CommitOutput(filePath, GeneratedContentBuilder);
}
}
else
{
Factory.CommitOutput(filePath, GeneratedContentBuilder);
}
}
}
}
@@ -0,0 +1,50 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="CSharpParamDefaultValueMetas.ubtplugin.csproj.props" Condition="Exists('CSharpParamDefaultValueMetas.ubtplugin.csproj.props')" />
<Import Project="$(EngineDir)\Source\Programs\Shared\UnrealEngine.csproj.props" />
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Configuration Condition=" '$(Configuration)' == '' ">Development</Configuration>
<OutputType>Library</OutputType>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>
<Configurations>Debug;Release;Development</Configurations>
<RootNamespace>CSharpParamDefaultValueMetas</RootNamespace>
<AssemblyName>CSharpParamDefaultValueMetas</AssemblyName>
<OutputPath>..\..\..\..\Binaries\DotNET\UnrealBuildTool\Plugins\CSharpParamDefaultValueMetas\</OutputPath>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<DebugType>pdbonly</DebugType>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Development|AnyCPU' ">
<DefineConstants>$(DefineConstants);TRACE</DefineConstants>
<Optimize>true</Optimize>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DefineConstants>$(DefineConstants);TRACE</DefineConstants>
<Optimize>true</Optimize>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DefineConstants>$(DefineConstants);DEBUG;TRACE</DefineConstants>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
</ItemGroup>
<ItemGroup>
<Reference Include="EpicGames.Build">
<HintPath>$(EngineDir)\Binaries\DotNET\UnrealBuildTool\EpicGames.Build.dll</HintPath>
</Reference>
<Reference Include="EpicGames.Core">
<HintPath>$(EngineDir)\Binaries\DotNET\UnrealBuildTool\EpicGames.Core.dll</HintPath>
</Reference>
<Reference Include="EpicGames.UHT">
<HintPath>$(EngineDir)\Binaries\DotNET\UnrealBuildTool\EpicGames.UHT.dll</HintPath>
</Reference>
<Reference Include="UnrealBuildTool">
<HintPath>$(EngineDir)\Binaries\DotNET\UnrealBuildTool\UnrealBuildTool.dll</HintPath>
</Reference>
</ItemGroup>
</Project>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<EngineDir Condition="'$(EngineDir)' == ''">D:\MiceCola\UE_5.5\Engine</EngineDir>
</PropertyGroup>
</Project>
@@ -0,0 +1,93 @@
{
"format": 1,
"restore": {
"D:\\MiceCola\\MingSimulator\\Plugins\\Puerts\\Source\\CSharpParamDefaultValueMetas\\CSharpParamDefaultValueMetas.ubtplugin.csproj": {}
},
"projects": {
"D:\\MiceCola\\MingSimulator\\Plugins\\Puerts\\Source\\CSharpParamDefaultValueMetas\\CSharpParamDefaultValueMetas.ubtplugin.csproj": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "D:\\MiceCola\\MingSimulator\\Plugins\\Puerts\\Source\\CSharpParamDefaultValueMetas\\CSharpParamDefaultValueMetas.ubtplugin.csproj",
"projectName": "CSharpParamDefaultValueMetas",
"projectPath": "D:\\MiceCola\\MingSimulator\\Plugins\\Puerts\\Source\\CSharpParamDefaultValueMetas\\CSharpParamDefaultValueMetas.ubtplugin.csproj",
"packagesPath": "C:\\Users\\张青\\.nuget\\packages\\",
"outputPath": "D:\\MiceCola\\MingSimulator\\Plugins\\Puerts\\Source\\CSharpParamDefaultValueMetas\\obj\\",
"projectStyle": "PackageReference",
"fallbackFolders": [
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
],
"configFilePaths": [
"C:\\Users\\张青\\AppData\\Roaming\\NuGet\\NuGet.Config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
],
"originalTargetFrameworks": [
"net6.0"
],
"sources": {
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net6.0": {
"targetAlias": "net6.0",
"projectReferences": {}
}
},
"warningProperties": {
"allWarningsAsErrors": true,
"warnAsError": [
"NU1605"
]
},
"restoreAuditProperties": {
"enableAudit": "true",
"auditLevel": "low",
"auditMode": "direct"
}
},
"frameworks": {
"net6.0": {
"targetAlias": "net6.0",
"dependencies": {
"Microsoft.CSharp": {
"target": "Package",
"version": "[4.7.0, )"
}
},
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48",
"net481"
],
"assetTargetFallback": true,
"warn": true,
"downloadDependencies": [
{
"name": "Microsoft.AspNetCore.App.Ref",
"version": "[6.0.30, 6.0.30]"
},
{
"name": "Microsoft.NETCore.App.Ref",
"version": "[6.0.30, 6.0.30]"
},
{
"name": "Microsoft.WindowsDesktop.App.Ref",
"version": "[6.0.30, 6.0.30]"
}
],
"frameworkReferences": {
"Microsoft.NETCore.App": {
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "D:\\MiceCola\\UE_5.5\\Engine\\Binaries\\ThirdParty\\DotNet\\8.0.300\\win-x64\\sdk\\8.0.300\\RuntimeIdentifierGraph.json"
}
}
}
}
}
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\张青\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.10.0</NuGetToolVersion>
</PropertyGroup>
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<SourceRoot Include="C:\Users\张青\.nuget\packages\" />
<SourceRoot Include="C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages\" />
</ItemGroup>
</Project>
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" />
@@ -0,0 +1,15 @@
is_global = true
build_property.TargetFramework = net6.0
build_property.TargetPlatformMinVersion =
build_property.UsingMicrosoftNETSdkWeb =
build_property.ProjectTypeGuids =
build_property.InvariantGlobalization =
build_property.PlatformNeutralAssembly =
build_property.EnforceExtendedAnalyzerRules =
build_property._SupportedPlatformList = Linux,macOS,Windows
build_property.RootNamespace = CSharpParamDefaultValueMetas
build_property.ProjectDir = D:\MiceCola\MingSimulator\Plugins\Puerts\Source\CSharpParamDefaultValueMetas\
build_property.EnableComHosting =
build_property.EnableGeneratedComInterfaceComImportInterop =
build_property.EffectiveAnalysisLevelStyle = 6.0
build_property.EnableCodeStyleSeverity =
@@ -0,0 +1 @@
acfc2ce6c21e11e243f1beb848c668c5ad8317be9df7ed1ce1347befd4c57e75
@@ -0,0 +1,3 @@
D:\MiceCola\MingSimulator\Plugins\Puerts\Source\CSharpParamDefaultValueMetas\obj\Development\CSharpParamDefaultValueMetas.ubtplugin.csproj.AssemblyReference.cache
D:\MiceCola\MingSimulator\Plugins\Puerts\Source\CSharpParamDefaultValueMetas\obj\Development\CSharpParamDefaultValueMetas.ubtplugin.GeneratedMSBuildEditorConfig.editorconfig
D:\MiceCola\MingSimulator\Plugins\Puerts\Source\CSharpParamDefaultValueMetas\obj\Development\CSharpParamDefaultValueMetas.ubtplugin.csproj.CoreCompileInputs.cache
@@ -0,0 +1,181 @@
{
"version": 3,
"targets": {
"net6.0": {
"Microsoft.CSharp/4.7.0": {
"type": "package",
"compile": {
"ref/netcoreapp2.0/_._": {}
},
"runtime": {
"lib/netcoreapp2.0/_._": {}
}
}
}
},
"libraries": {
"Microsoft.CSharp/4.7.0": {
"sha512": "pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA==",
"type": "package",
"path": "microsoft.csharp/4.7.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"LICENSE.TXT",
"THIRD-PARTY-NOTICES.TXT",
"lib/MonoAndroid10/_._",
"lib/MonoTouch10/_._",
"lib/net45/_._",
"lib/netcore50/Microsoft.CSharp.dll",
"lib/netcoreapp2.0/_._",
"lib/netstandard1.3/Microsoft.CSharp.dll",
"lib/netstandard2.0/Microsoft.CSharp.dll",
"lib/netstandard2.0/Microsoft.CSharp.xml",
"lib/portable-net45+win8+wp8+wpa81/_._",
"lib/uap10.0.16299/_._",
"lib/win8/_._",
"lib/wp80/_._",
"lib/wpa81/_._",
"lib/xamarinios10/_._",
"lib/xamarinmac20/_._",
"lib/xamarintvos10/_._",
"lib/xamarinwatchos10/_._",
"microsoft.csharp.4.7.0.nupkg.sha512",
"microsoft.csharp.nuspec",
"ref/MonoAndroid10/_._",
"ref/MonoTouch10/_._",
"ref/net45/_._",
"ref/netcore50/Microsoft.CSharp.dll",
"ref/netcore50/Microsoft.CSharp.xml",
"ref/netcore50/de/Microsoft.CSharp.xml",
"ref/netcore50/es/Microsoft.CSharp.xml",
"ref/netcore50/fr/Microsoft.CSharp.xml",
"ref/netcore50/it/Microsoft.CSharp.xml",
"ref/netcore50/ja/Microsoft.CSharp.xml",
"ref/netcore50/ko/Microsoft.CSharp.xml",
"ref/netcore50/ru/Microsoft.CSharp.xml",
"ref/netcore50/zh-hans/Microsoft.CSharp.xml",
"ref/netcore50/zh-hant/Microsoft.CSharp.xml",
"ref/netcoreapp2.0/_._",
"ref/netstandard1.0/Microsoft.CSharp.dll",
"ref/netstandard1.0/Microsoft.CSharp.xml",
"ref/netstandard1.0/de/Microsoft.CSharp.xml",
"ref/netstandard1.0/es/Microsoft.CSharp.xml",
"ref/netstandard1.0/fr/Microsoft.CSharp.xml",
"ref/netstandard1.0/it/Microsoft.CSharp.xml",
"ref/netstandard1.0/ja/Microsoft.CSharp.xml",
"ref/netstandard1.0/ko/Microsoft.CSharp.xml",
"ref/netstandard1.0/ru/Microsoft.CSharp.xml",
"ref/netstandard1.0/zh-hans/Microsoft.CSharp.xml",
"ref/netstandard1.0/zh-hant/Microsoft.CSharp.xml",
"ref/netstandard2.0/Microsoft.CSharp.dll",
"ref/netstandard2.0/Microsoft.CSharp.xml",
"ref/portable-net45+win8+wp8+wpa81/_._",
"ref/uap10.0.16299/_._",
"ref/win8/_._",
"ref/wp80/_._",
"ref/wpa81/_._",
"ref/xamarinios10/_._",
"ref/xamarinmac20/_._",
"ref/xamarintvos10/_._",
"ref/xamarinwatchos10/_._",
"useSharedDesignerContext.txt",
"version.txt"
]
}
},
"projectFileDependencyGroups": {
"net6.0": [
"Microsoft.CSharp >= 4.7.0"
]
},
"packageFolders": {
"C:\\Users\\张青\\.nuget\\packages\\": {},
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages": {}
},
"project": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "D:\\MiceCola\\MingSimulator\\Plugins\\Puerts\\Source\\CSharpParamDefaultValueMetas\\CSharpParamDefaultValueMetas.ubtplugin.csproj",
"projectName": "CSharpParamDefaultValueMetas",
"projectPath": "D:\\MiceCola\\MingSimulator\\Plugins\\Puerts\\Source\\CSharpParamDefaultValueMetas\\CSharpParamDefaultValueMetas.ubtplugin.csproj",
"packagesPath": "C:\\Users\\张青\\.nuget\\packages\\",
"outputPath": "D:\\MiceCola\\MingSimulator\\Plugins\\Puerts\\Source\\CSharpParamDefaultValueMetas\\obj\\",
"projectStyle": "PackageReference",
"fallbackFolders": [
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
],
"configFilePaths": [
"C:\\Users\\张青\\AppData\\Roaming\\NuGet\\NuGet.Config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
],
"originalTargetFrameworks": [
"net6.0"
],
"sources": {
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net6.0": {
"targetAlias": "net6.0",
"projectReferences": {}
}
},
"warningProperties": {
"allWarningsAsErrors": true,
"warnAsError": [
"NU1605"
]
},
"restoreAuditProperties": {
"enableAudit": "true",
"auditLevel": "low",
"auditMode": "direct"
}
},
"frameworks": {
"net6.0": {
"targetAlias": "net6.0",
"dependencies": {
"Microsoft.CSharp": {
"target": "Package",
"version": "[4.7.0, )"
}
},
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48",
"net481"
],
"assetTargetFallback": true,
"warn": true,
"downloadDependencies": [
{
"name": "Microsoft.AspNetCore.App.Ref",
"version": "[6.0.30, 6.0.30]"
},
{
"name": "Microsoft.NETCore.App.Ref",
"version": "[6.0.30, 6.0.30]"
},
{
"name": "Microsoft.WindowsDesktop.App.Ref",
"version": "[6.0.30, 6.0.30]"
}
],
"frameworkReferences": {
"Microsoft.NETCore.App": {
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "D:\\MiceCola\\UE_5.5\\Engine\\Binaries\\ThirdParty\\DotNet\\8.0.300\\win-x64\\sdk\\8.0.300\\RuntimeIdentifierGraph.json"
}
}
}
}
@@ -0,0 +1,13 @@
{
"version": 2,
"dgSpecHash": "+l+ToRTRVP0=",
"success": true,
"projectFilePath": "D:\\MiceCola\\MingSimulator\\Plugins\\Puerts\\Source\\CSharpParamDefaultValueMetas\\CSharpParamDefaultValueMetas.ubtplugin.csproj",
"expectedPackageFiles": [
"C:\\Users\\张青\\.nuget\\packages\\microsoft.csharp\\4.7.0\\microsoft.csharp.4.7.0.nupkg.sha512",
"C:\\Users\\张青\\.nuget\\packages\\microsoft.netcore.app.ref\\6.0.30\\microsoft.netcore.app.ref.6.0.30.nupkg.sha512",
"C:\\Users\\张青\\.nuget\\packages\\microsoft.windowsdesktop.app.ref\\6.0.30\\microsoft.windowsdesktop.app.ref.6.0.30.nupkg.sha512",
"C:\\Users\\张青\\.nuget\\packages\\microsoft.aspnetcore.app.ref\\6.0.30\\microsoft.aspnetcore.app.ref.6.0.30.nupkg.sha512"
],
"logs": []
}
@@ -0,0 +1,60 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may be subject to their corresponding license terms.
* This file is subject to the terms and conditions defined in file 'LICENSE', which is part of this source code package.
*/
using System;
using System.IO;
using UnrealBuildTool;
public class DeclarationGenerator : ModuleRules
{
public DeclarationGenerator(ReadOnlyTargetRules Target) : base(Target)
{
PublicIncludePaths.AddRange(
new string[] {
"Programs/UnrealHeaderTool/Public",
}
);
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"CoreUObject",
"UMG",
"UnrealEd",
"LevelEditor",
"Engine",
"Slate",
"SlateCore",
"EditorStyle",
"InputCore",
"Projects",
"JsEnv",
"Puerts",
#if UE_5_0_OR_LATER
"ToolMenus",
#endif
}
);
if (Target.Platform == UnrealTargetPlatform.Win64 ||Target.Platform == UnrealTargetPlatform.Mac)
{
PublicDependencyModuleNames.AddRange(
new string[]
{
"AssetRegistry"
}
);
}
if (JsEnv.WithSourceControl)
{
PrivateDependencyModuleNames.Add("PuertsEditor");
}
//PublicDefinitions.Add(string.Format("DECL_OUTPUT_PATH={0}", Path.GetFullPath(Path.Combine(ModuleDirectory, "..", "..", "Content", "Scripts"))));
}
}
@@ -0,0 +1,10 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "CodeGenerator.h"
// Add default functionality here for any ICodeGenerator functions that are not pure virtual.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,8 @@
// gen by puerts gen tools
auto SName = Struct -> GetName();
if (SName == "IntVector" || SName == "Color" || SName == "Quat" || SName == "Vector2D" || SName == "Vector4" ||
SName == "Transform" || SName == "LinearColor" || SName == "Box2D" || SName == "Vector" || SName == "IntPoint" ||
SName == "Rotator" || SName == "Guid")
{
return;
}
@@ -0,0 +1,19 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "GenDTSCommands.h"
#define LOCTEXT_NAMESPACE "FGenDTSModule"
void FGenDTSCommands::RegisterCommands()
{
UI_COMMAND(
PluginAction, "puerts", "Generate *.d.ts and copy some js builtin libs", EUserInterfaceActionType::Button, FInputChord());
}
#undef LOCTEXT_NAMESPACE
@@ -0,0 +1,76 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "GenDTSStyle.h"
#include "Framework/Application/SlateApplication.h"
#include "Styling/SlateStyleRegistry.h"
#include "Slate/SlateGameResources.h"
#include "Interfaces/IPluginManager.h"
TSharedPtr<FSlateStyleSet> FGenDTSStyle::StyleInstance = NULL;
void FGenDTSStyle::Initialize()
{
if (!StyleInstance.IsValid())
{
StyleInstance = Create();
FSlateStyleRegistry::RegisterSlateStyle(*StyleInstance);
}
}
void FGenDTSStyle::Shutdown()
{
FSlateStyleRegistry::UnRegisterSlateStyle(*StyleInstance);
ensure(StyleInstance.IsUnique());
StyleInstance.Reset();
}
FName FGenDTSStyle::GetStyleSetName()
{
static FName StyleSetName(TEXT("GenDTSStyle"));
return StyleSetName;
}
#define IMAGE_BRUSH(RelativePath, ...) FSlateImageBrush(Style->RootToContentDir(RelativePath, TEXT(".png")), __VA_ARGS__)
#define BOX_BRUSH(RelativePath, ...) FSlateBoxBrush(Style->RootToContentDir(RelativePath, TEXT(".png")), __VA_ARGS__)
#define BORDER_BRUSH(RelativePath, ...) FSlateBorderBrush(Style->RootToContentDir(RelativePath, TEXT(".png")), __VA_ARGS__)
#define TTF_FONT(RelativePath, ...) FSlateFontInfo(Style->RootToContentDir(RelativePath, TEXT(".ttf")), __VA_ARGS__)
#define OTF_FONT(RelativePath, ...) FSlateFontInfo(Style->RootToContentDir(RelativePath, TEXT(".otf")), __VA_ARGS__)
const FVector2D Icon16x16(16.0f, 16.0f);
const FVector2D Icon20x20(20.0f, 20.0f);
const FVector2D Icon40x40(40.0f, 40.0f);
TSharedRef<FSlateStyleSet> FGenDTSStyle::Create()
{
TSharedRef<FSlateStyleSet> Style = MakeShareable(new FSlateStyleSet("GenDTSStyle"));
Style->SetContentRoot(IPluginManager::Get().FindPlugin("Puerts")->GetBaseDir() / TEXT("Resources"));
Style->Set("GenDTS.PluginAction", new IMAGE_BRUSH(TEXT("ButtonIcon_40x"), Icon40x40));
return Style;
}
#undef IMAGE_BRUSH
#undef BOX_BRUSH
#undef BORDER_BRUSH
#undef TTF_FONT
#undef OTF_FONT
void FGenDTSStyle::ReloadTextures()
{
if (FSlateApplication::IsInitialized())
{
FSlateApplication::Get().GetRenderer()->ReloadTextureResources();
}
}
const ISlateStyle& FGenDTSStyle::Get()
{
return *StyleInstance;
}
@@ -0,0 +1,208 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "TemplateBindingGenerator.h"
#include "JSClassRegister.h"
#include "Interfaces/IPluginManager.h"
#include "CoreUObject.h"
#ifdef PUERTS_WITH_SOURCE_CONTROL
#include "FileSystemOperation.h"
#endif
struct FGenImp
{
FStringBuffer Output{"", ""};
FString GetNamePrefix(const PUERTS_NAMESPACE::CTypeInfo* TypeInfo)
{
return TypeInfo->IsUEType() && !HadNamespace(TypeInfo->Name()) ? "UE." : "";
}
FString GetName(const PUERTS_NAMESPACE::CTypeInfo* TypeInfo)
{
return UTF8_TO_TCHAR(TypeInfo->Name());
}
void Begin()
{
Output << "declare module \"cpp\" {\n";
Output << " import * as UE from \"ue\"\n";
Output << " import * as cpp from \"cpp\"\n";
Output << " import {$Ref, $Nullable, cstring} from \"puerts\"\n\n";
}
void GenArguments(const PUERTS_NAMESPACE::CFunctionInfo* Type, FStringBuffer& Buff)
{
for (unsigned int i = 0; i < Type->ArgumentCount(); i++)
{
if (i != 0)
Buff << ", ";
auto argInfo = Type->Argument(i);
Buff << FString::Printf(TEXT("p%d"), i);
if (i >= Type->ArgumentCount() - Type->DefaultCount())
{
Buff << "?";
}
Buff << ": ";
if (strcmp(argInfo->Name(), "cstring") != 0 && !argInfo->IsUEType() && !argInfo->IsObjectType() && argInfo->IsPointer())
{
Buff << "ArrayBuffer";
}
else
{
bool IsReference = argInfo->IsRef();
bool IsNullable = !IsReference && argInfo->IsPointer();
if (IsNullable)
{
Buff << "$Nullable<";
}
if (IsReference)
{
Buff << "$Ref<";
}
const PUERTS_NAMESPACE::CTypeInfo* TypeInfo = Type->Argument(i);
Buff << GetNamePrefix(TypeInfo) << GetName(TypeInfo);
if (IsNullable)
{
Buff << ">";
}
if (IsReference)
{
Buff << ">";
}
}
}
}
void GenClass(const PUERTS_NAMESPACE::JSClassDefinition* ClassDefinition)
{
if (HasUENamespace(ClassDefinition->ScriptName))
return;
Output << " class " << ClassDefinition->ScriptName;
if (ClassDefinition->SuperTypeId)
{
Output << " extends " << PUERTS_NAMESPACE::FindClassByID(ClassDefinition->SuperTypeId)->ScriptName;
}
Output << " {\n";
TSet<FString> AddedFunctions;
PUERTS_NAMESPACE::NamedFunctionInfo* ConstructorInfo = ClassDefinition->ConstructorInfos;
while (ConstructorInfo && ConstructorInfo->Name && ConstructorInfo->Type)
{
FStringBuffer Tmp;
Tmp << " constructor(";
GenArguments(ConstructorInfo->Type, Tmp);
Tmp << ");\n";
if (!AddedFunctions.Contains(Tmp.Buffer))
{
AddedFunctions.Add(Tmp.Buffer);
Output << Tmp;
}
++ConstructorInfo;
}
PUERTS_NAMESPACE::NamedPropertyInfo* PropertyInfo = ClassDefinition->PropertyInfos;
while (PropertyInfo && PropertyInfo->Name && PropertyInfo->Type)
{
Output << " " << PropertyInfo->Name << ": " << GetNamePrefix(PropertyInfo->Type) << PropertyInfo->Type->Name()
<< ";\n";
++PropertyInfo;
}
PUERTS_NAMESPACE::NamedPropertyInfo* VariableInfo = ClassDefinition->VariableInfos;
while (VariableInfo && VariableInfo->Name && VariableInfo->Type)
{
int Pos = VariableInfo - ClassDefinition->VariableInfos;
Output << " static " << (ClassDefinition->Variables[Pos].Setter ? "" : "readonly ") << VariableInfo->Name << ": "
<< GetNamePrefix(VariableInfo->Type) << VariableInfo->Type->Name() << ";\n";
++VariableInfo;
}
PUERTS_NAMESPACE::NamedFunctionInfo* FunctionInfo = ClassDefinition->FunctionInfos;
while (FunctionInfo && FunctionInfo->Name && FunctionInfo->Type)
{
FStringBuffer Tmp;
Tmp << " static " << FunctionInfo->Name;
if (FunctionInfo->Type->Return())
{
Tmp << "(";
GenArguments(FunctionInfo->Type, Tmp);
const PUERTS_NAMESPACE::CTypeInfo* ReturnType = FunctionInfo->Type->Return();
Tmp << ") :" << GetNamePrefix(ReturnType) << GetName(ReturnType) << ";\n";
}
else
{
Tmp << FunctionInfo->Type->CustomSignature() << ";\n";
}
if (!AddedFunctions.Contains(Tmp.Buffer))
{
AddedFunctions.Add(Tmp.Buffer);
Output << Tmp;
}
++FunctionInfo;
}
PUERTS_NAMESPACE::NamedFunctionInfo* MethodInfo = ClassDefinition->MethodInfos;
while (MethodInfo && MethodInfo->Name && MethodInfo->Type)
{
FStringBuffer Tmp;
Tmp << " " << MethodInfo->Name;
if (MethodInfo->Type->Return())
{
Tmp << "(";
GenArguments(MethodInfo->Type, Tmp);
const PUERTS_NAMESPACE::CTypeInfo* ReturnType = MethodInfo->Type->Return();
Tmp << ") :" << GetNamePrefix(ReturnType) << GetName(ReturnType) << ";\n";
}
else
{
Tmp << MethodInfo->Type->CustomSignature() << ";\n";
}
if (!AddedFunctions.Contains(Tmp.Buffer))
{
AddedFunctions.Add(Tmp.Buffer);
Output << Tmp;
}
++MethodInfo;
}
Output << " }\n\n";
}
void End()
{
Output << "}\n";
}
};
void UTemplateBindingGenerator::Gen_Implementation() const
{
FGenImp Gen;
Gen.Begin();
PUERTS_NAMESPACE::ForeachRegisterClass(
[&](const PUERTS_NAMESPACE::JSClassDefinition* ClassDefinition)
{
if (ClassDefinition->TypeId && ClassDefinition->ScriptName)
{
Gen.GenClass(ClassDefinition);
}
});
Gen.End();
const FString FilePath = FPaths::ProjectDir() / TEXT("Typing/cpp/index.d.ts");
#ifdef PUERTS_WITH_SOURCE_CONTROL
PuertsSourceControlUtils::MakeSourceControlFileWritable(FilePath);
#endif
FFileHelper::SaveStringToFile(Gen.Output.Buffer, *FilePath, FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM);
}
@@ -0,0 +1,27 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "CodeGenerator.generated.h"
// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UCodeGenerator : public UInterface
{
GENERATED_BODY()
};
/**
*
*/
class DECLARATIONGENERATOR_API ICodeGenerator
{
GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
UFUNCTION(BlueprintNativeEvent)
void Gen() const;
};
@@ -0,0 +1,29 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include "CoreMinimal.h"
#include "Framework/Commands/Commands.h"
#include "GenDTSStyle.h"
class FGenDTSCommands : public TCommands<FGenDTSCommands>
{
public:
FGenDTSCommands()
: TCommands<FGenDTSCommands>(
TEXT("GenDTS"), NSLOCTEXT("Contexts", "GenDTS", "GenDTS Plugin"), NAME_None, FGenDTSStyle::GetStyleSetName())
{
}
// TCommands<> interface
void RegisterCommands() override;
public:
TSharedPtr<FUICommandInfo> PluginAction;
};
@@ -0,0 +1,34 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include "CoreMinimal.h"
#include "Styling/SlateStyle.h"
class FGenDTSStyle
{
public:
static void Initialize();
static void Shutdown();
/** reloads textures used by slate renderer */
static void ReloadTextures();
/** @return The Slate style set for the Shooter game */
static const ISlateStyle& Get();
static FName GetStyleSetName();
private:
static TSharedRef<class FSlateStyleSet> Create();
private:
static TSharedPtr<class FSlateStyleSet> StyleInstance;
};
@@ -0,0 +1,32 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include <cstdio>
#include "Modules/ModuleManager.h"
#include "CoreMinimal.h"
class IDeclarationGenerator : public IModuleInterface //: public IScriptGeneratorPluginInterface
{
public:
static inline IDeclarationGenerator& Get()
{
return FModuleManager::LoadModuleChecked<IDeclarationGenerator>("DeclarationGenerator");
}
static inline bool IsAvailable()
{
return FModuleManager::Get().IsModuleLoaded("DeclarationGenerator");
}
virtual void GenTypeScriptDeclaration(bool InGenFull, FName InSearchPath) = 0;
virtual void GenReactDeclaration() = 0;
};
@@ -0,0 +1,25 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CodeGenerator.h"
#include "TypeScriptDeclarationGenerator.h"
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "TemplateBindingGenerator.generated.h"
/**
*
*/
UCLASS()
class DECLARATIONGENERATOR_API UTemplateBindingGenerator : public UObject, public ICodeGenerator
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintNativeEvent)
void Gen() const;
virtual void Gen_Implementation() const override;
};
@@ -0,0 +1,135 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include <map>
#include <vector>
#include "PropertyMacros.h"
struct DECLARATIONGENERATOR_API FStringBuffer
{
FString Buffer;
FString Prefix;
FStringBuffer& operator<<(const FString& InText);
FStringBuffer& operator<<(const TCHAR* InText);
FStringBuffer& operator<<(const char* InText);
FStringBuffer& operator<<(const FStringBuffer& Other);
void Indent(int Num);
};
struct DECLARATIONGENERATOR_API FTypeScriptDeclarationGenerator
{
FStringBuffer Output{"", ""};
TSet<UObject*> Processed;
TSet<FString> ProcessedByName;
std::map<UStruct*, std::vector<UFunction*>> ExtensionMethodsMap;
struct FunctionKey
{
FunctionKey(const FString& InFunctioName, bool InIsStatic) : FunctionName(InFunctioName), IsStatic(InIsStatic)
{
}
bool operator<(const FunctionKey& other) const
{
return IsStatic != other.IsStatic ? IsStatic < other.IsStatic : FunctionName < other.FunctionName;
}
FString FunctionName;
bool IsStatic;
};
typedef TArray<FString> FunctionOverloads;
typedef std::map<FunctionKey, FunctionOverloads> FunctionOutputs;
std::map<UStruct*, FunctionOutputs> AllFuncionOutputs;
std::map<UObject*, FString> NamespaceMap;
std::map<UObject*, bool> PathIsValidMap;
struct BlueprintTypeDeclInfo
{
TMap<FName, FString> NameToDecl;
FString FileVersionString;
bool IsExist;
bool Changed;
bool IsAssociation;
};
TMap<FName, BlueprintTypeDeclInfo> BlueprintTypeDeclInfoCache;
TArray<FAssetData> AssetList;
bool RefFromOuter = false;
bool BeginGenAssetData = false;
const FString& GetNamespace(UObject* Obj);
FString GetNameWithNamespace(UObject* Obj);
void NamespaceBegin(UObject* Obj, FStringBuffer& Buff);
void NamespaceEnd(UObject* Obj, FStringBuffer& Buff);
void WriteOutput(UObject* Obj, const FStringBuffer& Buff);
void RestoreBlueprintTypeDeclInfos(bool InGenFull);
void RestoreBlueprintTypeDeclInfos(const FString& FileContent, bool InGenFull);
void LoadAllWidgetBlueprint(FName InSearchPath, bool InGenFull);
void InitExtensionMethodsMap();
virtual void Begin(FString Namespace = TEXT("ue"));
void GenTypeScriptDeclaration(bool InGenStruct, bool InGenEnum);
virtual void Gen(UObject* ToGen);
virtual bool GenTypeDecl(FStringBuffer& StringBuffer, PropertyMacro* Property, TArray<UObject*>& AddToGen,
bool ArrayDimProcessed = false, bool TreatAsRawFunction = false);
virtual bool GenFunction(FStringBuffer& OwnerBuffer, UFunction* Function, bool WithName = true, bool ForceOneway = false,
bool IgnoreOut = false, bool IsExtensionMethod = false);
void GatherExtensions(UStruct* Struct, FStringBuffer& Buff);
void GenResolvedFunctions(UStruct* Struct, FStringBuffer& Buff);
FunctionOutputs& GetFunctionOutputs(UStruct* Struct);
FunctionOverloads& GetFunctionOverloads(FunctionOutputs& Outputs, const FString& FunctionName, bool IsStatic);
void TryToAddOverload(FunctionOutputs& Outputs, const FString& FunctionName, bool IsStatic, const FString& Overload);
virtual void GenClass(UClass* Class);
virtual void GenEnum(UEnum* Enum);
virtual void GenStruct(UStruct* Struct);
virtual void End();
FString ToString();
virtual ~FTypeScriptDeclarationGenerator()
{
}
};
bool HasUENamespace(const char* name);
bool HadNamespace(const char* name);
+737
View File
@@ -0,0 +1,737 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may be subject to their corresponding license terms.
* This file is subject to the terms and conditions defined in file 'LICENSE', which is part of this source code package.
*/
using System.Collections.Generic;
using UnrealBuildTool;
using System.IO;
using System.Reflection;
public class JsEnv : ModuleRules
{
enum SupportedV8Versions
{
VDeprecated, // for 4.24 or blow only
V8_4_371_19,
V9_4_146_24,
V10_6_194,
V11_8_172
}
private SupportedV8Versions UseV8Version =
#if UE_4_25_OR_LATER
SupportedV8Versions.V9_4_146_24;
#else
SupportedV8Versions.VDeprecated;
#endif
private bool UseNodejs = false;
private bool Node16 = true;
private bool UseQuickjs = false;
private bool QjsNamespaceSuffix = false;
private bool WithFFI = false;
private bool ForceStaticLibInEditor = false;
private bool ThreadSafe = false;
private bool FTextAsString = true;
private bool bEditorSuffix = true;
// v8 9.4+
private bool SingleThreaded = false;
public static bool WithSourceControl = false;
public bool WithByteCode = false;
private bool WithWebsocket = false;
public JsEnv(ReadOnlyTargetRules Target) : base(Target)
{
PublicDefinitions.Add("USING_IN_UNREAL_ENGINE");
//PublicDefinitions.Add("WITH_V8_FAST_CALL");
PublicDefinitions.Add("TS_BLUEPRINT_PATH=\"/Blueprints/TypeScript/\"");
PublicDefinitions.Add(ThreadSafe ? "THREAD_SAFE" : "NOT_THREAD_SAFE");
if (bEditorSuffix)
{
PublicDefinitions.Add("PUERTS_WITH_EDITOR_SUFFIX");
}
if (WithWebsocket)
{
PublicDefinitions.Add("WITH_WEBSOCKET");
PublicDefinitions.Add("WITH_WEBSOCKET_SSL");
PublicDependencyModuleNames.Add("OpenSSL");
}
ShadowVariableWarningLevel = WarningLevel.Warning;
if (!FTextAsString)
{
PublicDefinitions.Add("PUERTS_FTEXT_AS_OBJECT");
}
PublicDependencyModuleNames.AddRange(new string[]
{
"Core", "CoreUObject", "Engine", "ParamDefaultValueMetas", "UMG"
});
if (Target.bBuildEditor)
{
PublicDependencyModuleNames.AddRange(new string[] { "DirectoryWatcher", });
}
bEnableExceptions = true;
var ContextField = GetType().GetField("Context", BindingFlags.Instance | BindingFlags.NonPublic);
if (ContextField != null)
{
var bCanHotReloadField = ContextField.FieldType.GetField("bCanHotReload", BindingFlags.Instance | BindingFlags.Public);
if (bCanHotReloadField != null)
{
bCanHotReloadField.SetValue(ContextField.GetValue(this), false);
}
}
bool bForceAllUFunctionInCPP = false;
if (bForceAllUFunctionInCPP)
{
PublicDefinitions.Add("PUERTS_FORCE_CPP_UFUNCTION=1");
}
else
{
PublicDefinitions.Add("PUERTS_FORCE_CPP_UFUNCTION=0");
}
bool bKeepUObjectReference = true;
if(bKeepUObjectReference)
{
PublicDefinitions.Add("PUERTS_KEEP_UOBJECT_REFERENCE=1");
}
else
{
PublicDefinitions.Add("PUERTS_KEEP_UOBJECT_REFERENCE=0");
}
bool UseWasm = false;
if (UseWasm)
{
PublicDefinitions.Add("USE_WASM3=1");
}
else
{
PublicDefinitions.Add("USE_WASM3=0");
}
bool OverrideWebAssembly = false;
if (OverrideWebAssembly)
{
PublicDefinitions.Add("WASM3_OVERRIDE_WEBASSEMBLY=1");
}
else
{
PublicDefinitions.Add("WASM3_OVERRIDE_WEBASSEMBLY=0");
}
PublicDependencyModuleNames.AddRange(new string[]
{
"WasmCore", "Json"
});
if (UseNodejs)
{
ThirdPartyNodejs(Target);
}
else if (UseQuickjs)
{
ForceStaticLibInEditor = true;
ThirdPartyQJS(Target);
}
else if (UseV8Version > SupportedV8Versions.VDeprecated)
{
ThirdParty(Target);
}
else
{
OldThirdParty(Target);
}
if (WithFFI) AddFFI(Target);
string coreJSPath = Path.GetFullPath(Path.Combine(ModuleDirectory, "..", "..", "Content"));
string destDirName = Path.GetFullPath(Path.Combine(ModuleDirectory, "..", "..", "..", "..", "Content"));
DirectoryCopy(coreJSPath, destDirName, true);
}
void OldThirdParty(ReadOnlyTargetRules Target)
{
string LibraryPath = Path.GetFullPath(Path.Combine(ModuleDirectory, "..", "..", "ThirdParty", "v8_for_ue424_or_below", "Lib"));
if (Target.Platform == UnrealTargetPlatform.Win64)
{
//if (Target.bBuildEditor)
//{
// WinDll(Path.Combine(LibraryPath, "V8"));
//}
//else
{
string V8LibraryPath = Path.Combine(LibraryPath, "Win64");
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "encoding.lib"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "inspector.lib"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "inspector_string_conversions.lib"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "v8_base_without_compiler_0.lib"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "v8_base_without_compiler_1.lib"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "v8_compiler.lib"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "v8_external_snapshot.lib"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "v8_libbase.lib"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "v8_libplatform.lib"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "v8_libsampler.lib"));
}
}
else if (Target.Platform == UnrealTargetPlatform.Android)
{
if (Target.Version.MajorVersion == 4 && Target.Version.MinorVersion >= 25)
{
// for arm7
string V8LibraryPath = Path.Combine(LibraryPath, "Android", "armeabi-v7a", "8.4.371.19");
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libwee8.a"));
// for arm64
V8LibraryPath = Path.Combine(LibraryPath, "V8", "Android", "arm64-v8a", "8.4.371.19");
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libwee8.a"));
}
else if (Target.Version.MajorVersion == 4 && Target.Version.MinorVersion < 25 && Target.Version.MinorVersion >= 22)
{
// for arm7
string V8LibraryPath = Path.Combine(LibraryPath, "Android", "armeabi-v7a", "7.4.288");
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libinspector.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_base.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_external_snapshot.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_libbase.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_libplatform.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_libsampler.a"));
// for arm64
V8LibraryPath = Path.Combine(LibraryPath, "Android", "arm64-v8a", "7.4.288");
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libinspector.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_base.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_external_snapshot.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_libbase.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_libplatform.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_libsampler.a"));
}
#if !UE_4_22_OR_LATER
else if (Target.Version.MajorVersion == 4 && Target.Version.MinorVersion < 22)
{
string V8LibraryPath = Path.Combine(LibraryPath, "Android", "armeabi-v7a", "7.4.288");
PublicLibraryPaths.Add(V8LibraryPath);
V8LibraryPath = Path.Combine(LibraryPath, "Android", "arm64-v8a", "7.4.288");
PublicLibraryPaths.Add(V8LibraryPath);
PublicAdditionalLibraries.Add("inspector");
PublicAdditionalLibraries.Add("v8_base");
PublicAdditionalLibraries.Add("v8_external_snapshot");
PublicAdditionalLibraries.Add("v8_libbase");
PublicAdditionalLibraries.Add("v8_libplatform");
PublicAdditionalLibraries.Add("v8_libsampler");
}
#endif
}
else if (Target.Platform == UnrealTargetPlatform.Mac)
{
// PublicFrameworks.AddRange(new string[] { "WebKit", "JavaScriptCore" });
PublicFrameworks.AddRange(new string[] { "WebKit" });
string V8LibraryPath = Path.Combine(LibraryPath, "macOS");
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libbindings.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libencoding.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libinspector.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libinspector_string_conversions.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libtorque_base.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libtorque_generated_definitions.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libtorque_generated_initializers.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_base_without_compiler.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_compiler.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_external_snapshot.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_init.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_initializers.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_libbase.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_libplatform.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_libsampler.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_nosnapshot.a"));
}
else if (Target.Platform == UnrealTargetPlatform.IOS)
{
PublicFrameworks.AddRange(new string[] { "WebKit" });
string V8LibraryPath = Path.Combine(LibraryPath, "iOS", "arm64");
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libbindings.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libencoding.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libinspector.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libinspector_string_conversions.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libtorque_generated_definitions.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_base_without_compiler.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_compiler.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_external_snapshot.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_libbase.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_libplatform.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_libsampler.a"));
//PublicAdditionalLibraries.Add(Path.Combine(Path.Combine(LibraryPath, "ffi", "iOS"), "libffi.a"));
}
else if (Target.Platform == UnrealTargetPlatform.Linux)
{
string V8LibraryPath = Path.Combine(LibraryPath, "Linux");
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libwee8.a"));
}
string V8HeaderPath = Path.GetFullPath(Path.Combine(ModuleDirectory, "..", "..", "ThirdParty", "v8_for_ue424_or_below", "Inc"));
// External headers
if (Target.Platform == UnrealTargetPlatform.Android)
{
if (Target.Version.MajorVersion == 4 && Target.Version.MinorVersion >= 25)
{
PublicIncludePaths.AddRange(new string[] { Path.Combine(V8HeaderPath, "8.4.371.19") });
}
else if (Target.Version.MajorVersion == 4 && Target.Version.MinorVersion < 25)
{
PublicIncludePaths.AddRange(new string[] { Path.Combine(V8HeaderPath, "7.4.288") });
}
}
//else if (Target.bBuildEditor && Target.Platform == UnrealTargetPlatform.Win64)
//{
// PublicIncludePaths.AddRange(new string[] { Path.Combine(HeaderPath, "8.4.371.19") });
//}
else if (Target.Platform == UnrealTargetPlatform.Win64 ||
Target.Platform == UnrealTargetPlatform.IOS ||
Target.Platform == UnrealTargetPlatform.Mac ||
Target.Platform == UnrealTargetPlatform.Linux)
{
PublicIncludePaths.AddRange(new string[] { Path.Combine(V8HeaderPath, "7.7.299") });
}
string HeaderPath = Path.GetFullPath(Path.Combine(ModuleDirectory, "..", "..", "ThirdParty", "Include"));
PublicIncludePaths.AddRange(new string[] { Path.Combine(HeaderPath, "websocketpp") });
PublicIncludePaths.AddRange(new string[] { Path.Combine(HeaderPath, "asio") });
}
void AddFFI(ReadOnlyTargetRules Target)
{
string HeaderPath = Path.GetFullPath(Path.Combine(ModuleDirectory, "..", "..", "ThirdParty", "Include"));
string LibraryPath = Path.GetFullPath(Path.Combine(ModuleDirectory, "..", "..", "ThirdParty", "Library"));
if (Target.Platform == UnrealTargetPlatform.Win64)
{
PublicIncludePaths.AddRange(new string[] {Path.Combine(HeaderPath, "ffi", "Win64")});
PublicAdditionalLibraries.Add(Path.Combine(LibraryPath, "ffi", "Win64", "ffi.lib"));
}
else if (Target.Platform == UnrealTargetPlatform.Mac)
{
PublicIncludePaths.AddRange(new string[] {Path.Combine(HeaderPath, "ffi", "macOS")});
PublicAdditionalLibraries.Add(Path.Combine(LibraryPath, "ffi", "macOS", "libffi.a"));
}
else if (Target.Platform == UnrealTargetPlatform.IOS)
{
PublicIncludePaths.AddRange(new string[] {Path.Combine(HeaderPath, "ffi", "iOS")});
PublicAdditionalLibraries.Add(Path.Combine(LibraryPath, "ffi", "iOS", "libffi.a"));
}
else if (Target.Platform == UnrealTargetPlatform.Android)
{
PublicIncludePaths.AddRange(new string[] {Path.Combine(HeaderPath, "ffi", "Android")});
PublicAdditionalLibraries.Add(Path.Combine(LibraryPath, "ffi", "Android", "armeabi-v7a", "libffi.a"));
PublicAdditionalLibraries.Add(Path.Combine(LibraryPath, "ffi", "Android", "arm64-v8a", "libffi.a"));
}
PrivateDefinitions.Add("WITH_FFI");
}
void AddRuntimeDependencies(string[] DllNames, string LibraryPath, bool Delay)
{
foreach (var DllName in DllNames)
{
if(Delay) PublicDelayLoadDLLs.Add(DllName);
var DllPath = Path.Combine(LibraryPath, DllName);
var DestDllPath = Path.Combine("$(BinaryOutputDir)", DllName);
RuntimeDependencies.Add(DestDllPath, DllPath, StagedFileType.NonUFS);
}
}
void WinDll(string LibraryPath)
{
string V8LibraryPath = Path.Combine(LibraryPath, "Win64DLL");
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "v8.dll.lib"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "v8_libplatform.dll.lib"));
List<string> deps = new List<string> {
"v8.dll",
"v8_libplatform.dll",
"v8_libbase.dll"
};
deps.Add(UseV8Version == SupportedV8Versions.V11_8_172 ? "third_party_zlib.dll" : "zlib.dll");
AddRuntimeDependencies(deps.ToArray(), V8LibraryPath, false);
}
void MacDylib(string LibraryPath)
{
PublicAdditionalLibraries.Add(Path.Combine(LibraryPath, "libv8.dylib"));
PublicAdditionalLibraries.Add(Path.Combine(LibraryPath, "libv8_libplatform.dylib"));
PublicAdditionalLibraries.Add(Path.Combine(LibraryPath, "libv8_libbase.dylib"));
PublicAdditionalLibraries.Add(Path.Combine(LibraryPath, "libchrome_zlib.dylib"));
if (UseV8Version == SupportedV8Versions.V11_8_172)
{
PublicAdditionalLibraries.Add(Path.Combine(LibraryPath, "libthird_party_abseil-cpp_absl.dylib"));
}
}
void ThirdParty(ReadOnlyTargetRules Target)
{
if (SingleThreaded)
{
PrivateDefinitions.Add("USING_SINGLE_THREAD_PLATFORM");
}
if (WithByteCode)
{
PrivateDefinitions.Add("WITH_V8_BYTECODE");
}
string v8LibSuffix = "";
if (UseV8Version == SupportedV8Versions.V8_4_371_19)
{
if(Directory.Exists(Path.Combine(ModuleDirectory, "..", "..", "ThirdParty", "v8_8.4.371.19")))
{
v8LibSuffix = "_8.4.371.19";
}
}
else if (UseV8Version == SupportedV8Versions.V9_4_146_24)
{
v8LibSuffix = "_9.4.146.24";
}
else if (UseV8Version == SupportedV8Versions.V10_6_194)
{
v8LibSuffix = "_10.6.194";
}
else if (UseV8Version == SupportedV8Versions.V11_8_172)
{
#if !UE_5_0_OR_LATER
CppStandard = CppStandardVersion.Cpp17;
#endif
v8LibSuffix = "_11.8.172";
}
//Add header
string HeaderPath = Path.GetFullPath(Path.Combine(ModuleDirectory, "..", "..", "ThirdParty", "Include"));
PublicIncludePaths.AddRange(new string[] { Path.Combine(HeaderPath, "websocketpp") });
PublicIncludePaths.AddRange(new string[] { Path.Combine(HeaderPath, "asio") });
PublicIncludePaths.AddRange(new string[] { Path.Combine(ModuleDirectory, "..", "..", "ThirdParty", "v8" + v8LibSuffix, "Inc") });
string LibraryPath = Path.GetFullPath(Path.Combine(ModuleDirectory, "..", "..", "ThirdParty", "v8" + v8LibSuffix, "Lib"));
if (Target.Platform == UnrealTargetPlatform.Win64)
{
if (!Target.bBuildEditor || ForceStaticLibInEditor)
{
string V8LibraryPath = Path.Combine(LibraryPath, "Win64MD");
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "wee8.lib"));
}
else
{
WinDll(LibraryPath);
}
}
else if (Target.Platform == UnrealTargetPlatform.Android)
{
string V8LibraryPath = Path.Combine(LibraryPath, "Android", "armeabi-v7a");
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libwee8.a"));
V8LibraryPath = Path.Combine(LibraryPath, "Android", "arm64-v8a");
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libwee8.a"));
}
else if (Target.Platform == UnrealTargetPlatform.Mac)
{
//PublicFrameworks.AddRange(new string[] { "WebKit", "JavaScriptCore" });
//PublicFrameworks.AddRange(new string[] { "WebKit" });
if (!Target.bBuildEditor || ForceStaticLibInEditor)
{
LibraryPath = Path.Combine(LibraryPath, "macOS");
#if UE_5_2_OR_LATER
if (Target.Architecture == UnrealArch.Arm64)
{
LibraryPath += "_arm64";
}
#endif
PublicAdditionalLibraries.Add(Path.Combine(LibraryPath, "libwee8.a"));
}
else
{
LibraryPath = Path.Combine(LibraryPath, "macOSdylib");
#if UE_5_2_OR_LATER
if (Target.Architecture == UnrealArch.Arm64)
{
LibraryPath += "_arm64";
}
#endif
MacDylib(LibraryPath);
}
}
else if (Target.Platform == UnrealTargetPlatform.IOS)
{
PublicFrameworks.AddRange(new string[] { "WebKit" });
string V8LibraryPath = Path.Combine(LibraryPath, "iOS", "arm64");
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libwee8.a"));
}
else if (Target.Platform == UnrealTargetPlatform.Linux)
{
string V8LibraryPath = Path.Combine(LibraryPath, "Linux");
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libwee8.a"));
}
if (ForceStaticLibInEditor)
{
PrivateDefinitions.Add("FORCE_USE_STATIC_V8_LIB");
}
}
void ThirdPartyNodejs(ReadOnlyTargetRules Target)
{
PrivateDefinitions.Add("WITH_NODEJS");
string WsHeaderPath = Path.GetFullPath(Path.Combine(ModuleDirectory, "..", "..", "ThirdParty", "Include"));
PublicIncludePaths.AddRange(new string[] { Path.Combine(WsHeaderPath, "websocketpp") });
PublicIncludePaths.AddRange(new string[] { Path.Combine(WsHeaderPath, "asio") });
string NodeRoot = Node16 ? "nodejs_16" : "nodejs";
string HeaderPath = Path.GetFullPath(Path.Combine(ModuleDirectory, "..", "..", "ThirdParty", NodeRoot));
PublicIncludePaths.AddRange(new string[] { Path.Combine(HeaderPath, "include") });
PublicIncludePaths.AddRange(new string[] { Path.Combine(HeaderPath, "deps", "v8", "include") });
PublicIncludePaths.AddRange(new string[] { Path.Combine(HeaderPath, "deps", "uv", "include") });
string LibraryPath = Path.GetFullPath(Path.Combine(ModuleDirectory, "..", "..", "ThirdParty", NodeRoot, "lib"));
if (Target.Platform == UnrealTargetPlatform.Win64)
{
string V8LibraryPath = Path.Combine(LibraryPath, "Win64");
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libnode.lib"));
RuntimeDependencies.Add("$(TargetOutputDir)/libnode.dll", Path.Combine(V8LibraryPath, "libnode.dll"));
AddRuntimeDependencies(new string[] { "libnode.dll" }, V8LibraryPath, false);
}
else if (Target.Platform == UnrealTargetPlatform.Android)
{
/*
#if UE_4_19_OR_LATER
AdditionalPropertiesForReceipt.Add("AndroidPlugin", Path.Combine(ModuleDirectory, "..", "..", "ThirdParty", "Libnode_APL.xml"));
#else
AdditionalPropertiesForReceipt.Add(new ReceiptProperty("AndroidPlugin", Path.Combine(ModuleDirectory, "..", "..", "ThirdParty", "Libnode_APL.xml")));
#endif
#if UE_4_24_OR_LATER
PublicSystemLibraryPaths.Add(Path.Combine(LibraryPath, "Android", "armeabi-v7a"));
PublicSystemLibraryPaths.Add(Path.Combine(LibraryPath, "Android", "arm64-v8a"));
PublicSystemLibraries.Add("node");
#else
PublicLibraryPaths.Add(Path.Combine(LibraryPath, "Android", "armeabi-v7a"));
PublicLibraryPaths.Add(Path.Combine(LibraryPath, "Android", "arm64-v8a"));
PublicAdditionalLibraries.Add("node");
#endif //UE_4_24_OR_LATER
*/
string[] Archs = new string[] { "armeabi-v7a", "arm64-v8a" };
foreach (var Arch in Archs)
{
string V8LibraryPath = Path.Combine(LibraryPath, "Android", Arch);
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libhistogram.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libuvwasi.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libnode.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libnode_stub.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_snapshot.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_libplatform.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libzlib.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libllhttp.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libcares.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libuv.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libnghttp2.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libbrotli.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_base_without_compiler.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_libbase.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_zlib.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_compiler.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_initializers.a"));
if (!Node16)
{
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_libsampler.a"));
}
}
}
else if (Target.Platform == UnrealTargetPlatform.Mac)
{
string V8LibraryPath = Path.Combine(LibraryPath, "macOS");
if (Node16)
{
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libnode.93.dylib"));
}
else
{
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libnode.83.dylib"));
}
}
else if (Target.Platform == UnrealTargetPlatform.IOS)
{
string V8LibraryPath = Path.Combine(LibraryPath, "iOS");
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libhistogram.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libuvwasi.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libnode.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libnode_stub.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_snapshot.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_libplatform.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libzlib.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libllhttp.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libcares.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libuv.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libnghttp2.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libbrotli.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libopenssl.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_base_without_compiler.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_libbase.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_zlib.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_compiler.a"));
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_initializers.a"));
if (!Node16)
{
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libv8_libsampler.a"));
}
}
else if (Target.Platform == UnrealTargetPlatform.Linux)
{
string V8LibraryPath = Path.Combine(LibraryPath, "Linux");
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libnode.so"));
RuntimeDependencies.Add("$(TargetOutputDir)/libnode.so.93", Path.Combine(V8LibraryPath, "libnode.so.93"));
}
}
void ThirdPartyQJS(ReadOnlyTargetRules Target)
{
PrivateDefinitions.Add("WITHOUT_INSPECTOR");
PrivateDefinitions.Add("WITH_QUICKJS");
if (QjsNamespaceSuffix)
{
PublicDefinitions.Add("WITH_QJS_NAMESPACE_SUFFIX=1");
PublicDefinitions.Add("QJSV8NAMESPACE=v8_qjs");
}
PublicIncludePaths.AddRange(new string[] { Path.Combine(ModuleDirectory, "..", "..", "ThirdParty", "quickjs", "Inc") });
string LibraryPath = Path.GetFullPath(Path.Combine(ModuleDirectory, "..", "..", "ThirdParty", "quickjs", "Lib"));
if (Target.Platform == UnrealTargetPlatform.Win64)
{
string V8LibraryPath = Path.Combine(LibraryPath, "Win64MD");
bool UsingSource = false;
if (UsingSource)
{
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libquickjs.dll.a"));
PrivateDefinitions.Add("BUILDING_V8_SHARED");
}
else
{
if (Target.bBuildEditor && !ForceStaticLibInEditor)
{
V8LibraryPath = Path.Combine(LibraryPath, "Win64DLL");
AddRuntimeDependencies(new string[] { "v8qjs.dll" }, V8LibraryPath, false);
}
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "quickjs.dll.lib"));
}
AddRuntimeDependencies(new string[] { "msys-quickjs.dll" }, V8LibraryPath, false);
AddRuntimeDependencies(new string[]
{
"libgcc_s_seh-1.dll",
"libwinpthread-1.dll"
}, V8LibraryPath, true);
}
else if (Target.Platform == UnrealTargetPlatform.Android)
{
string V8LibraryPath = Path.Combine(LibraryPath, "Android", "armeabi-v7a");
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libquickjs.a"));
V8LibraryPath = Path.Combine(LibraryPath, "Android", "arm64-v8a");
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libquickjs.a"));
}
else if (Target.Platform == UnrealTargetPlatform.Mac)
{
// PublicFrameworks.AddRange(new string[] { "WebKit", "JavaScriptCore" });
//PublicFrameworks.AddRange(new string[] { "WebKit" });
if (!Target.bBuildEditor || ForceStaticLibInEditor)
{
string V8LibraryPath = Path.Combine(LibraryPath, "macOS");
#if UE_5_2_OR_LATER
if (Target.Architecture == UnrealArch.Arm64)
{
V8LibraryPath = Path.Combine(LibraryPath, "macOS_arm64");
}
#endif
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libquickjs.a"));
}
else
{
string V8LibraryPath = Path.Combine(LibraryPath, "macOSdylib");
string QJSDylibName = "libquickjs.dylib";
#if UE_5_2_OR_LATER
if (Target.Architecture == UnrealArch.Arm64)
{
V8LibraryPath = Path.Combine(LibraryPath, "macOS_arm64");
QJSDylibName = "libquickjs.a";
}
#endif
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, QJSDylibName));
}
}
else if (Target.Platform == UnrealTargetPlatform.IOS)
{
PublicFrameworks.AddRange(new string[] { "WebKit" });
string V8LibraryPath = Path.Combine(LibraryPath, "iOS", "arm64");
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libquickjs.a"));
}
else if (Target.Platform == UnrealTargetPlatform.Linux)
{
string V8LibraryPath = Path.Combine(LibraryPath, "Linux");
PublicAdditionalLibraries.Add(Path.Combine(V8LibraryPath, "libquickjs.a"));
}
}
private static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs)
{
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
if (!dir.Exists)
{
throw new DirectoryNotFoundException(
"Source directory does not exist or could not be found: "
+ sourceDirName);
}
if (!Directory.Exists(destDirName))
{
Directory.CreateDirectory(destDirName);
}
// Get the files in the directory and copy them to the new location.
FileInfo[] files = dir.GetFiles();
foreach (FileInfo file in files)
{
string temppath = Path.Combine(destDirName, file.Name);
file.CopyTo(temppath, true);
}
if (copySubDirs)
{
DirectoryInfo[] dirs = dir.GetDirectories();
foreach (DirectoryInfo subdir in dirs)
{
string temppath = Path.Combine(destDirName, subdir.Name);
DirectoryCopy(subdir.FullName, temppath, copySubDirs);
}
}
}
}
@@ -0,0 +1,277 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "ContainerMeta.h"
#include "UObject/Package.h"
namespace PUERTS_NAMESPACE
{
FContainerMeta::FContainerMeta()
{
::memset(&BuiltinProperty, 0, sizeof(BuiltinProperty));
#if (ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1) || ENGINE_MAJOR_VERSION > 5
PropertyMetaRoot = FindObject<UScriptStruct>(nullptr, TEXT("/Script/JsEnv.PropertyMetaRoot"));
#else
PropertyMetaRoot = FindObject<UScriptStruct>(ANY_PACKAGE, TEXT("PropertyMetaRoot"));
#endif
}
FContainerMeta::~FContainerMeta()
{
#if ENGINE_MINOR_VERSION >= 25 || ENGINE_MAJOR_VERSION > 4
// for (auto KV : ObjectPropertyMap)
//{
// delete KV.Value;
//}
#else
for (int i = 0; i < MaxBuiltinType; i++)
{
if (BuiltinProperty[i])
{
// UE_LOG(LogTemp, Warning, TEXT("BuiltinProperty RemoveFromRoot %s"), *BuiltinProperty[i]->GetName());
BuiltinProperty[i]->RemoveFromRoot();
}
}
for (auto KV : ObjectPropertyMap)
{
// UE_LOG(LogTemp, Warning, TEXT("BuiltinProperty RemoveFromRoot %s"), *KV.Value->GetName());
KV.Value->RemoveFromRoot();
}
#endif
}
PropertyMacro* FContainerMeta::GetBuiltinProperty(BuiltinType type)
{
PropertyMacro* Ret = nullptr;
if (type < MaxBuiltinType)
{
if (BuiltinProperty[type])
{
return BuiltinProperty[type];
}
switch (type)
{
#if ENGINE_MINOR_VERSION < 25 && ENGINE_MAJOR_VERSION < 5
case TBool:
Ret = new (EC_InternalUseOnlyConstructor, PropertyMetaRoot, NAME_None, RF_Transient)
UBoolProperty(FObjectInitializer(), EC_CppProperty, 0, (EPropertyFlags) 0, 0xFF, 1, true);
break;
case TByte:
Ret = new (EC_InternalUseOnlyConstructor, PropertyMetaRoot, NAME_None, RF_Transient)
UByteProperty(FObjectInitializer(), EC_CppProperty, 0, CPF_HasGetValueTypeHash);
break;
case TInt:
Ret = new (EC_InternalUseOnlyConstructor, PropertyMetaRoot, NAME_None, RF_Transient)
UIntProperty(FObjectInitializer(), EC_CppProperty, 0, CPF_HasGetValueTypeHash);
break;
case TFloat:
Ret = new (EC_InternalUseOnlyConstructor, PropertyMetaRoot, NAME_None, RF_Transient)
UFloatProperty(FObjectInitializer(), EC_CppProperty, 0, CPF_HasGetValueTypeHash);
break;
case TDouble:
Ret = new (EC_InternalUseOnlyConstructor, PropertyMetaRoot, NAME_None, RF_Transient)
UDoubleProperty(FObjectInitializer(), EC_CppProperty, 0, CPF_HasGetValueTypeHash);
break;
case TInt64:
Ret = new (EC_InternalUseOnlyConstructor, PropertyMetaRoot, NAME_None, RF_Transient)
UInt64Property(FObjectInitializer(), EC_CppProperty, 0, CPF_HasGetValueTypeHash);
break;
case TString:
Ret = new (EC_InternalUseOnlyConstructor, PropertyMetaRoot, NAME_None, RF_Transient)
UStrProperty(FObjectInitializer(), EC_CppProperty, 0, CPF_HasGetValueTypeHash);
break;
case TText:
Ret = new (EC_InternalUseOnlyConstructor, PropertyMetaRoot, NAME_None, RF_Transient)
UNameProperty(FObjectInitializer(), EC_CppProperty, 0, CPF_HasGetValueTypeHash);
break;
case TName:
Ret = new (EC_InternalUseOnlyConstructor, PropertyMetaRoot, NAME_None, RF_Transient)
UTextProperty(FObjectInitializer(), EC_CppProperty, 0, CPF_HasGetValueTypeHash);
break;
#elif ENGINE_MINOR_VERSION > 0 && ENGINE_MAJOR_VERSION > 4
case TBool:
Ret = new FBoolProperty(PropertyMetaRoot, NAME_None, RF_Transient);
static_cast<FBoolProperty*>(Ret)->SetBoolSize(1, true, 0xFF);
break;
case TByte:
Ret = new FByteProperty(PropertyMetaRoot, NAME_None, RF_Transient);
Ret->PropertyFlags |= CPF_HasGetValueTypeHash;
break;
case TInt:
Ret = new FIntProperty(PropertyMetaRoot, NAME_None, RF_Transient);
Ret->PropertyFlags |= CPF_HasGetValueTypeHash;
break;
case TFloat:
Ret = new FFloatProperty(PropertyMetaRoot, NAME_None, RF_Transient);
Ret->PropertyFlags |= CPF_HasGetValueTypeHash;
break;
case TDouble:
Ret = new FDoubleProperty(PropertyMetaRoot, NAME_None, RF_Transient);
Ret->PropertyFlags |= CPF_HasGetValueTypeHash;
break;
case TInt64:
Ret = new FInt64Property(PropertyMetaRoot, NAME_None, RF_Transient);
Ret->PropertyFlags |= CPF_HasGetValueTypeHash;
break;
case TString:
Ret = new FStrProperty(PropertyMetaRoot, NAME_None, RF_Transient);
Ret->PropertyFlags |= CPF_HasGetValueTypeHash;
break;
case TText:
Ret = new FTextProperty(PropertyMetaRoot, NAME_None, RF_Transient);
Ret->PropertyFlags |= CPF_HasGetValueTypeHash;
break;
case TName:
Ret = new FNameProperty(PropertyMetaRoot, NAME_None, RF_Transient);
Ret->PropertyFlags |= CPF_HasGetValueTypeHash;
break;
#else
case TBool:
Ret = new FBoolProperty(PropertyMetaRoot, NAME_None, RF_Transient, 0, (EPropertyFlags) 0, 0xFF, 1, true);
break;
case TByte:
Ret = new FByteProperty(PropertyMetaRoot, NAME_None, RF_Transient, 0, CPF_HasGetValueTypeHash);
break;
case TInt:
Ret = new FIntProperty(PropertyMetaRoot, NAME_None, RF_Transient, 0, CPF_HasGetValueTypeHash);
break;
case TFloat:
Ret = new FFloatProperty(PropertyMetaRoot, NAME_None, RF_Transient, 0, CPF_HasGetValueTypeHash);
break;
case TDouble:
Ret = new FDoubleProperty(PropertyMetaRoot, NAME_None, RF_Transient, 0, CPF_HasGetValueTypeHash);
break;
case TInt64:
Ret = new FInt64Property(PropertyMetaRoot, NAME_None, RF_Transient, 0, CPF_HasGetValueTypeHash);
break;
case TString:
Ret = new FStrProperty(PropertyMetaRoot, NAME_None, RF_Transient, 0, CPF_HasGetValueTypeHash);
break;
case TText:
Ret = new FTextProperty(PropertyMetaRoot, NAME_None, RF_Transient, 0, CPF_HasGetValueTypeHash);
break;
case TName:
Ret = new FNameProperty(PropertyMetaRoot, NAME_None, RF_Transient, 0, CPF_HasGetValueTypeHash);
break;
#endif
case MaxBuiltinType:
break;
default:
break;
}
if (Ret)
{
#if ENGINE_MINOR_VERSION < 25 && ENGINE_MAJOR_VERSION < 5
Ret->AddToRoot();
#endif
BuiltinProperty[type] = Ret;
}
}
return Ret;
}
PropertyMacro* FContainerMeta::GetObjectProperty(UField* Field)
{
auto Iter = ObjectPropertyMap.Find(Field);
if (Iter)
{
return *Iter;
}
PropertyMacro* Ret = nullptr;
if (auto Class = Cast<UClass>(Field))
{
#if ENGINE_MINOR_VERSION < 25 && ENGINE_MAJOR_VERSION < 5
Ret = new (EC_InternalUseOnlyConstructor, PropertyMetaRoot, NAME_None, RF_Transient)
UObjectProperty(FObjectInitializer(), EC_CppProperty, 0, CPF_HasGetValueTypeHash, Class);
#elif ENGINE_MINOR_VERSION > 0 && ENGINE_MAJOR_VERSION > 4
Ret = new FObjectProperty(PropertyMetaRoot, NAME_None, RF_Transient);
static_cast<FObjectProperty*>(Ret)->PropertyClass = Class;
Ret->PropertyFlags |= CPF_HasGetValueTypeHash;
#else
Ret = new FObjectProperty(PropertyMetaRoot, NAME_None, RF_Transient, 0, CPF_HasGetValueTypeHash, Class);
#endif
}
else if (auto ScriptStruct = Cast<UScriptStruct>(Field))
{
#if ENGINE_MINOR_VERSION < 25 && ENGINE_MAJOR_VERSION < 5
Ret = new (EC_InternalUseOnlyConstructor, PropertyMetaRoot, NAME_None, RF_Transient)
UStructProperty(FObjectInitializer(), EC_CppProperty, 0, CPF_HasGetValueTypeHash, ScriptStruct);
#elif ENGINE_MINOR_VERSION > 0 && ENGINE_MAJOR_VERSION > 4
Ret = new FStructProperty(PropertyMetaRoot, NAME_None, RF_Transient);
static_cast<FStructProperty*>(Ret)->Struct = ScriptStruct;
Ret->ElementSize = ScriptStruct->PropertiesSize;
Ret->PropertyFlags |= CPF_HasGetValueTypeHash;
#else
Ret = new FStructProperty(PropertyMetaRoot, NAME_None, RF_Transient, 0, CPF_HasGetValueTypeHash, ScriptStruct);
#endif
}
else if (auto Enum = Cast<UEnum>(Field))
{
#if ENGINE_MINOR_VERSION < 25 && ENGINE_MAJOR_VERSION < 5
UEnumProperty* EnumProp = new (EC_InternalUseOnlyConstructor, ScriptStruct, NAME_None, RF_Transient)
UEnumProperty(FObjectInitializer(), EC_CppProperty, 0, CPF_HasGetValueTypeHash, Enum);
UNumericProperty* UnderlyingProp = NewObject<UByteProperty>(EnumProp, TEXT("UnderlyingType"));
EnumProp->AddCppProperty(UnderlyingProp);
Ret = EnumProp;
#else
if (Enum->GetCppForm() == UEnum::ECppForm::EnumClass)
{
FEnumProperty* EnumProp =
new FEnumProperty(PropertyMetaRoot, NAME_None, RF_Transient, 0, CPF_HasGetValueTypeHash, Enum);
FNumericProperty* UnderlyingProp = new FByteProperty(EnumProp, TEXT("UnderlyingType"), RF_Transient);
EnumProp->AddCppProperty(UnderlyingProp);
EnumProp->ElementSize = UnderlyingProp->ElementSize;
EnumProp->PropertyFlags |= CPF_IsPlainOldData | CPF_NoDestructor | CPF_ZeroConstructor;
Ret = EnumProp;
}
else
{
FByteProperty* ByteProp = new FByteProperty(PropertyMetaRoot, NAME_None, RF_Transient);
ByteProp->Enum = Enum;
Ret = ByteProp;
}
Ret->SetPropertyFlags(CPF_HasGetValueTypeHash);
#endif
}
else
{
return nullptr;
}
#if ENGINE_MINOR_VERSION < 25 && ENGINE_MAJOR_VERSION < 5
Ret->AddToRoot();
#endif
ObjectPropertyMap.Add(Field, Ret);
return Ret;
}
void FContainerMeta::NotifyElementTypeDeleted(const UField* Field)
{
auto Iter = ObjectPropertyMap.Find(Field);
if (Iter)
{
#if ENGINE_MINOR_VERSION < 25 && ENGINE_MAJOR_VERSION < 5
(const_cast<UField*>(Field))->RemoveFromRoot();
#else
// delete *Iter;
#endif
ObjectPropertyMap.Remove(Field);
}
}
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,62 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include "PuertsNamespaceDef.h"
#include "CoreMinimal.h"
#include "Runtime/Launch/Resources/Version.h"
#include "PropertyMacros.h"
#include "UObject/UnrealType.h"
#include "UObject/TextProperty.h"
#if !defined(ENGINE_INDEPENDENT_JSENV)
#include "EngineMinimal.h"
#endif
USTRUCT(noexport)
struct FPropertyMetaRoot
{
};
namespace PUERTS_NAMESPACE
{
enum BuiltinType
{
TBool = 0,
TByte = 1,
TInt = 2,
TFloat = 3,
TDouble = 4,
TInt64 = 5,
TString = 6,
TText = 7,
TName = 8,
MaxBuiltinType
};
class FContainerMeta
{
public:
FContainerMeta();
~FContainerMeta();
PropertyMacro* GetBuiltinProperty(BuiltinType type);
PropertyMacro* GetObjectProperty(UField* Field);
void NotifyElementTypeDeleted(const UField* Struct);
private:
UScriptStruct* PropertyMetaRoot;
PropertyMacro* BuiltinProperty[MaxBuiltinType];
TMap<UField*, PropertyMacro*> ObjectPropertyMap;
};
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,850 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "ContainerWrapper.h"
#include "PropertyTranslator.h"
namespace PUERTS_NAMESPACE
{
v8::Local<v8::FunctionTemplate> FScriptArrayWrapper::ToFunctionTemplate(v8::Isolate* Isolate)
{
v8::Isolate::Scope Isolatescope(Isolate);
auto Result = v8::FunctionTemplate::New(Isolate, New);
Result->InstanceTemplate()->SetInternalFieldCount(4); // 0 Ptr, 1 Property
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Num"), v8::FunctionTemplate::New(Isolate, Num));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Add"), v8::FunctionTemplate::New(Isolate, Add));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Get"), v8::FunctionTemplate::New(Isolate, Get));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "GetRef"), v8::FunctionTemplate::New(Isolate, GetRef));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Set"), v8::FunctionTemplate::New(Isolate, Set));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Contains"), v8::FunctionTemplate::New(Isolate, Contains));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "FindIndex"), v8::FunctionTemplate::New(Isolate, FindIndex));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "RemoveAt"), v8::FunctionTemplate::New(Isolate, RemoveAt));
Result->PrototypeTemplate()->Set(
FV8Utils::InternalString(Isolate, "IsValidIndex"), v8::FunctionTemplate::New(Isolate, IsValidIndex));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Empty"), v8::FunctionTemplate::New(Isolate, Empty));
return Result;
}
void FScriptArrayWrapper::Add(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() > 0)
{
auto Self = FV8Utils::GetPointerFast<FScriptArray>(Info.Holder(), 0);
auto Inner = FV8Utils::GetPointerFast<FPropertyTranslator>(Info.Holder(), 1);
if (!Inner->IsPropertyValid())
{
FV8Utils::ThrowException(Isolate, "item info is invalid!");
return;
}
int32 Index = AddUninitialized(Self, GetSizeWithAlignment(Inner->Property), Info.Length());
for (int i = 0; i < Info.Length(); ++i)
{
uint8* DataPtr = GetData(Self, GetSizeWithAlignment(Inner->Property), Index + i);
Inner->Property->InitializeValue(DataPtr); //使用之前必须得初始化,即使是设置也要
Inner->JsToUE(Isolate, Context, Info[i], DataPtr, false);
}
Info.GetReturnValue().Set(Index);
}
}
void FScriptArrayWrapper::InternalGet(const v8::FunctionCallbackInfo<v8::Value>& Info, bool PassByPointer)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
CHECK_V8_ARGS_LEN(1);
auto Self = FV8Utils::GetPointerFast<FScriptArray>(Info.Holder(), 0);
auto Inner = FV8Utils::GetPointerFast<FPropertyTranslator>(Info.Holder(), 1);
if (!Inner->IsPropertyValid())
{
FV8Utils::ThrowException(Isolate, "item info is invalid!");
return;
}
int Index = Info[0]->Int32Value(Context).ToChecked();
if (Index < 0 || Index >= Self->Num())
{
FV8Utils::ThrowException(Isolate, TEXT("invalid index"));
return;
}
uint8* DataPtr = GetData(Self, GetSizeWithAlignment(Inner->Property), Index);
auto Ret = Inner->UEToJs(Isolate, Context, DataPtr, PassByPointer);
if (Inner->NeedLinkOuter && PassByPointer)
{
LinkOuterImpl(Context, Info.Holder(), Ret);
}
Info.GetReturnValue().Set(Ret);
}
void FScriptArrayWrapper::Get(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
InternalGet(Info, false);
}
void FScriptArrayWrapper::GetRef(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
InternalGet(Info, true);
}
void FScriptArrayWrapper::Set(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
CHECK_V8_ARGS_LEN(2);
auto Self = FV8Utils::GetPointerFast<FScriptArray>(Info.Holder(), 0);
auto Inner = FV8Utils::GetPointerFast<FPropertyTranslator>(Info.Holder(), 1);
if (!Inner->IsPropertyValid())
{
FV8Utils::ThrowException(Isolate, "item info is invalid!");
return;
}
int Index = Info[0]->Int32Value(Context).ToChecked();
if (Index < 0 || Index >= Self->Num())
{
FV8Utils::ThrowException(Isolate, TEXT("invalid index"));
return;
}
uint8* DataPtr = GetData(Self, GetSizeWithAlignment(Inner->Property), Index);
Inner->Property->InitializeValue(DataPtr);
Inner->JsToUE(Isolate, Context, Info[1], DataPtr, false);
}
void FScriptArrayWrapper::Contains(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
CHECK_V8_ARGS_LEN(1);
bool Result = FindIndexInner(Info) != INDEX_NONE;
Info.GetReturnValue().Set(Result);
}
void FScriptArrayWrapper::FindIndex(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
CHECK_V8_ARGS_LEN(1);
int32 Result = FindIndexInner(Info);
Info.GetReturnValue().Set(Result);
}
void FScriptArrayWrapper::RemoveAt(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
CHECK_V8_ARGS_LEN(1);
auto Self = FV8Utils::GetPointerFast<FScriptArray>(Info.Holder(), 0);
auto Inner = FV8Utils::GetPointerFast<FPropertyTranslator>(Info.Holder(), 1);
if (!Inner->IsPropertyValid())
{
FV8Utils::ThrowException(Isolate, "item info is invalid!");
return;
}
int32 Index = Info[0]->Int32Value(Context).ToChecked();
if (Index < 0 || Index >= Self->Num())
{
FV8Utils::ThrowException(Isolate, TEXT("invalid index"));
return;
}
else
{
FScriptArrayEx::Destruct(Self, Inner->Property, Index, 1);
#if ENGINE_MAJOR_VERSION > 4
Self->Remove(Index, 1, GetSizeWithAlignment(Inner->Property), __STDCPP_DEFAULT_NEW_ALIGNMENT__);
#else
Self->Remove(Index, 1, GetSizeWithAlignment(Inner->Property));
#endif
}
}
void FScriptArrayWrapper::IsValidIndex(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
CHECK_V8_ARGS_LEN(1);
auto Self = FV8Utils::GetPointerFast<FScriptArray>(Info.Holder(), 0);
int32 Index = Info[0]->Int32Value(Context).ToChecked();
Info.GetReturnValue().Set(Self->IsValidIndex(Index));
}
void FScriptArrayWrapper::Empty(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = FV8Utils::GetPointerFast<FScriptArray>(Info.Holder(), 0);
auto Inner = FV8Utils::GetPointerFast<FPropertyTranslator>(Info.Holder(), 1);
if (!Inner->IsPropertyValid())
{
FV8Utils::ThrowException(Isolate, "item info is invalid!");
return;
}
FScriptArrayEx::Empty(Self, Inner->Property);
}
FORCEINLINE int32 FScriptArrayWrapper::AddUninitialized(FScriptArray* ScriptArray, int32 ElementSize, int32 Count)
{
#if ENGINE_MAJOR_VERSION > 4
return ScriptArray->Add(Count, ElementSize, __STDCPP_DEFAULT_NEW_ALIGNMENT__);
#else
return ScriptArray->Add(Count, ElementSize);
#endif
}
FORCEINLINE uint8* FScriptArrayWrapper::GetData(FScriptArray* ScriptArray, int32 ElementSize, int32 Index)
{
return reinterpret_cast<uint8*>(ScriptArray->GetData()) + Index * ElementSize;
}
FORCEINLINE void FScriptArrayWrapper::Construct(FScriptArray* ScriptArray, FPropertyTranslator* Inner, int32 Index, int32 Count)
{
int32 ElementSize = GetSizeWithAlignment(Inner->Property);
uint8* Dest = GetData(ScriptArray, ElementSize, Index);
for (int32 i = 0; i < Count; ++i)
{
Inner->Property->InitializeValue(Dest);
Dest += ElementSize;
}
}
int32 FScriptArrayWrapper::FindIndexInner(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = FV8Utils::GetPointerFast<FScriptArray>(Info.Holder(), 0);
auto Inner = FV8Utils::GetPointerFast<FPropertyTranslator>(Info.Holder(), 1);
if (!Inner->IsPropertyValid())
{
FV8Utils::ThrowException(Isolate, "item info is invalid!");
return INDEX_NONE;
}
auto Property = Inner->Property;
void* Dest = FMemory_Alloca(GetSizeWithAlignment(Property));
Property->InitializeValue(Dest);
Inner->JsToUE(Isolate, Context, Info[0], Dest, false);
const int32 Num = Self->Num();
int32 Result = INDEX_NONE;
for (int32 i = 0; i < Num; ++i)
{
uint8* Src = GetData(Self, GetSizeWithAlignment(Property), i);
if (Property->Identical(Src, Dest))
{
Result = i;
break;
}
}
Property->DestroyValue(Dest);
return Result;
}
//---------------------------------------Set-----------------------------------------------
v8::Local<v8::FunctionTemplate> FScriptSetWrapper::ToFunctionTemplate(v8::Isolate* Isolate)
{
v8::Isolate::Scope Isolatescope(Isolate);
auto Result = v8::FunctionTemplate::New(Isolate, New);
Result->InstanceTemplate()->SetInternalFieldCount(4); // 0 Ptr, 1 Property
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Num"), v8::FunctionTemplate::New(Isolate, Num));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Add"), v8::FunctionTemplate::New(Isolate, Add));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Get"), v8::FunctionTemplate::New(Isolate, Get));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "GetRef"), v8::FunctionTemplate::New(Isolate, GetRef));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Contains"), v8::FunctionTemplate::New(Isolate, Contains));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "FindIndex"), v8::FunctionTemplate::New(Isolate, FindIndex));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "RemoveAt"), v8::FunctionTemplate::New(Isolate, RemoveAt));
Result->PrototypeTemplate()->Set(
FV8Utils::InternalString(Isolate, "GetMaxIndex"), v8::FunctionTemplate::New(Isolate, GetMaxIndex));
Result->PrototypeTemplate()->Set(
FV8Utils::InternalString(Isolate, "IsValidIndex"), v8::FunctionTemplate::New(Isolate, IsValidIndex));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Empty"), v8::FunctionTemplate::New(Isolate, Empty));
return Result;
}
void FScriptSetWrapper::Add(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
CHECK_V8_ARGS_LEN(1);
auto Self = FV8Utils::GetPointerFast<FScriptSet>(Info.Holder(), 0);
auto Inner = FV8Utils::GetPointerFast<FPropertyTranslator>(Info.Holder(), 1);
if (!Inner->IsPropertyValid())
{
FV8Utils::ThrowException(Isolate, "item info is invalid!");
return;
}
auto Property = Inner->Property;
void* DataPtr = FMemory_Alloca(GetSizeWithAlignment(Property));
Property->InitializeValue(DataPtr);
Inner->JsToUE(Isolate, Context, Info[0], DataPtr, false);
auto ScriptLayout = FScriptSet::GetScriptLayout(Property->GetSize(), Property->GetMinAlignment());
Self->Add(
DataPtr, ScriptLayout, [Property](const void* Element) { return Property->GetValueTypeHash(Element); },
[Property](const void* A, const void* B) { return Property->Identical(A, B); },
[Property, DataPtr](void* Element)
{
Property->InitializeValue(Element);
Property->CopySingleValue(Element, DataPtr);
},
[Property](void* Element) { Property->DestroyValue(Element); });
Property->DestroyValue(DataPtr);
}
void FScriptSetWrapper::InternalGet(const v8::FunctionCallbackInfo<v8::Value>& Info, bool PassByPointer)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
CHECK_V8_ARGS_LEN(1);
auto Self = FV8Utils::GetPointerFast<FScriptSet>(Info.Holder(), 0);
auto Inner = FV8Utils::GetPointerFast<FPropertyTranslator>(Info.Holder(), 1);
if (!Inner->IsPropertyValid())
{
FV8Utils::ThrowException(Isolate, "item info is invalid!");
return;
}
auto Property = Inner->Property;
int32 Index = Info[0]->Int32Value(Context).ToChecked();
if (Self->IsValidIndex(Index) == false)
{
FV8Utils::ThrowException(Isolate, "invalid index argument");
}
else
{
auto ScriptLayout = FScriptSet::GetScriptLayout(Property->GetSize(), Property->GetMinAlignment());
void* Data = Self->GetData(Index, ScriptLayout);
auto Ret = Inner->UEToJs(Isolate, Context, Data, PassByPointer);
if (Inner->NeedLinkOuter && PassByPointer)
{
LinkOuterImpl(Context, Info.Holder(), Ret);
}
Info.GetReturnValue().Set(Ret);
}
}
void FScriptSetWrapper::Get(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
InternalGet(Info, false);
}
void FScriptSetWrapper::GetRef(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
InternalGet(Info, true);
}
void FScriptSetWrapper::Contains(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
CHECK_V8_ARGS_LEN(1);
bool Result = FindIndexInner(Info) != INDEX_NONE;
Info.GetReturnValue().Set(Result);
}
void FScriptSetWrapper::FindIndex(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
CHECK_V8_ARGS_LEN(1);
int32 Result = FindIndexInner(Info);
Info.GetReturnValue().Set(Result);
}
void FScriptSetWrapper::RemoveAt(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
CHECK_V8_ARGS_LEN(1);
auto Self = FV8Utils::GetPointerFast<FScriptSet>(Info.Holder(), 0);
auto Inner = FV8Utils::GetPointerFast<FPropertyTranslator>(Info.Holder(), 1);
if (!Inner->IsPropertyValid())
{
FV8Utils::ThrowException(Isolate, "item info is invalid!");
return;
}
auto Property = Inner->Property;
int32 Index = Info[0]->Int32Value(Context).ToChecked();
if (Self->IsValidIndex(Index) == false)
{
FV8Utils::ThrowException(Isolate, "invalid index argument");
}
else
{
auto ScriptLayout = FScriptSet::GetScriptLayout(Property->GetSize(), Property->GetMinAlignment());
void* Data = Self->GetData(Index, ScriptLayout);
FScriptSetEx::Destruct(Self, Property, Index, 1);
Self->RemoveAt(Index, ScriptLayout);
}
}
void FScriptSetWrapper::GetMaxIndex(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = FV8Utils::GetPointerFast<FScriptSet>(Info.Holder(), 0);
uint32 Result = Self->GetMaxIndex();
Info.GetReturnValue().Set(Result);
}
void FScriptSetWrapper::IsValidIndex(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
CHECK_V8_ARGS_LEN(1);
auto Self = FV8Utils::GetPointerFast<FScriptSet>(Info.Holder(), 0);
int32 Index = Info[0]->Int32Value(Context).ToChecked();
uint32 Result = Self->IsValidIndex(Index);
Info.GetReturnValue().Set(Result);
}
void FScriptSetWrapper::Empty(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = FV8Utils::GetPointerFast<FScriptSet>(Info.Holder(), 0);
auto Inner = FV8Utils::GetPointerFast<FPropertyTranslator>(Info.Holder(), 1);
if (!Inner->IsPropertyValid())
{
FV8Utils::ThrowException(Isolate, "item info is invalid!");
return;
}
FScriptSetEx::Empty(Self, Inner->Property);
}
int32 FScriptSetWrapper::FindIndexInner(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = FV8Utils::GetPointerFast<FScriptSet>(Info.Holder(), 0);
auto Inner = FV8Utils::GetPointerFast<FPropertyTranslator>(Info.Holder(), 1);
if (!Inner->IsPropertyValid())
{
FV8Utils::ThrowException(Isolate, "item info is invalid!");
return INDEX_NONE;
}
auto Property = Inner->Property;
void* DataPtr = FMemory_Alloca(GetSizeWithAlignment(Property));
Property->InitializeValue(DataPtr);
Inner->JsToUE(Isolate, Context, Info[0], DataPtr, false);
auto ScriptLayout = FScriptSet::GetScriptLayout(Property->GetSize(), Property->GetMinAlignment());
int32 Result = Self->FindIndex(
DataPtr, ScriptLayout, [Property](const void* Element) { return Property->GetValueTypeHash(Element); },
[Property](const void* A, const void* B) { return Property->Identical(A, B); });
Property->DestroyValue(DataPtr);
return Result;
}
//---------------------------------------Map-----------------------------------------------
v8::Local<v8::FunctionTemplate> FScriptMapWrapper::ToFunctionTemplate(v8::Isolate* Isolate)
{
v8::Isolate::Scope Isolatescope(Isolate);
auto Result = v8::FunctionTemplate::New(Isolate, New);
Result->InstanceTemplate()->SetInternalFieldCount(6); // 0 Ptr, 1-2 Property
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Num"), v8::FunctionTemplate::New(Isolate, Num));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Add"), v8::FunctionTemplate::New(Isolate, Add));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Get"), v8::FunctionTemplate::New(Isolate, Get));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "GetRef"), v8::FunctionTemplate::New(Isolate, GetRef));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Set"), v8::FunctionTemplate::New(Isolate, Set));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Remove"), v8::FunctionTemplate::New(Isolate, Remove));
Result->PrototypeTemplate()->Set(
FV8Utils::InternalString(Isolate, "GetMaxIndex"), v8::FunctionTemplate::New(Isolate, GetMaxIndex));
Result->PrototypeTemplate()->Set(
FV8Utils::InternalString(Isolate, "IsValidIndex"), v8::FunctionTemplate::New(Isolate, IsValidIndex));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "GetKey"), v8::FunctionTemplate::New(Isolate, GetKey));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Empty"), v8::FunctionTemplate::New(Isolate, Empty));
return Result;
}
void FScriptMapWrapper::Add(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
CHECK_V8_ARGS_LEN(2);
auto Self = FV8Utils::GetPointerFast<FScriptMap>(Info.Holder(), 0);
auto KeyPropertyTranslator = FV8Utils::GetPointerFast<FPropertyTranslator>(Info.Holder(), 1);
auto KeyProperty = KeyPropertyTranslator->Property;
auto ValuePropertyTranslator = FV8Utils::GetPointerFast<FPropertyTranslator>(Info.Holder(), 2);
auto ValueProperty = ValuePropertyTranslator->Property;
if (!KeyPropertyTranslator->IsPropertyValid() || !ValuePropertyTranslator->IsPropertyValid())
{
FV8Utils::ThrowException(Isolate, "key/value info is invalid!");
return;
}
void* KeyPtr = FMemory_Alloca(GetSizeWithAlignment(KeyProperty));
KeyProperty->InitializeValue(KeyPtr);
void* ValuePtr = FMemory_Alloca(GetSizeWithAlignment(ValueProperty));
ValueProperty->InitializeValue(ValuePtr);
KeyPropertyTranslator->JsToUE(Isolate, Context, Info[0], KeyPtr, false);
ValuePropertyTranslator->JsToUE(Isolate, Context, Info[1], ValuePtr, false);
auto ScriptLayout = FScriptMap::GetScriptLayout(
KeyProperty->GetSize(), KeyProperty->GetMinAlignment(), ValueProperty->GetSize(), ValueProperty->GetMinAlignment());
Self->Add(
KeyPtr, ValuePtr, ScriptLayout, [KeyProperty](const void* ElementKey) { return KeyProperty->GetValueTypeHash(ElementKey); },
[KeyProperty](const void* A, const void* B) { return KeyProperty->Identical(A, B); },
[KeyProperty, KeyPtr](void* NewElementKey)
{
KeyProperty->InitializeValue(NewElementKey);
KeyProperty->CopySingleValue(NewElementKey, KeyPtr);
},
[ValueProperty, ValuePtr](void* NewElementValue)
{
ValueProperty->InitializeValue(NewElementValue);
ValueProperty->CopySingleValue(NewElementValue, ValuePtr);
},
[ValueProperty, ValuePtr](void* ExistingElementValue) { ValueProperty->CopySingleValue(ExistingElementValue, ValuePtr); },
[KeyProperty](void* ElementKey) { KeyProperty->DestroyValue(ElementKey); },
[ValueProperty](void* ElementValue) { ValueProperty->DestroyValue(ElementValue); });
KeyProperty->DestroyValue(KeyPtr);
ValueProperty->DestroyValue(ValuePtr);
}
void FScriptMapWrapper::InternalGet(const v8::FunctionCallbackInfo<v8::Value>& Info, bool PassByPointer)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
CHECK_V8_ARGS_LEN(1);
auto Self = FV8Utils::GetPointerFast<FScriptMap>(Info.Holder(), 0);
auto KeyPropertyTranslator = FV8Utils::GetPointerFast<FPropertyTranslator>(Info.Holder(), 1);
auto KeyProperty = KeyPropertyTranslator->Property;
auto ValuePropertyTranslator = FV8Utils::GetPointerFast<FPropertyTranslator>(Info.Holder(), 2);
auto ValueProperty = ValuePropertyTranslator->Property;
if (!KeyPropertyTranslator->IsPropertyValid() || !ValuePropertyTranslator->IsPropertyValid())
{
FV8Utils::ThrowException(Isolate, "key/value info is invalid!");
return;
}
void* KeyPtr = FMemory_Alloca(GetSizeWithAlignment(KeyProperty));
KeyProperty->InitializeValue(KeyPtr);
KeyPropertyTranslator->JsToUE(Isolate, Context, Info[0], KeyPtr, false);
auto ScriptLayout = FScriptMap::GetScriptLayout(
KeyProperty->GetSize(), KeyProperty->GetMinAlignment(), ValueProperty->GetSize(), ValueProperty->GetMinAlignment());
void* ValuePtr = Self->FindValue(
KeyPtr, ScriptLayout, [KeyProperty](const void* ElementKey) { return KeyProperty->GetValueTypeHash(ElementKey); },
[KeyProperty](const void* A, const void* B) { return KeyProperty->Identical(A, B); });
if (ValuePtr)
{
auto Ret = ValuePropertyTranslator->UEToJs(Isolate, Context, ValuePtr, PassByPointer);
if (ValuePropertyTranslator->NeedLinkOuter && PassByPointer)
{
LinkOuterImpl(Context, Info.Holder(), Ret);
}
Info.GetReturnValue().Set(Ret);
}
KeyProperty->DestroyValue(KeyPtr);
}
void FScriptMapWrapper::Get(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
InternalGet(Info, false);
}
void FScriptMapWrapper::GetRef(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
InternalGet(Info, true);
}
void FScriptMapWrapper::Set(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
Add(Info);
}
void FScriptMapWrapper::Remove(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
CHECK_V8_ARGS_LEN(1);
auto Self = FV8Utils::GetPointerFast<FScriptMap>(Info.Holder(), 0);
auto KeyPropertyTranslator = FV8Utils::GetPointerFast<FPropertyTranslator>(Info.Holder(), 1);
auto KeyProperty = KeyPropertyTranslator->Property;
auto ValuePropertyTranslator = FV8Utils::GetPointerFast<FPropertyTranslator>(Info.Holder(), 2);
auto ValueProperty = ValuePropertyTranslator->Property;
if (!KeyPropertyTranslator->IsPropertyValid() || !ValuePropertyTranslator->IsPropertyValid())
{
FV8Utils::ThrowException(Isolate, "key/value info is invalid!");
return;
}
void* KeyPtr = FMemory_Alloca(GetSizeWithAlignment(KeyProperty));
KeyProperty->InitializeValue(KeyPtr);
KeyPropertyTranslator->JsToUE(Isolate, Context, Info[0], KeyPtr, false);
auto ScriptLayout = GetScriptLayout(KeyProperty, ValueProperty);
int32 Index = Self->FindPairIndex(
KeyPtr, ScriptLayout, [KeyProperty](const void* Key) { return KeyProperty->GetValueTypeHash(Key); },
[KeyProperty](const void* A, const void* B) { return KeyProperty->Identical(A, B); });
if (Index == INDEX_NONE)
{
FV8Utils::ThrowException(Isolate, TEXT("invalid key argument"));
}
else
{
FScriptMapEx::Destruct(Self, KeyProperty, ValueProperty, Index, 1);
Self->RemoveAt(Index, ScriptLayout);
}
KeyProperty->DestroyValue(KeyPtr);
}
void FScriptMapWrapper::GetMaxIndex(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = FV8Utils::GetPointerFast<FScriptMap>(Info.Holder(), 0);
int32 Result = Self->GetMaxIndex();
Info.GetReturnValue().Set(Result);
}
void FScriptMapWrapper::IsValidIndex(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
CHECK_V8_ARGS_LEN(1);
auto Self = FV8Utils::GetPointerFast<FScriptMap>(Info.Holder(), 0);
int32 Index = Info[0]->Int32Value(Context).ToChecked();
Info.GetReturnValue().Set(Self->IsValidIndex(Index));
}
void FScriptMapWrapper::GetKey(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
CHECK_V8_ARGS_LEN(1);
auto Self = FV8Utils::GetPointerFast<FScriptMap>(Info.Holder(), 0);
int32 Index = Info[0]->Int32Value(Context).ToChecked();
if (Self->IsValidIndex(Index) == false)
{
FV8Utils::ThrowException(Isolate, TEXT("the argument is an invalid index"));
Info.GetReturnValue().Set(v8::Undefined(Isolate));
}
else
{
auto KeyPropertyTranslator = FV8Utils::GetPointerFast<FPropertyTranslator>(Info.Holder(), 1);
auto KeyProperty = KeyPropertyTranslator->Property;
auto ValuePropertyTranslator = FV8Utils::GetPointerFast<FPropertyTranslator>(Info.Holder(), 2);
auto ValueProperty = ValuePropertyTranslator->Property;
if (!KeyPropertyTranslator->IsPropertyValid() || !ValuePropertyTranslator->IsPropertyValid())
{
FV8Utils::ThrowException(Isolate, "key/value info is invalid!");
return;
}
auto ScriptLayout = GetScriptLayout(KeyProperty, ValueProperty);
uint8* Data = reinterpret_cast<uint8*>(Self->GetData(Index, ScriptLayout));
void* KeyPtr = Data + GetKeyOffset(ScriptLayout);
Info.GetReturnValue().Set(KeyPropertyTranslator->UEToJs(Isolate, Context, KeyPtr, false));
}
}
void FScriptMapWrapper::Empty(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = FV8Utils::GetPointerFast<FScriptMap>(Info.Holder(), 0);
auto KeyPropertyTranslator = FV8Utils::GetPointerFast<FPropertyTranslator>(Info.Holder(), 1);
auto KeyProperty = KeyPropertyTranslator->Property;
auto ValuePropertyTranslator = FV8Utils::GetPointerFast<FPropertyTranslator>(Info.Holder(), 2);
auto ValueProperty = ValuePropertyTranslator->Property;
if (!KeyPropertyTranslator->IsPropertyValid() || !ValuePropertyTranslator->IsPropertyValid())
{
FV8Utils::ThrowException(Isolate, "key/value info is invalid!");
return;
}
FScriptMapEx::Empty(Self, KeyProperty, ValueProperty);
}
FScriptMapLayout FScriptMapWrapper::GetScriptLayout(const PropertyMacro* KeyProperty, const PropertyMacro* ValueProperty)
{
return FScriptMap::GetScriptLayout(
KeyProperty->GetSize(), KeyProperty->GetMinAlignment(), ValueProperty->GetSize(), ValueProperty->GetMinAlignment());
}
//---------------------------------------Fix Size Array-----------------------------------------------
v8::Local<v8::FunctionTemplate> FFixSizeArrayWrapper::ToFunctionTemplate(v8::Isolate* Isolate)
{
v8::Isolate::Scope Isolatescope(Isolate);
auto Result = v8::FunctionTemplate::New(Isolate, New);
Result->InstanceTemplate()->SetInternalFieldCount(4); // 0 Ptr, 1 Property
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Num"), v8::FunctionTemplate::New(Isolate, Num));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Get"), v8::FunctionTemplate::New(Isolate, Get));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "GetRef"), v8::FunctionTemplate::New(Isolate, GetRef));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Set"), v8::FunctionTemplate::New(Isolate, Set));
// Result->PrototypeTemplate()->SetIndexedPropertyHandler(Getter, Setter);
return Result;
}
void FFixSizeArrayWrapper::Num(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Inner = FV8Utils::GetPointerFast<FPropertyTranslator>(Info.Holder(), 1);
if (!Inner->IsPropertyValid())
{
FV8Utils::ThrowException(Isolate, "item info is invalid!");
return;
}
Info.GetReturnValue().Set(Inner->Property->ArrayDim);
}
void FFixSizeArrayWrapper::InternalGet(const v8::FunctionCallbackInfo<v8::Value>& Info, bool PassByPointer)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = FV8Utils::GetPointerFast<uint8>(Info.Holder(), 0);
auto Inner = FV8Utils::GetPointerFast<FPropertyTranslator>(Info.Holder(), 1);
if (!Inner->IsPropertyValid())
{
FV8Utils::ThrowException(Isolate, "item info is invalid!");
return;
}
auto Property = Inner->Property;
int32 Index = -1;
if (Info[0]->IsInt32())
{
Index = Info[0]->Int32Value(Context).ToChecked();
}
if (Index < 0 || Index >= Property->ArrayDim)
{
FV8Utils::ThrowException(Isolate, "invalid index");
return;
}
auto Ptr = Self + Property->ElementSize * Index;
auto Ret = Inner->UEToJs(Isolate, Context, Ptr, PassByPointer);
if (Inner->NeedLinkOuter && PassByPointer)
{
LinkOuterImpl(Context, Info.Holder(), Ret);
}
Info.GetReturnValue().Set(Ret);
}
void FFixSizeArrayWrapper::Get(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
InternalGet(Info, false);
}
void FFixSizeArrayWrapper::GetRef(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
InternalGet(Info, true);
}
void FFixSizeArrayWrapper::Set(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = FV8Utils::GetPointerFast<uint8>(Info.Holder(), 0);
auto Inner = FV8Utils::GetPointerFast<FPropertyTranslator>(Info.Holder(), 1);
if (!Inner->IsPropertyValid())
{
FV8Utils::ThrowException(Isolate, "item info is invalid!");
return;
}
auto Property = Inner->Property;
int32 Index = -1;
if (Info[0]->IsInt32())
{
Index = Info[0]->Int32Value(Context).ToChecked();
}
if (Index < 0 || Index >= Property->ArrayDim)
{
FV8Utils::ThrowException(Isolate, "invalid index");
return;
}
auto Ptr = Self + Property->ElementSize * Index;
Inner->JsToUE(Isolate, Context, Info[1], Ptr, true);
}
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,417 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include <memory>
#include <vector>
#include "CoreMinimal.h"
#include "CoreUObject.h"
#include "V8Utils.h"
#include "ObjectMapper.h"
#include "JSLogger.h"
#include "NamespaceDef.h"
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#pragma warning(push, 0)
#include "libplatform/libplatform.h"
#include "v8.h"
#pragma warning(pop)
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
namespace PUERTS_NAMESPACE
{
class FPropertyTranslator;
FORCEINLINE int32 GetSizeWithAlignment(PropertyMacro* InProperty)
{
return Align(InProperty->GetSize(), InProperty->GetMinAlignment());
}
struct FScriptArrayEx
{
FScriptArray Data;
#if ENGINE_MINOR_VERSION < 25 && ENGINE_MAJOR_VERSION < 5
TWeakObjectPtr<PropertyMacro> PropertyPtr;
#else
TWeakFieldPtr<PropertyMacro> PropertyPtr;
#endif
FORCEINLINE FScriptArrayEx(PropertyMacro* InProperty)
{
// UE_LOG(LogTemp, Warning, TEXT("FScriptArrayEx:%p"), this);
PropertyPtr = InProperty;
}
FORCEINLINE ~FScriptArrayEx()
{
// UE_LOG(LogTemp, Warning, TEXT("~FScriptArrayEx:%p"), this);
if (PropertyPtr.IsValid())
{
Empty(&Data, PropertyPtr.Get());
}
else
{
UE_LOG(Puerts, Error, TEXT("~FScriptArrayEx: Property is invalid"));
}
}
FORCEINLINE static uint8* GetData(FScriptArray* ScriptArray, int32 ElementSize, int32 Index)
{
return static_cast<uint8*>(ScriptArray->GetData()) + Index * ElementSize;
}
FORCEINLINE static void Destruct(FScriptArray* ScriptArray, PropertyMacro* Property, int32 Index, int32 Count = 1)
{
const int32 ElementSize = GetSizeWithAlignment(Property);
uint8* Dest = GetData(ScriptArray, ElementSize, Index);
for (int32 i = 0; i < Count; ++i)
{
Property->DestroyValue(Dest);
Dest += ElementSize;
}
}
FORCEINLINE static void Empty(FScriptArray* ScriptArray, PropertyMacro* Property)
{
Destruct(ScriptArray, Property, 0, ScriptArray->Num());
#if ENGINE_MAJOR_VERSION > 4
ScriptArray->Empty(0, GetSizeWithAlignment(Property), __STDCPP_DEFAULT_NEW_ALIGNMENT__);
#else
ScriptArray->Empty(0, GetSizeWithAlignment(Property));
#endif
}
};
struct FScriptSetEx
{
FScriptSet Data;
#if ENGINE_MINOR_VERSION < 25 && ENGINE_MAJOR_VERSION < 5
TWeakObjectPtr<PropertyMacro> PropertyPtr;
#else
TWeakFieldPtr<PropertyMacro> PropertyPtr;
#endif
FORCEINLINE FScriptSetEx(PropertyMacro* InProperty)
{
// UE_LOG(LogTemp, Warning, TEXT("FScriptSetEx:%p"), this);
PropertyPtr = InProperty;
}
FORCEINLINE ~FScriptSetEx()
{
// UE_LOG(LogTemp, Warning, TEXT("~FScriptSetEx:%p"), this);
if (PropertyPtr.IsValid())
{
Empty(&Data, PropertyPtr.Get());
}
else
{
UE_LOG(Puerts, Error, TEXT("~FScriptSetEx: Property is invalid"));
}
}
FORCEINLINE static void Destruct(FScriptSet* ScriptSet, PropertyMacro* Property, int32 Index, int32 Count = 1)
{
auto SetLayout = ScriptSet->GetScriptLayout(Property->GetSize(), Property->GetMinAlignment());
for (int32 i = Index; i < Index + Count; ++i)
{
if (ScriptSet->IsValidIndex(i))
{
void* Data = ScriptSet->GetData(i, SetLayout);
Property->DestroyValue(Data);
}
}
}
FORCEINLINE static void Empty(FScriptSet* ScriptSet, PropertyMacro* Property)
{
auto SetLayout = FScriptSet::GetScriptLayout(Property->GetSize(), Property->GetMinAlignment());
Destruct(ScriptSet, Property, 0, ScriptSet->Num());
ScriptSet->Empty(0, SetLayout);
}
};
FORCEINLINE static int32 GetKeyOffset(const FScriptMapLayout& ScriptMapLayout)
{
#if ENGINE_MINOR_VERSION < 22 && ENGINE_MAJOR_VERSION < 5
return ScriptMapLayout.KeyOffset;
#else
return 0;
#endif
}
struct FScriptMapEx
{
FScriptMap Data;
#if ENGINE_MINOR_VERSION < 25 && ENGINE_MAJOR_VERSION < 5
TWeakObjectPtr<PropertyMacro> KeyPropertyPtr;
TWeakObjectPtr<PropertyMacro> ValuePropertyPtr;
#else
TWeakFieldPtr<PropertyMacro> KeyPropertyPtr;
TWeakFieldPtr<PropertyMacro> ValuePropertyPtr;
#endif
FORCEINLINE FScriptMapEx(PropertyMacro* InKeyProperty, PropertyMacro* InValueProperty)
{
// UE_LOG(LogTemp, Warning, TEXT("FScriptMapEx:%p"), this);
KeyPropertyPtr = InKeyProperty;
ValuePropertyPtr = InValueProperty;
}
FORCEINLINE ~FScriptMapEx()
{
// UE_LOG(LogTemp, Warning, TEXT("~FScriptMapEx:%p"), this);
if (KeyPropertyPtr.IsValid() && ValuePropertyPtr.IsValid())
{
Empty(&Data, KeyPropertyPtr.Get(), ValuePropertyPtr.Get());
}
else
{
UE_LOG(Puerts, Error, TEXT("~FScriptMapEx: Property is invalid"));
}
}
FORCEINLINE static FScriptMapLayout GetScriptLayout(const PropertyMacro* KeyProperty, const PropertyMacro* ValueProperty)
{
return FScriptMap::GetScriptLayout(
KeyProperty->GetSize(), KeyProperty->GetMinAlignment(), ValueProperty->GetSize(), ValueProperty->GetMinAlignment());
}
FORCEINLINE static void Destruct(
FScriptMap* ScriptMap, PropertyMacro* KeyProperty, PropertyMacro* ValueProperty, int32 Index, int32 Count = 1)
{
int32 MaxIndex = ScriptMap->GetMaxIndex();
auto MapLayout = GetScriptLayout(KeyProperty, ValueProperty);
for (int32 i = Index; i < Index + Count; ++i)
{
if (ScriptMap->IsValidIndex(i))
{
uint8* Data = reinterpret_cast<uint8*>(ScriptMap->GetData(i, MapLayout));
void* Key = Data + GetKeyOffset(MapLayout);
void* Value = Data + MapLayout.ValueOffset;
KeyProperty->DestroyValue(Key);
ValueProperty->DestroyValue(Value);
}
}
}
FORCEINLINE static void Empty(FScriptMap* ScriptMap, PropertyMacro* KeyProperty, PropertyMacro* ValueProperty)
{
auto MapLayout = GetScriptLayout(KeyProperty, ValueProperty);
Destruct(ScriptMap, KeyProperty, ValueProperty, 0, ScriptMap->Num());
ScriptMap->Empty(0, MapLayout);
}
};
template <typename T>
struct ContainerExTypeMapper;
template <>
struct ContainerExTypeMapper<FScriptArray>
{
using Type = FScriptArrayEx;
};
template <>
struct ContainerExTypeMapper<FScriptSet>
{
using Type = FScriptSetEx;
};
template <>
struct ContainerExTypeMapper<FScriptMap>
{
using Type = FScriptMapEx;
};
template <typename T>
class FContainerWrapper
{
public:
static void OnGarbageCollectedWithFree(const v8::WeakCallbackInfo<void>& Data)
{
typedef typename ContainerExTypeMapper<T>::Type ET;
ET* Container =
static_cast<ET*>(DataTransfer::MakeAddressWithHighPartOfTwo(Data.GetInternalField(0), Data.GetInternalField(1)));
FV8Utils::IsolateData<IObjectMapper>(Data.GetIsolate())->UnBindContainer(Container);
delete Container;
}
static void OnGarbageCollected(const v8::WeakCallbackInfo<void>& Data)
{
T* Container =
static_cast<T*>(DataTransfer::MakeAddressWithHighPartOfTwo(Data.GetInternalField(0), Data.GetInternalField(1)));
FV8Utils::IsolateData<IObjectMapper>(Data.GetIsolate())->UnBindContainer(Container);
}
static void New(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
FV8Utils::ThrowException(Isolate, "Container Constructor no support yet");
}
// TODO - 用doxygen注释
// 参数:无
// 返回:容器内元素总数
static void Num(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = FV8Utils::GetPointerFast<T>(Info.Holder());
Info.GetReturnValue().Set(Self->Num());
}
};
class FScriptArrayWrapper : public FContainerWrapper<FScriptArray>
{
public:
static v8::Local<v8::FunctionTemplate> ToFunctionTemplate(v8::Isolate* Isolate);
private:
// 参数:一到多个容器元素
// 返回:无
// 作用:追加新元素到容器
static void Add(const v8::FunctionCallbackInfo<v8::Value>& Info);
// 参数:索引
// 返回:元素(值类型,有内存拷贝)
// 作用:获取索引对应的元素,如果索引越界则抛出异常
static void Get(const v8::FunctionCallbackInfo<v8::Value>& Info);
// 参数:索引
// 返回:元素(引用类型)
// 作用:获取索引对应的元素,如果索引越界则抛出异常
static void GetRef(const v8::FunctionCallbackInfo<v8::Value>& Info);
// 参数1:索引;参数2:元素
// 返回:无
// 作用:设置容器中索引对应的元素值,如果索引越界则抛出异常
static void Set(const v8::FunctionCallbackInfo<v8::Value>& Info);
// 参数:元素
// 返回:bool
// 作用:查询容器是否包含该元素,若是则返回true,否则返回false
static void Contains(const v8::FunctionCallbackInfo<v8::Value>& Info);
// 参数:元素
// 返回:索引
// 作用:返回容器中第一次出现该元素的索引,若元素不存在则返回INDEX_NONE(-1)
static void FindIndex(const v8::FunctionCallbackInfo<v8::Value>& Info);
// 参数:索引
// 返回:无
// 作用:移除索引对应的元素,被移除的位置之后的元素会自动前移,如果索引越界则抛出异常
static void RemoveAt(const v8::FunctionCallbackInfo<v8::Value>& Info);
// 参数:索引
// 返回:bool
// 作用:如果参数是有效索引,返回true,否则返回false
static void IsValidIndex(const v8::FunctionCallbackInfo<v8::Value>& Info);
// 参数:无
// 返回:无
// 作用:清空容器
static void Empty(const v8::FunctionCallbackInfo<v8::Value>& Info);
FORCEINLINE static int32 AddUninitialized(FScriptArray* ScriptArray, int32 ElementSize, int32 Count = 1);
FORCEINLINE static uint8* GetData(FScriptArray* ScriptArray, int32 ElementSize, int32 Index);
FORCEINLINE static void Construct(FScriptArray* ScriptArray, FPropertyTranslator* Inner, int32 Index, int32 Count = 1);
static int32 FindIndexInner(const v8::FunctionCallbackInfo<v8::Value>& Info);
FORCEINLINE static void InternalGet(const v8::FunctionCallbackInfo<v8::Value>& Info, bool PassByPointer);
};
class FScriptSetWrapper : public FContainerWrapper<FScriptSet>
{
public:
static v8::Local<v8::FunctionTemplate> ToFunctionTemplate(v8::Isolate* Isolate);
private:
static void Add(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Get(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void GetRef(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Contains(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void FindIndex(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void RemoveAt(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void GetMaxIndex(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void IsValidIndex(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Empty(const v8::FunctionCallbackInfo<v8::Value>& Info);
FORCEINLINE static int32 FindIndexInner(const v8::FunctionCallbackInfo<v8::Value>& Info);
FORCEINLINE static void InternalGet(const v8::FunctionCallbackInfo<v8::Value>& Info, bool PassByPointer);
};
class FScriptMapWrapper : public FContainerWrapper<FScriptMap>
{
public:
static v8::Local<v8::FunctionTemplate> ToFunctionTemplate(v8::Isolate* Isolate);
private:
static void Add(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Get(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void GetRef(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Set(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Remove(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void GetMaxIndex(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void IsValidIndex(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void GetKey(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Empty(const v8::FunctionCallbackInfo<v8::Value>& Info);
FORCEINLINE static FScriptMapLayout GetScriptLayout(const PropertyMacro* KeyProperty, const PropertyMacro* ValueProperty);
FORCEINLINE static void InternalGet(const v8::FunctionCallbackInfo<v8::Value>& Info, bool PassByPointer);
};
class FFixSizeArrayWrapper
{
public:
static v8::Local<v8::FunctionTemplate> ToFunctionTemplate(v8::Isolate* Isolate);
private:
static void New(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
}
static void Num(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Get(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void GetRef(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Set(const v8::FunctionCallbackInfo<v8::Value>& Info);
FORCEINLINE static void InternalGet(const v8::FunctionCallbackInfo<v8::Value>& Info, bool PassByPointer);
};
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,424 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "CppObjectMapper.h"
#include "DataTransfer.h"
namespace PUERTS_NAMESPACE
{
template <typename T>
inline void __USE(T&&)
{
}
static void ThrowException(v8::Isolate* Isolate, const char* Message)
{
auto ExceptionStr = v8::String::NewFromUtf8(Isolate, Message, v8::NewStringType::kNormal).ToLocalChecked();
Isolate->ThrowException(v8::Exception::Error(ExceptionStr));
}
void FCppObjectMapper::LoadCppType(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
if (!Info[0]->IsString())
{
ThrowException(Isolate, "#0 argument expect a string");
return;
}
std::string TypeName = *(v8::String::Utf8Value(Isolate, Info[0]));
auto ClassDef = FindCppTypeClassByName(TypeName);
if (ClassDef)
{
Info.GetReturnValue().Set(GetTemplateOfClass(Isolate, ClassDef)->GetFunction(Context).ToLocalChecked());
}
else
{
const std::string ErrMsg = "can not find type: " + TypeName;
ThrowException(Isolate, ErrMsg.c_str());
}
}
v8::MaybeLocal<v8::Function> FCppObjectMapper::LoadTypeById(v8::Local<v8::Context> Context, const void* TypeId)
{
auto ClassDef = puerts::LoadClassByID(TypeId);
if (!ClassDef)
{
return v8::MaybeLocal<v8::Function>();
}
auto Template = GetTemplateOfClass(Context->GetIsolate(), ClassDef);
return Template->GetFunction(Context);
}
static void PointerNew(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
// do nothing
}
void FCppObjectMapper::Initialize(v8::Isolate* InIsolate, v8::Local<v8::Context> InContext)
{
auto LocalTemplate = v8::FunctionTemplate::New(InIsolate, PointerNew);
LocalTemplate->InstanceTemplate()->SetInternalFieldCount(4); // 0 Ptr, 1, CDataName
PointerTemplate = v8::UniquePersistent<v8::FunctionTemplate>(InIsolate, LocalTemplate);
#ifndef WITH_QUICKJS
PrivateKey.Reset(InIsolate, v8::Symbol::New(InIsolate));
#endif
}
v8::Local<v8::Value> FCppObjectMapper::FindOrAddCppObject(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const void* TypeId, void* Ptr, bool PassByPointer)
{
if (Ptr == nullptr)
{
return v8::Null(Isolate);
}
if (PassByPointer)
{
auto Iter = CDataCache.find(Ptr);
if (Iter != CDataCache.end())
{
auto CacheNodePtr = Iter->second.Find(TypeId);
if (CacheNodePtr)
{
return CacheNodePtr->Value.Get(Isolate);
}
}
}
// create and link
auto ClassDefinition = LoadClassByID(TypeId);
if (ClassDefinition)
{
auto Result = GetTemplateOfClass(Isolate, ClassDefinition)->InstanceTemplate()->NewInstance(Context).ToLocalChecked();
BindCppObject(Isolate, const_cast<JSClassDefinition*>(ClassDefinition), Ptr, Result, PassByPointer);
return Result;
}
else
{
auto Result = PointerTemplate.Get(Isolate)->InstanceTemplate()->NewInstance(Context).ToLocalChecked();
DataTransfer::SetPointer(Isolate, Result, Ptr, 0);
DataTransfer::SetPointer(Isolate, Result, TypeId, 1);
return Result;
}
}
bool FCppObjectMapper::IsInstanceOfCppObject(v8::Isolate* Isolate, const void* TypeId, v8::Local<v8::Object> JsObject)
{
if (DataTransfer::GetPointerFast<const void>(JsObject, 1) == TypeId)
{
return true;
}
auto ClassDefinition = FindClassByID(TypeId);
if (ClassDefinition)
{
auto Template = GetTemplateOfClass(Isolate, ClassDefinition);
return Template->HasInstance(JsObject);
}
return false;
}
std::weak_ptr<int> FCppObjectMapper::GetJsEnvLifeCycleTracker()
{
return std::weak_ptr<int>(Ref);
}
static void CDataNew(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
if (Info.IsConstructCall())
{
auto Self = Info.This();
JSClassDefinition* ClassDefinition = reinterpret_cast<JSClassDefinition*>(
reinterpret_cast<char*>(v8::Local<v8::External>::Cast(Info.Data())->Value()) - offsetof(JSClassDefinition, Data));
void* Ptr = nullptr;
if (ClassDefinition->Initialize)
Ptr = ClassDefinition->Initialize((pesapi_callback_info) &Info);
if (Ptr == nullptr)
return;
DataTransfer::IsolateData<ICppObjectMapper>(Isolate)->BindCppObject(Isolate, ClassDefinition, Ptr, Self, false);
}
else
{
ThrowException(Isolate, "only call as Construct is supported!");
}
}
MSVC_PRAGMA(warning(push))
MSVC_PRAGMA(warning(disable : 4191))
v8::Local<v8::FunctionTemplate> FCppObjectMapper::GetTemplateOfClass(v8::Isolate* Isolate, const JSClassDefinition* ClassDefinition)
{
auto Iter = TypeIdToTemplateMap.find(ClassDefinition->TypeId);
if (Iter == TypeIdToTemplateMap.end())
{
auto Template = v8::FunctionTemplate::New(
Isolate, CDataNew, v8::External::New(Isolate, &(const_cast<JSClassDefinition*>(ClassDefinition)->Data)));
Template->InstanceTemplate()->SetInternalFieldCount(4);
JSPropertyInfo* PropertyInfo = ClassDefinition->Properties;
while (PropertyInfo && PropertyInfo->Name && PropertyInfo->Getter)
{
v8::PropertyAttribute PropertyAttribute = v8::DontDelete;
if (!PropertyInfo->Setter)
PropertyAttribute = (v8::PropertyAttribute)(PropertyAttribute | v8::ReadOnly);
auto GetterData = v8::External::New(Isolate, &PropertyInfo->GetterData);
auto SetterData = v8::External::New(Isolate, &PropertyInfo->SetterData);
Template->PrototypeTemplate()->SetAccessorProperty(
v8::String::NewFromUtf8(Isolate, PropertyInfo->Name, v8::NewStringType::kNormal).ToLocalChecked(),
PropertyInfo->Getter ? v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) PropertyInfo->Getter, GetterData)
: v8::Local<v8::FunctionTemplate>(),
PropertyInfo->Setter ? v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) PropertyInfo->Setter, SetterData)
: v8::Local<v8::FunctionTemplate>(),
PropertyAttribute);
++PropertyInfo;
}
PropertyInfo = ClassDefinition->Variables;
while (PropertyInfo && PropertyInfo->Name && PropertyInfo->Getter)
{
v8::PropertyAttribute PropertyAttribute = v8::DontDelete;
if (!PropertyInfo->Setter)
PropertyAttribute = (v8::PropertyAttribute)(PropertyAttribute | v8::ReadOnly);
auto GetterData = v8::External::New(Isolate, &PropertyInfo->GetterData);
auto SetterData = v8::External::New(Isolate, &PropertyInfo->SetterData);
Template->SetAccessorProperty(
v8::String::NewFromUtf8(Isolate, PropertyInfo->Name, v8::NewStringType::kNormal).ToLocalChecked(),
PropertyInfo->Getter ? v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) PropertyInfo->Getter, GetterData)
: v8::Local<v8::FunctionTemplate>(),
PropertyInfo->Setter ? v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) PropertyInfo->Setter, SetterData)
: v8::Local<v8::FunctionTemplate>(),
PropertyAttribute);
++PropertyInfo;
}
JSFunctionInfo* FunctionInfo = ClassDefinition->Methods;
while (FunctionInfo && FunctionInfo->Name && FunctionInfo->Callback)
{
#ifndef WITH_QUICKJS
auto FastCallInfo = FunctionInfo->ReflectionInfo ? FunctionInfo->ReflectionInfo->FastCallInfo() : nullptr;
if (FastCallInfo)
{
Template->PrototypeTemplate()->Set(
v8::String::NewFromUtf8(Isolate, FunctionInfo->Name, v8::NewStringType::kNormal).ToLocalChecked(),
v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) FunctionInfo->Callback,
v8::External::New(Isolate, &FunctionInfo->Data), v8::Local<v8::Signature>(), 0,
v8::ConstructorBehavior::kThrow, v8::SideEffectType::kHasSideEffect, FastCallInfo));
}
else
#endif
{
Template->PrototypeTemplate()->Set(
v8::String::NewFromUtf8(Isolate, FunctionInfo->Name, v8::NewStringType::kNormal).ToLocalChecked(),
v8::FunctionTemplate::New(
Isolate, (v8::FunctionCallback) FunctionInfo->Callback, v8::External::New(Isolate, &FunctionInfo->Data)
#ifndef WITH_QUICKJS
,
v8::Local<v8::Signature>(), 0, v8::ConstructorBehavior::kThrow
#endif
));
}
++FunctionInfo;
}
FunctionInfo = ClassDefinition->Functions;
while (FunctionInfo && FunctionInfo->Name && FunctionInfo->Callback)
{
#ifndef WITH_QUICKJS
auto FastCallInfo = FunctionInfo->ReflectionInfo ? FunctionInfo->ReflectionInfo->FastCallInfo() : nullptr;
if (FastCallInfo)
{
Template->Set(v8::String::NewFromUtf8(Isolate, FunctionInfo->Name, v8::NewStringType::kNormal).ToLocalChecked(),
v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) FunctionInfo->Callback,
v8::External::New(Isolate, &FunctionInfo->Data), v8::Local<v8::Signature>(), 0,
v8::ConstructorBehavior::kThrow, v8::SideEffectType::kHasSideEffect, FastCallInfo));
}
else
#endif
{
Template->Set(v8::String::NewFromUtf8(Isolate, FunctionInfo->Name, v8::NewStringType::kNormal).ToLocalChecked(),
v8::FunctionTemplate::New(
Isolate, (v8::FunctionCallback) FunctionInfo->Callback, v8::External::New(Isolate, &FunctionInfo->Data)
#ifndef WITH_QUICKJS
,
v8::Local<v8::Signature>(), 0, v8::ConstructorBehavior::kThrow
#endif
));
}
++FunctionInfo;
}
if (ClassDefinition->SuperTypeId)
{
if (auto SuperDefinition = LoadClassByID(ClassDefinition->SuperTypeId))
{
Template->Inherit(GetTemplateOfClass(Isolate, SuperDefinition));
}
}
TypeIdToTemplateMap[ClassDefinition->TypeId] = v8::UniquePersistent<v8::FunctionTemplate>(Isolate, Template);
return Template;
}
else
{
return v8::Local<v8::FunctionTemplate>::New(Isolate, Iter->second);
}
}
MSVC_PRAGMA(warning(pop))
static void CDataGarbageCollectedWithFree(const v8::WeakCallbackInfo<JSClassDefinition>& Data)
{
JSClassDefinition* ClassDefinition = Data.GetParameter();
void* Ptr = DataTransfer::MakeAddressWithHighPartOfTwo(Data.GetInternalField(0), Data.GetInternalField(1));
if (ClassDefinition->Finalize)
ClassDefinition->Finalize(Ptr, ClassDefinition->Data, DataTransfer::GetIsolatePrivateData(Data.GetIsolate()));
DataTransfer::IsolateData<ICppObjectMapper>(Data.GetIsolate())->UnBindCppObject(Data.GetIsolate(), ClassDefinition, Ptr);
}
static void CDataGarbageCollectedWithoutFree(const v8::WeakCallbackInfo<JSClassDefinition>& Data)
{
JSClassDefinition* ClassDefinition = Data.GetParameter();
void* Ptr = DataTransfer::MakeAddressWithHighPartOfTwo(Data.GetInternalField(0), Data.GetInternalField(1));
DataTransfer::IsolateData<ICppObjectMapper>(Data.GetIsolate())->UnBindCppObject(Data.GetIsolate(), ClassDefinition, Ptr);
}
void FCppObjectMapper::BindCppObject(
v8::Isolate* Isolate, JSClassDefinition* ClassDefinition, void* Ptr, v8::Local<v8::Object> JSObject, bool PassByPointer)
{
DataTransfer::SetPointer(Isolate, JSObject, Ptr, 0);
DataTransfer::SetPointer(Isolate, JSObject, ClassDefinition->TypeId, 1);
auto Iter = CDataCache.find(Ptr);
FObjectCacheNode* CacheNodePtr;
if (Iter != CDataCache.end())
{
CacheNodePtr = Iter->second.Add(ClassDefinition->TypeId);
}
else
{
auto Ret = CDataCache.insert({Ptr, FObjectCacheNode(ClassDefinition->TypeId)});
CacheNodePtr = &Ret.first->second;
}
CacheNodePtr->Value.Reset(Isolate, JSObject);
if (!PassByPointer)
{
CacheNodePtr->MustCallFinalize = true;
CacheNodePtr->Value.SetWeak<JSClassDefinition>(
ClassDefinition, CDataGarbageCollectedWithFree, v8::WeakCallbackType::kInternalFields);
}
else
{
CacheNodePtr->Value.SetWeak<JSClassDefinition>(
ClassDefinition, CDataGarbageCollectedWithoutFree, v8::WeakCallbackType::kInternalFields);
}
if (ClassDefinition->OnEnter)
{
CacheNodePtr->UserData = ClassDefinition->OnEnter(Ptr, ClassDefinition->Data, DataTransfer::GetIsolatePrivateData(Isolate));
}
}
#define QJS_PRIVATE_KEY_STR "__,kp@"
void* FCppObjectMapper::GetPrivateData(v8::Local<v8::Context> Context, v8::Local<v8::Object> JSObject)
{
#ifndef WITH_QUICKJS
auto Key = PrivateKey.Get(Context->GetIsolate());
#else
auto Key = FV8Utils::InternalString(Context->GetIsolate(), QJS_PRIVATE_KEY_STR);
#endif
v8::MaybeLocal<v8::Value> maybeValue = JSObject->Get(Context, Key);
if (maybeValue.IsEmpty())
{
return nullptr;
}
v8::Local<v8::Value> maybeExternal = maybeValue.ToLocalChecked();
if (!maybeExternal->IsExternal())
{
return nullptr;
}
return v8::Local<v8::External>::Cast(maybeExternal)->Value();
}
void FCppObjectMapper::SetPrivateData(v8::Local<v8::Context> Context, v8::Local<v8::Object> JSObject, void* Ptr)
{
#ifndef WITH_QUICKJS
auto Key = PrivateKey.Get(Context->GetIsolate());
#else
auto Key = FV8Utils::InternalString(Context->GetIsolate(), QJS_PRIVATE_KEY_STR);
#endif
(void) (JSObject->Set(Context, Key, v8::External::New(Context->GetIsolate(), Ptr)));
}
void FCppObjectMapper::UnBindCppObject(v8::Isolate* Isolate, JSClassDefinition* ClassDefinition, void* Ptr)
{
auto Iter = CDataCache.find(Ptr);
if (Iter != CDataCache.end())
{
if (ClassDefinition->OnExit)
{
ClassDefinition->OnExit(
Ptr, ClassDefinition->Data, DataTransfer::GetIsolatePrivateData(Isolate), Iter->second.UserData);
}
auto Removed = Iter->second.Remove(ClassDefinition->TypeId, true);
if (!Iter->second.TypeId) // last one
{
CDataCache.erase(Ptr);
}
}
}
void FCppObjectMapper::UnInitialize(v8::Isolate* InIsolate)
{
auto PData = DataTransfer::GetIsolatePrivateData(InIsolate);
for (auto& KV : CDataCache)
{
FObjectCacheNode* PNode = &KV.second;
while (PNode)
{
const JSClassDefinition* ClassDefinition = FindClassByID(PNode->TypeId);
if (PNode->MustCallFinalize)
{
if (ClassDefinition && ClassDefinition->Finalize)
{
ClassDefinition->Finalize(KV.first, ClassDefinition->Data, PData);
}
PNode->MustCallFinalize = false;
}
if (ClassDefinition->OnExit)
{
ClassDefinition->OnExit(
KV.first, ClassDefinition->Data, DataTransfer::GetIsolatePrivateData(InIsolate), PNode->UserData);
}
PNode = PNode->Next;
}
}
CDataCache.clear();
TypeIdToTemplateMap.clear();
#ifndef WITH_QUICKJS
PrivateKey.Reset();
#endif
PointerTemplate.Reset();
}
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,84 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include "NamespaceDef.h"
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#pragma warning(push, 0)
#include "v8.h"
#pragma warning(pop)
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
#include <unordered_map>
#include "JSClassRegister.h"
#include "ObjectCacheNode.h"
#include "ObjectMapper.h"
namespace PUERTS_NAMESPACE
{
struct PointerHash
{
std::size_t operator()(const void* ptr) const
{
return reinterpret_cast<std::size_t>(ptr);
}
};
struct PointerEqual
{
bool operator()(const void* lhs, const void* rhs) const
{
return lhs == rhs;
}
};
class FCppObjectMapper final : public ICppObjectMapper
{
public:
void Initialize(v8::Isolate* InIsolate, v8::Local<v8::Context> InContext);
void LoadCppType(const v8::FunctionCallbackInfo<v8::Value>& Info);
virtual bool IsInstanceOfCppObject(v8::Isolate* Isolate, const void* TypeId, v8::Local<v8::Object> JsObject) override;
virtual std::weak_ptr<int> GetJsEnvLifeCycleTracker() override;
virtual v8::Local<v8::Value> FindOrAddCppObject(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const void* TypeId, void* Ptr, bool PassByPointer) override;
virtual void UnBindCppObject(v8::Isolate* Isolate, JSClassDefinition* ClassDefinition, void* Ptr) override;
virtual void BindCppObject(v8::Isolate* Isolate, JSClassDefinition* ClassDefinition, void* Ptr, v8::Local<v8::Object> JSObject,
bool PassByPointer) override;
virtual void* GetPrivateData(v8::Local<v8::Context> Context, v8::Local<v8::Object> JSObject) override;
virtual void SetPrivateData(v8::Local<v8::Context> Context, v8::Local<v8::Object> JSObject, void* Ptr) override;
virtual v8::MaybeLocal<v8::Function> LoadTypeById(v8::Local<v8::Context> Context, const void* TypeId) override;
void UnInitialize(v8::Isolate* InIsolate);
v8::Local<v8::FunctionTemplate> GetTemplateOfClass(v8::Isolate* Isolate, const JSClassDefinition* ClassDefinition);
private:
std::unordered_map<void*, FObjectCacheNode, PointerHash, PointerEqual> CDataCache;
std::unordered_map<const void*, v8::UniquePersistent<v8::FunctionTemplate>, PointerHash, PointerEqual> TypeIdToTemplateMap;
v8::UniquePersistent<v8::FunctionTemplate> PointerTemplate;
#ifndef WITH_QUICKJS
v8::Global<v8::Symbol> PrivateKey;
#endif
std::shared_ptr<int> Ref = std::make_shared<int>(0);
};
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,77 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "DataTransfer.h"
#include "ObjectMapper.h"
#if USING_IN_UNREAL_ENGINE
#include "V8Utils.h"
#endif
namespace PUERTS_NAMESPACE
{
v8::Local<v8::Value> DataTransfer::FindOrAddCData(
v8::Isolate* Isolate, v8::Local<v8::Context> Context, const void* TypeId, const void* Ptr, bool PassByPointer)
{
return IsolateData<ICppObjectMapper>(Isolate)->FindOrAddCppObject(
Isolate, Context, TypeId, const_cast<void*>(Ptr), PassByPointer);
}
bool DataTransfer::IsInstanceOf(v8::Isolate* Isolate, const void* TypeId, v8::Local<v8::Object> JsObject)
{
return IsolateData<ICppObjectMapper>(Isolate)->IsInstanceOfCppObject(Isolate, TypeId, JsObject);
}
v8::Local<v8::Value> DataTransfer::UnRef(v8::Isolate* Isolate, const v8::Local<v8::Value>& Value)
{
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Local<v8::Value> ReturnValue = Value->ToObject(Context).ToLocalChecked()->Get(Context, 0).ToLocalChecked();
return ReturnValue;
}
void DataTransfer::UpdateRef(v8::Isolate* Isolate, v8::Local<v8::Value> Outer, const v8::Local<v8::Value>& Value)
{
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Ret = Outer->ToObject(Context).ToLocalChecked()->Set(Context, 0, Value);
}
std::weak_ptr<int> DataTransfer::GetJsEnvLifeCycleTracker(v8::Isolate* Isolate)
{
return IsolateData<ICppObjectMapper>(Isolate)->GetJsEnvLifeCycleTracker();
}
#if USING_IN_UNREAL_ENGINE
FString DataTransfer::ToFString(v8::Isolate* Isolate, v8::Local<v8::Value> Value)
{
return FV8Utils::ToFString(Isolate, Value);
}
v8::Local<v8::Value> DataTransfer::FindOrAddObject(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, UClass* Class, UObject* UEObject)
{
return FV8Utils::IsolateData<IObjectMapper>(Isolate)->FindOrAdd(Isolate, Context, Class, UEObject);
}
v8::Local<v8::Value> DataTransfer::FindOrAddStruct(
v8::Isolate* Isolate, v8::Local<v8::Context> Context, UScriptStruct* ScriptStruct, void* Ptr, bool PassByPointer)
{
return FV8Utils::IsolateData<IObjectMapper>(Isolate)->FindOrAddStruct(Isolate, Context, ScriptStruct, Ptr, PassByPointer);
}
bool DataTransfer::IsInstanceOf(v8::Isolate* Isolate, UStruct* Struct, v8::Local<v8::Object> JsObject)
{
return FV8Utils::IsolateData<IObjectMapper>(Isolate)->IsInstanceOf(Struct, JsObject);
}
void DataTransfer::ThrowException(v8::Isolate* Isolate, const char* Message)
{
FV8Utils::ThrowException(Isolate, Message);
}
#endif
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,146 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "JSModuleLoader.h"
#include "Misc/Paths.h"
#include "Misc/FileHelper.h"
#include "Algo/Reverse.h"
#if (ENGINE_MAJOR_VERSION >= 5)
#include "HAL/PlatformFileManager.h"
#else
#include "HAL/PlatformFilemanager.h"
#endif
namespace PUERTS_NAMESPACE
{
static FString PathNormalize(const FString& PathIn)
{
TArray<FString> PathFrags;
PathIn.ParseIntoArray(PathFrags, TEXT("/"));
Algo::Reverse(PathFrags);
TArray<FString> NewPathFrags;
bool FromRoot = PathIn.StartsWith(TEXT("/"));
while (PathFrags.Num() > 0)
{
FString E = PathFrags.Pop();
if (E != TEXT("") && E != TEXT("."))
{
if (E == TEXT("..") && NewPathFrags.Num() > 0 && NewPathFrags.Last() != TEXT(".."))
{
NewPathFrags.Pop();
}
else
{
NewPathFrags.Push(E);
}
}
}
if (FromRoot)
{
return TEXT("/") + FString::Join(NewPathFrags, TEXT("/"));
}
else
{
return FString::Join(NewPathFrags, TEXT("/"));
}
}
bool DefaultJSModuleLoader::CheckExists(const FString& PathIn, FString& Path, FString& AbsolutePath)
{
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
FString NormalizedPath = PathNormalize(PathIn);
if (PlatformFile.FileExists(*NormalizedPath))
{
AbsolutePath = IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*NormalizedPath);
Path = NormalizedPath;
return true;
}
return false;
}
bool DefaultJSModuleLoader::SearchModuleInDir(
const FString& Dir, const FString& RequiredModule, FString& Path, FString& AbsolutePath)
{
FString Extension = FPaths::GetExtension(RequiredModule);
bool IsJs = Extension == TEXT("js") || Extension == TEXT("mjs") || Extension == TEXT("cjs") || Extension == TEXT("json");
if (IsJs && SearchModuleWithExtInDir(Dir, RequiredModule, Path, AbsolutePath))
return true;
return SearchModuleWithExtInDir(Dir, RequiredModule + ".js", Path, AbsolutePath) ||
SearchModuleWithExtInDir(Dir, RequiredModule + ".mjs", Path, AbsolutePath) ||
SearchModuleWithExtInDir(Dir, RequiredModule + ".cjs", Path, AbsolutePath) ||
#if defined(WITH_V8_BYTECODE)
SearchModuleWithExtInDir(Dir, RequiredModule + ".mbc", Path, AbsolutePath) ||
SearchModuleWithExtInDir(Dir, RequiredModule + ".cbc", Path, AbsolutePath) ||
#endif
SearchModuleWithExtInDir(Dir, RequiredModule / "package.json", Path, AbsolutePath) ||
SearchModuleWithExtInDir(Dir, RequiredModule / "index.js", Path, AbsolutePath);
}
bool DefaultJSModuleLoader::SearchModuleWithExtInDir(
const FString& Dir, const FString& RequiredModule, FString& Path, FString& AbsolutePath)
{
return CheckExists(Dir / RequiredModule, Path, AbsolutePath) ||
(!Dir.EndsWith(TEXT("node_modules")) && CheckExists(Dir / TEXT("node_modules") / RequiredModule, Path, AbsolutePath));
}
bool DefaultJSModuleLoader::Search(const FString& RequiredDir, const FString& RequiredModule, FString& Path, FString& AbsolutePath)
{
if (SearchModuleInDir(RequiredDir, RequiredModule, Path, AbsolutePath))
{
return true;
}
if (RequiredDir != TEXT("") && !RequiredModule.GetCharArray().Contains('/') && !RequiredModule.EndsWith(TEXT(".js")) &&
!RequiredModule.EndsWith(TEXT(".mjs")))
{
// 调用require的文件所在的目录往上找
TArray<FString> pathFrags;
RequiredDir.ParseIntoArray(pathFrags, TEXT("/"));
pathFrags.Pop(); // has try in "if (SearchModuleInDir(RequiredDir, RequiredModule, Path, AbsolutePath))"
while (pathFrags.Num() > 0)
{
if (!pathFrags.Last().Equals(TEXT("node_modules")))
{
if (SearchModuleInDir(FString::Join(pathFrags, TEXT("/")), RequiredModule, Path, AbsolutePath))
{
return true;
}
}
pathFrags.Pop();
}
}
return SearchModuleInDir(FPaths::ProjectContentDir() / ScriptRoot, RequiredModule, Path, AbsolutePath) ||
(ScriptRoot != TEXT("JavaScript") &&
SearchModuleInDir(FPaths::ProjectContentDir() / TEXT("JavaScript"), RequiredModule, Path, AbsolutePath));
}
bool DefaultJSModuleLoader::Load(const FString& Path, TArray<uint8>& Content)
{
// return (FPaths::FileExists(FullPath) && FFileHelper::LoadFileToString(Content, *FullPath));
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
IFileHandle* FileHandle = PlatformFile.OpenRead(*Path);
if (FileHandle)
{
int len = FileHandle->Size();
Content.Reset(len + 2);
Content.AddUninitialized(len);
const bool Success = FileHandle->Read(Content.GetData(), len);
delete FileHandle;
return Success;
}
return false;
}
FString& DefaultJSModuleLoader::GetScriptRoot()
{
return ScriptRoot;
}
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,211 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "DelegateWrapper.h"
#include "ObjectMapper.h"
#include "V8Utils.h"
namespace PUERTS_NAMESPACE
{
v8::Local<v8::FunctionTemplate> FDelegateWrapper::ToFunctionTemplate(v8::Isolate* Isolate)
{
auto Result = v8::FunctionTemplate::New(Isolate, New);
Result->InstanceTemplate()->SetInternalFieldCount(2);
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Bind"), v8::FunctionTemplate::New(Isolate, Bind));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "IsBound"), v8::FunctionTemplate::New(Isolate, IsBound));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Unbind"), v8::FunctionTemplate::New(Isolate, Unbind));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Execute"), v8::FunctionTemplate::New(Isolate, Execute));
return Result;
}
void FDelegateWrapper::New(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
}
void FDelegateWrapper::IsBound(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
auto DelegatePtr = FV8Utils::GetPointerFast<FScriptDelegate>(Info.Holder(), 0);
Info.GetReturnValue().Set(DelegatePtr->IsBound());
}
void FDelegateWrapper::Bind(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
if (Info.Length() == 1 && Info[0]->IsFunction())
{
auto DelegatePtr = FV8Utils::GetPointerFast<void>(Info.Holder(), 0);
FV8Utils::IsolateData<IObjectMapper>(Isolate)->AddToDelegate(
Isolate, Context, DelegatePtr, v8::Local<v8::Function>::Cast(Info[0]));
return;
}
if (Info.Length() == 2 && Info[0]->IsObject() && Info[1]->IsString())
{
if (auto Object = FV8Utils::GetUObject(Info[0].As<v8::Object>()))
{
if (FV8Utils::IsReleasedPtr(Object))
{
FV8Utils::ThrowException(Isolate, "passing a invalid object");
return;
}
auto DelegatePtr = FV8Utils::GetPointerFast<FScriptDelegate>(Info.Holder(), 0);
FScriptDelegate Delegate;
Delegate.BindUFunction(Object, FName(*FV8Utils::ToFString(Isolate, Info[1])));
*DelegatePtr = Delegate;
return;
}
}
FV8Utils::ThrowException(Isolate, "invalid arguments");
}
void FDelegateWrapper::Unbind(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
auto DelegatePtr = FV8Utils::GetPointerFast<void>(Info.Holder(), 0);
FV8Utils::IsolateData<IObjectMapper>(Isolate)->ClearDelegate(Isolate, Context, DelegatePtr);
}
void FDelegateWrapper::Execute(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
auto DelegatePtr = FV8Utils::GetPointerFast<void>(Info.Holder(), 0);
FV8Utils::IsolateData<IObjectMapper>(Isolate)->ExecuteDelegate(Isolate, Context, Info, DelegatePtr);
}
v8::Local<v8::FunctionTemplate> FMulticastDelegateWrapper::ToFunctionTemplate(v8::Isolate* Isolate)
{
auto Result = v8::FunctionTemplate::New(Isolate, New);
Result->InstanceTemplate()->SetInternalFieldCount(2);
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Add"), v8::FunctionTemplate::New(Isolate, Add));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Remove"), v8::FunctionTemplate::New(Isolate, Remove));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Clear"), v8::FunctionTemplate::New(Isolate, Clear));
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, "Broadcast"), v8::FunctionTemplate::New(Isolate, Broadcast));
return Result;
}
void FMulticastDelegateWrapper::New(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
}
void FMulticastDelegateWrapper::Add(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
if (Info.Length() == 1 && Info[0]->IsFunction())
{
auto DelegatePtr = FV8Utils::GetPointerFast<void>(Info.Holder(), 0);
FV8Utils::IsolateData<IObjectMapper>(Isolate)->AddToDelegate(
Isolate, Context, DelegatePtr, v8::Local<v8::Function>::Cast(Info[0]));
return;
}
if (Info.Length() == 2 && Info[0]->IsObject() && Info[1]->IsString())
{
if (auto Object = FV8Utils::GetUObject(Info[0].As<v8::Object>()))
{
if (FV8Utils::IsReleasedPtr(Object))
{
FV8Utils::ThrowException(Isolate, "passing a invalid object");
return;
}
auto DelegatePtr = FV8Utils::GetPointerFast<void>(Info.Holder(), 0);
if (auto Property = CastFieldMacro<MulticastDelegatePropertyMacro>(
FV8Utils::IsolateData<IObjectMapper>(Isolate)->FindDelegateProperty(DelegatePtr)))
{
FScriptDelegate Delegate;
Delegate.BindUFunction(Object, FName(*FV8Utils::ToFString(Isolate, Info[1])));
#if ENGINE_MINOR_VERSION >= 23 || ENGINE_MAJOR_VERSION > 4
if (Property->IsA<MulticastSparseDelegatePropertyMacro>())
{
Property->AddDelegate(MoveTemp(Delegate), nullptr, DelegatePtr);
}
else
#endif
{
static_cast<FMulticastScriptDelegate*>(DelegatePtr)->AddUnique(Delegate);
}
return;
}
}
}
FV8Utils::ThrowException(Isolate, "invalid arguments");
}
void FMulticastDelegateWrapper::Remove(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
if (Info.Length() == 1 && Info[0]->IsFunction())
{
auto DelegatePtr = FV8Utils::GetPointerFast<void>(Info.Holder(), 0);
FV8Utils::IsolateData<IObjectMapper>(Isolate)->RemoveFromDelegate(
Isolate, Context, DelegatePtr, v8::Local<v8::Function>::Cast(Info[0]));
}
else
{
FV8Utils::ThrowException(Isolate, "invalid arguments");
}
}
void FMulticastDelegateWrapper::Clear(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
auto DelegatePtr = FV8Utils::GetPointerFast<void>(Info.Holder(), 0);
FV8Utils::IsolateData<IObjectMapper>(Isolate)->ClearDelegate(Isolate, Context, DelegatePtr);
}
void FMulticastDelegateWrapper::Broadcast(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
auto DelegatePtr = FV8Utils::GetPointerFast<void>(Info.Holder(), 0);
FV8Utils::IsolateData<IObjectMapper>(Isolate)->ExecuteDelegate(Isolate, Context, Info, DelegatePtr);
}
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,62 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include "CoreMinimal.h"
#include "CoreUObject.h"
#include <memory>
#include <vector>
#include "PropertyTranslator.h"
#include "FunctionTranslator.h"
#include "NamespaceDef.h"
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#pragma warning(push, 0)
#include "libplatform/libplatform.h"
#include "v8.h"
#pragma warning(pop)
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
namespace PUERTS_NAMESPACE
{
class FDelegateWrapper
{
public:
static v8::Local<v8::FunctionTemplate> ToFunctionTemplate(v8::Isolate* Isolate);
private:
static void New(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Bind(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void IsBound(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Unbind(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Execute(const v8::FunctionCallbackInfo<v8::Value>& Info);
};
class FMulticastDelegateWrapper
{
public:
static v8::Local<v8::FunctionTemplate> ToFunctionTemplate(v8::Isolate* Isolate);
private:
static void New(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Add(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Remove(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Clear(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Broadcast(const v8::FunctionCallbackInfo<v8::Value>& Info);
};
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,29 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "DynamicDelegateProxy.h"
void UDynamicDelegateProxy::Fire()
{
// Do Nothing
}
void UDynamicDelegateProxy::ProcessEvent(UFunction*, void* Params)
{
#ifdef THREAD_SAFE
v8::Locker Locker(Isolate);
#endif
auto PinedDynamicInvoker = DynamicInvoker.Pin();
if (PinedDynamicInvoker && Owner.IsValid())
{
if (ensureAlwaysMsgf(!JsFunction.IsEmpty(), TEXT("Invalid JS Function")))
{
PinedDynamicInvoker->InvokeDelegateCallback(this, Params);
}
}
}
@@ -0,0 +1,51 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include "NamespaceDef.h"
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#pragma warning(push, 0)
#include "libplatform/libplatform.h"
#include "v8.h"
#pragma warning(pop)
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
#include "DynamicInvoker.h"
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "DynamicDelegateProxy.generated.h"
/**
*
*/
UCLASS()
class UDynamicDelegateProxy : public UObject
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "TGameJS")
void Fire();
void ProcessEvent(UFunction*, void* Parms) override;
TWeakPtr<PUERTS_NAMESPACE::IDynamicInvoker, ESPMode::ThreadSafe> DynamicInvoker;
TWeakObjectPtr<UFunction> SignatureFunction;
// So, only uobject's delelgate is supported!
TWeakObjectPtr<UObject> Owner;
v8::UniquePersistent<v8::Function> JsFunction;
#ifdef THREAD_SAFE
v8::Isolate* Isolate;
#endif
};
@@ -0,0 +1,136 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "CoreMinimal.h"
#include "Binding.hpp"
#include "UEDataBinding.hpp"
#include "V8Utils.h"
#if !defined(ENGINE_INDEPENDENT_JSENV)
#include "Kismet/DataTableFunctionLibrary.h"
#include "Components/SceneComponent.h"
#include "Engine/World.h"
#endif
UsingUClass(UObject);
UsingUClass(UClass);
UsingUClass(UStruct);
#if !defined(ENGINE_INDEPENDENT_JSENV)
UsingUClass(UWorld); // for return type
UsingUClass(USceneComponent);
UsingUClass(UActorComponent);
UsingUClass(UDataTable);
UsingUClass(UDataTableFunctionLibrary);
#endif
#ifdef PUERTS_FTEXT_AS_OBJECT
UsingCppType(FText);
static PUERTS_NAMESPACE::CFunctionInfoWithCustomSignature FormatSignature(
"(Fmt: string | FText, ...InArguments: (string | number | FText) []) :FText");
static void FText_Format(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
FTextFormat Fmt;
auto P0 = Info[0];
if (P0->IsString())
{
Fmt = FTextFormat::FromString(PUERTS_NAMESPACE::FV8Utils::ToFString(Isolate, P0));
}
else if (::PUERTS_NAMESPACE::v8_impl::Converter<FText*>::accept(Context, P0))
{
Fmt = *::PUERTS_NAMESPACE::v8_impl::Converter<FText*>::toCpp(Context, P0);
}
else
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Fmt expect a string or FText");
return;
}
FFormatOrderedArguments Args;
for (int i = 1; i < Info.Length(); i++)
{
if (Info[i]->IsInt32())
{
Args.Add(FFormatArgumentValue(Info[i]->Int32Value(Context).FromJust()));
}
else if (Info[i]->IsNumber())
{
Args.Add(FFormatArgumentValue(Info[i]->ToNumber(Context).ToLocalChecked()->Value()));
}
else if (Info[i]->IsString())
{
Args.Add(FFormatArgumentValue(FText::FromString(PUERTS_NAMESPACE::FV8Utils::ToFString(Isolate, Info[i]))));
}
else if (Info[i]->IsObject() && ::PUERTS_NAMESPACE::v8_impl::Converter<FText*>::accept(Context, Info[i]))
{
Args.Add(FFormatArgumentValue(*::PUERTS_NAMESPACE::v8_impl::Converter<FText*>::toCpp(Context, Info[i])));
}
else
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "InArguments expect a number/string/FText");
return;
}
}
Info.GetReturnValue().Set(::PUERTS_NAMESPACE::v8_impl::Converter<FText>::toScript(Context, FText::Format(Fmt, Args)));
}
#endif
struct AutoRegisterForUE
{
AutoRegisterForUE()
{
PUERTS_NAMESPACE::DefineClass<UObject>()
#if ENGINE_MAJOR_VERSION > 4 || ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION >= 23
.Method("CreateDefaultSubobject",
SelectFunction(UObject * (UObject::*) (FName, UClass*, UClass*, bool, bool), &UObject::CreateDefaultSubobject))
#else
.Method("CreateDefaultSubobject", SelectFunction(UObject * (UObject::*) (FName, UClass*, UClass*, bool, bool, bool),
&UObject::CreateDefaultSubobject))
#endif
.Method("GetName", SelectFunction(FString(UObjectBaseUtility::*)() const, &UObjectBaseUtility::GetName))
.Method("GetOuter", MakeFunction(&UObject::GetOuter))
.Method("GetClass", MakeFunction(&UObject::GetClass))
.Method("IsA", SelectFunction(bool (UObjectBaseUtility::*)(UClass*) const, &UObjectBaseUtility::IsA))
.Method("IsNative", MakeFunction(&UObjectBaseUtility::IsNative))
#if !defined(ENGINE_INDEPENDENT_JSENV)
.Method("GetWorld", MakeFunction(&UObject::GetWorld))
#endif
.Register();
PUERTS_NAMESPACE::DefineClass<UStruct>()
.Method("IsChildOf", SelectFunction(bool (UStruct::*)(const UStruct*) const, &UStruct::IsChildOf))
.Register();
#if !defined(ENGINE_INDEPENDENT_JSENV)
PUERTS_NAMESPACE::DefineClass<USceneComponent>()
.Method("SetupAttachment", MakeFunction(&USceneComponent::SetupAttachment))
.Register();
PUERTS_NAMESPACE::DefineClass<UActorComponent>()
.Method("RegisterComponent", MakeFunction(&UActorComponent::RegisterComponent))
.Register();
PUERTS_NAMESPACE::DefineClass<UDataTableFunctionLibrary>()
.Function("Generic_GetDataTableRowFromName", MakeFunction(&UDataTableFunctionLibrary::Generic_GetDataTableRowFromName))
.Register();
#endif
#ifdef PUERTS_FTEXT_AS_OBJECT
PUERTS_NAMESPACE::DefineClass<FText>()
.Constructor<>() // make destructor available
.Method("ToString", MakeFunction(&FText::ToString))
.Function("FromStringTable", MakeFunction(&FText::FromStringTable))
.Function("FromString", SelectFunction(FText(*)(const FString&), &FText::FromString))
.Function("Format", FText_Format, &FormatSignature)
.Register();
#endif
}
};
AutoRegisterForUE _AutoRegisterForUE__;
@@ -0,0 +1,9 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "ExtensionMethods.h"
@@ -0,0 +1,609 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "FFIBinding.h"
#ifdef WITH_FFI
#include "JSClassRegister.h"
#include "V8Utils.h"
#if _MSC_VER
#define FFI_BUILDING
#endif
#if PLATFORM_ANDROID_ARM
#include "armeabi-v7a/ffi.h"
#elif PLATFORM_ANDROID_ARM64
#include "arm64-v8a/ffi.h"
#else
#include "ffi.h"
#endif
static FuncPtr* GFuncArray = nullptr;
static uint32_t GFuncArrayLength = 0;
void SetFunctionArray(FuncPtr* FuncArray, uint32_t FuncArrayLength)
{
GFuncArray = FuncArray;
GFuncArrayLength = FuncArrayLength;
}
static v8::Local<v8::Uint8Array> WrapPointer(v8::Isolate* Isolate, void* Ptr, size_t Length)
{
v8::Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(Isolate, Ptr, Length);
return v8::Uint8Array::New(ab, 0, Length);
}
static v8::Local<v8::Uint8Array> WrapPointer(v8::Isolate* Isolate, void* Ptr)
{
return WrapPointer(Isolate, Ptr, 0);
}
static char* ArrayBufferData(v8::Local<v8::Value> Val)
{
if (!Val->IsArrayBufferView())
return nullptr;
auto ui = Val.As<v8::ArrayBufferView>();
auto ab_c = ui->Buffer()->GetContents();
return static_cast<char*>(ab_c.Data()) + ui->ByteOffset();
}
static size_t ArrayBufferLength(v8::Local<v8::Value> Val)
{
if (!Val->IsArrayBufferView())
return 0;
auto ui = Val.As<v8::ArrayBufferView>();
return ui->ByteLength();
}
static bool IsArrayBuffer(v8::Local<v8::Value> Val)
{
return Val->IsArrayBufferView();
}
inline int64_t GetInt64(v8::Local<v8::Value> Val)
{
return Val->IsNumber() ? (Val->IsBigInt() ? Val.As<v8::BigInt>()->Int64Value() : (int64_t) Val.As<v8::Number>()->Value()) : 0;
}
static void FFIPrepCif(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
unsigned int Nargs;
char *Cif, *ArgTypes, *RetType;
ffi_status Status;
ffi_abi Abi;
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
if (Info.Length() != 5 || !IsArrayBuffer(Info[0]) || !IsArrayBuffer(Info[3]) || !IsArrayBuffer(Info[4]))
{
PUERTS_NAMESPACE::FV8Utils::ThrowException(Isolate, "Bad parameters.");
return;
}
Cif = ArrayBufferData(Info[0]);
Abi = (ffi_abi) Info[1]->Uint32Value(Context).ToChecked();
Nargs = Info[2]->Uint32Value(Context).ToChecked();
RetType = ArrayBufferData(Info[3]);
ArgTypes = ArrayBufferData(Info[4]);
Status = ffi_prep_cif(
reinterpret_cast<ffi_cif*>(Cif), Abi, Nargs, reinterpret_cast<ffi_type*>(RetType), reinterpret_cast<ffi_type**>(ArgTypes));
Info.GetReturnValue().Set(v8::Integer::New(Isolate, Status));
}
static void FFIPrepCifVar(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
unsigned int FixArgs, TotoalArgs;
char *Cif, *ArgTypes, *RetType;
ffi_status Status;
ffi_abi Abi;
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
if (Info.Length() != 6 || !IsArrayBuffer(Info[0]) || !IsArrayBuffer(Info[4]) || !IsArrayBuffer(Info[5]))
{
PUERTS_NAMESPACE::FV8Utils::ThrowException(Isolate, "Bad parameters.");
return;
}
Cif = ArrayBufferData(Info[0]);
Abi = (ffi_abi) Info[1]->Uint32Value(Context).ToChecked();
FixArgs = Info[2]->Uint32Value(Context).ToChecked();
TotoalArgs = Info[3]->Uint32Value(Context).ToChecked();
RetType = ArrayBufferData(Info[4]);
ArgTypes = ArrayBufferData(Info[5]);
Status = ffi_prep_cif_var(reinterpret_cast<ffi_cif*>(Cif), Abi, FixArgs, TotoalArgs, reinterpret_cast<ffi_type*>(RetType),
reinterpret_cast<ffi_type**>(ArgTypes));
Info.GetReturnValue().Set(v8::Integer::New(Isolate, Status));
}
class ClosureInfo
{
public:
ClosureInfo(v8::Isolate* InIsolate, v8::Local<v8::Context> InContext, v8::Local<v8::Function> InFunction, void* InCodeLoc,
ffi_closure* InClosure, size_t InRetSize)
: CodeLoc(InCodeLoc)
, Isolate(InIsolate)
, Context(InIsolate, InContext)
, Function(InIsolate, InFunction)
, Closure(InClosure)
, RetSize(InRetSize)
{
}
void* CodeLoc;
v8::Isolate* Isolate;
v8::Global<v8::Context> Context;
v8::Global<v8::Function> Function;
ffi_closure* Closure;
size_t RetSize;
v8::Global<v8::ArrayBuffer> Buffer;
};
static void ClosureWrap(ffi_cif* Cif, void* Ret, void** Args, void* UserData)
{
ClosureInfo* CI = reinterpret_cast<ClosureInfo*>(UserData);
v8::Isolate* Isolate = CI->Isolate;
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = CI->Context.Get(Isolate);
v8::Context::Scope ContextScope(Context);
v8::Local<v8::Value> Argv[2] = {WrapPointer(Isolate, Ret, CI->RetSize), WrapPointer(Isolate, Args, 0)};
CI->Function.Get(CI->Isolate)->Call(Context, Context->Global(), 2, Argv);
}
static void FFIAllocClosure(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
if (!IsArrayBuffer(Info[0]))
{
PUERTS_NAMESPACE::FV8Utils::ThrowException(Isolate, "ffi_alloc_closure: Uint32Array expected as #1 argument");
return;
}
if (!Info[1]->IsFunction())
{
PUERTS_NAMESPACE::FV8Utils::ThrowException(Isolate, "ffi_alloc_closure: function expected as #2 argument");
return;
}
if (!Info[2]->IsNumber())
{
PUERTS_NAMESPACE::FV8Utils::ThrowException(Isolate, "ffi_alloc_closure: number expected as #3 argument");
return;
}
ffi_cif* Cif = reinterpret_cast<ffi_cif*>(ArrayBufferData(Info[0]));
v8::Local<v8::Function> Callback = v8::Local<v8::Function>::Cast(Info[1]);
size_t RetSize = Info[2]->Uint32Value(Context).ToChecked();
void* CodeLoc;
ffi_closure* Closure = reinterpret_cast<ffi_closure*>(ffi_closure_alloc(sizeof(ffi_closure), &CodeLoc));
if (!Closure)
{
PUERTS_NAMESPACE::FV8Utils::ThrowException(Isolate, "ffi_alloc_closure: alloc closure fail!");
return;
}
v8::Local<v8::ArrayBuffer> AB = v8::ArrayBuffer::New(Isolate, sizeof(ClosureInfo));
ClosureInfo* CI = new (AB->GetContents().Data()) ClosureInfo(Isolate, Context, Callback, CodeLoc, Closure, RetSize);
ffi_status status = ffi_prep_closure_loc(Closure, Cif, ClosureWrap, CI, CodeLoc);
if (status != FFI_OK)
{
ffi_closure_free(Closure);
PUERTS_NAMESPACE::FV8Utils::ThrowException(Isolate, "ffi_alloc_closure: ffi_prep_closure_loc fail!");
return;
}
Info.GetReturnValue().Set(v8::Uint8Array::New(AB, 0, sizeof(ClosureInfo)));
}
static void FFIFreeClosure(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
if (!IsArrayBuffer(Info[0]))
{
PUERTS_NAMESPACE::FV8Utils::ThrowException(Isolate, "ffi_free_closure: invalid type for #1 argument");
return;
}
if (ArrayBufferLength(Info[0]) != sizeof(ClosureInfo))
{
PUERTS_NAMESPACE::FV8Utils::ThrowException(Isolate, "ffi_free_closure: #1 argument length not match");
return;
}
ClosureInfo* CI = reinterpret_cast<ClosureInfo*>(ArrayBufferData(Info[0]));
ffi_closure_free(CI->Closure);
CI->~ClosureInfo();
}
static void FFICall(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
if (Info.Length() != 4)
{
PUERTS_NAMESPACE::FV8Utils::ThrowException(Isolate, "ffi_call(): requires 4 arguments!");
return;
}
if (!IsArrayBuffer(Info[0]))
{
PUERTS_NAMESPACE::FV8Utils::ThrowException(Isolate, "ffi_call(): Uint32Array expected as #1 argument");
return;
}
if (Info[1]->IsNumber())
{
if (Info[1]->Uint32Value(Context).ToChecked() >= GFuncArrayLength)
{
PUERTS_NAMESPACE::FV8Utils::ThrowException(Isolate, "ffi_call(): function index out of range!");
return;
}
}
char* Cif = ArrayBufferData(Info[0]);
char* FuncPtr = Info[1]->IsNumber() ? reinterpret_cast<char*>(GFuncArray[Info[1]->Uint32Value(Context).ToChecked()])
: ArrayBufferData(Info[1]);
char* ReturnPtr = ArrayBufferData(Info[2]);
char* ArgsPtr = ArrayBufferData(Info[3]);
#if __OBJC__ || __OBJC2__
// @try {
#endif
ffi_call(
reinterpret_cast<ffi_cif*>(Cif), FFI_FN(FuncPtr), reinterpret_cast<void*>(ReturnPtr), reinterpret_cast<void**>(ArgsPtr));
#if __OBJC__ || __OBJC2__
// } @catch (id ex) {
// PUERTS_NAMESPACE::FV8Utils::ThrowException(Isolate, "ffi_call() throw exeption!");
// return;
// }
#endif
Info.GetReturnValue().SetUndefined();
}
static void WritePointer(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
if (!IsArrayBuffer(Info[0]))
{
PUERTS_NAMESPACE::FV8Utils::ThrowException(Isolate, "writePointer: Uint32Array expected as #1 argument");
return;
}
auto Value = Info[1];
if (!(Value->IsNull() || IsArrayBuffer(Value)))
{
PUERTS_NAMESPACE::FV8Utils::ThrowException(Isolate, "writePointer: Uint32Array expected as #3 argument");
return;
}
int64_t Offset = GetInt64(Info[2]);
char* Ptr = ArrayBufferData(Info[0]) + Offset;
if (Value->IsNull())
{
*reinterpret_cast<char**>(Ptr) = NULL;
}
else
{
char* ValuePtr = ArrayBufferData(Value);
if (Info.Length() >= 4 && Info[3]->IsNumber())
{
ValuePtr += GetInt64(Info[3]);
}
*reinterpret_cast<char**>(Ptr) = ValuePtr;
}
Info.GetReturnValue().SetUndefined();
}
static void ReadPointer(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
if (!IsArrayBuffer(Info[0]))
{
PUERTS_NAMESPACE::FV8Utils::ThrowException(Isolate, "readPointer: Uint32Array expected as #1 argument");
return;
}
int64_t Offset = GetInt64(Info[1]);
char* Ptr = ArrayBufferData(Info[0]) + Offset;
char* Val = *reinterpret_cast<char**>(Ptr);
size_t Size = !Info[2]->IsNull() ? Info[2]->Uint32Value(Context).ToChecked() : 0;
Info.GetReturnValue().Set(WrapPointer(Isolate, Val, Size));
}
static void WriteUTF8String(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
if (!IsArrayBuffer(Info[0]))
{
PUERTS_NAMESPACE::FV8Utils::ThrowException(Isolate, "WriteString: Uint32Array expected as #1 argument");
return;
}
if (!Info[1]->IsString())
{
PUERTS_NAMESPACE::FV8Utils::ThrowException(Isolate, "WriteString: string expected as #2 argument");
return;
}
v8::String::Utf8Value utf8Str(Isolate, Info[1]);
int64_t Offset = GetInt64(Info[2]);
if (utf8Str.length() >= ArrayBufferLength(Info[0]) - Offset)
{
PUERTS_NAMESPACE::FV8Utils::ThrowException(Isolate, "WriteString: no enough space");
return;
}
char* Ptr = ArrayBufferData(Info[0]) + Offset;
memcpy(Ptr, *utf8Str, utf8Str.length() + 1);
}
static void ReadUTF8String(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
if (!IsArrayBuffer(Info[0]))
{
PUERTS_NAMESPACE::FV8Utils::ThrowException(Isolate, "ReadCString: Uint32Array expected as #1 argument");
return;
}
int64_t Offset = GetInt64(Info[1]);
char* Ptr = ArrayBufferData(Info[0]) + Offset;
Info.GetReturnValue().Set(PUERTS_NAMESPACE::FV8Utils::ToV8String(Isolate, Ptr));
}
static void UTF8Length(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
if (!Info[0]->IsString())
{
PUERTS_NAMESPACE::FV8Utils::ThrowException(Isolate, "WriteString: string expected as #2 argument");
return;
}
v8::String::Utf8Value utf8Str(Isolate, Info[0]);
Info.GetReturnValue().Set(utf8Str.length());
}
static void Init(v8::Local<v8::Context> Context, v8::Local<v8::Object> Exports)
{
v8::Isolate* Isolate = Context->GetIsolate();
Exports
->Set(Context, PUERTS_NAMESPACE::FV8Utils::ToV8String(Isolate, "ffi_prep_cif"),
v8::FunctionTemplate::New(Isolate, FFIPrepCif)->GetFunction(Context).ToLocalChecked())
.Check();
Exports
->Set(Context, PUERTS_NAMESPACE::FV8Utils::ToV8String(Isolate, "ffi_prep_cif_var"),
v8::FunctionTemplate::New(Isolate, FFIPrepCifVar)->GetFunction(Context).ToLocalChecked())
.Check();
Exports
->Set(Context, PUERTS_NAMESPACE::FV8Utils::ToV8String(Isolate, "ffi_call"),
v8::FunctionTemplate::New(Isolate, FFICall)->GetFunction(Context).ToLocalChecked())
.Check();
Exports
->Set(Context, PUERTS_NAMESPACE::FV8Utils::ToV8String(Isolate, "writePointer"),
v8::FunctionTemplate::New(Isolate, WritePointer)->GetFunction(Context).ToLocalChecked())
.Check();
Exports
->Set(Context, PUERTS_NAMESPACE::FV8Utils::ToV8String(Isolate, "readPointer"),
v8::FunctionTemplate::New(Isolate, ReadPointer)->GetFunction(Context).ToLocalChecked())
.Check();
Exports
->Set(Context, PUERTS_NAMESPACE::FV8Utils::ToV8String(Isolate, "writeUTF8String"),
v8::FunctionTemplate::New(Isolate, WriteUTF8String)->GetFunction(Context).ToLocalChecked())
.Check();
Exports
->Set(Context, PUERTS_NAMESPACE::FV8Utils::ToV8String(Isolate, "readUTF8String"),
v8::FunctionTemplate::New(Isolate, ReadUTF8String)->GetFunction(Context).ToLocalChecked())
.Check();
Exports
->Set(Context, PUERTS_NAMESPACE::FV8Utils::ToV8String(Isolate, "UTF8Length"),
v8::FunctionTemplate::New(Isolate, UTF8Length)->GetFunction(Context).ToLocalChecked())
.Check();
Exports
->Set(Context, PUERTS_NAMESPACE::FV8Utils::ToV8String(Isolate, "ffi_alloc_closure"),
v8::FunctionTemplate::New(Isolate, FFIAllocClosure)->GetFunction(Context).ToLocalChecked())
.Check();
Exports
->Set(Context, PUERTS_NAMESPACE::FV8Utils::ToV8String(Isolate, "ffi_free_closure"),
v8::FunctionTemplate::New(Isolate, FFIFreeClosure)->GetFunction(Context).ToLocalChecked())
.Check();
#define SET_FFI_ENUM(value) \
Exports->DefineOwnProperty(Context, PUERTS_NAMESPACE::FV8Utils::ToV8String(Isolate, #value), \
v8::Integer::New(Isolate, (uint32_t) (value)), static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete))
SET_FFI_ENUM(FFI_OK);
SET_FFI_ENUM(FFI_BAD_TYPEDEF);
SET_FFI_ENUM(FFI_BAD_ABI);
SET_FFI_ENUM(FFI_DEFAULT_ABI);
SET_FFI_ENUM(FFI_FIRST_ABI);
SET_FFI_ENUM(FFI_LAST_ABI);
SET_FFI_ENUM(FFI_TYPE_STRUCT);
#undef SET_FFI_ENUM
auto Types = v8::Object::New(Isolate);
#define SET_FFI_TYPE(key, value) \
Types->DefineOwnProperty(Context, PUERTS_NAMESPACE::FV8Utils::ToV8String(Isolate, key), \
WrapPointer(Isolate, reinterpret_cast<char*>(&value)), static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete))
SET_FFI_TYPE("void", ffi_type_void);
SET_FFI_TYPE("uint8", ffi_type_uint8);
SET_FFI_TYPE("int8", ffi_type_sint8);
SET_FFI_TYPE("uint16", ffi_type_uint16);
SET_FFI_TYPE("int16", ffi_type_sint16);
SET_FFI_TYPE("uint32", ffi_type_uint32);
SET_FFI_TYPE("int32", ffi_type_sint32);
SET_FFI_TYPE("uint64", ffi_type_uint64);
SET_FFI_TYPE("int64", ffi_type_sint64);
SET_FFI_TYPE("float", ffi_type_float);
SET_FFI_TYPE("double", ffi_type_double);
SET_FFI_TYPE("pointer", ffi_type_pointer);
#undef SET_FFI_TYPE
Exports->Set(Context, PUERTS_NAMESPACE::FV8Utils::ToV8String(Isolate, "FFI_TYPES"), Types).Check();
auto SizeOf = v8::Object::New(Isolate);
#define SET_SIZEOF(key, type) \
SizeOf->DefineOwnProperty(Context, PUERTS_NAMESPACE::FV8Utils::ToV8String(Isolate, key), \
v8::Integer::New(Isolate, static_cast<uint32_t>(sizeof(type))), \
static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete))
SET_SIZEOF("uint8", uint8_t);
SET_SIZEOF("int8", int8_t);
SET_SIZEOF("uint16", uint16_t);
SET_SIZEOF("int16", int16_t);
SET_SIZEOF("uint32", uint32_t);
SET_SIZEOF("int32", int32_t);
SET_SIZEOF("uint64", uint64_t);
SET_SIZEOF("int64", int64_t);
SET_SIZEOF("float", float);
SET_SIZEOF("double", double);
SET_SIZEOF("pointer", char*);
#undef SET_SIZEOF
Exports->Set(Context, PUERTS_NAMESPACE::FV8Utils::ToV8String(Isolate, "sizeof"), SizeOf).Check();
auto AlignOf = v8::Object::New(Isolate);
#if _MSC_VER
#define SET_ALIGNOF(name, type) \
struct s_##name \
{ \
type a; \
}; \
AlignOf->DefineOwnProperty(Context, PUERTS_NAMESPACE::FV8Utils::ToV8String(Isolate, #name), \
v8::Integer::New(Isolate, static_cast<uint32_t>(alignof(struct s_##name))), \
static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete))
#else
#define SET_ALIGNOF(name, type) \
struct s_##name \
{ \
type a; \
}; \
AlignOf->DefineOwnProperty(Context, PUERTS_NAMESPACE::FV8Utils::ToV8String(Isolate, #name), \
v8::Integer::New(Isolate, static_cast<uint32_t>(__alignof__(struct s_##name))), \
static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete))
#endif
SET_ALIGNOF(uint8, uint8_t);
SET_ALIGNOF(int8, int8_t);
SET_ALIGNOF(uint16, uint16_t);
SET_ALIGNOF(int16, int16_t);
SET_ALIGNOF(uint32, uint32_t);
SET_ALIGNOF(int32, int32_t);
SET_ALIGNOF(uint64, uint64_t);
SET_ALIGNOF(int64, int64_t);
SET_ALIGNOF(float, float);
SET_ALIGNOF(double, double);
SET_ALIGNOF(pointer, char*);
#undef SET_ALIGNOF
Exports->Set(Context, PUERTS_NAMESPACE::FV8Utils::ToV8String(Isolate, "alignof"), AlignOf).Check();
#define SET_Property(key, value) \
Exports->DefineOwnProperty(Context, PUERTS_NAMESPACE::FV8Utils::ToV8String(Isolate, key), \
v8::Integer::New(Isolate, (uint32_t) (value)), static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete))
SET_Property("FFI_ARG_SIZE", sizeof(ffi_arg));
SET_Property("FFI_SARG_SIZE", sizeof(ffi_sarg));
SET_Property("FFI_TYPE_SIZE", sizeof(ffi_type));
SET_Property("FFI_CIF_SIZE", sizeof(ffi_cif));
SET_Property("POINTER_SIZE", sizeof(char*));
#undef SET_Property
}
PUERTS_MODULE(ffi_bindings, Init);
#else
void SetFunctionArray(FuncPtr* FuncArray, uint32_t FuncArrayLength)
{
}
#endif
@@ -0,0 +1,740 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "FunctionTranslator.h"
#include "V8Utils.h"
#include "Misc/DefaultValueHelper.h"
#include <mutex>
static TMap<FName, TMap<FName, TMap<FName, FString>>> ParamDefaultMetas;
static TMap<FName, TMap<FName, FString>>* PC = nullptr;
static TMap<FName, FString>* PF = nullptr;
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 2
UE_DISABLE_OPTIMIZATION
#else
PRAGMA_DISABLE_OPTIMIZATION
#endif
static void ParamDefaultMetasInit()
{
// PC = &ParamDefaultMetas.Add(TEXT("MainObject"));
// PF = &PC->Add(TEXT("DefaultTest"));
// PF->Add(TEXT("Str"), TEXT("i am default"));
// PF->Add(TEXT("I"), TEXT("10"));
// PF->Add(TEXT("Vec"), TEXT("1.100000,2.200000,3.300000"));
#include "InitParamDefaultMetas.inl"
return;
}
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 2
UE_ENABLE_OPTIMIZATION
#else
PRAGMA_ENABLE_OPTIMIZATION
#endif
std::once_flag ParamDefaultMetasInitFlag;
TMap<FName, FString>* GetParamDefaultMetaFor(UFunction* InFunction)
{
std::call_once(ParamDefaultMetasInitFlag, ParamDefaultMetasInit);
UClass* OuterClass = InFunction->GetOuterUClass();
auto ClassParamDefaultMeta = ParamDefaultMetas.Find(OuterClass->GetFName());
if (ClassParamDefaultMeta)
{
return ClassParamDefaultMeta->Find(InFunction->GetFName());
}
return nullptr;
}
namespace PUERTS_NAMESPACE
{
static const int ARG_ARRAY_SIZE = 8;
#if defined(USE_GLOBAL_PARAMS_BUFFER)
// Global Buffer, Not thread safe
static void* Buffer = nullptr;
static int BufferSize = 0;
static void RequireBuffer(int RequireSize)
{
if (RequireSize > BufferSize)
{
if (Buffer)
FMemory::Free(Buffer);
Buffer = FMemory::Malloc(RequireSize, 16);
BufferSize = RequireSize;
}
}
class GlobalBufferAutoRelease
{
public:
~GlobalBufferAutoRelease()
{
if (Buffer)
FMemory::Free(Buffer);
Buffer = nullptr;
BufferSize = 0;
}
};
static GlobalBufferAutoRelease Dummy;
#endif
FFunctionTranslator::FFunctionTranslator(UFunction* InFunction, bool IsDelegate)
{
Init(InFunction, IsDelegate);
}
void FFunctionTranslator::Init(UFunction* InFunction, bool IsDelegate)
{
check(InFunction);
Function = InFunction;
#if WITH_EDITOR
FunctionName = Function->GetFName();
#endif
ParamsBufferSize = InFunction->PropertiesSize > InFunction->ParmsSize ? InFunction->PropertiesSize : InFunction->ParmsSize;
#if defined(USE_GLOBAL_PARAMS_BUFFER)
RequireBuffer(ParamsBufferSize);
#endif
if (IsDelegate)
{
IsInterfaceFunction = false;
IsStatic = false;
}
else
{
UClass* OuterClass = InFunction->GetOuterUClass();
IsInterfaceFunction = (OuterClass->HasAnyClassFlags(CLASS_Interface) && OuterClass != UInterface::StaticClass());
IsStatic = InFunction->HasAnyFunctionFlags(FUNC_Static);
}
Arguments.clear();
SkipWorldContextInArg0 = false;
for (TFieldIterator<PropertyMacro> It(InFunction); It && (It->PropertyFlags & CPF_Parm); ++It)
{
PropertyMacro* Property = *It;
static const FName WorldContextPinName(TEXT("__WorldContext"));
if (IsStatic && !InFunction->IsNative() && Property->GetFName() == WorldContextPinName && Arguments.size() == 0)
{
SkipWorldContextInArg0 = true;
;
}
if (Property->HasAnyPropertyFlags(CPF_ReturnParm))
{
Return = FPropertyTranslator::Create(Property);
}
else
{
Arguments.push_back(FPropertyTranslator::Create(Property));
}
}
ArgumentDefaultValues = nullptr;
if (!IsDelegate)
{
TMap<FName, FString>* MetaMap = GetParamDefaultMetaFor(InFunction);
if (MetaMap)
{
for (TFieldIterator<PropertyMacro> ParamIt(InFunction); ParamIt; ++ParamIt)
{
auto Property = *ParamIt;
if (Property->PropertyFlags & CPF_Parm)
{
if (!(Property->PropertyFlags & CPF_ReturnParm))
{
// const FName MetadataCppDefaultValueKey(*(FString(TEXT("CPP_Default_")) + Property->GetName()));
FString* DefaultValuePtr = nullptr;
DefaultValuePtr = MetaMap->Find(Property->GetFName());
if (DefaultValuePtr && !DefaultValuePtr->IsEmpty())
{
// UE_LOG(LogTemp, Warning, TEXT("Meta %s %s"), *Property->GetFName().ToString(), **DefaultValuePtr);
if (!ArgumentDefaultValues)
{
ArgumentDefaultValues = FMemory::Malloc(ParamsBufferSize, 16);
InFunction->InitializeStruct(ArgumentDefaultValues);
}
void* PropValuePtr = Property->ContainerPtrToValuePtr<void>(ArgumentDefaultValues);
if (const StructPropertyMacro* StructProp = CastFieldMacro<StructPropertyMacro>(Property))
{
if (StructProp->Struct == TBaseStructure<FVector>::Get())
{
FVector* Vector = (FVector*) PropValuePtr;
FDefaultValueHelper::ParseVector(**DefaultValuePtr, *Vector);
continue;
}
else if (StructProp->Struct == TBaseStructure<FVector2D>::Get())
{
FVector2D* Vector2D = (FVector2D*) PropValuePtr;
FDefaultValueHelper::ParseVector2D(**DefaultValuePtr, *Vector2D);
continue;
}
else if (StructProp->Struct == TBaseStructure<FRotator>::Get())
{
FRotator* Rotator = (FRotator*) PropValuePtr;
FDefaultValueHelper::ParseRotator(**DefaultValuePtr, *Rotator);
continue;
}
else if (StructProp->Struct == TBaseStructure<FColor>::Get())
{
FColor* Color = (FColor*) PropValuePtr;
FDefaultValueHelper::ParseColor(**DefaultValuePtr, *Color);
continue;
}
else if (StructProp->Struct == TBaseStructure<FLinearColor>::Get())
{
FLinearColor* LinearColor = (FLinearColor*) PropValuePtr;
LinearColor->InitFromString(**DefaultValuePtr);
continue;
}
}
#if ENGINE_MINOR_VERSION > 0 && ENGINE_MAJOR_VERSION > 4
Property->ImportText_Direct(**DefaultValuePtr, PropValuePtr, nullptr, PPF_None);
#else
Property->ImportText(**DefaultValuePtr, PropValuePtr, PPF_None, nullptr);
#endif
}
}
}
}
}
}
}
v8::Local<v8::FunctionTemplate> FFunctionTranslator::ToFunctionTemplate(v8::Isolate* Isolate)
{
return v8::FunctionTemplate::New(Isolate, Call, v8::External::New(Isolate, this));
}
void FFunctionTranslator::Call(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
FFunctionTranslator* This = static_cast<FFunctionTranslator*>((v8::Local<v8::External>::Cast(Info.Data()))->Value());
This->Call(Isolate, Context, Info);
}
void FFunctionTranslator::Call(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const v8::FunctionCallbackInfo<v8::Value>& Info)
{
UObject* CallObject = IsStatic ? BindObject.Get() : FV8Utils::GetUObject(Info.Holder());
if (!CallObject)
{
if (IsStatic) //延时初始化
{
CallObject = Function->GetOuterUClass()->GetDefaultObject();
BindObject = CallObject;
}
if (!CallObject)
{
FV8Utils::ThrowException(Isolate, "access a null object");
return;
}
}
if (FV8Utils::IsReleasedPtr(CallObject))
{
FV8Utils::ThrowException(Isolate, "access a invalid object");
return;
}
TWeakObjectPtr<UFunction> CallFunction =
!IsInterfaceFunction ? Function : (CallObject->GetClass()->FindFunctionByName(Function->GetFName()));
#if defined(USE_GLOBAL_PARAMS_BUFFER)
void* Params = Buffer;
#else
void* Params = ParamsBufferSize > 0 ? FMemory_Alloca(ParamsBufferSize) : nullptr;
#endif
#if WITH_EDITOR
if (!CallFunction.IsValid())
{
CallFunction = CallObject->GetClass()->FindFunctionByName(FunctionName);
Init(CallFunction.Get(), false);
}
#endif
auto CallFunctionPtr = CallFunction.Get();
if ((Function->FunctionFlags & FUNC_Native) && !(Function->FunctionFlags & FUNC_Net) &&
!CallFunctionPtr->HasAnyFunctionFlags(FUNC_UbergraphFunction))
{
FastCall(Isolate, Context, Info, CallObject, CallFunctionPtr, Params);
}
else
{
SlowCall(Isolate, Context, Info, CallObject, CallFunctionPtr, Params);
}
}
void FFunctionTranslator::SlowCall(v8::Isolate* Isolate, v8::Local<v8::Context>& Context,
const v8::FunctionCallbackInfo<v8::Value>& Info, UObject* CallObject, UFunction* CallFunction, void* Params)
{
if (Params)
{
FMemory::Memzero(Params, ParamsBufferSize);
}
if (!Call_ProcessParams(Isolate, Context, Info, Params, 0))
{
return;
}
CallObject->UObject::ProcessEvent(CallFunction, Params);
Call_ProcessReturnAndOutParams(Isolate, Context, Info, Params, 0);
}
void FFunctionTranslator::FastCall(v8::Isolate* Isolate, v8::Local<v8::Context>& Context,
const v8::FunctionCallbackInfo<v8::Value>& Info, UObject* CallObject, UFunction* CallFunction, void* Params)
{
if (Params)
{
FMemory::Memzero(Params, ParamsBufferSize);
if (Return)
{
Return->Property->InitializeValue_InContainer(Params);
}
}
FFrame NewStack(CallObject, CallFunction, Params, nullptr,
#if ENGINE_MINOR_VERSION >= 25 || ENGINE_MAJOR_VERSION > 4
Function->ChildProperties
#else
Function->Children
#endif
);
checkSlow(NewStack.Locals || Function->ParmsSize == 0);
FOutParmRec** LastOut = &NewStack.OutParms;
int Index = 0;
for (TFieldIterator<PropertyMacro> It(CallFunction); It && (It->PropertyFlags & CPF_Parm); ++It)
{
PropertyMacro* Property = *It;
FOutParmRec* Out = nullptr;
if (Property->HasAnyPropertyFlags(CPF_OutParm))
{
CA_SUPPRESS(6263)
Out = (FOutParmRec*) FMemory_Alloca(sizeof(FOutParmRec));
Out->Property = Property;
if (*LastOut)
{
(*LastOut)->NextOutParm = Out;
LastOut = &(*LastOut)->NextOutParm;
}
else
{
*LastOut = Out;
}
}
if (Property->HasAnyPropertyFlags(CPF_ReturnParm))
{
if (Property->HasAnyPropertyFlags(CPF_OutParm))
{
Out->PropAddr = Property->ContainerPtrToValuePtr<uint8>(Params);
}
continue;
}
if (UNLIKELY(ArgumentDefaultValues && Info[Index]->IsUndefined()))
{
Property->CopyCompleteValue_InContainer(Params, ArgumentDefaultValues);
if (Property->HasAnyPropertyFlags(CPF_OutParm))
{
Out->PropAddr = Property->ContainerPtrToValuePtr<uint8>(Params);
}
}
else
{
Property->InitializeValue_InContainer(Params);
if (Property->HasAnyPropertyFlags(CPF_OutParm))
{
if (!Arguments[Index]->JsToUEFastInContainer(
Isolate, Context, Info[Index], Params, reinterpret_cast<void**>(&(Out->PropAddr))))
{
return;
}
}
else
{
if (!Arguments[Index]->JsToUEInContainer(Isolate, Context, Info[Index], Params, false))
{
return;
}
}
}
++Index;
}
if (CallFunction->HasAnyFunctionFlags(FUNC_HasOutParms))
{
if (*LastOut)
{
(*LastOut)->NextOutParm = NULL;
}
}
const bool bHasReturnParam = CallFunction->ReturnValueOffset != MAX_uint16;
uint8* ReturnValueAddress = bHasReturnParam ? ((uint8*) Params + CallFunction->ReturnValueOffset) : nullptr;
CallFunction->Invoke(CallObject, NewStack, ReturnValueAddress);
if (Return)
{
Info.GetReturnValue().Set(Return->UEToJsInContainer(Isolate, Context, Params));
Return->Property->DestroyValue_InContainer(Params);
}
LastOut = &NewStack.OutParms;
for (int i = 0; i < Arguments.size(); ++i)
{
auto PropertyFlags = Arguments[i]->Property->PropertyFlags;
if (PropertyFlags & CPF_OutParm)
{
if ((PropertyFlags & CPF_Parm) && (!(PropertyFlags & CPF_ConstParm)) && (!(PropertyFlags & CPF_ReturnParm)))
{
if ((*LastOut)->PropAddr >= (uint8*) Params && (*LastOut)->PropAddr < ((uint8*) Params + ParamsBufferSize))
{
Arguments[i]->UEOutToJsInContainer(Isolate, Context, Info[i], Params, false);
}
else
{
LastOut = &(*LastOut)->NextOutParm;
continue;
}
}
LastOut = &(*LastOut)->NextOutParm;
}
if (Arguments[i]->ParamShallowCopySize == 0)
{
Arguments[i]->Property->DestroyValue_InContainer(Params);
}
}
}
void FFunctionTranslator::Call(v8::Isolate* Isolate, v8::Local<v8::Context>& Context,
const v8::FunctionCallbackInfo<v8::Value>& Info, std::function<void(void*)> OnCall)
{
#if defined(USE_GLOBAL_PARAMS_BUFFER)
void* Params = Buffer;
#else
void* Params = ParamsBufferSize > 0 ? FMemory_Alloca(ParamsBufferSize) : nullptr;
#endif
if (Params)
FMemory::Memzero(Params, ParamsBufferSize);
Call_ProcessParams(Isolate, Context, Info, Params, 0);
OnCall(Params);
Call_ProcessReturnAndOutParams(Isolate, Context, Info, Params, 0);
}
void FFunctionTranslator::CallJs(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, v8::Local<v8::Function> JsFunction,
v8::Local<v8::Value> This, void* Params)
{
v8::Local<v8::Value>* Args =
static_cast<v8::Local<v8::Value>*>(FMemory_Alloca(sizeof(v8::Local<v8::Value>) * Arguments.size()));
FMemory::Memset(Args, 0, sizeof(v8::Local<v8::Value>) * Arguments.size());
for (int i = 0; i < Arguments.size(); ++i)
{
Args[i] = Arguments[i]->UEToJsInContainer(Isolate, Context, Params, false);
}
v8::MaybeLocal<v8::Value> Result;
if (UNLIKELY(SkipWorldContextInArg0))
{
Result = JsFunction->Call(Context, This, Arguments.size() - 1, &Args[0] + 1);
}
else
{
Result = JsFunction->Call(Context, This, Arguments.size(), Args);
}
if (!Result.IsEmpty()) // empty mean exception
{
if (Return)
{
Return->JsToUEInContainer(Isolate, Context, Result.ToLocalChecked(), Params, true);
}
for (int i = 0; i < Arguments.size(); ++i)
{
Arguments[i]->JsToUEOutInContainer(Isolate, Context, Args[i], Params, true);
}
}
}
static FOutParmRec* GetMatchOutParmRec(FOutParmRec* OutParam, PropertyMacro* OutProperty)
{
FOutParmRec* Out = OutParam;
while (Out)
{
if (Out->Property == OutProperty)
{
return Out;
}
Out = Out->NextOutParm;
}
return nullptr;
}
void FFunctionTranslator::CallJs(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, v8::Local<v8::Function> JsFunction,
v8::Local<v8::Value> This, UObject* ContextObject, FFrame& Stack, void* RESULT_PARAM)
{
void* Params = Stack.Locals;
FOutParmRec* NewOutParms = nullptr;
const bool CallByBP = Stack.Node != Stack.CurrentNativeFunction;
if (CallByBP)
{
#if defined(USE_GLOBAL_PARAMS_BUFFER)
void* Params = Buffer;
#else
Params = ParamsBufferSize > 0 ? FMemory_Alloca(ParamsBufferSize) : nullptr;
#endif
if (Params)
{
FMemory::Memzero(Params, ParamsBufferSize);
FOutParmRec** LastOut = &NewOutParms;
// ScriptCore.cpp
for (PropertyMacro* Property = (PropertyMacro*) (
#if ENGINE_MINOR_VERSION >= 25 || ENGINE_MAJOR_VERSION > 4
Function->ChildProperties
#else
Function->Children
#endif
);
*Stack.Code != EX_EndFunctionParms; Property = (PropertyMacro*) (Property->Next))
{
checkfSlow(Property, TEXT("NULL Property in Function %s"), *Function->GetPathName());
Property->InitializeValue_InContainer(Params);
if ((Property->PropertyFlags & CPF_ReturnParm) != 0)
{
continue;
}
Stack.MostRecentPropertyAddress = nullptr;
if (Property->PropertyFlags & CPF_OutParm)
{
Stack.Step(Stack.Object, Property->ContainerPtrToValuePtr<uint8>(Params));
if (LastOut)
{
CA_SUPPRESS(6263)
FOutParmRec* Out = (FOutParmRec*) FMemory_Alloca(sizeof(FOutParmRec));
ensure(Stack.MostRecentPropertyAddress);
Out->PropAddr = (Stack.MostRecentPropertyAddress != NULL) ? Stack.MostRecentPropertyAddress
: Property->ContainerPtrToValuePtr<uint8>(Params);
Out->Property = Property;
if (*LastOut)
{
(*LastOut)->NextOutParm = Out;
LastOut = &(*LastOut)->NextOutParm;
}
else
{
*LastOut = Out;
}
}
}
else
{
Stack.Step(Stack.Object, Property->ContainerPtrToValuePtr<uint8>(Params));
}
}
}
if (Stack.Code)
{
check(Stack.PeekCode() == EX_EndFunctionParms);
Stack.SkipCode(1); // skip EX_EndFunctionParms
}
}
v8::Local<v8::Value>* Args =
static_cast<v8::Local<v8::Value>*>(FMemory_Alloca(sizeof(v8::Local<v8::Value>) * Arguments.size()));
FMemory::Memset(Args, 0, sizeof(v8::Local<v8::Value>) * Arguments.size());
for (int i = 0; i < Arguments.size(); ++i)
{
const auto Property = Arguments[i]->Property;
if (!CallByBP && (Property->PropertyFlags & CPF_OutParm) && Stack.OutParms) // may be fast call
{
FOutParmRec* Out = Stack.OutParms;
while (Out->Property != Property)
{
Out = Out->NextOutParm;
checkSlow(Out);
}
Args[i] = Arguments[i]->UEToJs(Isolate, Context, Out->PropAddr, false);
continue;
}
Args[i] = Arguments[i]->UEToJsInContainer(Isolate, Context, Params, false);
}
v8::MaybeLocal<v8::Value> Result;
if (UNLIKELY(SkipWorldContextInArg0))
{
Result = JsFunction->Call(Context, This, Arguments.size() - 1, &Args[0] + 1);
}
else
{
Result = JsFunction->Call(Context, This, Arguments.size(), Args);
}
if (!Result.IsEmpty()) // empty mean exception
{
if (Return)
{
Return->JsToUE(Isolate, Context, Result.ToLocalChecked(), RESULT_PARAM, true);
}
auto OutParms = NewOutParms ? NewOutParms : Stack.OutParms;
for (int i = 0; i < Arguments.size(); ++i)
{
if (Arguments[i]->IsOut())
{
auto OutParmRec = GetMatchOutParmRec(OutParms, Arguments[i]->Property);
if (OutParmRec)
{
Arguments[i]->JsToUEOut(Isolate, Context, Args[i], OutParmRec->PropAddr, true);
}
}
}
}
if (Params && Params != Stack.Locals)
{
// destruct properties on the stack, except for out params since we know we didn't use that memory
for (PropertyMacro* Destruct = Function->DestructorLink; Destruct; Destruct = Destruct->DestructorLinkNext)
{
if (!Destruct->HasAnyPropertyFlags(CPF_OutParm))
{
Destruct->DestroyValue_InContainer(Params);
}
}
}
}
bool FFunctionTranslator::IsValid() const
{
return Function.IsValid();
}
FExtensionMethodTranslator::FExtensionMethodTranslator(UFunction* InFunction) : FFunctionTranslator(InFunction, false)
{
TFieldIterator<PropertyMacro> It(InFunction);
PropertyMacro* Property = *It;
IsUObject = Property->IsA<ObjectPropertyBaseMacro>();
Arguments[0] = FPropertyTranslator::Create(Property, true);
}
v8::Local<v8::FunctionTemplate> FExtensionMethodTranslator::ToFunctionTemplate(v8::Isolate* Isolate)
{
return v8::FunctionTemplate::New(Isolate, CallExtension, v8::External::New(Isolate, this));
}
void FExtensionMethodTranslator::CallExtension(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
FExtensionMethodTranslator* This =
reinterpret_cast<FExtensionMethodTranslator*>((v8::Local<v8::External>::Cast(Info.Data()))->Value());
This->CallExtension(Isolate, Context, Info);
}
void FExtensionMethodTranslator::CallExtension(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const v8::FunctionCallbackInfo<v8::Value>& Info)
{
#if defined(USE_GLOBAL_PARAMS_BUFFER)
void* Params = Buffer;
#else
void* Params = ParamsBufferSize > 0 ? FMemory_Alloca(ParamsBufferSize) : nullptr;
#endif
if (Params)
Function->InitializeStruct(Params);
if (!Arguments[0]->JsToUEInContainer(Isolate, Context, Info.Holder(), Params, false))
{
if (Params)
{
for (int i = 0; i < Arguments.size(); ++i)
{
if (Arguments[i]->ParamShallowCopySize == 0)
{
Arguments[i]->Property->DestroyValue_InContainer(Params);
}
}
}
FV8Utils::ThrowException(Isolate, "access a invalid object");
return;
}
for (int i = 1; i < Arguments.size(); ++i)
{
if (UNLIKELY(ArgumentDefaultValues && Info[i - 1]->IsUndefined()))
{
Arguments[i]->Property->CopyCompleteValue_InContainer(Params, ArgumentDefaultValues);
}
else if (!Arguments[i]->JsToUEInContainer(Isolate, Context, Info[i - 1], Params, false))
{
return;
}
}
if (!BindObject.IsValid())
{
BindObject = Function->GetOuterUClass()->GetDefaultObject();
}
BindObject->UObject::ProcessEvent(Function.Get(), Params);
if (Return)
{
Info.GetReturnValue().Set(Return->UEToJsInContainer(Isolate, Context, Params));
Return->Property->DestroyValue_InContainer(Params);
}
for (int i = 1; i < Arguments.size(); ++i)
{
Arguments[i]->UEOutToJsInContainer(Isolate, Context, Info[i - 1], Params, false);
}
// Function->HasAnyFlags()
if (!IsUObject) // FScriptStruct, so copy back
{
auto StructProperty = Arguments[0]->StructProperty;
StructProperty->CopySingleValue(FV8Utils::GetPointer(Info.Holder()), StructProperty->ContainerPtrToValuePtr<void>(Params));
}
if (Params)
{
for (int i = 0; i < Arguments.size(); ++i)
{
if (Arguments[i]->ParamShallowCopySize == 0)
{
Arguments[i]->Property->DestroyValue_InContainer(Params);
}
}
}
}
}; // namespace PUERTS_NAMESPACE
@@ -0,0 +1,151 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include <memory>
#include <vector>
#include <functional>
#include "CoreMinimal.h"
#include "CoreUObject.h"
#include "PropertyTranslator.h"
#include "NamespaceDef.h"
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#pragma warning(push, 0)
#include "libplatform/libplatform.h"
#include "v8.h"
#pragma warning(pop)
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
namespace PUERTS_NAMESPACE
{
class FFunctionTranslator
{
public:
explicit FFunctionTranslator(UFunction* InFunction, bool IsDelegate);
virtual ~FFunctionTranslator()
{
if (ArgumentDefaultValues)
{
FMemory::Free(ArgumentDefaultValues);
}
}
virtual v8::Local<v8::FunctionTemplate> ToFunctionTemplate(v8::Isolate* Isolate);
void CallJs(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, v8::Local<v8::Function> JsFunction,
v8::Local<v8::Value> This, void* Params);
void CallJs(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, v8::Local<v8::Function> JsFunction,
v8::Local<v8::Value> This, UObject* ContextObject, FFrame& Stack, void* RESULT_PARAM);
void Call(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const v8::FunctionCallbackInfo<v8::Value>& Info,
std::function<void(void*)> OnCall);
bool IsValid() const;
protected:
FORCEINLINE bool Call_ProcessParams(v8::Isolate* Isolate, v8::Local<v8::Context>& Context,
const v8::FunctionCallbackInfo<v8::Value>& Info, void* Params, int StartPos)
{
if (Return)
{
Return->Property->InitializeValue_InContainer(Params);
}
for (int i = StartPos; i < Arguments.size(); ++i)
{
Arguments[i]->Property->InitializeValue_InContainer(Params);
if (UNLIKELY(ArgumentDefaultValues && Info[i - StartPos]->IsUndefined()))
{
Arguments[i]->Property->CopyCompleteValue_InContainer(Params, ArgumentDefaultValues);
}
else if (!Arguments[i]->JsToUEInContainer(Isolate, Context, Info[i - StartPos], Params, false))
{
return false;
}
}
return true;
}
FORCEINLINE void Call_ProcessReturnAndOutParams(v8::Isolate* Isolate, v8::Local<v8::Context>& Context,
const v8::FunctionCallbackInfo<v8::Value>& Info, void* Params, int StartPos)
{
if (Return)
{
Info.GetReturnValue().Set(Return->UEToJsInContainer(Isolate, Context, Params));
Return->Property->DestroyValue_InContainer(Params);
}
for (int i = StartPos; i < Arguments.size(); ++i)
{
Arguments[i]->UEOutToJsInContainer(Isolate, Context, Info[i - StartPos], Params, false);
if (Arguments[i]->ParamShallowCopySize == 0)
{
Arguments[i]->Property->DestroyValue_InContainer(Params);
}
}
}
std::vector<std::unique_ptr<FPropertyTranslator>> Arguments;
std::unique_ptr<FPropertyTranslator> Return;
TWeakObjectPtr<UFunction> Function;
bool IsInterfaceFunction;
TWeakObjectPtr<UObject> BindObject;
bool IsStatic;
bool SkipWorldContextInArg0;
uint32 ParamsBufferSize;
void* ArgumentDefaultValues;
#if WITH_EDITOR
FName FunctionName;
#endif
private:
static void Call(const v8::FunctionCallbackInfo<v8::Value>& Info);
void Call(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const v8::FunctionCallbackInfo<v8::Value>& Info);
void SlowCall(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const v8::FunctionCallbackInfo<v8::Value>& Info,
UObject* CallObject, UFunction* CallFunction, void* Params);
void FastCall(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const v8::FunctionCallbackInfo<v8::Value>& Info,
UObject* CallObject, UFunction* CallFunction, void* Params);
void Init(UFunction* InFunction, bool IsDelegate);
friend class FStructWrapper;
friend class FJsEnvImpl;
};
class FExtensionMethodTranslator : public FFunctionTranslator
{
public:
explicit FExtensionMethodTranslator(UFunction* InFunction);
v8::Local<v8::FunctionTemplate> ToFunctionTemplate(v8::Isolate* Isolate) override;
private:
static void CallExtension(const v8::FunctionCallbackInfo<v8::Value>& Info);
void CallExtension(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const v8::FunctionCallbackInfo<v8::Value>& Info);
bool IsUObject;
};
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,754 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
// gen by puerts gen tools
#include "GenHeaders.h"
#include "CoreMinimal.h"
#include "DataTransfer.h"
#include "JSClassRegister.h"
// <SourceLocation file 'D:\\Program Files\\Epic Games\\UE_4.24\\Engine\\Source\\Runtime\\Core\\Public\\Math/Box2D.h', line 111,
// column 22> unsupported method : operator+= FBox2D &(const FVector2D &) __attribute__((thiscall))
// <SourceLocation file 'D:\\Program Files\\Epic Games\\UE_4.24\\Engine\\Source\\Runtime\\Core\\Public\\Math/Box2D.h', line 130,
// column 22> unsupported method : operator+= FBox2D &(const FBox2D &) __attribute__((thiscall))
static void* _FBox2DNew_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
FBox2D* Obj = new FBox2D();
// UE_LOG(LogTemp, Warning, TEXT("_FBox2DNew_:%p"), Obj);
return Obj;
}
}
if (Info.Length() == 1)
{
if (Info[0]->IsNumber())
{
EForceInit Arg0 = EForceInit(Info[0]->ToInt32(Context).ToLocalChecked()->Value());
FBox2D* Obj = new FBox2D(Arg0);
// UE_LOG(LogTemp, Warning, TEXT("_FBox2DNew_:%p"), Obj);
return Obj;
}
}
if (Info.Length() == 2)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FVector2D>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()) &&
Info[1]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FVector2D>(Isolate, Info[1]->ToObject(Context).ToLocalChecked()))
{
const FVector2D* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FVector2D>(Info[0]->ToObject(Context).ToLocalChecked());
const FVector2D* Arg1 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FVector2D>(Info[1]->ToObject(Context).ToLocalChecked());
FBox2D* Obj = new FBox2D(*Arg0, *Arg1);
// UE_LOG(LogTemp, Warning, TEXT("_FBox2DNew_:%p"), Obj);
return Obj;
}
}
if (Info.Length() == 2)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FVector2D>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()) &&
Info[1]->IsNumber())
{
const FVector2D* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FVector2D>(Info[0]->ToObject(Context).ToLocalChecked());
const int32 Arg1 = Info[1]->ToInteger(Context).ToLocalChecked()->Value();
FBox2D* Obj = new FBox2D(Arg0, Arg1);
// UE_LOG(LogTemp, Warning, TEXT("_FBox2DNew_:%p"), Obj);
return Obj;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
return nullptr;
}
static void _FBox2DDelete_(void* Ptr, void* ClassData, void* EnvData)
{
FBox2D* Self = static_cast<FBox2D*>(Ptr);
// UE_LOG(LogTemp, Warning, TEXT("_FBox2DDelete_:%p"), Self);
delete Self;
}
static void FBox2DM_op_Equality(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FBox2D>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()))
{
const FBox2D* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info[0]->ToObject(Context).ToLocalChecked());
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FBox2D::M_op_Equality] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->operator==(*Arg0);
auto V8Result = v8::Boolean::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FBox2DM_op_Inequality(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FBox2D>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()))
{
const FBox2D* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info[0]->ToObject(Context).ToLocalChecked());
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FBox2D::M_op_Inequality] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->operator!=(*Arg0);
auto V8Result = v8::Boolean::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FBox2DM_op_Addition(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FVector2D>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()))
{
const FVector2D* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FVector2D>(Info[0]->ToObject(Context).ToLocalChecked());
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FBox2D::M_op_Addition] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->operator+(*Arg0);
void* Ptr = new FBox2D(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FBox2D>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
if (Info.Length() == 1)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FBox2D>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()))
{
const FBox2D* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info[0]->ToObject(Context).ToLocalChecked());
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FBox2D::M_op_Addition] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->operator+(*Arg0);
void* Ptr = new FBox2D(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FBox2D>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FBox2DM_set_Item(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsNumber())
{
int32 Arg0 = Info[0]->ToInteger(Context).ToLocalChecked()->Value();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FBox2D::M_set_Item] Attempt to access a NULL self pointer");
return;
}
Self->operator[](Arg0);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FBox2DM_ComputeSquaredDistanceToPoint(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FVector2D>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()))
{
const FVector2D* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FVector2D>(Info[0]->ToObject(Context).ToLocalChecked());
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FBox2D::M_ComputeSquaredDistanceToPoint] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->ComputeSquaredDistanceToPoint(*Arg0);
auto V8Result = v8::Number::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FBox2DM_ExpandBy(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsNumber())
{
const float Arg0 = Info[0]->ToNumber(Context).ToLocalChecked()->Value();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FBox2D::M_ExpandBy] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->ExpandBy(Arg0);
void* Ptr = new FBox2D(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FBox2D>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FBox2DM_GetArea(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FBox2D::M_GetArea] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->GetArea();
auto V8Result = v8::Number::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FBox2DM_GetCenter(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FBox2D::M_GetCenter] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->GetCenter();
void* Ptr = new FVector2D(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FVector2D>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FBox2DM_GetCenterAndExtents(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 2)
{
if (Info[0]->IsObject() && PUERTS_NAMESPACE::DataTransfer::UnRef(Isolate, Info[0])->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FVector2D>(
Isolate, PUERTS_NAMESPACE::DataTransfer::UnRef(Isolate, Info[0])->ToObject(Context).ToLocalChecked()) &&
Info[1]->IsObject() && PUERTS_NAMESPACE::DataTransfer::UnRef(Isolate, Info[1])->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FVector2D>(
Isolate, PUERTS_NAMESPACE::DataTransfer::UnRef(Isolate, Info[1])->ToObject(Context).ToLocalChecked()))
{
FVector2D* Arg0 = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FVector2D>(
PUERTS_NAMESPACE::DataTransfer::UnRef(Isolate, Info[0])->ToObject(Context).ToLocalChecked());
FVector2D* Arg1 = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FVector2D>(
PUERTS_NAMESPACE::DataTransfer::UnRef(Isolate, Info[1])->ToObject(Context).ToLocalChecked());
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FBox2D::M_GetCenterAndExtents] Attempt to access a NULL self pointer");
return;
}
Self->GetCenterAndExtents(*Arg0, *Arg1);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FBox2DM_GetClosestPointTo(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FVector2D>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()))
{
const FVector2D* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FVector2D>(Info[0]->ToObject(Context).ToLocalChecked());
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FBox2D::M_GetClosestPointTo] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->GetClosestPointTo(*Arg0);
void* Ptr = new FVector2D(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FVector2D>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FBox2DM_GetExtent(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FBox2D::M_GetExtent] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->GetExtent();
void* Ptr = new FVector2D(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FVector2D>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FBox2DM_GetSize(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FBox2D::M_GetSize] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->GetSize();
void* Ptr = new FVector2D(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FVector2D>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FBox2DM_Init(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FBox2D::M_Init] Attempt to access a NULL self pointer");
return;
}
Self->Init();
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FBox2DM_Intersect(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FBox2D>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()))
{
const FBox2D* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info[0]->ToObject(Context).ToLocalChecked());
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FBox2D::M_Intersect] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->Intersect(*Arg0);
auto V8Result = v8::Boolean::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FBox2DM_IsInside(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FVector2D>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()))
{
const FVector2D* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FVector2D>(Info[0]->ToObject(Context).ToLocalChecked());
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FBox2D::M_IsInside] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->IsInside(*Arg0);
auto V8Result = v8::Boolean::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
if (Info.Length() == 1)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FBox2D>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()))
{
const FBox2D* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info[0]->ToObject(Context).ToLocalChecked());
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FBox2D::M_IsInside] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->IsInside(*Arg0);
auto V8Result = v8::Boolean::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FBox2DM_ShiftBy(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FVector2D>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()))
{
const FVector2D* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FVector2D>(Info[0]->ToObject(Context).ToLocalChecked());
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FBox2D::M_ShiftBy] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->ShiftBy(*Arg0);
void* Ptr = new FBox2D(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FBox2D>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FBox2DM_ToString(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FBox2D::M_ToString] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->ToString();
auto V8Result =
v8::String::NewFromUtf8(Isolate, TCHAR_TO_UTF8(*MethodResult), v8::NewStringType::kNormal).ToLocalChecked();
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void _FBox2DMinGet_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FBox2D::Min] Attempt to access a NULL self pointer");
return;
}
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FVector2D>(Isolate, Context, &(Self->Min), true);
PUERTS_NAMESPACE::DataTransfer::LinkOuter<FBox2D, FVector2D>(Context, Info.Holder(), V8Result);
Info.GetReturnValue().Set(V8Result);
}
static void _FBox2DMinSet_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FBox2D::Min] Attempt to access a NULL self pointer");
return;
}
auto Value = Info[0];
Self->Min = *PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FVector2D>(Value->ToObject(Context).ToLocalChecked());
}
static void _FBox2DMaxGet_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FBox2D::Max] Attempt to access a NULL self pointer");
return;
}
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FVector2D>(Isolate, Context, &(Self->Max), true);
PUERTS_NAMESPACE::DataTransfer::LinkOuter<FBox2D, FVector2D>(Context, Info.Holder(), V8Result);
Info.GetReturnValue().Set(V8Result);
}
static void _FBox2DMaxSet_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FBox2D::Max] Attempt to access a NULL self pointer");
return;
}
auto Value = Info[0];
Self->Max = *PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FVector2D>(Value->ToObject(Context).ToLocalChecked());
}
static void _FBox2DbIsValidGet_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FBox2D::bIsValid] Attempt to access a NULL self pointer");
return;
}
auto V8Result = v8::Boolean::New(Isolate, Self->bIsValid);
PUERTS_NAMESPACE::DataTransfer::LinkOuter<FBox2D, bool>(Context, Info.Holder(), V8Result);
Info.GetReturnValue().Set(V8Result);
}
static void _FBox2DbIsValidSet_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FBox2D>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FBox2D::bIsValid] Attempt to access a NULL self pointer");
return;
}
auto Value = Info[0];
Self->bIsValid = Value->ToBoolean(Isolate)->Value();
}
struct AutoRegisterForFBox2D
{
AutoRegisterForFBox2D()
{
PUERTS_NAMESPACE::JSClassDefinition Def = JSClassEmptyDefinition;
static PUERTS_NAMESPACE::JSPropertyInfo Properties[] = {{"Min", _FBox2DMinGet_, _FBox2DMinSet_},
{"Max", _FBox2DMaxGet_, _FBox2DMaxSet_}, {"bIsValid", _FBox2DbIsValidGet_, _FBox2DbIsValidSet_}, {0, 0, 0}};
static PUERTS_NAMESPACE::JSFunctionInfo Methods[] = {{"op_Equality", FBox2DM_op_Equality},
{"op_Inequality", FBox2DM_op_Inequality}, {"op_Addition", FBox2DM_op_Addition}, {"set_Item", FBox2DM_set_Item},
{"ComputeSquaredDistanceToPoint", FBox2DM_ComputeSquaredDistanceToPoint}, {"ExpandBy", FBox2DM_ExpandBy},
{"GetArea", FBox2DM_GetArea}, {"GetCenter", FBox2DM_GetCenter}, {"GetCenterAndExtents", FBox2DM_GetCenterAndExtents},
{"GetClosestPointTo", FBox2DM_GetClosestPointTo}, {"GetExtent", FBox2DM_GetExtent}, {"GetSize", FBox2DM_GetSize},
{"Init", FBox2DM_Init}, {"Intersect", FBox2DM_Intersect}, {"IsInside", FBox2DM_IsInside}, {"ShiftBy", FBox2DM_ShiftBy},
{"ToString", FBox2DM_ToString}, {0, 0}};
static PUERTS_NAMESPACE::JSFunctionInfo Functions[] = {{0, 0}};
Def.UETypeName = "Box2D";
Def.SetInitialize(_FBox2DNew_);
Def.Finalize = _FBox2DDelete_;
Def.Properties = Properties;
Def.Methods = Methods;
Def.Functions = Functions;
PUERTS_NAMESPACE::RegisterJSClass(Def);
}
};
AutoRegisterForFBox2D _AutoRegisterForFBox2D_;
@@ -0,0 +1,560 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
// gen by puerts gen tools
#include "GenHeaders.h"
#include "CoreMinimal.h"
#include "DataTransfer.h"
#include "JSClassRegister.h"
// <SourceLocation file 'D:\\Program Files\\Epic Games\\UE_4.24\\Engine\\Source\\Runtime\\Core\\Public\\Math/Color.h', line 483,
// column 19> unsupported method : operator+= void (const FColor &) __attribute__((thiscall))
static void* _FColorNew_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
FColor* Obj = new FColor();
// UE_LOG(LogTemp, Warning, TEXT("_FColorNew_:%p"), Obj);
return Obj;
}
}
if (Info.Length() == 1)
{
if (Info[0]->IsNumber())
{
EForceInit Arg0 = EForceInit(Info[0]->ToInt32(Context).ToLocalChecked()->Value());
FColor* Obj = new FColor(Arg0);
// UE_LOG(LogTemp, Warning, TEXT("_FColorNew_:%p"), Obj);
return Obj;
}
}
if (Info.Length() == 4)
{
if (Info[0]->IsNumber() && Info[1]->IsNumber() && Info[2]->IsNumber() && Info[3]->IsNumber())
{
uint8 Arg0 = Info[0]->ToInteger(Context).ToLocalChecked()->Value();
uint8 Arg1 = Info[1]->ToInteger(Context).ToLocalChecked()->Value();
uint8 Arg2 = Info[2]->ToInteger(Context).ToLocalChecked()->Value();
uint8 Arg3 = Info[3]->ToInteger(Context).ToLocalChecked()->Value();
FColor* Obj = new FColor(Arg0, Arg1, Arg2, Arg3);
// UE_LOG(LogTemp, Warning, TEXT("_FColorNew_:%p"), Obj);
return Obj;
}
}
if (Info.Length() == 1)
{
if (Info[0]->IsNumber())
{
uint32 Arg0 = Info[0]->ToInteger(Context).ToLocalChecked()->Value();
FColor* Obj = new FColor(Arg0);
// UE_LOG(LogTemp, Warning, TEXT("_FColorNew_:%p"), Obj);
return Obj;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
return nullptr;
}
static void _FColorDelete_(void* Ptr, void* ClassData, void* EnvData)
{
FColor* Self = static_cast<FColor*>(Ptr);
// UE_LOG(LogTemp, Warning, TEXT("_FColorDelete_:%p"), Self);
delete Self;
}
static void FColorM_DWColor(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FColor>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FColor::M_DWColor] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->DWColor();
auto V8Result = v8::Integer::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FColor>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FColor::M_DWColor] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->DWColor();
auto V8Result = v8::Integer::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FColorM_op_Equality(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FColor>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()))
{
const FColor* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FColor>(Info[0]->ToObject(Context).ToLocalChecked());
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FColor>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FColor::M_op_Equality] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->operator==(*Arg0);
auto V8Result = v8::Boolean::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FColorM_op_Inequality(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FColor>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()))
{
const FColor* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FColor>(Info[0]->ToObject(Context).ToLocalChecked());
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FColor>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FColor::M_op_Inequality] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->operator!=(*Arg0);
auto V8Result = v8::Boolean::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FColorM_FromRGBE(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FColor>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FColor::M_FromRGBE] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->FromRGBE();
void* Ptr = new FLinearColor(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FLinearColor>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FColorS_FromHex(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsString())
{
const FString Arg0 = UTF8_TO_TCHAR(*(v8::String::Utf8Value(Isolate, Info[0])));
auto MethodResult = FColor::FromHex(Arg0);
void* Ptr = new FColor(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FColor>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FColorS_MakeRandomColor(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto MethodResult = FColor::MakeRandomColor();
void* Ptr = new FColor(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FColor>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FColorS_MakeRedToGreenColorFromScalar(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsNumber())
{
float Arg0 = Info[0]->ToNumber(Context).ToLocalChecked()->Value();
auto MethodResult = FColor::MakeRedToGreenColorFromScalar(Arg0);
void* Ptr = new FColor(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FColor>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FColorS_MakeFromColorTemperature(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsNumber())
{
float Arg0 = Info[0]->ToNumber(Context).ToLocalChecked()->Value();
auto MethodResult = FColor::MakeFromColorTemperature(Arg0);
void* Ptr = new FColor(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FColor>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FColorM_WithAlpha(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsNumber())
{
uint8 Arg0 = Info[0]->ToInteger(Context).ToLocalChecked()->Value();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FColor>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FColor::M_WithAlpha] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->WithAlpha(Arg0);
void* Ptr = new FColor(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FColor>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FColorM_ReinterpretAsLinear(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FColor>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FColor::M_ReinterpretAsLinear] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->ReinterpretAsLinear();
void* Ptr = new FLinearColor(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FLinearColor>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FColorM_ToHex(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FColor>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FColor::M_ToHex] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->ToHex();
auto V8Result =
v8::String::NewFromUtf8(Isolate, TCHAR_TO_UTF8(*MethodResult), v8::NewStringType::kNormal).ToLocalChecked();
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FColorM_ToString(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FColor>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FColor::M_ToString] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->ToString();
auto V8Result =
v8::String::NewFromUtf8(Isolate, TCHAR_TO_UTF8(*MethodResult), v8::NewStringType::kNormal).ToLocalChecked();
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FColorM_InitFromString(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsString())
{
const FString Arg0 = UTF8_TO_TCHAR(*(v8::String::Utf8Value(Isolate, Info[0])));
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FColor>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FColor::M_InitFromString] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->InitFromString(Arg0);
auto V8Result = v8::Boolean::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FColorM_ToPackedARGB(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FColor>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FColor::M_ToPackedARGB] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->ToPackedARGB();
auto V8Result = v8::Integer::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FColorM_ToPackedABGR(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FColor>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FColor::M_ToPackedABGR] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->ToPackedABGR();
auto V8Result = v8::Integer::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FColorM_ToPackedRGBA(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FColor>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FColor::M_ToPackedRGBA] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->ToPackedRGBA();
auto V8Result = v8::Integer::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FColorM_ToPackedBGRA(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FColor>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FColor::M_ToPackedBGRA] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->ToPackedBGRA();
auto V8Result = v8::Integer::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
struct AutoRegisterForFColor
{
AutoRegisterForFColor()
{
PUERTS_NAMESPACE::JSClassDefinition Def = JSClassEmptyDefinition;
static PUERTS_NAMESPACE::JSPropertyInfo Properties[] = {{0, 0, 0}};
static PUERTS_NAMESPACE::JSFunctionInfo Methods[] = {{"DWColor", FColorM_DWColor}, {"op_Equality", FColorM_op_Equality},
{"op_Inequality", FColorM_op_Inequality}, {"FromRGBE", FColorM_FromRGBE}, {"WithAlpha", FColorM_WithAlpha},
{"ReinterpretAsLinear", FColorM_ReinterpretAsLinear}, {"ToHex", FColorM_ToHex}, {"ToString", FColorM_ToString},
{"InitFromString", FColorM_InitFromString}, {"ToPackedARGB", FColorM_ToPackedARGB},
{"ToPackedABGR", FColorM_ToPackedABGR}, {"ToPackedRGBA", FColorM_ToPackedRGBA}, {"ToPackedBGRA", FColorM_ToPackedBGRA},
{0, 0}};
static PUERTS_NAMESPACE::JSFunctionInfo Functions[] = {{"FromHex", FColorS_FromHex},
{"MakeRandomColor", FColorS_MakeRandomColor}, {"MakeRedToGreenColorFromScalar", FColorS_MakeRedToGreenColorFromScalar},
{"MakeFromColorTemperature", FColorS_MakeFromColorTemperature}, {0, 0}};
Def.UETypeName = "Color";
Def.SetInitialize(_FColorNew_);
Def.Finalize = _FColorDelete_;
Def.Properties = Properties;
Def.Methods = Methods;
Def.Functions = Functions;
PUERTS_NAMESPACE::RegisterJSClass(Def);
}
};
AutoRegisterForFColor _AutoRegisterForFColor_;
@@ -0,0 +1,424 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
// gen by puerts gen tools
#include "GenHeaders.h"
#include "CoreMinimal.h"
#include "DataTransfer.h"
#include "JSClassRegister.h"
static void* _FGuidNew_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
FGuid* Obj = new FGuid();
// UE_LOG(LogTemp, Warning, TEXT("_FGuidNew_:%p"), Obj);
return Obj;
}
}
if (Info.Length() == 4)
{
if (Info[0]->IsNumber() && Info[1]->IsNumber() && Info[2]->IsNumber() && Info[3]->IsNumber())
{
uint32 Arg0 = Info[0]->ToInteger(Context).ToLocalChecked()->Value();
uint32 Arg1 = Info[1]->ToInteger(Context).ToLocalChecked()->Value();
uint32 Arg2 = Info[2]->ToInteger(Context).ToLocalChecked()->Value();
uint32 Arg3 = Info[3]->ToInteger(Context).ToLocalChecked()->Value();
FGuid* Obj = new FGuid(Arg0, Arg1, Arg2, Arg3);
// UE_LOG(LogTemp, Warning, TEXT("_FGuidNew_:%p"), Obj);
return Obj;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
return nullptr;
}
static void _FGuidDelete_(void* Ptr, void* ClassData, void* EnvData)
{
FGuid* Self = static_cast<FGuid*>(Ptr);
// UE_LOG(LogTemp, Warning, TEXT("_FGuidDelete_:%p"), Self);
delete Self;
}
static void FGuidM_set_Item(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsNumber())
{
int32 Arg0 = Info[0]->ToInteger(Context).ToLocalChecked()->Value();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FGuid>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FGuid::M_set_Item] Attempt to access a NULL self pointer");
return;
}
Self->operator[](Arg0);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FGuidM_get_Item(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsNumber())
{
int32 Arg0 = Info[0]->ToInteger(Context).ToLocalChecked()->Value();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FGuid>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FGuid::M_get_Item] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->operator[](Arg0);
auto V8Result = v8::Integer::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FGuidM_Invalidate(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FGuid>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FGuid::M_Invalidate] Attempt to access a NULL self pointer");
return;
}
Self->Invalidate();
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FGuidM_IsValid(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FGuid>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FGuid::M_IsValid] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->IsValid();
auto V8Result = v8::Boolean::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FGuidM_ToString(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FGuid>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FGuid::M_ToString] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->ToString();
auto V8Result =
v8::String::NewFromUtf8(Isolate, TCHAR_TO_UTF8(*MethodResult), v8::NewStringType::kNormal).ToLocalChecked();
Info.GetReturnValue().Set(V8Result);
return;
}
}
if (Info.Length() == 1)
{
if (Info[0]->IsNumber())
{
EGuidFormats Arg0 = EGuidFormats(Info[0]->ToInt32(Context).ToLocalChecked()->Value());
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FGuid>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FGuid::M_ToString] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->ToString(Arg0);
auto V8Result =
v8::String::NewFromUtf8(Isolate, TCHAR_TO_UTF8(*MethodResult), v8::NewStringType::kNormal).ToLocalChecked();
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FGuidS_NewGuid(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto MethodResult = FGuid::NewGuid();
void* Ptr = new FGuid(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FGuid>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FGuidS_Parse(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 2)
{
if (Info[0]->IsString() && Info[1]->IsObject() && PUERTS_NAMESPACE::DataTransfer::UnRef(Isolate, Info[1])->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FGuid>(
Isolate, PUERTS_NAMESPACE::DataTransfer::UnRef(Isolate, Info[1])->ToObject(Context).ToLocalChecked()))
{
const FString Arg0 = UTF8_TO_TCHAR(*(v8::String::Utf8Value(Isolate, Info[0])));
FGuid* Arg1 = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FGuid>(
PUERTS_NAMESPACE::DataTransfer::UnRef(Isolate, Info[1])->ToObject(Context).ToLocalChecked());
auto MethodResult = FGuid::Parse(Arg0, *Arg1);
auto V8Result = v8::Boolean::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FGuidS_ParseExact(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 3)
{
if (Info[0]->IsString() && Info[1]->IsNumber() && Info[2]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::UnRef(Isolate, Info[2])->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FGuid>(
Isolate, PUERTS_NAMESPACE::DataTransfer::UnRef(Isolate, Info[2])->ToObject(Context).ToLocalChecked()))
{
const FString Arg0 = UTF8_TO_TCHAR(*(v8::String::Utf8Value(Isolate, Info[0])));
EGuidFormats Arg1 = EGuidFormats(Info[1]->ToInt32(Context).ToLocalChecked()->Value());
FGuid* Arg2 = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FGuid>(
PUERTS_NAMESPACE::DataTransfer::UnRef(Isolate, Info[2])->ToObject(Context).ToLocalChecked());
auto MethodResult = FGuid::ParseExact(Arg0, Arg1, *Arg2);
auto V8Result = v8::Boolean::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void _FGuidAGet_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FGuid>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FGuid::A] Attempt to access a NULL self pointer");
return;
}
auto V8Result = v8::Integer::New(Isolate, Self->A);
PUERTS_NAMESPACE::DataTransfer::LinkOuter<FGuid, uint32>(Context, Info.Holder(), V8Result);
Info.GetReturnValue().Set(V8Result);
}
static void _FGuidASet_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FGuid>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FGuid::A] Attempt to access a NULL self pointer");
return;
}
auto Value = Info[0];
Self->A = Value->ToInteger(Context).ToLocalChecked()->Value();
}
static void _FGuidBGet_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FGuid>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FGuid::B] Attempt to access a NULL self pointer");
return;
}
auto V8Result = v8::Integer::New(Isolate, Self->B);
PUERTS_NAMESPACE::DataTransfer::LinkOuter<FGuid, uint32>(Context, Info.Holder(), V8Result);
Info.GetReturnValue().Set(V8Result);
}
static void _FGuidBSet_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FGuid>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FGuid::B] Attempt to access a NULL self pointer");
return;
}
auto Value = Info[0];
Self->B = Value->ToInteger(Context).ToLocalChecked()->Value();
}
static void _FGuidCGet_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FGuid>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FGuid::C] Attempt to access a NULL self pointer");
return;
}
auto V8Result = v8::Integer::New(Isolate, Self->C);
PUERTS_NAMESPACE::DataTransfer::LinkOuter<FGuid, uint32>(Context, Info.Holder(), V8Result);
Info.GetReturnValue().Set(V8Result);
}
static void _FGuidCSet_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FGuid>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FGuid::C] Attempt to access a NULL self pointer");
return;
}
auto Value = Info[0];
Self->C = Value->ToInteger(Context).ToLocalChecked()->Value();
}
static void _FGuidDGet_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FGuid>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FGuid::D] Attempt to access a NULL self pointer");
return;
}
auto V8Result = v8::Integer::New(Isolate, Self->D);
PUERTS_NAMESPACE::DataTransfer::LinkOuter<FGuid, uint32>(Context, Info.Holder(), V8Result);
Info.GetReturnValue().Set(V8Result);
}
static void _FGuidDSet_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FGuid>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FGuid::D] Attempt to access a NULL self pointer");
return;
}
auto Value = Info[0];
Self->D = Value->ToInteger(Context).ToLocalChecked()->Value();
}
struct AutoRegisterForFGuid
{
AutoRegisterForFGuid()
{
PUERTS_NAMESPACE::JSClassDefinition Def = JSClassEmptyDefinition;
static PUERTS_NAMESPACE::JSPropertyInfo Properties[] = {{"A", _FGuidAGet_, _FGuidASet_}, {"B", _FGuidBGet_, _FGuidBSet_},
{"C", _FGuidCGet_, _FGuidCSet_}, {"D", _FGuidDGet_, _FGuidDSet_}, {0, 0, 0}};
static PUERTS_NAMESPACE::JSFunctionInfo Methods[] = {{"set_Item", FGuidM_set_Item}, {"get_Item", FGuidM_get_Item},
{"Invalidate", FGuidM_Invalidate}, {"IsValid", FGuidM_IsValid}, {"ToString", FGuidM_ToString}, {0, 0}};
static PUERTS_NAMESPACE::JSFunctionInfo Functions[] = {
{"NewGuid", FGuidS_NewGuid}, {"Parse", FGuidS_Parse}, {"ParseExact", FGuidS_ParseExact}, {0, 0}};
Def.UETypeName = "Guid";
Def.SetInitialize(_FGuidNew_);
Def.Finalize = _FGuidDelete_;
Def.Properties = Properties;
Def.Methods = Methods;
Def.Functions = Functions;
PUERTS_NAMESPACE::RegisterJSClass(Def);
}
};
AutoRegisterForFGuid _AutoRegisterForFGuid_;
@@ -0,0 +1,724 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
// gen by puerts gen tools
#include "GenHeaders.h"
#include "CoreMinimal.h"
#include "DataTransfer.h"
#include "JSClassRegister.h"
// <SourceLocation file 'D:\\Program Files\\Epic Games\\UE_4.24\\Engine\\Source\\Runtime\\Core\\Public\\Math/IntPoint.h', line 60,
// column 15> unsupported method : operator() const int32 &(int32) __attribute__((thiscall)) const
// <SourceLocation file 'D:\\Program Files\\Epic Games\\UE_4.24\\Engine\\Source\\Runtime\\Core\\Public\\Math/IntPoint.h', line 68,
// column 9> unsupported method : operator() int32 &(int32) __attribute__((thiscall))
// <SourceLocation file 'D:\\Program Files\\Epic Games\\UE_4.24\\Engine\\Source\\Runtime\\Core\\Public\\Math/IntPoint.h', line 92,
// column 13> unsupported method : operator*= FIntPoint &(int32) __attribute__((thiscall))
// <SourceLocation file 'D:\\Program Files\\Epic Games\\UE_4.24\\Engine\\Source\\Runtime\\Core\\Public\\Math/IntPoint.h', line 100,
// column 13> unsupported method : operator/= FIntPoint &(int32) __attribute__((thiscall))
// <SourceLocation file 'D:\\Program Files\\Epic Games\\UE_4.24\\Engine\\Source\\Runtime\\Core\\Public\\Math/IntPoint.h', line 108,
// column 13> unsupported method : operator+= FIntPoint &(const FIntPoint &) __attribute__((thiscall))
// <SourceLocation file 'D:\\Program Files\\Epic Games\\UE_4.24\\Engine\\Source\\Runtime\\Core\\Public\\Math/IntPoint.h', line 116,
// column 13> unsupported method : operator-= FIntPoint &(const FIntPoint &) __attribute__((thiscall))
// <SourceLocation file 'D:\\Program Files\\Epic Games\\UE_4.24\\Engine\\Source\\Runtime\\Core\\Public\\Math/IntPoint.h', line 124,
// column 13> unsupported method : operator/= FIntPoint &(const FIntPoint &) __attribute__((thiscall))
// <SourceLocation file 'D:\\Program Files\\Epic Games\\UE_4.24\\Engine\\Source\\Runtime\\Core\\Public\\Math/IntPoint.h', line 132,
// column 13> unsupported method : operator= FIntPoint &(const FIntPoint &) __attribute__((thiscall))
static void* _FIntPointNew_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
FIntPoint* Obj = new FIntPoint();
// UE_LOG(LogTemp, Warning, TEXT("_FIntPointNew_:%p"), Obj);
return Obj;
}
}
if (Info.Length() == 2)
{
if (Info[0]->IsNumber() && Info[1]->IsNumber())
{
int32 Arg0 = Info[0]->ToInteger(Context).ToLocalChecked()->Value();
int32 Arg1 = Info[1]->ToInteger(Context).ToLocalChecked()->Value();
FIntPoint* Obj = new FIntPoint(Arg0, Arg1);
// UE_LOG(LogTemp, Warning, TEXT("_FIntPointNew_:%p"), Obj);
return Obj;
}
}
if (Info.Length() == 1)
{
if (Info[0]->IsNumber())
{
EForceInit Arg0 = EForceInit(Info[0]->ToInt32(Context).ToLocalChecked()->Value());
FIntPoint* Obj = new FIntPoint(Arg0);
// UE_LOG(LogTemp, Warning, TEXT("_FIntPointNew_:%p"), Obj);
return Obj;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
return nullptr;
}
static void _FIntPointDelete_(void* Ptr, void* ClassData, void* EnvData)
{
FIntPoint* Self = static_cast<FIntPoint*>(Ptr);
// UE_LOG(LogTemp, Warning, TEXT("_FIntPointDelete_:%p"), Self);
delete Self;
}
static void FIntPointM_op_Equality(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FIntPoint>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()))
{
const FIntPoint* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info[0]->ToObject(Context).ToLocalChecked());
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntPoint::M_op_Equality] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->operator==(*Arg0);
auto V8Result = v8::Boolean::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntPointM_op_Inequality(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FIntPoint>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()))
{
const FIntPoint* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info[0]->ToObject(Context).ToLocalChecked());
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntPoint::M_op_Inequality] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->operator!=(*Arg0);
auto V8Result = v8::Boolean::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntPointM_op_Multiply(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsNumber())
{
int32 Arg0 = Info[0]->ToInteger(Context).ToLocalChecked()->Value();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntPoint::M_op_Multiply] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->operator*(Arg0);
void* Ptr = new FIntPoint(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FIntPoint>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntPointM_op_Division(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsNumber())
{
int32 Arg0 = Info[0]->ToInteger(Context).ToLocalChecked()->Value();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntPoint::M_op_Division] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->operator/(Arg0);
void* Ptr = new FIntPoint(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FIntPoint>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
if (Info.Length() == 1)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FIntPoint>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()))
{
const FIntPoint* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info[0]->ToObject(Context).ToLocalChecked());
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntPoint::M_op_Division] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->operator/(*Arg0);
void* Ptr = new FIntPoint(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FIntPoint>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntPointM_op_Addition(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FIntPoint>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()))
{
const FIntPoint* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info[0]->ToObject(Context).ToLocalChecked());
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntPoint::M_op_Addition] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->operator+(*Arg0);
void* Ptr = new FIntPoint(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FIntPoint>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntPointM_op_Subtraction(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FIntPoint>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()))
{
const FIntPoint* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info[0]->ToObject(Context).ToLocalChecked());
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntPoint::M_op_Subtraction] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->operator-(*Arg0);
void* Ptr = new FIntPoint(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FIntPoint>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntPointM_set_Item(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsNumber())
{
int32 Arg0 = Info[0]->ToInteger(Context).ToLocalChecked()->Value();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntPoint::M_set_Item] Attempt to access a NULL self pointer");
return;
}
Self->operator[](Arg0);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntPointM_get_Item(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsNumber())
{
int32 Arg0 = Info[0]->ToInteger(Context).ToLocalChecked()->Value();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntPoint::M_get_Item] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->operator[](Arg0);
auto V8Result = v8::Integer::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntPointM_ComponentMin(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FIntPoint>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()))
{
const FIntPoint* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info[0]->ToObject(Context).ToLocalChecked());
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntPoint::M_ComponentMin] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->ComponentMin(*Arg0);
void* Ptr = new FIntPoint(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FIntPoint>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntPointM_ComponentMax(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FIntPoint>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()))
{
const FIntPoint* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info[0]->ToObject(Context).ToLocalChecked());
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntPoint::M_ComponentMax] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->ComponentMax(*Arg0);
void* Ptr = new FIntPoint(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FIntPoint>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntPointM_GetMax(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntPoint::M_GetMax] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->GetMax();
auto V8Result = v8::Integer::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntPointM_GetMin(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntPoint::M_GetMin] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->GetMin();
auto V8Result = v8::Integer::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntPointM_Size(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntPoint::M_Size] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->Size();
auto V8Result = v8::Integer::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntPointM_SizeSquared(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntPoint::M_SizeSquared] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->SizeSquared();
auto V8Result = v8::Integer::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntPointM_ToString(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntPoint::M_ToString] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->ToString();
auto V8Result =
v8::String::NewFromUtf8(Isolate, TCHAR_TO_UTF8(*MethodResult), v8::NewStringType::kNormal).ToLocalChecked();
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntPointS_DivideAndRoundUp(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 2)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FIntPoint>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()) &&
Info[1]->IsNumber())
{
FIntPoint* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info[0]->ToObject(Context).ToLocalChecked());
int32 Arg1 = Info[1]->ToInteger(Context).ToLocalChecked()->Value();
auto MethodResult = FIntPoint::DivideAndRoundUp(*Arg0, Arg1);
void* Ptr = new FIntPoint(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FIntPoint>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
if (Info.Length() == 2)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FIntPoint>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()) &&
Info[1]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FIntPoint>(Isolate, Info[1]->ToObject(Context).ToLocalChecked()))
{
FIntPoint* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info[0]->ToObject(Context).ToLocalChecked());
FIntPoint* Arg1 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info[1]->ToObject(Context).ToLocalChecked());
auto MethodResult = FIntPoint::DivideAndRoundUp(*Arg0, *Arg1);
void* Ptr = new FIntPoint(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FIntPoint>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntPointS_DivideAndRoundDown(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 2)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FIntPoint>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()) &&
Info[1]->IsNumber())
{
FIntPoint* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info[0]->ToObject(Context).ToLocalChecked());
int32 Arg1 = Info[1]->ToInteger(Context).ToLocalChecked()->Value();
auto MethodResult = FIntPoint::DivideAndRoundDown(*Arg0, Arg1);
void* Ptr = new FIntPoint(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FIntPoint>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntPointS_Num(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto MethodResult = FIntPoint::Num();
auto V8Result = v8::Integer::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void _FIntPointXGet_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FIntPoint::X] Attempt to access a NULL self pointer");
return;
}
auto V8Result = v8::Integer::New(Isolate, Self->X);
PUERTS_NAMESPACE::DataTransfer::LinkOuter<FIntPoint, int32>(Context, Info.Holder(), V8Result);
Info.GetReturnValue().Set(V8Result);
}
static void _FIntPointXSet_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FIntPoint::X] Attempt to access a NULL self pointer");
return;
}
auto Value = Info[0];
Self->X = Value->ToInteger(Context).ToLocalChecked()->Value();
}
static void _FIntPointYGet_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FIntPoint::Y] Attempt to access a NULL self pointer");
return;
}
auto V8Result = v8::Integer::New(Isolate, Self->Y);
PUERTS_NAMESPACE::DataTransfer::LinkOuter<FIntPoint, int32>(Context, Info.Holder(), V8Result);
Info.GetReturnValue().Set(V8Result);
}
static void _FIntPointYSet_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntPoint>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FIntPoint::Y] Attempt to access a NULL self pointer");
return;
}
auto Value = Info[0];
Self->Y = Value->ToInteger(Context).ToLocalChecked()->Value();
}
struct AutoRegisterForFIntPoint
{
AutoRegisterForFIntPoint()
{
PUERTS_NAMESPACE::JSClassDefinition Def = JSClassEmptyDefinition;
static PUERTS_NAMESPACE::JSPropertyInfo Properties[] = {
{"X", _FIntPointXGet_, _FIntPointXSet_}, {"Y", _FIntPointYGet_, _FIntPointYSet_}, {0, 0, 0}};
static PUERTS_NAMESPACE::JSFunctionInfo Methods[] = {{"op_Equality", FIntPointM_op_Equality},
{"op_Inequality", FIntPointM_op_Inequality}, {"op_Multiply", FIntPointM_op_Multiply},
{"op_Division", FIntPointM_op_Division}, {"op_Addition", FIntPointM_op_Addition},
{"op_Subtraction", FIntPointM_op_Subtraction}, {"set_Item", FIntPointM_set_Item}, {"get_Item", FIntPointM_get_Item},
{"ComponentMin", FIntPointM_ComponentMin}, {"ComponentMax", FIntPointM_ComponentMax}, {"GetMax", FIntPointM_GetMax},
{"GetMin", FIntPointM_GetMin}, {"Size", FIntPointM_Size}, {"SizeSquared", FIntPointM_SizeSquared},
{"ToString", FIntPointM_ToString}, {0, 0}};
static PUERTS_NAMESPACE::JSFunctionInfo Functions[] = {{"DivideAndRoundUp", FIntPointS_DivideAndRoundUp},
{"DivideAndRoundDown", FIntPointS_DivideAndRoundDown}, {"Num", FIntPointS_Num}, {0, 0}};
Def.UETypeName = "IntPoint";
Def.SetInitialize(_FIntPointNew_);
Def.Finalize = _FIntPointDelete_;
Def.Properties = Properties;
Def.Methods = Methods;
Def.Functions = Functions;
PUERTS_NAMESPACE::RegisterJSClass(Def);
}
};
AutoRegisterForFIntPoint _AutoRegisterForFIntPoint_;
@@ -0,0 +1,647 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
// gen by puerts gen tools
#include "GenHeaders.h"
#include "CoreMinimal.h"
#include "DataTransfer.h"
#include "JSClassRegister.h"
// <SourceLocation file 'D:\\Program Files\\Epic Games\\UE_4.24\\Engine\\Source\\Runtime\\Core\\Public\\Math/IntVector.h', line 78,
// column 15> unsupported method : operator() const int32 &(int32) __attribute__((thiscall)) const
// <SourceLocation file 'D:\\Program Files\\Epic Games\\UE_4.24\\Engine\\Source\\Runtime\\Core\\Public\\Math/IntVector.h', line 86,
// column 9> unsupported method : operator() int32 &(int32) __attribute__((thiscall))
// <SourceLocation file 'D:\\Program Files\\Epic Games\\UE_4.24\\Engine\\Source\\Runtime\\Core\\Public\\Math/IntVector.h', line 126,
// column 14> unsupported method : operator*= FIntVector &(int32) __attribute__((thiscall))
// <SourceLocation file 'D:\\Program Files\\Epic Games\\UE_4.24\\Engine\\Source\\Runtime\\Core\\Public\\Math/IntVector.h', line 134,
// column 14> unsupported method : operator/= FIntVector &(int32) __attribute__((thiscall))
// <SourceLocation file 'D:\\Program Files\\Epic Games\\UE_4.24\\Engine\\Source\\Runtime\\Core\\Public\\Math/IntVector.h', line 142,
// column 14> unsupported method : operator+= FIntVector &(const FIntVector &) __attribute__((thiscall))
// <SourceLocation file 'D:\\Program Files\\Epic Games\\UE_4.24\\Engine\\Source\\Runtime\\Core\\Public\\Math/IntVector.h', line 150,
// column 14> unsupported method : operator-= FIntVector &(const FIntVector &) __attribute__((thiscall))
// <SourceLocation file 'D:\\Program Files\\Epic Games\\UE_4.24\\Engine\\Source\\Runtime\\Core\\Public\\Math/IntVector.h', line 158,
// column 14> unsupported method : operator= FIntVector &(const FIntVector &) __attribute__((thiscall))
// <SourceLocation file 'D:\\Program Files\\Epic Games\\UE_4.24\\Engine\\Source\\Runtime\\Core\\Public\\Math/IntVector.h', line 198,
// column 13> unsupported method : operator>> FIntVector (int32) __attribute__((thiscall)) const
// <SourceLocation file 'D:\\Program Files\\Epic Games\\UE_4.24\\Engine\\Source\\Runtime\\Core\\Public\\Math/IntVector.h', line 206,
// column 13> unsupported method : operator<< FIntVector (int32) __attribute__((thiscall)) const
// <SourceLocation file 'D:\\Program Files\\Epic Games\\UE_4.24\\Engine\\Source\\Runtime\\Core\\Public\\Math/IntVector.h', line 214,
// column 13> unsupported method : operator& FIntVector (int32) __attribute__((thiscall)) const
static void* _FIntVectorNew_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
FIntVector* Obj = new FIntVector();
// UE_LOG(LogTemp, Warning, TEXT("_FIntVectorNew_:%p"), Obj);
return Obj;
}
}
if (Info.Length() == 3)
{
if (Info[0]->IsNumber() && Info[1]->IsNumber() && Info[2]->IsNumber())
{
int32 Arg0 = Info[0]->ToInteger(Context).ToLocalChecked()->Value();
int32 Arg1 = Info[1]->ToInteger(Context).ToLocalChecked()->Value();
int32 Arg2 = Info[2]->ToInteger(Context).ToLocalChecked()->Value();
FIntVector* Obj = new FIntVector(Arg0, Arg1, Arg2);
// UE_LOG(LogTemp, Warning, TEXT("_FIntVectorNew_:%p"), Obj);
return Obj;
}
}
if (Info.Length() == 1)
{
if (Info[0]->IsNumber())
{
int32 Arg0 = Info[0]->ToInteger(Context).ToLocalChecked()->Value();
FIntVector* Obj = new FIntVector(Arg0);
// UE_LOG(LogTemp, Warning, TEXT("_FIntVectorNew_:%p"), Obj);
return Obj;
}
}
if (Info.Length() == 1)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FVector>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()))
{
FVector* Arg0 = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FVector>(Info[0]->ToObject(Context).ToLocalChecked());
FIntVector* Obj = new FIntVector(*Arg0);
// UE_LOG(LogTemp, Warning, TEXT("_FIntVectorNew_:%p"), Obj);
return Obj;
}
}
if (Info.Length() == 1)
{
if (Info[0]->IsNumber())
{
EForceInit Arg0 = EForceInit(Info[0]->ToInt32(Context).ToLocalChecked()->Value());
FIntVector* Obj = new FIntVector(Arg0);
// UE_LOG(LogTemp, Warning, TEXT("_FIntVectorNew_:%p"), Obj);
return Obj;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
return nullptr;
}
static void _FIntVectorDelete_(void* Ptr, void* ClassData, void* EnvData)
{
FIntVector* Self = static_cast<FIntVector*>(Ptr);
// UE_LOG(LogTemp, Warning, TEXT("_FIntVectorDelete_:%p"), Self);
delete Self;
}
static void FIntVectorM_get_Item(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsNumber())
{
int32 Arg0 = Info[0]->ToInteger(Context).ToLocalChecked()->Value();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntVector>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntVector::M_get_Item] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->operator[](Arg0);
auto V8Result = v8::Integer::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntVectorM_set_Item(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsNumber())
{
int32 Arg0 = Info[0]->ToInteger(Context).ToLocalChecked()->Value();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntVector>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntVector::M_set_Item] Attempt to access a NULL self pointer");
return;
}
Self->operator[](Arg0);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntVectorM_op_Equality(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FIntVector>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()))
{
const FIntVector* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntVector>(Info[0]->ToObject(Context).ToLocalChecked());
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntVector>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntVector::M_op_Equality] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->operator==(*Arg0);
auto V8Result = v8::Boolean::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntVectorM_op_Inequality(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FIntVector>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()))
{
const FIntVector* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntVector>(Info[0]->ToObject(Context).ToLocalChecked());
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntVector>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntVector::M_op_Inequality] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->operator!=(*Arg0);
auto V8Result = v8::Boolean::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntVectorM_op_Multiply(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsNumber())
{
int32 Arg0 = Info[0]->ToInteger(Context).ToLocalChecked()->Value();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntVector>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntVector::M_op_Multiply] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->operator*(Arg0);
void* Ptr = new FIntVector(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FIntVector>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntVectorM_op_Division(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsNumber())
{
int32 Arg0 = Info[0]->ToInteger(Context).ToLocalChecked()->Value();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntVector>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntVector::M_op_Division] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->operator/(Arg0);
void* Ptr = new FIntVector(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FIntVector>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntVectorM_op_Addition(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FIntVector>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()))
{
const FIntVector* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntVector>(Info[0]->ToObject(Context).ToLocalChecked());
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntVector>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntVector::M_op_Addition] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->operator+(*Arg0);
void* Ptr = new FIntVector(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FIntVector>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntVectorM_op_Subtraction(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 1)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FIntVector>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()))
{
const FIntVector* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntVector>(Info[0]->ToObject(Context).ToLocalChecked());
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntVector>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntVector::M_op_Subtraction] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->operator-(*Arg0);
void* Ptr = new FIntVector(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FIntVector>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntVectorM_IsZero(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntVector>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntVector::M_IsZero] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->IsZero();
auto V8Result = v8::Boolean::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntVectorM_GetMax(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntVector>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntVector::M_GetMax] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->GetMax();
auto V8Result = v8::Integer::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntVectorM_GetMin(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntVector>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntVector::M_GetMin] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->GetMin();
auto V8Result = v8::Integer::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntVectorM_Size(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntVector>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntVector::M_Size] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->Size();
auto V8Result = v8::Integer::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntVectorM_ToString(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntVector>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(
Isolate, "[FIntVector::M_ToString] Attempt to access a NULL self pointer");
return;
}
auto MethodResult = Self->ToString();
auto V8Result =
v8::String::NewFromUtf8(Isolate, TCHAR_TO_UTF8(*MethodResult), v8::NewStringType::kNormal).ToLocalChecked();
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntVectorS_DivideAndRoundUp(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 2)
{
if (Info[0]->IsObject() &&
PUERTS_NAMESPACE::DataTransfer::IsInstanceOf<FIntVector>(Isolate, Info[0]->ToObject(Context).ToLocalChecked()) &&
Info[1]->IsNumber())
{
FIntVector* Arg0 =
PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntVector>(Info[0]->ToObject(Context).ToLocalChecked());
int32 Arg1 = Info[1]->ToInteger(Context).ToLocalChecked()->Value();
auto MethodResult = FIntVector::DivideAndRoundUp(*Arg0, Arg1);
void* Ptr = new FIntVector(MethodResult);
auto V8Result = PUERTS_NAMESPACE::DataTransfer::FindOrAddStruct<FIntVector>(Isolate, Context, Ptr, false);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void FIntVectorS_Num(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
if (Info.Length() == 0)
{
if (true)
{
auto MethodResult = FIntVector::Num();
auto V8Result = v8::Integer::New(Isolate, MethodResult);
Info.GetReturnValue().Set(V8Result);
return;
}
}
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "Invalid argument!");
}
static void _FIntVectorXGet_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntVector>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FIntVector::X] Attempt to access a NULL self pointer");
return;
}
auto V8Result = v8::Integer::New(Isolate, Self->X);
PUERTS_NAMESPACE::DataTransfer::LinkOuter<FIntVector, int32>(Context, Info.Holder(), V8Result);
Info.GetReturnValue().Set(V8Result);
}
static void _FIntVectorXSet_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntVector>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FIntVector::X] Attempt to access a NULL self pointer");
return;
}
auto Value = Info[0];
Self->X = Value->ToInteger(Context).ToLocalChecked()->Value();
}
static void _FIntVectorYGet_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntVector>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FIntVector::Y] Attempt to access a NULL self pointer");
return;
}
auto V8Result = v8::Integer::New(Isolate, Self->Y);
PUERTS_NAMESPACE::DataTransfer::LinkOuter<FIntVector, int32>(Context, Info.Holder(), V8Result);
Info.GetReturnValue().Set(V8Result);
}
static void _FIntVectorYSet_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntVector>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FIntVector::Y] Attempt to access a NULL self pointer");
return;
}
auto Value = Info[0];
Self->Y = Value->ToInteger(Context).ToLocalChecked()->Value();
}
static void _FIntVectorZGet_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntVector>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FIntVector::Z] Attempt to access a NULL self pointer");
return;
}
auto V8Result = v8::Integer::New(Isolate, Self->Z);
PUERTS_NAMESPACE::DataTransfer::LinkOuter<FIntVector, int32>(Context, Info.Holder(), V8Result);
Info.GetReturnValue().Set(V8Result);
}
static void _FIntVectorZSet_(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = PUERTS_NAMESPACE::DataTransfer::GetPointerFast<FIntVector>(Info.Holder());
if (!Self)
{
PUERTS_NAMESPACE::DataTransfer::ThrowException(Isolate, "[FIntVector::Z] Attempt to access a NULL self pointer");
return;
}
auto Value = Info[0];
Self->Z = Value->ToInteger(Context).ToLocalChecked()->Value();
}
struct AutoRegisterForFIntVector
{
AutoRegisterForFIntVector()
{
PUERTS_NAMESPACE::JSClassDefinition Def = JSClassEmptyDefinition;
static PUERTS_NAMESPACE::JSPropertyInfo Properties[] = {{"X", _FIntVectorXGet_, _FIntVectorXSet_},
{"Y", _FIntVectorYGet_, _FIntVectorYSet_}, {"Z", _FIntVectorZGet_, _FIntVectorZSet_}, {0, 0, 0}};
static PUERTS_NAMESPACE::JSFunctionInfo Methods[] = {{"get_Item", FIntVectorM_get_Item}, {"set_Item", FIntVectorM_set_Item},
{"op_Equality", FIntVectorM_op_Equality}, {"op_Inequality", FIntVectorM_op_Inequality},
{"op_Multiply", FIntVectorM_op_Multiply}, {"op_Division", FIntVectorM_op_Division},
{"op_Addition", FIntVectorM_op_Addition}, {"op_Subtraction", FIntVectorM_op_Subtraction},
{"IsZero", FIntVectorM_IsZero}, {"GetMax", FIntVectorM_GetMax}, {"GetMin", FIntVectorM_GetMin},
{"Size", FIntVectorM_Size}, {"ToString", FIntVectorM_ToString}, {0, 0}};
static PUERTS_NAMESPACE::JSFunctionInfo Functions[] = {
{"DivideAndRoundUp", FIntVectorS_DivideAndRoundUp}, {"Num", FIntVectorS_Num}, {0, 0}};
Def.UETypeName = "IntVector";
Def.SetInitialize(_FIntVectorNew_);
Def.Finalize = _FIntVectorDelete_;
Def.Properties = Properties;
Def.Methods = Methods;
Def.Functions = Functions;
PUERTS_NAMESPACE::RegisterJSClass(Def);
}
};
AutoRegisterForFIntVector _AutoRegisterForFIntVector_;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,66 @@
#pragma once
#if !defined(ENGINE_INDEPENDENT_JSENV)
#include "Engine/NetworkObjectList.h"
#include "TimerManager.h"
#include "Materials/MaterialInstanceDynamic.h"
#include "Containers/Array.h"
#include "DisplayDebugHelpers.h"
#include "Engine/BlueprintGeneratedClass.h"
#include "Engine/ActorChannel.h"
#include "Engine/NetConnection.h"
#include "Engine/Canvas.h"
#include "GameFramework/Actor.h"
#include "GameFramework/CameraBlockingVolume.h"
#include "GameFramework/Character.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "GameFramework/CheatManager.h"
#include "GameFramework/Controller.h"
#include "GameFramework/DamageType.h"
#include "GameFramework/DebugTextInfo.h"
#include "GameFramework/DefaultPawn.h"
#include "GameFramework/DefaultPhysicsVolume.h"
#include "GameFramework/EngineMessage.h"
#include "GameFramework/FloatingPawnMovement.h"
#include "GameFramework/ForceFeedbackAttenuation.h"
#include "GameFramework/ForceFeedbackEffect.h"
#include "GameFramework/GameMode.h"
#include "GameFramework/GameModeBase.h"
#include "GameFramework/GameNetworkManager.h"
#include "GameFramework/GameSession.h"
#include "GameFramework/GameState.h"
#include "GameFramework/GameStateBase.h"
#include "GameFramework/GameUserSettings.h"
#include "GameFramework/HUD.h"
#include "GameFramework/HUDHitBox.h"
#include "GameFramework/Info.h"
#include "GameFramework/InputSettings.h"
#include "GameFramework/KillZVolume.h"
#include "GameFramework/LocalMessage.h"
#include "GameFramework/MovementComponent.h"
#include "GameFramework/NavMovementComponent.h"
#include "GameFramework/OnlineReplStructs.h"
#include "GameFramework/OnlineSession.h"
#include "GameFramework/PainCausingVolume.h"
#include "GameFramework/Pawn.h"
#include "GameFramework/PawnMovementComponent.h"
#include "GameFramework/PhysicsVolume.h"
#include "GameFramework/PlayerController.h"
#include "GameFramework/PlayerInput.h"
#include "GameFramework/PlayerMuteList.h"
#include "GameFramework/PlayerStart.h"
#include "GameFramework/PlayerState.h"
#include "GameFramework/ProjectileMovementComponent.h"
#include "GameFramework/RootMotionSource.h"
#include "GameFramework/RotatingMovementComponent.h"
#include "GameFramework/SaveGame.h"
#include "GameFramework/SimpleReticle.h"
#include "GameFramework/SpectatorPawn.h"
#include "GameFramework/SpectatorPawnMovement.h"
#include "GameFramework/SpringArmComponent.h"
#include "GameFramework/TouchInterface.h"
#include "GameFramework/Volume.h"
#include "GameFramework/WorldSettings.h"
#include "Runtime/Launch/Resources/Version.h"
#endif
@@ -0,0 +1,60 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may be subject to their corresponding license terms.
* This file is subject to the terms and conditions defined in file 'LICENSE', which is part of this source code package.
*/
#if PLATFORM_IOS
#import <Foundation/Foundation.h>
#include <pesapi.h>
#include <string>
@interface PesapiFrameworkLoader : NSObject
@end
@implementation PesapiFrameworkLoader
+ (int)load:(NSString*) frameworkName entryClassName:(NSString*)entryClassName funcPtrArray:(pesapi_func_ptr*)funcPtrArray {
NSLog(@"load addon name:%@ entry class:%@", frameworkName, entryClassName);
//for + function
Class entryClass = NSClassFromString(entryClassName);
if (entryClass) {
SEL selector = NSSelectorFromString(@"initlib:");
//for + function
IMP impl = [entryClass methodForSelector:selector];
if (impl) {
//@try {
void* (*entryFunc)(Class, SEL, pesapi_func_ptr*) = (void*(*)(Class,SEL,pesapi_func_ptr*))impl;
entryFunc(entryClass, selector, funcPtrArray);
return 0;
//}
//@catch (NSException * e) {
// NSLog(@"PesapiFrameworkLoader loadFramework exception: %@", e);
//}
//@finally {
// NSLog(@"PesapiFrameworkLoader loadFramework finally");
//}
} else {
NSLog(@"load addon %@ fail: can not found selector initlib:", frameworkName);
}
} else {
NSLog(@"load addon %@ fail: can not found class:%@", frameworkName, entryClassName);
}
return -1;
}
@end
int PesapiLoadFramework(std::string frameworkName, std::string entryClassName, pesapi_func_ptr* funcPtrArray)
{
NSString* p1 = [NSString stringWithUTF8String:frameworkName.c_str()];
NSString* p2 = [NSString stringWithUTF8String:entryClassName.c_str()];
return [PesapiFrameworkLoader load:p1 entryClassName:p2 funcPtrArray:funcPtrArray];
}
#endif
@@ -0,0 +1,52 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "JSAnimGeneratedClass.h"
#include "JSGeneratedFunction.h"
void UJSAnimGeneratedClass::StaticConstructor(const FObjectInitializer& ObjectInitializer)
{
auto Class = static_cast<UJSAnimGeneratedClass*>(ObjectInitializer.GetClass());
auto Object = ObjectInitializer.GetObj();
Class->GetSuperClass()->ClassConstructor(ObjectInitializer);
#ifdef THREAD_SAFE
v8::Locker Locker(Class->Isolate);
#endif
auto PinedDynamicInvoker = Class->DynamicInvoker.Pin();
if (PinedDynamicInvoker)
{
PinedDynamicInvoker->JsConstruct(Class, Object, Class->Constructor, Class->Prototype);
}
}
void UJSAnimGeneratedClass::InitPropertiesFromCustomList(uint8* DataPtr, const uint8* DefaultDataPtr)
{
if (const FCustomPropertyListNode* CustomPropertyList = GetCustomPropertyListForPostConstruction())
{
UBlueprintGeneratedClass::InitPropertiesFromCustomList(CustomPropertyList, this, DataPtr, DefaultDataPtr);
}
}
void UJSAnimGeneratedClass::Release()
{
for (TFieldIterator<UFunction> It(this, EFieldIteratorFlags::IncludeSuper, EFieldIteratorFlags::ExcludeDeprecated,
EFieldIteratorFlags::IncludeInterfaces);
It; ++It)
{
if (auto Function = Cast<UJSGeneratedFunction>(*It))
{
// UE_LOG(LogTemp, Warning, TEXT("release: %s"), *Function->GetName());
Function->JsFunction.Reset();
}
}
Constructor.Reset();
Prototype.Reset();
}
@@ -0,0 +1,51 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include "NamespaceDef.h"
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#pragma warning(push, 0)
#include "libplatform/libplatform.h"
#include "v8.h"
#pragma warning(pop)
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
#include "DynamicInvoker.h"
#include "CoreMinimal.h"
#include "Animation/AnimBlueprintGeneratedClass.h"
#include "JSAnimGeneratedClass.generated.h"
/**
*
*/
UCLASS()
class UJSAnimGeneratedClass : public UAnimBlueprintGeneratedClass
{
GENERATED_BODY()
public:
void InitPropertiesFromCustomList(uint8* DataPtr, const uint8* DefaultDataPtr) override;
void Release();
static void StaticConstructor(const FObjectInitializer& ObjectInitializer);
public:
v8::UniquePersistent<v8::Function> Constructor;
v8::UniquePersistent<v8::Object> Prototype;
TWeakPtr<PUERTS_NAMESPACE::IDynamicInvoker, ESPMode::ThreadSafe> DynamicInvoker;
#ifdef THREAD_SAFE
v8::Isolate* Isolate;
#endif
};
@@ -0,0 +1,392 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "JSClassRegister.h"
#if USING_IN_UNREAL_ENGINE
#include "UObject/Class.h"
#endif
#include <map>
#include <cstring>
namespace PUERTS_NAMESPACE
{
template <class T>
static T* PropertyInfoDuplicate(T* Arr)
{
if (Arr == nullptr)
return nullptr;
int Count = 0;
;
while (true)
{
if (Arr[Count++].Name == nullptr)
break;
}
T* Ret = new T[Count];
::memcpy(Ret, Arr, sizeof(T) * Count);
return Ret;
}
JSClassDefinition* JSClassDefinitionDuplicate(const JSClassDefinition* ClassDefinition)
{
auto Ret = new JSClassDefinition;
::memcpy(Ret, ClassDefinition, sizeof(JSClassDefinition));
Ret->Methods = PropertyInfoDuplicate(ClassDefinition->Methods);
Ret->Functions = PropertyInfoDuplicate(ClassDefinition->Functions);
Ret->Properties = PropertyInfoDuplicate(ClassDefinition->Properties);
Ret->Variables = PropertyInfoDuplicate(ClassDefinition->Variables);
Ret->ConstructorInfos = PropertyInfoDuplicate(ClassDefinition->ConstructorInfos);
Ret->MethodInfos = PropertyInfoDuplicate(ClassDefinition->MethodInfos);
Ret->FunctionInfos = PropertyInfoDuplicate(ClassDefinition->FunctionInfos);
Ret->PropertyInfos = PropertyInfoDuplicate(ClassDefinition->PropertyInfos);
Ret->VariableInfos = PropertyInfoDuplicate(ClassDefinition->VariableInfos);
return Ret;
}
void JSClassDefinitionDelete(JSClassDefinition* ClassDefinition)
{
delete[] ClassDefinition->Methods;
delete[] ClassDefinition->Functions;
delete[] ClassDefinition->Properties;
delete[] ClassDefinition->Variables;
delete[] ClassDefinition->ConstructorInfos;
delete[] ClassDefinition->MethodInfos;
delete[] ClassDefinition->FunctionInfos;
delete[] ClassDefinition->PropertyInfos;
delete[] ClassDefinition->VariableInfos;
delete ClassDefinition;
}
class JSClassRegister
{
public:
JSClassRegister();
~JSClassRegister();
void RegisterClass(const JSClassDefinition& ClassDefinition);
void SetClassTypeInfo(const void* TypeId, const NamedFunctionInfo* ConstructorInfos, const NamedFunctionInfo* MethodInfos,
const NamedFunctionInfo* FunctionInfos, const NamedPropertyInfo* PropertyInfos, const NamedPropertyInfo* VariableInfos);
void ForeachRegisterClass(std::function<void(const JSClassDefinition* ClassDefinition)>);
const JSClassDefinition* FindClassByID(const void* TypeId);
void OnClassNotFound(pesapi_class_not_found_callback InCallback)
{
ClassNotFoundCallback = InCallback;
}
const JSClassDefinition* LoadClassByID(const void* TypeId)
{
if (!TypeId)
{
return nullptr;
}
auto clsDef = FindClassByID(TypeId);
if (!clsDef && ClassNotFoundCallback)
{
if (!ClassNotFoundCallback(TypeId))
{
return nullptr;
}
clsDef = FindClassByID(TypeId);
}
return clsDef;
}
const JSClassDefinition* FindCppTypeClassByName(const std::string& Name);
#if USING_IN_UNREAL_ENGINE
void RegisterAddon(const std::string& Name, AddonRegisterFunc RegisterFunc);
AddonRegisterFunc FindAddonRegisterFunc(const std::string& Name);
const JSClassDefinition* FindClassByType(UStruct* Type);
#endif
private:
std::map<const void*, JSClassDefinition*> CDataIdToClassDefinition;
std::map<std::string, JSClassDefinition*> CDataNameToClassDefinition;
pesapi_class_not_found_callback ClassNotFoundCallback = nullptr;
#if USING_IN_UNREAL_ENGINE
std::map<std::string, AddonRegisterFunc> AddonRegisterInfos;
std::map<FString, JSClassDefinition*> StructNameToClassDefinition;
#endif
};
JSClassRegister::JSClassRegister()
{
}
JSClassRegister::~JSClassRegister()
{
for (auto& KV : CDataIdToClassDefinition)
{
JSClassDefinitionDelete(KV.second);
}
CDataIdToClassDefinition.clear();
#if USING_IN_UNREAL_ENGINE
for (auto& KV : StructNameToClassDefinition)
{
JSClassDefinitionDelete(KV.second);
}
StructNameToClassDefinition.clear();
#endif
}
void JSClassRegister::RegisterClass(const JSClassDefinition& ClassDefinition)
{
if (ClassDefinition.TypeId && ClassDefinition.ScriptName)
{
auto cd_iter = CDataIdToClassDefinition.find(ClassDefinition.TypeId);
if (cd_iter != CDataIdToClassDefinition.end())
{
JSClassDefinitionDelete(cd_iter->second);
}
CDataIdToClassDefinition[ClassDefinition.TypeId] = JSClassDefinitionDuplicate(&ClassDefinition);
std::string SN = ClassDefinition.ScriptName;
CDataNameToClassDefinition[SN] = CDataIdToClassDefinition[ClassDefinition.TypeId];
CDataIdToClassDefinition[ClassDefinition.TypeId]->ScriptName = CDataNameToClassDefinition.find(SN)->first.c_str();
}
#if USING_IN_UNREAL_ENGINE
else if (ClassDefinition.UETypeName)
{
FString SN = UTF8_TO_TCHAR(ClassDefinition.UETypeName);
auto ud_iter = StructNameToClassDefinition.find(SN);
if (ud_iter != StructNameToClassDefinition.end())
{
JSClassDefinitionDelete(ud_iter->second);
}
StructNameToClassDefinition[SN] = JSClassDefinitionDuplicate(&ClassDefinition);
}
#endif
}
void SetReflectoinInfo(JSFunctionInfo* Methods, const NamedFunctionInfo* MethodInfos)
{
std::map<std::string, std::tuple<int, const NamedFunctionInfo*>> InfoMap;
const NamedFunctionInfo* MethodInfo = MethodInfos;
while (MethodInfo->Name)
{
auto Iter = InfoMap.find(MethodInfo->Name);
if (Iter == InfoMap.end())
{
InfoMap[MethodInfo->Name] = std::make_tuple(1, MethodInfo);
}
else
{
std::get<0>(Iter->second) = 2;
}
++MethodInfo;
}
JSFunctionInfo* Method = Methods;
while (Method->Name)
{
auto Iter = InfoMap.find(Method->Name);
if (Iter != InfoMap.end() && std::get<0>(Iter->second) == 1)
{
Method->ReflectionInfo = std::get<1>(Iter->second)->Type;
}
++Method;
}
}
void JSClassRegister::SetClassTypeInfo(const void* TypeId, const NamedFunctionInfo* ConstructorInfos,
const NamedFunctionInfo* MethodInfos, const NamedFunctionInfo* FunctionInfos, const NamedPropertyInfo* PropertyInfos,
const NamedPropertyInfo* VariableInfos)
{
auto ClassDef = const_cast<JSClassDefinition*>(FindClassByID(TypeId));
if (ClassDef)
{
ClassDef->ConstructorInfos = PropertyInfoDuplicate(const_cast<NamedFunctionInfo*>(ConstructorInfos));
ClassDef->MethodInfos = PropertyInfoDuplicate(const_cast<NamedFunctionInfo*>(MethodInfos));
ClassDef->FunctionInfos = PropertyInfoDuplicate(const_cast<NamedFunctionInfo*>(FunctionInfos));
ClassDef->PropertyInfos = PropertyInfoDuplicate(const_cast<NamedPropertyInfo*>(PropertyInfos));
ClassDef->VariableInfos = PropertyInfoDuplicate(const_cast<NamedPropertyInfo*>(VariableInfos));
SetReflectoinInfo(ClassDef->Methods, ClassDef->MethodInfos);
SetReflectoinInfo(ClassDef->Functions, ClassDef->FunctionInfos);
}
}
const JSClassDefinition* JSClassRegister::FindClassByID(const void* TypeId)
{
if (!TypeId)
{
return nullptr;
}
auto Iter = CDataIdToClassDefinition.find(TypeId);
if (Iter == CDataIdToClassDefinition.end())
{
return nullptr;
}
else
{
return Iter->second;
}
}
const JSClassDefinition* JSClassRegister::FindCppTypeClassByName(const std::string& Name)
{
auto Iter = CDataNameToClassDefinition.find(Name);
if (Iter == CDataNameToClassDefinition.end())
{
return nullptr;
}
else
{
return Iter->second;
}
}
#if USING_IN_UNREAL_ENGINE
void JSClassRegister::RegisterAddon(const std::string& Name, AddonRegisterFunc RegisterFunc)
{
AddonRegisterInfos[Name] = RegisterFunc;
}
AddonRegisterFunc JSClassRegister::FindAddonRegisterFunc(const std::string& Name)
{
auto Iter = AddonRegisterInfos.find(Name);
if (Iter == AddonRegisterInfos.end())
{
return nullptr;
}
else
{
return Iter->second;
}
}
const JSClassDefinition* JSClassRegister::FindClassByType(UStruct* Type)
{
auto Iter = StructNameToClassDefinition.find(Type->GetName());
if (Iter == StructNameToClassDefinition.end())
{
return nullptr;
}
else
{
return Iter->second;
}
}
#endif
void JSClassRegister::ForeachRegisterClass(std::function<void(const JSClassDefinition* ClassDefinition)> Callback)
{
for (auto& KV : CDataNameToClassDefinition)
{
Callback(KV.second);
}
#if USING_IN_UNREAL_ENGINE
for (auto& KV : StructNameToClassDefinition)
{
Callback(KV.second);
}
#endif
}
JSClassRegister* GetJSClassRegister()
{
static JSClassRegister S_JSClassRegister;
return &S_JSClassRegister;
}
void RegisterJSClass(const JSClassDefinition& ClassDefinition)
{
GetJSClassRegister()->RegisterClass(ClassDefinition);
}
void SetClassTypeInfo(const void* TypeId, const NamedFunctionInfo* ConstructorInfos, const NamedFunctionInfo* MethodInfos,
const NamedFunctionInfo* FunctionInfos, const NamedPropertyInfo* PropertyInfos, const NamedPropertyInfo* VariableInfos)
{
GetJSClassRegister()->SetClassTypeInfo(TypeId, ConstructorInfos, MethodInfos, FunctionInfos, PropertyInfos, VariableInfos);
}
void ForeachRegisterClass(std::function<void(const JSClassDefinition* ClassDefinition)> Callback)
{
GetJSClassRegister()->ForeachRegisterClass(Callback);
}
const JSClassDefinition* FindClassByID(const void* TypeId)
{
return GetJSClassRegister()->FindClassByID(TypeId);
}
void OnClassNotFound(pesapi_class_not_found_callback Callback)
{
GetJSClassRegister()->OnClassNotFound(Callback);
}
const JSClassDefinition* LoadClassByID(const void* TypeId)
{
return GetJSClassRegister()->LoadClassByID(TypeId);
}
const JSClassDefinition* FindCppTypeClassByName(const std::string& Name)
{
return GetJSClassRegister()->FindCppTypeClassByName(Name);
}
bool TraceObjectLifecycle(const void* TypeId, pesapi_on_native_object_enter OnEnter, pesapi_on_native_object_exit OnExit)
{
if (auto clsDef = const_cast<JSClassDefinition*>(GetJSClassRegister()->FindClassByID(TypeId)))
{
clsDef->OnEnter = OnEnter;
clsDef->OnExit = OnExit;
return true;
}
return false;
}
#if USING_IN_UNREAL_ENGINE
bool IsEditorOnlyUFunction(const UFunction* Func)
{
// a simplified version of IsEditorOnlyObject(), sadly it's a EditorOnly Function so I have to reimplement a toy one
if (!Func)
{
return false;
}
if (Func->HasAnyFunctionFlags(FUNC_EditorOnly))
{
return true;
}
auto InObject = Func;
if (InObject->HasAnyMarks(OBJECTMARK_EditorOnly) || InObject->IsEditorOnly())
{
return true;
}
auto Package = Func->GetPackage();
if (Package && Package->HasAnyPackageFlags(PKG_EditorOnly))
{
return true;
}
return false;
}
void RegisterAddon(const char* Name, AddonRegisterFunc RegisterFunc)
{
GetJSClassRegister()->RegisterAddon(Name, RegisterFunc);
}
AddonRegisterFunc FindAddonRegisterFunc(const std::string& Name)
{
return GetJSClassRegister()->FindAddonRegisterFunc(Name);
}
const JSClassDefinition* FindClassByType(UStruct* Type)
{
return GetJSClassRegister()->FindClassByType(Type);
}
#endif
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,385 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "JSGeneratedClass.h"
#include "Engine/Blueprint.h"
#include "JSGeneratedFunction.h"
#include "JSWidgetGeneratedClass.h"
#include "JSAnimGeneratedClass.h"
#include "JSLogger.h"
#define OLD_METHOD_PREFIX "__puerts_old__"
#define MIXIN_METHOD_SUFFIX "__puerts_mixin__"
UClass* UJSGeneratedClass::Create(const FString& Name, UClass* Parent,
TSharedPtr<PUERTS_NAMESPACE::IDynamicInvoker, ESPMode::ThreadSafe> DynamicInvoker, v8::Isolate* Isolate,
v8::Local<v8::Function> Constructor, v8::Local<v8::Object> Prototype)
{
auto Outer = GetTransientPackage();
UClass* Class = nullptr;
if (Cast<UWidgetBlueprintGeneratedClass>(Parent))
{
auto JSGeneratedClass = NewObject<UJSWidgetGeneratedClass>(Outer, *Name, RF_Public);
#ifdef THREAD_SAFE
JSGeneratedClass->Isolate = Isolate;
#endif
JSGeneratedClass->DynamicInvoker = DynamicInvoker;
JSGeneratedClass->Constructor = v8::UniquePersistent<v8::Function>(Isolate, Constructor);
JSGeneratedClass->Prototype = v8::UniquePersistent<v8::Object>(Isolate, Prototype);
JSGeneratedClass->ClassConstructor = &UJSWidgetGeneratedClass::StaticConstructor;
Class = JSGeneratedClass;
}
else if (Cast<UAnimBlueprintGeneratedClass>(Parent))
{
auto JSGeneratedClass = NewObject<UJSAnimGeneratedClass>(Outer, *Name, RF_Public);
#ifdef THREAD_SAFE
JSGeneratedClass->Isolate = Isolate;
#endif
JSGeneratedClass->DynamicInvoker = DynamicInvoker;
JSGeneratedClass->Constructor = v8::UniquePersistent<v8::Function>(Isolate, Constructor);
JSGeneratedClass->Prototype = v8::UniquePersistent<v8::Object>(Isolate, Prototype);
JSGeneratedClass->ClassConstructor = &UJSAnimGeneratedClass::StaticConstructor;
Class = JSGeneratedClass;
}
else
{
auto JSGeneratedClass = NewObject<UJSGeneratedClass>(Outer, *Name, RF_Public);
#ifdef THREAD_SAFE
JSGeneratedClass->Isolate = Isolate;
#endif
JSGeneratedClass->DynamicInvoker = DynamicInvoker;
JSGeneratedClass->Constructor = v8::UniquePersistent<v8::Function>(Isolate, Constructor);
JSGeneratedClass->Prototype = v8::UniquePersistent<v8::Object>(Isolate, Prototype);
JSGeneratedClass->ClassConstructor = &UJSGeneratedClass::StaticConstructor;
Class = JSGeneratedClass;
}
auto Blueprint = NewObject<UBlueprint>(Outer);
Blueprint->GeneratedClass = Class;
#if ENGINE_MAJOR_VERSION < 5 || WITH_EDITOR
Class->ClassGeneratedBy = Blueprint;
#endif
// Set properties we need to regenerate the class with
Class->PropertyLink = Parent->PropertyLink;
Class->ClassWithin = Parent->ClassWithin;
Class->ClassConfigName = Parent->ClassConfigName;
Class->SetSuperStruct(Parent);
Class->ClassFlags |= (Parent->ClassFlags & (CLASS_Inherit | CLASS_ScriptInherit | CLASS_CompiledFromBlueprint));
Class->ClassFlags |= CLASS_CompiledFromBlueprint; // AActor::Tick只有有这标记时,才会调用ReceiveTick
Class->ClassCastFlags |= Parent->ClassCastFlags;
return Class;
}
void UJSGeneratedClass::StaticConstructor(const FObjectInitializer& ObjectInitializer)
{
auto Class = ObjectInitializer.GetClass();
auto Object = ObjectInitializer.GetObj();
Class->GetSuperClass()->ClassConstructor(ObjectInitializer);
if (auto JSGeneratedClass = Cast<UJSGeneratedClass>(Class))
{
#ifdef THREAD_SAFE
v8::Locker Locker(JSGeneratedClass->Isolate);
#endif
auto PinedDynamicInvoker = JSGeneratedClass->DynamicInvoker.Pin();
if (PinedDynamicInvoker)
{
PinedDynamicInvoker->JsConstruct(JSGeneratedClass, Object, JSGeneratedClass->Constructor, JSGeneratedClass->Prototype);
}
}
}
void UJSGeneratedClass::Override(v8::Isolate* Isolate, UClass* Class, UFunction* Super, v8::Local<v8::Function> JSImpl,
TSharedPtr<PUERTS_NAMESPACE::IDynamicInvoker, ESPMode::ThreadSafe> DynamicInvoker, bool IsNative)
{
bool Existed = Super->GetOuter() == Class;
FName FunctionName = Super->GetFName();
if (Existed)
{
if (auto MaybeJSFunction = Cast<UJSGeneratedFunction>(Super)) //这种情况只需简单替换下js函数
{
MaybeJSFunction->DynamicInvoker = DynamicInvoker;
MaybeJSFunction->FunctionTranslator = std::make_unique<PUERTS_NAMESPACE::FFunctionTranslator>(Super, false);
MaybeJSFunction->JsFunction.Reset(Isolate, JSImpl);
MaybeJSFunction->SetNativeFunc(&UJSGeneratedFunction::execCallJS);
return;
}
// UE_LOG(LogTemp, Error, TEXT("replace %s of %s"), *Super->GetName(), *Class->GetName());
//同一Outer下的同名对象只能有一个...
Super->Rename(*FString::Printf(TEXT("%s%s"), TEXT(OLD_METHOD_PREFIX), *Super->GetName()), Class,
REN_DontCreateRedirectors | REN_DoNotDirty | REN_ForceNoResetLoaders);
Class->AddFunctionToFunctionMap(Super, Super->GetFName());
// UE_LOG(LogTemp, Error, TEXT("rename to %s"), *Super->GetName());
}
// UE_LOG(LogTemp, Error, TEXT("new function name %s"), *FunctionName.ToString());
UJSGeneratedFunction* Function = Cast<UJSGeneratedFunction>(
StaticDuplicateObject(Super, Class, FunctionName, RF_Transient, UJSGeneratedFunction::StaticClass()));
for (TFieldIterator<UFunction> It(Class, EFieldIteratorFlags::IncludeSuper, EFieldIteratorFlags::ExcludeDeprecated,
EFieldIteratorFlags::IncludeInterfaces);
It; ++It)
{
if (*It == Function)
{
return;
}
}
if (!Existed)
{
// UE_LOG(LogTemp, Error, TEXT("new function %s"), *FunctionName.ToString());
Function->SetSuperStruct(Super);
}
else
{
// UE_LOG(LogTemp, Error, TEXT("replace function %s"), *FunctionName.ToString());
Function->SetSuperStruct(Super->GetSuperStruct());
}
Function->Bind();
Function->StaticLink(true);
if (IsNative)
{
Function->FunctionFlags |= FUNC_Native; //让UE不走解析
}
Function->SetNativeFunc(&UJSGeneratedFunction::execCallJS);
Function->JsFunction = v8::UniquePersistent<v8::Function>(Isolate, JSImpl);
Function->DynamicInvoker = DynamicInvoker;
Function->FunctionTranslator = std::make_unique<PUERTS_NAMESPACE::FFunctionTranslator>(Function, false);
if (Existed)
{
Function->Next = Super->Next;
if (Class->Children == Super) // first one
{
Class->Children = Function;
}
else
{
auto P = Class->Children;
while (P && P->Next != Super)
P = P->Next;
check(P);
P->Next = Function;
}
Class->RemoveFunctionFromFunctionMap(Super);
}
else
{
Function->Next = Class->Children;
Class->Children = Function;
}
Class->AddFunctionToFunctionMap(Function, Function->GetFName());
}
UFunction* UJSGeneratedClass::Mixin(v8::Isolate* Isolate, UClass* Class, UFunction* Super,
TSharedPtr<PUERTS_NAMESPACE::IDynamicInvoker, ESPMode::ThreadSafe> DynamicInvoker, bool TakeJsObjectRef, bool Warning)
{
bool Existed = Super->GetOuter() == Class;
if (!Existed)
{
UFunction* Tmp =
Cast<UFunction>(StaticDuplicateObject(Super, Class, Super->GetFName(), RF_AllFlags, UFunction::StaticClass()));
Tmp->SetSuperStruct(Super);
Tmp->Next = Class->Children;
Class->Children = Tmp;
Class->AddFunctionToFunctionMap(Tmp, Tmp->GetFName());
Tmp->SetFlags(Tmp->GetFlags() | RF_Transient);
Super = Tmp;
}
auto MaybeJSFunction = Cast<UJSGeneratedFunction>(Super);
if (!MaybeJSFunction)
{
MaybeJSFunction = UJSGeneratedFunction::GetJSGeneratedFunctionFromScript(Super);
}
if (MaybeJSFunction)
{
if (Warning)
{
UE_LOG(Puerts, Warning, TEXT("Try to mixin a function[%s:%s] already mixin by anthor vm"), *Class->GetName(),
*Super->GetName());
}
return MaybeJSFunction;
}
const FString FunctionName = *FString::Printf(TEXT("%s%s"), *Super->GetName(), TEXT(MIXIN_METHOD_SUFFIX));
// "Failed to bind native" warning
Class->AddNativeFunction(*FunctionName, &UJSGeneratedFunction::execCallMixin);
UJSGeneratedFunction* Function = Cast<UJSGeneratedFunction>(
StaticDuplicateObject(Super, Class, *FunctionName, RF_AllFlags, UJSGeneratedFunction::StaticClass()));
Function->SetFlags(Function->GetFlags() | RF_Transient);
for (TFieldIterator<UFunction> It(Class, EFieldIteratorFlags::IncludeSuper, EFieldIteratorFlags::ExcludeDeprecated,
EFieldIteratorFlags::IncludeInterfaces);
It; ++It)
{
if (*It == Function)
{
return Function;
}
}
Function->SetSuperStruct(Super->GetSuperStruct());
Function->DynamicInvoker = DynamicInvoker;
Function->FunctionTranslator = std::make_unique<PUERTS_NAMESPACE::FFunctionTranslator>(Super, false);
Function->TakeJsObjectRef = TakeJsObjectRef;
Function->Next = Class->Children;
Class->Children = Function;
Class->AddFunctionToFunctionMap(Function, Function->GetFName());
Function->FunctionFlags |= FUNC_Native; //让UE不走解析
Function->SetNativeFunc(&UJSGeneratedFunction::execCallMixin);
Function->Bind();
Function->StaticLink(true);
Function->ClearInternalFlags(EInternalObjectFlags::Native);
if (Class->HasAnyInternalFlags(EInternalObjectFlags::RootSet))
{
Function->AddToRoot();
}
Function->Original = Super;
Function->OriginalFunc = Super->GetNativeFunc();
Function->OriginalFunctionFlags = Super->FunctionFlags;
Super->FunctionFlags |= FUNC_Native; //让UE不走解析
Super->SetNativeFunc(&UJSGeneratedFunction::execCallMixin);
Class->AddNativeFunction(*Super->GetName(), &UJSGeneratedFunction::execCallMixin);
UJSGeneratedFunction::SetJSGeneratedFunctionToScript(Super, Function);
return Function;
}
void UJSGeneratedClass::Restore(UClass* Class)
{
FString OrphanedClassString = FString::Printf(TEXT("ORPHANED_DATA_ONLY_%s"), *Class->GetName());
FName OrphanedClassName =
MakeUniqueObjectName(GetTransientPackage(), UBlueprintGeneratedClass::StaticClass(), FName(*OrphanedClassString));
UClass* OrphanedClass = NewObject<UBlueprintGeneratedClass>(GetTransientPackage(), OrphanedClassName, RF_Public | RF_Transient);
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION > 0
OrphanedClass->CppClassStaticFunctions = Class->CppClassStaticFunctions;
#else
OrphanedClass->ClassAddReferencedObjects = Class->AddReferencedObjects;
#endif
OrphanedClass->ClassFlags |= CLASS_CompiledFromBlueprint;
#if ENGINE_MAJOR_VERSION < 5 || WITH_EDITOR
OrphanedClass->ClassGeneratedBy = Class->ClassGeneratedBy;
#endif
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION > 2
UField** PP = nullptr;
UField* ChildrenPtr = Class->Children.Get();
PP = &ChildrenPtr;
#else
auto PP = &Class->Children;
#endif
while (*PP)
{
if (auto JGF = Cast<UJSGeneratedFunction>(*PP)) // to delete
{
if (JGF->Original)
{
if (JGF->Script.Num() == 0)
{
JGF->Original->Script.Empty();
}
else
{
JGF->Original->Script = JGF->Script;
}
JGF->Original->SetNativeFunc(JGF->OriginalFunc);
Class->AddNativeFunction(*JGF->Original->GetName(), JGF->OriginalFunc);
JGF->Original->FunctionFlags = JGF->OriginalFunctionFlags;
}
JGF->JsFunction.Reset();
*PP = JGF->Next;
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION > 2
if (PP == &ChildrenPtr)
{
Class->Children = ChildrenPtr;
}
#endif
Class->RemoveFunctionFromFunctionMap(JGF);
if (JGF->IsRooted())
{
JGF->RemoveFromRoot();
}
JGF->Rename(nullptr, OrphanedClass, REN_DontCreateRedirectors | REN_DoNotDirty | REN_ForceNoResetLoaders);
FLinkerLoad::InvalidateExport(JGF);
}
else
{
PP = &(*PP)->Next;
}
}
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION > 2
PP = &ChildrenPtr;
#else
PP = &Class->Children;
#endif
while (*PP)
{
if (auto Function = Cast<UFunction>(*PP))
{
if (Function->GetName().StartsWith(TEXT(OLD_METHOD_PREFIX)))
{
Class->RemoveFunctionFromFunctionMap(Function);
Function->Rename(*Function->GetName().Mid(strlen(OLD_METHOD_PREFIX)), Class,
REN_DontCreateRedirectors | REN_DoNotDirty | REN_ForceNoResetLoaders);
Class->AddFunctionToFunctionMap(Function, Function->GetFName());
}
}
PP = &(*PP)->Next;
}
Class->ClearFunctionMapsCaches();
for (TObjectIterator<UClass> It; It; ++It)
{
if (Class != *It && It->IsChildOf(Class) && !It->HasAnyClassFlags(CLASS_Abstract) &&
!It->GetName().StartsWith(TEXT("REINST_")))
{
It->ClearFunctionMapsCaches();
}
}
}
void UJSGeneratedClass::InitPropertiesFromCustomList(uint8* DataPtr, const uint8* DefaultDataPtr)
{
if (const FCustomPropertyListNode* CustomPropertyList = GetCustomPropertyListForPostConstruction())
{
UBlueprintGeneratedClass::InitPropertiesFromCustomList(CustomPropertyList, this, DataPtr, DefaultDataPtr);
}
}
void UJSGeneratedClass::Release()
{
for (TFieldIterator<UFunction> It(this, EFieldIteratorFlags::IncludeSuper, EFieldIteratorFlags::ExcludeDeprecated,
EFieldIteratorFlags::IncludeInterfaces);
It; ++It)
{
if (auto Function = Cast<UJSGeneratedFunction>(*It))
{
// UE_LOG(LogTemp, Warning, TEXT("release: %s"), *Function->GetName());
Function->JsFunction.Reset();
}
}
Constructor.Reset();
Prototype.Reset();
}
@@ -0,0 +1,63 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include "NamespaceDef.h"
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#pragma warning(push, 0)
#include "libplatform/libplatform.h"
#include "v8.h"
#pragma warning(pop)
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
#include "DynamicInvoker.h"
#include "CoreMinimal.h"
#include "Engine/BlueprintGeneratedClass.h"
#include "JSGeneratedClass.generated.h"
/**
*
*/
UCLASS()
class UJSGeneratedClass : public UBlueprintGeneratedClass
{
GENERATED_BODY()
public:
static UClass* Create(const FString& Name, UClass* Parent,
TSharedPtr<PUERTS_NAMESPACE::IDynamicInvoker, ESPMode::ThreadSafe> DynamicInvoker, v8::Isolate* Isolate,
v8::Local<v8::Function> Constructor, v8::Local<v8::Object> Prototype);
static void Override(v8::Isolate* Isolate, UClass* Class, UFunction* Super, v8::Local<v8::Function> JSImpl,
TSharedPtr<PUERTS_NAMESPACE::IDynamicInvoker, ESPMode::ThreadSafe> DynamicInvoker, bool IsNative);
static UFunction* Mixin(v8::Isolate* Isolate, UClass* Class, UFunction* Super,
TSharedPtr<PUERTS_NAMESPACE::IDynamicInvoker, ESPMode::ThreadSafe> DynamicInvoker, bool TakeJsObjectRef, bool Warning);
static void Restore(UClass* Class);
void InitPropertiesFromCustomList(uint8* DataPtr, const uint8* DefaultDataPtr) override;
void Release();
static void StaticConstructor(const FObjectInitializer& ObjectInitializer);
public:
v8::UniquePersistent<v8::Function> Constructor;
v8::UniquePersistent<v8::Object> Prototype;
TWeakPtr<PUERTS_NAMESPACE::IDynamicInvoker, ESPMode::ThreadSafe> DynamicInvoker;
#ifdef THREAD_SAFE
v8::Isolate* Isolate;
#endif
};
@@ -0,0 +1,50 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "JSGeneratedFunction.h"
DEFINE_FUNCTION(UJSGeneratedFunction::execCallJS)
{
#if !defined(ENGINE_INDEPENDENT_JSENV)
UJSGeneratedFunction* Func = Cast<UJSGeneratedFunction>(Stack.CurrentNativeFunction ? Stack.CurrentNativeFunction : Stack.Node);
check(Func);
// UE_LOG(LogTemp, Warning, TEXT("overrided function called, %s(%p)"), *Func->GetName(), Func);
if (Func)
{
auto PinedDynamicInvoker = Func->DynamicInvoker.Pin();
if (PinedDynamicInvoker)
{
PinedDynamicInvoker->InvokeJsMethod(Context, Func, Stack, RESULT_PARAM);
}
}
#endif
}
DEFINE_FUNCTION(UJSGeneratedFunction::execCallMixin)
{
#if !defined(ENGINE_INDEPENDENT_JSENV)
UFunction* Func = Stack.CurrentNativeFunction ? Stack.CurrentNativeFunction : Stack.Node;
UJSGeneratedFunction* JsFunc = Cast<UJSGeneratedFunction>(Func);
if (!JsFunc)
{
JsFunc = GetJSGeneratedFunctionFromScript(Func);
}
check(JsFunc);
// UE_LOG(LogTemp, Warning, TEXT("overrided function called, %s(%p)"), *Func->GetName(), Func);
if (JsFunc)
{
auto PinedDynamicInvoker = JsFunc->DynamicInvoker.Pin();
if (PinedDynamicInvoker)
{
PinedDynamicInvoker->InvokeMixinMethod(Context, JsFunc, Stack, RESULT_PARAM);
}
}
#endif
}
@@ -0,0 +1,80 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include <memory>
#include "NamespaceDef.h"
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#pragma warning(push, 0)
#include "libplatform/libplatform.h"
#include "v8.h"
#pragma warning(pop)
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
#include "DynamicInvoker.h"
#include "FunctionTranslator.h"
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "JSGeneratedFunction.generated.h"
/**
*
*/
UCLASS()
class UJSGeneratedFunction : public UFunction
{
GENERATED_BODY()
public:
DECLARE_FUNCTION(execCallJS);
DECLARE_FUNCTION(execCallMixin);
v8::UniquePersistent<v8::Function> JsFunction;
TWeakPtr<PUERTS_NAMESPACE::IDynamicInvoker, ESPMode::ThreadSafe> DynamicInvoker;
std::unique_ptr<PUERTS_NAMESPACE::FFunctionTranslator> FunctionTranslator;
bool TakeJsObjectRef;
UFunction* Original = nullptr;
FNativeFuncPtr OriginalFunc = nullptr;
EFunctionFlags OriginalFunctionFlags;
static constexpr uint8 GEN_FUNC_MAGIC = 107;
FORCEINLINE static void SetJSGeneratedFunctionToScript(UFunction* InFunc, UJSGeneratedFunction* JsGenFunc)
{
JsGenFunc->Script = InFunc->Script;
InFunc->Script.Empty();
InFunc->Script.AddUninitialized(3 + sizeof(int64));
uint8* Code = InFunc->Script.GetData();
*(Code++) = EX_ByteConst;
*(Code++) = GEN_FUNC_MAGIC;
*(Code++) = EX_Int64Const;
FPlatformMemory::WriteUnaligned<UJSGeneratedFunction*>(Code, JsGenFunc);
}
FORCEINLINE static UJSGeneratedFunction* GetJSGeneratedFunctionFromScript(UFunction* InFunc)
{
const uint8* Code = InFunc->Script.GetData();
if (Code && InFunc->Script.Num() >= (3 + sizeof(int64)) && EX_ByteConst == Code[0] && GEN_FUNC_MAGIC == Code[1] &&
EX_Int64Const == Code[2])
{
return FPlatformMemory::ReadUnaligned<UJSGeneratedFunction*>(&Code[3]);
}
return nullptr;
}
};
@@ -0,0 +1,35 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "JSLogger.h"
DEFINE_LOG_CATEGORY(Puerts);
namespace PUERTS_NAMESPACE
{
void FDefaultLogger::Log(const FString& Message) const
{
UE_LOG(Puerts, Log, TEXT("(0x%p) %s"), this, *Message);
}
void FDefaultLogger::Info(const FString& Message) const
{
UE_LOG(Puerts, Display, TEXT("(0x%p) %s"), this, *Message);
}
void FDefaultLogger::Warn(const FString& Message) const
{
UE_LOG(Puerts, Warning, TEXT("(0x%p) %s"), this, *Message);
}
void FDefaultLogger::Error(const FString& Message) const
{
UE_LOG(Puerts, Error, TEXT("(0x%p) %s"), this, *Message);
}
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,51 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "JSWidgetGeneratedClass.h"
#include "JSGeneratedFunction.h"
void UJSWidgetGeneratedClass::StaticConstructor(const FObjectInitializer& ObjectInitializer)
{
auto Class = static_cast<UJSWidgetGeneratedClass*>(ObjectInitializer.GetClass());
auto Object = ObjectInitializer.GetObj();
Class->GetSuperClass()->ClassConstructor(ObjectInitializer);
#ifdef THREAD_SAFE
v8::Locker Locker(Class->Isolate);
#endif
auto PinedDynamicInvoker = Class->DynamicInvoker.Pin();
if (PinedDynamicInvoker)
{
PinedDynamicInvoker->JsConstruct(Class, Object, Class->Constructor, Class->Prototype);
}
}
void UJSWidgetGeneratedClass::InitPropertiesFromCustomList(uint8* DataPtr, const uint8* DefaultDataPtr)
{
if (const FCustomPropertyListNode* CustomPropertyList = GetCustomPropertyListForPostConstruction())
{
UBlueprintGeneratedClass::InitPropertiesFromCustomList(CustomPropertyList, this, DataPtr, DefaultDataPtr);
}
}
void UJSWidgetGeneratedClass::Release()
{
for (TFieldIterator<UFunction> It(this, EFieldIteratorFlags::IncludeSuper, EFieldIteratorFlags::ExcludeDeprecated,
EFieldIteratorFlags::IncludeInterfaces);
It; ++It)
{
if (auto Function = Cast<UJSGeneratedFunction>(*It))
{
// UE_LOG(LogTemp, Warning, TEXT("release: %s"), *Function->GetName());
Function->JsFunction.Reset();
}
}
Constructor.Reset();
Prototype.Reset();
}
@@ -0,0 +1,51 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include "NamespaceDef.h"
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#pragma warning(push, 0)
#include "libplatform/libplatform.h"
#include "v8.h"
#pragma warning(pop)
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
#include "DynamicInvoker.h"
#include "CoreMinimal.h"
#include "Blueprint/WidgetBlueprintGeneratedClass.h"
#include "JSWidgetGeneratedClass.generated.h"
/**
*
*/
UCLASS()
class UJSWidgetGeneratedClass : public UWidgetBlueprintGeneratedClass
{
GENERATED_BODY()
public:
void InitPropertiesFromCustomList(uint8* DataPtr, const uint8* DefaultDataPtr) override;
static void StaticConstructor(const FObjectInitializer& ObjectInitializer);
void Release();
public:
v8::UniquePersistent<v8::Function> Constructor;
v8::UniquePersistent<v8::Object> Prototype;
TWeakPtr<PUERTS_NAMESPACE::IDynamicInvoker, ESPMode::ThreadSafe> DynamicInvoker;
#ifdef THREAD_SAFE
v8::Isolate* Isolate;
#endif
};
@@ -0,0 +1,94 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "JsEnv.h"
#include "JsEnvImpl.h"
namespace PUERTS_NAMESPACE
{
FJsEnv::FJsEnv(const FString& ScriptRoot)
{
GameScript = std::make_unique<FJsEnvImpl>(ScriptRoot);
}
FJsEnv::FJsEnv(std::shared_ptr<IJSModuleLoader> InModuleLoader, std::shared_ptr<ILogger> InLogger, int InDebugPort,
std::function<void(const FString&)> InOnSourceLoadedCallback, const FString InFlags, void* InExternalRuntime,
void* InExternalContext)
{
GameScript = std::make_unique<FJsEnvImpl>(
std::move(InModuleLoader), InLogger, InDebugPort, InOnSourceLoadedCallback, InFlags, InExternalRuntime, InExternalContext);
}
void FJsEnv::Start(const FString& ModuleName, const TArray<TPair<FString, UObject*>>& Arguments)
{
GameScript->Start(ModuleName, Arguments);
}
bool FJsEnv::IdleNotificationDeadline(double DeadlineInSeconds)
{
return GameScript->IdleNotificationDeadline(DeadlineInSeconds);
}
void FJsEnv::LowMemoryNotification()
{
GameScript->LowMemoryNotification();
}
void FJsEnv::RequestMinorGarbageCollectionForTesting()
{
GameScript->RequestMinorGarbageCollectionForTesting();
}
void FJsEnv::RequestFullGarbageCollectionForTesting()
{
GameScript->RequestFullGarbageCollectionForTesting();
}
void FJsEnv::WaitDebugger(double timeout)
{
GameScript->WaitDebugger(timeout);
}
#if !defined(ENGINE_INDEPENDENT_JSENV)
void FJsEnv::TryBindJs(const class UObjectBase* InObject)
{
GameScript->TryBindJs(InObject);
}
void FJsEnv::RebindJs()
{
GameScript->RebindJs();
}
#endif
FString FJsEnv::CurrentStackTrace()
{
return GameScript->CurrentStackTrace();
}
void FJsEnv::InitExtensionMethodsMap()
{
GameScript->InitExtensionMethodsMap();
}
void FJsEnv::ReloadModule(FName ModuleName, const FString& JsSource)
{
GameScript->ReloadModule(ModuleName, JsSource);
}
void FJsEnv::ReloadSource(const FString& Path, const std::string& JsSource)
{
GameScript->ReloadSource(Path, JsSource);
}
void FJsEnv::OnSourceLoaded(std::function<void(const FString&)> Callback)
{
GameScript->OnSourceLoaded(Callback);
}
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,186 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#if !defined(ENGINE_INDEPENDENT_JSENV)
#include "JsEnvGroup.h"
#include "JsEnvImpl.h"
#include "TsDynamicInvoker.h"
#include "DynamicInvoker.h"
#include "PuertsNamespaceDef.h"
namespace PUERTS_NAMESPACE
{
class FGroupDynamicInvoker : public ITsDynamicInvoker, public IDynamicInvoker
{
public:
FGroupDynamicInvoker(std::vector<FJsEnvImpl*> InJsEnvs) : JsEnvs(InJsEnvs)
{
}
FORCEINLINE int GetSelectIndex(UObject* Object)
{
int Size = JsEnvs.size();
int Index = Selector ? Selector(Object, Size) : 0;
return (Index > 0 && Index < Size) ? Index : 0;
}
void TsConstruct(UTypeScriptGeneratedClass* Class, UObject* Object) override
{
// 对于cdo,应该在所有的虚拟机中调用construct,因为cdo并没有明确的jsenv
// 不过不大确定cdo的这样判断够不够
// JsEnvs[GetSelectIndex(Object)]->TsConstruct(Class, Object);
if (Object->HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject | RF_WasLoaded))
{
for (int i = 0; i < JsEnvs.size(); i++)
{
JsEnvs[i]->TsConstruct(Class, Object);
}
}
else
{
JsEnvs[GetSelectIndex(Object)]->TsConstruct(Class, Object);
}
}
void InvokeTsMethod(UObject* ContextObject, UFunction* Function, FFrame& Stack, void* RESULT_PARAM) override
{
JsEnvs[GetSelectIndex(ContextObject)]->InvokeTsMethod(ContextObject, Function, Stack, RESULT_PARAM);
}
void NotifyReBind(UTypeScriptGeneratedClass* Class) override
{
for (int i = 0; i < JsEnvs.size(); i++)
{
JsEnvs[i]->NotifyReBind(Class);
}
}
virtual void InvokeDelegateCallback(UDynamicDelegateProxy* Proxy, void* Params) override
{
ensureMsgf(false, TEXT("InvokeDelegateCallback in GroupDynamicInvoker"));
}
#if !defined(ENGINE_INDEPENDENT_JSENV)
virtual void JsConstruct(UClass* Class, UObject* Object, const v8::UniquePersistent<v8::Function>& Constructor,
const v8::UniquePersistent<v8::Object>& Prototype) override
{
ensureMsgf(false, TEXT("JsConstruct in GroupDynamicInvoker"));
}
virtual void InvokeJsMethod(UObject* ContextObject, UJSGeneratedFunction* Function, FFrame& Stack, void* RESULT_PARAM) override
{
ensureMsgf(false, TEXT("InvokeJsMethod in GroupDynamicInvoker"));
}
virtual void InvokeMixinMethod(
UObject* ContextObject, UJSGeneratedFunction* Function, FFrame& Stack, void* RESULT_PARAM) override
{
JsEnvs[GetSelectIndex(ContextObject)]->InvokeMixinMethod(ContextObject, Function, Stack, RESULT_PARAM);
}
#endif
std::vector<FJsEnvImpl*> JsEnvs;
std::function<int(UObject*, int)> Selector;
virtual ~FGroupDynamicInvoker()
{
}
};
FJsEnvGroup::FJsEnvGroup(int Size, const FString& ScriptRoot)
{
check(Size > 1);
for (int i = 0; i < Size; i++)
{
JsEnvList.push_back(std::make_shared<FJsEnvImpl>(ScriptRoot));
}
Init();
}
FJsEnvGroup::FJsEnvGroup(int Size, std::shared_ptr<IJSModuleLoader> InModuleLoader, std::shared_ptr<ILogger> InLogger,
int InDebugStartPort, std::function<void(const FString&)> InOnSourceLoadedCallback, const FString InFlags,
void* InExternalRuntime, void* InExternalContext)
{
check(Size > 1);
std::shared_ptr<IJSModuleLoader> SharedModuleLoader = std::move(InModuleLoader);
for (int i = 0; i < Size; i++)
{
JsEnvList.push_back(std::make_shared<FJsEnvImpl>(SharedModuleLoader, InLogger, InDebugStartPort + i,
InOnSourceLoadedCallback, InFlags, InExternalRuntime, InExternalContext));
}
Init();
}
void FJsEnvGroup::Init()
{
std::vector<FJsEnvImpl*> JsEnvs;
for (int i = 0; i < JsEnvList.size(); i++)
{
JsEnvs.push_back(static_cast<FJsEnvImpl*>(JsEnvList[i].get()));
}
auto GroupDynamicInvoker = MakeShared<FGroupDynamicInvoker, ESPMode::ThreadSafe>(JsEnvs);
for (int i = 0; i < JsEnvs.size(); i++)
{
JsEnvs[i]->TsDynamicInvoker = GroupDynamicInvoker;
JsEnvs[i]->MixinInvoker = GroupDynamicInvoker;
}
}
FJsEnvGroup::~FJsEnvGroup()
{
JsEnvList.clear();
}
void FJsEnvGroup::TryBindJs(const class UObjectBase* InObject)
{
for (int i = 0; i < JsEnvList.size(); i++)
{
JsEnvList[i]->TryBindJs(InObject);
}
}
void FJsEnvGroup::RebindJs()
{
for (int i = 0; i < JsEnvList.size(); i++)
{
JsEnvList[i]->RebindJs();
}
}
void FJsEnvGroup::InitExtensionMethodsMap()
{
for (int i = 0; i < JsEnvList.size(); i++)
{
JsEnvList[i]->InitExtensionMethodsMap();
}
}
void FJsEnvGroup::ReloadModule(FName ModuleName, const FString& JsSource)
{
for (int i = 0; i < JsEnvList.size(); i++)
{
JsEnvList[i]->ReloadModule(ModuleName, JsSource);
}
}
std::shared_ptr<IJsEnv> FJsEnvGroup::Get(int Index)
{
return JsEnvList[Index];
}
void FJsEnvGroup::SetJsEnvSelector(std::function<int(UObject*, int)> InSelector)
{
auto DynamicInvoker = static_cast<FJsEnvImpl*>(JsEnvList[0].get())->TsDynamicInvoker;
if (DynamicInvoker.IsValid())
{
static_cast<FGroupDynamicInvoker*>(DynamicInvoker.Get())->Selector = InSelector;
}
}
} // namespace PUERTS_NAMESPACE
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,767 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include "JsEnv.h"
#include "DynamicDelegateProxy.h"
#include "StructWrapper.h"
#include "CppObjectMapper.h"
#include "V8Utils.h"
#include "ObjectMapper.h"
#include "JSLogger.h"
#include "ObjectRetainer.h"
#if !defined(ENGINE_INDEPENDENT_JSENV)
#include "TypeScriptGeneratedClass.h"
#endif
#include "UECompatible.h"
#include "ContainerMeta.h"
#include "ObjectCacheNode.h"
#include <unordered_map>
#if ENGINE_MINOR_VERSION >= 25 || ENGINE_MAJOR_VERSION > 4
#include "UObject/WeakFieldPtr.h"
#endif
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#pragma warning(push, 0)
#include "libplatform/libplatform.h"
#include "v8.h"
#pragma warning(pop)
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
#include "NamespaceDef.h"
#include "V8InspectorImpl.h"
#if defined(WITH_NODEJS)
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#pragma warning(push, 0)
#include "node.h"
#include "uv.h"
#pragma warning(pop)
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
#endif
#if USE_WASM3
#include "WasmRuntime.h"
#include "PuertsWasm/WasmJsFunctionParams.h"
#endif
#if V8_MAJOR_VERSION < 8 || defined(WITH_QUICKJS) || defined(WITH_NODEJS) || (WITH_EDITOR && !defined(FORCE_USE_STATIC_V8_LIB))
#define WITH_BACKING_STORE_AUTO_FREE 0
#else
#define WITH_BACKING_STORE_AUTO_FREE 1
#endif
namespace PUERTS_NAMESPACE
{
class JSError
{
public:
FString Message;
JSError()
{
}
explicit JSError(const FString& m) : Message(m)
{
}
};
class FJsEnvImpl : public IJsEnv, IObjectMapper, public FUObjectArray::FUObjectDeleteListener
{
public:
explicit FJsEnvImpl(const FString& ScriptRoot);
FJsEnvImpl(std::shared_ptr<IJSModuleLoader> InModuleLoader, std::shared_ptr<ILogger> InLogger, int InPort,
std::function<void(const FString&)> InOnSourceLoadedCallback, const FString InFlags, void* InExternalRuntime,
void* InExternalContext);
virtual ~FJsEnvImpl() override;
virtual void Start(const FString& ModuleNameOrScript, const TArray<TPair<FString, UObject*>>& Arguments) override;
virtual bool IdleNotificationDeadline(double DeadlineInSeconds) override;
virtual void LowMemoryNotification() override;
virtual void RequestMinorGarbageCollectionForTesting() override;
virtual void RequestFullGarbageCollectionForTesting() override;
virtual void WaitDebugger(double timeout) override
{
#ifdef THREAD_SAFE
v8::Locker Locker(MainIsolate);
#endif
const auto startTime = FDateTime::Now();
while (Inspector && !Inspector->Tick())
{
if (timeout > 0)
{
auto now = FDateTime::Now();
if ((now - startTime).GetTotalSeconds() >= timeout)
{
break;
}
}
}
}
#if !defined(ENGINE_INDEPENDENT_JSENV)
virtual void TryBindJs(const class UObjectBase* InObject) override;
virtual void RebindJs() override;
#endif
virtual FString CurrentStackTrace() override;
virtual void InitExtensionMethodsMap() override;
void JsHotReload(FName ModuleName, const FString& JsSource);
virtual void ReloadModule(FName ModuleName, const FString& JsSource) override;
virtual void ReloadSource(const FString& Path, const std::string& JsSource) override;
std::function<void(const FString&)> OnSourceLoadedCallback;
virtual void OnSourceLoaded(std::function<void(const FString&)> Callback) override;
public:
bool IsTypeScriptGeneratedClass(UClass* Class);
void SetJsTakeRef(UObject* UEObject, FClassWrapper* ClassWrapper);
virtual void Bind(FClassWrapper* ClassWrapper, UObject* UEObject, v8::Local<v8::Object> JSObject) override;
virtual void UnBind(UClass* Class, UObject* UEObject) override;
virtual void UnBind(UClass* Class, UObject* UEObject, bool ResetPointer);
v8::Local<v8::Value> FindOrAdd(
v8::Isolate* InIsolate, v8::Local<v8::Context>& Context, UClass* Class, UObject* UEObject, bool SkipTypeScriptInitial);
virtual v8::Local<v8::Value> FindOrAdd(
v8::Isolate* InIsolate, v8::Local<v8::Context>& Context, UClass* Class, UObject* UEObject) override;
virtual void BindStruct(
FScriptStructWrapper* ScriptStructWrapper, void* Ptr, v8::Local<v8::Object> JSObject, bool PassByPointer) override;
virtual void UnBindStruct(FScriptStructWrapper* ScriptStructWrapper, void* Ptr) override;
virtual void UnBindCppObject(v8::Isolate* Isolate, JSClassDefinition* ClassDefinition, void* Ptr) override;
virtual v8::Local<v8::Value> FindOrAddStruct(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, UScriptStruct* ScriptStruct, void* Ptr, bool PassByPointer) override;
virtual void BindCppObject(v8::Isolate* InIsolate, JSClassDefinition* ClassDefinition, void* Ptr,
v8::Local<v8::Object> JSObject, bool PassByPointer) override;
virtual void* GetPrivateData(v8::Local<v8::Context> Context, v8::Local<v8::Object> JSObject) override;
virtual void SetPrivateData(v8::Local<v8::Context> Context, v8::Local<v8::Object> JSObject, void* Ptr) override;
virtual v8::MaybeLocal<v8::Function> LoadTypeById(v8::Local<v8::Context> Context, const void* TypeId) override;
virtual v8::Local<v8::Value> FindOrAddCppObject(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const void* TypeId, void* Ptr, bool PassByPointer) override;
virtual void Merge(
v8::Isolate* Isolate, v8::Local<v8::Context> Context, v8::Local<v8::Object> Src, UStruct* DesType, void* Des) override;
enum ContainerType
{
EArray,
EMap,
ESet
};
void BindContainer(void* Ptr, v8::Local<v8::Object> JSObject, void (*Callback)(const v8::WeakCallbackInfo<void>& data),
bool PassByPointer, ContainerType Type);
virtual void UnBindContainer(void* Ptr) override;
virtual v8::Local<v8::Value> FindOrAddContainer(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, PropertyMacro* Property,
FScriptArray* Ptr, bool PassByPointer) override;
virtual v8::Local<v8::Value> FindOrAddContainer(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, PropertyMacro* Property,
FScriptSet* Ptr, bool PassByPointer) override;
virtual v8::Local<v8::Value> FindOrAddContainer(v8::Isolate* Isolate, v8::Local<v8::Context>& Context,
PropertyMacro* KeyProperty, PropertyMacro* ValueProperty, FScriptMap* Ptr, bool PassByPointer) override;
virtual v8::Local<v8::Value> FindOrAddDelegate(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, UObject* Owner,
PropertyMacro* Property, void* DelegatePtr, bool PassByPointer) override;
virtual bool AddToDelegate(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, void* DelegatePtr, v8::Local<v8::Function> JsFunction) override;
virtual PropertyMacro* FindDelegateProperty(void* DelegatePtr) override;
virtual FScriptDelegate NewDelegate(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, UObject* Owner,
v8::Local<v8::Function> JsFunction, UFunction* SignatureFunction) override;
void ReleaseManualReleaseDelegate(const v8::FunctionCallbackInfo<v8::Value>& Info);
virtual bool RemoveFromDelegate(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, void* DelegatePtr, v8::Local<v8::Function> JsFunction) override;
virtual bool ClearDelegate(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, void* DelegatePtr) override;
virtual void ExecuteDelegate(v8::Isolate* Isolate, v8::Local<v8::Context>& Context,
const v8::FunctionCallbackInfo<v8::Value>& Info, void* DelegatePtr) override;
virtual bool IsInstanceOf(UStruct* Struct, v8::Local<v8::Object> JsObject) override;
virtual bool IsInstanceOfCppObject(v8::Isolate* Isolate, const void* TypeId, v8::Local<v8::Object> JsObject) override;
virtual std::weak_ptr<int> GetJsEnvLifeCycleTracker() override;
virtual v8::Local<v8::Value> AddSoftObjectPtr(v8::Isolate* Isolate, v8::Local<v8::Context> Context,
FSoftObjectPtr* SoftObjectPtr, UClass* Class, bool IsSoftClass) override;
bool CheckDelegateProxies(float Tick);
virtual v8::Local<v8::Value> CreateArray(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, FPropertyTranslator* Property, void* ArrayPtr) override;
void InvokeDelegateCallback(UDynamicDelegateProxy* Proxy, void* Params);
#if !defined(ENGINE_INDEPENDENT_JSENV)
void JsConstruct(UClass* Class, UObject* Object, const v8::UniquePersistent<v8::Function>& Constructor,
const v8::UniquePersistent<v8::Object>& Prototype);
void TsConstruct(UTypeScriptGeneratedClass* Class, UObject* Object);
void InvokeJsMethod(UObject* ContextObject, UJSGeneratedFunction* Function, FFrame& Stack, void* RESULT_PARAM);
void InvokeMixinMethod(UObject* ContextObject, UJSGeneratedFunction* Function, FFrame& Stack, void* RESULT_PARAM);
void TypeScriptInitial(UClass* Class, UObject* Object, const bool TypeScriptClassFound = false);
void InvokeTsMethod(UObject* ContextObject, UFunction* Function, FFrame& Stack, void* RESULT_PARAM);
void NotifyReBind(UTypeScriptGeneratedClass* Class);
#endif
v8::UniquePersistent<v8::Function> JsPromiseRejectCallback;
V8_INLINE static FJsEnvImpl* Get(v8::Isolate* Isolate)
{
return static_cast<FJsEnvImpl*>(FV8Utils::IsolateData<IObjectMapper>(Isolate));
}
public:
#if ENGINE_MINOR_VERSION > 22 || ENGINE_MAJOR_VERSION > 4
virtual void OnUObjectArrayShutdown() override
{
GUObjectArray.RemoveUObjectDeleteListener(static_cast<FUObjectArray::FUObjectDeleteListener*>(this));
}
#endif
virtual void NotifyUObjectDeleted(const class UObjectBase* Object, int32 Index) override;
void TryReleaseType(UStruct* Struct);
private:
bool LoadFile(const FString& RequiringDir, const FString& ModuleName, FString& OutPath, FString& OutDebugPath,
TArray<uint8>& Data, FString& ErrInfo);
void ExecuteModule(const FString& ModuleName);
void EvalScript(const v8::FunctionCallbackInfo<v8::Value>& Info);
void Log(const v8::FunctionCallbackInfo<v8::Value>& Info);
void SearchModule(const v8::FunctionCallbackInfo<v8::Value>& Info);
void LoadModule(const v8::FunctionCallbackInfo<v8::Value>& Info);
v8::Local<v8::Value> UETypeToJsClass(v8::Isolate* Isolate, v8::Local<v8::Context> Context, UField* Type);
void LoadUEType(const v8::FunctionCallbackInfo<v8::Value>& Info);
void LoadCppType(const v8::FunctionCallbackInfo<v8::Value>& Info);
void UEClassToJSClass(const v8::FunctionCallbackInfo<v8::Value>& Info);
void SetJsTakeRefInTs(const v8::FunctionCallbackInfo<v8::Value>& Info);
bool GetContainerTypeProperty(v8::Local<v8::Context> Context, v8::Local<v8::Value> Value, PropertyMacro** PropertyPtr);
void NewContainer(const v8::FunctionCallbackInfo<v8::Value>& Info);
std::shared_ptr<FStructWrapper> GetStructWrapper(UStruct* InStruct, bool& IsReuseTemplate);
struct FTemplateInfo
{
v8::UniquePersistent<v8::FunctionTemplate> Template;
std::shared_ptr<FStructWrapper> StructWrapper;
};
FTemplateInfo* GetTemplateInfoOfType(UStruct* Class, bool& Existed);
v8::Local<v8::Function> GetJsClass(UStruct* Class, v8::Local<v8::Context> Context);
FPropertyTranslator* GetContainerPropertyTranslator(PropertyMacro* Property);
void SetTimeout(const v8::FunctionCallbackInfo<v8::Value>& Info);
void SetFTickerDelegate(const v8::FunctionCallbackInfo<v8::Value>& Info, bool Continue);
bool TimerCallback(int DelegateHandleId, bool Continue);
void RemoveFTickerDelegateHandle(int HandleId);
void SetInterval(const v8::FunctionCallbackInfo<v8::Value>& Info);
void ClearInterval(const v8::FunctionCallbackInfo<v8::Value>& Info);
void MergeObject(const v8::FunctionCallbackInfo<v8::Value>& Info);
void NewObjectByClass(const v8::FunctionCallbackInfo<v8::Value>& Info);
void NewStructByScriptStruct(const v8::FunctionCallbackInfo<v8::Value>& Info);
#if !defined(ENGINE_INDEPENDENT_JSENV)
void MakeUClass(const v8::FunctionCallbackInfo<v8::Value>& Info);
TArray<TWeakObjectPtr<UClass>> MixinClasses;
void Mixin(const v8::FunctionCallbackInfo<v8::Value>& Info);
#endif
void FindModule(const v8::FunctionCallbackInfo<v8::Value>& Info);
void DumpStatisticsLog(const v8::FunctionCallbackInfo<v8::Value>& Info);
void SetInspectorCallback(const v8::FunctionCallbackInfo<v8::Value>& Info);
void DispatchProtocolMessage(const v8::FunctionCallbackInfo<v8::Value>& Info);
#ifndef WITH_QUICKJS
v8::MaybeLocal<v8::Module> FetchESModuleTree(v8::Local<v8::Context> Context, const FString& FileName);
v8::MaybeLocal<v8::Module> FetchCJSModuleAsESModule(v8::Local<v8::Context> Context, const FString& ModuleName);
struct FModuleInfo
{
v8::Global<v8::Module> Module;
TMap<FString, v8::Global<v8::Module>> ResolveCache;
v8::Global<v8::Value> CJSValue;
};
std::unordered_multimap<int, FModuleInfo*>::iterator FindModuleInfo(v8::Local<v8::Module> Module);
static v8::MaybeLocal<v8::Module> ResolveModuleCallback(v8::Local<v8::Context> Context, v8::Local<v8::String> Specifier,
#if V8_MAJOR_VERSION >= 9
v8::Local<v8::FixedArray> ImportAttributes, // not implement yet
#endif
v8::Local<v8::Module> Referrer);
#endif
struct ObjectMerger;
std::unique_ptr<ObjectMerger>& GetObjectMerger(UStruct* Struct);
struct ObjectMerger
{
std::map<std::string, std::unique_ptr<FPropertyTranslator>> Fields;
UStruct* Struct;
FJsEnvImpl* Parent;
ObjectMerger(FJsEnvImpl* InParent, UStruct* InStruct)
{
Parent = InParent;
Struct = InStruct;
for (TFieldIterator<PropertyMacro> It(Struct); It; ++It)
{
PropertyMacro* Property = *It;
TStringConversion<TStringConvert<TCHAR, ANSICHAR>> Name(*Property->GetName());
Fields[Name.Get()] = FPropertyTranslator::Create(Property);
}
}
void Merge(v8::Isolate* Isolate, v8::Local<v8::Context> Context, v8::Local<v8::Object> JsObject, void* Ptr)
{
if (auto Class = Cast<UClass>(Struct))
{
UObject* Object = reinterpret_cast<UObject*>(Ptr);
if (!Object->IsValidLowLevel() || UEObjectIsPendingKill(Object) || Object->GetClass() != Class ||
FV8Utils::GetPointer(JsObject))
{
return;
}
}
auto Keys = JsObject->GetOwnPropertyNames(Context).ToLocalChecked();
for (decltype(Keys->Length()) i = 0; i < Keys->Length(); ++i)
{
auto Key = Keys->Get(Context, i).ToLocalChecked();
auto Iter = Fields.find(*v8::String::Utf8Value(Isolate, Key));
if (Iter != Fields.end())
{
auto MaybeValue = JsObject->Get(Context, Key);
if (!MaybeValue.IsEmpty())
{
auto Value = MaybeValue.ToLocalChecked();
if (Value->IsObject())
{
auto JsObjectField = Value->ToObject(Context).ToLocalChecked();
if (!FV8Utils::GetPointerFast<void>(JsObjectField))
{
UStruct* FieldStruct = nullptr;
if (auto ObjectPropertyBase = CastFieldMacro<ObjectPropertyBaseMacro>(Iter->second->Property))
{
FieldStruct = ObjectPropertyBase->PropertyClass;
}
else if (auto StructProperty = CastFieldMacro<StructPropertyMacro>(Iter->second->Property))
{
FieldStruct = StructProperty->Struct;
}
if (FieldStruct)
{
Parent->GetObjectMerger(FieldStruct)
->Merge(Isolate, Context, JsObjectField,
Iter->second->Property->ContainerPtrToValuePtr<void>(Ptr));
}
continue;
}
}
if (!Value->IsUndefined())
Iter->second->JsToUEInContainer(Isolate, Context, Value, Ptr, true);
}
}
}
}
};
friend ObjectMerger;
#if USE_WASM3
std::shared_ptr<WasmEnv> PuertsWasmEnv;
//在执行module.instance的时候,如果有指定memory,那么这个module对应会创建一个runtime
TArray<std::shared_ptr<WasmRuntime>> PuertsWasmRuntimeList;
TArray<WasmNormalLinkInfo*> PuertsWasmCachedLinkFunctionList;
protected:
void Wasm_NewMemory(const v8::FunctionCallbackInfo<v8::Value>& Info);
void Wasm_MemoryGrowth(const v8::FunctionCallbackInfo<v8::Value>& Info);
void Wasm_MemoryBuffer(const v8::FunctionCallbackInfo<v8::Value>& Info);
void Wasm_TableGrowth(const v8::FunctionCallbackInfo<v8::Value>& Info);
void Wasm_TableSet(const v8::FunctionCallbackInfo<v8::Value>& Info);
void Wasm_TableLen(const v8::FunctionCallbackInfo<v8::Value>& Info);
void Wasm_Instance(const v8::FunctionCallbackInfo<v8::Value>& Info);
void Wasm_OverrideWebAssembly(const v8::FunctionCallbackInfo<v8::Value>& Info);
#endif
public:
#if !defined(ENGINE_INDEPENDENT_JSENV)
class TsDynamicInvokerImpl : public ITsDynamicInvoker
{
public:
TsDynamicInvokerImpl(FJsEnvImpl* InParent) : Parent(InParent)
{
}
virtual void TsConstruct(UTypeScriptGeneratedClass* Class, UObject* Object) override
{
if (Parent)
Parent->TsConstruct(Class, Object);
}
virtual void InvokeTsMethod(UObject* ContextObject, UFunction* Function, FFrame& Stack, void* RESULT_PARAM) override
{
if (Parent)
Parent->InvokeTsMethod(ContextObject, Function, Stack, RESULT_PARAM);
}
virtual void NotifyReBind(UTypeScriptGeneratedClass* Class) override
{
if (Parent)
Parent->NotifyReBind(Class);
}
FJsEnvImpl* Parent;
};
TSharedPtr<ITsDynamicInvoker, ESPMode::ThreadSafe> TsDynamicInvoker;
TSharedPtr<IDynamicInvoker, ESPMode::ThreadSafe> MixinInvoker;
#endif
private:
FObjectRetainer UserObjectRetainer;
FObjectRetainer SysObjectRetainer;
std::shared_ptr<IJSModuleLoader> ModuleLoader;
std::shared_ptr<ILogger> Logger;
bool Started;
private:
v8::Isolate::CreateParams CreateParams;
#if defined(WITH_NODEJS)
uv_loop_t NodeUVLoop;
std::unique_ptr<node::ArrayBufferAllocator> NodeArrayBufferAllocator;
node::IsolateData* NodeIsolateData;
node::Environment* NodeEnv;
uv_thread_t PollingThread;
uv_sem_t PollingSem;
uv_async_t DummyUVHandle;
bool PollingClosed = false;
FGraphEventRef LastJob;
#if PLATFORM_LINUX
int Epoll;
#endif
void StartPolling();
void UvRunOnce();
void PollEvents();
static void OnWatcherQueueChanged(uv_loop_t* loop);
void WakeupPollingThread();
void StopPolling();
#endif
v8::Isolate* MainIsolate;
v8::Global<v8::Context> DefaultContext;
v8::Global<v8::Function> Require;
v8::Global<v8::Function> GetESMMain;
v8::Global<v8::Function> ReloadJs;
#if !PUERTS_FORCE_CPP_UFUNCTION
v8::Global<v8::Function> MergePrototype;
#endif
v8::Global<v8::Function> RemoveListItem;
v8::Global<v8::Function> GenListApply;
#if defined(WITH_V8_BYTECODE)
v8::Global<v8::Function> GenEmptyCode;
#endif
TMap<UStruct*, FTemplateInfo> TypeToTemplateInfoMap;
TMap<FString, std::shared_ptr<FStructWrapper>> TypeReflectionMap;
TMap<UObject*, v8::UniquePersistent<v8::Value>> ObjectMap;
TMap<void*, FObjectCacheNode> StructCache;
struct ContainerCacheItem
{
v8::UniquePersistent<v8::Value> Container;
bool NeedRelease;
ContainerType Type;
};
TMap<void*, ContainerCacheItem> ContainerCache;
FCppObjectMapper CppObjectMapper;
v8::UniquePersistent<v8::FunctionTemplate> ArrayTemplate;
v8::UniquePersistent<v8::FunctionTemplate> SetTemplate;
v8::UniquePersistent<v8::FunctionTemplate> MapTemplate;
v8::UniquePersistent<v8::FunctionTemplate> FixSizeArrayTemplate;
struct ContainerPropertyInfo
{
#if ENGINE_MINOR_VERSION < 25 && ENGINE_MAJOR_VERSION < 5
TWeakObjectPtr<PropertyMacro> PropertyWeakPtr;
#else
TWeakFieldPtr<PropertyMacro> PropertyWeakPtr;
#endif
std::unique_ptr<FPropertyTranslator> PropertyTranslator;
};
std::map<PropertyMacro*, ContainerPropertyInfo> ContainerPropertyMap;
std::map<UFunction*, std::unique_ptr<FFunctionTranslator>> JsCallbackPrototypeMap;
std::map<UStruct*, std::unique_ptr<ObjectMerger>> ObjectMergers;
struct DelegateObjectInfo
{
v8::UniquePersistent<v8::Object> JSObject; // function to proxy save here
TWeakObjectPtr<UObject> Owner; //可用于自动清理
DelegatePropertyMacro* DelegateProperty;
MulticastDelegatePropertyMacro* MulticastDelegateProperty;
UFunction* SignatureFunction;
bool PassByPointer;
TWeakObjectPtr<UDynamicDelegateProxy> Proxy;
v8::UniquePersistent<v8::Array> JsCallbacks;
};
struct TsFunctionInfo
{
v8::UniquePersistent<v8::Function> JsFunction;
std::unique_ptr<FFunctionTranslator> FunctionTranslator;
};
class DynamicInvokerImpl : public IDynamicInvoker
{
public:
DynamicInvokerImpl(FJsEnvImpl* InParent) : Parent(InParent)
{
}
virtual void InvokeDelegateCallback(UDynamicDelegateProxy* Proxy, void* Params) override
{
if (Parent)
Parent->InvokeDelegateCallback(Proxy, Params);
}
#if !defined(ENGINE_INDEPENDENT_JSENV)
virtual void JsConstruct(UClass* Class, UObject* Object, const v8::UniquePersistent<v8::Function>& Constructor,
const v8::UniquePersistent<v8::Object>& Prototype) override
{
if (Parent)
Parent->JsConstruct(Class, Object, Constructor, Prototype);
}
virtual void InvokeJsMethod(
UObject* ContextObject, UJSGeneratedFunction* Function, FFrame& Stack, void* RESULT_PARAM) override
{
if (Parent)
Parent->InvokeJsMethod(ContextObject, Function, Stack, RESULT_PARAM);
}
virtual void InvokeMixinMethod(
UObject* ContextObject, UJSGeneratedFunction* Function, FFrame& Stack, void* RESULT_PARAM) override
{
if (Parent)
Parent->InvokeMixinMethod(ContextObject, Function, Stack, RESULT_PARAM);
}
#endif
FJsEnvImpl* Parent;
};
#if !defined(ENGINE_INDEPENDENT_JSENV)
struct FBindInfo
{
FName Name;
v8::UniquePersistent<v8::Function> Constructor;
v8::UniquePersistent<v8::Object> Prototype;
bool InjectNotFinished;
};
TMap<UTypeScriptGeneratedClass*, FBindInfo> BindInfoMap;
void FinishInjection(UClass* InClass);
void MakeSureInject(UTypeScriptGeneratedClass* Class, bool ForceReinject, bool RebindObject);
#endif
TSharedPtr<DynamicInvokerImpl, ESPMode::ThreadSafe> DynamicInvoker;
TSet<UClass*> GeneratedClasses;
v8::UniquePersistent<v8::FunctionTemplate> DelegateTemplate;
v8::UniquePersistent<v8::FunctionTemplate> MulticastDelegateTemplate;
v8::UniquePersistent<v8::FunctionTemplate> SoftObjectPtrTemplate;
std::map<void*, DelegateObjectInfo> DelegateMap;
TMap<UFunction*, TsFunctionInfo> TsFunctionMap;
TMap<UFunction*, v8::UniquePersistent<v8::Function>> MixinFunctionMap;
std::map<UStruct*, std::vector<UFunction*>> ExtensionMethodsMap;
bool ExtensionMethodsMapInited = false;
struct FTimerInfo
{
v8::Global<v8::Function> Callback;
FUETickDelegateHandle TickerHandle;
};
uint32_t TimerID = 0;
TMap<uint32_t, FTimerInfo> TimerInfos;
FUETickDelegateHandle DelegateProxiesCheckerHandler;
V8Inspector* Inspector;
V8InspectorChannel* InspectorChannel;
v8::Global<v8::Function> InspectorMessageHandler;
FContainerMeta ContainerMeta;
v8::Global<v8::Map> ManualReleaseCallbackMap;
std::vector<TWeakObjectPtr<UDynamicDelegateProxy>> ManualReleaseCallbackList;
TMap<UObject*, TArray<TWeakObjectPtr<UDynamicDelegateProxy>>> AutoReleaseCallbacksMap;
#ifndef WITH_QUICKJS
TMap<FString, v8::Global<v8::Module>> PathToModule;
std::unordered_multimap<int, FModuleInfo*> HashToModuleInfo;
#endif
#ifdef SINGLE_THREAD_VERIFY
uint32 BoundThreadId;
#endif
typedef void (FJsEnvImpl::*V8MethodCallback)(const v8::FunctionCallbackInfo<v8::Value>& Info);
template <V8MethodCallback callback>
struct MethodBindingHelper
{
static void Bind(v8::Isolate* Isolate, v8::Local<v8::Context> Context, v8::Local<v8::Object> Obj, const char* Key,
v8::Local<v8::External> This)
{
Obj->Set(Context, FV8Utils::ToV8String(Isolate, Key),
v8::FunctionTemplate::New(
Isolate,
[](const v8::FunctionCallbackInfo<v8::Value>& Info)
{
auto Self = static_cast<FJsEnvImpl*>((v8::Local<v8::External>::Cast(Info.Data()))->Value());
(Self->*callback)(Info);
},
This)
->GetFunction(Context)
.ToLocalChecked())
.Check();
}
};
#if defined(WITH_V8_BYTECODE)
uint32_t Expect_FlagHash = 0;
#if V8_MAJOR_VERSION >= 11
uint32_t Expect_ReadOnlySnapshotChecksum = 0;
#endif
#endif
};
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,273 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "JsEnvModule.h"
//#include "TGameJSCorePCH.h"
#include "HAL/MemoryBase.h"
#include "NamespaceDef.h"
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#if defined(WITH_NODEJS)
#pragma warning(push, 0)
#include "node.h"
#include "uv.h"
#pragma warning(pop)
#endif
#pragma warning(push, 0)
#include "v8.h"
#include "libplatform/libplatform.h"
#pragma warning(pop)
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
class FMallocWrapper final : public FMalloc
{
public:
FMalloc* InnerMalloc;
public:
FMallocWrapper(FMalloc* InMalloc)
{
InnerMalloc = InMalloc;
}
virtual void* Malloc(SIZE_T Size, uint32 Alignment) override
{
if (UNLIKELY(Size == 0))
{
Size = 1;
}
return InnerMalloc->Malloc(Size, Alignment);
}
#if ENGINE_MINOR_VERSION >= 25 || ENGINE_MAJOR_VERSION > 4
virtual void* TryMalloc(SIZE_T Size, uint32 Alignment) override
{
if (UNLIKELY(Size == 0))
{
Size = 1;
}
return InnerMalloc->TryMalloc(Size, Alignment);
}
#endif
virtual void* Realloc(void* Ptr, SIZE_T NewSize, uint32 Alignment) override
{
return InnerMalloc->Realloc(Ptr, NewSize, Alignment);
}
#if ENGINE_MINOR_VERSION >= 25 || ENGINE_MAJOR_VERSION > 4
virtual void* TryRealloc(void* Ptr, SIZE_T NewSize, uint32 Alignment) override
{
return InnerMalloc->TryRealloc(Ptr, NewSize, Alignment);
}
#endif
virtual void Free(void* Ptr) override
{
return InnerMalloc->Free(Ptr);
}
virtual bool GetAllocationSize(void* Original, SIZE_T& SizeOut) override
{
return InnerMalloc->GetAllocationSize(Original, SizeOut);
}
virtual bool IsInternallyThreadSafe() const override
{
return InnerMalloc->IsInternallyThreadSafe();
}
virtual bool ValidateHeap() override
{
return InnerMalloc->ValidateHeap();
}
virtual const TCHAR* GetDescriptiveName() override
{
return InnerMalloc->GetDescriptiveName();
}
virtual SIZE_T QuantizeSize(SIZE_T Count, uint32 Alignment) override
{
return InnerMalloc->QuantizeSize(Count, Alignment);
}
#if ENGINE_MINOR_VERSION > 21 || ENGINE_MAJOR_VERSION > 4
virtual void Trim(bool bTrimThreadCaches) override
{
InnerMalloc->Trim(bTrimThreadCaches);
}
#else
virtual void Trim() override
{
InnerMalloc->Trim();
}
#endif
virtual void SetupTLSCachesOnCurrentThread() override
{
InnerMalloc->SetupTLSCachesOnCurrentThread();
}
virtual void ClearAndDisableTLSCachesOnCurrentThread() override
{
InnerMalloc->ClearAndDisableTLSCachesOnCurrentThread();
}
virtual void InitializeStatsMetadata() override
{
InnerMalloc->InitializeStatsMetadata();
}
virtual bool Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) override
{
return InnerMalloc->Exec(InWorld, Cmd, Ar);
}
virtual void UpdateStats() override
{
InnerMalloc->UpdateStats();
}
virtual void GetAllocatorStats(FGenericMemoryStats& out_Stats) override
{
InnerMalloc->GetAllocatorStats(out_Stats);
}
virtual void DumpAllocatorStats(class FOutputDevice& Ar) override
{
InnerMalloc->DumpAllocatorStats(Ar);
}
};
DEFINE_LOG_CATEGORY_STATIC(JsEnvModule, Log, All);
class FJsEnvModule : public IJsEnvModule
{
/** IModuleInterface implementation */
void StartupModule() override;
void ShutdownModule() override;
FMallocWrapper* MallocWrapper = nullptr;
public:
void* GetV8Platform() override;
private:
#if defined(V8_HAS_WRAP_API_WITHOUT_STL)
v8::Platform* platform_;
#else
std::unique_ptr<v8::Platform> platform_;
#endif
};
IMPLEMENT_MODULE(FJsEnvModule, JsEnv)
void FJsEnvModule::StartupModule()
{
int* Dummy = new (std::nothrow) int[0];
if (!Dummy)
{
UE_LOG(JsEnvModule, Warning, TEXT("new (std::nothrow) int[0] return nullptr, try fix it!"));
MallocWrapper = new FMallocWrapper(GMalloc);
GMalloc = MallocWrapper;
}
delete[] Dummy;
// This code will execute after your module is loaded into memory (but after global variables are initialized, of course.)
#if defined(WITH_NODEJS)
platform_ = node::MultiIsolatePlatform::Create(4);
#else
#if defined(V8_HAS_WRAP_API_WITHOUT_STL)
#if defined(USING_SINGLE_THREAD_PLATFORM)
platform_ = v8::platform::NewSingleThreadedDefaultPlatform_Without_Stl();
#else
platform_ = v8::platform::NewDefaultPlatform_Without_Stl();
#endif
#else
#if defined(USING_SINGLE_THREAD_PLATFORM)
platform_ = v8::platform::NewSingleThreadedDefaultPlatform();
#else
platform_ = v8::platform::NewDefaultPlatform();
#endif
#endif
#endif
#if PLATFORM_IOS
v8::V8::SetFlagsFromString("--jitless --no-expose-wasm");
#endif
#ifdef WITH_V8_FAST_CALL
v8::V8::SetFlagsFromString("--turbo-fast-api-calls");
#endif
#if defined(USING_SINGLE_THREAD_PLATFORM)
v8::V8::SetFlagsFromString("--single-threaded");
#endif
#if defined(WITH_V8_BYTECODE)
v8::V8::SetFlagsFromString("--no-lazy --no-flush-bytecode --no-enable-lazy-source-positions");
#endif
// v8::V8::SetFlagsFromString("--expose-gc");
// v8::V8::SetFlagsFromString("--no-freeze-flags-after-init");
#if defined(V8_HAS_WRAP_API_WITHOUT_STL)
v8::V8::InitializePlatform(platform_);
#else
v8::V8::InitializePlatform(platform_.get());
#endif
v8::V8::Initialize();
#if defined(WITH_NODEJS)
int Argc = 1;
char* ArgvIn[1];
ArgvIn[0] = const_cast<char*>("puerts");
char** Argv = uv_setup_args(Argc, ArgvIn);
std::vector<std::string> Args(Argv, Argv + Argc);
std::vector<std::string> ExecArgs;
std::vector<std::string> Errors;
int ExitCode = node::InitializeNodeWithArgs(&Args, &ExecArgs, &Errors);
for (const std::string& error : Errors)
{
UE_LOG(LogTemp, Error, TEXT("Initialize Node: %s"), UTF8_TO_TCHAR(error.c_str()));
}
#endif
}
void FJsEnvModule::ShutdownModule()
{
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
// we call this function before unloading the module.
v8::V8::Dispose();
#if V8_MAJOR_VERSION > 9
v8::V8::DisposePlatform();
#else
v8::V8::ShutdownPlatform();
#endif
#if defined(V8_HAS_WRAP_API_WITHOUT_STL)
v8::platform::DeletePlatform_Without_Stl(platform_);
#endif
if (MallocWrapper && MallocWrapper == GMalloc)
{
GMalloc = MallocWrapper->InnerMalloc;
delete MallocWrapper;
MallocWrapper = nullptr;
UE_LOG(JsEnvModule, Warning, TEXT("GMalloc restored!"));
}
}
void* FJsEnvModule::GetV8Platform()
{
#if defined(V8_HAS_WRAP_API_WITHOUT_STL)
return reinterpret_cast<void*>(platform_);
#else
return reinterpret_cast<void*>(platform_.get());
#endif
}
@@ -0,0 +1,134 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include "NamespaceDef.h"
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#pragma warning(push, 0)
#include "v8.h"
#pragma warning(pop)
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
namespace PUERTS_NAMESPACE
{
class FObjectCacheNode
{
public:
V8_INLINE FObjectCacheNode(const void* TypeId_) : TypeId(TypeId_), UserData(nullptr), Next(nullptr), MustCallFinalize(false)
{
}
V8_INLINE FObjectCacheNode(const void* TypeId_, FObjectCacheNode* Next_)
: TypeId(TypeId_), UserData(nullptr), Next(Next_), MustCallFinalize(false)
{
}
V8_INLINE FObjectCacheNode(FObjectCacheNode&& other) noexcept
: TypeId(other.TypeId)
, UserData(other.UserData)
, Next(other.Next)
, Value(std::move(other.Value))
, MustCallFinalize(other.MustCallFinalize)
{
other.TypeId = nullptr;
other.UserData = nullptr;
other.Next = nullptr;
other.MustCallFinalize = false;
}
V8_INLINE FObjectCacheNode& operator=(FObjectCacheNode&& rhs) noexcept
{
TypeId = rhs.TypeId;
Next = rhs.Next;
Value = std::move(rhs.Value);
UserData = rhs.UserData;
MustCallFinalize = rhs.MustCallFinalize;
rhs.UserData = nullptr;
rhs.TypeId = nullptr;
rhs.Next = nullptr;
rhs.MustCallFinalize = false;
return *this;
}
~FObjectCacheNode()
{
if (Next)
delete Next;
}
V8_INLINE FObjectCacheNode* Find(const void* TypeId_)
{
if (TypeId_ == TypeId)
{
return this;
}
if (Next)
{
return Next->Find(TypeId_);
}
return nullptr;
}
FObjectCacheNode* Remove(const void* TypeId_, bool IsHead)
{
if (TypeId_ == TypeId)
{
if (IsHead)
{
if (Next)
{
auto PreNext = Next;
*this = std::move(*Next);
delete PreNext;
}
else
{
TypeId = nullptr;
Next = nullptr;
Value.Reset();
}
}
return this;
}
if (Next)
{
auto Removed = Next->Remove(TypeId_, false);
if (Removed && Removed == Next) // detach & delete by prev node
{
Next = Removed->Next;
Removed->Next = nullptr;
delete Removed;
}
return Removed;
}
return nullptr;
}
V8_INLINE FObjectCacheNode* Add(const void* TypeId_)
{
Next = new FObjectCacheNode(TypeId_, Next);
return Next;
}
const void* TypeId;
void* UserData;
FObjectCacheNode* Next;
v8::UniquePersistent<v8::Value> Value;
bool MustCallFinalize;
FObjectCacheNode(const FObjectCacheNode&) = delete;
void operator=(const FObjectCacheNode&) = delete;
};
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,120 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#if USING_IN_UNREAL_ENGINE
#include "CoreMinimal.h"
#include "PropertyTranslator.h"
#include "StructWrapper.h"
#endif
#include "JSClassRegister.h"
#include "NamespaceDef.h"
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#pragma warning(push, 0)
#include "v8.h"
#pragma warning(pop)
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
#include <memory>
namespace PUERTS_NAMESPACE
{
class ICppObjectMapper
{
public:
virtual void BindCppObject(v8::Isolate* Isolate, JSClassDefinition* ClassDefinition, void* Ptr, v8::Local<v8::Object> JSObject,
bool PassByPointer) = 0;
virtual void UnBindCppObject(v8::Isolate* Isolate, JSClassDefinition* ClassDefinition, void* Ptr) = 0;
virtual v8::Local<v8::Value> FindOrAddCppObject(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const void* TypeId, void* Ptr, bool PassByPointer) = 0;
virtual bool IsInstanceOfCppObject(v8::Isolate* Isolate, const void* TypeId, v8::Local<v8::Object> JsObject) = 0;
virtual void* GetPrivateData(v8::Local<v8::Context> Context, v8::Local<v8::Object> JSObject) = 0;
virtual void SetPrivateData(v8::Local<v8::Context> Context, v8::Local<v8::Object> JSObject, void* Ptr) = 0;
virtual v8::MaybeLocal<v8::Function> LoadTypeById(v8::Local<v8::Context> Context, const void* TypeId) = 0;
virtual std::weak_ptr<int> GetJsEnvLifeCycleTracker() = 0;
virtual ~ICppObjectMapper()
{
}
};
#if USING_IN_UNREAL_ENGINE
class IObjectMapper : public ICppObjectMapper
{
public:
virtual void Bind(FClassWrapper* ClassWrapper, UObject* UEObject, v8::Local<v8::Object> JSObject) = 0;
virtual void UnBind(UClass* Class, UObject* UEObject) = 0;
virtual v8::Local<v8::Value> FindOrAdd(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, UClass* Class, UObject* UEObject) = 0;
virtual void BindStruct(
FScriptStructWrapper* ScriptStructWrapper, void* Ptr, v8::Local<v8::Object> JSObject, bool PassByPointer) = 0;
virtual void UnBindStruct(FScriptStructWrapper* ScriptStructWrapper, void* Ptr) = 0;
// PassByPointer为false代表需要在js对象释放时,free相应的内存
// 相关信息见该issue:https://github.com/Tencent/puerts/issues/693
virtual v8::Local<v8::Value> FindOrAddStruct(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, UScriptStruct* ScriptStruct, void* Ptr, bool PassByPointer) = 0;
virtual void Merge(
v8::Isolate* Isolate, v8::Local<v8::Context> Context, v8::Local<v8::Object> Src, UStruct* DesType, void* Des) = 0;
virtual void UnBindContainer(void* Ptr) = 0;
virtual v8::Local<v8::Value> FindOrAddContainer(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, PropertyMacro* Property, FScriptArray* Ptr, bool PassByPointer) = 0;
virtual v8::Local<v8::Value> FindOrAddContainer(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, PropertyMacro* Property, FScriptSet* Ptr, bool PassByPointer) = 0;
virtual v8::Local<v8::Value> FindOrAddContainer(v8::Isolate* Isolate, v8::Local<v8::Context>& Context,
PropertyMacro* KeyProperty, PropertyMacro* ValueProperty, FScriptMap* Ptr, bool PassByPointer) = 0;
virtual v8::Local<v8::Value> FindOrAddDelegate(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, UObject* Owner,
PropertyMacro* Property, void* DelegatePtr, bool PassByPointer) = 0;
virtual bool AddToDelegate(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, void* DelegatePtr, v8::Local<v8::Function> JsFunction) = 0;
virtual PropertyMacro* FindDelegateProperty(void* DelegatePtr) = 0;
virtual FScriptDelegate NewDelegate(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, UObject* Owner,
v8::Local<v8::Function> JsFunction, UFunction* SignatureFunction) = 0;
virtual bool RemoveFromDelegate(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, void* DelegatePtr, v8::Local<v8::Function> JsFunction) = 0;
virtual bool ClearDelegate(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, void* DelegatePtr) = 0;
virtual void ExecuteDelegate(v8::Isolate* Isolate, v8::Local<v8::Context>& Context,
const v8::FunctionCallbackInfo<v8::Value>& Info, void* DelegatePtr) = 0;
virtual v8::Local<v8::Value> CreateArray(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, FPropertyTranslator* Property, void* ArrayPtr) = 0;
virtual bool IsInstanceOf(UStruct* Struct, v8::Local<v8::Object> JsObject) = 0;
virtual v8::Local<v8::Value> AddSoftObjectPtr(
v8::Isolate* Isolate, v8::Local<v8::Context> Context, FSoftObjectPtr* SoftObjectPtr, UClass* Class, bool IsSoftClass) = 0;
};
#endif
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,69 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "ObjectRetainer.h"
#include "PuertsNamespaceDef.h"
#ifdef THREAD_SAFE
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#pragma warning(push, 0)
#include "v8.h"
#pragma warning(pop)
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
#endif
namespace PUERTS_NAMESPACE
{
void FObjectRetainer::Retain(UObject* Object)
{
#ifdef THREAD_SAFE
FScopeLock ScopeLock(&RetainedObjectsCritical);
#endif
if (!RetainedObjects.Contains(Object))
{
RetainedObjects.Add(Object);
}
}
void FObjectRetainer::Release(UObject* Object)
{
#ifdef THREAD_SAFE
FScopeLock ScopeLock(&RetainedObjectsCritical);
#endif
if (RetainedObjects.Contains(Object))
{
RetainedObjects.Remove(Object);
}
}
void FObjectRetainer::Clear()
{
#ifdef THREAD_SAFE
FScopeLock ScopeLock(&RetainedObjectsCritical);
#endif
RetainedObjects.Empty();
}
void FObjectRetainer::AddReferencedObjects(FReferenceCollector& Collector)
{
#ifdef THREAD_SAFE
FScopeLock ScopeLock(&RetainedObjectsCritical);
#endif
Collector.AddReferencedObjects(RetainedObjects);
}
FString FObjectRetainer::GetReferencerName() const
{
return Name;
}
FObjectRetainer::~FObjectRetainer()
{
Clear();
}
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,186 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#ifndef WITH_QUICKJS
#include "pesapi.h"
#include "CoreMinimal.h"
#include "V8Utils.h"
#include <map>
#include <string>
#include <sstream>
#define STRINGIFY_(x) #x
#define STRINGIFY(x) STRINGIFY_(x)
static std::map<std::string, std::string> LoadedModules;
#if PLATFORM_IOS
int PesapiLoadFramework(std::string frameworkName, std::string entryClassName, pesapi_func_ptr* funcPtrArray);
#endif
MSVC_PRAGMA(warning(push))
MSVC_PRAGMA(warning(disable : 4191))
static pesapi_func_ptr funcs[] = {(pesapi_func_ptr) &pesapi_create_null, (pesapi_func_ptr) &pesapi_create_undefined,
(pesapi_func_ptr) &pesapi_create_boolean, (pesapi_func_ptr) &pesapi_create_int32, (pesapi_func_ptr) &pesapi_create_uint32,
(pesapi_func_ptr) &pesapi_create_int64, (pesapi_func_ptr) &pesapi_create_uint64, (pesapi_func_ptr) &pesapi_create_double,
(pesapi_func_ptr) &pesapi_create_string_utf8, (pesapi_func_ptr) &pesapi_create_binary, (pesapi_func_ptr) &pesapi_create_array,
(pesapi_func_ptr) &pesapi_create_object, (pesapi_func_ptr) &pesapi_create_function, (pesapi_func_ptr) &pesapi_create_class,
(pesapi_func_ptr) &pesapi_get_value_bool, (pesapi_func_ptr) &pesapi_get_value_int32, (pesapi_func_ptr) &pesapi_get_value_uint32,
(pesapi_func_ptr) &pesapi_get_value_int64, (pesapi_func_ptr) &pesapi_get_value_uint64,
(pesapi_func_ptr) &pesapi_get_value_double, (pesapi_func_ptr) &pesapi_get_value_string_utf8,
(pesapi_func_ptr) &pesapi_get_value_binary, (pesapi_func_ptr) &pesapi_get_array_length, (pesapi_func_ptr) &pesapi_is_null,
(pesapi_func_ptr) &pesapi_is_undefined, (pesapi_func_ptr) &pesapi_is_boolean, (pesapi_func_ptr) &pesapi_is_int32,
(pesapi_func_ptr) &pesapi_is_uint32, (pesapi_func_ptr) &pesapi_is_int64, (pesapi_func_ptr) &pesapi_is_uint64,
(pesapi_func_ptr) &pesapi_is_double, (pesapi_func_ptr) &pesapi_is_string, (pesapi_func_ptr) &pesapi_is_object,
(pesapi_func_ptr) &pesapi_is_function, (pesapi_func_ptr) &pesapi_is_binary, (pesapi_func_ptr) &pesapi_is_array,
(pesapi_func_ptr) &pesapi_native_object_to_value, (pesapi_func_ptr) &pesapi_get_native_object_ptr,
(pesapi_func_ptr) &pesapi_get_native_object_typeid, (pesapi_func_ptr) &pesapi_is_instance_of, (pesapi_func_ptr) &pesapi_boxing,
(pesapi_func_ptr) &pesapi_unboxing, (pesapi_func_ptr) &pesapi_update_boxed_value, (pesapi_func_ptr) &pesapi_is_boxed_value,
(pesapi_func_ptr) &pesapi_get_args_len, (pesapi_func_ptr) &pesapi_get_arg, (pesapi_func_ptr) &pesapi_get_env,
(pesapi_func_ptr) &pesapi_get_this, (pesapi_func_ptr) &pesapi_get_holder, (pesapi_func_ptr) &pesapi_get_userdata,
(pesapi_func_ptr) &pesapi_add_return, (pesapi_func_ptr) &pesapi_throw_by_string, (pesapi_func_ptr) &pesapi_create_env_ref,
(pesapi_func_ptr) &pesapi_env_ref_is_valid, (pesapi_func_ptr) &pesapi_get_env_from_ref,
(pesapi_func_ptr) &pesapi_duplicate_env_ref, (pesapi_func_ptr) &pesapi_release_env_ref, (pesapi_func_ptr) &pesapi_open_scope,
(pesapi_func_ptr) &pesapi_open_scope_placement, (pesapi_func_ptr) &pesapi_has_caught,
(pesapi_func_ptr) &pesapi_get_exception_as_string, (pesapi_func_ptr) &pesapi_close_scope,
(pesapi_func_ptr) &pesapi_close_scope_placement, (pesapi_func_ptr) &pesapi_create_value_ref,
(pesapi_func_ptr) &pesapi_duplicate_value_ref, (pesapi_func_ptr) &pesapi_release_value_ref,
(pesapi_func_ptr) &pesapi_get_value_from_ref, (pesapi_func_ptr) &pesapi_set_ref_weak, (pesapi_func_ptr) &pesapi_set_owner,
(pesapi_func_ptr) &pesapi_get_ref_associated_env, (pesapi_func_ptr) &pesapi_get_ref_internal_fields,
(pesapi_func_ptr) &pesapi_get_property, (pesapi_func_ptr) &pesapi_set_property, (pesapi_func_ptr) &pesapi_get_private,
(pesapi_func_ptr) &pesapi_set_private, (pesapi_func_ptr) &pesapi_get_property_uint32,
(pesapi_func_ptr) &pesapi_set_property_uint32, (pesapi_func_ptr) &pesapi_call_function, (pesapi_func_ptr) &pesapi_eval,
(pesapi_func_ptr) &pesapi_global, (pesapi_func_ptr) &pesapi_get_env_private, (pesapi_func_ptr) &pesapi_set_env_private,
(pesapi_func_ptr) &pesapi_alloc_type_infos, (pesapi_func_ptr) &pesapi_set_type_info,
(pesapi_func_ptr) &pesapi_create_signature_info, (pesapi_func_ptr) &pesapi_alloc_property_descriptors,
(pesapi_func_ptr) &pesapi_set_method_info, (pesapi_func_ptr) &pesapi_set_property_info, (pesapi_func_ptr) &pesapi_define_class,
(pesapi_func_ptr) &pesapi_get_class_data, (pesapi_func_ptr) &pesapi_trace_native_object_lifecycle,
(pesapi_func_ptr) &pesapi_on_class_not_found, (pesapi_func_ptr) &pesapi_class_type_info,
(pesapi_func_ptr) &pesapi_find_type_id};
MSVC_PRAGMA(warning(pop))
EXTERN_C_START
extern const char* GPesapiModuleName;
EXTERN_C_END
namespace puerts
{
void LoadPesapiDll(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
if (!Info[0]->IsString())
{
FV8Utils::ThrowException(Info.GetIsolate(), "#0 argument expect a string");
return;
}
FString Path = FV8Utils::ToFString(Info.GetIsolate(), Info[0]);
auto Iter = LoadedModules.find(TCHAR_TO_UTF8(*Path));
if (Iter != LoadedModules.end())
{
Info.GetReturnValue().Set(FV8Utils::ToV8String(Info.GetIsolate(), Iter->second.c_str()));
return;
}
void* DllHandle = FPlatformProcess::GetDllHandle(*Path);
if (!DllHandle)
{
FV8Utils::ThrowException(Info.GetIsolate(), FString(TEXT("dlopen fail for ")) + Path);
return;
}
const FString EntryName = UTF8_TO_TCHAR(STRINGIFY(PESAPI_MODULE_INITIALIZER(dynamic)));
auto Init = (const char* (*) (pesapi_func_ptr*) )(uintptr_t) FPlatformProcess::GetDllExport(DllHandle, *EntryName);
if (Init)
{
const char* ModuleName = Init(nullptr);
GPesapiModuleName = ModuleName;
Init(funcs);
GPesapiModuleName = nullptr;
LoadedModules[TCHAR_TO_UTF8(*Path)] = ModuleName;
Info.GetReturnValue().Set(FV8Utils::ToV8String(Info.GetIsolate(), ModuleName));
}
else
{
const FString VersionEntryName = UTF8_TO_TCHAR(STRINGIFY(PESAPI_MODULE_VERSION()));
auto Ver = (int (*)())(uintptr_t) FPlatformProcess::GetDllExport(DllHandle, *VersionEntryName);
if (!Ver)
{
FV8Utils::ThrowException(Info.GetIsolate(), "can find entry");
}
else
{
int PesapiVersion = Ver();
FV8Utils::ThrowException(Info.GetIsolate(),
FString::Printf(TEXT("pesapi version mismatch, expect: %d, but got %d"), PESAPI_VERSION, PesapiVersion));
}
FPlatformProcess::FreeDllHandle(DllHandle);
}
}
} // namespace puerts
static int LoadAddon(const char* path, const char* module_name)
{
if (LoadedModules.find(path) != LoadedModules.end())
{
// UE_LOG(LogTemp, Warning, TEXT("Try load addon already loaded: %s"), UTF8_TO_TCHAR(path));
return 0;
}
#if !PLATFORM_IOS
void* Handle = FPlatformProcess::GetDllHandle(UTF8_TO_TCHAR(path));
if (Handle)
{
FString EntryName = UTF8_TO_TCHAR(STRINGIFY(PESAPI_MODULE_INITIALIZER(dynamic)));
auto Init = (const char* (*) (pesapi_func_ptr*) )(uintptr_t) FPlatformProcess::GetDllExport(Handle, *EntryName);
if (Init)
{
const char* ModuleName = Init(nullptr);
GPesapiModuleName = ModuleName;
Init(funcs);
GPesapiModuleName = nullptr;
LoadedModules[path] = ModuleName;
return 0;
}
else
{
FString VersionEntryName = UTF8_TO_TCHAR(STRINGIFY(PESAPI_MODULE_VERSION()));
auto Ver = (int (*)())(uintptr_t) FPlatformProcess::GetDllExport(Handle, *VersionEntryName);
if (!Ver)
{
UE_LOG(LogTemp, Error, TEXT("Could not find entry for: %s"), UTF8_TO_TCHAR(path));
}
else
{
int PesapiVersion = Ver();
UE_LOG(LogTemp, Error, TEXT("pesapi version mismatch, expect: %d, but got: %d"), PESAPI_VERSION, PesapiVersion);
}
}
}
else
{
UE_LOG(LogTemp, Error, TEXT("Could not load addon: %s"), UTF8_TO_TCHAR(path));
}
return -1;
#else
FString EntryName = UTF8_TO_TCHAR(STRINGIFY(PESAPI_MODULE_INITIALIZER(___magic_module_name_xx___)));
EntryName = EntryName.Replace(TEXT("___magic_module_name_xx___"), UTF8_TO_TCHAR(module_name));
return PesapiLoadFramework(module_name, TCHAR_TO_UTF8(*EntryName), funcs);
#endif
}
EXTERN_C_START
int pesapi_load_addon(const char* path, const char* module_name)
{
return LoadAddon(path, module_name);
}
EXTERN_C_END
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,113 @@
#pragma once
#include <sstream>
#if !defined(PUERTS_NAMESPACE)
#if defined(WITH_QJS_NAMESPACE_SUFFIX)
#define PUERTS_NAMESPACE puerts_qjs
#else
#define PUERTS_NAMESPACE puerts
#endif
#endif
namespace PUERTS_NAMESPACE
{
template <typename T>
inline void __USE(T&&)
{
}
template <typename T>
void PromiseRejectCallback(v8::PromiseRejectMessage Message)
{
auto Promise = Message.GetPromise();
auto Isolate = Promise->GetIsolate();
auto Event = Message.GetEvent();
auto JsEngine = T::Get(Isolate);
auto Callback = JsEngine->JsPromiseRejectCallback.Get(Isolate);
if (Callback.IsEmpty())
{
return;
}
v8::Local<v8::Value> Value;
if (Event == v8::kPromiseRejectWithNoHandler)
{
Value = Message.GetValue();
}
else if (Event == v8::kPromiseHandlerAddedAfterReject)
{
Value = v8::Undefined(Isolate);
}
else if (Event == v8::kPromiseResolveAfterResolved)
{
Value = Message.GetValue();
}
else if (Event == v8::kPromiseRejectAfterResolved)
{
Value = Message.GetValue();
}
else
{
return;
}
if (Value.IsEmpty())
{
Value = v8::Undefined(Isolate);
}
v8::Local<v8::Value> Args[] = {v8::Number::New(Isolate, Event), Promise, Value};
__USE(Callback->Call(Isolate->GetCurrentContext(), v8::Undefined(Isolate), 3, Args));
}
template <typename T>
void SetPromiseRejectCallback(const v8::FunctionCallbackInfo<v8::Value>& Args)
{
auto Isolate = Args.GetIsolate();
auto JsEngine = T::Get(Isolate);
JsEngine->JsPromiseRejectCallback.Reset(Isolate, Args[0].As<v8::Function>());
}
// TODO: rename this file
#ifndef WITH_QUICKJS
std::string StackTraceToString(v8::Isolate* InIsolate, v8::Local<v8::StackTrace> InStack)
{
std::ostringstream stm;
for (int i = 0; i < InStack->GetFrameCount(); i++)
{
v8::Local<v8::StackFrame> StackFrame = InStack->GetFrame(InIsolate, i);
v8::String::Utf8Value FuncName(InIsolate, StackFrame->GetFunctionName());
v8::String::Utf8Value ScriptName(InIsolate, StackFrame->GetScriptName());
const int LineNumber = StackFrame->GetLineNumber();
const int Column = StackFrame->GetColumn();
if (StackFrame->IsEval())
{
if (StackFrame->GetScriptId() == v8::Message::kNoScriptIdInfo)
{
stm << " at [eval]:" << LineNumber << ":" << Column << std::endl;
}
else
{
stm << " at [eval] (" << (*ScriptName ? *ScriptName : "anonymous") << ":" << LineNumber << ":" << Column << ")"
<< std::endl;
}
break;
}
if (FuncName.length() == 0)
{
stm << " at " << (*ScriptName ? *ScriptName : "anonymous") << ":" << LineNumber << ":" << Column << std::endl;
}
else
{
stm << " at " << *FuncName << "(" << (*ScriptName ? *ScriptName : "anonymous") << ":" << LineNumber << ":" << Column
<< ")" << std::endl;
}
}
return stm.str();
}
#endif
} // namespace PUERTS_NAMESPACE
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,202 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include <memory>
#include "CoreMinimal.h"
#include "CoreUObject.h"
#include "Runtime/Launch/Resources/Version.h"
#include "PropertyMacros.h"
#if ENGINE_MINOR_VERSION >= 25 || ENGINE_MAJOR_VERSION > 4
#include "UObject/WeakFieldPtr.h"
#endif
#include "NamespaceDef.h"
#include "ArrayBuffer.h"
#include "JsObject.h"
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#pragma warning(push, 0)
#include "libplatform/libplatform.h"
#include "v8.h"
#pragma warning(pop)
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
namespace PUERTS_NAMESPACE
{
class FPropertyTranslator
{
public:
static std::unique_ptr<FPropertyTranslator> Create(PropertyMacro* InProperty, bool IgnoreOut = false);
static void CreateOn(PropertyMacro* InProperty, FPropertyTranslator* InOldProperty);
FORCEINLINE v8::Local<v8::Value> UEToJsInContainer(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const void* ContainerPtr, bool PassByPointer = false) const
{
return UEToJs(Isolate, Context, Property->ContainerPtrToValuePtr<void>(ContainerPtr), PassByPointer);
}
FORCEINLINE bool JsToUEInContainer(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const v8::Local<v8::Value>& Value,
void* ContainerPtr, bool DeepCopy) const
{
return JsToUE(Isolate, Context, Value, Property->ContainerPtrToValuePtr<void>(ContainerPtr), DeepCopy);
}
FORCEINLINE bool JsToUEFastInContainer(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const v8::Local<v8::Value>& Value,
void* TempBuff, void** OutValuePtr) const
{
return JsToUEFast(Isolate, Context, Value, Property->ContainerPtrToValuePtr<void>(TempBuff), OutValuePtr);
}
FORCEINLINE void UEOutToJsInContainer(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const v8::Local<v8::Value>& Value,
const void* ContainerPtr, bool PassByPointer) const
{
UEOutToJs(Isolate, Context, Value, Property->ContainerPtrToValuePtr<void>(ContainerPtr), PassByPointer);
}
FORCEINLINE bool JsToUEOutInContainer(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const v8::Local<v8::Value>& Value,
void* ContainerPtr, bool PassByPointer) const
{
return JsToUEOut(Isolate, Context, Value, Property->ContainerPtrToValuePtr<void>(ContainerPtr), PassByPointer);
}
virtual v8::Local<v8::Value> UEToJs(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const void* ValuePtr, bool PassByPointer) const = 0;
virtual bool JsToUE(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const v8::Local<v8::Value>& Value, void* ValuePtr,
bool DeepCopy) const = 0;
virtual bool JsToUEFast(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const v8::Local<v8::Value>& Value,
void* TempBuff, void** OutValuePtr) const
{
*OutValuePtr = TempBuff; // using temp buffer by default
return JsToUE(Isolate, Context, Value, TempBuff, false);
}
virtual void Cleanup(void* ContainerPtr) const
{
}
virtual void UEOutToJs(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const v8::Local<v8::Value>& Value,
const void* ValuePtr, bool PassByPointer) const
{
}
virtual bool JsToUEOut(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const v8::Local<v8::Value>& Value, void* ValuePtr,
bool DeepCopy) const
{
return true;
}
virtual bool IsOut() const
{
return false;
}
explicit FPropertyTranslator(PropertyMacro* InProperty)
{
Init(InProperty);
}
FORCEINLINE void Init(PropertyMacro* InProperty)
{
Property = InProperty;
PropertyWeakPtr = InProperty;
OwnerIsClass = InProperty->GetOwnerClass() != nullptr;
NeedLinkOuter = false;
if (!OwnerIsClass)
{
if ((InProperty->IsA<StructPropertyMacro>() && StructProperty->Struct != FArrayBuffer::StaticStruct() &&
StructProperty->Struct != FArrayBufferValue::StaticStruct() &&
StructProperty->Struct != FJsObject::StaticStruct()) ||
InProperty->IsA<MapPropertyMacro>() || InProperty->IsA<ArrayPropertyMacro>() || InProperty->IsA<SetPropertyMacro>())
{
NeedLinkOuter = true;
}
}
}
virtual ~FPropertyTranslator()
{
}
union
{
PropertyMacro* Property;
NumericPropertyMacro* NumericProperty;
IntPropertyMacro* IntProperty;
EnumPropertyMacro* EnumProperty;
BoolPropertyMacro* BoolProperty;
ObjectPropertyBaseMacro* ObjectBaseProperty;
SoftObjectPropertyMacro* SoftObjectProperty;
SoftClassPropertyMacro* SoftClassProperty;
InterfacePropertyMacro* InterfaceProperty;
NamePropertyMacro* NameProperty;
StrPropertyMacro* StringProperty;
TextPropertyMacro* TextProperty;
ArrayPropertyMacro* ArrayProperty;
MapPropertyMacro* MapProperty;
SetPropertyMacro* SetProperty;
StructPropertyMacro* StructProperty;
DelegatePropertyMacro* DelegateProperty;
MulticastDelegatePropertyMacro* MulticastDelegateProperty;
ClassPropertyMacro* ClassProperty;
#if ENGINE_MINOR_VERSION >= 25 || ENGINE_MAJOR_VERSION > 4
FFieldPathProperty* FieldPathProperty;
#endif
};
bool OwnerIsClass;
bool NeedLinkOuter;
size_t ParamShallowCopySize = 0;
std::unique_ptr<FPropertyTranslator> Inner;
static void Getter(const v8::FunctionCallbackInfo<v8::Value>& Info);
void Getter(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Setter(const v8::FunctionCallbackInfo<v8::Value>& Info);
void Setter(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, v8::Local<v8::Value> Value,
const v8::FunctionCallbackInfo<v8::Value>& Info);
static void DelegateGetter(const v8::FunctionCallbackInfo<v8::Value>& Info);
void SetAccessor(v8::Isolate* Isolate, v8::Local<v8::FunctionTemplate> Template);
bool IsPropertyValid()
{
if (!PropertyWeakPtr.IsValid())
{
return false;
}
#if WITH_EDITOR
FProperty* TestP = PropertyWeakPtr.Get();
if (TestP != Property)
{
Init(TestP);
}
#endif
return true;
}
private:
#if ENGINE_MINOR_VERSION < 25 && ENGINE_MAJOR_VERSION < 5
TWeakObjectPtr<PropertyMacro> PropertyWeakPtr;
#else
TWeakFieldPtr<PropertyMacro> PropertyWeakPtr;
#endif
};
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,337 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#if USE_WASM3
#include "WasmJsFunctionParams.h"
#include "ContainerMeta.h"
#include "Misc/FileHelper.h"
#include "Serialization/JsonReader.h"
#include "WasmRuntime.h"
#include "V8Utils.h"
#include "JSLogger.h"
#include "../ObjectMapper.h"
#include "UECompatible.h"
#include "WasmModuleInstance.h"
#include "GenericPlatform/GenericPlatformMemory.h"
namespace PUERTS_NAMESPACE
{
static void NormalInstanceCall(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
IM3Function _Function = static_cast<IM3Function>((v8::Local<v8::External>::Cast(Info.Data()))->Value());
int argCount = _Function->funcType->numArgs;
check(Info.Length() >= argCount);
auto Isolate = Info.GetIsolate();
auto Context = Isolate->GetCurrentContext();
int64* args = (int64*) FMemory_Alloca(sizeof(int64) * argCount);
void** argsPointer = (void**) FMemory_Alloca(sizeof(void*) * argCount);
for (int Index = 0; Index < argCount; Index++)
{
const int type = _Function->funcType->types[_Function->funcType->numRets + Index];
switch (type)
{
case c_m3Type_i32:
check(Info[Index]->IsNumber());
*((int*) (args + Index)) = Info[Index]->Int32Value(Context).ToChecked();
argsPointer[Index] = args + Index;
break;
case c_m3Type_i64:
check(Info[Index]->IsBigInt());
*(args + Index) = Info[Index]->ToBigInt(Context).ToLocalChecked()->Int64Value();
argsPointer[Index] = args + Index;
break;
case c_m3Type_f32:
check(Info[Index]->IsNumber());
*((float*) (args + Index)) = (float) Info[Index]->NumberValue(Context).ToChecked();
argsPointer[Index] = args + Index;
break;
case c_m3Type_f64:
check(Info[Index]->IsNumber());
*((double*) (args + Index)) = Info[Index]->NumberValue(Context).ToChecked();
argsPointer[Index] = args + Index;
break;
default:
check(0);
}
}
if (Export_m3_Call(_Function, argCount, (const void**) argsPointer))
{
check(_Function->funcType->numRets <= 1);
if (_Function->funcType->numRets == 1)
{
int64 RetValue;
void* ret[1] = {&RetValue};
if (Export_m3_GetResults(_Function, 1, (const void**) ret))
{
const int type = _Function->funcType->types[0];
switch (type)
{
case c_m3Type_i32:
Info.GetReturnValue().Set(*((int*) (&RetValue)));
break;
case c_m3Type_i64:
Info.GetReturnValue().Set(v8::BigInt::New(Isolate, RetValue));
break;
case c_m3Type_f32:
Info.GetReturnValue().Set(*((float*) (&RetValue)));
break;
case c_m3Type_f64:
Info.GetReturnValue().Set(*((double*) (&RetValue)));
default:
check(0);
}
}
else
{
FV8Utils::ThrowException(Isolate, "call wasm get results failed");
}
}
}
else
{
FV8Utils::ThrowException(Isolate, "call wasm failed");
}
}
static const void* NormalInstanceLink(IM3Runtime runtime, IM3ImportContext _ctx, uint64_t* _sp, void* _mem)
{
IM3Function _Function = _ctx->function;
WasmNormalLinkInfo* _Info = (WasmNormalLinkInfo*) _ctx->userdata;
check(_Function->funcType->numRets <= 1);
uint64_t* raw_sp = _sp;
if (_Function->funcType->numRets > 0)
{
_sp++;
}
TArray<v8::Local<v8::Value>, TInlineAllocator<20>> Params;
check(_Function->funcType->numArgs < 20);
for (int i = 0; i < _Function->funcType->numArgs; i++)
{
const int type = _Function->funcType->types[_Function->funcType->numRets + i];
switch (type)
{
case c_m3Type_i32:
Params.Add(v8::Int32::New(_Info->Isolate, *((int32*) (_sp + i))));
break;
case c_m3Type_i64:
Params.Add(v8::BigInt::New(_Info->Isolate, *(_sp + i)));
break;
case c_m3Type_f32:
Params.Add(v8::Number::New(_Info->Isolate, *((float*) (_sp + i))));
break;
case c_m3Type_f64:
Params.Add(v8::Number::New(_Info->Isolate, *((double*) (_sp + i))));
break;
default:
check(0);
}
}
v8::TryCatch TryCatch(_Info->Isolate);
auto Ret = _Info->CachedFunction.Get(_Info->Isolate)
->Call(_Info->Isolate->GetCurrentContext(), v8::Undefined(_Info->Isolate), Params.Num(), Params.GetData());
if (TryCatch.HasCaught())
{
UE_LOG(Puerts, Error, TEXT("%s"), *FV8Utils::TryCatchToString(_Info->Isolate, &TryCatch));
return "some error";
}
if (_Function->funcType->numRets == 1)
{
v8::Local<v8::Value> RetValue = Ret.ToLocalChecked();
const int type = _Function->funcType->types[0];
switch (type)
{
case c_m3Type_i32:
check(RetValue->IsNumber());
*((int*) (raw_sp)) = RetValue->Int32Value(_Info->Isolate->GetCurrentContext()).ToChecked();
break;
case c_m3Type_i64:
check(RetValue->IsBigInt());
*raw_sp = RetValue->ToBigInt(_Info->Isolate->GetCurrentContext()).ToLocalChecked()->Int64Value();
break;
case c_m3Type_f32:
check(RetValue->IsNumber());
*((float*) (raw_sp)) = RetValue->NumberValue(_Info->Isolate->GetCurrentContext()).ToChecked();
break;
case c_m3Type_f64:
check(RetValue->IsNumber());
*((double*) (raw_sp)) = RetValue->NumberValue(_Info->Isolate->GetCurrentContext()).ToChecked();
break;
default:
check(0);
}
}
return nullptr;
}
WasmRuntime* NormalInstanceModule(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, TArray<uint8>& InData,
v8::Local<v8::Object>& ExportsObject, v8::Local<v8::Value> ImportsValue,
const TArray<std::shared_ptr<WasmRuntime>>& RuntimeList, TArray<WasmNormalLinkInfo*>& CachedLinkFunctionList)
{
WasmRuntime* UsedRuntime = RuntimeList[0].get();
v8::Local<v8::Object> MemoryObject;
v8::Local<v8::Object> ImportsObject;
//需要同时支持使用js mem以及 env memory
if (ImportsValue->IsObject())
{
v8::Local<v8::Object> EnvObject;
ImportsObject = ImportsValue.As<v8::Object>();
{
auto MaybeEnvValue = ImportsObject->Get(Context, FV8Utils::ToV8String(Isolate, "env"));
if (!MaybeEnvValue.IsEmpty())
{
auto EnvValue = MaybeEnvValue.ToLocalChecked();
if (EnvValue->IsObject())
{
EnvObject = EnvValue.As<v8::Object>();
auto MaybeMemory = EnvObject->Get(Context, FV8Utils::ToV8String(Isolate, "memory"));
if (!MaybeMemory.IsEmpty())
{
auto MemoryValue = MaybeMemory.ToLocalChecked();
if (MemoryValue->IsObject())
{
MemoryObject = MemoryValue.As<v8::Object>();
}
}
}
}
}
if (EnvObject.IsEmpty())
{
auto MaybeEnvValue = ImportsObject->Get(Context, FV8Utils::ToV8String(Isolate, "js"));
if (!MaybeEnvValue.IsEmpty())
{
auto EnvValue = MaybeEnvValue.ToLocalChecked();
if (EnvValue->IsObject())
{
EnvObject = EnvValue.As<v8::Object>();
auto MaybeMemory = EnvObject->Get(Context, FV8Utils::ToV8String(Isolate, "mem"));
if (!MaybeMemory.IsEmpty())
{
auto MemoryValue = MaybeMemory.ToLocalChecked();
if (MemoryValue->IsObject())
{
MemoryObject = MemoryValue.As<v8::Object>();
}
}
}
}
}
}
//默认情况下使用第一个runtime,其他情况使用memory里面指定的
if (!MemoryObject.IsEmpty())
{
int Seq =
MemoryObject->Get(Context, FV8Utils::ToV8String(Isolate, "_Seq")).ToLocalChecked()->Int32Value(Context).ToChecked();
for (auto r : RuntimeList)
{
if (r->GetRuntimeSeq() == Seq)
{
UsedRuntime = r.get();
break;
}
}
}
auto CustomLinkFunc = [&](IM3Module _Module) -> bool
{
if (!ImportsObject.IsEmpty())
{
auto ModuleNames = ImportsObject->GetOwnPropertyNames(Context).ToLocalChecked();
for (decltype(ModuleNames->Length()) j = 0; j < ModuleNames->Length(); ++j)
{
v8::Local<v8::Value> ModuleName;
v8::Local<v8::Value> ModuleValue;
if (ModuleNames->Get(Context, j).ToLocal(&ModuleName) &&
ImportsObject->Get(Context, ModuleName).ToLocal(&ModuleValue))
{
auto Module = ModuleValue.As<v8::Object>();
v8::String::Utf8Value UtfModuleName(Isolate, ModuleName);
auto FunctionNames = Module->GetOwnPropertyNames(Context).ToLocalChecked();
for (decltype(FunctionNames->Length()) i = 0; i < FunctionNames->Length(); ++i)
{
v8::Local<v8::Value> FunctionName;
v8::Local<v8::Value> FunctionValue;
if (FunctionNames->Get(Context, i).ToLocal(&FunctionName) &&
Module->Get(Context, FunctionName).ToLocal(&FunctionValue))
{
if (FunctionValue->IsFunction())
{
WasmNormalLinkInfo* NewInfo = new WasmNormalLinkInfo();
NewInfo->CachedFunction.Reset(Isolate, FunctionValue.As<v8::Function>());
NewInfo->Isolate = Isolate;
CachedLinkFunctionList.Add(NewInfo);
if (!Export_m3_LinkRawFunctionEx(_Module, *UtfModuleName,
(*(v8::String::Utf8Value(Isolate, FunctionName))), nullptr, &NormalInstanceLink, NewInfo))
{
return false;
}
}
}
}
}
}
}
return true;
};
WasmModuleInstance* NewInstance = new WasmModuleInstance(InData);
if (NewInstance->ParseModule(UsedRuntime->GetEnv()))
{
//如果没有指明需要import memory,那么使用默认的runtime即可,即便外面传入了memory也不生效
if (!NewInstance->GetModule()->memoryImported)
{
UsedRuntime = RuntimeList[0].get();
}
if (!NewInstance->LoadModule(UsedRuntime, 0, CustomLinkFunc))
{
delete NewInstance;
NewInstance = nullptr;
}
}
else
{
delete NewInstance;
NewInstance = nullptr;
}
if (NewInstance && NewInstance->GetAllExportFunctions().Num())
{
IM3Module _Module = NewInstance->GetModule();
for (uint32 i = 0; i < _Module->numFunctions; ++i)
{
IM3Function f = &_Module->functions[i];
if (f->compiled && f->export_name && *(f->export_name))
{
auto Data = v8::External::New(Isolate, f);
auto Func = v8::Function::New(Context, NormalInstanceCall, Data).ToLocalChecked();
Func->Set(Context, FV8Utils::ToV8String(Isolate, M3_FUNCTION_KEY), Data);
(void) ExportsObject->Set(Context, FV8Utils::ToV8String(Isolate, f->export_name), Func);
}
}
}
if (NewInstance->GetModule()->memoryExportName)
{
(void) ExportsObject->Set(Context, FV8Utils::ToV8String(Isolate, "__memoryExport"),
FV8Utils::ToV8String(Isolate, NewInstance->GetModule()->memoryExportName));
}
if (NewInstance->GetModule()->tableExportName)
{
(void) ExportsObject->Set(Context, FV8Utils::ToV8String(Isolate, "__tableExport"),
FV8Utils::ToV8String(Isolate, NewInstance->GetModule()->tableExportName));
(void) ExportsObject->Set(
Context, FV8Utils::ToV8String(Isolate, "__moduleIndex"), v8::Integer::New(Isolate, NewInstance->Index));
}
return UsedRuntime;
}
} // namespace PUERTS_NAMESPACE
#endif
@@ -0,0 +1,38 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#if USE_WASM3
#include "CoreMinimal.h"
#include "WasmModule.h"
#include "PuertsNamespaceDef.h"
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#pragma warning(push, 0)
#include "libplatform/libplatform.h"
#include "v8.h"
#pragma warning(pop)
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
#include "WasmFunction.h"
#define M3_FUNCTION_KEY "__puerts_inner_m3_func"
namespace PUERTS_NAMESPACE
{
struct WasmNormalLinkInfo
{
v8::UniquePersistent<v8::Function> CachedFunction;
v8::Isolate* Isolate;
};
WasmRuntime* NormalInstanceModule(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, TArray<uint8>& InData,
v8::Local<v8::Object>& ExportsObject, v8::Local<v8::Value> ImportsValue,
const TArray<std::shared_ptr<WasmRuntime>>& RuntimeList, TArray<WasmNormalLinkInfo*>& CachedLinkFunctionList);
}; // namespace PUERTS_NAMESPACE
#endif
@@ -0,0 +1,24 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#if USE_WASM3
#include <array>
#include <tuple>
#include "WasmRuntime.h"
#include "WasmModule.h"
#include "WasmFunction.h"
#include "WasmStaticLink.h"
#include "CoreMinimal.h"
#include "Binding.hpp"
#include "UEDataBinding.hpp"
struct AutoRegisterForWasmExtension
{
};
AutoRegisterForWasmExtension __AutoRegisterForWasmExtension__;
#endif
@@ -0,0 +1,30 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#if USE_WASM3
#include <array>
#include <tuple>
#include "WasmRuntime.h"
#include "WasmModule.h"
#include "WasmFunction.h"
#include "WasmStaticLink.h"
#include "CoreMinimal.h"
#include "Binding.hpp"
#include "UEDataBinding.hpp"
#include "Kismet/KismetMathLibrary.h"
float atan2_ue_bind(float X, float Y)
{
return UKismetMathLibrary::Atan2(X, Y);
}
WASM_BEGIN_LINK_GLOBAL(TestMath, 0)
WASM_LINK_GLOBAL(atan2_ue_bind)
WASM_END_LINK_GLOBAL(TestMath, 0)
#endif
@@ -0,0 +1,89 @@
#include "SoftObjectWrapper.h"
#include "V8Utils.h"
#include "ObjectMapper.h"
namespace PUERTS_NAMESPACE
{
v8::Local<v8::FunctionTemplate> FSoftObjectWrapper::ToFunctionTemplate(v8::Isolate* Isolate)
{
auto Result = v8::FunctionTemplate::New(Isolate);
Result->InstanceTemplate()->SetInternalFieldCount(6);
Result->PrototypeTemplate()->Set(
FV8Utils::ToV8String(Isolate, "LoadSynchronous"), v8::FunctionTemplate::New(Isolate, &LoadSynchronous));
Result->PrototypeTemplate()->Set(FV8Utils::ToV8String(Isolate, "Get"), v8::FunctionTemplate::New(Isolate, &Get));
return Result;
}
typedef UObject* (*FSoftObjectPtrObjectGetter)(FSoftObjectPtr* Ptr);
static void GenericObjectGet(const v8::FunctionCallbackInfo<v8::Value>& Info, FSoftObjectPtrObjectGetter Getter)
{
auto Isolate = Info.GetIsolate();
auto Context = Isolate->GetCurrentContext();
FSoftObjectPtr* Ptr = FV8Utils::GetPointerFast<FSoftObjectPtr>(Info.Holder());
if (!Ptr)
{
FV8Utils::ThrowException(Isolate, "passing a invalid object for FSoftObjectPtr");
return;
}
auto Obj = Getter(Ptr);
if (Obj)
{
UClass* PropertyClass = nullptr;
if (UObject* Object = FV8Utils::GetUObject(Info.Holder(), 1))
{
if (FV8Utils::IsReleasedPtr(Object))
{
FV8Utils::ThrowException(Isolate, "passing a invalid object");
return;
}
PropertyClass = Cast<UClass>(Object);
}
UClass* MetaClass = nullptr;
if (UObject* Object = FV8Utils::GetUObject(Info.Holder(), 2))
{
if (FV8Utils::IsReleasedPtr(Object))
{
FV8Utils::ThrowException(Isolate, "passing a invalid object");
return;
}
MetaClass = Cast<UClass>(Object);
}
if (PropertyClass && !Obj->GetClass()->IsChildOf(PropertyClass))
{
// FV8Utils::ThrowException(Isolate, "invalid type");
return;
}
if (MetaClass)
{
auto Class = Cast<UClass>(Obj);
if (!Class)
{
// FV8Utils::ThrowException(Isolate, "not a class");
return;
}
if (!Class->IsChildOf(MetaClass))
{
// FV8Utils::ThrowException(Isolate, "not a expect class");
return;
}
}
Info.GetReturnValue().Set(FV8Utils::IsolateData<IObjectMapper>(Isolate)->FindOrAdd(Isolate, Context, Obj->GetClass(), Obj));
}
}
void FSoftObjectWrapper::LoadSynchronous(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
GenericObjectGet(Info, [](FSoftObjectPtr* Ptr) { return Ptr->LoadSynchronous(); });
}
void FSoftObjectWrapper::Get(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
GenericObjectGet(Info, [](FSoftObjectPtr* Ptr) { return Ptr->Get(); });
}
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,34 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include "CoreMinimal.h"
#include "NamespaceDef.h"
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#pragma warning(push, 0)
#include "libplatform/libplatform.h"
#include "v8.h"
#pragma warning(pop)
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
namespace PUERTS_NAMESPACE
{
class FSoftObjectWrapper
{
public:
static v8::Local<v8::FunctionTemplate> ToFunctionTemplate(v8::Isolate* Isolate);
private:
static void LoadSynchronous(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Get(const v8::FunctionCallbackInfo<v8::Value>& Info);
};
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,105 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#if WITH_EDITOR
#include "SourceFileWatcher.h"
#include "DirectoryWatcherModule.h"
#include "Modules/ModuleManager.h"
#include "JSLogger.h"
#include "Misc/ScopeLock.h"
namespace PUERTS_NAMESPACE
{
FSourceFileWatcher::FSourceFileWatcher(std::function<void(const FString&)> InOnWatchedFileChanged)
: OnWatchedFileChanged(InOnWatchedFileChanged)
{
}
void FSourceFileWatcher::OnSourceLoaded(const FString& InPath)
{
FString Dir = FPaths::GetPath(InPath);
FString FileName = FPaths::GetCleanFilename(InPath);
FScopeLock ScopeLock(&SourceFileWatcherCritical);
if (!WatchedDirs.Contains(Dir))
{
FDirectoryWatcherModule& DirectoryWatcherModule =
FModuleManager::Get().LoadModuleChecked<FDirectoryWatcherModule>(TEXT("DirectoryWatcher"));
IDirectoryWatcher* DirectoryWatcher = DirectoryWatcherModule.Get();
FDelegateHandle DelegateHandle;
DirectoryWatcher->RegisterDirectoryChangedCallback_Handle(Dir,
IDirectoryWatcher::FDirectoryChanged::CreateRaw(this, &FSourceFileWatcher::OnDirectoryChanged), DelegateHandle,
IDirectoryWatcher::IgnoreChangesInSubtree);
WatchedDirs.Emplace(Dir, DelegateHandle);
UE_LOG(Puerts, Log, TEXT("add watched dir: %s"), *Dir);
}
if (!WatchedFiles.Contains(Dir))
{
WatchedFiles.Emplace(Dir, TMap<FString, FMD5Hash>());
}
if (!WatchedFiles[Dir].Contains(FileName))
{
UE_LOG(Puerts, Log, TEXT("add watched file: %s"), *InPath);
FMD5Hash Hash = FMD5Hash::HashFile(*InPath);
WatchedFiles[Dir].Add(FileName, Hash);
}
}
void FSourceFileWatcher::OnDirectoryChanged(const TArray<FFileChangeData>& FileChanges)
{
FScopeLock ScopeLock(&SourceFileWatcherCritical);
if (!OnWatchedFileChanged)
return;
for (auto Change : FileChanges)
{
if (Change.Action == FFileChangeData::FCA_Modified && Change.Filename.EndsWith(TEXT(".js")))
{
FPaths::NormalizeFilename(Change.Filename);
Change.Filename = FPaths::ConvertRelativePathToFull(Change.Filename);
FString Dir = FPaths::GetPath(Change.Filename);
FString FileName = FPaths::GetCleanFilename(Change.Filename);
FString Splitter = TEXT("/");
if (!WatchedFiles.Contains(Dir))
{
Dir = Dir.Replace(TEXT("/"), TEXT("\\"));
Splitter = TEXT("\\");
}
if (WatchedFiles.Contains(Dir))
{
if (WatchedFiles[Dir].Contains(FileName))
{
FString NotifyPath = Dir + Splitter + FileName;
FMD5Hash Hash = FMD5Hash::HashFile(*NotifyPath);
if (WatchedFiles[Dir][FileName] != Hash)
{
OnWatchedFileChanged(NotifyPath);
WatchedFiles[Dir][FileName] = Hash;
}
}
}
else
{
UE_LOG(Puerts, Error, TEXT("callback with unwatched dir: %s"), *Dir);
}
}
}
}
FSourceFileWatcher::~FSourceFileWatcher()
{
FDirectoryWatcherModule& DirectoryWatcherModule =
FModuleManager::Get().LoadModuleChecked<FDirectoryWatcherModule>(TEXT("DirectoryWatcher"));
IDirectoryWatcher* DirectoryWatcher = DirectoryWatcherModule.Get();
FScopeLock ScopeLock(&SourceFileWatcherCritical);
for (auto KV : WatchedDirs)
{
DirectoryWatcher->UnregisterDirectoryChangedCallback_Handle(KV.Key, KV.Value);
}
}
} // namespace PUERTS_NAMESPACE
#endif
@@ -0,0 +1,730 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "StructWrapper.h"
#include "V8Utils.h"
#include "ObjectMapper.h"
#include "PathEscape.h"
namespace PUERTS_NAMESPACE
{
void FStructWrapper::AddExtensionMethods(const std::vector<UFunction*>& InExtensionMethods)
{
ExtensionMethods.insert(ExtensionMethods.end(), InExtensionMethods.begin(), InExtensionMethods.end());
}
std::shared_ptr<FPropertyTranslator> FStructWrapper::GetPropertyTranslator(PropertyMacro* InProperty)
{
auto Iter = PropertiesMap.Find(InProperty->GetFName());
if (!Iter)
{
std::shared_ptr<FPropertyTranslator> PropertyTranslator = FPropertyTranslator::Create(InProperty);
if (PropertyTranslator)
{
PropertiesMap.Add(InProperty->GetFName(), PropertyTranslator);
Properties.push_back(PropertyTranslator);
}
return PropertyTranslator;
}
FPropertyTranslator::CreateOn(InProperty, Iter->get());
return *Iter;
}
std::shared_ptr<FFunctionTranslator> FStructWrapper::GetMethodTranslator(UFunction* InFunction, bool IsExtension)
{
auto Iter = MethodsMap.Find(InFunction->GetFName());
if (!Iter)
{
std::shared_ptr<FFunctionTranslator> FunctionTranslator;
if (IsExtension)
{
FunctionTranslator = std::make_shared<FExtensionMethodTranslator>(InFunction);
}
else
{
FunctionTranslator = std::make_shared<FFunctionTranslator>(InFunction, false);
}
MethodsMap.Add(InFunction->GetFName(), FunctionTranslator);
return FunctionTranslator;
}
Iter->get()->Init(InFunction, false);
return *Iter;
}
std::shared_ptr<FFunctionTranslator> FStructWrapper::GetFunctionTranslator(UFunction* InFunction)
{
auto Iter = FunctionsMap.Find(InFunction->GetFName());
if (!Iter)
{
auto FunctionTranslator = std::make_shared<FFunctionTranslator>(InFunction, false);
FunctionsMap.Add(InFunction->GetFName(), FunctionTranslator);
return FunctionTranslator;
}
Iter->get()->Init(InFunction, false);
return *Iter;
}
void FStructWrapper::RefreshMethod(UFunction* InFunction)
{
if (!InFunction->HasAnyFunctionFlags(FUNC_Static))
{
GetMethodTranslator(InFunction, false);
}
}
MSVC_PRAGMA(warning(push))
MSVC_PRAGMA(warning(disable : 4191))
void FStructWrapper::InitTemplateProperties(
v8::Isolate* Isolate, UStruct* InStruct, v8::Local<v8::FunctionTemplate> Template, bool IsReuseTemplate)
{
auto ClassDefinition = FindClassByType(Struct.Get());
TSet<FName> AddedProperties;
if (ClassDefinition)
{
JSPropertyInfo* PropertyInfo = ClassDefinition->Properties;
while (PropertyInfo && PropertyInfo->Name && PropertyInfo->Getter)
{
AddedProperties.Add(PropertyInfo->Name);
if (!IsReuseTemplate)
{
v8::PropertyAttribute PropertyAttribute = v8::DontDelete;
if (!PropertyInfo->Setter)
PropertyAttribute = (v8::PropertyAttribute)(PropertyAttribute | v8::ReadOnly);
auto GetterData = PropertyInfo->GetterData
? static_cast<v8::Local<v8::Value>>(v8::External::New(Isolate, PropertyInfo->GetterData))
: v8::Local<v8::Value>();
auto SetterData = PropertyInfo->SetterData
? static_cast<v8::Local<v8::Value>>(v8::External::New(Isolate, PropertyInfo->SetterData))
: v8::Local<v8::Value>();
Template->PrototypeTemplate()->SetAccessorProperty(FV8Utils::InternalString(Isolate, PropertyInfo->Name),
PropertyInfo->Getter
? v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) PropertyInfo->Getter, GetterData)
: v8::Local<v8::FunctionTemplate>(),
PropertyInfo->Setter
? v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) PropertyInfo->Setter, SetterData)
: v8::Local<v8::FunctionTemplate>(),
PropertyAttribute);
}
++PropertyInfo;
}
if (!IsReuseTemplate)
{
PropertyInfo = ClassDefinition->Variables;
while (PropertyInfo && PropertyInfo->Name && PropertyInfo->Getter)
{
v8::PropertyAttribute PropertyAttribute = v8::DontDelete;
if (!PropertyInfo->Setter)
PropertyAttribute = (v8::PropertyAttribute)(PropertyAttribute | v8::ReadOnly);
auto GetterData = PropertyInfo->GetterData
? static_cast<v8::Local<v8::Value>>(v8::External::New(Isolate, PropertyInfo->GetterData))
: v8::Local<v8::Value>();
auto SetterData = PropertyInfo->SetterData
? static_cast<v8::Local<v8::Value>>(v8::External::New(Isolate, PropertyInfo->SetterData))
: v8::Local<v8::Value>();
Template->SetAccessorProperty(FV8Utils::InternalString(Isolate, PropertyInfo->Name),
PropertyInfo->Getter
? v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) PropertyInfo->Getter, GetterData)
: v8::Local<v8::FunctionTemplate>(),
PropertyInfo->Setter
? v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) PropertyInfo->Setter, SetterData)
: v8::Local<v8::FunctionTemplate>(),
PropertyAttribute);
++PropertyInfo;
}
}
}
for (TFieldIterator<PropertyMacro> PropertyIt(InStruct, EFieldIteratorFlags::ExcludeSuper); PropertyIt; ++PropertyIt)
{
PropertyMacro* Property = *PropertyIt;
if (AddedProperties.Contains(Property->GetFName()))
{
continue;
}
auto PropertyTranslator = GetPropertyTranslator(Property);
if (PropertyTranslator)
{
if (!IsReuseTemplate)
PropertyTranslator->SetAccessor(Isolate, Template);
}
else
{
// UE_LOG(LogTemp, Warning, TEXT("%s:%s not supported"), *Property->GetOwnerStruct()->GetName(), *Property->GetName());
}
}
}
v8::Local<v8::FunctionTemplate> FStructWrapper::ToFunctionTemplate(v8::Isolate* Isolate, v8::FunctionCallback Construtor)
{
auto ClassDefinition = FindClassByType(Struct.Get());
bool IsReuseTemplate = false;
#if PUERTS_REUSE_STRUCTWRAPPER_FUNCTIONTEMPLATE
IsReuseTemplate = true;
if (CachedFunctionTemplate.IsEmpty())
{
IsReuseTemplate = false;
auto Temp = v8::FunctionTemplate::New(Isolate, Construtor, v8::External::New(Isolate, this));
Temp->InstanceTemplate()->SetInternalFieldCount(4);
CachedFunctionTemplate.Reset(Isolate, Temp);
}
auto Result = CachedFunctionTemplate.Get(Isolate);
#else
auto Result = v8::FunctionTemplate::New(
Isolate, Construtor, v8::External::New(Isolate, this)); // 和class的区别就这里传的函数不一样,后续尽量重用
Result->InstanceTemplate()->SetInternalFieldCount(4);
#endif
TSet<FName> AddedMethods;
TSet<FName> AddedFunctions;
if (ClassDefinition)
{
ExternalInitialize = (V8InitializeFuncType) ClassDefinition->Initialize;
ExternalFinalize = ClassDefinition->Finalize;
JSFunctionInfo* FunctionInfo = ClassDefinition->Methods;
while (FunctionInfo && FunctionInfo->Name && FunctionInfo->Callback)
{
AddedMethods.Add(FunctionInfo->Name);
if (!IsReuseTemplate)
{
#ifndef WITH_QUICKJS
auto FastCallInfo = FunctionInfo->ReflectionInfo ? FunctionInfo->ReflectionInfo->FastCallInfo() : nullptr;
if (FastCallInfo)
{
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, FunctionInfo->Name),
v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) FunctionInfo->Callback,
FunctionInfo->Data ? static_cast<v8::Local<v8::Value>>(v8::External::New(Isolate, FunctionInfo->Data))
: v8::Local<v8::Value>(),
v8::Local<v8::Signature>(), 0, v8::ConstructorBehavior::kThrow, v8::SideEffectType::kHasSideEffect,
FastCallInfo));
}
else
#endif
{
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, FunctionInfo->Name),
v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) FunctionInfo->Callback,
FunctionInfo->Data ? static_cast<v8::Local<v8::Value>>(v8::External::New(Isolate, FunctionInfo->Data))
: v8::Local<v8::Value>()));
}
}
++FunctionInfo;
}
FunctionInfo = ClassDefinition->Functions;
while (FunctionInfo && FunctionInfo->Name && FunctionInfo->Callback)
{
AddedFunctions.Add(FunctionInfo->Name);
if (!IsReuseTemplate)
{
#ifndef WITH_QUICKJS
auto FastCallInfo = FunctionInfo->ReflectionInfo ? FunctionInfo->ReflectionInfo->FastCallInfo() : nullptr;
if (FastCallInfo)
{
Result->Set(FV8Utils::InternalString(Isolate, FunctionInfo->Name),
v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) FunctionInfo->Callback,
FunctionInfo->Data ? static_cast<v8::Local<v8::Value>>(v8::External::New(Isolate, FunctionInfo->Data))
: v8::Local<v8::Value>(),
v8::Local<v8::Signature>(), 0, v8::ConstructorBehavior::kThrow, v8::SideEffectType::kHasSideEffect,
FastCallInfo));
}
else
#endif
{
Result->Set(FV8Utils::InternalString(Isolate, FunctionInfo->Name),
v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) FunctionInfo->Callback,
FunctionInfo->Data ? static_cast<v8::Local<v8::Value>>(v8::External::New(Isolate, FunctionInfo->Data))
: v8::Local<v8::Value>()));
}
}
++FunctionInfo;
}
}
InitTemplateProperties(Isolate, Struct.Get(), Result, IsReuseTemplate);
if (const auto Class = Cast<UClass>(Struct.Get()))
{
for (TFieldIterator<UFunction> FuncIt(Class, EFieldIteratorFlags::ExcludeSuper); FuncIt; ++FuncIt)
{
UFunction* Function = *FuncIt;
if ((Function->HasAnyFunctionFlags(FUNC_Static) && AddedFunctions.Contains(Function->GetFName())) ||
(!Function->HasAnyFunctionFlags(FUNC_Static) && AddedMethods.Contains(Function->GetFName())))
{
// UE_LOG(LogTemp, Warning, TEXT("%s added"), *Function->GetName());
continue;
}
FString FuncName = Function->GetName();
auto Key = FV8Utils::InternalString(Isolate, FuncName);
#ifdef PUERTS_WITH_EDITOR_SUFFIX
// 这里同时绑定带Suffix和不带Suffix的后缀是为了兼容现有的一些js写的代码(PuertsEditor)
v8::Local<v8::String> AdditionalKey{};
if (puerts::IsEditorOnlyUFunction(Function))
{
FString SuffixFuncName = FuncName + EditorOnlyPropertySuffix.GetData();
AdditionalKey = FV8Utils::InternalString(Isolate, SuffixFuncName);
}
#endif
// 这里同时绑定带Suffix和不带Suffix的后缀是为了兼容现有的一些js写的代码(PuertsEditor)
if (Function->HasAnyFunctionFlags(FUNC_Static))
{
auto FunctionTranslator = GetFunctionTranslator(Function);
AddedFunctions.Add(Function->GetFName());
if (!IsReuseTemplate)
{
Result->Set(Key, FunctionTranslator->ToFunctionTemplate(Isolate));
#ifdef PUERTS_WITH_EDITOR_SUFFIX
if (!AdditionalKey.IsEmpty())
{
Result->Set(AdditionalKey, FunctionTranslator->ToFunctionTemplate(Isolate));
}
#endif
}
}
else
{
auto FunctionTranslator = GetMethodTranslator(Function, false);
AddedMethods.Add(Function->GetFName());
if (!IsReuseTemplate)
{
Result->PrototypeTemplate()->Set(Key, FunctionTranslator->ToFunctionTemplate(Isolate));
#ifdef PUERTS_WITH_EDITOR_SUFFIX
if (!AdditionalKey.IsEmpty())
{
Result->PrototypeTemplate()->Set(AdditionalKey, FunctionTranslator->ToFunctionTemplate(Isolate));
}
#endif
}
}
}
for (const FImplementedInterface& Interface : Class->Interfaces)
{
if (Interface.Class)
{
for (TFieldIterator<UFunction> ItfFuncIt(Interface.Class, EFieldIteratorFlags::ExcludeSuper); ItfFuncIt;
++ItfFuncIt)
{
UFunction* ItfFunction = *ItfFuncIt;
if (!ItfFunction->HasAnyFunctionFlags(FUNC_Static) && !AddedMethods.Contains(ItfFunction->GetFName()))
{
auto ItfFunctionTranslator = GetMethodTranslator(ItfFunction, false);
AddedMethods.Add(ItfFunction->GetFName());
if (!IsReuseTemplate)
Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, ItfFunction->GetName()),
ItfFunctionTranslator->ToFunctionTemplate(Isolate));
}
}
}
}
if (!IsReuseTemplate)
{
Result->Set(FV8Utils::InternalString(Isolate, "Find"),
v8::FunctionTemplate::New(Isolate, Find, v8::External::New(Isolate, this)));
Result->Set(FV8Utils::InternalString(Isolate, "Load"),
v8::FunctionTemplate::New(Isolate, Load, v8::External::New(Isolate, this)));
}
}
for (auto Iter = ExtensionMethods.begin(); Iter != ExtensionMethods.end(); ++Iter)
{
UFunction* Function = *Iter;
if (AddedMethods.Contains(Function->GetFName()))
{
continue;
}
auto FunctionTranslator = GetMethodTranslator(Function, true);
AddedMethods.Add(Function->GetFName());
if (!IsReuseTemplate)
{
auto Key = FV8Utils::InternalString(Isolate, Function->GetName());
Result->PrototypeTemplate()->Set(Key, FunctionTranslator->ToFunctionTemplate(Isolate));
}
}
if (!IsReuseTemplate)
Result->Set(FV8Utils::InternalString(Isolate, "StaticClass"),
v8::FunctionTemplate::New(Isolate, StaticClass, v8::External::New(Isolate, this)));
if (!Struct->IsA<UClass>() && !IsReuseTemplate)
{
Result->Set(FV8Utils::InternalString(Isolate, "StaticStruct"),
v8::FunctionTemplate::New(Isolate, StaticClass, v8::External::New(Isolate, this)));
}
#ifndef WITH_QUICKJS
if (!IsReuseTemplate)
Result->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
[](v8::Local<v8::Name> Property, const v8::PropertyCallbackInfo<v8::Value>& Info)
{
if (Property->IsSymbol())
return;
auto InnerIsolate = Info.GetIsolate();
auto Context = InnerIsolate->GetCurrentContext();
auto This = Info.This();
FName RequiredFName(*FV8Utils::ToFString(Info.GetIsolate(), Property));
auto FixedPropertyName = FV8Utils::ToV8String(InnerIsolate, RequiredFName);
if (This->GetPrototype()->IsObject())
{
auto Proto = This->GetPrototype().As<v8::Object>();
if (Proto->Has(Context, FixedPropertyName).FromMaybe(false))
{
Info.GetReturnValue().Set(This->Get(Context, FixedPropertyName).ToLocalChecked());
auto DescriptorVal = Proto->GetOwnPropertyDescriptor(Context, FixedPropertyName).ToLocalChecked();
while (!DescriptorVal->IsObject())
{
auto Parent = Proto->GetPrototype();
if (!Parent->IsObject())
break;
Proto = Parent.As<v8::Object>();
DescriptorVal = Proto->GetOwnPropertyDescriptor(Context, FixedPropertyName).ToLocalChecked();
}
if (DescriptorVal->IsObject())
{
auto Descriptor = DescriptorVal.As<v8::Object>();
auto Getter = Descriptor->Get(Context, FV8Utils::ToV8String(InnerIsolate, "get")).ToLocalChecked();
if (!Getter->IsFunction())
{
auto Value = Descriptor->Get(Context, FV8Utils::ToV8String(InnerIsolate, "value")).ToLocalChecked();
(void) (Proto->Set(Context, Property, Value));
}
else
{
Proto->SetAccessorProperty(Property, Getter.As<v8::Function>(),
Descriptor->Get(Context, FV8Utils::ToV8String(InnerIsolate, "set"))
.ToLocalChecked()
.As<v8::Function>());
}
}
}
}
},
[](v8::Local<v8::Name> Property, v8::Local<v8::Value> Value, const v8::PropertyCallbackInfo<v8::Value>& Info)
{
if (Property->IsSymbol())
return;
auto InnerIsolate = Info.GetIsolate();
auto Context = InnerIsolate->GetCurrentContext();
auto This = Info.This();
FName RequiredFName(*FV8Utils::ToFString(Info.GetIsolate(), Property));
auto FixedPropertyName = FV8Utils::ToV8String(InnerIsolate, RequiredFName);
if (This->GetPrototype()->IsObject())
{
auto Proto = This->GetPrototype().As<v8::Object>();
if (Proto->Has(Context, FixedPropertyName).FromMaybe(false))
{
auto _UnUsed = This->Set(Context, FixedPropertyName, Value);
Info.GetReturnValue().Set(Value);
auto DescriptorVal = Proto->GetOwnPropertyDescriptor(Context, FixedPropertyName).ToLocalChecked();
while (!DescriptorVal->IsObject())
{
auto Parent = Proto->GetPrototype();
if (!Parent->IsObject())
break;
Proto = Parent.As<v8::Object>();
DescriptorVal = Proto->GetOwnPropertyDescriptor(Context, FixedPropertyName).ToLocalChecked();
}
if (DescriptorVal->IsObject())
{
auto Descriptor = DescriptorVal.As<v8::Object>();
// set first, mush set accessor of object
Proto->SetAccessorProperty(Property,
Descriptor->Get(Context, FV8Utils::ToV8String(InnerIsolate, "get"))
.ToLocalChecked()
.As<v8::Function>(),
Descriptor->Get(Context, FV8Utils::ToV8String(InnerIsolate, "set"))
.ToLocalChecked()
.As<v8::Function>());
}
}
}
},
nullptr, nullptr, nullptr, v8::Local<v8::Value>(), v8::PropertyHandlerFlags::kNonMasking));
#endif
return Result;
}
MSVC_PRAGMA(warning(pop))
void FStructWrapper::StaticClass(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
FStructWrapper* This = reinterpret_cast<FStructWrapper*>((v8::Local<v8::External>::Cast(Info.Data()))->Value());
if (!This->Struct.IsValid())
{
FV8Utils::ThrowException(Isolate, "Associated UStruct had been GC");
return;
}
auto Result =
FV8Utils::IsolateData<IObjectMapper>(Isolate)->FindOrAdd(Isolate, Context, This->Struct->GetClass(), This->Struct.Get());
Info.GetReturnValue().Set(Result);
}
void FStructWrapper::Find(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
FStructWrapper* This = reinterpret_cast<FStructWrapper*>((v8::Local<v8::External>::Cast(Info.Data()))->Value());
if (!This->Struct.IsValid())
{
FV8Utils::ThrowException(Isolate, "Associated UStruct had been GC");
return;
}
UClass* Class = Cast<UClass>(This->Struct);
if (Class && Info.Length() >= 1 && Info[0]->IsString())
{
UObject* Object = nullptr;
if (Info.Length() > 1)
{
UObject* Outer = FV8Utils::GetUObject(Context, Info[1]);
Object = StaticFindObject(Class, Outer, *FV8Utils::ToFString(Isolate, Info[0]), false);
}
else
{
#if (ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1) || ENGINE_MAJOR_VERSION > 5
Object = StaticFindFirstObject(Class, *FV8Utils::ToFString(Isolate, Info[0]));
#else
Object = StaticFindObject(Class, ANY_PACKAGE, *FV8Utils::ToFString(Isolate, Info[0]), false);
#endif
}
if (Object)
{
auto Result = FV8Utils::IsolateData<IObjectMapper>(Isolate)->FindOrAdd(Isolate, Context, Object->GetClass(), Object);
Info.GetReturnValue().Set(Result);
}
else
{
Info.GetReturnValue().Set(v8::Undefined(Isolate));
}
}
else
{
FV8Utils::ThrowException(Isolate, "invalid argument");
}
}
void FStructWrapper::Load(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
FStructWrapper* This = reinterpret_cast<FStructWrapper*>((v8::Local<v8::External>::Cast(Info.Data()))->Value());
if (!This->Struct.IsValid())
{
FV8Utils::ThrowException(Isolate, "Associated UStruct had been GC");
return;
}
UClass* Class = Cast<UClass>(This->Struct);
if (Class && Info.Length() > 0 && Info[0]->IsString())
{
bool UnEscape = false;
if (Info.Length() > 1)
{
UnEscape = Info[1]->BooleanValue(Isolate);
}
auto Path = FV8Utils::ToFString(Isolate, Info[0]);
auto Object =
StaticLoadObject(Class, nullptr, UnEscape ? *TypeScriptVariableNameToFilename(Path) : *Path, nullptr, LOAD_NoWarn);
if (Object)
{
auto Result = FV8Utils::IsolateData<IObjectMapper>(Isolate)->FindOrAdd(Isolate, Context, Object->GetClass(), Object);
Info.GetReturnValue().Set(Result);
}
else
{
Info.GetReturnValue().Set(v8::Undefined(Isolate));
}
}
else
{
FV8Utils::ThrowException(Isolate, "invalid argument");
}
}
void FScriptStructWrapper::New(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
FScriptStructWrapper* This = reinterpret_cast<FScriptStructWrapper*>((v8::Local<v8::External>::Cast(Info.Data()))->Value());
if (!This->Struct.IsValid())
{
FV8Utils::ThrowException(Isolate, "Associated UStruct had been GC");
return;
}
This->New(Isolate, Context, Info);
}
void FScriptStructWrapper::New(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const v8::FunctionCallbackInfo<v8::Value>& Info)
{
if (Info.IsConstructCall())
{
auto Self = Info.This();
void* Memory = nullptr;
{
if (ExternalInitialize)
{
Memory = ExternalInitialize(Info);
if (!Memory) // do not bind nullptr
{
return;
}
}
else
{
Memory = Alloc(static_cast<UScriptStruct*>(Struct.Get()));
const int Count = Info.Length() < Properties.size() ? Info.Length() : Properties.size();
for (int i = 0; i < Count; ++i)
{
Properties[i]->JsToUEInContainer(Isolate, Context, Info[i], Memory, false);
}
}
}
FV8Utils::IsolateData<IObjectMapper>(Isolate)->BindStruct(this, Memory, Self, false);
}
else
{
FV8Utils::ThrowException(Isolate, "only call as Construct is supported!");
}
}
void* FScriptStructWrapper::Alloc(UScriptStruct* InScriptStruct)
{
void* ScriptStructMemory = new char[InScriptStruct->GetStructureSize()];
InScriptStruct->InitializeStruct(ScriptStructMemory);
return ScriptStructMemory;
}
void FScriptStructWrapper::Free(TWeakObjectPtr<UStruct> InStruct, pesapi_finalize InExternalFinalize, void* Ptr)
{
if (InExternalFinalize)
{
InExternalFinalize(Ptr, nullptr, nullptr);
}
else
{
if (InStruct.IsValid())
InStruct->DestroyStruct(Ptr);
delete[] static_cast<char*>(Ptr);
}
}
void FScriptStructWrapper::OnGarbageCollectedWithFree(const v8::WeakCallbackInfo<FScriptStructWrapper>& Data)
{
FScriptStructWrapper* ScriptStructWrapper = Data.GetParameter();
void* ScriptStructMemory = DataTransfer::MakeAddressWithHighPartOfTwo(Data.GetInternalField(0), Data.GetInternalField(1));
FV8Utils::IsolateData<IObjectMapper>(Data.GetIsolate())->UnBindStruct(ScriptStructWrapper, ScriptStructMemory);
Free(ScriptStructWrapper->Struct, ScriptStructWrapper->ExternalFinalize, ScriptStructMemory);
}
void FScriptStructWrapper::OnGarbageCollected(const v8::WeakCallbackInfo<FScriptStructWrapper>& Data)
{
void* ScriptStructMemory = DataTransfer::MakeAddressWithHighPartOfTwo(Data.GetInternalField(0), Data.GetInternalField(1));
FV8Utils::IsolateData<IObjectMapper>(Data.GetIsolate())->UnBindStruct(Data.GetParameter(), ScriptStructMemory);
}
void FClassWrapper::OnGarbageCollected(const v8::WeakCallbackInfo<UClass>& Data)
{
FV8Utils::IsolateData<IObjectMapper>(Data.GetIsolate())
->UnBind(Data.GetParameter(), reinterpret_cast<UObject*>(DataTransfer::MakeAddressWithHighPartOfTwo(
Data.GetInternalField(0), Data.GetInternalField(1))));
}
void FClassWrapper::New(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
FClassWrapper* This = reinterpret_cast<FClassWrapper*>((v8::Local<v8::External>::Cast(Info.Data()))->Value());
if (!This->Struct.IsValid())
{
FV8Utils::ThrowException(Isolate, "Associated UStruct had been GC");
return;
}
This->New(Isolate, Context, Info);
}
void FClassWrapper::New(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const v8::FunctionCallbackInfo<v8::Value>& Info)
{
if (Info.IsConstructCall())
{
auto Self = Info.This();
UObject* Object = nullptr;
auto Class = static_cast<UClass*>(Struct.Get());
{
UObject* Outer = GetTransientPackage();
FName Name = NAME_None;
EObjectFlags ObjectFlags = RF_NoFlags;
if (Info.Length() > 0)
{
Outer = FV8Utils::GetUObject(Context, Info[0]);
if (FV8Utils::IsReleasedPtr(Outer))
{
FV8Utils::ThrowException(Isolate, "passing a invalid object");
return;
}
}
if (Info.Length() > 1)
{
Name = FName(*FV8Utils::ToFString(Isolate, Info[1]));
}
if (Info.Length() > 2)
{
ObjectFlags = (EObjectFlags) (Info[2]->Int32Value(Context).ToChecked());
}
Object = NewObject<UObject>(Outer, Class, Name, ObjectFlags);
}
FV8Utils::IsolateData<IObjectMapper>(Isolate)->Bind(this, Object, Self);
}
else
{
FV8Utils::ThrowException(Isolate, "only call as Construct is supported!");
}
}
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,141 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include <memory>
#include <vector>
#include <map>
#include "CoreMinimal.h"
#include "CoreUObject.h"
#include "PropertyTranslator.h"
#include "FunctionTranslator.h"
#include "JSClassRegister.h"
#include "NamespaceDef.h"
#define PUERTS_REUSE_STRUCTWRAPPER_FUNCTIONTEMPLATE 1
namespace PUERTS_NAMESPACE
{
class FStructWrapper
{
public:
explicit FStructWrapper(UStruct* InStruct) : ExternalInitialize(nullptr), ExternalFinalize(nullptr), Struct(InStruct)
{
}
FORCEINLINE void Init(UStruct* InStruct, bool IsReuseTemplate)
{
Struct = InStruct;
if (!IsReuseTemplate)
{
ExternalInitialize = nullptr;
ExternalFinalize = nullptr;
Properties.clear();
ExtensionMethods.clear();
#if PUERTS_REUSE_STRUCTWRAPPER_FUNCTIONTEMPLATE
CachedFunctionTemplate.Reset();
#endif
}
}
void AddExtensionMethods(const std::vector<UFunction*>& InExtensionMethods);
#if PUERTS_REUSE_STRUCTWRAPPER_FUNCTIONTEMPLATE
v8::UniquePersistent<v8::FunctionTemplate> CachedFunctionTemplate;
#endif
protected:
std::vector<std::shared_ptr<FPropertyTranslator>> Properties;
TMap<FName, std::shared_ptr<FPropertyTranslator>> PropertiesMap;
std::shared_ptr<FPropertyTranslator> GetPropertyTranslator(PropertyMacro* InProperty);
TMap<FName, std::shared_ptr<FFunctionTranslator>> FunctionsMap;
TMap<FName, std::shared_ptr<FFunctionTranslator>> MethodsMap;
std::shared_ptr<FFunctionTranslator> GetFunctionTranslator(UFunction* InFunction);
std::shared_ptr<FFunctionTranslator> GetMethodTranslator(UFunction* InFunction, bool IsExtension);
void RefreshMethod(UFunction* InFunction);
void InitTemplateProperties(
v8::Isolate* Isolate, UStruct* InStruct, v8::Local<v8::FunctionTemplate> Template, bool IsReuseTemplate);
v8::Local<v8::FunctionTemplate> ToFunctionTemplate(v8::Isolate* Isolate, v8::FunctionCallback Construtor);
std::vector<UFunction*> ExtensionMethods;
typedef void* (*V8InitializeFuncType)(const v8::FunctionCallbackInfo<v8::Value>& Info);
V8InitializeFuncType ExternalInitialize;
pesapi_finalize ExternalFinalize;
TWeakObjectPtr<UStruct> Struct;
#if PUERTS_KEEP_UOBJECT_REFERENCE
bool IsNativeTakeJsRef = false;
#else
bool IsNativeTakeJsRef = true;
#endif
bool IsTypeScriptGeneratedClass = false;
static void StaticClass(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Find(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Load(const v8::FunctionCallbackInfo<v8::Value>& Info);
friend class FJsEnvImpl;
};
class FScriptStructWrapper : public FStructWrapper
{
public:
explicit FScriptStructWrapper(UScriptStruct* InScriptStruct) : FStructWrapper(InScriptStruct)
{
}
static void OnGarbageCollectedWithFree(const v8::WeakCallbackInfo<FScriptStructWrapper>& Data);
static void OnGarbageCollected(const v8::WeakCallbackInfo<FScriptStructWrapper>& Data);
static void* Alloc(UScriptStruct* InScriptStruct);
static void Free(TWeakObjectPtr<UStruct> InStruct, pesapi_finalize InExternalFinalize, void* Ptr);
void Free(void* Ptr)
{
Free(Struct, ExternalFinalize, Ptr);
}
static void New(const v8::FunctionCallbackInfo<v8::Value>& Info);
void New(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const v8::FunctionCallbackInfo<v8::Value>& Info);
};
class FClassWrapper : public FStructWrapper
{
public:
explicit FClassWrapper(UClass* InClass) : FStructWrapper(InClass)
{
}
static void OnGarbageCollected(const v8::WeakCallbackInfo<UClass>& Data);
static void New(const v8::FunctionCallbackInfo<v8::Value>& Info);
void New(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const v8::FunctionCallbackInfo<v8::Value>& Info);
};
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,11 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "TypeScriptBlueprint.h"
#include "TypeScriptGeneratedClass.h"
#if WITH_EDITOR
UClass* UTypeScriptBlueprint::GetBlueprintClass() const
{
return UTypeScriptGeneratedClass::StaticClass();
}
#endif
@@ -0,0 +1,294 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "TypeScriptGeneratedClass.h"
#include "Runtime/Launch/Resources/Version.h"
#include "PropertyMacros.h"
#include "JSGeneratedFunction.h"
#include "JSLogger.h"
DEFINE_FUNCTION(UTypeScriptGeneratedClass::execCallJS)
{
UFunction* Func = Stack.CurrentNativeFunction ? Stack.CurrentNativeFunction : Stack.Node;
check(Func);
// UE_LOG(LogTemp, Warning, TEXT("overrided function called, %s(%p)"), *Func->GetName(), Func);
UTypeScriptGeneratedClass* Class = Cast<UTypeScriptGeneratedClass>(Func->GetOuter());
if (Class)
{
#if WITH_EDITOR
if (Context)
{
UTypeScriptGeneratedClass* ClassMayNeedReBind = nullptr;
auto TempClass = Context->GetClass();
while (TempClass && (TempClass != Class) && (!ClassMayNeedReBind || !ClassMayNeedReBind->NeedReBind))
{
ClassMayNeedReBind = Cast<UTypeScriptGeneratedClass>(TempClass);
TempClass = TempClass->GetSuperClass();
}
if (ClassMayNeedReBind)
{
NotifyRebind(ClassMayNeedReBind);
}
}
#endif
auto PinedDynamicInvoker = Class->DynamicInvoker.Pin();
if (PinedDynamicInvoker)
{
PinedDynamicInvoker->InvokeTsMethod(Context, Func, Stack, RESULT_PARAM);
}
else
{
UE_LOG(Puerts, Error, TEXT("call %s::%s fail!, DynamicInvoker invalid"), *Class->GetName(), *Func->GetName());
}
}
else
{
UE_LOG(Puerts, Error, TEXT("calling a not ts class method %s::%s"), *Func->GetOuter()->GetName(), *Func->GetName());
}
}
DEFINE_FUNCTION(UTypeScriptGeneratedClass::execLazyLoadCallJS)
{
UFunction* Function = Stack.CurrentNativeFunction ? Stack.CurrentNativeFunction : Stack.Node;
check(Function);
auto Class = Cast<UTypeScriptGeneratedClass>(Function->GetOuterUClassUnchecked());
#if !WITH_EDITOR
auto PinedDynamicInvoker = Class->DynamicInvoker.Pin();
if (PinedDynamicInvoker)
{
PinedDynamicInvoker->NotifyReBind(Class);
}
#else
NotifyRebind(Context ? Context->GetClass() : Class);
#endif
Class->RestoreNativeFunc();
execCallJS(Context, Stack, RESULT_PARAM);
}
#if WITH_EDITOR
void UTypeScriptGeneratedClass::NotifyRebind(UClass* Class)
{
if (Class->ClassConstructor == &UTypeScriptGeneratedClass::StaticConstructor)
{
while (Class)
{
if (UTypeScriptGeneratedClass* TsClass = Cast<UTypeScriptGeneratedClass>(Class))
{
if (TsClass->NeedReBind && TsClass->DynamicInvoker.IsValid())
{
TsClass->NeedReBind = false;
UTypeScriptGeneratedClass* CachedClass = TsClass;
Class = Class->GetSuperClass();
while (Class)
{
if (UTypeScriptGeneratedClass* SuperTsClass = Cast<UTypeScriptGeneratedClass>(Class))
{
SuperTsClass->NeedReBind = false;
}
Class = Class->GetSuperClass();
}
CachedClass->DynamicInvoker.Pin()->NotifyReBind(CachedClass);
}
return;
}
Class = Class->GetSuperClass();
}
}
}
void UTypeScriptGeneratedClass::LazyLoadRedirect()
{
for (TFieldIterator<UFunction> FuncIt(this, EFieldIteratorFlags::ExcludeSuper); FuncIt; ++FuncIt)
{
auto Function = *FuncIt;
if (!FunctionToRedirect.Contains(Function->GetFName()))
{
continue;
}
Function->FunctionFlags |= FUNC_BlueprintCallable | FUNC_BlueprintEvent | FUNC_Public | FUNC_Native;
Function->SetNativeFunc(&UTypeScriptGeneratedClass::execLazyLoadCallJS);
AddNativeFunction(*Function->GetName(), &UTypeScriptGeneratedClass::execLazyLoadCallJS);
}
}
#endif
void UTypeScriptGeneratedClass::StaticConstructor(const FObjectInitializer& ObjectInitializer)
{
auto Class = ObjectInitializer.GetClass();
//蓝图继承ts类,既然进了这里,表明链上必然有ts类,由于目前不支持ts继承蓝图,所以顶部节点往下找的第一个UTypeScriptGeneratedClass就是本类
while (Class)
{
if (auto TypeScriptGeneratedClass = Cast<UTypeScriptGeneratedClass>(Class))
{
TypeScriptGeneratedClass->ObjectInitialize(ObjectInitializer);
break;
}
Class = Class->GetSuperClass();
}
}
void UTypeScriptGeneratedClass::RestoreNativeFunc()
{
for (auto& KV : TempNativeFuncStorage)
{
if (!FunctionToRedirect.Contains(KV.Key))
{
auto Function = FindFunctionByName(KV.Key, EIncludeSuperFlag::ExcludeSuper);
if (Function)
{
Function->SetNativeFunc(KV.Value);
AddNativeFunction(*Function->GetName(), KV.Value);
}
}
}
TempNativeFuncStorage.Empty();
}
void UTypeScriptGeneratedClass::ObjectInitialize(const FObjectInitializer& ObjectInitializer)
{
auto Object = ObjectInitializer.GetObj();
if (auto SuperTypeScriptGeneratedClass = Cast<UTypeScriptGeneratedClass>(GetSuperClass()))
{
SuperTypeScriptGeneratedClass->ObjectInitialize(ObjectInitializer);
}
else
{
GetSuperClass()->ClassConstructor(ObjectInitializer);
}
#if !WITH_EDITOR
if (Object->HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))
return;
#endif
auto PinedDynamicInvoker = DynamicInvoker.Pin();
if (PinedDynamicInvoker)
{
#ifdef THREAD_SAFE
PinedDynamicInvoker->TsConstruct(this, Object);
#else
if (IsInGameThread())
{
PinedDynamicInvoker->TsConstruct(this, Object);
}
#endif
}
else
{
UE_LOG(Puerts, Error, TEXT("call TsConstruct of %s(%p) fail!, DynamicInvoker invalid"), *Object->GetName(), Object);
}
if (UNLIKELY(!RedirectedToTypeScript))
{
for (TFieldIterator<UFunction> FuncIt(this, EFieldIteratorFlags::ExcludeSuper); FuncIt; ++FuncIt)
{
auto Function = *FuncIt;
if (!Function->IsNative() && Function->HasAnyFunctionFlags(FUNC_Public))
{
TempNativeFuncStorage.Add(Function->GetFName(), Function->GetNativeFunc());
Function->FunctionFlags |= FUNC_Native;
Function->SetNativeFunc(&UTypeScriptGeneratedClass::execLazyLoadCallJS);
AddNativeFunction(*Function->GetName(), &UTypeScriptGeneratedClass::execLazyLoadCallJS);
}
}
RedirectedToTypeScript = true;
}
}
void UTypeScriptGeneratedClass::RedirectToTypeScript(UFunction* InFunction)
{
if (!FunctionToRedirect.Contains(InFunction->GetFName()))
{
return;
}
InFunction->FunctionFlags |= FUNC_BlueprintCallable | FUNC_BlueprintEvent | FUNC_Public;
InFunction->SetNativeFunc(&UTypeScriptGeneratedClass::execCallJS);
AddNativeFunction(*InFunction->GetName(), &UTypeScriptGeneratedClass::execCallJS);
}
void UTypeScriptGeneratedClass::RedirectToTypeScriptFinish()
{
for (TFieldIterator<UFunction> FuncIt(this, EFieldIteratorFlags::ExcludeSuper); FuncIt; ++FuncIt)
{
auto Function = *FuncIt;
if (!FunctionToRedirect.Contains(Function->GetFName()))
{
continue;
}
Function->FunctionFlags |= FUNC_BlueprintCallable | FUNC_BlueprintEvent | FUNC_Public | FUNC_Native;
}
}
void UTypeScriptGeneratedClass::CancelRedirection()
{
for (TFieldIterator<UFunction> FuncIt(this, EFieldIteratorFlags::ExcludeSuper); FuncIt; ++FuncIt)
{
auto Function = *FuncIt;
if (!FunctionToRedirect.Contains(Function->GetFName()))
{
continue;
}
Function->FunctionFlags &= ~FUNC_Native;
// Function->SetNativeFunc(ProcessInternal);
Function->Bind(); // the same as Function->SetNativeFunc(ProcessInternal) if no native
NativeFunctionLookupTable.RemoveAll(
[=](const FNativeFunctionLookup& NativeFunctionLookup) { return Function->GetFName() == NativeFunctionLookup.Name; });
}
}
bool UTypeScriptGeneratedClass::NotSupportInject()
{
return (GetName().StartsWith("SKEL_") || GetName().StartsWith("REINST_") || GetName().StartsWith("TRASHCLASS_") ||
GetName().StartsWith("PLACEHOLDER-") || GetName().StartsWith("HOTRELOADED_"));
}
void UTypeScriptGeneratedClass::Bind()
{
if (GetName().StartsWith("REINST_"))
{
for (TFieldIterator<UFunction> FuncIt(this, EFieldIteratorFlags::ExcludeSuper); FuncIt; ++FuncIt)
{
auto Function = *FuncIt;
Function->FunctionFlags &= ~FUNC_Native;
}
}
Super::Bind();
if (NotSupportInject())
{
return;
}
if (HasConstructor)
{
//普通对象会从CDO拷贝,而CDO会从蓝图AR那反序列化(见UBlueprintGeneratedClass::SerializeDefaultObject),这会
//导致TS的构造函数对生成的蓝图变量赋值都失效,不太符合程序员直觉,设置CPF_SkipSerialization可以跳过这个过程。
//然而在构造对象还有一个PostConstructInit步骤,里头有个从基类的CDO拷贝值的过程(ps:UE对象构造巨复杂,对象巨大)
//这个过程如果是CDO的话,目前只找到把属性的flag设置为CPF_Transient | CPF_InstancedReference才能搞定
// TODO: 后续尝试下TypeScript生成类不继承UBlueprintGeneratedClass的实现,能实现的话优雅些
for (TFieldIterator<PropertyMacro> PropertyIt(this, EFieldIteratorFlags::ExcludeSuper); PropertyIt; ++PropertyIt)
{
PropertyMacro* Property = *PropertyIt;
Property->SetPropertyFlags(CPF_SkipSerialization | CPF_Transient | CPF_InstancedReference);
}
//可避免非CDO的在PostConstructInit从基类拷贝值
// ClassFlags |= CLASS_Native;
}
#if WITH_EDITOR
if (DynamicInvoker.IsValid())
#endif
{
ClassConstructor = &StaticConstructor;
}
}
@@ -0,0 +1,606 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
// TODO: 静态库11.8 window调试崩溃
#if defined(UE_GAME) || defined(UE_EDITOR) || defined(UE_SERVER) || defined(USING_IN_UNREAL_ENGINE)
#define USING_UE 1
#else
#define USING_UE 0
#endif
#if (PLATFORM_WINDOWS || PLATFORM_MAC || PLATFORM_LINUX || defined(WITH_INSPECTOR)) && !defined(WITHOUT_INSPECTOR)
#include "V8InspectorImpl.h"
#if USING_UE
#include "UECompatible.h"
#endif
#include <functional>
#include <string>
#include <locale>
#include <codecvt>
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#pragma warning(push)
#if defined(_MSC_VER)
#pragma warning(disable : 4251)
#endif
#include "v8.h"
#include "v8-inspector.h"
#include "libplatform/libplatform.h"
#pragma warning(pop)
#define ASIO_NO_TYPEID // UE需避免使用RTTI功能
#define ASIO_STANDALONE
#define _WEBSOCKETPP_CPP11_TYPE_TRAITS_
#include "websocketpp/config/asio_no_tls.hpp"
#include "websocketpp/server.hpp"
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
#if USING_UE
#include "Containers/Ticker.h"
#else
#include "Log.h"
#endif
#if USING_UE
DEFINE_LOG_CATEGORY_STATIC(LogV8Inspector, Log, All);
#endif
namespace PUERTS_NAMESPACE
{
class V8InspectorChannelImpl : public v8_inspector::V8Inspector::Channel, public V8InspectorChannel
{
public:
V8InspectorChannelImpl(v8::Isolate* InIsolate, v8_inspector::V8Inspector* InV8Inspector, const int32_t InCxtGroupID);
void DispatchProtocolMessage(const std::string& Message) override;
void OnMessage(std::function<void(const std::string&)> Handler) override;
virtual ~V8InspectorChannelImpl() override
{
OnSendMessage = nullptr;
}
private:
void SendMessage(v8_inspector::StringBuffer& MessageBuffer);
void sendResponse(int CallID, std::unique_ptr<v8_inspector::StringBuffer> Message) override;
void sendNotification(std::unique_ptr<v8_inspector::StringBuffer> Message) override;
void flushProtocolNotifications() override
{
}
std::unique_ptr<v8_inspector::V8InspectorSession> V8InspectorSession;
std::function<void(const std::string&)> OnSendMessage;
v8::Isolate* Isolate;
};
V8InspectorChannelImpl::V8InspectorChannelImpl(
v8::Isolate* InIsolate, v8_inspector::V8Inspector* InV8Inspector, const int32_t InCxtGroupID)
{
v8_inspector::StringView DummyState;
Isolate = InIsolate;
#if V8_MAJOR_VERSION >= 10
V8InspectorSession = InV8Inspector->connect(InCxtGroupID, this, DummyState, v8_inspector::V8Inspector::kFullyTrusted);
#else
V8InspectorSession = InV8Inspector->connect(InCxtGroupID, this, DummyState);
#endif
}
void V8InspectorChannelImpl::DispatchProtocolMessage(const std::string& Message)
{
const auto MessagePtr = reinterpret_cast<const uint8_t*>(Message.c_str());
const auto MessageLen = (size_t) Message.length();
v8_inspector::StringView StringView(MessagePtr, MessageLen);
#ifdef THREAD_SAFE
v8::Locker Locker(Isolate);
#endif
v8::Isolate::Scope IsolateScope(Isolate);
v8::SealHandleScope HandleScope(Isolate);
V8InspectorSession->dispatchProtocolMessage(StringView);
}
void V8InspectorChannelImpl::OnMessage(std::function<void(const std::string&)> Handler)
{
OnSendMessage = Handler;
}
void V8InspectorChannelImpl::SendMessage(v8_inspector::StringBuffer& MessageBuffer)
{
v8_inspector::StringView MessageView = MessageBuffer.string();
std::string Message;
if (MessageView.is8Bit())
{
Message = reinterpret_cast<const char*>(MessageView.characters8());
}
else
{
#if PLATFORM_WINDOWS
#pragma warning(disable : 4996)
std::wstring_convert<std::codecvt_utf8_utf16<uint16_t>, uint16_t> Conv;
const uint16_t* Start = MessageView.characters16();
#else
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> Conv;
const char16_t* Start = reinterpret_cast<const char16_t*>(MessageView.characters16());
#endif
Message = Conv.to_bytes(Start, Start + MessageView.length());
}
if (OnSendMessage)
OnSendMessage(Message);
}
void V8InspectorChannelImpl::sendResponse(int /* CallID */, std::unique_ptr<v8_inspector::StringBuffer> Message)
{
SendMessage(*Message);
}
void V8InspectorChannelImpl::sendNotification(std::unique_ptr<v8_inspector::StringBuffer> Message)
{
SendMessage(*Message);
}
class V8InspectorClientImpl : public V8Inspector,
#if USING_UE
#if ENGINE_MAJOR_VERSION >= 5
public FTSTickerObjectBase,
#else
public FTickerObjectBase,
#endif
#endif
public v8_inspector::V8InspectorClient
{
public:
using wspp_server = websocketpp::server<websocketpp::config::asio>;
using wspp_connection_hdl = websocketpp::connection_hdl;
using wspp_message_ptr = wspp_server::message_ptr;
using wspp_exception = websocketpp::exception;
V8InspectorClientImpl(int32_t InPort, v8::Local<v8::Context> InContext);
virtual ~V8InspectorClientImpl();
void Close() override;
#if USING_UE
bool Tick(float DeltaTime) override;
#else
bool Tick(float DeltaTime);
#endif
bool Tick() override;
V8InspectorChannel* CreateV8InspectorChannel() override;
private:
void OnHTTP(wspp_connection_hdl Handle);
void OnOpen(wspp_connection_hdl Handle);
void OnReceiveMessage(wspp_connection_hdl Handle, wspp_message_ptr Message);
void OnSendMessage(wspp_connection_hdl Handle, const std::string& Message);
void OnClose(wspp_connection_hdl Handle);
void OnFail(wspp_connection_hdl Handle);
void runMessageLoopOnPause(int ContextGroupId) override;
void quitMessageLoopOnPause() override;
void runIfWaitingForDebugger(int ContextGroupId) override
{
Connected = true;
}
v8::Isolate* Isolate;
v8::Persistent<v8::Context> Context;
v8::Persistent<v8::Function> MicroTasksRunner;
int32_t Port;
#if defined(V8_HAS_WRAP_API_WITHOUT_STL)
v8_inspector::V8Inspector* V8Inspector;
#else
std::unique_ptr<v8_inspector::V8Inspector> V8Inspector;
#endif
int32_t CtxGroupID;
std::map<void*, V8InspectorChannelImpl*> V8InspectorChannels;
wspp_server Server;
std::string JSONVersion;
std::string JSONList;
bool IsAlive;
bool IsPaused;
bool Connected;
};
#if USING_UE
void ReportException(const websocketpp::exception& Exception, const TCHAR* JobInfo)
{
#if PLATFORM_WINDOWS
int len = MultiByteToWideChar(CP_ACP, 0, Exception.what(), -1, NULL, 0);
wchar_t* wstr = new wchar_t[len + 1];
memset(wstr, 0, len + 1);
MultiByteToWideChar(CP_ACP, 0, Exception.what(), -1, wstr, len);
len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
char* str = new char[len + 1];
memset(str, 0, len + 1);
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
delete[] wstr;
UE_LOG(LogV8Inspector, Warning, TEXT("%s, errno:%d, message:%s"), JobInfo, Exception.code().value(), UTF8_TO_TCHAR(str));
delete[] str;
#else
UE_LOG(LogV8Inspector, Warning, TEXT("%s, errno:%d, message:%s"), JobInfo, Exception.code().value(),
ANSI_TO_TCHAR(Exception.what()));
#endif
}
#endif
void MicroTasksRunnerFunction(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
// throw an error so the v8 will clean pending exception later
Info.GetIsolate()->ThrowException(
v8::Exception::Error(v8::String::NewFromUtf8(Info.GetIsolate(), "test", v8::NewStringType::kNormal).ToLocalChecked()));
}
V8InspectorClientImpl::V8InspectorClientImpl(int32_t InPort, v8::Local<v8::Context> InContext)
#if USING_UE
#if ENGINE_MAJOR_VERSION >= 5
: FTSTickerObjectBase(0.001f)
#else
: FTickerObjectBase(0.001f)
#endif
#endif
{
Isolate = InContext->GetIsolate();
Context.Reset(Isolate, InContext);
MicroTasksRunner.Reset(
Isolate, v8::FunctionTemplate::New(Isolate, MicroTasksRunnerFunction)->GetFunction(InContext).ToLocalChecked());
Port = InPort;
IsAlive = false;
Connected = false;
static int32_t CurrentCtxGroupID = 1;
CtxGroupID = CurrentCtxGroupID++;
const uint8_t CtxNameConst[] = "V8InspectorContext";
v8_inspector::StringView CtxName(CtxNameConst, sizeof(CtxNameConst) - 1);
#if defined(V8_HAS_WRAP_API_WITHOUT_STL)
V8Inspector = V8Inspector_Create_Without_Stl(Isolate, this);
#else
V8Inspector = v8_inspector::V8Inspector::create(Isolate, this);
#endif
V8Inspector->contextCreated(v8_inspector::V8ContextInfo(InContext, CtxGroupID, CtxName));
if (Port < 0)
return;
try
{
Server.set_reuse_addr(true);
Server.set_access_channels(websocketpp::log::alevel::none);
Server.set_error_channels(websocketpp::log::elevel::none);
Server.set_http_handler(std::bind(&V8InspectorClientImpl::OnHTTP, this, std::placeholders::_1));
Server.set_open_handler(std::bind(&V8InspectorClientImpl::OnOpen, this, std::placeholders::_1));
Server.set_message_handler(
std::bind(&V8InspectorClientImpl::OnReceiveMessage, this, std::placeholders::_1, std::placeholders::_2));
Server.set_close_handler(std::bind(&V8InspectorClientImpl::OnClose, this, std::placeholders::_1));
Server.set_fail_handler(std::bind(&V8InspectorClientImpl::OnFail, this, std::placeholders::_1));
Server.init_asio();
Server.listen(Port);
Server.start_accept();
JSONVersion = R"({
"Browser": "Puerts/v1.0.0",
"Protocol-Version": "1.1"
})";
JSONList = R"([{
"description": "Puerts Inspector",
"id": "0",
"title": "Puerts Inspector",
"type": "node",
)";
JSONList += "\"webSocketDebuggerUrl\"";
JSONList += ":";
JSONList += "\"ws://127.0.0.1:";
JSONList += std::to_string(Port) + "\"\r\n}]";
IsAlive = true;
#if USING_UE
FString InspectorUrl =
FString::Printf(TEXT("devtools://devtools/bundled/inspector.html?v8only=true&ws=127.0.0.1:%d"), Port);
UE_LOG(LogV8Inspector, Log,
TEXT("Startup Inspector Successfully!\n"
"Please Open This URL in Debugger Front-End(e.g. Chrome DevTool):\n \n"
"\t%s\n \n"),
*InspectorUrl);
#endif
}
catch (const websocketpp::exception& Exception)
{
IsAlive = false;
#if USING_UE
ReportException(Exception, TEXT("Failed to Startup Inspector"));
#else
puerts::PLog(puerts::Error, "V8InspectorClientImpl: %s", Exception.what());
puerts::PLog(puerts::Error, "Failed to Startup Inspector.");
#endif
}
IsPaused = false;
}
V8InspectorChannel* V8InspectorClientImpl::CreateV8InspectorChannel()
{
#if defined(V8_HAS_WRAP_API_WITHOUT_STL)
return new V8InspectorChannelImpl(Isolate, V8Inspector, CtxGroupID);
#else
return new V8InspectorChannelImpl(Isolate, V8Inspector.get(), CtxGroupID);
#endif
}
V8InspectorClientImpl::~V8InspectorClientImpl()
{
Close();
#if defined(V8_HAS_WRAP_API_WITHOUT_STL)
v8_inspector::V8Inspector_Destroy_Without_Stl(V8Inspector);
#endif
}
void V8InspectorClientImpl::Close()
{
if (IsAlive)
{
#ifdef THREAD_SAFE
v8::Locker Locker(Isolate);
#endif
Server.stop_listening();
for (auto Iter = V8InspectorChannels.begin(); Iter != V8InspectorChannels.end(); ++Iter)
{
delete Iter->second;
}
V8InspectorChannels.clear();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
V8Inspector->contextDestroyed(Context.Get(Isolate));
IsAlive = false;
IsPaused = false;
}
}
bool V8InspectorClientImpl::Tick(float /* DeltaTime */)
{
try
{
if (IsAlive)
{
#ifdef THREAD_SAFE
v8::Locker Locker(Isolate);
#endif
{
// v8::Locker lock(Isolate);
Server.poll();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
auto LocalContext = Context.Get(Isolate);
v8::Context::Scope ContextScope(LocalContext);
v8::TryCatch TryCatch(Isolate);
MicroTasksRunner.Get(Isolate)->Call(LocalContext, LocalContext->Global(), 0, nullptr);
}
}
}
catch (const wspp_exception& Exception)
{
#if USING_UE
ReportException(Exception, TEXT("Tick"));
#else
puerts::PLog(puerts::Error, "Tick: %s", Exception.what());
#endif
}
return true;
}
bool V8InspectorClientImpl::Tick()
{
Tick(0);
return IsAlive && Connected;
}
void V8InspectorClientImpl::OnHTTP(wspp_connection_hdl Handle)
{
try
{
auto Connection = Server.get_con_from_hdl(Handle);
auto Resource = Connection->get_resource();
if (Resource == "/json" || Resource == "/json/list")
{
#if USING_UE
UE_LOG(LogV8Inspector, Display, TEXT("request /json/list"));
#else
puerts::PLog(puerts::Log, "request /json/list");
#endif
Connection->set_body(JSONList);
Connection->set_status(websocketpp::http::status_code::ok);
}
else if (Resource == "/json/version")
{
#if USING_UE
UE_LOG(LogV8Inspector, Display, TEXT("request /json/version"));
#else
puerts::PLog(puerts::Log, "request /json/version");
#endif
Connection->set_body(JSONVersion);
Connection->set_status(websocketpp::http::status_code::ok);
}
else
{
#if USING_UE
UE_LOG(LogV8Inspector, Display, TEXT("404 Not Found"));
#else
puerts::PLog(puerts::Log, "404 Not Found");
#endif
Connection->set_body("404 Not Found");
Connection->set_status(websocketpp::http::status_code::not_found);
}
}
catch (const wspp_exception& Exception)
{
#if USING_UE
ReportException(Exception, TEXT("OnHTTP"));
#else
puerts::PLog(puerts::Error, "OnHTTP: %s", Exception.what());
#endif
}
}
void V8InspectorClientImpl::OnOpen(wspp_connection_hdl Handle)
{
V8InspectorChannelImpl* channel = static_cast<V8InspectorChannelImpl*>(CreateV8InspectorChannel());
V8InspectorChannels[Handle.lock().get()] = channel;
channel->OnMessage(std::bind(&V8InspectorClientImpl::OnSendMessage, this, Handle, std::placeholders::_1));
#if USING_UE
UE_LOG(LogV8Inspector, Display, TEXT("Inspector: Connect"));
#else
puerts::PLog(puerts::Log, "Inspector: Connect");
#endif
}
void V8InspectorClientImpl::OnReceiveMessage(wspp_connection_hdl Handle, wspp_message_ptr Message)
{
//#if USING_UE
// UE_LOG(LogV8Inspector, Display, TEXT("<---: %s"), ANSI_TO_TCHAR(Message->get_payload().c_str()));
//#else
// puerts::PLog(puerts::Log, "<---: %s", Message->get_payload().c_str());
//#endif
auto channel = V8InspectorChannels[Handle.lock().get()];
{
// v8::Locker Locker(Isolate);
v8::Isolate::Scope IsolateScope(Isolate);
v8::SealHandleScope scope(Isolate);
channel->DispatchProtocolMessage(Message->get_payload());
}
}
void V8InspectorClientImpl::OnSendMessage(wspp_connection_hdl Handle, const std::string& Message)
{
//#if USING_UE
// UE_LOG(LogV8Inspector, Display, TEXT("--->: %s"), ANSI_TO_TCHAR(Message.c_str()));
//#else
// puerts::PLog(puerts::Log, "--->: %s", Message.c_str());
//#endif
try
{
Server.send(Handle, Message, websocketpp::frame::opcode::TEXT);
}
catch (const websocketpp::exception& Exception)
{
#if USING_UE
ReportException(Exception, TEXT("OnSendMessage"));
#else
puerts::PLog(puerts::Error, "OnSendMessage: %s", Exception.what());
#endif
}
}
void V8InspectorClientImpl::OnClose(wspp_connection_hdl Handle)
{
void* HandlePtr = Handle.lock().get();
delete V8InspectorChannels[HandlePtr];
V8InspectorChannels.erase(HandlePtr);
#if USING_UE
UE_LOG(LogV8Inspector, Display, TEXT("Inspector: Disconnect"));
#endif
}
void V8InspectorClientImpl::OnFail(wspp_connection_hdl Handle)
{
wspp_server::connection_ptr con = Server.get_con_from_hdl(Handle);
std::string message = con->get_ec().message();
#if USING_UE
UE_LOG(LogV8Inspector, Error, TEXT("Connection OnFail %s"), UTF8_TO_TCHAR(message.c_str()));
#else
puerts::PLog(puerts::Error, "Connection OnFail %s", message.c_str());
#endif
}
void V8InspectorClientImpl::runMessageLoopOnPause(int /* ContextGroupId */)
{
if (IsPaused)
{
return;
}
IsPaused = true;
while (IsPaused)
{
Tick();
}
}
void V8InspectorClientImpl::quitMessageLoopOnPause()
{
IsPaused = false;
}
V8Inspector* CreateV8Inspector(int32_t Port, void* InContextPtr)
{
v8::Local<v8::Context>* ContextPtr = static_cast<v8::Local<v8::Context>*>(InContextPtr);
return new V8InspectorClientImpl(Port, *ContextPtr);
}
}; // namespace PUERTS_NAMESPACE
#else
#include "V8InspectorImpl.h"
namespace PUERTS_NAMESPACE
{
V8Inspector* CreateV8Inspector(int32_t Port, void* InContextPtr)
{
return nullptr;
}
}; // namespace PUERTS_NAMESPACE
#endif // WITH_EDITOR && (PLATFORM_WINDOWS || PLATFORM_MAC)
@@ -0,0 +1,74 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include <stdint.h>
#include <functional>
#include <string>
#if !defined(PUERTS_NAMESPACE)
#if defined(WITH_QJS_NAMESPACE_SUFFIX)
#define PUERTS_NAMESPACE puerts_qjs
#else
#define PUERTS_NAMESPACE puerts
#endif
#endif
#ifndef PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#if defined(_MSC_VER)
#define PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS __pragma(warning(push)) __pragma(warning(disable : 4668))
#elif defined(__clang__)
#define PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS \
_Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wundef\"")
#elif defined(__GNUC__)
#define PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wundef\"")
#endif
#endif // PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#ifndef PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
#if defined(_MSC_VER)
#define PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS __pragma(warning(pop))
#elif defined(__clang__)
#define PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS _Pragma("clang diagnostic pop")
#elif defined(__GNUC__)
#define PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS _Pragma("GCC diagnostic pop")
#endif
#endif // PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
namespace PUERTS_NAMESPACE
{
class V8InspectorChannel
{
public:
virtual void DispatchProtocolMessage(const std::string& Message) = 0;
virtual void OnMessage(std::function<void(const std::string&)> Handler) = 0;
virtual ~V8InspectorChannel()
{
}
};
class V8Inspector
{
public:
virtual void Close() = 0;
virtual bool Tick() = 0;
virtual V8InspectorChannel* CreateV8InspectorChannel() = 0;
virtual ~V8Inspector()
{
}
};
// 接受端口和v8::Local<v8::Context>指针,返回一个新的V8Inspector指针
V8Inspector* CreateV8Inspector(int32_t Port, void* InContextPtr);
}; // namespace PUERTS_NAMESPACE
@@ -0,0 +1,19 @@
#include <V8Utils.h>
v8::Local<v8::String> puerts::FV8Utils::ToV8String(v8::Isolate* Isolate, const TCHAR* String)
{
#ifdef WITH_QUICKJS
return v8::String::NewFromUtf8(Isolate, TCHAR_TO_UTF8(String), v8::NewStringType::kNormal).ToLocalChecked();
#else
return v8::String::NewFromTwoByte(Isolate, TCHAR_TO_UTF16(String), v8::NewStringType::kNormal).ToLocalChecked();
#endif
}
FString puerts::FV8Utils::ToFString(v8::Isolate* Isolate, v8::Local<v8::Value> Value)
{
#ifdef WITH_QUICKJS
return UTF8_TO_TCHAR(*(v8::String::Utf8Value(Isolate, Value)));
#else
return UTF16_TO_TCHAR(*(v8::String::Value(Isolate, Value)));
#endif
}
@@ -0,0 +1,458 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#if defined(WITH_WEBSOCKET)
#include "V8InspectorImpl.h" // for PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#include "V8Utils.h"
#ifndef THIRD_PARTY_INCLUDES_START
#define THIRD_PARTY_INCLUDES_START
#endif
#ifndef THIRD_PARTY_INCLUDES_END
#define THIRD_PARTY_INCLUDES_END
#endif
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#pragma warning(push)
#if defined(_MSC_VER)
#pragma warning(disable : 4251)
#endif
#include "v8.h"
#pragma warning(pop)
#define ASIO_NO_TYPEID // UE需避免使用RTTI功能
#define ASIO_STANDALONE
#define _WEBSOCKETPP_CPP11_TYPE_TRAITS_
#define UI UI_ST
THIRD_PARTY_INCLUDES_START
#if defined(WITH_WEBSOCKET_SSL)
#include <websocketpp/config/asio.hpp>
#else
#include "websocketpp/config/asio_no_tls.hpp"
#endif
#include "websocketpp/client.hpp"
THIRD_PARTY_INCLUDES_END
#undef UI
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
#include <sstream>
namespace PUERTS_NAMESPACE
{
#if !defined(USING_IN_UNREAL_ENGINE)
class DataTransfer
{
public:
static void* GetArrayBufferData(v8::Local<v8::ArrayBuffer> InArrayBuffer)
{
size_t DataLength;
return GetArrayBufferData(InArrayBuffer, DataLength);
}
static void* GetArrayBufferData(v8::Local<v8::ArrayBuffer> InArrayBuffer, size_t& DataLength)
{
#if defined(HAS_ARRAYBUFFER_NEW_WITHOUT_STL)
return v8::ArrayBuffer_Get_Data(InArrayBuffer, DataLength);
#else
#if USING_IN_UNREAL_ENGINE
DataLength = InArrayBuffer->GetContents().ByteLength();
return InArrayBuffer->GetContents().Data();
#else
auto BS = InArrayBuffer->GetBackingStore();
DataLength = BS->ByteLength();
return BS->Data();
#endif
#endif
}
static v8::Local<v8::ArrayBuffer> NewArrayBuffer(v8::Local<v8::Context> Context, void* Data, size_t DataLength)
{
#if defined(HAS_ARRAYBUFFER_NEW_WITHOUT_STL)
return v8::ArrayBuffer_New_Without_Stl(Context->GetIsolate(), Data, DataLength);
#else
#if USING_IN_UNREAL_ENGINE
return v8::ArrayBuffer::New(Context->GetIsolate(), Data, DataLength);
#else
auto Backing = v8::ArrayBuffer::NewBackingStore(Data, DataLength, v8::BackingStore::EmptyDeleter, nullptr);
return v8::ArrayBuffer::New(Context->GetIsolate(), std::move(Backing));
#endif
#endif
}
};
#endif
class V8WebSocketClientImpl
{
public:
V8WebSocketClientImpl(v8::Isolate* InIsolate, v8::Local<v8::Context> InContext, v8::Local<v8::Object> InSelf);
#if defined(WITH_WEBSOCKET_SSL)
using wspp_client = websocketpp::client<websocketpp::config::asio_tls>;
#else
using wspp_client = websocketpp::client<websocketpp::config::asio>;
#endif
using wspp_connection_hdl = websocketpp::connection_hdl;
using wspp_message_ptr = wspp_client::message_ptr;
using wspp_exception = websocketpp::exception;
enum HandlerType
{
ON_OPEN,
ON_MESSAGE,
ON_CLOSE,
ON_FAIL,
HANDLE_TYPE_END
};
void Connect(const v8::FunctionCallbackInfo<v8::Value>& Info);
void Send(const v8::FunctionCallbackInfo<v8::Value>& Info);
void SetHandles(const v8::FunctionCallbackInfo<v8::Value>& Info);
void Close(const v8::FunctionCallbackInfo<v8::Value>& Info);
void Close(websocketpp::close::status::value const code, std::string const& reason);
void PollOne();
private:
void OnOpen(wspp_connection_hdl Handle);
void OnMessage(wspp_connection_hdl Handle, wspp_message_ptr Message);
void OnClose(wspp_connection_hdl Handle);
void OnFail(wspp_connection_hdl Handle);
void Cleanup();
private:
v8::Isolate* Isolate;
v8::Global<v8::Context> GContext;
v8::Global<v8::Object> GSelf;
wspp_client Client;
wspp_connection_hdl Handle;
bool Connenting = false;
v8::Global<v8::Function> Handles[HANDLE_TYPE_END];
};
static void OnGarbageCollectedWithFree(const v8::WeakCallbackInfo<V8WebSocketClientImpl>& Data)
{
// UE_LOG(LogTemp, Warning, TEXT(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> auto gc %p"), Data.GetParameter());
Data.GetParameter()->Close(websocketpp::close::status::normal, "");
delete Data.GetParameter();
}
V8WebSocketClientImpl::V8WebSocketClientImpl(v8::Isolate* InIsolate, v8::Local<v8::Context> InContext, v8::Local<v8::Object> InSelf)
: Isolate(InIsolate), GContext(InIsolate, InContext), GSelf(InIsolate, InSelf)
{
GSelf.SetWeak<V8WebSocketClientImpl>(this, &OnGarbageCollectedWithFree, v8::WeakCallbackType::kInternalFields);
// UE_LOG(LogTemp, Warning, TEXT(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> set weak %p"), this);
}
#if defined(WITH_WEBSOCKET_SSL)
websocketpp::lib::shared_ptr<puerts_asio::ssl::context> on_tls_init(websocketpp::connection_hdl)
{
auto ctx = websocketpp::lib::make_shared<puerts_asio::ssl::context>(websocketpp::lib::puerts_asio::ssl::context::sslv23);
ctx->set_verify_mode(puerts_asio::ssl::verify_none);
return ctx;
}
#endif
void V8WebSocketClientImpl::Connect(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
std::string uri = *(v8::String::Utf8Value(Isolate, Info[0]));
Client.set_access_channels(websocketpp::log::alevel::none);
Client.set_error_channels(websocketpp::log::elevel::none);
Client.set_open_handler(std::bind(&V8WebSocketClientImpl::OnOpen, this, std::placeholders::_1));
Client.set_message_handler(std::bind(&V8WebSocketClientImpl::OnMessage, this, std::placeholders::_1, std::placeholders::_2));
Client.set_close_handler(std::bind(&V8WebSocketClientImpl::OnClose, this, std::placeholders::_1));
Client.set_fail_handler(std::bind(&V8WebSocketClientImpl::OnFail, this, std::placeholders::_1));
#if defined(WITH_WEBSOCKET_SSL)
Client.set_tls_init_handler(&on_tls_init);
#endif
Client.init_asio();
websocketpp::lib::error_code ec;
wspp_client::connection_ptr con = Client.get_connection(uri, ec);
if (ec)
{
std::stringstream ss;
ss << "could not create connection because: " << ec.message() << std::endl;
FV8Utils::ThrowException(Isolate, ss.str().c_str());
return;
}
// Note that connect here only requests a connection. No network messages are
// exchanged until the event loop starts running in the next line.
Client.connect(con);
Connenting = true;
}
void V8WebSocketClientImpl::Send(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
if (Handle.expired())
{
FV8Utils::ThrowException(Isolate, "WebSocket is not open");
return;
}
websocketpp::lib::error_code ec;
auto Value = Info[0];
const void* bin = nullptr;
size_t bin_len = 0;
if (Value->IsString())
{
v8::String::Utf8Value str(Isolate, Value);
std::string payload(*str, str.length());
Client.send(Handle, payload, websocketpp::frame::opcode::TEXT, ec);
}
else if (Value->IsArrayBufferView())
{
v8::Local<v8::ArrayBufferView> BuffView = Value.As<v8::ArrayBufferView>();
auto Ab = BuffView->Buffer();
bin = static_cast<char*>(DataTransfer::GetArrayBufferData(Ab)) + BuffView->ByteOffset();
bin_len = BuffView->ByteLength();
}
else if (Value->IsArrayBuffer())
{
auto Ab = v8::Local<v8::ArrayBuffer>::Cast(Value);
size_t ByteLength;
bin = DataTransfer::GetArrayBufferData(Ab, ByteLength);
bin_len = ByteLength;
}
else
{
FV8Utils::ThrowException(Isolate, "data must be String/ArrayBuffer/ArrayBufferView");
return;
}
if (bin)
{
Client.send(Handle, bin, bin_len, websocketpp::frame::opcode::BINARY, ec);
}
if (ec)
{
std::stringstream ss;
ss << "could not create connection because: " << ec.message() << std::endl;
FV8Utils::ThrowException(Isolate, ss.str().c_str());
}
}
void V8WebSocketClientImpl::SetHandles(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
for (int i = 0; i < HANDLE_TYPE_END; ++i)
{
if (Info[i]->IsFunction())
{
Handles[i].Reset(Isolate, Info[i].As<v8::Function>());
}
}
}
void V8WebSocketClientImpl::Cleanup()
{
if (!Isolate)
{
return;
}
Connenting = false;
Handle.reset();
v8::Isolate::Scope IsolateScope(Isolate);
for (int i = 0; i < HANDLE_TYPE_END; ++i)
{
Handles[i].Reset();
}
// GSelf.Reset();
GContext.Reset();
Isolate = nullptr;
}
void V8WebSocketClientImpl::Close(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
auto InIsolate = Info.GetIsolate();
websocketpp::close::status::value code = websocketpp::close::status::normal;
std::string reason = "";
if (Info[0]->IsInt32())
{
code = Info[0]->Int32Value(Info.GetIsolate()->GetCurrentContext()).FromJust();
}
if (Info[1]->IsString())
{
reason = *v8::String::Utf8Value(InIsolate, Info[1]);
}
Close(code, reason);
}
void V8WebSocketClientImpl::Close(websocketpp::close::status::value const code, std::string const& reason)
{
if (!Handle.expired())
{
Client.close(Handle, code, reason);
}
Cleanup();
}
void V8WebSocketClientImpl::PollOne()
{
if (Connenting || !Handle.expired())
{
Client.poll_one();
}
}
void V8WebSocketClientImpl::OnOpen(wspp_connection_hdl InHandle)
{
Handle = InHandle;
Connenting = false;
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
if (!Handles[ON_OPEN].IsEmpty())
{
v8::Local<v8::Value> args[1];
// must not raise exception in js, recommend just push a pending msg and process later.
Handles[ON_OPEN].Get(Isolate)->Call(GContext.Get(Isolate), v8::Undefined(Isolate), 0, args);
}
}
void V8WebSocketClientImpl::OnMessage(wspp_connection_hdl InHandle, wspp_message_ptr InMessage)
{
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
if (!Handles[ON_MESSAGE].IsEmpty())
{
v8::Local<v8::Value> args[1];
if (InMessage->get_opcode() == websocketpp::frame::opcode::TEXT)
{
args[0] = v8::String::NewFromUtf8(
Isolate, InMessage->get_payload().c_str(), v8::NewStringType::kNormal, InMessage->get_payload().size())
.ToLocalChecked();
}
else if (InMessage->get_opcode() == websocketpp::frame::opcode::BINARY)
{
args[0] = DataTransfer::NewArrayBuffer(
GContext.Get(Isolate), (void*) InMessage->get_payload().c_str(), InMessage->get_payload().size());
}
else
{
args[0] = v8::Undefined(Isolate);
}
// must not raise exception in js, recommend just push a pending msg and process later.
Handles[ON_MESSAGE].Get(Isolate)->Call(GContext.Get(Isolate), v8::Undefined(Isolate), 1, args);
}
}
void V8WebSocketClientImpl::OnClose(wspp_connection_hdl InHandle)
{
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
if (!Handles[ON_CLOSE].IsEmpty())
{
wspp_client::connection_ptr con = Client.get_con_from_hdl(InHandle);
v8::Local<v8::Value> args[2] = {v8::Integer::New(Isolate, con->get_remote_close_code()),
v8::String::NewFromUtf8(
Isolate, con->get_remote_close_reason().c_str(), v8::NewStringType::kNormal, con->get_remote_close_reason().size())
.ToLocalChecked()};
// must not raise exception in js, recommend just push a pending msg and process later.
Handles[ON_CLOSE].Get(Isolate)->Call(GContext.Get(Isolate), v8::Undefined(Isolate), 2, args);
}
Cleanup();
}
void V8WebSocketClientImpl::OnFail(wspp_connection_hdl InHandle)
{
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
if (!Handles[ON_FAIL].IsEmpty())
{
wspp_client::connection_ptr con = Client.get_con_from_hdl(InHandle);
v8::Local<v8::Value> args[1] = {v8::String::NewFromUtf8(
Isolate, con->get_ec().message().c_str(), v8::NewStringType::kNormal, con->get_ec().message().size())
.ToLocalChecked()};
// must not raise exception in js, recommend just push a pending msg and process later.
Handles[ON_FAIL].Get(Isolate)->Call(GContext.Get(Isolate), v8::Undefined(Isolate), 1, args);
}
Close(websocketpp::close::status::abnormal_close, "");
}
} // namespace PUERTS_NAMESPACE
void InitWebsocketPPWrap(v8::Local<v8::Context> Context)
{
auto Isolate = Context->GetIsolate();
auto WSTemplate = v8::FunctionTemplate::New(Context->GetIsolate(),
[](const v8::FunctionCallbackInfo<v8::Value>& Info)
{
auto ws =
new PUERTS_NAMESPACE::V8WebSocketClientImpl(Info.GetIsolate(), Info.GetIsolate()->GetCurrentContext(), Info.This());
Info.This()->SetAlignedPointerInInternalField(0, ws);
ws->Connect(Info);
});
WSTemplate->InstanceTemplate()->SetInternalFieldCount(1);
WSTemplate->PrototypeTemplate()->Set(v8::String::NewFromUtf8(Isolate, "send").ToLocalChecked(),
v8::FunctionTemplate::New(Isolate,
[](const v8::FunctionCallbackInfo<v8::Value>& Info) {
static_cast<PUERTS_NAMESPACE::V8WebSocketClientImpl*>(Info.Holder()->GetAlignedPointerFromInternalField(0))
->Send(Info);
}));
WSTemplate->PrototypeTemplate()->Set(v8::String::NewFromUtf8(Isolate, "setHandles").ToLocalChecked(),
v8::FunctionTemplate::New(Isolate,
[](const v8::FunctionCallbackInfo<v8::Value>& Info)
{
static_cast<PUERTS_NAMESPACE::V8WebSocketClientImpl*>(Info.Holder()->GetAlignedPointerFromInternalField(0))
->SetHandles(Info);
}));
WSTemplate->PrototypeTemplate()->Set(v8::String::NewFromUtf8(Isolate, "close").ToLocalChecked(),
v8::FunctionTemplate::New(Isolate,
[](const v8::FunctionCallbackInfo<v8::Value>& Info) {
static_cast<PUERTS_NAMESPACE::V8WebSocketClientImpl*>(Info.Holder()->GetAlignedPointerFromInternalField(0))
->Close(Info);
}));
WSTemplate->PrototypeTemplate()->Set(v8::String::NewFromUtf8(Isolate, "poll").ToLocalChecked(),
v8::FunctionTemplate::New(Isolate,
[](const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::TryCatch TryCatch(Info.GetIsolate());
static_cast<PUERTS_NAMESPACE::V8WebSocketClientImpl*>(Info.Holder()->GetAlignedPointerFromInternalField(0))
->PollOne();
}));
Context->Global()->Set(Context, v8::String::NewFromUtf8(Isolate, "WebSocketPP").ToLocalChecked(),
WSTemplate->GetFunction(Context).ToLocalChecked());
}
#endif
@@ -0,0 +1,36 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include "CoreMinimal.h"
#include "ArrayBuffer.generated.h"
USTRUCT(BlueprintType)
struct FArrayBuffer
{
public:
GENERATED_USTRUCT_BODY()
public:
void* Data;
size_t Length;
bool bCopy = false;
};
USTRUCT(BlueprintType)
struct FArrayBufferValue
{
public:
GENERATED_USTRUCT_BODY()
public:
TArray<uint8> Data;
};
@@ -0,0 +1,14 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include "PuertsNamespaceDef.h"
#include "StaticCall.hpp"
#include "ScriptBackend.hpp"
#include "Object.hpp"
@@ -0,0 +1,370 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#if USING_IN_UNREAL_ENGINE
#include "CoreMinimal.h"
#include "UObject/Package.h"
#include "UObject/Class.h"
#else
#include "JSClassRegister.h"
#endif
#include "NamespaceDef.h"
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#pragma warning(push, 0)
#include "v8.h"
#pragma warning(pop)
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
#if !defined(MAPPER_ISOLATE_DATA_POS)
#define MAPPER_ISOLATE_DATA_POS 0
#endif
#ifndef PESAPI_PRIVATE_DATA_POS_IN_ISOLATE
#define PESAPI_PRIVATE_DATA_POS_IN_ISOLATE (MAPPER_ISOLATE_DATA_POS + 1)
#endif
#define RELEASED_UOBJECT ((UObject*) 12)
#define RELEASED_UOBJECT_MEMBER ((void*) 12)
namespace PUERTS_NAMESPACE
{
template <typename T, typename FT, typename = void>
struct TOuterLinker
{
V8_INLINE static void Link(v8::Local<v8::Context> Context, v8::Local<v8::Value> Outer, v8::Local<v8::Value> Inner)
{
}
};
V8_INLINE void LinkOuterImpl(v8::Local<v8::Context> Context, v8::Local<v8::Value> Outer, v8::Local<v8::Value> Inner)
{
#ifdef WITH_OUTER_LINK
Inner.As<v8::Object>()->Set(Context, 0, Outer);
#endif
}
#if USING_IN_UNREAL_ENGINE
FORCEINLINE UScriptStruct* GetScriptStructInCoreUObject(const TCHAR* Name)
{
static UPackage* CoreUObjectPkg = FindObjectChecked<UPackage>(nullptr, TEXT("/Script/CoreUObject"));
return FindObjectChecked<UScriptStruct>(CoreUObjectPkg, Name);
}
template <class T, typename Enable = void>
struct TScriptStructTraits
{
};
template <>
struct TScriptStructTraits<FVector>
{
static UScriptStruct* Get()
{
return TBaseStructure<FVector>::Get();
}
};
template <>
struct TScriptStructTraits<FVector2D>
{
static UScriptStruct* Get()
{
return TBaseStructure<FVector2D>::Get();
}
};
template <>
struct TScriptStructTraits<FVector4>
{
static UScriptStruct* Get()
{
return TBaseStructure<FVector4>::Get();
}
};
template <>
struct TScriptStructTraits<FRotator>
{
static UScriptStruct* Get()
{
return TBaseStructure<FRotator>::Get();
}
};
template <>
struct TScriptStructTraits<FQuat>
{
static UScriptStruct* Get()
{
return TBaseStructure<FQuat>::Get();
}
};
template <>
struct TScriptStructTraits<FTransform>
{
static UScriptStruct* Get()
{
return TBaseStructure<FTransform>::Get();
}
};
template <>
struct TScriptStructTraits<FLinearColor>
{
static UScriptStruct* Get()
{
return TBaseStructure<FLinearColor>::Get();
}
};
template <>
struct TScriptStructTraits<FColor>
{
static UScriptStruct* Get()
{
return TBaseStructure<FColor>::Get();
}
};
template <>
struct TScriptStructTraits<FGuid>
{
static UScriptStruct* Get()
{
return TBaseStructure<FGuid>::Get();
}
};
template <>
struct TScriptStructTraits<FBox2D>
{
static UScriptStruct* Get()
{
return TBaseStructure<FBox2D>::Get();
}
};
template <>
struct TScriptStructTraits<FIntPoint>
{
static UScriptStruct* Get()
{
return GetScriptStructInCoreUObject(TEXT("IntPoint"));
}
};
template <>
struct TScriptStructTraits<FIntVector>
{
static UScriptStruct* Get()
{
return GetScriptStructInCoreUObject(TEXT("IntVector"));
}
};
template <>
struct TScriptStructTraits<FPlane>
{
static UScriptStruct* Get()
{
return GetScriptStructInCoreUObject(TEXT("Plane"));
}
};
template <class...>
using ToVoid = void;
template <typename T, typename = void>
struct HasStaticStructHelper : std::false_type
{
};
template <typename T>
struct HasStaticStructHelper<T, ToVoid<decltype(&T::StaticStruct)>> : std::true_type
{
};
template <typename T>
struct TScriptStructTraits<T, typename std::enable_if<HasStaticStructHelper<T>::value>::type>
{
static UScriptStruct* Get()
{
return T::StaticStruct();
}
};
template <typename T, typename FT>
struct TOuterLinker<T, FT, ToVoid<decltype(&TScriptStructTraits<FT>::Get)>>
{
V8_INLINE static void Link(v8::Local<v8::Context> Context, v8::Local<v8::Value> Outer, v8::Local<v8::Value> Inner)
{
LinkOuterImpl(Context, Outer, Inner);
}
};
#endif
class JSENV_API DataTransfer
{
public:
FORCEINLINE static void* MakeAddressWithHighPartOfTwo(void* Address1, void* Address2)
{
UPTRINT High = reinterpret_cast<UPTRINT>(Address1) & (((UPTRINT) -1) << (sizeof(UPTRINT) / 2)); //清除低位
UPTRINT Low = (reinterpret_cast<UPTRINT>(Address2) >> (sizeof(UPTRINT) / 2)) &
~(((UPTRINT) -1) << (sizeof(UPTRINT) / 2)); //右移,然后清除高位
return reinterpret_cast<void*>(High | Low);
}
FORCEINLINE static void SplitAddressToHighPartOfTwo(const void* Address, UPTRINT& High, UPTRINT& Low)
{
High = reinterpret_cast<UPTRINT>(Address) & (((UPTRINT) -1) << (sizeof(UPTRINT) / 2)); //清除低位
Low = reinterpret_cast<UPTRINT>(Address) << (sizeof(UPTRINT) / 2);
}
template <typename T>
FORCEINLINE static T* GetPointerFast(v8::Local<v8::Object> Object, int Index)
{
int P1 = Index << 1;
int P2 = P1 + 1;
if (V8_LIKELY(Object->InternalFieldCount() > P2))
{
return static_cast<T*>(MakeAddressWithHighPartOfTwo(
Object->GetAlignedPointerFromInternalField(P1), Object->GetAlignedPointerFromInternalField(P2)));
}
return nullptr;
}
template <typename T>
FORCEINLINE static T* GetPointerFast(v8::Local<v8::Object> Object)
{
if (V8_LIKELY(Object->InternalFieldCount() > 1))
{
return static_cast<T*>(MakeAddressWithHighPartOfTwo(
Object->GetAlignedPointerFromInternalField(0), Object->GetAlignedPointerFromInternalField(1)));
}
return nullptr;
}
//替代 Object->SetAlignedPointerInInternalField(Index, Ptr);
FORCEINLINE static void SetPointer(v8::Isolate* Isolate, v8::Local<v8::Object> Object, const void* Ptr, int Index)
{
// Object->SetInternalField(Index, v8::External::New(Isolate, Ptr));
// Object->SetAlignedPointerInInternalField(Index, Ptr);
UPTRINT High;
UPTRINT Low;
SplitAddressToHighPartOfTwo(Ptr, High, Low);
Object->SetAlignedPointerInInternalField(Index * 2, reinterpret_cast<void*>(High));
Object->SetAlignedPointerInInternalField(Index * 2 + 1, reinterpret_cast<void*>(Low));
}
template <typename T>
FORCEINLINE static T* IsolateData(v8::Isolate* Isolate)
{
return static_cast<T*>(Isolate->GetData(MAPPER_ISOLATE_DATA_POS));
}
FORCEINLINE static void* GetIsolatePrivateData(v8::Isolate* Isolate)
{
return Isolate->GetData(PESAPI_PRIVATE_DATA_POS_IN_ISOLATE);
}
FORCEINLINE static void SetIsolatePrivateData(v8::Isolate* Isolate, void* PrivateData)
{
Isolate->SetData(PESAPI_PRIVATE_DATA_POS_IN_ISOLATE, PrivateData);
}
static v8::Local<v8::Value> FindOrAddCData(
v8::Isolate* Isolate, v8::Local<v8::Context> Context, const void* TypeId, const void* Ptr, bool PassByPointer);
static bool IsInstanceOf(v8::Isolate* Isolate, const void* TypeId, v8::Local<v8::Object> JsObject);
static v8::Local<v8::Value> UnRef(v8::Isolate* Isolate, const v8::Local<v8::Value>& Value);
static void UpdateRef(v8::Isolate* Isolate, v8::Local<v8::Value> Outer, const v8::Local<v8::Value>& Value);
static std::weak_ptr<int> GetJsEnvLifeCycleTracker(v8::Isolate* Isolate);
#if USING_IN_UNREAL_ENGINE
template <typename T>
static v8::Local<v8::Value> FindOrAddObject(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, T* UEObject)
{
return FindOrAddObject(Isolate, Context, UEObject == nullptr ? T::StaticClass() : UEObject->GetClass(), UEObject);
}
static v8::Local<v8::Value> FindOrAddObject(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, UClass* Class, UObject* UEObject);
template <typename T>
static v8::Local<v8::Value> FindOrAddStruct(v8::Isolate* Isolate, v8::Local<v8::Context> Context, void* Ptr, bool PassByPointer)
{
return FindOrAddStruct(Isolate, Context, TScriptStructTraits<T>::Get(), Ptr, PassByPointer);
}
static v8::Local<v8::Value> FindOrAddStruct(
v8::Isolate* Isolate, v8::Local<v8::Context> Context, UScriptStruct* ScriptStruct, void* Ptr, bool PassByPointer);
template <typename T>
static bool IsInstanceOf(v8::Isolate* Isolate, v8::Local<v8::Object> JsObject)
{
return IsInstanceOf(Isolate, TScriptStructTraits<T>::Get(), JsObject);
}
static bool IsInstanceOf(v8::Isolate* Isolate, UStruct* Struct, v8::Local<v8::Object> JsObject);
static FString ToFString(v8::Isolate* Isolate, v8::Local<v8::Value> Value);
static void ThrowException(v8::Isolate* Isolate, const char* Message);
#endif
template <typename T1, typename T2>
FORCEINLINE static void LinkOuter(v8::Local<v8::Context> Context, v8::Local<v8::Value> Outer, v8::Local<v8::Value> Inner)
{
TOuterLinker<T1, T2>::Link(Context, Outer, Inner);
}
FORCEINLINE static v8::Local<v8::ArrayBuffer> NewArrayBuffer(v8::Local<v8::Context> Context, void* Data, size_t DataLength)
{
#if defined(HAS_ARRAYBUFFER_NEW_WITHOUT_STL)
return v8::ArrayBuffer_New_Without_Stl(Context->GetIsolate(), Data, DataLength);
#else
#if USING_IN_UNREAL_ENGINE
return v8::ArrayBuffer::New(Context->GetIsolate(), Data, DataLength);
#else
auto Backing = v8::ArrayBuffer::NewBackingStore(Data, DataLength, v8::BackingStore::EmptyDeleter, nullptr);
return v8::ArrayBuffer::New(Context->GetIsolate(), std::move(Backing));
#endif
#endif
}
FORCEINLINE static void* GetArrayBufferData(v8::Local<v8::ArrayBuffer> InArrayBuffer)
{
size_t DataLength;
return GetArrayBufferData(InArrayBuffer, DataLength);
}
FORCEINLINE static void* GetArrayBufferData(v8::Local<v8::ArrayBuffer> InArrayBuffer, size_t& DataLength)
{
#if defined(HAS_ARRAYBUFFER_NEW_WITHOUT_STL)
return v8::ArrayBuffer_Get_Data(InArrayBuffer, DataLength);
#else
#if USING_IN_UNREAL_ENGINE
DataLength = InArrayBuffer->GetContents().ByteLength();
return InArrayBuffer->GetContents().Data();
#else
auto BS = InArrayBuffer->GetBackingStore();
DataLength = BS->ByteLength();
return BS->Data();
#endif
#endif
}
};
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,40 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include "NamespaceDef.h"
#include "CoreUObject.h"
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#pragma warning(push, 0)
#include "v8.h"
#pragma warning(pop)
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
class UDynamicDelegateProxy;
class UJSGeneratedFunction;
namespace PUERTS_NAMESPACE
{
class IDynamicInvoker
{
public:
virtual void InvokeDelegateCallback(UDynamicDelegateProxy* Proxy, void* Params) = 0;
#if !defined(ENGINE_INDEPENDENT_JSENV)
virtual void JsConstruct(UClass* Class, UObject* Object, const v8::UniquePersistent<v8::Function>& Constructor,
const v8::UniquePersistent<v8::Object>& Prototype) = 0;
virtual void InvokeJsMethod(UObject* ContextObject, UJSGeneratedFunction* Function, FFrame& Stack, void* RESULT_PARAM) = 0;
virtual void InvokeMixinMethod(UObject* ContextObject, UJSGeneratedFunction* Function, FFrame& Stack, void* RESULT_PARAM) = 0;
#endif
};
} // namespace PUERTS_NAMESPACE

Some files were not shown because too many files have changed in this diff Show More