添加ReactUMG插件
搭建TS环境
This commit is contained in:
+13
@@ -0,0 +1,13 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Rider ignored files
|
||||||
|
/modules.xml
|
||||||
|
/projectSettingsUpdater.xml
|
||||||
|
/contentModel.xml
|
||||||
|
/.idea.MingSimulator.iml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
GameDefaultMap=/Game/TopDown/Maps/TopDownMap.TopDownMap
|
GameDefaultMap=/Game/TopDown/Maps/TopDownMap.TopDownMap
|
||||||
EditorStartupMap=/Game/TopDown/Maps/TopDownMap.TopDownMap
|
EditorStartupMap=/Game/TopDown/Maps/TopDownMap.TopDownMap
|
||||||
GlobalDefaultGameMode="/Script/MingSimulator.MingSimulatorGameMode"
|
GlobalDefaultGameMode="/Script/MingSimulator.MingSimulatorGameMode"
|
||||||
|
GameInstanceClass=/Script/MingSimulator.MingGameInstance
|
||||||
|
|
||||||
[/Script/Engine.RendererSettings]
|
[/Script/Engine.RendererSettings]
|
||||||
r.DefaultFeature.AutoExposure.ExtendDefaultLuminanceRange=True
|
r.DefaultFeature.AutoExposure.ExtendDefaultLuminanceRange=True
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
Copyright (c) 2023, puerts
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
# ReactUMG
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"FileVersion": 3,
|
||||||
|
"FriendlyName": "react umg",
|
||||||
|
"Version": 1,
|
||||||
|
"VersionName": "1.0",
|
||||||
|
"FriendlyVersion": "1.0",
|
||||||
|
"Description": "react umg",
|
||||||
|
"Category": "Programming",
|
||||||
|
"CreatedBy": "Tencent Corporation",
|
||||||
|
"CreatedByURL": "https://github.com/Tencent",
|
||||||
|
"EnabledByDefault": true,
|
||||||
|
"MarketplaceURL" : "",
|
||||||
|
"CanContainContent": true,
|
||||||
|
"CanBeUsedWithUnrealHeaderTool" : false,
|
||||||
|
"Modules": [
|
||||||
|
{
|
||||||
|
"Name": "ReactDeclarationGenerator",
|
||||||
|
"Type": "Editor",
|
||||||
|
"LoadingPhase": "Default"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "ReactUMG",
|
||||||
|
"Type": "Runtime",
|
||||||
|
"LoadingPhase": "PreDefault",
|
||||||
|
"WhitelistPlatforms": [ "Win64", "Android", "Mac", "IOS", "Linux" ]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Plugins": [
|
||||||
|
{
|
||||||
|
"Name": "Puerts",
|
||||||
|
"Enabled": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
+281
@@ -0,0 +1,281 @@
|
|||||||
|
// Fill out your copyright notice in the Description page of Project Settings.
|
||||||
|
|
||||||
|
#include "ReactDeclarationGenerator.h"
|
||||||
|
#include "TypeScriptDeclarationGenerator.h"
|
||||||
|
#include "Misc/Paths.h"
|
||||||
|
#include "CoreUObject.h"
|
||||||
|
#include "TypeScriptDeclarationGenerator.h"
|
||||||
|
#include "Components/PanelSlot.h"
|
||||||
|
#include "Components/Widget.h"
|
||||||
|
#include "Interfaces/IPluginManager.h"
|
||||||
|
|
||||||
|
static FString SafeName(const FString& Name)
|
||||||
|
{
|
||||||
|
auto Ret = Name.Replace(TEXT(" "), TEXT(""))
|
||||||
|
.Replace(TEXT("-"), TEXT("_"))
|
||||||
|
.Replace(TEXT("/"), TEXT("_"))
|
||||||
|
.Replace(TEXT("("), TEXT("_"))
|
||||||
|
.Replace(TEXT(")"), TEXT("_"))
|
||||||
|
.Replace(TEXT("?"), TEXT("$"))
|
||||||
|
.Replace(TEXT(","), TEXT("_"));
|
||||||
|
if (Ret.Len() > 0)
|
||||||
|
{
|
||||||
|
auto FirstChar = Ret[0];
|
||||||
|
if ((TCHAR) '0' <= FirstChar && FirstChar <= (TCHAR) '9')
|
||||||
|
{
|
||||||
|
return TEXT("_") + Ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsDelegate(PropertyMacro* InProperty)
|
||||||
|
{
|
||||||
|
return InProperty->IsA<DelegatePropertyMacro>() || InProperty->IsA<MulticastDelegatePropertyMacro>()
|
||||||
|
#if ENGINE_MINOR_VERSION >= 23
|
||||||
|
|| InProperty->IsA<MulticastInlineDelegatePropertyMacro>() || InProperty->IsA<MulticastSparseDelegatePropertyMacro>()
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool HasObjectParam(UFunction* InFunction)
|
||||||
|
{
|
||||||
|
for (TFieldIterator<PropertyMacro> ParamIt(InFunction); ParamIt; ++ParamIt)
|
||||||
|
{
|
||||||
|
auto Property = *ParamIt;
|
||||||
|
if (Property->IsA<ObjectPropertyBaseMacro>())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FReactDeclarationGenerator : public FTypeScriptDeclarationGenerator
|
||||||
|
{
|
||||||
|
void Begin(FString Namespace) override;
|
||||||
|
|
||||||
|
void GenReactDeclaration();
|
||||||
|
|
||||||
|
void GenClass(UClass* Class) override;
|
||||||
|
|
||||||
|
void GenStruct(UStruct* Struct) override;
|
||||||
|
|
||||||
|
void GenEnum(UEnum* Enum) override;
|
||||||
|
|
||||||
|
void End() override;
|
||||||
|
|
||||||
|
virtual ~FReactDeclarationGenerator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//--- FSlotDeclarationGenerator begin ---
|
||||||
|
void FReactDeclarationGenerator::Begin(FString Namespace)
|
||||||
|
{
|
||||||
|
} // do nothing
|
||||||
|
|
||||||
|
void FReactDeclarationGenerator::End()
|
||||||
|
{
|
||||||
|
} // do nothing
|
||||||
|
|
||||||
|
void FReactDeclarationGenerator::GenReactDeclaration()
|
||||||
|
{
|
||||||
|
FString Components = TEXT("exports.lazyloadComponents = {};\n");
|
||||||
|
Output << "declare module \"react-umg\" {\n";
|
||||||
|
Output << " "
|
||||||
|
<< "import * as React from 'react';\n import * as UE from 'ue';\n import * as cpp from 'cpp';\n type TArray<T> "
|
||||||
|
"= UE.TArray<T>;\n type "
|
||||||
|
"TSet<T> = UE.TSet<T>;\n type TMap<TKey, TValue> = UE.TMap<TKey, TValue>;\n\n";
|
||||||
|
|
||||||
|
Output << " type RecursivePartial<T> = {\n"
|
||||||
|
<< " [P in keyof T]?:\n"
|
||||||
|
<< " T[P] extends (infer U)[] ? RecursivePartial<U>[] :\n"
|
||||||
|
<< " T[P] extends object ? RecursivePartial<T[P]> :\n"
|
||||||
|
<< " T[P];\n"
|
||||||
|
<< " };\n\n";
|
||||||
|
|
||||||
|
for (TObjectIterator<UClass> It; It; ++It)
|
||||||
|
{
|
||||||
|
UClass* Class = *It;
|
||||||
|
checkfSlow(Class != nullptr, TEXT("Class name corruption!"));
|
||||||
|
if (Class->GetName().StartsWith("SKEL_") || Class->GetName().StartsWith("REINST_") ||
|
||||||
|
Class->GetName().StartsWith("TRASHCLASS_") || Class->GetName().StartsWith("PLACEHOLDER_"))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Class->IsChildOf<UPanelSlot>())
|
||||||
|
Gen(Class);
|
||||||
|
}
|
||||||
|
|
||||||
|
Output << " "
|
||||||
|
<< "export interface Props {\n";
|
||||||
|
Output << " "
|
||||||
|
<< " Slot ? : PanelSlot;\n";
|
||||||
|
Output << " "
|
||||||
|
<< "}\n\n";
|
||||||
|
|
||||||
|
for (TObjectIterator<UClass> It; It; ++It)
|
||||||
|
{
|
||||||
|
UClass* Class = *It;
|
||||||
|
checkfSlow(Class != nullptr, TEXT("Class name corruption!"));
|
||||||
|
if (Class->GetName().StartsWith("SKEL_") || Class->GetName().StartsWith("REINST_") ||
|
||||||
|
Class->GetName().StartsWith("TRASHCLASS_") || Class->GetName().StartsWith("PLACEHOLDER_"))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Class->IsChildOf<UWidget>())
|
||||||
|
{
|
||||||
|
Gen(Class);
|
||||||
|
Components += "exports." + SafeName(Class->GetName()) + " = '" + SafeName(Class->GetName()) + "';\n";
|
||||||
|
if (!(Class->ClassFlags & CLASS_Native))
|
||||||
|
{
|
||||||
|
Components += "exports.lazyloadComponents." + SafeName(Class->GetName()) + " = '" + Class->GetPathName() + "';\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Output << R"(
|
||||||
|
interface Root {
|
||||||
|
removeFromViewport() : void;
|
||||||
|
getWidget(): any;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TReactUMG {
|
||||||
|
render(element: React.ReactElement) : Root;
|
||||||
|
init(world: any) : void;
|
||||||
|
}
|
||||||
|
|
||||||
|
var ReactUMG : TReactUMG;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
FFileHelper::SaveStringToFile(ToString(), *(FPaths::ProjectDir() / TEXT("Typing/react-umg/index.d.ts")),
|
||||||
|
FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM);
|
||||||
|
FFileHelper::SaveStringToFile(Components, *(FPaths::ProjectContentDir() / TEXT("JavaScript/react-umg/components.js")),
|
||||||
|
FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsReactSupportProperty(PropertyMacro* Property)
|
||||||
|
{
|
||||||
|
if (CastFieldMacro<ObjectPropertyMacro>(Property) || CastFieldMacro<ClassPropertyMacro>(Property) ||
|
||||||
|
CastFieldMacro<WeakObjectPropertyMacro>(Property) || CastFieldMacro<SoftObjectPropertyMacro>(Property) ||
|
||||||
|
CastFieldMacro<LazyObjectPropertyMacro>(Property))
|
||||||
|
return false;
|
||||||
|
if (auto ArrayProperty = CastFieldMacro<ArrayPropertyMacro>(Property))
|
||||||
|
{
|
||||||
|
return IsReactSupportProperty(ArrayProperty->Inner);
|
||||||
|
}
|
||||||
|
else if (auto DelegateProperty = CastFieldMacro<DelegatePropertyMacro>(Property))
|
||||||
|
{
|
||||||
|
return !HasObjectParam(DelegateProperty->SignatureFunction);
|
||||||
|
}
|
||||||
|
else if (auto MulticastDelegateProperty = CastFieldMacro<MulticastDelegatePropertyMacro>(Property))
|
||||||
|
{
|
||||||
|
return !HasObjectParam(MulticastDelegateProperty->SignatureFunction);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FReactDeclarationGenerator::GenClass(UClass* Class)
|
||||||
|
{
|
||||||
|
if (!Class->IsChildOf<UPanelSlot>() && !Class->IsChildOf<UWidget>())
|
||||||
|
return;
|
||||||
|
bool IsWidget = Class->IsChildOf<UWidget>();
|
||||||
|
FStringBuffer StringBuffer{"", ""};
|
||||||
|
StringBuffer << " "
|
||||||
|
<< "interface " << SafeName(Class->GetName());
|
||||||
|
if (IsWidget)
|
||||||
|
StringBuffer << "Props";
|
||||||
|
|
||||||
|
auto Super = Class->GetSuperStruct();
|
||||||
|
|
||||||
|
if (Super && (Super->IsChildOf<UPanelSlot>() || Super->IsChildOf<UWidget>()))
|
||||||
|
{
|
||||||
|
Gen(Super);
|
||||||
|
StringBuffer << " extends " << SafeName(Super->GetName());
|
||||||
|
if (Super->IsChildOf<UWidget>())
|
||||||
|
StringBuffer << "Props";
|
||||||
|
}
|
||||||
|
else if (IsWidget)
|
||||||
|
{
|
||||||
|
StringBuffer << " extends Props";
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuffer << " {\n";
|
||||||
|
|
||||||
|
for (TFieldIterator<PropertyMacro> PropertyIt(Class, EFieldIteratorFlags::ExcludeSuper); PropertyIt; ++PropertyIt)
|
||||||
|
{
|
||||||
|
auto Property = *PropertyIt;
|
||||||
|
if (!IsReactSupportProperty(Property))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//UE.27上遇到一个问题,
|
||||||
|
//引擎内置蓝图DefaultBurnIn有个FLinearColor类型的变量Foreground Color,
|
||||||
|
//并且父类UUserWidget有个FSlateColor类型的变量ForegroundColor
|
||||||
|
//此处SafeName去掉空格导致interface写入了父类变量名字,类型对不上,有报错,仅此一例
|
||||||
|
//PuerTS插件DeclarationGenerator.cpp中的SafeName存在同样隐患
|
||||||
|
FString PropertyNameSafe = SafeName(Property->GetName());
|
||||||
|
UClass* SuperClass = Class->GetSuperClass();
|
||||||
|
if (PropertyNameSafe != Property->GetName() &&
|
||||||
|
SuperClass != nullptr && SuperClass->FindPropertyByName(*PropertyNameSafe) != nullptr)
|
||||||
|
{
|
||||||
|
UE_LOG(LogTemp, Warning, TEXT("ReactUMG, invalid property name, origin name: %s, safe name %s in super class!"), *Property->GetName(), *PropertyNameSafe);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
FStringBuffer TmpBuff;
|
||||||
|
TmpBuff << " " << SafeName(Property->GetName()) << "?: ";
|
||||||
|
TArray<UObject*> RefTypesTmp;
|
||||||
|
if (!IsWidget && IsDelegate(Property)) // UPanelSlot skip delegate
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (CastFieldMacro<StructPropertyMacro>(Property))
|
||||||
|
{
|
||||||
|
TmpBuff << "RecursivePartial<";
|
||||||
|
}
|
||||||
|
if (!GenTypeDecl(TmpBuff, Property, RefTypesTmp, false, true))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (CastFieldMacro<StructPropertyMacro>(Property))
|
||||||
|
{
|
||||||
|
TmpBuff << ">";
|
||||||
|
}
|
||||||
|
for (auto Type : RefTypesTmp)
|
||||||
|
{
|
||||||
|
Gen(Type);
|
||||||
|
}
|
||||||
|
StringBuffer << " " << TmpBuff.Buffer << ";\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuffer << " "
|
||||||
|
<< "}\n\n";
|
||||||
|
|
||||||
|
if (IsWidget)
|
||||||
|
{
|
||||||
|
StringBuffer << " "
|
||||||
|
<< "class " << SafeName(Class->GetName()) << " extends React.Component<" << SafeName(Class->GetName())
|
||||||
|
<< "Props> {\n"
|
||||||
|
<< " nativePtr: " << GetNameWithNamespace(Class) << ";\n }\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
Output << StringBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FReactDeclarationGenerator::GenStruct(UStruct* Struct)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void FReactDeclarationGenerator::GenEnum(UEnum* Enum)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//--- FSlotDeclarationGenerator end ---
|
||||||
|
|
||||||
|
void UReactDeclarationGenerator::Gen_Implementation() const
|
||||||
|
{
|
||||||
|
FReactDeclarationGenerator ReactDeclarationGenerator;
|
||||||
|
ReactDeclarationGenerator.GenReactDeclaration();
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
#include "IReactDeclarationGenerator.h"
|
||||||
|
#include "Features/IModularFeatures.h"
|
||||||
|
|
||||||
|
class FReactDeclarationGeneratorModule : public IReactDeclarationGenerator
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
public:
|
||||||
|
void StartupModule() override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShutdownModule() override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
IMPLEMENT_MODULE(FReactDeclarationGeneratorModule, ReactDeclarationGenerator)
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* 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>
|
||||||
|
|
||||||
|
#if ENGINE_MAJOR_VERSION < 5 || ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION < 2
|
||||||
|
#include "IScriptGeneratorPluginInterface.h"
|
||||||
|
#endif
|
||||||
|
#include "Modules/ModuleManager.h"
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
|
||||||
|
class IReactDeclarationGenerator : public IModuleInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static inline IReactDeclarationGenerator& Get()
|
||||||
|
{
|
||||||
|
return FModuleManager::LoadModuleChecked<IReactDeclarationGenerator>("ReactDeclarationGenerator");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool IsAvailable()
|
||||||
|
{
|
||||||
|
return FModuleManager::Get().IsModuleLoaded("ReactDeclarationGenerator");
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
// Fill out your copyright notice in the Description page of Project Settings.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CodeGenerator.h"
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "UObject/NoExportTypes.h"
|
||||||
|
#include "ReactDeclarationGenerator.generated.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
UCLASS()
|
||||||
|
class REACTDECLARATIONGENERATOR_API UReactDeclarationGenerator : public UObject, public ICodeGenerator
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UFUNCTION(BlueprintNativeEvent)
|
||||||
|
void Gen() const;
|
||||||
|
|
||||||
|
virtual void Gen_Implementation() const override;
|
||||||
|
};
|
||||||
@@ -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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using UnrealBuildTool;
|
||||||
|
|
||||||
|
public class ReactDeclarationGenerator : ModuleRules
|
||||||
|
{
|
||||||
|
public ReactDeclarationGenerator(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",
|
||||||
|
"DeclarationGenerator",
|
||||||
|
"JsEnv",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* 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 "Modules/ModuleInterface.h"
|
||||||
|
#include "Modules/ModuleManager.h"
|
||||||
|
|
||||||
|
class IReactUMG : public IModuleInterface //: public IScriptGeneratorPluginInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static inline IReactUMG& Get()
|
||||||
|
{
|
||||||
|
return FModuleManager::LoadModuleChecked<IReactUMG>("ReactUMG");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool IsAvailable()
|
||||||
|
{
|
||||||
|
return FModuleManager::Get().IsModuleLoaded("ReactUMG");
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* 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 UnrealBuildTool;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
public class ReactUMG : ModuleRules
|
||||||
|
{
|
||||||
|
public ReactUMG(ReadOnlyTargetRules Target) : base(Target)
|
||||||
|
{
|
||||||
|
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||||
|
|
||||||
|
PublicDependencyModuleNames.AddRange(new string[]
|
||||||
|
{
|
||||||
|
"Core", "CoreUObject", "Engine", "InputCore", "Serialization", "UMG"
|
||||||
|
});
|
||||||
|
|
||||||
|
bEnableExceptions = true;
|
||||||
|
|
||||||
|
//string coreJSPath = Path.GetFullPath(Path.Combine(ModuleDirectory, "..", "..", "Content", "Scripts"));
|
||||||
|
//string destDirName = Path.GetFullPath(Path.Combine(ModuleDirectory, "..", "..", "..", "..", "Content", "Scripts"));
|
||||||
|
//DirectoryCopy(coreJSPath, destDirName, true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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,25 @@
|
|||||||
|
/*
|
||||||
|
* 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 "IReactUMG.h"
|
||||||
|
#include "Features/IModularFeatures.h"
|
||||||
|
|
||||||
|
class FReactUMGModule : public IReactUMG
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
public:
|
||||||
|
void StartupModule() override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShutdownModule() override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
IMPLEMENT_MODULE(FReactUMGModule, ReactUMG)
|
||||||
@@ -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 "ReactWidget.h"
|
||||||
|
#include "Blueprint/WidgetTree.h"
|
||||||
|
|
||||||
|
UReactWidget::UReactWidget(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
|
||||||
|
{
|
||||||
|
WidgetTree = CreateDefaultSubobject<UWidgetTree>(TEXT("WidgetTree"));
|
||||||
|
WidgetTree->SetFlags(RF_Transactional);
|
||||||
|
}
|
||||||
|
|
||||||
|
UPanelSlot* UReactWidget::AddChild(UWidget* Content)
|
||||||
|
{
|
||||||
|
if (Content == nullptr)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RootSlot)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Content->RemoveFromParent();
|
||||||
|
|
||||||
|
EObjectFlags NewObjectFlags = RF_Transactional;
|
||||||
|
if (HasAnyFlags(RF_Transient))
|
||||||
|
{
|
||||||
|
NewObjectFlags |= RF_Transient;
|
||||||
|
}
|
||||||
|
|
||||||
|
UPanelSlot* PanelSlot = NewObject<UPanelSlot>(this, UPanelSlot::StaticClass(), NAME_None, NewObjectFlags);
|
||||||
|
PanelSlot->Content = Content;
|
||||||
|
|
||||||
|
Content->Slot = PanelSlot;
|
||||||
|
|
||||||
|
RootSlot = PanelSlot;
|
||||||
|
|
||||||
|
WidgetTree->RootWidget = Content;
|
||||||
|
|
||||||
|
InvalidateLayoutAndVolatility();
|
||||||
|
|
||||||
|
return PanelSlot;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UReactWidget::RemoveChild(UWidget* Content)
|
||||||
|
{
|
||||||
|
if (Content == nullptr || RootSlot == nullptr || Content != RootSlot->Content)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
UPanelSlot* PanelSlot = RootSlot;
|
||||||
|
RootSlot = nullptr;
|
||||||
|
|
||||||
|
if (PanelSlot->Content)
|
||||||
|
{
|
||||||
|
PanelSlot->Content->Slot = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool bReleaseChildren = true;
|
||||||
|
PanelSlot->ReleaseSlateResources(bReleaseChildren);
|
||||||
|
PanelSlot->Parent = nullptr;
|
||||||
|
PanelSlot->Content = nullptr;
|
||||||
|
|
||||||
|
WidgetTree->RootWidget = nullptr;
|
||||||
|
|
||||||
|
InvalidateLayoutAndVolatility();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -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 "Blueprint/UserWidget.h"
|
||||||
|
#include "ReactWidget.generated.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
UCLASS()
|
||||||
|
class REACTUMG_API UReactWidget : public UUserWidget
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
protected:
|
||||||
|
UPanelSlot* RootSlot;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit UReactWidget(const FObjectInitializer& ObjectInitializer);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Scripting | Javascript")
|
||||||
|
UPanelSlot* AddChild(UWidget* Content);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Scripting | Javascript")
|
||||||
|
bool RemoveChild(UWidget* Content);
|
||||||
|
};
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* 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 "UMGManager.h"
|
||||||
|
#include "Engine/Engine.h"
|
||||||
|
#include "Async/Async.h"
|
||||||
|
|
||||||
|
UReactWidget* UUMGManager::CreateReactWidget(UWorld* World)
|
||||||
|
{
|
||||||
|
return ::CreateWidget<UReactWidget>(World);
|
||||||
|
}
|
||||||
|
|
||||||
|
UUserWidget* UUMGManager::CreateWidget(UWorld* World, UClass* Class)
|
||||||
|
{
|
||||||
|
return ::CreateWidget<UUserWidget>(World, Class);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UUMGManager::SynchronizeWidgetProperties(UWidget* Widget)
|
||||||
|
{
|
||||||
|
Widget->SynchronizeProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UUMGManager::SynchronizeSlotProperties(UPanelSlot* Slot)
|
||||||
|
{
|
||||||
|
Slot->SynchronizeProperties();
|
||||||
|
}
|
||||||
@@ -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 "CoreMinimal.h"
|
||||||
|
#include "UObject/NoExportTypes.h"
|
||||||
|
#include "ReactWidget.h"
|
||||||
|
#include "Components/PanelSlot.h"
|
||||||
|
#include "Blueprint/UserWidget.h"
|
||||||
|
#include "Blueprint/WidgetBlueprintLibrary.h"
|
||||||
|
#include "Kismet/BlueprintFunctionLibrary.h"
|
||||||
|
#include "GameFramework/PlayerController.h"
|
||||||
|
#include "UMGManager.generated.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
UCLASS()
|
||||||
|
class REACTUMG_API UUMGManager : public UBlueprintFunctionLibrary
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
public:
|
||||||
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "Widget")
|
||||||
|
static UReactWidget* CreateReactWidget(UWorld* World);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "Widget")
|
||||||
|
static UUserWidget* CreateWidget(UWorld* World, UClass* Class);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "Widget")
|
||||||
|
static void SynchronizeWidgetProperties(UWidget* Widget);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "Widget")
|
||||||
|
static void SynchronizeSlotProperties(UPanelSlot* Slot);
|
||||||
|
};
|
||||||
@@ -0,0 +1,300 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as Reconciler from 'react-reconciler'
|
||||||
|
import * as puerts from 'puerts'
|
||||||
|
import * as UE from 'ue'
|
||||||
|
|
||||||
|
let world: UE.World;
|
||||||
|
|
||||||
|
function deepEquals(x: any, y: any) {
|
||||||
|
if ( x === y ) return true;
|
||||||
|
|
||||||
|
if ( typeof x !== 'object' || x === null || typeof y !== 'object' || y === null ) return false;
|
||||||
|
|
||||||
|
for (var p in x) { // all x[p] in y
|
||||||
|
if (p == 'children' || p == 'Slot') continue;
|
||||||
|
if (!deepEquals(x[p], y[p])) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var p in y) {
|
||||||
|
if (p == 'children' || p == 'Slot') continue;
|
||||||
|
if (!x.hasOwnProperty(p)) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare const exports: {lazyloadComponents:{}}
|
||||||
|
|
||||||
|
class UEWidget {
|
||||||
|
type: string;
|
||||||
|
callbackRemovers: {[key: string] : () => void};
|
||||||
|
nativePtr: UE.Widget;
|
||||||
|
slot: any;
|
||||||
|
nativeSlotPtr: UE.PanelSlot;
|
||||||
|
|
||||||
|
constructor (type: string, props: any) {
|
||||||
|
this.type = type;
|
||||||
|
this.callbackRemovers = {};
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.init(type, props);
|
||||||
|
} catch(e) {
|
||||||
|
console.error("create " + type + " throw " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init(type: string, props: any) {
|
||||||
|
let classPath = exports.lazyloadComponents[type];
|
||||||
|
if (classPath) {
|
||||||
|
//this.nativePtr = asyncUIManager.CreateComponentByClassPathName(classPath);
|
||||||
|
this.nativePtr = UE.NewObject(UE.Class.Load(classPath)) as UE.Widget;
|
||||||
|
} else {
|
||||||
|
this.nativePtr = new UE[type]();
|
||||||
|
}
|
||||||
|
|
||||||
|
let myProps = {};
|
||||||
|
for (const key in props) {
|
||||||
|
let val = props[key];
|
||||||
|
if (key == 'Slot') {
|
||||||
|
this.slot = val;
|
||||||
|
} else if (typeof val === 'function') {
|
||||||
|
this.bind(key, val);
|
||||||
|
} else if(key !== 'children') {
|
||||||
|
myProps[key] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//console.log("UEWidget", type, JSON.stringify(myProps))
|
||||||
|
puerts.merge(this.nativePtr, myProps);
|
||||||
|
//console.log(type + ' inited')
|
||||||
|
}
|
||||||
|
|
||||||
|
bind(name: string, callback: Function) {
|
||||||
|
let nativePtr = this.nativePtr
|
||||||
|
let prop = nativePtr[name];
|
||||||
|
if (typeof prop.Add === 'function') {
|
||||||
|
prop.Add(callback);
|
||||||
|
this.callbackRemovers[name] = () => {
|
||||||
|
prop.Remove(callback);
|
||||||
|
}
|
||||||
|
} else if (typeof prop.Bind == 'function') {
|
||||||
|
prop.Bind(callback);
|
||||||
|
this.callbackRemovers[name] = () => {
|
||||||
|
prop.Unbind();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn("unsupport callback " + name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update(oldProps: any, newProps: any) {
|
||||||
|
let myProps = {};
|
||||||
|
let propChange = false;
|
||||||
|
for(var key in newProps) {
|
||||||
|
let oldProp = oldProps[key];
|
||||||
|
let newProp = newProps[key];
|
||||||
|
if (key != 'children' && oldProp != newProp) {
|
||||||
|
if (key == 'Slot') {
|
||||||
|
this.slot = newProp;
|
||||||
|
//console.log("update slot..", this.toJSON());
|
||||||
|
puerts.merge(this.nativeSlotPtr, newProp);
|
||||||
|
UE.UMGManager.SynchronizeSlotProperties(this.nativeSlotPtr)
|
||||||
|
} else if (typeof newProp === 'function') {
|
||||||
|
this.unbind(key);
|
||||||
|
this.bind(key, newProp);
|
||||||
|
} else {
|
||||||
|
myProps[key] = newProp;
|
||||||
|
propChange = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (propChange) {
|
||||||
|
//console.log("update props", this.toJSON(), JSON.stringify(myProps));
|
||||||
|
puerts.merge(this.nativePtr, myProps);
|
||||||
|
UE.UMGManager.SynchronizeWidgetProperties(this.nativePtr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unbind(name: string) {
|
||||||
|
let remover = this.callbackRemovers[name];
|
||||||
|
this.callbackRemovers[name] = undefined;
|
||||||
|
if (remover) {
|
||||||
|
remover();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unbindAll() {
|
||||||
|
for(var key in this.callbackRemovers) {
|
||||||
|
this.callbackRemovers[key]();
|
||||||
|
}
|
||||||
|
this.callbackRemovers = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
appendChild(child: UEWidget) {
|
||||||
|
let nativeSlot = (this.nativePtr as UE.PanelWidget).AddChild(child.nativePtr);
|
||||||
|
//console.log("appendChild", (await this.nativePtr).toJSON(), (await child.nativePtr).toJSON());
|
||||||
|
child.nativeSlot = nativeSlot;
|
||||||
|
}
|
||||||
|
|
||||||
|
removeChild(child: UEWidget) {
|
||||||
|
child.unbindAll();
|
||||||
|
(this.nativePtr as UE.PanelWidget).RemoveChild(child.nativePtr);
|
||||||
|
//console.log("removeChild", (await this.nativePtr).toJSON(), (await child.nativePtr).toJSON())
|
||||||
|
}
|
||||||
|
|
||||||
|
set nativeSlot(value: UE.PanelSlot) {
|
||||||
|
this.nativeSlotPtr = value;
|
||||||
|
//console.log('setting nativeSlot', value.toJSON());
|
||||||
|
if (this.slot) {
|
||||||
|
puerts.merge(this.nativeSlotPtr, this.slot);
|
||||||
|
UE.UMGManager.SynchronizeSlotProperties(this.nativeSlotPtr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UEWidgetRoot {
|
||||||
|
nativePtr: UE.ReactWidget;
|
||||||
|
Added: boolean;
|
||||||
|
|
||||||
|
constructor(nativePtr: UE.ReactWidget) {
|
||||||
|
this.nativePtr = nativePtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
appendChild(child: UEWidget) {
|
||||||
|
let nativeSlot = this.nativePtr.AddChild(child.nativePtr);
|
||||||
|
child.nativeSlot = nativeSlot;
|
||||||
|
}
|
||||||
|
|
||||||
|
removeChild(child: UEWidget) {
|
||||||
|
child.unbindAll();
|
||||||
|
this.nativePtr.RemoveChild(child.nativePtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
addToViewport(z : number) {
|
||||||
|
if (!this.Added) {
|
||||||
|
this.nativePtr.AddToViewport(z);
|
||||||
|
this.Added = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeFromViewport() {
|
||||||
|
this.nativePtr.RemoveFromViewport();
|
||||||
|
}
|
||||||
|
|
||||||
|
getWidget() {
|
||||||
|
return this.nativePtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const hostConfig : Reconciler.HostConfig<string, any, UEWidgetRoot, UEWidget, UEWidget, any, any, {}, any, any, any, any> = {
|
||||||
|
getRootHostContext () {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
//CanvasPanel()的parentHostContext是getRootHostContext返回的值
|
||||||
|
getChildHostContext (parentHostContext: {}) {
|
||||||
|
return parentHostContext;//no use, share one
|
||||||
|
},
|
||||||
|
appendInitialChild (parent: UEWidget, child: UEWidget) {
|
||||||
|
parent.appendChild(child);
|
||||||
|
},
|
||||||
|
appendChildToContainer (container: UEWidgetRoot, child: UEWidget) {
|
||||||
|
container.appendChild(child);
|
||||||
|
},
|
||||||
|
appendChild (parent: UEWidget, child: UEWidget) {
|
||||||
|
parent.appendChild(child);
|
||||||
|
},
|
||||||
|
createInstance (type: string, props: any) {
|
||||||
|
return new UEWidget(type, props);
|
||||||
|
},
|
||||||
|
createTextInstance (text: string) {
|
||||||
|
return new UEWidget("TextBlock", {Text: text});
|
||||||
|
},
|
||||||
|
finalizeInitialChildren () {
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
getPublicInstance (instance: UEWidget) {
|
||||||
|
console.warn('getPublicInstance');
|
||||||
|
return instance
|
||||||
|
},
|
||||||
|
now: Date.now,
|
||||||
|
prepareForCommit () {
|
||||||
|
//log('prepareForCommit');
|
||||||
|
},
|
||||||
|
resetAfterCommit (container: UEWidgetRoot) {
|
||||||
|
container.addToViewport(0);
|
||||||
|
},
|
||||||
|
resetTextContent () {
|
||||||
|
console.error('resetTextContent not implemented!');
|
||||||
|
},
|
||||||
|
shouldSetTextContent (type, props) {
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
|
||||||
|
commitTextUpdate (textInstance: UEWidget, oldText: string, newText: string) {
|
||||||
|
if (oldText != newText) {
|
||||||
|
textInstance.update({}, {Text: newText})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
//return false表示不更新,真值将会出现到commitUpdate的updatePayload里头
|
||||||
|
prepareUpdate (instance: UEWidget, type: string, oldProps: any, newProps: any) {
|
||||||
|
try{
|
||||||
|
return !deepEquals(oldProps, newProps);
|
||||||
|
} catch(e) {
|
||||||
|
console.error(e.message);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
commitUpdate (instance: UEWidget, updatePayload: any, type : string, oldProps : any, newProps: any) {
|
||||||
|
try{
|
||||||
|
instance.update(oldProps, newProps);
|
||||||
|
} catch(e) {
|
||||||
|
console.error("commitUpdate fail!, " + e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeChildFromContainer (container: UEWidgetRoot, child: UEWidget) {
|
||||||
|
console.error('removeChildFromContainer');
|
||||||
|
//container.removeChild(child).catch(e => {
|
||||||
|
// console.error('removeChildFromContainer , e:' + e.message);
|
||||||
|
//});
|
||||||
|
},
|
||||||
|
removeChild(parent: UEWidget, child: UEWidget) {
|
||||||
|
parent.removeChild(child);
|
||||||
|
},
|
||||||
|
|
||||||
|
//useSyncScheduling: true,
|
||||||
|
supportsMutation: true,
|
||||||
|
isPrimaryRenderer: true,
|
||||||
|
supportsPersistence: false,
|
||||||
|
supportsHydration: false,
|
||||||
|
|
||||||
|
shouldDeprioritizeSubtree: undefined,
|
||||||
|
setTimeout: undefined,
|
||||||
|
clearTimeout: undefined,
|
||||||
|
cancelDeferredCallback: undefined,
|
||||||
|
noTimeout: undefined,
|
||||||
|
scheduleDeferredCallback: undefined,
|
||||||
|
}
|
||||||
|
|
||||||
|
const reconciler = Reconciler(hostConfig)
|
||||||
|
|
||||||
|
export const ReactUMG = {
|
||||||
|
render: function(reactElement: React.ReactNode) {
|
||||||
|
if (world == undefined) {
|
||||||
|
throw new Error("init with World first!");
|
||||||
|
}
|
||||||
|
let root = new UEWidgetRoot(UE.UMGManager.CreateReactWidget(world));
|
||||||
|
const container = reconciler.createContainer(root, false, false);
|
||||||
|
reconciler.updateContainer(reactElement, container, null, null);
|
||||||
|
return root;
|
||||||
|
},
|
||||||
|
init: function(inWorld: UE.World) {
|
||||||
|
world = inWorld;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#include "FMCJsEnvManager.h"
|
||||||
|
#include "JsEnv.h"
|
||||||
|
|
||||||
|
void FMCJsEnvManager::Init(TObjectPtr<UGameInstance> GameInstance)
|
||||||
|
{
|
||||||
|
M_GameInstance = GameInstance;
|
||||||
|
//TODO:从PuertsSettings获取是否开启Debug,是否阻塞,端口号等信息
|
||||||
|
//8080是调试端口
|
||||||
|
M_JsEnv = MakeShared<puerts::FJsEnv>(std::make_unique<puerts::DefaultJSModuleLoader>(TEXT("JavaScript")), std::make_shared<puerts::FDefaultLogger>(), 8080);
|
||||||
|
//M_JsEnv->WaitDebugger();
|
||||||
|
TArray<TPair<FString, UObject*>> Arguments;
|
||||||
|
Arguments.Add(TPair<FString, UObject*>(TEXT("GameInstance"), GameInstance)); // 可选步骤
|
||||||
|
M_JsEnv->Start("entry.js", Arguments);
|
||||||
|
//GameScript = MakeShared<puerts::FJsEnv>(std::make_unique<puerts::DefaultJSModuleLoader>(TEXT("JavaScript")), std::make_shared<puerts::FDefaultLogger>(), 8080);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FMCJsEnvManager::Release()
|
||||||
|
{
|
||||||
|
M_JsEnv.Reset();
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace puerts
|
||||||
|
{
|
||||||
|
class FJsEnv;
|
||||||
|
}
|
||||||
|
|
||||||
|
class FMCJsEnvManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Init(TObjectPtr<UGameInstance> GameInstance);
|
||||||
|
void Release();
|
||||||
|
private:
|
||||||
|
TObjectPtr<UGameInstance> M_GameInstance;
|
||||||
|
TSharedPtr<puerts::FJsEnv> M_JsEnv;
|
||||||
|
};
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// Fill out your copyright notice in the Description page of Project Settings.
|
||||||
|
|
||||||
|
|
||||||
|
#include "MingGameInstance.h"
|
||||||
|
|
||||||
|
|
||||||
|
void UMingGameInstance::Init()
|
||||||
|
{
|
||||||
|
Super::Init();
|
||||||
|
M_JsEnvManager = MakeShared<FMCJsEnvManager>(FMCJsEnvManager());
|
||||||
|
M_JsEnvManager->Init(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UMingGameInstance::Shutdown()
|
||||||
|
{
|
||||||
|
M_JsEnvManager->Release();
|
||||||
|
Super::Shutdown();
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// Fill out your copyright notice in the Description page of Project Settings.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "FMCJsEnvManager.h"
|
||||||
|
#include "Kismet/BlueprintPlatformLibrary.h"
|
||||||
|
#include "MingGameInstance.generated.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
UCLASS()
|
||||||
|
class MINGSIMULATOR_API UMingGameInstance : public UPlatformGameInstance
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
public:
|
||||||
|
virtual void Init() override;
|
||||||
|
virtual void Shutdown() override;
|
||||||
|
private:
|
||||||
|
TSharedPtr<FMCJsEnvManager> M_JsEnvManager;
|
||||||
|
};
|
||||||
@@ -8,6 +8,6 @@ public class MingSimulator : ModuleRules
|
|||||||
{
|
{
|
||||||
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
|
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||||
|
|
||||||
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "NavigationSystem", "AIModule", "Niagara", "EnhancedInput" });
|
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "NavigationSystem", "AIModule", "Niagara", "EnhancedInput","JsEnv" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
import * as UE from 'ue'
|
||||||
|
import {argv} from 'puerts';
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "mingsimulator",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "大明模拟器",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "http://micecola.top:8418/starmen1265/MingSimulator.git"
|
||||||
|
},
|
||||||
|
"author": "MiceCola",
|
||||||
|
"license": "ISC"
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "esnext",
|
||||||
|
"module": "commonjs",
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"useDefineForClassFields": false,
|
||||||
|
"jsx": "react",
|
||||||
|
"sourceMap": true,
|
||||||
|
"typeRoots": [
|
||||||
|
"Typing",
|
||||||
|
"./node_modules/@types"
|
||||||
|
],
|
||||||
|
"outDir": "Content/JavaScript"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"TypeScript/**/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user