技术文档
<table>
<thead>
<tr>
<th>文档名称</th>
<th>鱼机串接技术文档</th>
</tr>
</thead>
<tbody>
<tr>
<td>适用范围</td>
<td>技术部</td>
</tr>
<tr>
<td>撰 写</td>
<td>cloud</td>
</tr>
<tr>
<td>审 核</td>
<td></td>
</tr>
<tr>
<td>签 发</td>
<td>nex</td>
</tr>
<tr>
<td>创建日期</td>
<td>2023年03月23日</td>
</tr>
<tr>
<td>修改日期</td>
<td>2023年03月23日</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th>修订日期</th>
<th>修订内容</th>
</tr>
</thead>
<tbody>
<tr>
<td>2023年03月23日</td>
<td>创建文档</td>
</tr>
</tbody>
</table>
<p>[toc]</p>
<h1>架构流程</h1>
<p><img src="https://www.showdoc.com.cn/server/api/attachment/visitFile?sign=3399d61bff07a456b14e89f38822af0d&amp;file=file.png" alt="" /></p>
<h2>鱼机H5资源</h2>
<table>
<thead>
<tr>
<th style="text-align: left;">项</th>
<th style="text-align: left;">期望值</th>
<th style="text-align: left;">备注</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left;">资源存储</td>
<td style="text-align: left;">aws-s3</td>
<td style="text-align: left;">有其他方式请提出</td>
</tr>
<tr>
<td style="text-align: left;">首次加载</td>
<td style="text-align: left;">10s</td>
<td style="text-align: left;">评估出资源大小, 在100kbps指标下大约需要多久加载时间</td>
</tr>
<tr>
<td style="text-align: left;">通讯协议</td>
<td style="text-align: left;">ws</td>
<td style="text-align: left;">http tcp websocket 哪种选型</td>
</tr>
</tbody>
</table>
<h2>鱼机服务器</h2>
<table>
<thead>
<tr>
<th style="text-align: left;">项</th>
<th style="text-align: left;">期望值</th>
<th style="text-align: left;">备注</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left;">运行方式</td>
<td style="text-align: left;">容器</td>
<td style="text-align: left;">容器</td>
</tr>
<tr>
<td style="text-align: left;">SERVER</td>
<td style="text-align: left;">3个微服务</td>
<td style="text-align: left;">docker 部署</td>
</tr>
<tr>
<td style="text-align: left;">DB</td>
<td style="text-align: left;">RDS</td>
<td style="text-align: left;">docker 部署 主从版</td>
</tr>
<tr>
<td style="text-align: left;">CACHE</td>
<td style="text-align: left;">es</td>
<td style="text-align: left;">docker 部署集群</td>
</tr>
<tr>
<td style="text-align: left;">MQ</td>
<td style="text-align: left;">docker</td>
<td style="text-align: left;">docker 部署</td>
</tr>
<tr>
<td style="text-align: left;">nacos</td>
<td style="text-align: left;">服务发现</td>
<td style="text-align: left;">docker 部署</td>
</tr>
<tr>
<td style="text-align: left;">后台</td>
<td style="text-align: left;">是</td>
<td style="text-align: left;">传统部署web-server 是否提供后台</td>
</tr>
</tbody>
</table>
<ul>
<li>部署方案:
<ul>
<li>A: H5资源和config 都存放到我方S3.</li>
<li>B: H5资源和config 都存放到 OSS .(优选)</li>
<li>C: H5资源S3 config放到 OSS.</li>
<li>我方准备2台EC2(8C16G) 后续可再扩容 ssh-key</li>
<li>h5-client 通过config 发现 fish-server 地址(公网IP).</li>
</ul></li>
</ul>
<h2>鱼机维护</h2>
<ul>
<li>鱼机H5 + 配置 + server版本 主要由长沙维护, 如果有企划相关的配置改动, 对方提供协助教程由台湾这边更新.</li>
<li>鱼机有机器人(假机器人,)</li>
</ul>
<h1>接口协议</h1>
<h2>玩家进入鱼机机台</h2>
<table>
<thead>
<tr>
<th style="text-align: left;">-</th>
<th style="text-align: left;">-</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left;">接口</td>
<td style="text-align: left;">enter_fish_machine</td>
</tr>
<tr>
<td style="text-align: left;">通讯方法</td>
<td style="text-align: left;">HTTP</td>
</tr>
<tr>
<td style="text-align: left;">协议格式</td>
<td style="text-align: left;">PB</td>
</tr>
<tr>
<td style="text-align: left;">备注</td>
<td style="text-align: left;">此接口由我方支持(更新玩家机台和座位数据)</td>
</tr>
</tbody>
</table>
<ul>
<li>鱼机:随机房间随机位置的策略</li>
<li>机台台号: 1-300 (房间 room_no)</li>
<li>座位号: 1-4 (鱼机是随机位置? 企划:鱼机H5里面的位置可以是随机的)</li>
</ul>
<p>方案A:</p>
<ul>
<li>client -> server -> fish-server -> server(更新我方的台号和座位号) # 台号 和 座位号 由 fish-server 控制 (台号 和 座位号 规则不符)</li>
</ul>
<p>方案B:</p>
<ul>
<li>client -> server -> client # 台号 和 座位号 [选这个]</li>
</ul>
<h2>玩家进入鱼机H5</h2>
<table>
<thead>
<tr>
<th style="text-align: left;">-</th>
<th style="text-align: left;">-</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left;">接口</td>
<td style="text-align: left;">player_enter</td>
</tr>
<tr>
<td style="text-align: left;">通讯方法</td>
<td style="text-align: left;">postMessage or url</td>
</tr>
<tr>
<td style="text-align: left;">协议格式</td>
<td style="text-align: left;">BASE64(JSON)</td>
</tr>
<tr>
<td style="text-align: left;">备注</td>
<td style="text-align: left;">加载鱼机H5时传递玩家初始化参数</td>
</tr>
<tr>
<td style="text-align: left;">备注</td>
<td style="text-align: left;">H5中需要的静态资料(内置,调用client的接口获取)</td>
</tr>
</tbody>
</table>
<ul>
<li>playerid</li>
<li>台号(room)</li>
<li>座位号</li>
<li>token</li>
<li>Hall EnterHall <code>json:&quot;Hall&quot;</code> // 厅级配置</li>
<li>Setting EnterSetting</li>
</ul>
<pre><code class="language-go">// 玩家进入厅的参数
type EnterHall struct {
HallType int `json:&quot;HallType&quot;` // 1:体验厅 2:一般厅 3:高手厅
# BetScores []int `json:&quot;BetScores&quot;` // 押注范围scores
MachineID int `json:&quot;MachineID&quot;` // 机台台号
SeatNo int `json:&quot;SeatNo&quot;` // 机台座位号(1-4)
}
// 系统设置
type EnterSetting struct {
soundEnable
musicEnable
}</code></pre>
<h2>鱼机服务器初始化玩家资料</h2>
<table>
<thead>
<tr>
<th style="text-align: left;">-</th>
<th style="text-align: left;">-</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left;">说明</td>
<td style="text-align: left;">fish-server -> server get初始化玩家资料</td>
</tr>
</tbody>
</table>
<pre><code class="language-go">// 参数结构(以下为Golang语法,自行脑补为json格式)
type Enter struct {
Player EnterPlayer `json:&quot;Player&quot;` // 玩家资料
Cards []EnterCard `json:&quot;Cards&quot;` // 玩家的卡片
AccessToken string `json:&quot;AccessToken&quot;` // 令牌
}
// 玩家进入自己的资料
type EnterPlayer struct {
PlayerSN int64 `json:&quot;PlayerSN&quot;` // 玩家流水號
PlayerID string `json:&quot;PlayerID&quot;` // 玩家帳號
NickName string `json:&quot;NickName&quot;` // 玩家暱稱
AvatarURL string `json:&quot;AvatarURL&quot;` // 玩家頭像連結
AvatarFrame int `json:&quot;AvatarFrame&quot;` // 玩家頭像框
Score int64 `json:&quot;score&quot;` // 玩家score -&gt; coin ( 1:100 )
VipLevel int `json:&quot;VipLevel&quot;` // 玩家VIP等級
Level int `json:&quot;Level&quot;` // 玩家等級
Exp int `json:&quot;Level&quot;` // 玩家當前經驗值
Active int `json:&quot;Active&quot;` // 玩家活躍度
}
// 玩家进入卡片资料(企划需要跟对方协商增加卡片配置表,以及卡片的使用和掉落规则)
type EnterCard struct {
ID int64 `json:&quot;ID&quot;` // 道具DBID
ItemID int `json:&quot;ItemID&quot;` // 道具ID
ItemCount int `json:&quot;ItemCount&quot;` // 道具数量
}
</code></pre>
<h2>Client通知鱼机H5跑马灯和大奖推播發</h2>
<table>
<thead>
<tr>
<th style="text-align: left;">-</th>
<th style="text-align: left;">-</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left;">说明</td>
<td style="text-align: left;">完全由我方支持(h5上面显示的)</td>
</tr>
</tbody>
</table>
<h2>鱼机服务器触发跑马灯事件(❓)</h2>
<table>
<thead>
<tr>
<th style="text-align: left;">-</th>
<th style="text-align: left;">-</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left;">接口</td>
<td style="text-align: left;">/game/BroadcastMarquee</td>
</tr>
<tr>
<td style="text-align: left;">协议</td>
<td style="text-align: left;">HTTP</td>
</tr>
<tr>
<td style="text-align: left;">方法</td>
<td style="text-align: left;">POST</td>
</tr>
<tr>
<td style="text-align: left;">数据格式</td>
<td style="text-align: left;">JSON</td>
</tr>
<tr>
<td style="text-align: left;">HEAD[Content-type]</td>
<td style="text-align: left;">application/json;charset=utf-8</td>
</tr>
<tr>
<td style="text-align: left;">HEAD[X-Access-Token]</td>
<td style="text-align: left;">player_enter.AccessToken(进入鱼机H5传递的令牌)</td>
</tr>
<tr>
<td style="text-align: left;">HEAD[HOST]</td>
<td style="text-align: left;">game.lm777.net</td>
</tr>
<tr>
<td style="text-align: left;">备注</td>
<td style="text-align: left;">无</td>
</tr>
</tbody>
</table>
<pre><code class="language-go">// 参数结构(以下为Golang语法,自行脑补为json格式)
type BroadcastMarquee struct {
PlayerName string `json:&quot;PlayerName&quot;` // 玩家昵称
PlayerAvatar string `json:&quot;PlayerAvatar&quot;` // 玩家头像url
PlayerFrame int `json:&quot;PlayerFrame&quot;` // 玩家头像框
MachineID int `json:&quot;MachineID&quot;` // 来源游戏ID
Hall int `json:&quot;Hall&quot;` // 廳別[必填]
GainItemID int `json:&quot;GainItemID&quot;` // 获得道具ID
JPPoolID int `json:&quot;JPPoolID&quot;` // JP
BigWinType int `json:&quot;BigWinType&quot;` // 大獎類型
GameScore int64 `json:&quot;GameScore&quot;` // 游戏得分
Priority int `json:&quot;Priority&quot;` // 优先级
ChatStringID string `json:&quot;ChatStringID&quot;` // 聊天系统使用的字串ID(此字段有值表示广播讯息需要同步显示到聊天框里面)
}</code></pre>
<h2>鱼机服务器提交结算资料</h2>
<table>
<thead>
<tr>
<th style="text-align: left;">-</th>
<th style="text-align: left;">-</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left;">说明</td>
<td style="text-align: left;">鱼机server提交结算资料</td>
</tr>
<tr>
<td style="text-align: left;">接口</td>
<td style="text-align: left;">/game/submit_settle</td>
</tr>
<tr>
<td style="text-align: left;">协议</td>
<td style="text-align: left;">HTTP</td>
</tr>
<tr>
<td style="text-align: left;">方法</td>
<td style="text-align: left;">POST</td>
</tr>
<tr>
<td style="text-align: left;">数据格式</td>
<td style="text-align: left;">JSON</td>
</tr>
<tr>
<td style="text-align: left;">HEAD[Content-type]</td>
<td style="text-align: left;">application/json;charset=utf-8</td>
</tr>
<tr>
<td style="text-align: left;">HEAD[X-Access-Token]</td>
<td style="text-align: left;">player_enter.AccessToken(进入鱼机H5传递的令牌)</td>
</tr>
<tr>
<td style="text-align: left;">HEAD[HOST]</td>
<td style="text-align: left;">game.lm777.net</td>
</tr>
<tr>
<td style="text-align: left;">备注</td>
<td style="text-align: left;">结算时机(特定结算逻辑单元(10s))</td>
</tr>
<tr>
<td style="text-align: left;">备注</td>
<td style="text-align: left;">结算数据内容定义</td>
</tr>
<tr>
<td style="text-align: left;">备注</td>
<td style="text-align: left;">断线续玩保护时间 10s</td>
</tr>
</tbody>
</table>
<pre><code class="language-go">// 参数结构(以下为Golang语法,自行脑补为json格式)
// 请求参数
type SubmitSettle struct {
CurrentRouteID string `json:&quot;CurrentRouteID&quot;` // 对局ID
PlayerID string `json:&quot;PlayerID&quot;` // 玩家帳戶ID
PrevScore int64 `json:&quot;PrevScore&quot;` // 玩家之前分數(更新前)
CurrScore int64 `json:&quot;CurrScore&quot;` // 玩家當前分數(更新後)
LevelExp int `json:&quot;LevelExp&quot;` // 玩家當前經驗值
UseItems []UserItem `json:&quot;UserItems&quot;` // 消耗道具
GotItems []UserItem `json:&quot;GotItems&quot;` // 得到的道具
/* 其他资料由 企划与对方沟通制定*/
DetailInfo // 什么炮 什么鱼 时间 ... 我们这边需要有鱼类 炮类 静态配置.
}
// 结算时消耗的道具
type UserItem struct {
ItemID int `json:&quot;ItemID&quot;` // 道具ID
Count int `json:&quot;ItemCount&quot;` // 道具数量
}
// 应答参数
{
server 更新玩家资料,并返回最新资料(vip level exp ...)
}</code></pre>
<h2>鱼机服务器随机切换机台座位</h2>
<table>
<thead>
<tr>
<th style="text-align: left;">-</th>
<th style="text-align: left;">-</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left;">接口</td>
<td style="text-align: left;">/game/switch_machine</td>
</tr>
<tr>
<td style="text-align: left;">协议</td>
<td style="text-align: left;">HTTP</td>
</tr>
<tr>
<td style="text-align: left;">方法</td>
<td style="text-align: left;">POST</td>
</tr>
<tr>
<td style="text-align: left;">数据格式</td>
<td style="text-align: left;">JSON</td>
</tr>
<tr>
<td style="text-align: left;">HEAD[Content-type]</td>
<td style="text-align: left;">application/json;charset=utf-8</td>
</tr>
<tr>
<td style="text-align: left;">HEAD[X-Access-Token]</td>
<td style="text-align: left;">player_enter.AccessToken(进入鱼机H5传递的令牌)</td>
</tr>
<tr>
<td style="text-align: left;">HEAD[HOST]</td>
<td style="text-align: left;">game.lm777.net</td>
</tr>
<tr>
<td style="text-align: left;">备注</td>
<td style="text-align: left;">无</td>
</tr>
</tbody>
</table>
<pre><code class="language-go">// 请求参数
type ReqParam struct {
PlayerID string `json:&quot;PlayerID&quot;` // 玩家帳戶ID
Hall int `json:&quot;Hall&quot;` // 廳別[必填]
}
// 应答参数
type AckParam struct {
MachineNo int `json:&quot;MachineNo&quot;` // 机台台号
SeatNo int `json:&quot;SeatNo&quot;` // 机台座位号(1-4)
}</code></pre>
<h2>客户端刷新游戏数据</h2>
<table>
<thead>
<tr>
<th style="text-align: left;">-</th>
<th style="text-align: left;">-</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left;">接口</td>
<td style="text-align: left;">freshen</td>
</tr>
<tr>
<td style="text-align: left;">通讯方法</td>
<td style="text-align: left;">HTTP</td>
</tr>
<tr>
<td style="text-align: left;">协议格式</td>
<td style="text-align: left;">PB</td>
</tr>
<tr>
<td style="text-align: left;">备注</td>
<td style="text-align: left;">此接口由我方支持(刷新玩家数据异常恢复)</td>
</tr>
</tbody>
</table>
<h2>游戏中异常</h2>
<p><img src="https://www.showdoc.com.cn/server/api/attachment/visitFile?sign=44e6f9663f6a6c5368a79eed54d2b241&amp;file=file.png" alt="" /></p>
<p><img src="https://www.showdoc.com.cn/server/api/attachment/visitFile?sign=2f9d7511462b6f7cd842708b85b90a8d&amp;file=file.png" alt="" /></p>
<h2>强制玩家离开鱼机</h2>
<table>
<thead>
<tr>
<th style="text-align: left;">-</th>
<th style="text-align: left;">-</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left;">接口</td>
<td style="text-align: left;">freshen</td>
</tr>
<tr>
<td style="text-align: left;">通讯方法</td>
<td style="text-align: left;">HTTP</td>
</tr>
<tr>
<td style="text-align: left;">协议格式</td>
<td style="text-align: left;">json</td>
</tr>
<tr>
<td style="text-align: left;">备注</td>
<td style="text-align: left;">server -> fish-server 让玩家即刻结算并离开鱼机</td>
</tr>
</tbody>
</table>
<p>client 收到GM惩罚, 直接关闭H5. 由fish-server 通知 game-server 玩家离开,并清理玩家数据.</p>