小组

【游戏众筹&招募】视觉小说《「命运之绳」》预告&规划
Dreamdawn 2022-05-21

「命运之绳」预告:

发行日期:暂定为2023-3-1日发行

发行平台:itch.io,steam,Google Play

可游玩平台:Linux x86_64内核版本大于等于5.4,Windows 7及以上(不含非x86_64版本),Android 7.0及以上。

游戏引擎:Ren'Py

程序语言:

Python,C++,C,Ren'Py,Cython,dotnet(Dreamdawn Launcher使用),Java(Android版本编译时使用)

现需要人员如下

  1. 翻译:简体中文到繁体中文
  2. 翻译:简体中文到英语(美国)
  3. 翻译:简体中文到日本语
  4. 画师*2:负责立绘
  5. 画师:负责场景绘画
  6. 程序*2:负责实现玩法与其他Dreamdawn解决方案

关于AI续写:我们将在游戏中集成自主研发的ai文字续写与聊天引擎,同时配合2个开源项目来提供更好的体验:MockingBirdPainterEngine

关于配音问题:如果向游戏添加配音,甚至比我们和Cloudflare签Enterprise合同还贵,我们将视众筹以及销售情况确定是否对游戏进行配音,此外对于全语种而言添加配音价格过高,可能不会添加。

文本量:原型文本大约30w,通过AI引擎续写,扩充后可达13线路,每条线路均有原生的24万字文本+AI过渡文本。

独创玩法的填空选项,目前来看视觉小说行业独家提供。此外,我们的AI文本引擎也会开源(虽然代码质量不敢恭维)

文本价格:70¥/千字

翻译价格(根据中文字数计算):英语80¥/千字,日本语100¥/千字

立绘价格:700+0.2%游戏净利润/张


文本概括:

刚进高一的学习生活似乎就已进入了高三,沉重的学业中似乎依然找不到什么可苦中作乐的点了,然而就在此时,一条头绳,就这么把他们的生活串接在了一起。
五位少男少女的灵魂,在一个奇妙的日子中成功的在虚幻中碰头,而之后,便被命运决定了他们的灵魂交换,而作为男主,自然是得有一个好基友和妹妹了。在剧情中男主将有概率随着选项的选择而推进主角所在身体以及潜移默化的影响,通过此类事件推进主角与剧情变换。
而那条头绳,也编织起了这五位少男少女的命运。


流畅自然的文本与选项衔接,提供更沉浸的体验!

游戏特色:AI混合制作,超大量文本以及目前全行业唯一的填空选项,可以念一段话并做成自己的语音包

我们的官方网站:https://www.dreamdawn.net,相关合作事宜以及联系方式均可在官网找到。

由于官网经常抽风,所以emmmmmm

Contact us:

  1. Telegram:@Dreamdawn_Studio
  2. Twitter:@DreamdawnStudio
  3. E-mail:hr@dreamdawn.net

0CubeLori发布的帖子也是同一个项目,但是我是策划()

新游鉴赏:国产赛博朋克Roguelite横版动作游戏《生死轮回》LOOPMANCER首次轮回玩派PLAYSECT试玩
玩派 2022-05-21

   《生死轮回》LOOPMANCER是由北京的18人游戏开发团队eBrainStudio制作,赛博朋克题材的Roguelite横版动作游戏。游戏预计登陆PC和主机平台,具体发售日和售价不明。

游戏简介:

在2046年的龙城,脑机接口,仿生义体和纳米生物技术普及,社会高度发达,贫富差距分化严重。

项子戌是一名出色的私家侦探,在执行“调查著名女记者失踪”的任务时不幸遇难。伴着死亡,他从自己公寓的床上惊醒。还没来得及思索,电话响起,事务所的同事为他介绍新案子,任务便是"调查失踪的著名女记者"。

Image title


本作使用UE4引擎开发,描绘了赛博朋克美学下的东方城市风貌,设计了7张庞大精美的关卡。玩家将在这个鲜活的东方未来城市中与多方势力战斗,经历死亡与重生,探索轮回背后的真相。

(转发自:原日志地址
新游鉴赏:国产赛博朋克Roguelite横版动作游戏《生死轮回》LOOPMANCER首次轮回玩派PLAYSECT试玩
玩派 2022-05-21

   《生死轮回》LOOPMANCER是由北京的18人游戏开发团队eBrainStudio制作,赛博朋克题材的Roguelite横版动作游戏。游戏预计登陆PC和主机平台,具体发售日和售价不明。

游戏简介:

在2046年的龙城,脑机接口,仿生义体和纳米生物技术普及,社会高度发达,贫富差距分化严重。

项子戌是一名出色的私家侦探,在执行“调查著名女记者失踪”的任务时不幸遇难。伴着死亡,他从自己公寓的床上惊醒。还没来得及思索,电话响起,事务所的同事为他介绍新案子,任务便是"调查失踪的著名女记者"。

Image title


本作使用UE4引擎开发,描绘了赛博朋克美学下的东方城市风貌,设计了7张庞大精美的关卡。玩家将在这个鲜活的东方未来城市中与多方势力战斗,经历死亡与重生,探索轮回背后的真相。

(转发自:原日志地址
荐书《梦之囚徒》
方程 2022-05-20

以“给我的游戏取材”为借口到处找书的过程中,我偶然发现一套叫《梦之囚徒》的法国漫画,很纯正一部元漫画。

丛书第一册《起源》第23页最后一格,主角读到了《起源》这部漫画的第27页。

Image title

太有趣了!

我的游戏欲似乎复活了?
方程 2022-05-20

还有大约一个月就到夏促。钱包急不可耐!

老头环!意航员2!狐尔达!遗忘之城!小白兔电商!神经病主播女孩!绝路!沙贝!瑟芬妮!梦境档案2!

这一年来我长期陷于游戏低迷,但现在,我想玩!

停止一年不买不玩,看来还是有疗效的。

游戏鉴赏家:3D二次元动作砍杀游戏《刀剑乱舞无双》KOEI TECMO 玩派PLAYSECT试玩
玩派 2022-05-20

    《刀剑乱舞无双》KOEI TECMO 全系列作品结合了由DMM GAMES和Nitro+共同推出的刀剑养成模拟游戏《刀剑乱舞-ONLINE-》,以及由光荣特库摩开发的动作游戏《无双》系列的元素,为玩家带来一骑当千的爽快感。

十五把失去了主人——“审神者”的刀剑男士, 在时间轴上漂流之际突然遭受敌人“时间溯行军”的袭击。 随后,他们收到由“时之政府”指派的一项名为“突击调查”的任务。 失去主人的他们决定共同出征,前往历史逐渐遭到篡改的战国时代。

Image title


(转发自:原日志地址
游戏鉴赏家:3D二次元动作砍杀游戏《刀剑乱舞无双》KOEI TECMO 玩派PLAYSECT试玩
玩派 2022-05-20

    《刀剑乱舞无双》KOEI TECMO 全系列作品结合了由DMM GAMES和Nitro+共同推出的刀剑养成模拟游戏《刀剑乱舞-ONLINE-》,以及由光荣特库摩开发的动作游戏《无双》系列的元素,为玩家带来一骑当千的爽快感。

十五把失去了主人——“审神者”的刀剑男士, 在时间轴上漂流之际突然遭受敌人“时间溯行军”的袭击。 随后,他们收到由“时之政府”指派的一项名为“突击调查”的任务。 失去主人的他们决定共同出征,前往历史逐渐遭到篡改的战国时代。

Image title


(转发自:原日志地址
游戏鉴赏家:日式和风回合制JRPG《命途》The Use of Life 玩派PLAYSECT试玩
玩派 2022-05-19


    《命途》The Use of Life 是一款2D自选取向多结局的JRPG。游戏中,根据玩家选择的不同,主人公的【执念】乃至性格和想法也会随之发生改变。游戏的结局也会随着你所选择的“命途”而变化。

(转发自:原日志地址
游戏鉴赏家:日式和风回合制JRPG《命途》The Use of Life 玩派PLAYSECT试玩
玩派 2022-05-19


    《命途》The Use of Life 是一款2D自选取向多结局的JRPG。游戏中,根据玩家选择的不同,主人公的【执念】乃至性格和想法也会随之发生改变。游戏的结局也会随着你所选择的“命途”而变化。

(转发自:原日志地址
索尼最新视频游戏订阅服务PlayStation Plus - Official Trailer官方发行预告片
玩派 2022-05-18


PlayStation Plus是一项索尼推出的视频游戏订阅服务。索尼公布了全新的 PlayStation Plus 游戏阵容,包括《刺客信条:英灵殿》《荒野大镖客 2》《死亡搁浅》等,从Official Trailer可以进一步了解详细内容。

(转发自:原日志地址
索尼最新视频游戏订阅服务PlayStation Plus - Official Trailer官方发行预告片
玩派 2022-05-18


PlayStation Plus是一项索尼推出的视频游戏订阅服务。索尼公布了全新的 PlayStation Plus 游戏阵容,包括《刺客信条:英灵殿》《荒野大镖客 2》《死亡搁浅》等,从Official Trailer可以进一步了解详细内容。

(转发自:原日志地址
师姐结婚,学妹毕业,而站在大海前的我呢。
无有时代 2022-05-17

今天是一个平常的日子

上班,喜欢的球队输球了,在朋友圈看到学妹毕业了,还有一些事情,总之心情不好

也不知怎么形容,或许就是老了

以前有篇开发日志,结尾谈到师姐结婚了,如今就轮到学妹毕业了

该怎么说呢,以前的生活过去了,就过去了

如今过的是什么生活呢,我也说不上来

好像没什么期盼的感觉了,估计生活也不会有什么波澜,无非一天天的打工糊口,感觉这有点像电子阳痿,不过叫生活阳痿更贴切些


想起以前难过的时候,就想打游戏,特别是战斗类的发泄一下

今晚也有同样的想法,但想到下载就觉得很麻烦很累

所以也放弃了,就呆呆地熬了一下夜(熬夜发呆真的会上瘾,感觉世界静静的就挺好的)

打开自己做的游戏《最后一日》,看到海的照片,不由想起当年走路去海边的情景,想起从前

真想再看一次海啊


人生,就像大海一样

流着流着就过去了

到头来……

也不知怎么结尾好,就这样吧。

(转发自:原日志地址
bailt 2022-05-16

RTS中同一单位生产出来具有一样的生命上限、但是有不同剩余生命、击杀数、法力、经验和等级,这是如何做出来的,希望能够详细一点
目前我只知道一些零零碎碎,但是解决这个问题
基础层、单位层、角色层

游戏鉴赏家:以假乱真《德州电锯杀人狂》The Texas Chain Saw Massacre游戏与电影对比预告片
玩派 2022-05-16

           Gun工作室公布非对称多人恐怖游戏游戏《德州电锯杀人狂》The Texas Chain Saw Massacre游戏与电影对比预告,该作于2021年TGA颁奖礼上首次亮相,基于1974年开创且标志性同名电影改编而来。

Image title

Image title

Image title


(转发自:原日志地址
游戏鉴赏家:以假乱真《德州电锯杀人狂》The Texas Chain Saw Massacre游戏与电影对比预告片
玩派 2022-05-16

           Gun工作室公布非对称多人恐怖游戏游戏《德州电锯杀人狂》The Texas Chain Saw Massacre游戏与电影对比预告,该作于2021年TGA颁奖礼上首次亮相,基于1974年开创且标志性同名电影改编而来。

Image title

Image title

Image title


(转发自:原日志地址
RogueLike + TPS、柴油朋克风世界观游戏寻美术
TJ 2022-05-15

如题,本人正在制作一款RogueLike + TPS,柴油朋克风世界观的游戏。目前已有初步的世界观原型和玩法原型,需要寻求志同道合的美术同学一起参与。可能需要一位原画、一位动画/3D建模的样子。游戏引擎使用的Unity。

一些其他信息:

【关于我自己】

本人三年左右经验,之前是大厂的UE引擎程序(核心组打杂),也用过很长时间的Unity。这次会裸辞回家全勤做。然后业余时间写过小说以及参加gamejam设计游戏,所以这次也以会以半程半策的方式参与项目。

【关于人员】

目前找了一个客户端程序,和一个TA。都是我自己的同学。经验和年龄都相仿.

【关于资金】

目前我自己大概能出60W左右,不过初步算成本肯定会要高于这个数,到时候估计需要走摩点、steam ea这些来补剩下的....

【关于酬劳】

前期希望能用爱发电,等到上线了在分钱,毕竟钱还是希望尽量花在外包上,这样游戏也能有更好的品质。不过如果确实有大佬感兴趣的话,也可以给个报价来,这个也可以argue~

【关于工作量】

每周能有15 - 20个小时的半全勤模式即可(当然也欢迎一起裸辞~)

【关于合作&理念】

因为TA同学在日本某厂,所以会采用线上合作的方式。

我的开发理念是all work and all design(当然这也是不找纯策划的原因),所以大家都会参与到玩法设计和世界观设计当中,不过话语权有所不同。

【关于联系】

QQ:895815753,有意向者可以带一下自己的作品集,当然我这边也会提供一份更完整的企划。


不算是个浪漫的爱情故事:《洞窟寓言》开发记录Part 2
mizukinokara 2022-05-15

时间到了五月的中旬,距离上次发文大概过去了一周多?Image title

原本预期是在下月的月头更新一篇进度放出一些剧情和内容的介绍,但在上海隔离的这个失眠的雨夜(文章发出来的时候上海大概已经不下雨了吧)让我没忍住写了点东西。

我们先往回退几天,对于肉身在上海的朋友来说五一假期和这两个月的普通的每一天没什么区别,依旧是被隔离。可能区别是现在能下楼透过小区的围墙栅栏看到外面的世界吧。

自从能下楼开始,每天下楼遛狗总是能看到零星的居民隔着围墙朝着外面的世界望去。柏拉图的洞窟寓言(也有叫地穴寓言)大概讲的是野人因为被关在洞窟当中而对外面和洞窟的世界产生错觉。此刻在这座城市中生活的那几千万人口何尝不是活在一个巨大的洞穴当中,此时深陷互联网各种媒介漩涡分不清真假的我们何尝不是洞窟中的野人呢。


在《洞窟寓言》中,讲述的大概也是这些事,只是系托了别的载体,这个载体是一个谈不上浪漫的爱情故事,一些取材来自几个朋友的经历一些来自自我的迷思:

多年前还在读书的时候,我的一个朋友失恋整日饮酒活在过去的世界里,每次见面就和我描述他和前任的美好生活。同时还反复和我说一句话——他总是和我说:人就像动物一样逃不掉。Image title

这本来只是酒后的一句醉话,因为是在微信里发出来的,当时还被我截图做进了一本zine里作为网络memes。随后时光飞逝,一晃过了些年,虚拟偶像、互联网社交、新时代二次元的流行,网络社会转眼就成为我们现在看到的样子,不能说它多坏但也谈不上多好。

它虽然实现了麦克卢汉描绘的地球村也模糊了卢汉所说的冷热媒介,我们逐渐成为被互联网困住的动物,一睁开眼睛就是信息,图片和各种毫无线索的情感宣泄,我们时长没办法选择所接受的信息内容,这些信息像决堤的洪水一样灌了下来,尽管偶尔想逃避但似乎却怎么也逃不掉了。

或许我们需要和互联网媒介进行一次“分手”?

《洞窟寓言》里的爱情故事正是这样的一个关于“分手”的故事,主角“普兰”也是生活中的你我它,需要去分手的对象“莎蒂”是这个世界,是过去,是自己的一场梦。主角在游戏内经历着盗梦空间般的层层梦境,最终迎来结局。

当然游戏里还有其他几个角色。我不确定是否能把这个故事在我的能力范围内讲明白,并且我也不确定这是个有趣的故事(在我拿给朋友玩之前我是这样极度怀疑的)。Image title

况且目前自我感觉故事还是有些破碎的状态【虽然在创作初期我写清楚了大部分脚本,并且极力控制后面的自我放飞,但最后我还是陷入了杜琪峰式(误)的创作模式】【尽管一些朋友玩了近期版本觉得还算有趣】。

文字冒险终归是文字冒险,文字作为交互媒介可能在如今会给游戏带来一些小门槛吧(毕竟avg现在算不上一个热门的品类),何况我自己都不好意思把这个称作游戏,我可以把它这个称作大型的自嗨现场。

因此游戏本身也是比较试验性质的存在,并且单结局时长不是很长,是一个大家都能读完所有所思的短中篇小说的长度。在这里并不想过多的拉高大家对这款游戏的期待,所谓期待越高差评越多(笑)。


【Ps:对游戏感兴趣的可以加QQ群:243518944】


(转发自:原日志地址
不算是个浪漫的爱情故事:《洞窟寓言》开发记录Part 2
mizukinokara 2022-05-15

时间到了五月的中旬,距离上次发文大概过去了一周多?Image title

原本预期是在下月的月头更新一篇进度放出一些剧情和内容的介绍,但在上海隔离的这个失眠的雨夜(文章发出来的时候上海大概已经不下雨了吧)让我没忍住写了点东西。

我们先往回退几天,对于肉身在上海的朋友来说五一假期和这两个月的普通的每一天没什么区别,依旧是被隔离。可能区别是现在能下楼透过小区的围墙栅栏看到外面的世界吧。

自从能下楼开始,每天下楼遛狗总是能看到零星的居民隔着围墙朝着外面的世界望去。柏拉图的洞窟寓言(也有叫地穴寓言)大概讲的是野人因为被关在洞窟当中而对外面和洞窟的世界产生错觉。此刻在这座城市中生活的那几千万人口何尝不是活在一个巨大的洞穴当中,此时深陷互联网各种媒介漩涡分不清真假的我们何尝不是洞窟中的野人呢。


在《洞窟寓言》中,讲述的大概也是这些事,只是系托了别的载体,这个载体是一个谈不上浪漫的爱情故事,一些取材来自几个朋友的经历一些来自自我的迷思:

多年前还在读书的时候,我的一个朋友失恋整日饮酒活在过去的世界里,每次见面就和我描述他和前任的美好生活。同时还反复和我说一句话——他总是和我说:人就像动物一样逃不掉。Image title

这本来只是酒后的一句醉话,因为是在微信里发出来的,当时还被我截图做进了一本zine里作为网络memes。随后时光飞逝,一晃过了些年,虚拟偶像、互联网社交、新时代二次元的流行,网络社会转眼就成为我们现在看到的样子,不能说它多坏但也谈不上多好。

它虽然实现了麦克卢汉描绘的地球村也模糊了卢汉所说的冷热媒介,我们逐渐成为被互联网困住的动物,一睁开眼睛就是信息,图片和各种毫无线索的情感宣泄,我们时长没办法选择所接受的信息内容,这些信息像决堤的洪水一样灌了下来,尽管偶尔想逃避但似乎却怎么也逃不掉了。

或许我们需要和互联网媒介进行一次“分手”?

《洞窟寓言》里的爱情故事正是这样的一个关于“分手”的故事,主角“普兰”也是生活中的你我它,需要去分手的对象“莎蒂”是这个世界,是过去,是自己的一场梦。主角在游戏内经历着盗梦空间般的层层梦境,最终迎来结局。

当然游戏里还有其他几个角色。我不确定是否能把这个故事在我的能力范围内讲明白,并且我也不确定这是个有趣的故事(在我拿给朋友玩之前我是这样极度怀疑的)。Image title

况且目前自我感觉故事还是有些破碎的状态【虽然在创作初期我写清楚了大部分脚本,并且极力控制后面的自我放飞,但最后我还是陷入了杜琪峰式(误)的创作模式】【尽管一些朋友玩了近期版本觉得还算有趣】。

文字冒险终归是文字冒险,文字作为交互媒介可能在如今会给游戏带来一些小门槛吧(毕竟avg现在算不上一个热门的品类),何况我自己都不好意思把这个称作游戏,我可以把它这个称作大型的自嗨现场。

因此游戏本身也是比较试验性质的存在,并且单结局时长不是很长,是一个大家都能读完所有所思的短中篇小说的长度。在这里并不想过多的拉高大家对这款游戏的期待,所谓期待越高差评越多(笑)。


【Ps:对游戏感兴趣的可以加QQ群:243518944】


(转发自:原日志地址
Wind:一款面向云的分布式游戏服务器引擎
2022-05-14

Wind是一款面向云的高性能、高效率以及高扩展性的大型分布式游戏服务器引擎。Wind利用Python语言的简洁语法以及丰富的生态库来提高游戏业务的开发效率,针对一些对性能有要求的游戏业务功能(如实时战斗功能),Wind利用Golang的高并发特性来保证服务的高性能,同时Wind接入云的组件来保证游戏服务的动态扩展性,提高服务资源的利用率。

https://github.com/ferris1/wind

Wind是游戏服务器界首次结合go与python优点的服务器,如果Wind能解决你的问题的话,希望能帮Wind点个Star,如果不能解决大家的问题的话,也欢迎大家提Issue和Request,我会持续开发和完善Wind。

本文是Wind服务器引擎设计与实现系列的第一篇

1:Wind单服务引擎功能的设计与实现

2:Wind分布式集群功能的设计与实现(待更新)

3:Wind服务云部署功能的设计与实现(待更新)

Wind单机引擎功能的设计与实现

本篇文章主要介绍Wind的出现背景,Wind要解决什么问题,以及Wind的设计和服务器引擎实现方案。从游戏业务需求出发,介绍Wind拥有的特性以及引擎各个功能如何实现这些特性。

Wind出现背景

得益于云计算的低成本、按需灵活配置和高资源利用率的特性,大量的互联网应用已经在云上部署。但游戏服务上云的进度却很缓慢,这其中的原因跟游戏产品特性有关系。相对于互联网产品,游戏产品对延时更敏感,尤其是一些强竞技性游戏,如果将游戏服务部署上云的话,会有一些额外运算与路由导致延时增加,这也导致游戏服务上云进程比较缓慢。

虽然一些强竞技性游戏上云后可能影响游戏体验,但是对于一些休闲类、放置类、弱竞技类游戏来说,这些游戏对时延并不敏感,还是非常适合上云的。而且随着云游戏的发展和游戏产品的国际化,游戏上云是一个必然趋势。游戏上云可以很好运用云上资源,更灵活的配置服务资源以及更高效的管理服务,降低游戏服务的成本。

早前开源服务器更多关注的是单服务器内部的设计,如云风的Skynet,虽然单服务器性能很高,但没有提供一个很好的服务集群化方案,集群的配置、集群的监控管理以及集群间的通信交互都很麻烦,集群服务的动态扩展性也不强,导致搭建服务集群困难以及整体服务资源利用率低下。

因此Wind致力于解决上述问题,简化游戏服务集群方案,提高服务资源利用率,同时也保证游戏服务的开发效率以及运行性能。Wind是一款面向云的高性能、高效率以及高扩展性的大型分布式游戏服务器引擎。Wind利用Python语言的简洁语法以及丰富的生态库来提高游戏业务的开发效率,针对一些对性能有要求的游戏业务功能(如实时战斗功能),Wind利用Golang的高并发特性来保证服务的高性能,同时Wind接入云的组件来保证游戏服务动态扩展性,提高服务资源的利用率。

游戏界有Unity和Unreal这样完善并且开箱即用的客户端引擎,这样的引擎大大缩短了游戏的开发周期,基本上一天就能做一个能跑的游戏。但是却并不存在一款大家熟知分布式服务器引擎,这样的服务器引擎可以快速上手并且能满足游戏各个阶段的开发需求。Wind致力于做一款易上手且完善的分布式服务器引擎,帮助独立游戏开发者或者中小企业快速搭建服务器框架并且快速开发游戏业务,降低游戏服务器开发难度与成本。

Image title


Wind特性

游戏产品生命周期通常会经历三个阶段,第一个阶段是开发阶段,第二阶段是上线阶段,第三个阶段是运营阶段,不同阶段面对场景与需求不一样,对服务器特性要求也不一样。产品前期更倾向于开发的高效率,后期更倾向于产品的质量与稳定,Wind针对三个阶段的需求有不同的设计。

开发阶段

开发阶段处在游戏产品快速试错与完善阶段,通常会有大量需求增加和变更,此时为了应对需求快速变更的情况,主要要求服务器具有便利性,便利性又可分为开发便利性与部署便利性。

  • 开发便利性

开发便利性是指给定一个功能需求,服务器框架能否快速实现逻辑需求,能否降低项目组或者程序员的开发时间和开发难度。一个游戏服务器功能的开发便利性大体可以由两部分来保证,一部分是底层引擎功能的抽象复用,如网络通信、数据存储、并发模型、远程函数调用等,抽象是消除复杂的最好工具之一,抽象提供简洁明了的接口,降低程序员上手难度。开发便利性另一部分保证是游戏逻辑语言的选择,通常一个服务器大部分代码都是产品逻辑代码,如果选择一些非常底层的语言来写逻辑代码的话,那会非常痛苦,比如用汇编来编写UI交互逻辑,写出来的代码又臭又长,因此逻辑程序语言会选择一些高级语言来实现,Wind使用Python来编写游戏业务代码,主要利用Python简洁的语法以及丰富的库。Python对程序新手也更友好,可以更快的上手服务器开发。

  • 部署便利性

游戏服务部署主要包括服务参数配置、服务环境安装以及针对不同类型服务部署在不同物理区域。一般游戏会有三套运行环境,一个是开发环境、一个是测试环境,一个是运营环境。比较传统的部署方式是直接在服务器操作系统中部署多个服务,这种部署方式有个缺点是如果服务环境升级的话,那各个环境也要手动更新,操作重复且容易出错。考虑到环境的问题,有些运营的比较久的游戏根本不敢轻易升级。所以现代部署基本上是容器部署,比如Docker容器,只需要写一个Dockerfile脚本便可以在各个环境使用最新配置运行,降低了不同职能的环境配置成本。

上线阶段

游戏产品上线阶段是最重要的时刻,游戏上线意味着产品投放外部玩家,开始接受外部玩家的考验。刚上线时是统一时间初次开放,大量玩家同时登陆游戏,这要求服务器需要由高并发能力,同时也要求服务器具有强大的可靠性和扩展性,保证大量玩家登录时能正常玩游戏和当人数超出预期时可自动伸缩服务来承载玩家游戏。

  • 可靠性

服务的可靠性体现在预期负载和数据量下,服务器能否保持良好的性能运行。Wind的单服务性能主要由Golang语言来确保,一些调用频繁的功能以及对性能有要求的游戏功能(如网络通信功能、游戏战斗功能)由Golang这种静态语言编写,提升服务运行效率。同时Wind在Golang层采用多线程并发模型,为每一个客户端开一个线程处理网络包,提高单服务的并发性。Wind的多服务可靠性由专用的游戏负载均衡算法保证,负载均衡包含多种算法(比如最小分配、最大分配),可根据游戏业务进行切换。同时Wind使用Python动态语言来编写逻辑,支持函数级别的热更且可以在不停服的情况下热更游戏资源。

  • 扩展性

扩展可以分为功能扩展与资源扩展。游戏的功能扩展属于软件层面上的扩展,Wind使用插件模式来保证游戏功能高扩展性,每个功能以插件的形式加入引擎,如果你不想用原先的功能,你可以写一个新的插件替换掉原来的插件,插件模式可以很好扩展游戏组件。

资源扩展属于硬件扩展,硬件扩展又可分为纵向扩展和横向扩展,纵向扩展是将服务器换成性能更强大的服务器,这种方式扩展有限。现代分布式服务器下更常用的是横向扩展,也就是添加更多的机器。Wind使用服务发现和负载均衡来保证硬件的扩展性,每当新增服务时,原有的服务集群可以很快发现服务并调度服务,服务的横向扩展能力主要由服务发现的能力来决定。游戏服务上云后又可以让服务扩展性又进一步,服务上云后可利用云上公共资源,动态伸缩服务,提高服务的利用率,降低冗余,从而降低资源成本。

运营阶段

运营阶段处于游戏的稳定阶段,玩家数量会保持在一定数量上,服务器会长期的运行,此时稳定性是服务器最重要的一个特性。又因为运营阶段是长期的一个维护阶段,因此可维护性也是一个非常重要的特性。

  • 可维护性

软件的大部分开销并不在最初的开发阶段,而是在持续的维护阶段,维护包括漏洞修复、保持系统正常运行、调查失效、适配新的平台、为新的场景进行修改、添加新的功能等等。不幸的是,大部分程序员都不喜欢维护所谓的遗留系统,可能因为涉及修复其他人的错误、和过时的平台打交道是份额外工作。服务的维护主要是服务监控,良好服务监控可以在一定程度上预防服务问题的大规模扩散。

Wind引擎实现

大型分布式服务器主要由早前单服务引擎发展而来,早前服务器服务玩家数量较少,基本上单进程服务器便能服务玩家。但由于互联网技术的发展,玩家越来越多,单进程服务器服务不了更多的玩家,因此发展分布式服务器来服务更多的玩家。得益于云的发展,游戏服务上云提高了资源利用率,降低了服务维护成本。Wind分布式引擎主要由这三个部分组成,第一部分是单服务器引擎,第二部分是分布式集群,第三部分是服务云部署。

  • 单服务引擎:

单服务引擎包含一个服务器能运转的所有功能,游戏客户端发送请求给单服务引擎,单服务引擎处理请求后并回包给客户端。单服务器引擎主要包括程序语言、网络通信、并发模型、远程函数调用这些主要功能。

  • 分布式集群:

分布式集群由每个运行的单服务引擎组成,分布式集群主要是为了解决单服务器引擎只能服务少量玩家的问题,通过横向扩展服务器来解决单服务器压力过大的问题,分布式集群功能主要包含服务发现、负载均衡、消息队列和数据存储等功能。

  • 服务云部署:

对于一些只有几十个人的游戏,你可能就只需要起一个服务就行了,但是对于上百万玩家的游戏,这时就需要起上千或者上万个服,而且针对不同地区有不同的部署方案,面对这么庞大的部署,如果纯手动管理,那会非常耗时耗力,这时就需要一些云部署工具来支持。云部署主要包含容器部署、K8S编排、服务治理与监控。

单服务器引擎

单服务引擎包含一个服务器运行的所有功能,能单独运行并服务一部分玩家。单服务引擎运行后,客户端通过网络通信将请求发送到服务器中,服务器通过并发模型将请求交给逻辑模块处理,逻辑模块通过序列化解码参数数据并将请求数据交给服务注册的RPC函数处理。

程序语言

目前游戏服务器开发语言使用比较广泛的组合是C/C++和Lua。C/C++属于静态语言,拥有很高的运行性能,但因为C/C++语法更倾向于计算机的理解方式,对程序员编写业务逻辑并不够友好,降低了产品的开发效率,而且C/C++热更方法比较有限,线上出问题时不能快速且方便的修复,可能要时不时的停服关机修复,比较影响游戏体验,因此引入语法更简洁、更方便而且支持打补丁的高级动态解释语言Lua。引入Lua后,C/C++的分工有了变化,一些要求高性能的服务器模块用C/C++编写,比如网络库、数学计算库以及局内实时战斗逻辑等,Lua负责一些对性能要求不高的模块,但业务逻辑量比较大的模块,这样的模块其实占游戏业务的很大一部分,比如游戏的一些外围系统:等级系统,背包系统,聊天系统等等。相比于Lua,其实个人更喜欢Python,Python比Lua拥有更简洁的语法、更高的容错以及更完善的函数库,在开发产品业务时,拥有更高的开发效率,所以Wind的游戏业务逻辑语言使用Python开发。

使用C/C++编写一些模块,可以很好解决服务运行效率问题,但C/C++没有自动内存管理,写逻辑时很容易发生内存泄漏,而且C/C++语法复杂,程序员上手难度较高,开发成本大,因此引入Golang语言。Golang以高并发著称,拥有比C++更简明的语法特性,可提升开发效率,同时Golang提供自动内存管理机制,极大的简化了程序员开发的难度。因此Wind使用Golang来开发一些对效率有要求的模块,目前Wind的网络库是Golang写的。一些对性能要求高的游戏业务你也可以使用Golang来开发,比如战斗功能。

Python与Golang的交互

Wind的网络库由Golang编写,目前支持TCP,之后会支持KCP、Udp和Quic这些协议。每个客户端连接过来后,Golang会开一个线程去处理网络数据,有数据发过来后,Golang会将数据交给Python逻辑端处理,这里有个问题,就是Python线程和Golang线程是怎么进行交互的?Wind服务器引擎的主线程是在Python端,在起服务器时加载Golang编写的网络动态库(so文件或者DLL文件)并且开启网络线程处理客户端数据,目前Python与Golang的数据交互使用Socket通信交互,Python端启用一个TCP端口,Golang连接这个端口并且将数据传送给Python端。当然你也可以换Python与Golang的交互方式,比如换成ZMQ的zmq_inproc通信,使用zmq_inproc通信时,线程间共享一个ZMQ Context,可以通过共享内存来传递数据,不需要使用I/O线程,可以加快Python和Golang的交互。

Image title


并发模型

游戏客户端所做的工作基本上是将数据按一定逻辑显示在屏幕上,单个客户端并不需要与太多的服务器进行交互,多的也就两三个左右,所以客户端基本上对并发没有太多的要求。但是服务器就不一样了,同一个服务器要服务的客户端可能是上千个,甚至可能是上万个,这时候就需要并发模型来合理分配服务器的计算资源并正确的为客户端服务。

为了最大化利用物理机的多核资源,一般会有两种并发模型,一种是单进程多线程模型,这种模型通常是单个进程中存在多个游戏服务,每个服务分配一个核进行计算。游戏界应用这种并发模型比较成熟的是云风的Skynet,Skynet启用多个工作线程来处理服务的事件,各个线程间基于消息传递来通信。这种单进程多服务的缺点是,服务之间的隔离比较弱,服务之间共用了进程的数据,单个服务发生问题时可能影响其他服务,这样的设计也并不适合云部署,云部署所满足的一个基本要求就是服务间相互独立,每个服务是云调度的基本单位,每个服务可自由的被调度,因此更适合云部署的是多进程单线程模型,每个进程是一个服务,同一台机器可以起多个进程来利用多核优势,同时单线程中使用异步来处理数据I/O,提高服务器的并发

那么Wind使用的是哪个模型了? Wind使用是的混合模型,Wind是单进程单服务,网络库利用Golang的高并发特性,每个客户端连接启用一个线程来读取数据,同时为了减低业务逻辑编写难度,避免多线程锁问题,Python使用单线程异步协程来编写业务逻辑。网络层的多线程消息数据会通过一个队列来发给Python协程(asyncio)。

Image title


Python协程

Python协程本质上是异步,只不过这个协程是语言层面上的支持,编写游戏业务时更清晰、更简单。Python启动线程时,会启动一个事件循环,这个循环会一直检测是否有事件可以处理,如果某个任务要进行I/O(磁盘I/O或者网络I/O),那么这个任务会被挂起,直到对应数据到来时,这个任务又会被事件循环处理。

import asyncio

async def main():
    print('Hello ...')
    await asyncio.sleep(1)
    print('... World!')

loop = asyncio.get_event_loop()
loop.create_task(main())
loop.run_forever()

使用异步协程编写游戏业务逻辑时,同一个时刻只能有一个客户端请求被处理,降低了开发难度,与协程搭配使用的是各个模块的单例化。

网络通信

实现游戏服务器时,主要会接触到的是传输层以上的一些网络协议,传输层协议包括UDP协议和TCP协议。UDP是一种无连接的协议,没有可靠性保证、顺序保证以及流量控制,但正是因为控制项比较少,UDP在数据传输过程中延迟小,速率高。游戏中一些对可靠性要求不高,但要求高速率的业务可以使用UDP传输,比如游戏语音服务。

TCP是面向连接的、可靠的、基于字节流的传输层通信协议,TCP通过序号确认机制、超时重传机制、重复累计确认机制和检验和机制来实现可靠性传输,同时提供流量控制和拥塞控制来控制源端的发送速率,以确保对端能正确接收。相对于UDP啥都没做来说,TCP什么事都做了,导致TCP传输速率低,延迟大。游戏是实时性应用,游戏的一些外围功能(背包功能、个人信息)时延要求不高,TCP够用了,但是对于游戏战斗这类高实时性功能,TCP的延迟太大了,会导致游戏战斗时体验会非常差。

为了解决TCP传输延时大的问题,游戏界通常会在UDP之上实现一个延时更低的可靠性传输协议,比如KCP,Enet。KCP能以比TCP浪费10%-20%的带宽的代价、换取平均延迟降低30%-40%,且最大延迟降低三倍的传输效果。ENet是专门为多人第一人称射击游戏Cube开发的可靠性传输协议,Enet提供连接管理,Enet最大的特点是提供多通道机制,每个通道包传送独立,单个通道会确保前一个序号消息到达才会发送下一个序号消息,以保证可靠性。

通常游戏会集成好几个传输协议到网络层,以便在不同需求场景下切换,比如集成UDP、KCP和TCP到网络传输层。Wind的网络层也会集成多个网络协议,以便在不同游戏场景中进行切换。

Image title


远程函数调用(RPC)

在单机游戏中,如果你要实现某个游戏效果,你可以通过函数名字直接调用对应函数来实现效果,但在网络游戏中,有些游戏效果需要向远端的服务器请求计算或者数据(比如匹配,背包)来实现,这时就会需要远程函数调用。远程函数调用通常发生在同一个共享网络下的不同地址空间中,比如不同物理机。远程函数调用通常采用Request-Response通信模式,每个远程函数名字以Request/Response(也可以用其他结尾,比如Packet)结尾,以此来区分本地函数。

封装好远程函数调用库后,写代码时就像写本地函数调用一样,程序员并不需要关心与远端的交互细节。但与本地函数调用不同的是,远程函数调用需要经过网络传输,网络传输增加了调用的时延与不确定性,为了防止主线程逻辑卡死,远程函数调用一般设计成异步调用,Request包发出后,不会等待包的返回,而是Response包返回后在处理之前的逻辑。

实现远程函数调用需要两个功能支持,一个是序列化功能,一个是协议工厂功能。

序列化

序列化是一个将数据结构和对象信息转化成可以存储和传输形式的过程。我们在写代码时通常以对象的形式读取数据,因为对象更符合人类思维习惯,我们能更快编写程序代码。但是对象信息数据通常是不连续的内存,不能直接进行存储或者传输,所以序列化需要将对象数据转化成二进制或者连续的字符串。序列化技术有很多种,比较常见的是Json、Xml、Protobuf等。Json是直接将对象转化成字符串,拥有很强的可读性,但缺点也很明显,那就是序列化后的数据太大了,导致需要的网络带宽也会加大,而且Json不安全,没有错误处理机制,你可以将同一个字段值转化成其他类型的数据。现在比较大型的游戏通常采用的序列化是Protobuf,Protobuf是协议定义型的,在使用时你需要定义你的数据类型,而且因为Protobuf在序列化时是用ID作为标识符,而不是字段名来标识,所以序列化后的Protobuf数据很小。对于游戏来说,Protobuf支持函数引用定义,解决了函数重复定义的问题。使用Protobuf后也可以用协议定义文件来生成MD5,以次来标识不同游戏版本的网络协议接口,以防老版本的客户端连接新版本的服务器,造成数据错误。

协议工厂

Json序列化时可以将函数名序列化进去,数据包到达服务器后,服务器根据函数名调用注册的RPC函数,但Protobuf序列化时并不会将函数名的信息带进去,Protobuf只会序列化协议参数数据,所以要使用Protobuf进行服务器序列化时,还需要一个新字段来标识这些数据是来自哪个协议的数据。通常是用一个ID来表示协议函数,那么哪个协议ID代表哪个函数了?这时候就会需要协议工厂功能。定义好协议文件后,将协议文件转化成代码文件时,通常会给每个协议一个ID,然后生成一个协议工厂代码文件,这个工厂代码就是根据ID来调用对应函数。

Image title


服务继承

Wind整个项目的核心代码是Engine目录下的SrvEngine.py 其他所有代码都是以组件的形式附加到这个文件下。Engine拥有一款引擎的所有功能,但并不作具体的逻辑服务使用,具体的逻辑服务需要继承Engine,然后添加各个逻辑服务的一些特定功能,具体服务在service 目录下,目前有Gateway服务和Game服务。各个服的具体设计可以参考这边文章

(转发自:原日志地址
Wind:一款面向云的分布式游戏服务器引擎
2022-05-14

Wind是一款面向云的高性能、高效率以及高扩展性的大型分布式游戏服务器引擎。Wind利用Python语言的简洁语法以及丰富的生态库来提高游戏业务的开发效率,针对一些对性能有要求的游戏业务功能(如实时战斗功能),Wind利用Golang的高并发特性来保证服务的高性能,同时Wind接入云的组件来保证游戏服务的动态扩展性,提高服务资源的利用率。

https://github.com/ferris1/wind

Wind是游戏服务器界首次结合go与python优点的服务器,如果Wind能解决你的问题的话,希望能帮Wind点个Star,如果不能解决大家的问题的话,也欢迎大家提Issue和Request,我会持续开发和完善Wind。

本文是Wind服务器引擎设计与实现系列的第一篇

1:Wind单服务引擎功能的设计与实现

2:Wind分布式集群功能的设计与实现(待更新)

3:Wind服务云部署功能的设计与实现(待更新)

Wind单机引擎功能的设计与实现

本篇文章主要介绍Wind的出现背景,Wind要解决什么问题,以及Wind的设计和服务器引擎实现方案。从游戏业务需求出发,介绍Wind拥有的特性以及引擎各个功能如何实现这些特性。

Wind出现背景

得益于云计算的低成本、按需灵活配置和高资源利用率的特性,大量的互联网应用已经在云上部署。但游戏服务上云的进度却很缓慢,这其中的原因跟游戏产品特性有关系。相对于互联网产品,游戏产品对延时更敏感,尤其是一些强竞技性游戏,如果将游戏服务部署上云的话,会有一些额外运算与路由导致延时增加,这也导致游戏服务上云进程比较缓慢。

虽然一些强竞技性游戏上云后可能影响游戏体验,但是对于一些休闲类、放置类、弱竞技类游戏来说,这些游戏对时延并不敏感,还是非常适合上云的。而且随着云游戏的发展和游戏产品的国际化,游戏上云是一个必然趋势。游戏上云可以很好运用云上资源,更灵活的配置服务资源以及更高效的管理服务,降低游戏服务的成本。

早前开源服务器更多关注的是单服务器内部的设计,如云风的Skynet,虽然单服务器性能很高,但没有提供一个很好的服务集群化方案,集群的配置、集群的监控管理以及集群间的通信交互都很麻烦,集群服务的动态扩展性也不强,导致搭建服务集群困难以及整体服务资源利用率低下。

因此Wind致力于解决上述问题,简化游戏服务集群方案,提高服务资源利用率,同时也保证游戏服务的开发效率以及运行性能。Wind是一款面向云的高性能、高效率以及高扩展性的大型分布式游戏服务器引擎。Wind利用Python语言的简洁语法以及丰富的生态库来提高游戏业务的开发效率,针对一些对性能有要求的游戏业务功能(如实时战斗功能),Wind利用Golang的高并发特性来保证服务的高性能,同时Wind接入云的组件来保证游戏服务动态扩展性,提高服务资源的利用率。

游戏界有Unity和Unreal这样完善并且开箱即用的客户端引擎,这样的引擎大大缩短了游戏的开发周期,基本上一天就能做一个能跑的游戏。但是却并不存在一款大家熟知分布式服务器引擎,这样的服务器引擎可以快速上手并且能满足游戏各个阶段的开发需求。Wind致力于做一款易上手且完善的分布式服务器引擎,帮助独立游戏开发者或者中小企业快速搭建服务器框架并且快速开发游戏业务,降低游戏服务器开发难度与成本。

Image title


Wind特性

游戏产品生命周期通常会经历三个阶段,第一个阶段是开发阶段,第二阶段是上线阶段,第三个阶段是运营阶段,不同阶段面对场景与需求不一样,对服务器特性要求也不一样。产品前期更倾向于开发的高效率,后期更倾向于产品的质量与稳定,Wind针对三个阶段的需求有不同的设计。

开发阶段

开发阶段处在游戏产品快速试错与完善阶段,通常会有大量需求增加和变更,此时为了应对需求快速变更的情况,主要要求服务器具有便利性,便利性又可分为开发便利性与部署便利性。

  • 开发便利性

开发便利性是指给定一个功能需求,服务器框架能否快速实现逻辑需求,能否降低项目组或者程序员的开发时间和开发难度。一个游戏服务器功能的开发便利性大体可以由两部分来保证,一部分是底层引擎功能的抽象复用,如网络通信、数据存储、并发模型、远程函数调用等,抽象是消除复杂的最好工具之一,抽象提供简洁明了的接口,降低程序员上手难度。开发便利性另一部分保证是游戏逻辑语言的选择,通常一个服务器大部分代码都是产品逻辑代码,如果选择一些非常底层的语言来写逻辑代码的话,那会非常痛苦,比如用汇编来编写UI交互逻辑,写出来的代码又臭又长,因此逻辑程序语言会选择一些高级语言来实现,Wind使用Python来编写游戏业务代码,主要利用Python简洁的语法以及丰富的库。Python对程序新手也更友好,可以更快的上手服务器开发。

  • 部署便利性

游戏服务部署主要包括服务参数配置、服务环境安装以及针对不同类型服务部署在不同物理区域。一般游戏会有三套运行环境,一个是开发环境、一个是测试环境,一个是运营环境。比较传统的部署方式是直接在服务器操作系统中部署多个服务,这种部署方式有个缺点是如果服务环境升级的话,那各个环境也要手动更新,操作重复且容易出错。考虑到环境的问题,有些运营的比较久的游戏根本不敢轻易升级。所以现代部署基本上是容器部署,比如Docker容器,只需要写一个Dockerfile脚本便可以在各个环境使用最新配置运行,降低了不同职能的环境配置成本。

上线阶段

游戏产品上线阶段是最重要的时刻,游戏上线意味着产品投放外部玩家,开始接受外部玩家的考验。刚上线时是统一时间初次开放,大量玩家同时登陆游戏,这要求服务器需要由高并发能力,同时也要求服务器具有强大的可靠性和扩展性,保证大量玩家登录时能正常玩游戏和当人数超出预期时可自动伸缩服务来承载玩家游戏。

  • 可靠性

服务的可靠性体现在预期负载和数据量下,服务器能否保持良好的性能运行。Wind的单服务性能主要由Golang语言来确保,一些调用频繁的功能以及对性能有要求的游戏功能(如网络通信功能、游戏战斗功能)由Golang这种静态语言编写,提升服务运行效率。同时Wind在Golang层采用多线程并发模型,为每一个客户端开一个线程处理网络包,提高单服务的并发性。Wind的多服务可靠性由专用的游戏负载均衡算法保证,负载均衡包含多种算法(比如最小分配、最大分配),可根据游戏业务进行切换。同时Wind使用Python动态语言来编写逻辑,支持函数级别的热更且可以在不停服的情况下热更游戏资源。

  • 扩展性

扩展可以分为功能扩展与资源扩展。游戏的功能扩展属于软件层面上的扩展,Wind使用插件模式来保证游戏功能高扩展性,每个功能以插件的形式加入引擎,如果你不想用原先的功能,你可以写一个新的插件替换掉原来的插件,插件模式可以很好扩展游戏组件。

资源扩展属于硬件扩展,硬件扩展又可分为纵向扩展和横向扩展,纵向扩展是将服务器换成性能更强大的服务器,这种方式扩展有限。现代分布式服务器下更常用的是横向扩展,也就是添加更多的机器。Wind使用服务发现和负载均衡来保证硬件的扩展性,每当新增服务时,原有的服务集群可以很快发现服务并调度服务,服务的横向扩展能力主要由服务发现的能力来决定。游戏服务上云后又可以让服务扩展性又进一步,服务上云后可利用云上公共资源,动态伸缩服务,提高服务的利用率,降低冗余,从而降低资源成本。

运营阶段

运营阶段处于游戏的稳定阶段,玩家数量会保持在一定数量上,服务器会长期的运行,此时稳定性是服务器最重要的一个特性。又因为运营阶段是长期的一个维护阶段,因此可维护性也是一个非常重要的特性。

  • 可维护性

软件的大部分开销并不在最初的开发阶段,而是在持续的维护阶段,维护包括漏洞修复、保持系统正常运行、调查失效、适配新的平台、为新的场景进行修改、添加新的功能等等。不幸的是,大部分程序员都不喜欢维护所谓的遗留系统,可能因为涉及修复其他人的错误、和过时的平台打交道是份额外工作。服务的维护主要是服务监控,良好服务监控可以在一定程度上预防服务问题的大规模扩散。

Wind引擎实现

大型分布式服务器主要由早前单服务引擎发展而来,早前服务器服务玩家数量较少,基本上单进程服务器便能服务玩家。但由于互联网技术的发展,玩家越来越多,单进程服务器服务不了更多的玩家,因此发展分布式服务器来服务更多的玩家。得益于云的发展,游戏服务上云提高了资源利用率,降低了服务维护成本。Wind分布式引擎主要由这三个部分组成,第一部分是单服务器引擎,第二部分是分布式集群,第三部分是服务云部署。

  • 单服务引擎:

单服务引擎包含一个服务器能运转的所有功能,游戏客户端发送请求给单服务引擎,单服务引擎处理请求后并回包给客户端。单服务器引擎主要包括程序语言、网络通信、并发模型、远程函数调用这些主要功能。

  • 分布式集群:

分布式集群由每个运行的单服务引擎组成,分布式集群主要是为了解决单服务器引擎只能服务少量玩家的问题,通过横向扩展服务器来解决单服务器压力过大的问题,分布式集群功能主要包含服务发现、负载均衡、消息队列和数据存储等功能。

  • 服务云部署:

对于一些只有几十个人的游戏,你可能就只需要起一个服务就行了,但是对于上百万玩家的游戏,这时就需要起上千或者上万个服,而且针对不同地区有不同的部署方案,面对这么庞大的部署,如果纯手动管理,那会非常耗时耗力,这时就需要一些云部署工具来支持。云部署主要包含容器部署、K8S编排、服务治理与监控。

单服务器引擎

单服务引擎包含一个服务器运行的所有功能,能单独运行并服务一部分玩家。单服务引擎运行后,客户端通过网络通信将请求发送到服务器中,服务器通过并发模型将请求交给逻辑模块处理,逻辑模块通过序列化解码参数数据并将请求数据交给服务注册的RPC函数处理。

程序语言

目前游戏服务器开发语言使用比较广泛的组合是C/C++和Lua。C/C++属于静态语言,拥有很高的运行性能,但因为C/C++语法更倾向于计算机的理解方式,对程序员编写业务逻辑并不够友好,降低了产品的开发效率,而且C/C++热更方法比较有限,线上出问题时不能快速且方便的修复,可能要时不时的停服关机修复,比较影响游戏体验,因此引入语法更简洁、更方便而且支持打补丁的高级动态解释语言Lua。引入Lua后,C/C++的分工有了变化,一些要求高性能的服务器模块用C/C++编写,比如网络库、数学计算库以及局内实时战斗逻辑等,Lua负责一些对性能要求不高的模块,但业务逻辑量比较大的模块,这样的模块其实占游戏业务的很大一部分,比如游戏的一些外围系统:等级系统,背包系统,聊天系统等等。相比于Lua,其实个人更喜欢Python,Python比Lua拥有更简洁的语法、更高的容错以及更完善的函数库,在开发产品业务时,拥有更高的开发效率,所以Wind的游戏业务逻辑语言使用Python开发。

使用C/C++编写一些模块,可以很好解决服务运行效率问题,但C/C++没有自动内存管理,写逻辑时很容易发生内存泄漏,而且C/C++语法复杂,程序员上手难度较高,开发成本大,因此引入Golang语言。Golang以高并发著称,拥有比C++更简明的语法特性,可提升开发效率,同时Golang提供自动内存管理机制,极大的简化了程序员开发的难度。因此Wind使用Golang来开发一些对效率有要求的模块,目前Wind的网络库是Golang写的。一些对性能要求高的游戏业务你也可以使用Golang来开发,比如战斗功能。

Python与Golang的交互

Wind的网络库由Golang编写,目前支持TCP,之后会支持KCP、Udp和Quic这些协议。每个客户端连接过来后,Golang会开一个线程去处理网络数据,有数据发过来后,Golang会将数据交给Python逻辑端处理,这里有个问题,就是Python线程和Golang线程是怎么进行交互的?Wind服务器引擎的主线程是在Python端,在起服务器时加载Golang编写的网络动态库(so文件或者DLL文件)并且开启网络线程处理客户端数据,目前Python与Golang的数据交互使用Socket通信交互,Python端启用一个TCP端口,Golang连接这个端口并且将数据传送给Python端。当然你也可以换Python与Golang的交互方式,比如换成ZMQ的zmq_inproc通信,使用zmq_inproc通信时,线程间共享一个ZMQ Context,可以通过共享内存来传递数据,不需要使用I/O线程,可以加快Python和Golang的交互。

Image title


并发模型

游戏客户端所做的工作基本上是将数据按一定逻辑显示在屏幕上,单个客户端并不需要与太多的服务器进行交互,多的也就两三个左右,所以客户端基本上对并发没有太多的要求。但是服务器就不一样了,同一个服务器要服务的客户端可能是上千个,甚至可能是上万个,这时候就需要并发模型来合理分配服务器的计算资源并正确的为客户端服务。

为了最大化利用物理机的多核资源,一般会有两种并发模型,一种是单进程多线程模型,这种模型通常是单个进程中存在多个游戏服务,每个服务分配一个核进行计算。游戏界应用这种并发模型比较成熟的是云风的Skynet,Skynet启用多个工作线程来处理服务的事件,各个线程间基于消息传递来通信。这种单进程多服务的缺点是,服务之间的隔离比较弱,服务之间共用了进程的数据,单个服务发生问题时可能影响其他服务,这样的设计也并不适合云部署,云部署所满足的一个基本要求就是服务间相互独立,每个服务是云调度的基本单位,每个服务可自由的被调度,因此更适合云部署的是多进程单线程模型,每个进程是一个服务,同一台机器可以起多个进程来利用多核优势,同时单线程中使用异步来处理数据I/O,提高服务器的并发

那么Wind使用的是哪个模型了? Wind使用是的混合模型,Wind是单进程单服务,网络库利用Golang的高并发特性,每个客户端连接启用一个线程来读取数据,同时为了减低业务逻辑编写难度,避免多线程锁问题,Python使用单线程异步协程来编写业务逻辑。网络层的多线程消息数据会通过一个队列来发给Python协程(asyncio)。

Image title


Python协程

Python协程本质上是异步,只不过这个协程是语言层面上的支持,编写游戏业务时更清晰、更简单。Python启动线程时,会启动一个事件循环,这个循环会一直检测是否有事件可以处理,如果某个任务要进行I/O(磁盘I/O或者网络I/O),那么这个任务会被挂起,直到对应数据到来时,这个任务又会被事件循环处理。

import asyncio

async def main():
    print('Hello ...')
    await asyncio.sleep(1)
    print('... World!')

loop = asyncio.get_event_loop()
loop.create_task(main())
loop.run_forever()

使用异步协程编写游戏业务逻辑时,同一个时刻只能有一个客户端请求被处理,降低了开发难度,与协程搭配使用的是各个模块的单例化。

网络通信

实现游戏服务器时,主要会接触到的是传输层以上的一些网络协议,传输层协议包括UDP协议和TCP协议。UDP是一种无连接的协议,没有可靠性保证、顺序保证以及流量控制,但正是因为控制项比较少,UDP在数据传输过程中延迟小,速率高。游戏中一些对可靠性要求不高,但要求高速率的业务可以使用UDP传输,比如游戏语音服务。

TCP是面向连接的、可靠的、基于字节流的传输层通信协议,TCP通过序号确认机制、超时重传机制、重复累计确认机制和检验和机制来实现可靠性传输,同时提供流量控制和拥塞控制来控制源端的发送速率,以确保对端能正确接收。相对于UDP啥都没做来说,TCP什么事都做了,导致TCP传输速率低,延迟大。游戏是实时性应用,游戏的一些外围功能(背包功能、个人信息)时延要求不高,TCP够用了,但是对于游戏战斗这类高实时性功能,TCP的延迟太大了,会导致游戏战斗时体验会非常差。

为了解决TCP传输延时大的问题,游戏界通常会在UDP之上实现一个延时更低的可靠性传输协议,比如KCP,Enet。KCP能以比TCP浪费10%-20%的带宽的代价、换取平均延迟降低30%-40%,且最大延迟降低三倍的传输效果。ENet是专门为多人第一人称射击游戏Cube开发的可靠性传输协议,Enet提供连接管理,Enet最大的特点是提供多通道机制,每个通道包传送独立,单个通道会确保前一个序号消息到达才会发送下一个序号消息,以保证可靠性。

通常游戏会集成好几个传输协议到网络层,以便在不同需求场景下切换,比如集成UDP、KCP和TCP到网络传输层。Wind的网络层也会集成多个网络协议,以便在不同游戏场景中进行切换。

Image title


远程函数调用(RPC)

在单机游戏中,如果你要实现某个游戏效果,你可以通过函数名字直接调用对应函数来实现效果,但在网络游戏中,有些游戏效果需要向远端的服务器请求计算或者数据(比如匹配,背包)来实现,这时就会需要远程函数调用。远程函数调用通常发生在同一个共享网络下的不同地址空间中,比如不同物理机。远程函数调用通常采用Request-Response通信模式,每个远程函数名字以Request/Response(也可以用其他结尾,比如Packet)结尾,以此来区分本地函数。

封装好远程函数调用库后,写代码时就像写本地函数调用一样,程序员并不需要关心与远端的交互细节。但与本地函数调用不同的是,远程函数调用需要经过网络传输,网络传输增加了调用的时延与不确定性,为了防止主线程逻辑卡死,远程函数调用一般设计成异步调用,Request包发出后,不会等待包的返回,而是Response包返回后在处理之前的逻辑。

实现远程函数调用需要两个功能支持,一个是序列化功能,一个是协议工厂功能。

序列化

序列化是一个将数据结构和对象信息转化成可以存储和传输形式的过程。我们在写代码时通常以对象的形式读取数据,因为对象更符合人类思维习惯,我们能更快编写程序代码。但是对象信息数据通常是不连续的内存,不能直接进行存储或者传输,所以序列化需要将对象数据转化成二进制或者连续的字符串。序列化技术有很多种,比较常见的是Json、Xml、Protobuf等。Json是直接将对象转化成字符串,拥有很强的可读性,但缺点也很明显,那就是序列化后的数据太大了,导致需要的网络带宽也会加大,而且Json不安全,没有错误处理机制,你可以将同一个字段值转化成其他类型的数据。现在比较大型的游戏通常采用的序列化是Protobuf,Protobuf是协议定义型的,在使用时你需要定义你的数据类型,而且因为Protobuf在序列化时是用ID作为标识符,而不是字段名来标识,所以序列化后的Protobuf数据很小。对于游戏来说,Protobuf支持函数引用定义,解决了函数重复定义的问题。使用Protobuf后也可以用协议定义文件来生成MD5,以次来标识不同游戏版本的网络协议接口,以防老版本的客户端连接新版本的服务器,造成数据错误。

协议工厂

Json序列化时可以将函数名序列化进去,数据包到达服务器后,服务器根据函数名调用注册的RPC函数,但Protobuf序列化时并不会将函数名的信息带进去,Protobuf只会序列化协议参数数据,所以要使用Protobuf进行服务器序列化时,还需要一个新字段来标识这些数据是来自哪个协议的数据。通常是用一个ID来表示协议函数,那么哪个协议ID代表哪个函数了?这时候就会需要协议工厂功能。定义好协议文件后,将协议文件转化成代码文件时,通常会给每个协议一个ID,然后生成一个协议工厂代码文件,这个工厂代码就是根据ID来调用对应函数。

Image title


服务继承

Wind整个项目的核心代码是Engine目录下的SrvEngine.py 其他所有代码都是以组件的形式附加到这个文件下。Engine拥有一款引擎的所有功能,但并不作具体的逻辑服务使用,具体的逻辑服务需要继承Engine,然后添加各个逻辑服务的一些特定功能,具体服务在service 目录下,目前有Gateway服务和Game服务。各个服的具体设计可以参考这边文章

(转发自:原日志地址

加入 indienova

  • 建立个人/工作室档案
  • 建立开发中的游戏档案
  • 关注个人/工作室动态
  • 寻找合作伙伴共同开发
  • 寻求线上发行
  • 更多服务……
登录/注册