云风的 BLOG

思绪来得快去得也快,偶尔会在这里停留

Latest articles

服务的创建和退出问题

TL;DR 系统中每个和系统活得一样久的单元(服务),都应该提供一个关闭接口,而不是释放接口。关闭只做必要操作,不必释放资源,不必和其它单元协调。整个系统退出时,只需要命令所有单元关闭,然后让世界戛然而止。 最近在和同事一起完善 ltask 。这个项目可以看成是对 skynet 的一个回顾。我们打算把它用在客户端引擎中。 在 ltask 中,原来在 skynet 里用 C 实现的 timer network 等线程都被移到了 lua 中实现。它们被成为 exclusive service ,会独占一个操作系统线程,但之外的部分和普通服务并没有太大区别。 因为这样一些基础服务也挪到了 lua 中实现,以前在 skynet 中天然而成的层级被模糊了。在 skynet...

fbx 到 gltf 转换问题

我们的游戏引擎采用的资源格式是 gltf 2.0 。 gltf 在这几年发展很迅猛,我认为是 3d 文件格式中标准化做的最好的一个。可惜,游戏行业中,美术创作人员常用的 max maya 等工具对其支持还有瑕疵。Autodesk 在 2019 年作为 contributor 成员加入了 Khronos 组织,在 max maya 这些 Autodesk 工具中看到官方的 gltf 支持应该不会等太久。来自官方的消息 ,‎在 2020 的 3 月底,gltf 加入官方支持已经处于 Under Review 状态。希望今年内可以看到。 因为 Unity 的流行,fbx 是游戏行业目前的实施标准。但 fbx 是一个私有格式,并没有任何公开的标准文档。而且其格式设计有很多历史包袱,甚至连字段名都因为有...

skynet 处理 TCP 连接半关闭问题

TCP 连接是双工的,既可以上行数据,又可以下行数据。连接断开时,两侧通道也是分别关闭的。 从 API 层面看,如果 read 返回 0 ,则说明上行数据已经关闭,后续不再会有数据进来。但此时,下行通道未必关闭,也就是说对端还可能期待收取数据。 同样,如果 write 返回 -1 ,错误是 EPIPE ,则表示下行通道已经关闭,不应再发送数据。但上行通道未必关闭,之后的 read 还可能收到数据。 用 shutdown 指令可以主动关闭单个通道(上行或下行)。 如果 tcp 连接只有一侧关闭,我们(skynet 中)称之为半关闭状态。在最开始,skynet 是将半关闭视为关闭的。这是因为,skynet 一开始只考虑网络游戏应用。在网络游戏中,连接被视为不可靠的,任何时候客户端都应该妥善处理服务器断开的情况,而服务器也应该处理客户端不告而别。业务层一般会额外做一套握手协议,不完全依赖...

ltask :Lua 的多任务库

ltask 是我前两周实现的一个 lua 的多任务库 。 这个项目复用了我之前的一个类似项目的名字 。目的是一样的,但是我做了全新的设计。所以我干脆将以前的仓库移除,以同样的名字创建了新的仓库。 和之前的版本设计不同。在消息通讯机制上,这个更接近 skynet 的模型,但它是一个库而不是一个框架。调度模块是按前段时间的想法实现的,不过只做了一个初步的模型,细节上还有一些工作待完善。 它的 C 部分提供的库被分为四个部分: ltask ltask.bootstrap ltask.exclusive ltask.root 如果用官方的 Lua 解析器作为入口,那么入口代码只可以使用 ltask.bootstrap 这个子库。它提供的 api...

关于 skynet 调度器的一点想法(续)

这篇是继续上次的一些想法。 我最近想重新做一个新的基于消息管道的 N:M 多任务调度器。主要用在我们的客户端上。算是解决在使用 skynet 多年来总结出来的一些问题。 首先,我想改变 skynet 服务直接将待发消息投递到对方消息队列的做法。发出消息会让服务挂起,等待投递。 然后,我设计了一个叫做调度器的模块,用于把带发消息投递到对应的接收管道中。调度器是发送消息的消费者,接收管道的唯一生产者;而每个服务是它自己的发送消息的唯一生产者,接收管道的唯一消费者。这样没有竞争,当消息队列是定长的时候,也无需使用锁(但引入了消息队列满的新状态)。 同时,也遵循 skynet 的约定,send 消息是不会引起服务重入的。所以,因为发送消息而挂起的服务,调度器会尽快处理,给出结果,延续服务的运行。中间不会插入针对这个服务的别的事务。消息投递结果可能是成功,也可能是对方不存在,或对方队列阻塞。如果发送发送阻塞,逻辑层可以决定是重试还是丢弃。...

把 skynet 的原子操作换成了 stdatomic

stdatomic 已经是 C11 的标准,并且成为了 C++ 标准的一部分。msvc 也将会支持 stdatomic 。在 skynet 项目开始的时候,还没有这个可以用,所以我采用的是更早一点的 gcc sync 系列的扩展 。 我想,用 stdatomic 来实现原子操作,会有利于 skynet 未来的发展。上周花了点时间熟悉这套 api 并在 skynet 中实现。同时保留了之前的实现,如果编译器定义了 __STD_NO_ATOMICS__ 就会切换回老版本。 首先,C11 增加了 _Atomic(T) 类型。这在之前的 gcc Atomic builtins 里没有。过去是直接使用已有的原生数据类型的。现在,如果一个 int 是一个原子变量,就需要使用 atomic_int...

预运算地图寻路的一种方法

上次谈到服务器上寻路算法的优化。文末提到,其实,针对具体需求,我们实际上可以预运算所有的路径,把结果持久化在文件中,运行时用 O(1) 的时间就可以查询到任意路径。 对于半径为 N 的地图网格,选取任意两点作为起点和终点,一共有 N^4 数量级的路径,直接按起点和终点来缓存路径显然不现实。 但实际上,除非整张地图是个复杂的迷宫,大部分路径是重复的。这和人实际上行路是一样的。如果你从家中的卧室去到办公室的工位上,整条路径和你从客厅出发是高度重叠的;仅有出家门前的那一小段略有不同。 在服务器上寻路,通常解决的是 NPC 的小范围内移动绕开障碍(从卧室到家门)的问题,远距离移动的路线(从家到公司)应当在另一个层面去解决。 基于网格寻路无论是用 A star 还是基于图的 dijkstra...

内存的惰性初始化

这两天和同事讨论一个问题,我写了个小玩意。 事情起因是,我们公司上海的工作室的一个 MMO 项目做服务器压力测试。谈及优化,涉及到服务器中使用的 C 模块。他们把同一套 C++ 加上 namespace 编译了很多份,供多个服务使用。我很好奇,一般来说,Lua 的 C 模块是可以供多个 vm 共用的,并不需要实际链接很多份。仔细探究发现,原来这个代码中用到了一些全局对象(singleton 模式)。 我本能的觉得全局对象的设计中透着糟糕的味道,在逐个分析每个全局对象的必要性时,发现了一个有趣的东西:寻路模块。 寻路模块本身的实现是没有持久状态的,场景地图的障碍信息是独立出去的静态不变数据,全局共享,这是合理的设计。但是一个无状态的 pathfinding 对象却被实例化了很多份,供不同的服务独立使用。...

粒子系统中的材质组织

粒子系统中,势必会引入多种材质。要么按材质分为不同的管理器对象,要么把所有粒子片放在一个管理器下,但增加材质的属性。 如果是前者,即使粒子的其它属性都有共性,也无法一起处理;而后者,则涉及材质分类的问题。 我们不大可能在渲染阶段无视粒子的材质属性,每个粒子片都单独向渲染器提交材质。因为无论是面片粒子,还是模型粒子,都应该批量提交粒子的空间结构数据,然后一次渲染。如果粒子是面片,那么就应该把一组粒子的顶点信息组织在同一个顶点 buffer 中;如果粒子是模型,就应该把每个个体的空间矩阵组织在 Instance Buffer 中。 如果材质属性只是一个 id 或材质对象指针,作为一个属性关联在粒子对象上的话,不同材质的粒子是无序的,怎样的数据结构可以方便管理呢? ...

粒子管理器的 C++ 封装

这篇接着上一篇 粒子系统的设计。 TL;DR 在花了一整个晚上用 C++ 完成了这一块的功能后,我陷入了自我怀疑中。到底花这么多精力做这么一小块功能有意义么?强调类型安全无非是为了减少与之关联的代码的缺陷,提高质量;但代码不那么浅显易懂却降低了质量。 我们用 C 实现了一个基于 ECS 结构的粒子系统的管理器,代码 psystem_manager.h 在这里。 先来回顾一下设计:在这个粒子系统中,我期望把粒子对象的不同属性分开管理。 即:传统的面向对象的数据结构中,一个对象 particle 可以有很多属性 a,b,c 。通常是用一个结构体(或类)静态定义出来的,这些属性也可以看作是 a b c 组件,它们构成了粒子对象。而在 ECS 结构中,我们在每个时间点,并非去处理一个对象的多个属性,而是处理同一个属性的多个对象。所以,我们最好按属性分类将多个对象的同一属性聚合起来,而不是按对象,把同一对象的不同属性聚合在一起。...

Discover, share and read the best on the web

Subscribe to RSS Feeds, Blogs, Podcasts, Twitter searches, Facebook pages, even Email Newsletters! Get unfiltered news feeds or filter them to your liking.

Get Inoreader
Inoreader - Subscribe to RSS Feeds, Blogs, Podcasts, Twitter searches, Facebook pages, even Email Newsletters!