游戏是Luminids,对于有兴趣的玩家可以报名参加测试: https://store.steampowered.com/app/4070510/Luminids/

我即将进行Steam测试,并意识到我无法依赖手写反馈。大多数玩家不会写任何东西,我无法在我不拥有的硬件上重现bug或性能问题。因此,我建立了一个遥测+反馈管道。分享我采用的方法和错误,以便在需要的时候可以节省时间。

目标: 了解玩家在哪里卡住了,玩家喜欢什么,时间花在哪里,以及在现场跑起来的游戏如何运行花费帧时间或收集任何PII。

堆栈:

  • Aptabase 用于产品分析 — 开源、隐私优先、EU区域、慷慨的免费等级(每月20k事件,随后约$10/200k)。它有一个Godot SDK; 我为更好的控制做了一个小客户端(批量HTTP POST via HTTPRequest)。
  • Discord webhook 用于在游戏中报告bug — 暂停菜单按钮打开一个表单(免费文本+截图),它POST直到一个私人频道。零后端。
  • 重用了我的现有hitch/FPS记录器来发送性能-根据硬件数据 - 唯一真正无法以任何其他方式获得的东西。

架构:

  • 一条规则在游戏线程上:只在内存缓冲区中追加一个小结构。从不触摸磁盘或网络。背景刷新每隔约20秒和退出时批处理它。我的track() 调用benchmarked在 \~2µs 。
  • 在设备上聚合,不要流式传输。 而不是每10秒一个事件,我积累计数器(时间-活动、特性使用、粗糙的居住网格)并在会话结束时发出一个总结事件。分析工具想要滚动任何事情,保持在免费等级之下。
  • 本地优先: 所有内容也写入一个本地包含的JSONL文件,如此一来,没有东西会丢失,如果网络断开,我就可以在离线状态下调试整个东西。
  • Godot-wise,它是3个autoloads,ConfigFile 用于秘密,HTTPRequest (线程化)用于云,和一个专门的Thread 用于本地写入。

隐私: 一个随机安装UUID:没有Steam ID,没有IP,没有PII → 在GDPR/CCPA之外,随着第一次启动的开关(Hades“传输数据”的模型)一起提供了一个优选的退出选项。最大的特点是将匿名调查答案与同一个安装ID相关联,例如“这感觉很混乱”,与“使用了2/8个系统并早期跳出”相关联。

我踩的陷阱(从我的痛苦中学习):

  1. 测量,不要假设。 我的“无害”的本地JSON刷新在主线程上是 7ms 每20秒:一个周期性阻塞。将其移到一个写入线程中 → 17µs 。只有当我对其进行了基准测试时才发现。
  2. Aptabase属性必须是扁平的标量值: 嵌套字典会被强制转换为字面字符串 "{Object}" 。将其展平到点符号键。
  3. 异步云接收器在退出时会丢失最后一个批次 (进程在HTTP完成之前就退出):这就是你的会话总结/结束事件,这些事件最丰富。将刷新同步 在退出时。
  4. 调试vs发布拆分: Aptabase根据一个isDebug 标志(OS.is_debug_build())将数据分开,所以开发运行不会污染生产。将云输出的门槛设置为OS.has_feature("release"/"template") 所以编辑器永远不会发送。
  5. 导出陷阱: 非资源文件(我的秘密.cfg 文件,其中包含密钥)不会打包,除非它们在导出预设的包含筛选器中。代码被发射;密钥没有被发射。静默本地-只读的fallback。

最大的教训: 最好的殖民地模拟(RimWorld,Factorio)从观看新玩家玩游戏中学到了更多东西,而不是从仪表板中。遥测告诉你玩家在规模上卡住了在哪里;观看会告诉你为什么。希望我能做到。

如果您有任何问题,欢迎提问。