@ fabi-play/ protocol (英语)
电话、屏幕和游戏之间的信息 Fabi 游戏,用他们的支票:
地标P, (中文(简体) ), Body),玩家,年龄乐队,游戏表 (fabi-play.json, (中文(简体) ), parseManifest,以及
JSON Schema),和剖析方 运行在其得到的.
npm install @fabi-play/protocol
import { parseManifest, AGE_RANGES, type GameManifest } from '@fabi-play/protocol'
const result = parseManifest(JSON.parse(text))
if ('errors' in result) console.error(result.errors)
名单的JSON斯克马: @fabi-play/protocol/fabi-play.schema.json (同样在SDK旁边服役)
https://cdn.fabiplay.app (英语)无害环境管理,包括类型,不依赖。 文档 : https://docs.fabiplay.app (英语)。 。 。 .
游戏介绍
清单的可选性 intro (单位:千美元)GameIntro: 1到4个步骤,每个句子在一幅相片或一幅相片上),就是法比所想的
校正前在电视上说,请看"Fabi解释你的游戏"
@fabi-play/sdk 读取。 。 。 . parseManifest 报告有什么不对劲
(a) 与《公约》有关的规定; parseIntro 给予介绍或无效(电视跳过一个坏的,包括未知的字段), introText 页:1
语言和年龄.
- 判决:每个语言最多90个字符,计为NFC格式的Unicode代码点(一个emoji是
; 两端没有空白; 没有控制字符、 单独代位或双向控制
(U+202A–U+202E,U+2066–U+2069). JSON Schema也这么说 除了孤独的代孕者和NFC计数
便携式JSON Schema regexes无法表达:
parseManifest这是参考文献. - 路径 (单位:千美元)
entry,一个步骤的image:相对于游戏地址,没有方案,没有领先/没有空的,.或者说..片段,最多200个字符; ASCII 字母的片段, 数字,_财务报告和审定财务报表-(口袋在里面,不是第一个); 小写扩展 :.html页:1entry, (中文(简体) ),.jpg或者说.png图像( e)intro/track.jpg没有intro/Track.PNG. 没有WebP:旧电视浏览器(WebKit基于Tizen 2.x,webOS 1–2)可能无法解码. JPG (质量) 大约80个),用于截图,PNG只用于平面艺术. - 语音短片:一个句子的片断在
voiceClipUrl(base, locale, voiceKeySync(text, locale)),这是${base}/voice/${FABI_VOICE}/${locale}/${key}.mp3,每个语言一个文件夹(voiceKey与约同;voiceClipUrl抛出在本地地址上,但it或者说en) (中文(简体) ). 键是 UTF-8 字节中的 SHA-256 的第一个32个小写十六进制字符`${FABI_VOICE}\n${locale}\n${t}`(单位:千美元)FABI_VOICE实值fabi-v1),在其中t是 Unicode NFC 中的文本,使用 Java 脚本trim()已应用; 有效句子周围没有空白, 因此对于任何语言的生成器t只是NFC的文本。 这么说吧voiceKeySync('Salta!', 'it')实值cbd16ba39816bdc5afd34a3e84082331及其剪辑https://cdn.fabiplay.app/voice/fabi-v1/it/cbd16ba39816bdc5afd34a3e84082331.mp3。 。 。 .voiceUrl(base, key)旧的 没有本地文件夹的平面布局, 已贬值 。 SHA-256为平原JavaScript,, 同步: 无crypto.subtle因此,它在电视网页上工作,服务于http、旧的电视浏览器和节点18 软件包engines) (中文(简体) ). - 电话的按钮: 在介绍期间,电话发送
{ type: 'intro', action },有动作next, (中文(简体) ),repeat, (中文(简体) ),skip,或replay(从暂停菜单:再次解释);屏幕告诉它什么是法比 说{ type: 'intro', step, steps, text, voice }。 。phase信件携带intro: true当 游戏有介绍:只有这样,电话才会提供replay。 。 。 .
盖面
清单的可选性 cover 是游戏目录中的游戏卡片: 游戏的16: 9 图像( 建议 1280x720)
拥有文件, cover.jpg。 。 。 . parseManifest 检查路径( e)isCoverPath: 相对、无计划、无领导 /,没有
倒斜,没有空的, . 或者说 .. 部分, .jpg, (中文(简体) ), .jpeg, (中文(简体) ), .png 或者说 .webp 小写,最多 COVER_MAX_PATH, (中文(简体) ),
(原始内容存档于2017-10-12). 128, phone. 文件本身由 Fabi Play 的审查检查, 常数导出在此 :
COVER_MAX_BYTES (15万个), COVER_ASPECT (第16/9号决议) COVER_ASPECT_TOLERANCE (0.02,相对数)
isCoverAspect(width, height)· ; COVER_EXTENSIONS 财务报告和审定财务报表 COVER_RECOMMENDED (1280×720) (中文(简体) ).
方向
清单的可选性 orientations 列出游戏可以玩的屏幕取向( e)Orientation数字 :
'landscape' | 'portrait',他们全部在 ORIENTATIONS:非空地,不重复;没有手段
['landscape'],哪个 gameOrientations(manifest) 适用。 一个电话(“Gioca qui / Play here”)是直立的
只提供列表的游戏 'portrait'电视和石碑都是景观 屏幕说方向a
游戏开始于 init.orientation (单位:千美元)orientationOf(width, height): 宽度( h): 'landscape'; 缺席
旧宿主,意思是 'landscape'。这是信息:一个游戏的外观大小.
瞄准目标. aimPoint(body | frame, side, { orientation, view }) 一条规则是 手对准
屏幕(它碰到的),分数:地平面 toScreen(view, wrist); 在肖像中, 相机图像所在之处
在电话底部很小,手腕被肩膀伸到整个屏幕上(HAND_SPACE,则
长度 PlayerFrame.leftHand,被夹到0–1;臀部看不见的躯干至少是
TORSO_PER_SHOULDER_WIDTH 肩宽。 当手腕(在肖像上,肩膀也一样)不见时,是无效的
(单位:千美元)AIM_VISIBLE) (中文(简体) ). AimHold {\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}把一只失落的手藏起来 AIM_HOLD_MS (300) (英语). SDK的车 play.aim 编辑
发动机 hands() 应用它.
安全区. init.safeArea (可选的)是电话的出处, 圆角和家酒吧封面, 分数
在游戏的取景口: { top, bottom, left, right } (单位:千美元)SafeArea) (中文(简体) ). parseSafeArea 每边夹到0-0.25
(单位:千美元)MAX_SAFE_INSET失踪时为0; NO_SAFE_AREA 是所有0, 什么主机不发送它的意思.
局部姿势. init.localPoses (可选)是 true 当画面中的尸体来自同一个相机
设备作为屏幕(单独播放的电话或平板电脑),而不是网络上的电话。 然后SDK滑动
默认情况下插出变相器较轻( 空闲度: 要吸收的不快), 除非游戏给出
(单位:千美元) smooth 数额。 缺席(老年人主机,电话发送到电视)是指 false。 。 。 .
两个屏幕上的旋转木马
电话可以显示电视机的旋转木马游戏,两者同时移动. 成年的刷子,电话发出
{ type: 'focus', game } (CaptainMessage) 对于它中心卡片: 仅一个预览,没有开始(pick 开始
(游戏) 屏幕将同一张牌集中,并用其声音(屏幕拥有声音
电话保持安静。 当屏幕的旋转木马因任何其他原因而移动时(遥控器、手光标、另一个)
电话,它发送 { type: 'focus', game } (ScreenMessage)和电话跟随. 都一样 pick
(单位:千美元)isGameId; 其目录中没有游戏的一面忽略了消息.
电线上的可能性
电话流 { type: 'pose', t, bodies } 在一个无序、无转发的数据上每秒约30次
频道. 列表的屏幕 POSE_CODEC_VERSION 致欢迎词binaryPose: [1],参见 acceptsBinaryPose获得
在二进制中, encodePose 电话和 decodePose 在屏幕上; 任何其他屏幕都得到 JSON 和屏幕
都读了 版本 1, 小- endian :
| 折减 | 大小 | 外地 |
|---|---|---|
| 0 个 | 1个 | 魔术 0xFB |
| 1个 | 1个 | 编码版本, 1 |
| 2个 | 1个 | 类型, 1=姿势 |
| 3个 | 1个 | 尸体数,0-4 |
| 页:1 | 第8条 | t,浮点64 (按电话钟计) |
| 第12条 | 每人132人 | 33个地标 × 金特32:比特0-9 x-1000,10-19 y-1000,20-29能见度 1000,30-31 0 |
因此有12个+132×个活体字节(4个活体540个活体). 值为千分之一 toPlayerSpace 弹入,所以解码
姿势和JSON一样. decodePose 返回为空(长度错误,),
魔法,版本或类型,超过4个身体,值超过1000, t 永远不要扔.
大多数游戏只需要 @fabi-play/sdk,它包括它使用的东西
从这个包裹.
许可证
Fabi Play Kit License:可自由使用,仅用于为Fabi Play制作游戏和工具. 见 自由主义。 。 。 .
电视遥控器
清单的可选性 inputs (单位:千美元)GameInput[]从 GAME_INPUTS数字 : body, (中文(简体) ), remote; 缺席 ["body"],参见
gameInputs),表示在没有电话的情况下,游戏是否可以用电视遥控器来玩; parseManifest
需求 body 在其中,没有重复和未知值。 屏幕告诉游戏如何播放会话
init.input (缺席) 'body'和,与 'remote',是否远程点(init.pointerLG的魔法遥控器:
游戏页面中的普通指针和鼠标事件). 屏幕将密钥转换成手势( QQ 或 确定) jump, 举行
squat编号 :stand车道,好两次 clap,退后平台的暂停),一次扮演一个孩子:init's
players 是孩子现在在玩(一个id)。 有几个孩子轮流玩游戏,他们的名单上写着 "turns": true
(仅以 remote 内 inputs;这意味着游戏遵循回合合同;没有它,只有一个孩子: init.turns
按顺序列出每个儿童parseTurnOrder; 缺席 : players) (中文(简体) ). 游戏每个孩子玩一回合; 当 a
孩子们的圆末(也撞倒了) 转弯不动,它问 break('turn'),屏幕总是回答
break-start (它转动的屏幕), { type: 'turn', players: [2] } (确切地说,一个id,下一个顺序;
parseTurnPlayers 检查其形状)和 break-done下一个孩子的傀儡就在中道 之后
最后一轮比赛以每个孩子的分数结束. level 财务报告和审定财务报表 gameover 课间休息从不交换玩家; 主机
在转弯前回答 turn 作为未知的原因,一次。 游戏按玩家ID保持分数. 见"用电视遥控器播放"
@fabi-play/sdk 读取。 。 。 .
箭头作为光标
清单的可选性 "remoteCursor": true (仅以 remote 内 inputs)以远程模式询问屏幕,
将箭头变成自由光标而不是手势。 屏幕保存所持箭头并运行
KeyCursor 每个动画框( e)update(held, dtMs) → { x, y }, 0–1 游戏框: 初慢而快
箭头持有的时间越长,对面箭头取消,对角不快,被夹在边上,一个长相框计算
等于100毫秒; reset() 在游戏上方绘制光标,并发送 { type: 'cursor', x, y, down }
(单位:千美元)parseCursor当它移动,当OK走下或上。 里面写着 pointer: true以魔术遥控器发誓, 这个
SDK在游戏的页面中将信件变成指针和鼠标事件,因此游戏无论用哪种方式都可以看到鼠标. 回来
保留平台的暂停; OK是光标的按钮, 不是跳出 .
手机上的图片
游戏可以在家庭手机上保存一张照片. 路径和消息:
- 屏幕告诉游戏是否可以:
init.pictures当它改变时,{ type: 'capabilities', pictures }。这是真实的,当一个电话hello说pictures: true链接( app; 网络电话) 不说). - 游戏发送
{ type: 'picture', data, title?, id? }(游戏):dataa base64 数据 URL,data:image/jpeg或者说data:image/png最多MAX_PICTURE_BYTES(3 MiB of image),其字节真正开始为 该类型(checkPicture· ;parseGameMessage其他东西都丢掉);title最多MAX_PICTURE_TITLE(60个) 字符,由parsePictureTitle。 。 。 . - 屏幕通过他们可靠 订购的数据频道发送到手机上 片段,因为数据频道
不要携带多兆字节消息( 16 KiB 是每个浏览器需要的) :
chunkPicture(dataUrl, id, title)给{ type: 'picture-start', id, mime, size, title? }(单位:千美元)size在图像的字节中),然后{ type: 'picture-chunk', id, seq, data }(单位:千美元)PICTURE_CHUNK_CHARS16,000个基数64,每个但最后一个,seq从 0 开始;那么, JSON 的每个消息都保持在 16 KiB 以内{ type: 'picture-end', id }(史记. - 电话给他们喂的
PictureAssembler(按任意顺序划出;缺少块,超过极限的图片,a) 块过其大小, 字节不是该开始的类型, 全部失败有原因) 和答案{ type: 'picture-saved', id }或者说{ type: 'picture-failed', id }(主计长发言). - 屏幕回答游戏
{ type: 'picture-result', id, result }(单位:千美元)parsePictureResult:'sent', (中文(简体) ),'unavailable', (中文(简体) ),'too-big'或者说'error'。 。 。 .
隐私:照片只通过直接链接(WebRTC,加密)通过电视 手机,从未通过或进入服务器, 其它地方也没有副本 Games只能这样发送一个JPEG或PNG图像.