跳到主内容
Rust
文章阅读

UE5(c++)使用rust编写插件给虚幻调用

2025/12/16113 次阅读7 分钟

新建一个空的UE插件项目

在插件根目录下的Source新建一个rust lib项目

html2markdown-dylib 项目名


 cargo new --lib html2markdown-dylib

image.png

路径如下 image.png

配置Cargo.toml

html2markdown_dylib 记得改这,不要使用-横杠


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

[dependencies]
mdka = "1.2.10"
reqwest = { version = "0.12.12", features = ["blocking"] }

[lib]
crate-type = ["dylib"]
name = "html2markdown_dylib"

[build-dependencies]
cbindgen = "0.27.0"

编写实际代码

md_loader.rs


pub struct MdLoader;

impl MdLoader {
    /// 从网络URL中加载markdown文本
    pub fn load_md_from_url(url: &str) -> String {
        let response = reqwest::blocking::get(url);
        if let Ok(response) = response {
            if let Ok(text) = response.text() {
                let md = mdka::from_html(&text);
                return md;
            }
        }
        return format!("Loading markdown from url: {}", url);
    }
}

构建头文件

在根目录下新建build.rs


extern crate cbindgen;

use std::env;

fn main() {
    let create_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let mut config: cbindgen::Config = Default::default();
    config.language = cbindgen::Language::Cxx;
    cbindgen::generate_with_config(&create_dir, config)
        .expect("unable to generate bindings")
        .write_to_file("include/UEHTML2MARKDOWN.h");
}

编译


cargo build --release

会在include目录下生成一个头文件,后面会在ue项目中使用 像这样


#include "UEHTML2MARKDOWN.h"

最终结果 image.png

在UE插件中添加依赖

UE插件名.Build.cs编辑


using System;
using System.IO;
using UnrealBuildTool;

public class UEHtml2Md : ModuleRules
{
	public UEHtml2Md(ReadOnlyTargetRules Target) : base(Target)
	{


		if (Target.Platform == UnrealTargetPlatform.Mac)
		{
			Console.WriteLine($"梁典典:module directory path: {ModuleDirectory}");
			var includePath = Path.Combine(ModuleDirectory, "../html2markdown-dylib/include");
			Console.WriteLine($"梁典典:header include path{includePath}");
			PublicIncludePaths.Add(includePath);
			PublicAdditionalLibraries.Add(Path.Combine(ModuleDirectory, "../html2markdown-dylib","target", "release", "libhtml2markdown_dylib.dylib"));
			RuntimeDependencies.Add("${PluginDir}/Binaries/Mac/libhtml2markdown_dylib.dylib");
		}


		PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
		
		PublicIncludePaths.AddRange(
			new string[] {
				// ... add public include paths required here ...
			}
			);
				
		
		PrivateIncludePaths.AddRange(
			new string[] {
			}
			);
			
		
		PublicDependencyModuleNames.AddRange(
			new string[]
			{
				"Core",
				"Projects",
				"UEHtml2Md"
			}
			);
			
		
		PrivateDependencyModuleNames.AddRange(
			new string[]
			{
				"CoreUObject",
				"Engine",
				"Slate",
				"SlateCore",
			}
			);
		
		
		DynamicallyLoadedModuleNames.AddRange(
			new string[]
			{
				// ... add any modules that your module loads dynamically here ...
			}
			);
	}
}

在插件模块接口中加载句柄

文件: 插件名.h


#pragma once

#include "Modules/ModuleManager.h"

class FUEHtml2MdModule : public IModuleInterface
{
public:

	void* Instance; // 句柄
	

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

文件:插件名.cpp



#include "UEHtml2Md.h"

#include "Interfaces/IPluginManager.h"

#define LOCTEXT_NAMESPACE "FUEHtml2MdModule"

void FUEHtml2MdModule::StartupModule()
{
	const auto PluginDir = IPluginManager::Get().FindPlugin("UEHtml2Md")->GetBaseDir();
	if (const auto LibPath = FPaths::Combine(*PluginDir, TEXT("Binaries/Mac/libhtml2markdown_dylib.dylib")); !LibPath.IsEmpty())
	{
		Instance = FPlatformProcess::GetDllHandle(*LibPath);
	}
	if (!Instance){
		UE_LOG(LogTemp,Error,TEXT("ldd: load dll failed!"));
	}else
	{
		UE_LOG(LogTemp,Log,TEXT("ldd: load dll success!"));
	}
}

void FUEHtml2MdModule::ShutdownModule()
{
	if (Instance)
	{
		FPlatformProcess::FreeDllHandle(Instance);
		Instance = nullptr;
	}
}

#undef LOCTEXT_NAMESPACE
	
IMPLEMENT_MODULE(FUEHtml2MdModule, UEHtml2Md)

最终: 在虚幻项目中引入插件

文件: 项目.Build.cs image.png

使用


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

	// 测试加载,这里调用rust写的函数,可以在插件中封装更友好的类调用
	const auto Result = load_markdown_form_url_ffi("https://www.rust-lang.org");
	const FString Str = FString(Result);
	UE_LOG(LogTemp, Display, TEXT("%s"), *Str);
	if (TextComponent)
	{
		TextComponent->SetText(FText::FromString(Str));
	}
}

返回顶部