UE(虚幻)学习(三) UnrealSharp插件中调用非托管DLL

上一篇文章中我使用UnrealSharp成功使用了我的一个C#控制台程序中的网络模块,这个程序是基于KCP网络了,其中调用了Cmake 编译的一个C++的DLL,在虚幻中DLL需要放在Binaries目录中才可以。Unity中只要放在任意Plugins目录中就可以。

但是Binaries目录版本控制一般不提交,我们可以改一下,改成按照路径加载。

修改前的脚本

csharp 复制代码
using System.Runtime.InteropServices;

//脚本修改自//https://github.com/a11s/kcp_warpper

namespace NetLibrary
{
    
    public unsafe class KCP
    {


        const string LIBNAME = "libikcp.dll";
        //---------------------------------------------------------------------
        // interface
        //---------------------------------------------------------------------

        /// <summary>
        /// create a new kcp control object, 'conv' must equal in two endpoint
        /// from the same connection. 'user' will be passed to the output callback
        /// output callback can be setup like this: 'kcp->output = my_udp_output'
        /// </summary>
        /// <param name="conv"></param>
        /// <param name="user"></param>
        /// <returns></returns>
        [DllImport(LIBNAME, EntryPoint = "ikcp_create", CallingConvention = CallingConvention.Cdecl)]
        public static extern IKCPCB* ikcp_create(uint conv, void* user);

        /// <summary>
        /// release kcp control object
        /// </summary>
        /// <param name="kcp"></param>
        [DllImport(LIBNAME, EntryPoint = "ikcp_release", CallingConvention = CallingConvention.Cdecl)]
        public static extern void ikcp_release(IKCPCB* kcp);

        /// <summary>
        /// set output callback, which will be invoked by kcp
        ///public static extern void ikcp_setoutput(IKCPCB* kcp, int (* output)(byte* buf, int len,             ikcpcb *kcp, void* user));
        /// </summary>
        /// <param name="kcp"></param>
        /// <param name="d_output"></param>
        [DllImport(LIBNAME, EntryPoint = "ikcp_setoutput", CallingConvention = CallingConvention.Cdecl)]
        public static extern void ikcp_setoutput(IKCPCB* kcp, System.IntPtr d_output);

       

篇幅太大没有必要,只展示部分代码片段。

可以看到之前是通过DllImport 载入LIBNAME变量来载入DLL的。

改为动态路径

先放上所有改动

csharp 复制代码
// 动态获取库路径
private static string GetLibraryPath()
{
    string baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
    //动态库的路径被拼接到 Binaries\Managed\Third\libikcp.dll,而你的实际库文件存放在 E:\myproject\Third\libikcp.dll,这说明 AppDomain.CurrentDomain.BaseDirectory 返回的路径是 Binaries\Managed。
    baseDirectory = Path.Combine(baseDirectory, "../../");
    string relativePath;
    
    // 根据平台选择库路径
    if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
    {
        relativePath = "ThirdParty/Kcp/Win64/libikcp.dll";
    }
    else if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("ANDROID")))
    {
        relativePath = "ThirdParty/Kcp/Android/arm64-v8a/libikcp.so";
    }
    else
    {
        throw new PlatformNotSupportedException("Unsupported platform");
    }

    return Path.Combine(baseDirectory, relativePath);
}

// DllImport 使用动态路径
private const string LIBNAME = "PLACEHOLDER"; // 占位符
private static bool _isResolverSet = false;
// 添加初始化方法以动态设置路径
public static void Initialize()
{
    if (_isResolverSet)
    {
        Loger.Debug($"BSserver DLL: 已经加载过了 .");
        return;
    }
    try
    {
        string libraryPath = GetLibraryPath();
        
        //Loger.Error($"BSserver DLL:{libraryPath}");
        NativeLibrary.SetDllImportResolver(typeof(KCP).Assembly, (name, assembly, path) =>
        {
            if (name == LIBNAME)
            {
                return NativeLibrary.Load(libraryPath);
            }
            return IntPtr.Zero;
        });
        _isResolverSet = true;
    }
    catch(Exception e) {
        //AClientMain.inst.PrintString("C# : DLL:" + libraryPath);
        Console.WriteLine($"Loaded library 加载错误 ."+e.Message);
        Loger.Error($"BSserver DLL 加载错误 : " + e.Message);
    }
    
}
//const string LIBNAME = "libikcp.dll";
//---------------------------------------------------------------------
// interface
//---------------------------------------------------------------------

/// <summary>
/// create a new kcp control object, 'conv' must equal in two endpoint
/// from the same connection. 'user' will be passed to the output callback
/// output callback can be setup like this: 'kcp->output = my_udp_output'
/// </summary>
/// <param name="conv"></param>
/// <param name="user"></param>
/// <returns></returns>
[DllImport(LIBNAME, EntryPoint = "ikcp_create", CallingConvention = CallingConvention.Cdecl)]
public static extern IKCPCB* ikcp_create(uint conv, void* user);

/// <summary>
/// release kcp control object
/// </summary>
/// <param name="kcp"></param>
[DllImport(LIBNAME, EntryPoint = "ikcp_release", CallingConvention = CallingConvention.Cdecl)]
public static extern void ikcp_release(IKCPCB* kcp);

使用方法:

我们在UE的工程下创建目录ThirdParty,按照代码里的路径,把DLL放进去,按照不同平台。

在加载DLL之前,我们需要调用Initialize方法初始化动态设置路径就可以了。

这些代码是ChatGPT帮忙写的,经过几次修改有了这段代码。

小技巧

以前是内事不决问baidu,外事不决问google,现在是内事问豆包,外事问ChatGPT。 :)

但是小心AI一本正经的胡说八道。 :P

相关推荐
应用市场2 天前
无人机姿态控制系统详解与实现
游戏引擎·cocos2d
陈言必行2 天前
Unity 性能优化 之 编辑器创建资源优化( 工作流 | 场景 | 预制体)
unity·编辑器·游戏引擎
1uther3 天前
Unity核心概念⑨:Screen
开发语言·游戏·unity·c#·游戏引擎
死也不注释3 天前
【Unity UGUI 交互组件——Slider(7)】
unity·游戏引擎·交互
挂科是不可能出现的3 天前
unity导入blender动画
unity·游戏引擎·blender
派葛穆3 天前
Unity-按钮实现场景跳转
java·unity·游戏引擎
绀目澄清4 天前
unity UGUI 鼠标画线
unity·计算机外设·游戏引擎
Magnum Lehar4 天前
3d wpf游戏引擎的导入文件功能c++的.h实现
3d·游戏引擎·wpf
作孽就得先起床4 天前
unity pcd 二进制版 简单显示文件对象(单色)
unity·游戏引擎
陈言必行4 天前
Unity 性能优化 之 静态资源优化 (音频 | 模型 | 纹理 | 动画)
unity·性能优化·游戏引擎