怀特先生 发表于 2021-7-9 17:20:32

VCMI的源码笔记

个人笔记的样子,一些看问题当时的猜想,以后会被打脸

怀特先生 发表于 2021-7-9 17:21:34

21年7月9日
编译release时出现重定义问题,导致无法编译成功
将VCAI项目的..\..\bin\Debug\VCMI_lib.lib和..\FuzzyLite\fuzzylite\bin\Debug\fuzzylite-static-debug.lib这两个附加依赖项顺序调换后编译成功;具体原因未知

替换为中文资源后,游戏内出现乱码
将config/fonts.json中的字体改为中文支持的字体
将config/schemas/settings.json中的encoding项值修改为GBK后解决;编译的VCMI launcher提供该选择,此处效果应该为修改默认编码格式为GBK

游戏内出现无法播放游戏公司商标动画的问题
程序中无法检索到商标动画的资源,怀疑为资源路径不正确,应该是我放置的游戏资源版本问题,我使用的版本是4.0

游戏内出现无法播放音乐和过场动画对白问题
资源确定存在且可以正常的在游戏外播放,怀疑是SDL2调用ffmpeg解码时失败,这里因为vcpkg编译ffmpeg失败而无法验证

CResourceHandler //资源文件管理类
这个类负责索引资源的缺省情况,并且支持同样名字的资源可以同时存在,按照优先顺序来读取资源

CSimpleJoinScreen //IP地址输入框
很奇怪的,VCMI的实际游戏必须启动一个服务器,单机游戏是一个本地服务器。这也是为什么玩战役会弹出一个输入IP地址的对话框
这个对话框还不安全,如果点返回关闭以后再打开,会因为多线程的原因,导致对同一段内存同时进行读写操作而崩溃
改进方案:
对话框出现的很奇怪,在尝试进行单机游戏的情况下不应当出现
本地服务器很奇怪...因为不需要进行数据验效来防作弊,怀疑是把大量游戏过程写到了服务器的代码里,而不是游戏过程需要验效->检查是否是多人游戏->是->调用验效接口...加锁等待服务器验证结果...验效成功继续游戏
如果这种猜想正确,游戏启动时自动启用本地服务器,多人游戏时再析构并使用多人游戏服务器是一种更接近原版体验的选择

总上所述 发表于 2021-7-9 20:38:32

欢迎

总上所述 发表于 2021-7-9 20:40:12

@baalkyo

怀特先生 发表于 2021-7-12 18:38:52

21年7月12日
CMapService //工厂类,负责地图的加载(注释说还支持保存),调用CResourceHandler将地图文件加载到内存

CMap //地图的对象,似乎是可以从两种文件中加载,一种是原版的H3M文件,另一种是从json中读取,应该是VCMI自己的格式

CMapHeader //地图信息以及要求,玩家数量、地图名字(本地化文本,汉化文字从这里读取)、地图大小之类的.
原注释: The map header holds information about loss/victory condition,map format, version, players, height, width,...

CCampaign //里面实质上是有一堆CMap,只是需要的时候才转换出来,平时是用二进制存储在内存的
CCampaignHeader //战役,其余同上

CMapInfo //同时存了CMapHeader和CCampaignHeader,按照类型调用不同的对象,不太合适的设计
这里对深渊号角的支持注掉了,永不读取深渊号角的地图
enum EMapFormat: ui8
{
        INVALID = 0,
        //    HEX   DEC
        ROE = 0x0e, // 14
        AB= 0x15, // 21
        SOD = 0x1c, // 28
// HOTA = 0x1e ... 0x20 // 28 ... 30
        WOG = 0x33,// 51
        VCMI = 0xF0
};

SelectionTab //可显示的地图信息与UI,管理一堆CMapInfo,单人场景、战役、读取存盘都会用到
这边的设计上也不太合适,把UI和数据混合在一块了,这也是在打开战役的时候会弹出几帧类似于自定义战役的选择列表的原因
注意到比起原版,vcmi在调用单人场景的选择界面时,cpu使用很低,比原版强大很多,以后再对比下其它场景

怀特先生 发表于 2021-7-13 19:01:35

本帖最后由 怀特先生 于 2021-7-13 19:02 编辑

21年7月13日
CGuiHandler //UI的管理组件,IShowActivatable是UI对象的基类,UI系统是栈模式,后进先出
这套逻辑想要放进脚本很困难,使用了很多继承,我觉得会让做mod的时候添加新按钮新界面变困难

CBonusSelection //战役的介绍、选择奖励和难度的界面
这里选择奖励会触发一个无动画的报错,看起来是选奖励以后奖励的图片会开始播动画,但是官方战役的奖励图片是没有动画的,没啥影响
选择奖励和修改难度会重新设置整个UI,重读奖励图片(这个倒是不要紧,因为图片有缓存),可以改进
难度选择控件与原版不相符,最低难度和最高难度还可以继续点击,建议将:
      if (CSH->si->difficulty <= 0)
      {
                buttonDifficultyLeft->disable();
      }
      else
      {
                buttonDifficultyLeft->enable();
      }
      if (CSH->si->difficulty >= difficultyIcons.size() - 1)
      {
                buttonDifficultyRight->disable();
      }
      else
      {
                buttonDifficultyRight->enable();
      }
添加到void CBonusSelection::updateAfterStateChange()函数中

CPrologEpilogVideo //开场白,出现了老问题,旁白播不出来

进入游戏的函数sendStartGame验证了我之前的猜想,确实是把游戏过程写到服务器代码了

CGameState //存了一局游戏中的全局状态,比较重要的对象
CGameState->map 地图
CGameState->players 玩家,按颜色来查找,不按名字(所以可以重名)
CGameState->currentPlayer 正在进行回合的当前玩家
CGameState->scenarioOps 场景信息和剧情信息
CGameState->initialOpts 初始信息
CGameState->curB 当前正在进行的战斗信息
CGameState->day 过了几天
CGameState->teams 玩家之间的分组
CGameState->globalEffects 全局影响,还没看是什么意思,可能是xx之周
CGameState->rumor 传闻/谣言

怀特先生 发表于 2021-7-14 18:20:45

21年7月14日
CMemorySerializer //动态缓存序列,有点意思,这个是手动控制内存分配的策略,这里的问题是可以改为使用更复杂的链表结构,可以降低分配内存的难度

initNewGame和initCampaign的这两个接口,前者还会有一个是否生成随机地图的功能,后者不会。这里我遇到了无法创建随机地图的问题,待看

CBonusSelection这个UI在游戏内打开会有问题,尤其是可以修改难度,这会导致游戏崩溃
1.背景地图没有把发生地区充填成绿色
2.右上角的地图大小按钮是all
3.场景描述是空的
4.玩家分组空
5.已经选择的奖励空
6.难度不正确并且出现左右箭头
7.没有过场动画重播按钮
另外这个界面实际上和原版有差异,原版的地图是用框围住一圈的,VCMI没有这个框;原版的地图绿色还会闪烁几下,VCMI不会闪烁
检查发现除了重播按钮是没有实现,其它的都是代码里写错了,没有在添加奖励界面以后更新界面

游戏开始阶段
initNewGame或initCampaign 获取一个地图的实例CMap
initAllowedArtifactsList 按照允许出现的宝物列表设置地图上的宝物
initPlayerStates 初始化玩家(按照之前的选择分配玩家颜色与分组
placeCampaignHeroes 是战役的情况下放置战役英雄,注意会对战役有奖励英雄的情况做特殊处理

怀特先生 发表于 2021-7-15 16:26:48

21年7月15日
        奖励英雄有给哪个玩家的选项,也就是说可以实现选择对手的战役
        奖励英雄会优先给本族英雄
        玩家也会有种族,只是在游戏里不体现
        placeStartingHero 把英雄放置在主城镇的下方(这里是按城镇位置的x轴-2来得到的)
有战役关顺序的错误,例如战争的破坏第二章放在了第一章之前,待查
createObject 推测为在地图上创建物体(包括地形,原来地形也是物体的
getVisitableOffset //不太理解,这里应该是要拿到一个obj的平铺覆盖(占大地图上的几格),但是不理解为什么要加给角色位置
关于地图结构的吐槽,这可是遍历全地图上所有的对象啊,越大的地图就会越卡,虽然我也没想到更好的方案...
HEROES_FROM_PREVIOUS_SCENARIO //这个奖励类型我在游戏里没见过,继承之前场景的英雄

不行,VCMI没有脚本支持,UI系统全是写在c++里的,想要做添加新界面新按钮的mod不现实

xiaohua303 发表于 2021-7-17 11:41:04

VCMI的AI感觉好傻
页: [1]
查看完整版本: VCMI的源码笔记

捐赠