0%

许多库,共享出来的代码在往往存在一定的编译问题,Qt 源代码的问题也很多。不同版本存在不同的问题,建议参考 vcpkg 中编译的流程和需要的补丁。

环境

system: macOS 12.4 (21F79)
cpu: Apple M1
Xcode 13.2.1
macOS SDK 12.1

使用vcpkg编译安装arm64版

指令:vcpkg install qt5:arm64-osx, 本次安装的版本为 5.15.4

  • icu
    目前macOS使用vcpkg安装icu有些问题,没有自动依赖或指出需要的环境,需要手动安装autoconf,automake,autoconf-archive
  • XXX-NOTFOUND
    编译时qmake command还出现了XXX-NOTFOUND的字段,实质是依赖某个库但是没有正确找到。本次编译过程中出现了 ZSTD-XXX-NOTFOUNDLZMA_DEBUG-NOTFOUND, vcpkg 中重新安装zstdliblzma后解决了问题,推测这两个包应该是被文件加密系统影响没有正确的安装。
阅读全文 »

环境

UE4.27.2 win10 x64 VS2019

问题:

EnhancedInput在首次使用中会失效, 如果是在编辑器中运行, 第二次运行后就可以使用. 在打包的程序, 或以独立窗口运行都会失效. 奇怪的是, 在EnhancedInput失效的时候,是能正常访问EnhancedInput System Interface 的, 而且绑定也没有出问题

解决方法:

在角色蓝图中应用 EnhancedInput System Interface, EnhancedInput的代码里写到蓝图里的函数很多都是只有外表接口,没有实际作用的.但是在蓝图里显式引用了下EnhancedInput System Local Player Interface后的确在首次运行了也可以正常使用EnhancedInput了.

原因:

尚未找到确切原因, 推测是UObject的引用问题, 或者首次运行,在设置了EnhancedInput之后, 引擎有部分逻辑错误又将InputSystem初始化了

由于UE4的反射系统,应当慎重把握UObject对象的游戏性初始化时机。例如一个UObject对象,需要创建另一个UObject并持续引用时,则不应再PostInit中创建。这样会导致继承该UObject的蓝图,在保存时会运行一次PostInit,从而试图保存一个动态创建的UObject。
从另外一个角度来说,在UE4 editor中,由于代码热加载/编辑器多次运行地图,对象有可能在任何时候进行调用设置的游戏性初始化设置。而一般的设想中,这些游戏性初始化的顺序都是按照编写的逻辑线性运行,而这里由于为了实现编辑器的动态加载功能,有很多初始化将会被多次运行,但UOBject并不是完全重新初始化。所以需要仔细安排进入和退出代码。同时在网络环境,也会出现这种时序不对的问题,所以代码逻辑不能按照一般的线性逻辑去编写

先说结论

失败设计, 性能大幅度劣化

介绍

使用set/map需要一个对储存元素比较大小的算法,很多时候会用上向量、矩阵的储存。一般来说是这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct vec4 {
double x,y,z,w;

bool operator<(cosnt vec4& r) const {
if(x < r.x) return true;
if(x > r.x) return false;

if(y < r.y) return true;
if(y > r.y) return false;

if(z < r.z) return true;
if(z > r.z) return false;

if(w < r.x) return true;
return false;
}
};

需要多次比较,对CPU来说不够友好,特别是通常来说一次查找需要多次比较
Boost里面给出的方法是多次hash,而且不保证严格正确

1
2
3
4
5
6
7
8
size_t seed = 0;

for(; first != last; ++first)
{
hash_combine(seed, *first);
}

return seed;
阅读全文 »

编译下述代码时遇到了第一次遇到的问题

1
2
3
4
5
6
7
8
9
// 将boost::geometry中的box转换成自定义的Boundary
template <typename NumType = double>
Boundary<NumType, 2> fromBoost(
const boost::geometry::model::box<boost::geometry::model::point<NumType, 2,boost::geometry::cs::cartesian>>& box)
{
return Boundary<NumType, 2>(Vec<NumType,2>(box.min_corner().get<0>(), box.min_corner().get<1>()),
Vec<NumType, 2>(box.max_corner().get<0>(), box.max_corner().get<1>()));

}

这段代码在 VS2019 C++17 的标准下能编译过了,但是在 Apple Clang 下检查时,box.min_corner().get<0>() 等函数却报了一个第一次见的错误

阅读全文 »

在blog切换到Hexo同时使用Github Actions来实现CI/CD时,遇到了一个奇怪的问题。
使用下面代码生成的ssh Key无法被Github Actions使用

1
ssh-keygen -t rsa -b 4096 -C "Hexo Deploy Key" -f github-deploy-key -N "namespace"

下面代码生成的Key则可以

1
2
# 要保持passphase为空
ssh-keygen -t rsa -C "username@example.com"

暂不清除是passphase的问题还是-b -N等参数带来的问题

Solution

示例代码里的struct transition_table : mpl::vector改为继承boost::fusion::vector
在C++11的标准下就能解放vector容量上限
根据Boost中的解释

Question: Why do I get a very long compile error when I define more than 20 rows in the transition table?

Answer: MSM uses Boost.MPL under the hood and this is the default maximum size. Please define the following 3 macros before including any MSM headers:

#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS  
#define BOOST_MPL_LIMIT_VECTOR_SIZE 30 // or whatever you need  
#define BOOST_MPL_LIMIT_MAP_SIZE 30 // or whatever you need  

Question: Why do I get this error: ”error C2977: ‘boost::mpl::vector’ : too many template arguments”?

Answer: The first possibility is that you defined a transition table as, say, vector17 and have 18 entries. The second is that you have 17 entries and have a composite state. Under the hood, MSM adds a row for every event in the composite transition table. The third one is that you used a mpl::vector without the number of entries but are close to the MPL default of 50 and have a composite, thus pushing you above 50. Then you need mpl/vector60/70….hpp and a mpl/map60/70….hpp

Question: Why do I get a very long compile error when I define more than 10 states in a state machine?

Answer: MSM uses Boost.Fusion under the hood and this is the default maximum size. Please define the following macro before including any MSM headers:

#define FUSION_MAX_VECTOR_SIZE 20 // or whatever you need 

在不预定义宏的情况下无法修改。而且哪怕定义了,也是支撑不起大规模的状态机的(需要自己实现mpl/map60等等)

阅读全文 »

设置

editor 设置

  • 插件启用Gameplay Abilities和GameplayTagsEditor

Native代码设置

  • 要使用此系统的全部功能,添加"GameplayAbilities"、“GameplayTags"和"GameplayTasks"到项目的”(ProjectName).Build.cs"文件中的 PublicDependencyModuleNames 中。
  • 继承实现一个UAttributeSet作为属性集
  • 继承自ACharacterAPown之类的角色文件要同样继承接口IAbilitySystemInterface并添加组件UAbilitySysrtemComponent
阅读全文 »

  • Charactor 中开启物理模拟(Simulate Physics)后会使Movement component失效

UE4 attach 调试流程

  1. VS IDE中选择的工程配置要和Editor中要一直,鼠标在UE Editor左上角项目名字悬停看弹出的配置信息,一般都是Development
  2. VS中不用编译,直接attach到UE Editor
  3. 在UE Editor中点编译,多点几次,有时候代码可能会没有热更新上去
  4. 运行时就能命中VS中设置的断点了
  5. 如果还是无法命中代码,尝试在无法命中的地方随便修改下代码,然后再在UE编辑器里编译

C++ 读取蓝图类

  • 非静态加载
1
2
//GameplayAbilityBlueprint'/Game/Ability/MeleeBase_BP.MeleeBase_BP是在UE Editor中对对应蓝图类右键选择copy reference获得的,还需要强制加上 "_C"后缀
auto ability = LoadClass<UGameplayAbility>(NULL, TEXT("GameplayAbilityBlueprint'/Game/Ability/MeleeBase_BP.MeleeBase_BP_C'"));

以C++为基类的蓝图类

  • 当C++基类发生改变时,切记要把对应得蓝图子类切换下父类再切换回来才能应用到正确的数据

代码热更新问题

有很多类别都不能在C++代码编译后与立刻而更新到编辑器,比如Enum,函数返回参数等,在代码接口改变后,推荐关闭编辑器重新编译代码再打开

Model/View Framework

Qt中的QTableWidgetQListWidgetQTreeWidge等背后都是一套常见的Model/View架构用户分离显示和数据。一般的自定义View/Model都可以通过继承QAbstractItemViewQAbstractItemModel来快速实现。

ModelIndex

View/Model中通过ModelIndex来索引,ModelIndex中通过rowcolinternalPointer来索引到具体的数据。能够适配到绝大分数据结构。
但是也存在很大的问题,就在于internalPointer的类型是一个const void *,会丢失原有类型信息,这就要求internalPointer指向统一中数据结构。但是很多时候是无法把要显示的数据的数据结构都做成同一个虚基类(比如是修改不了的不同的外部连接库的类)。
通过传入类型擦除后的数据结构的指针,或者建立一个map表来索引internalPointer到具体的类型信息可以解决一部分问题,但是还有一些致命的问题————无法自动释放internalPointer指向类型擦除数据结构或者即使的清空map表,随着时间的迁移,内存占用会越来越庞大,或者引入了非常复杂的自动释放机制。

Solution

解决的办法很简单,将internalPointer的类型从const void *替换为QVariant等即可,以QVariant储存类型擦除后的数据结构,不需要修改任何逻辑。
不过这样则需要复制下QAbstractItemViewQAbstractItemModelModelIndex的源代码,重新构建下应用QVariantModelIndexModel/View框架。