当前位置: 首页 > news >正文

UE4中Taglib使用及插件制作

UE4中Taglib使用及插件制作

https://blog.ch-wind.com/ue4-taglib-usage-and-plugin/

UE4中Taglib使用及插件制作

2015年9月10日0

目录 [隐藏]

  • 1 Taglib的使用
  • 2 UE4插件制作
  • 3 Taglib改造
  • 4 Android平台
  • 5 RTTI
  • 6 插件使用

UE4使用第三方库时,为了方便跨平台编译、避免冲突和多次复用,将其制作成插件是不错的选择。

当前UE4版本为4.10.1。

Taglib的使用

Taglib是一个用于读取多媒体文件标签的第三方库,之所以会使用到,是因为当前FMod在读取含有非英文的标签会得到错误的结果。

Taglib需要自己使用CMake进行配置和编译。如果只是在Windows下使用的话,最简单的方法是直接引用生成的.lib文件。在项目的.build.cs中,ModuleRules的实现里面添加:

PublicIncludePaths.Add("F:/Libs/taglib-master/include/taglib");

PublicAdditionalLibraries.Add("F:/Libs/taglib-master/taglib/Release/tag.lib");

然后在需要使用的地方使用Taglib即可

#define TAGLIB_STATIC

#include "fileref.h"

#include "tag.h"

#include "tpropertymap.h"

// ……

/** TagLib Fetch Tag */

MusicItem->AlubmName = "";

MusicItem->ArtistName = "";

TagLib::FileRef TLFile(*MusicFullPath);

if (!TLFile.isNull() && TLFile.tag()){

OutputDebugStringA("TagLib Fetch Reading Begin.\n");

TagLib::Tag *tag = TLFile.tag();

std::wstring tWsName = tag->title().toWString();

if (tWsName.length()>0) MusicItem->SetDisplayName(tWsName.c_str());

MusicItem->AlubmName = tag->album().toWString().c_str();

MusicItem->ArtistName = tag->artist().toWString().c_str();

}

else{

OutputDebugStringA("TagLib Fetch Fails.\n");

}

/** TagLib Fetch Tag - End */

 

但是这样的方法在进行Android之类的平台上的编译时,会遇到很多麻烦。因此将其制作为UE4插件是最好的解决方法。

UE4插件制作

UE4的插件制作一直都处在WIP的状态,直到4.9版本开始,官方文档才变更为了可以使用的状态。因此,为了避免研究了之后官方大规模的更新,到了现在才开始研究。

UE4插件的制作相对还是比较简单的,在引擎中,官方就已经提供了4个示例插件,以其为基础进行插件开发即可。

插件的代码布局和UE4的游戏项目差不多,只有在Public中定义的类对外界才是可见的。详细的插件系统介绍可以参照[官方文档]。

插件的描述文件中最重要的地方是Modules中的Type参数,这个参数是决定插件的加载类型的。通常情况下,如果是在实际游戏逻辑中使用的插件的话,这里需要修改为Runtime。

如果是在项目的Plugins目录中添加插件目录进行开发的话,需要重新生成下项目文件

这样才能在vs中看到插件。还有比较容易忘记的是,直接继承自UObject的类,必须定义Blueprintable才可以在编辑器中可见。

Taglib改造

将taglib的源代码整个扔到Private目录中去,并在.build.cs中添加包含路径

PrivateIncludePaths.AddRange(

new string[] {

"TagLibs/Private","TagLibs/Private/taglib", "TagLibs/Private/taglib/toolkit", "TagLibs/Private/taglib/asf", "TagLibs/Private/taglib/mpeg", "TagLibs/Private/taglib/ogg", "TagLibs/Private/taglib/ogg/flac", "TagLibs/Private/taglib/flac", "TagLibs/Private/taglib/mpc", "TagLibs/Private/taglib/mp4", "TagLibs/Private/taglib/ogg/vorbis", "TagLibs/Private/taglib/ogg/speex", "TagLibs/Private/taglib/ogg/opus", "TagLibs/Private/taglib/mpeg/id3v2", "TagLibs/Private/taglib/mpeg/id3v2/frames", "TagLibs/Private/taglib/mpeg/id3v1", "TagLibs/Private/taglib/ape", "TagLibs/Private/taglib/wavpack", "TagLibs/Private/taglib/trueaudio", "TagLibs/Private/taglib/riff", "TagLibs/Private/taglib/riff/aiff", "TagLibs/Private/taglib/riff/wav", "TagLibs/Private/taglib/mod", "TagLibs/Private/taglib/s3m", "TagLibs/Private/taglib/it", "TagLibs/Private/taglib/xm"

}

);

要添加的比较多,主要是因为Taglib本身使用的就是这样的方法,稍微有点麻烦。

添加完路径之后,首先遇到的错误是

2>EXEC : error : The first include statement in source file ‘F:\Unreal\PluginDev\Plugins\TagLibs\Source\TagLibs\Private\taglib\mpeg\id3v2\id3v2header.cpp’ is trying to include the file ‘iostream’ as the precompiled header, but that file could not be located in any of the module’s include search paths.

这个错误的来源乍看之下很奇怪,其实在项目中有时候也会遇到。修正方法是,在cpp文件中首先包含模块头文件。

#include "TagLibsPrivatePCH.h"

添加了上面的文件之后,就会遇到Taglib内部大规模的namespace引发的错误,这一部分只能是一个一个的对命名空间进行控制修改了。

命名空间修正之后,会遇到如下错误

error C2872: “DWORD”: 不明确的符号

在UE4内部有对DWORD进行禁止使用的机制,这里需要重新开启。开启的方法是使用UE4内部提供的机制。

#include "AllowWindowsPlatformTypes.h"

#include <windows.h>

#include "HideWindowsPlatformTypes.h"

这样的话就可以使用DWORD等了。

在编译过程中还会遇到

4310:编译器执行的转换将截断数据

这个错误出现点有点多,直接让编译器忽略比较快。

#pragma warning(disable: 4310)

经过上面的几个步骤,基本就可以正常的通过编译了。只是在打包的时候会有这样的错误:

UnrealBuildTool: ERROR: Couldn’t find referenced module ‘PluginName’

或者

Plugin ‘PluginName’ failed to load because module ‘PluginName’ could not be found. Please ensure the plugin is properly installed, otherwise consider disabling the plugin for this project

这时候需要在Development下对代码进行一次重新编译。

这样的话就可以在Windows下正常的使用了。

Android平台

插件在Android平台打包时会遇到很多编译器相关的错误,需要进行一些修正。

首先遇到的错误是

error : delete called on ‘const TagLib::FileRef::FileTypeResolver’ that is abstract but has non-virtual destructor [-Werror,-Wdelete-non-virtual-dtor]

这个错误原本是warning,据说是taglib为了保证其自身的向下兼容性等原因而遗留的。

因此,修正方法是让编译器忽略这个warning。直接在模块头文件上加上

#if defined(__clang__)

#pragma clang diagnostic ignored "-Wdocumentation"

#pragma clang diagnostic ignored "-Wshadow"

#pragma clang diagnostic ignored "-Wdelete-non-virtual-dtor"

#pragma clang diagnostic ignored "-Wunused-function"

#define HAVE_SNPRINTF

#endif

RTTI

整个改造过程最麻烦的问题出在了RTTI上,Taglib内部大量的使用了dynamic_cast进行类型检测,而不是使用virtual来进行函数重载。

而UE4和大多数游戏引擎一样,出于效率原因是禁止使用RTTI的,好在UE4提供了可以单独在插件和项目中打开RTTI的方法。

在插件的.build.cs中添加如下所示的代码即可:

namespace UnrealBuildTool.Rules

{

public class TagLibs : ModuleRules

{

public TagLibs(TargetInfo Target)

{

bUseRTTI = true; // 打开RTTI

// ... ...

但是,这个开关对Android是没有作用的,我们需要编辑引擎源码进行修正。在AndroidToolChain.cs中,将所有的

Result += " -fno-rtti";

改为

if (!CompileEnvironment.Config.bUseRTTI) Result += " -fno-rtti";

混合使用RTTI的情况下需要注意的是,根据编译器的不同,将定义了virtual的多态类型在两种不同的编译方式之间混合使用时,其结果是不可预知的。具体而言可能会出现类似下面的错误:

error: undefined reference to ‘typeinfo for UObject’

error: cannot pass object of non-trivial type ‘FString’ through variadic function; call will abort at runtime [-Wnon-pod-varargs]

结论上,就是在插件中要尽量避免使用UE4内部的类。详细的技术上的原因可以参照[这里]。

插件使用

插件制作完成后,使用起来就比较简单了。如果要在代码中使用TagLibs插件的话,在.build.cs中添加

PrivateDependencyModuleNames.AddRange(new string[] { "TagLibs" });

然后在要使用的类,一般是蓝图函数库的文件中添加包含

#include "ITagLibs.h"

以及使用

ITagLibs::Get().GetMusicInfo(args…)

即可。

其他详情可参见完成的Taglib插件源码,已上传至[Github]。

Taglib | UE4 | 插件

本博客所有内容遵循CC BY-NC-SA 3.0协议, 如有转载,请注明出处。

 

 

 

 

 

相关文章:

  • UE4编辑器扩展踩坑血泪史
  • require函数
  • UE4 给static mesh 动态添加Socket
  • UE4 角色用Child Actor组建添加装备 这样方便随时添加,更换套装等行为
  • Unity Assets目录下的特殊文件夹名称
  • Unity-ShaderVariantCollection
  • Unity渲染教程(九):复杂材质 https://www.jianshu.com/p/5e3af869870f
  • HttpWebRequest(System.Net)模拟HTTP发送POST
  • C#中用HttpWebRequest中发送GET/HTTP/HTTPS请求 (转载)
  • System.Net.HttpWebRequest.GetRequestStream超时问题
  • System.Net.HttpWebRequest.GetResponse() 远程服务器
  • 【转载】HttpWebRequest的GetResponse或GetRequestStream偶尔超时 + 总结各种超时死掉的可能和相应的解决办法
  • UE4 AIController
  • [UE4]创建自定义AIController的方法(C++)
  • eclipse + pydev远程调试OpenStack
  • IE9 : DOM Exception: INVALID_CHARACTER_ERR (5)
  • ABAP的include关键字,Java的import, C的include和C4C ABSL 的import比较
  • gf框架之分页模块(五) - 自定义分页
  • isset在php5.6-和php7.0+的一些差异
  • JavaScript HTML DOM
  • JavaScript对象详解
  • MYSQL如何对数据进行自动化升级--以如果某数据表存在并且某字段不存在时则执行更新操作为例...
  • PaddlePaddle-GitHub的正确打开姿势
  • Quartz实现数据同步 | 从0开始构建SpringCloud微服务(3)
  • REST架构的思考
  • SegmentFault 2015 Top Rank
  • SpiderData 2019年2月16日 DApp数据排行榜
  • Xmanager 远程桌面 CentOS 7
  • 阿里云爬虫风险管理产品商业化,为云端流量保驾护航
  • 警报:线上事故之CountDownLatch的威力
  • 批量截取pdf文件
  • 前端代码风格自动化系列(二)之Commitlint
  • 什么软件可以剪辑音乐?
  • 手机端车牌号码键盘的vue组件
  • 微信小程序设置上一页数据
  • 小李飞刀:SQL题目刷起来!
  • 一个项目push到多个远程Git仓库
  • 原创:新手布局福音!微信小程序使用flex的一些基础样式属性(一)
  • ionic异常记录
  • Java性能优化之JVM GC(垃圾回收机制)
  • 回归生活:清理微信公众号
  • ​软考-高级-信息系统项目管理师教程 第四版【第23章-组织通用管理-思维导图】​
  • # 日期待t_最值得等的SUV奥迪Q9:空间比MPV还大,或搭4.0T,香
  • #### go map 底层结构 ####
  • #Z0458. 树的中心2
  • #在线报价接单​再坚持一下 明天是真的周六.出现货 实单来谈
  • (2.2w字)前端单元测试之Jest详解篇
  • (M)unity2D敌人的创建、人物属性设置,遇敌掉血
  • (阿里巴巴 dubbo,有数据库,可执行 )dubbo zookeeper spring demo
  • (附源码)springboot家庭装修管理系统 毕业设计 613205
  • (蓝桥杯每日一题)平方末尾及补充(常用的字符串函数功能)
  • (六)c52学习之旅-独立按键
  • (四)Tiki-taka算法(TTA)求解无人机三维路径规划研究(MATLAB)
  • (一)Thymeleaf用法——Thymeleaf简介
  • (转)项目管理杂谈-我所期望的新人