0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Rust在虚幻引擎5中的使用

jf_wN0SrCdH 来源:Rust语言中文社区 作者:Rust语言中文社区 2022-12-21 11:05 次阅读

前言

前段时间,研究了一套 Rust 接入 Maya Plugin 的玩法,主要原理还是使用 C ABI 去交互。那我想着 UE 是使用 C++ 写的,肯定也可以使用 C ABI 去交互,如果可以的话在 UE 中就可以使用 Rust 代码去跑,甚至还可以使用 Rust Crates,免得使用 C++ 去写关于数据库操作、加密操作等容易引发安全漏洞的代码。所以我在昨天开始了这个计划,使用了 Rust 的 html2md 的库在 UE 中使用,效果图如下。

开工

这个案例就是在 UE 中实现 html2md,虽然实际效果可能没卵用,主要目的还是带大家跑下这套流程。

我们要实现的功能就是在 Level 放置一个 Text Render
游戏开始阶段,这个
Text Render 就会拉取 Rust 官网页面,并将它转为 Markdown 格式展示在游戏中。

创建 UE 项目

我这里使用的版本是 5.0.1,大家使用 4.x 也是可以的。
我们创建一个
第三人称游戏 C++项目,命名为Html2mdExample
45f90370-807e-11ed-8abf-dac502259ad0.png

创建 UE 插件

我们将 Html2md 的功能封装成一个插件,这样就可以在各个项目中去使用它。

我们创建一个空白插件,插件名随意,我这边就叫 html2md

4619586e-807e-11ed-8abf-dac502259ad0.png

在插件中添加 Text Render

我们要在插件中添加一个 Actor,作为处理 HTTP 请求,并渲染 MarkdownText Render

一定要选择添加到插件中,而不是项目中。

4638d2fc-807e-11ed-8abf-dac502259ad0.png

TextRender.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Runtime/Engine/Classes/Components/TextRenderComponent.h"
#include "TextRender.generated.h"

UCLASS()
class HTML2MD_API ATextRender : public AActor
{
GENERATED_BODY()

UPROPERTY(VisibleAnywhere)
UTextRenderComponent* Text;

public:
ATextRender();

protected:
virtual void BeginPlay() override;

public:
virtual void Tick(float DeltaTime) override;

};

TextRender.cpp

简单写一写代码,添加一个 UTextRenderComponent,并修改它的颜色、旋转、缩放等属性。

#include "TextRender.h"

ATextRender::ATextRender()
{
PrimaryActorTick.bCanEverTick = true;

Text = CreateDefaultSubobject<UTextRenderComponent>(TEXT("Text"));
Text->SetupAttachment(RootComponent);
}

void ATextRender::BeginPlay()
{
Super::BeginPlay();

Text->SetRelativeRotation(FRotator(90.f, 180.f, 0.f));
Text->SetTextRenderColor(FColor(0, 255, 225));
Text->SetRelativeScale3D(FVector(2.f, 2.f, 2.f));
}

void ATextRender::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);

}

创建 Rust 项目

我们 Rust 项目要创建在 UE 插件项目目录下。找到插件源码目录,与 C++ 源码同级运行以下命令创建项目。

cargo new --lib html2md-dylib

464fe384-807e-11ed-8abf-dac502259ad0.png

Cargo.toml

[package]
name = "html2md-dylib"
version = "0.1.0"
edition = "2021"

# 将库打包成动态链接库
[lib]
crate-type = ["dylib"]
name = "html2md_dylib"

[dependencies]
# 用于 HTML 转为 Markdown
html2md = "0.2.14"
# 用于进行 HTTP 请求
reqwest = { version = "0.11.13", features = ["blocking"] }

[build-dependencies]
# 用于生成 C 头文件
cbindgen = "0.24.3"

src/md_loader.rs

在这里我们实现一个从 HTTP 请求拉取 HTML 并转为 Markdown 的实现。

pub struct MDLoader;

impl MDLoader {
pub fn load_md_from_url(url: &str) -> String {
let body = if let Ok(res) = reqwest::get(url) {
if let Ok(text) = res.text() {
text
} else {
return format!("Failed get {} text", url);
}
} else {
return format!("Failed get {} body", url);
};

html2md::parse_html(&body)
}
}

src/lib.rs

将函数导出,这样在动态链接库中就可以调用这个函数了。

use std::{c_char, CStr, CString};

mod md_loader;

#[no_mangle]
pub extern "C" fn load_md_from_url_ffi(url: *const c_char) -> *const c_char {
let url = unsafe { CStr::from_ptr(url) };
let res = md_loader::load_md_from_url(&url.to_string_lossy());

CString::new(res).unwrap().into_raw()
}

build.rs

我们需要使用到构建脚本来帮我们生成 C 头文件,我们将在 C++ 代码中使用它。

头文件生成到 include/UEHtml2md.h

extern crate cbindgen;

use std::env;

fn main() {
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let mut config: cbindgen::Config = Default::default();
config.language = cbindgen::Cxx;

cbindgen::generate_with_config(&crate_dir, config)
.expect("Unable to generate bindings")
.write_to_file("include/UEHtml2md.h");
}

html2md-dylib.build.cs

我们要添加一个 Rust 项目名.build.cs,让 UE 认到我们的动态链接库。相关文档

using System;
using System.IO;
using UnrealBuildTool;
public class Html2mdDyLib : ModuleRules
{
public Html2mdDyLib(ReadOnlyTargetRules Target) : base(Target)
{
Type = ModuleType.External;
if (Target.Platform == UnrealTargetPlatform.Win64)
{
// 添加头文件目录
PublicIncludePaths.Add(Path.Combine(ModuleDirectory, "include"));
// 添加 .lib
PublicAdditionalLibraries.Add(Path.Combine(ModuleDirectory, "target", "release", "html2md_dylib.dll.lib"));
// 添加 .dll
PublicDelayLoadDLLs.Add("html2md_dylib.dll");
// 我们需要将 .dll 文件复制到这边
RuntimeDependencies.Add("$(PluginDir)/Binaries/Win64/html2md_dylib.dll");
}
}
}

构建 Rust 项目

我们先运行构建命令

cargo build --release

然后将 html2md_dylib.dll 复制一份到 插件目录/Binaries/Win64/html2md_dylib.dll

这一步可以使用脚本去完成,我这边就不写了。

连接 Rust & UE

因为我们 Rust 项目目录名不符合 UE 的规范,所以我们要将 html2md-dylib 目录更改为 Html2mdDyLibhtml2md-dylib.build.cs 也需要更为 Html2mdDyLib.build.cs

将动态链接库添加到依赖

我们编辑 html2md.build.cs,也就是插件的构建脚本。在 PublicDependencyModuleNames 添加 Html2mdDyLibProjects

PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"Html2mdDyLib",
"Projects",
// ... add other public dependencies that you statically link with here ...
}
);

插件加载动态链接库

html2md.h

插件头文件中声明 DLL 句柄

// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"

class Fhtml2mdModule : public IModuleInterface
{
void* Html2mdLibraryHandle;

public:

/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
};

html2md.cpp

插件加载动态链接库

如果与本案例命名不同,记得替换代码中的路径

// Copyright Epic Games, Inc. All Rights Reserved.

#include "html2md.h"
#include "Core.h"
#include "Modules/ModuleManager.h"
#include "Interfaces/IPluginManager.h"

#define LOCTEXT_NAMESPACE "Fhtml2mdModule"

void Fhtml2mdModule::StartupModule()
{
FString BaseDir = IPluginManager::Get().FindPlugin("html2md")->GetBaseDir();
FString Html2mdLibraryPath = FPaths::Combine(*BaseDir, TEXT("Binaries/Win64/html2md_dylib.dll"));
Html2mdLibraryHandle = !Html2mdLibraryPath.IsEmpty() ? FPlatformProcess::GetDllHandle(*Html2mdLibraryPath) : nullptr;

if (Html2mdLibraryHandle == nullptr)
{
FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("ThirdPartyLibraryError", "Failed to load Html2mdLibrary"));
}
}

void Fhtml2mdModule::ShutdownModule()
{
FPlatformProcess::FreeDllHandle(Html2mdLibraryHandle);
Html2mdLibraryHandle = nullptr;
}

#undef LOCTEXT_NAMESPACE

IMPLEMENT_MODULE(Fhtml2mdModule, html2md)

Text Render 调用 Rust

终于来到了最后要实现的目标,我们将调用 Rust 接口,将返回值显示在 Text Render 中。

TextRender.cpp

#include "TextRender.h"
#include "Html2mdDyLib/include/UEHtml2md.h"

ATextRender::ATextRender()
{
PrimaryActorTick.bCanEverTick = true;

Text = CreateDefaultSubobject<UTextRenderComponent>(TEXT("Text"));
Text->SetupAttachment(RootComponent);
}

void ATextRender::BeginPlay()
{
Super::BeginPlay();

// 在这里调用 Rust 接口
const char* text = "https://www.rust-lang.org/";
FString result = FString(load_md_from_url_ffi(text));
Text->SetText(FText::FromString(result)); // 设置 Text 内容

Text->SetRelativeRotation(FRotator(90.f, 180.f, 0.f));
Text->SetTextRenderColor(FColor(0, 255, 225));
Text->SetRelativeScale3D(FVector(2.f, 2.f, 2.f));
}
void ATextRender::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);

}

编译项目

Visual Studio虚幻引擎 中编译都可以。

在 UE 中查看效果

我们将 TextRender 拖入场景。

465ca560-807e-11ed-8abf-dac502259ad0.png

运行游戏!我们会发现 Text Render 展示了 Rust 官网的内容。

46719b64-807e-11ed-8abf-dac502259ad0.png

总结

通过这次案例,我发现 Rust 可以在 UE 中做很多事情,我只是使用了 html2md 库作为案例来演示,大家感兴趣的话也可以去使用 wsmysql 等,关于网络通讯、数据库、甚至可以在 Rust 中实现游戏功能的算法、状态机等接入到虚幻引擎中使用。
能用少量并安全的代码去编写这些复杂的功能,何乐而不为呢?

用洛佳大佬的话来说:“如果996了一整天,每个开发者都无法避免疲惫的自己忘记释放指针或者释放了两次,很有可能一个漏洞就埋下来了。

能用编程语言理论检查出来漏洞还是好事情。这也不意味着我可以做一个强行检查 C++ 的编译器来达到一样的效果,因为这种理论要求整个语言要重新设计,Rust 就是重新设计的结果”


审核编辑 :李倩


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 数据库
    +关注

    关注

    7

    文章

    3799

    浏览量

    64393
  • 编程语言
    +关注

    关注

    10

    文章

    1945

    浏览量

    34737
  • Rust
    +关注

    关注

    1

    文章

    228

    浏览量

    6610

原文标题:Rust 在虚幻引擎 5 中的使用

文章出处:【微信号:Rust语言中文社区,微信公众号:Rust语言中文社区】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    如何用Rust编写一个ChatGPT桌面应用(保姆级教程)

    用IDEA开发的java仔) 安装 Rust 语言工具链:首先,请确保你已安装了 Rust 编程语言工具链,包括 Rust 编译器 (rustc) 和包管理工具 (cargo)。可以通过访问
    的头像 发表于 09-25 11:19 355次阅读
    如何用<b class='flag-5'>Rust</b>编写一个ChatGPT桌面应用(保姆级教程)

    C2000™器件的CRC引擎

    电子发烧友网站提供《C2000™器件的CRC引擎.pdf》资料免费下载
    发表于 08-30 10:38 1次下载
    C2000™器件<b class='flag-5'>中</b>的CRC<b class='flag-5'>引擎</b>

    未来嵌入式系统的黄金搭档 MCX N947遇上Rust

    基于 Rust 的安全性和性能引入了 RustRust 有很多优势,内存安全、并发安全、生态系统、包管理与构建管理,同时也有与 C/C++ 相同等级的性能。Rust 通过强化所有权
    的头像 发表于 07-25 09:14 1354次阅读
    未来嵌入式系统的黄金搭档 MCX N947遇上<b class='flag-5'>Rust</b>

    Vector和HighTec推出基于Rust和AUTOSAR Classic实现安全应用的解决方案

    Vector和HighTec两家公司成功展示了Rust应用程序与基于C语言的AUTOSAR Classic基础软件的集成,这在行业内还属首次。这样一来,Rust及其优势可以被应用在有最高功能安全要求的汽车ECU
    的头像 发表于 07-17 14:42 764次阅读
    Vector和HighTec推出基于<b class='flag-5'>Rust</b>和AUTOSAR Classic实现安全应用的解决方案

    esp32s3开发时,每次改动,rust编译的时间都很长为什么?

    esp32s3 开发时,每次改动,rust编译时间太长
    发表于 06-05 06:36

    Linux 6.10集成RISC-V更新,支持Rust编程语言

    本次补丁升级,Linux内核进一步扩展了对应于RISC-V架构的Rust编程语言支持。在此之前,Rust已可应用在x86_64、龙芯LoongArch以及ARM64等多种架构之上。
    的头像 发表于 05-23 17:16 961次阅读

    Aurix Tc375Lk上使用Rust编程语言可以吗?

    您好,如果我想在 Aurix Tc375Lk 上使用 Rust 编程语言,可以吗?如果是,链接 rust 编译器 ADS 和 freetoolchain 的步骤是什么?你有 ADS 或 freetoolchian
    发表于 05-17 13:42

    嵌入式系统中集成Rust和Qt的实践

    Rust 拥有丰富的库生态系统,用于序列化和反序列化、异步操作、解析不安全输入、线程、静态分析等,而 Qt 是一个 C++ 工具包,支持跨各种平台的丰富的、基于 GUI 的应用程序,从 iOS 到嵌入式Linux。Qt 应用程序包括表示业务逻辑的 C++ 插件
    发表于 05-03 10:26 1818次阅读
    <b class='flag-5'>在</b>嵌入式系统中集成<b class='flag-5'>Rust</b>和Qt的实践

    [鸿蒙]OpenHarmony4.0的Rust开发

    背景 Rust 是一门静态强类型语言,具有更安全的内存管理、更好的运行性能、原生支持多线程开发等优势。Rust 官方也使用 Cargo 工具来专门为 Rust 代码创建工程和构建编译
    的头像 发表于 02-26 17:28 893次阅读
    [鸿蒙]OpenHarmony4.0的<b class='flag-5'>Rust</b>开发

    谷歌捐款100万美元给Rust基金会,以增强C++与Rust的交互性

    如今,谷歌多项核心业务仍以 C++为主要编程语言,虽然无法直接使用Rust替代现有的C++程序,但谷歌依然选择支持Rust基金会的“Interop Initiative”计划,帮助那些选用C++的机构更为顺畅地过渡至Rust上。
    的头像 发表于 02-19 15:41 656次阅读

    鸿蒙OS之Rust开发

    Rust是一门静态强类型语言,具有更安全的内存管理、更好的运行性能、原生支持多线程开发等优势。
    的头像 发表于 01-29 17:19 959次阅读

    一次Rust重写基础软件的实践

    Rust 语言。本文的主要目的是通过记录此次转化过程遇到的比较常见且有意思的问题以及解决此问题的方法与大家一起做相关的技术交流和讨论。
    的头像 发表于 01-25 11:21 641次阅读

    如何用Rust过程宏魔法简化SQL函数呢?

    这是 RisingWave 中一个 SQL 函数的实现。只需短短几行代码,通过 Rust 函数上加一行过程宏,我们就把它包装成了一个 SQL 函数。
    的头像 发表于 01-23 09:43 961次阅读
    如何用<b class='flag-5'>Rust</b>过程宏魔法简化SQL函数呢?

    如何利用 S5PV210 的 G2D 引擎

    大佬们好! 小弟最近在学习 S5PV210 的时候遇见了一些关于 G2D 引擎的疑惑,有没有大佬好心帮帮忙,小弟在这里先谢过了 ! 我尝试裸机环境下面配置 S5PV210 的 G
    发表于 01-04 21:56

    从Rustup出发看Rust编译生态

    从Rustup出发看Rust编译生态 1. Rust和LLVM的关系是怎样的? 2. Rustuptargets是什么,为什么可以安装多个? 3. Rust
    的头像 发表于 01-02 11:00 534次阅读