上一篇文章中我使用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