转载

年度巨献:移动游戏实现技术优化的解决方案详解

年度巨献:移动游戏实现技术优化的解决方案详解

腾讯手游技术总监  张丹

手游经过多年来的高速发展,如今已经进入白热化的红海竞争时代,仅凭一个好的创意就能大获成功的产品已经越来越少,必须经过不断精细化的打磨,追求极致的用户体验,才能做出S级大作。

下面,我试着讲述如何从技术角度追求手游(特别是多人对战手游)用户体验提升的解决方案。

我们将用户体验从用户行为划分为五大模块:

年度巨献:移动游戏实现技术优化的解决方案详解

以下分别从这五个方面描述手游基础技术上,特有的问题和解决方案:

年度巨献:移动游戏实现技术优化的解决方案详解

一、下载

移动游戏下载包括两种:

1.应用市场或者官网整包下载。

2.游戏内自更新升级。

剔除掉“用户主动取消”和“无网络”的情况下,成功率可以达到80%-99%。

下载简单示意图:

年度巨献:移动游戏实现技术优化的解决方案详解

下载主要失败原因有(比例较小的原因就不详细列出了):

客户端出现问题的主要原因:

1.有网络但下载不了。

可能原因:

a.用户禁用了该应用市场APP的 非WiFi网络访问权限 (在非WiFi情况下)。

b.连上了WiFi,但此 WiFi需要验证 或者此 WiFi无法访问网络

c.该网络处于 网络拥塞 或者 信号较弱 的情况。

解决方案:

检测网络连通性,提醒用户检查系统设置等。

2.磁盘空间不够。

解决方案:

下载前先检查磁盘空间是否足够,提醒用户清理。

3.创建文件异常/写入文件异常。

解决方案:

此情况可能是 存储卡IO异常 ,一般先进行判断writeleft>0和进行fwrite几次重试即可恢复。

少部分用户可能是 手机内存卡有写保护 ,提醒用户进行设置(一般安卓系统里没有,需要在PC里面设置或者root用户通过系统软件设置)。

网络问题的主要原因:

1.整包或部分文件被劫持或者Cache。

此问题移动网络下比较常见,特别是中国移动,劫持或Cache导致的失败率占一半以上,当地运营商(各省策略不一样)由于各种原因,将某些下载文件劫持,导致下载失败。

解决方案:

提供备份BGP下载地址,由于CDN边缘节点较多,整个CDN节点都进行备份,资源浪费比较严重,由于失败用户占比较小,所以采取集中的BGP IP下载备份源,当CDN下载失败时,直接连接BGP IP的nginx代理重试下载。

效果:

在某些游戏上,失败用户使用了BGP IP直连方式,整体成功率 提升了20~30%

年度巨献:移动游戏实现技术优化的解决方案详解

2.移动网络下,数据文件被运营商网关截断。

解决方案:

少部分运营商 WAP网关会对单数据包大于10M的请求进行截断 导致下载失败,解决方法是采用 分片下载 的方式,当一个下载资源包大于10M时,将资源包分成数个小于10M的资源包进行下载,本地再进行组合。

3. 跨网下载 很慢或者失败,由于下载过程中网络发生切换(移动网络切换WiFi或者WiFi切换另一个运营商WiFi)导致。

解决方案:

及时判断网络的制式以及和后台通讯看用户的IP是否发生变化,如发生变化,重新解析CDN域名获取与用户IP所属运营商一致的CDN资源,并支持 断点重连 技术。

CDN问题主要原因:

CDN的问题主要是和各个CDN厂商相关,比如有些CDN厂商的CDN池分两种:

小资源CDN池:整体带宽相对小,支持频繁更新(回源频率快),边缘节点多,离用户近,下载更快。

大资源CDN池:整体带宽大,不支持频繁更新(大资源对回源服务器压力大),边缘节点少,主要集中在大城市,下载相对较慢。

这里就要注意:

1.大的整包资源尽量不要放在小资源CDN池,假如该CDN每十分钟清理文件并到回源服务器去拉取最新文件,会导致每十分钟你的整包资源会被删掉,并且在回源完成的过程中无法下载成功。

2.图片、配置文件、公告等小资源可放在小资源CDN池,这样配置文件,公告等经常更新的资源更新后会更快速及时的被用户下载到。

3.一般CDN边缘节点会有LRU(Least Recently Used )近期最少使用算法 ,如果你的资源老被淘汰到磁盘上而非内存中,必然导致下载速度相对较慢, 如果CDN边缘节点负载过高 ,也会导致下载较慢或者失败,这些需要找CDN厂商帮你定位解决。

另外,文件越大,下载时间越长,整体失败率也相对越高(用户看到包太大也会有所顾虑),而针对游戏版本升级,应用市场还有一种 增量更新 的方案可以减少文件大小和下载时长。

增量更新原理图

年度巨献:移动游戏实现技术优化的解决方案详解

这些优化完之后,整体的下载成功率可以提高到98%以上(剔除掉“用户主动取消”和“无网络”)。

针对应用市场下载,仅仅看下载成功率是不够的,应用市场下载到注册的流程是:

年度巨献:移动游戏实现技术优化的解决方案详解

这里要有一个详细的漏斗图,了解到每一个步骤用户流失的情况是怎么样的,和大盘比是否很差,可能在哪些方面有问题:是否产品的曝光标题不够吸引人?是否产品详情页不能打动用户?是否游戏启动后,新手引导设计不合理,导致用户没有注册?……根据每步的数据有针对性的对每个环节进行优化。

年度巨献:移动游戏实现技术优化的解决方案详解

二、登录

DNS解析:

DNS解析是登录的第一步,也是使用域名业务最常遇到的问题,这里介绍 移动网络特有的几个DNS的问题

1.移动网络LocalDNS劫持

DNS劫持是大家遇到最多的问题,移动运营商由于算法、调度和网间流量等种种原因,将域名的IP解析成自己网内的一个IP或者一个错误IP,导致玩家无法登录服务器,突发的时候 DNS劫持率可以达到2%以上 。这个状况大家应该都比较了解,就不再细讲。

2.移动网络DNS解析IP非本运营商IP

原因一:

部分运营商骨干网带宽较小(特别是中国移动运营商),访问LocalDNS得到的是 本运营商的接入点IP (因为我们做了分运营商接入),但是用户访问的时候,运营商判断出口带宽不够,就把流量调度到租用的第三方出口,也就是说获取DNS的网络路径和流量的网络路径不一致,我们最终看到用户的 出口IP是第三方的IP ,这样就会导致用户出现跨网访问。

年度巨献:移动游戏实现技术优化的解决方案详解

原因二(非常少量):

运营商为了防止DNS服务器故障,做了第三方DNS服务器备份,当LocalDNS故障时,用户访问到第三方DNS服务器得到其他运营商的接入点IP,导致跨网访问。

年度巨献:移动游戏实现技术优化的解决方案详解

3.移动4G网络DNS解析很慢

这是 4G网络 的一个 特有问题

通过一些用户投诉我们发现有些游戏登陆非常慢,而实际上他的网络质量还是很好的,玩的过程中即便延时也很快。于是,我们抓包发现:

年度巨献:移动游戏实现技术优化的解决方案详解

移动4G用户DNS先去查询4A地址(IPV6地址),大部分业务现在都没有配置4A地址,所以正常的应该返回4A地址为空,然后就会去查询A地址,获得正常的IPV4地址。一般流程如下:

年度巨献:移动游戏实现技术优化的解决方案详解

可是这里DNS服务出现问题,不是返回IPV6地址不存在,而是返回4A地址 查询错误

年度巨献:移动游戏实现技术优化的解决方案详解

这个时候部分安卓系统就会出现问题,系统认为查询错误不是没有IPV6地址,而是系统错误,就会不停地重试去访问4A地址,甚至重试几分钟后才去获取IPV4地址,导致业务一直卡在DNS获取地方,登陆游戏很慢。

既然有这种问题,那么为什么没有大面积投诉呢?是不是可能只是部分网络有这个问题?

经过查询相关文档,我们发现,目前只有4G网络是支持IPV6的。

于是我们对移动,联通,电信 2/3/4G,WiFi网络都进行了测试,发现只有移动4G有这个问题,可是当我们在另外一个省移动4G进行测试时,我们发现没有去进行4A访问。

难道查询4A还和省份有关系?最终经过我们重重跟进,我们发现查询4A地址(IPV6),不仅仅和 网络制式 有关系,和 手机型号或定制系统 也有关系。因为我们另外一个省是用小米note去测试的,而我们自己使用华为mate 7测试;另外一个省用华为mate 7测试也是要先访问4A,而小米note无论哪个省移动4G都不去查询4A地址。

于是,我们得出结论:

年度巨献:移动游戏实现技术优化的解决方案详解

支持4A查询的移动4G网络,也只有手机支持查询4A地址,才会去查询4A,这也是用户投诉面积不大的原因。

另外,我们通过抓包,同样在移动,联通,电信4G情况下,支持4A(IPV6)的手机也没有去查询网络是否支持4A(IPV6),就直接发起4A(移动)或者A(联通/电信)查询, 我猜测网络是否支持4G,应该是核心网会知会手机,这个知会并不是走网络协议,而是3GPP核心网内部的一个协议,所以我们抓不到包(仅是我的猜测,还未得到官方证实)。

说了这么多,那么解决这些DNS问题有什么办法?

我们主要采用 httpdns+LDNS结合 的方式:

年度巨献:移动游戏实现技术优化的解决方案详解

技术原理:

A、SDK通过高效的BGP线路直接访问HTTPDNS后台,获取域名的最优IP,客户端获取到业务IP后,就直接往此IP发送业务协议请求。

B、基于容灾考虑,保留使用运营商LocalDNS解析域名的方式作为备份线路。

(因为我们发现,有些BGP IP也会被极少数运营商劫持)

年度巨献:移动游戏实现技术优化的解决方案详解

由于优先取HTTPDNS,而不是LDNS,跨运营商和4A的问题也相应得到解决。

通过搭建我们自己的HTTPDNS服务和LDNS双备份服务,发现域名劫持率基本由1.5%降为0.1%,跨运营商访问率也由4%基本降为0,4A导致的登录慢情况也不再出现。

网络连接:

网络连接主要有以下几个问题:

1.运营商之间出口带宽小,网络不稳定,如业务部署的服务器和用户不在一个运营商,会导致连接超时或丢包严重。

这个是最基本的问题,大家应该都有解决方案,一般有2种:

分运营商接入:

年度巨献:移动游戏实现技术优化的解决方案详解

使用BGP IP:

百度搜索BGP的解释:边界网关协议(BGP)是运行于 TCP 上的一种自治系统的路由协议。 BGP 是唯一一个用来处理像因特网大小的网络协议,也是唯一能够妥善处理好不相关路由域间的多路连接的协议。

BGP实现单一IP覆盖所有运营商用户的效果,利于运营资源利用率的提升,并能彻底解决用户跨网穿越的问题。

对于解决中国这么复杂的运营商网络,BGP是一个不错的解决方案,但BGP资源一般都比较贵。

2.手游用户经常在国外访问我们的服务器。

手游用户由于出国游玩或者居住国外,经常会从国外连入我们国内的服务器,由于中国对国际出口的管制,导致网络质量会非常差。

有能力的公司可以增加国外接入点(建议在香港),然后调度国外用户接入国外接入点,再通过vpn或者专线接入国内服务器(这个vpn或者专线也会受到国家监管),提高国外用户访问质量。

这些问题相信大家都知道,这里不再细说。

除了这些基础问题外,我们来看看一个典型的手游登录流程:

年度巨献:移动游戏实现技术优化的解决方案详解

用户启动游戏后,一般先检查是否有更新包,如果有的话就下载更新(选择更新或强制更新),然后调用个平台的sdk进行登录授权,通过后选择区服,然后进入游戏大厅。

登录成功率低可能有很多原因,我们要知道每个环节的成功率和流失率是怎么样的才能细致的去做优化,比如用户是不是 检查更新失败 ,是不是我们的更新服务器出了问题?用户是不是 更新下载失败 (前面已讲过原因和方法)?是不是 登录sdk 出了问题?是不是 大区列表拉取失败?上次登录服和推荐服是否错误? 最后才是 连接游戏服务器失败

年度巨献:移动游戏实现技术优化的解决方案详解

三、游戏内体验

Crash问题(闪退):

手游Crash对用户带来的体验伤害,大家应该都已经非常清楚了。Crash严重会导致大量的用户流失,所以对手游进行Crash监控和优化非常重要!

这里首先大概介绍下Crash的捕获和获取堆栈信息的方法(方便定位问题):

Android:

Java层异常的捕获,一般是在启动时设置异常回调:

void java.lang.Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler handler)  

一旦发生异常会调用到handler进行处理,handler参数中带有Thread和Throwable,可以通过这两个变量来获取线程堆栈和异常堆栈。

public static interface UncaughtExceptionHandler {  void uncaughtException(Thread thread, Throwable ex);  }  

但是游戏一般都不是用原生Java开发,都是使用游戏引擎,主流游戏引擎Unity是由C++(native)开发的,一般native的收集方法:

启动时注册信号处理

int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);  

一旦发生崩溃会调用到信号处理函数,只不过native收集会更麻烦一点,因此它把堆栈放在一个特定的内存中,需要fork出一个子进程去获取。

iOS:

程序启动,一般可以通过signal方法注册信号处理,signal(int signum, void (*shandler) (int));

系统调用AppDelegate的didFinishLaunchingWithOption方法处理,捕获SIGABRT,SIGILL,SIGSEGV等信号,当发生Crash的时候通过backtrace和backtrace_symbols这两个方法是追溯到出错堆栈。

并且,仅仅关注Crash还不够,我们还要关注引擎或者开发语言脚本的异常,因为这些异常可能最终导致Crash,也可能导致黑屏,花屏,数据显示异常,画面卡顿等,要实现一个完善的Crash和异常收集机制:

年度巨献:移动游戏实现技术优化的解决方案详解

Crash信息收集上来之后,crash次数非常多,我们必须集中精力优先解决重要的Crash问题,而一些 用户感觉不出来的Crash ,其实可以 不用解决或者放后解决 ,例如游戏切换到后台或者在游戏退出的时候产生的Crash,关于退出Crash,我们在unity中就发现一个典型例子:

我们发现很多游戏Crash的堆栈信息是发生在 nativeDone ,,nativeDone以上是native C++代码,通过反编译的追查,我们最终发现Application.Quit来调用的nativeDone,我们只用改写Application.Quit函数,只要调用Application.Quit函数,我们直接调用System.Diagnostics.Process.GetCurrentProcess().Kill(),这样就不用走到nativeDone了。

Unity引擎游戏还有一个比较典型的Crash:

很多unity游戏堆栈中,都有 nativeInjectEvent 这个函数,这个Crash是unity4.x的问题导致的,5.x似乎不会有这个问题。经过不断重现,我们发现这个跟输入法有关系,由于游戏拉起后立即输入所致。可能的原因也许是引擎尚未初始化完整,即尝试处理某些输入导致。解决方案就是在启动后立即屏蔽输入,不将其传递给unity,直到我们真的需要输入时为止。

这个Activity应该直接或者间接继承于unity的UnityPlayerNativeActivity。而我们要做的就是用一个开关来禁止或者允许android事件传输给unity的命令队列,重写dispatchKeyEvent等几个函数就可以解决。

其实还有很多Crash都是比较初级的编码规范没有执行好,例如空指针导致Crash,越界访问,调用空方法,地址无效,指针未初始化等等,解决起来也相对比较简单。

年度巨献:移动游戏实现技术优化的解决方案详解

一款手游要想Crash原因不造成用户流失,个人觉得 Crash率应该控制在3%以下 ,如果要做S级精品手机游戏, Crash率要控制在1%以内 最好。

解决了Crash的问题,我们就要分场景解决游戏内体验的问题:

我们主要将游戏(特别是有pvp对战的游戏)分为四个场景:

大厅:

年度巨献:移动游戏实现技术优化的解决方案详解

大厅承载了很多内容,包括各种玩法的入口,活动,任务,商城,背包,战队,联盟等等,这里我们认为对用户体验有较大影响的主要有:

公告弹出时长(拉取公告信息时间太长会导致用户界面假死),背包加载时长,活动加载时长,商城打开时长等……这些都是用户最常用的一些功能,且需要拉取服务器数据,打不开或太慢的话会严重影响玩家玩游戏的耐心和体验。

另外,我们还会去捕捉大厅的 屏幕热力区域 ,看看哪个区域是玩家点击最多的地方,从而去分析玩家对哪部分玩法最感兴趣,或者说可能是哪个按钮的点击区域有问题导致经常按不到等。

匹配:

年度巨献:移动游戏实现技术优化的解决方案详解

匹配一般用于多人pvp的游戏,即将酣畅淋漓的对战就要开始了。

这里我们主要关注 匹配成功率,平均匹配时长,地图加载时长 等。手游的玩家相对是比较没有耐心的,一旦匹配时间,加载时间过长,很容易就一个home键将游戏切到后台,导致出现用户挂机或游戏重连,严重影响游戏的对战性。

对局(重点):

年度巨献:移动游戏实现技术优化的解决方案详解

对局是pvp游戏的核心玩法,这里也是我们游戏内体验的 核心场景 ,这里也是我们关注的重点:

FPS:

FPS采集方法:unity每一帧都会执行一遍脚本的这些函数:update->lateUpdate->onGUI,典型的做法是new一个gameobject并挂载脚本。

在脚本的update函数中统计,update函数中,每次执行update函数,frame++,并累积时间,当累积时间>=1s时,计算fps = frame/time。

一般认为,平均FPS>25帧是体验较好的情况,平均15<FPS<25帧是体验一般的情况,平均FPS<15帧是体验较差的情况。如果一局当中FPS突然下降10帧以上,我们认为是一次卡顿,卡顿次数多了用户玩的体验就非常差了。

针对FPS较低的用户,我们通过大数据分析出一个“机能库”,把相应手机机型的推荐配置发送给用户,例如小米note手机关掉语音,音效,降低画质,每秒帧数,FPS分别可以提高多少等,帮助玩家尽可能的提高游戏的体验。

延时:

延时的采集方法:每3~5秒对游戏服务器进行一次延时测速,可以采用心跳包的模式,这里建议采用和游戏同样的协议,例如游戏室TCP连接的,那么,我们使用TCP心跳进行测速,游戏是UDP连接的,那应该使用UDP心跳进行测速,而不是统一使用PING进行测速,因为有可能和实际游戏使用的协议延时不一致,而且有些服务器禁止了PING协议。

网络低延时是pvp游戏的核心诉求!

年度巨献:移动游戏实现技术优化的解决方案详解

其中在2G情况下,80%以上的延时是在运营商核心网部分,这里确实没有什么办法优化;3G大概60%的延时是在运营商接入网部分,而4G大概只有40%左右的延时在核心网部分(取决于游戏服务器的部署)。

年度巨献:移动游戏实现技术优化的解决方案详解

而移动手机网络相对固定网络来说,有着明显的特点:

1.网络切换,移动网络切换到WiFi,WiFi切换到另一个WiFi,移动网络切换到另外一个移动网络(目前已经有双卡双待手机支持)等。

2.网络中断,当电话或者短信来的时候,移动网络会中断,有些4G网络(中国移动)会切换成2G网络,进电梯/地下室等等也会导致网络短暂中断。

3.网络拥塞,人员较多的地方,例如医院,大商场,演唱会等等,即使信号满格也会网速非常慢,偏远地区/室内信号不好的地方,只有1,2格信号也会导致网速变慢。

年度巨献:移动游戏实现技术优化的解决方案详解

那么,怎么解决这个问题?

我们分为两个层面去解决,一个层面是降低运营商接入网延时,一个是降低公网延时。

运营商接入网部分:

3G:3GPP协议里面PDP和DSCP都具有QOS保障字段,可以进行无线核心网的网络质量保障。

年度巨献:移动游戏实现技术优化的解决方案详解

4G:LTE网络定义了QCI可以对数据包进行管理和保障

年度巨献:移动游戏实现技术优化的解决方案详解

其中还定义了QCI等于3就是用于实时游戏。

年度巨献:移动游戏实现技术优化的解决方案详解

我们和运营商,设备商积极沟通,发现是存在调用运营商的平台去对用户核心网的QOS策略进行设置的可能的,不过这个推动所有运营商都开发这个能力,需要一定的时间。

年度巨献:移动游戏实现技术优化的解决方案详解

公网部分:

手游和端游在部署上一个显著特点:

端游一般是分区域部署,用户就近接入游戏大区,例如北京电信一区,上海联通一区,广东电信二区,游戏服务器都是按区部署在北京IDC,上海IDC,广东IDC; 手游一般都是集中部署 ,也不会按地区去进行分区,很多游戏还是全区全服游戏,游戏服务器一般都部署在一个idc,所以internet公网的延时会比PC端游更高。

公网典型是通过搭建 加速代理的方式 进行加速:

年度巨献:移动游戏实现技术优化的解决方案详解

卡顿率:

我们把FPS降低10帧以上,网络延时突然增加100ms以上定义为卡顿,这两种情况都会导致用户口中的“卡”,对游戏体验影响严重。

拖拽率:

拖拽的大概原因就是客户端本地会进行一定的惯性计算,当服务器负载过高,或者网络延迟严重的情况下,会导致客户端收到服务器的数据后对客户端的数据进行校正,就会出现拖拽的情况,同样,拖拽对游戏的体验影响比较严重。

掉线率:

掉线对玩家体验的影响这里就不用强调了。

除了关注以上这些数据外,我们还要关注一些基础数据,例如:

手机Cpu使用率,内存使用率,DRAWCALL、平均三角面(次)、电量消耗,流量等,这些也对游戏体验有不同得影响。

结算:

年度巨献:移动游戏实现技术优化的解决方案详解

结算是我们这局惊心动魄对战的结果,也是对玩家这局游戏的一个评定,进行排位,积分奖励,任务奖励,甚至是货币奖励,很多玩家就是冲着这个奖励而来。

这里,我们主要关注结算画面异常率,结算数据异常率,结算页面弹出时长,结算奖励/积分到账率等。

四、支付

目前手游主要支付包括两个平台:苹果支付和安卓支付。

苹果支付统一走苹果IAP,安卓由于Google Play未进入中国,大多使用第三方渠道sdk进行支付。

支付的典型流程为:

年度巨献:移动游戏实现技术优化的解决方案详解

支付失败,我们需要关注每个环节的失败率,特别是区分出用户主动取消和支付过程失败。

例如iOS支付失败的典型原因有用户安装了IAP破解插件的越狱手机,越狱手机的票据非法或者被替换等。

年度巨献:移动游戏实现技术优化的解决方案详解

由于支付大多都是由第三方sdk实现,优化方案也一般由sdk实现,这里就不在详述。

这里特别提醒下关于iOS支付,黑卡,恶意退款,汇率差三大iOS黑产业链,给手游的iOS收入带来绝大部分损失。这些产业链上每个角色分工非常明确,

黑卡:与iTunes账户绑定的非法信用卡,这些账户或为APP余额账户,或为透支账户,来源遍布美国、日本、加拿大等许多国家,倒卖者背后是破解或者盗取他人信用卡的黑客。

恶意退款:就是先IAP付款,然后打电话给苹果投诉,要求退款,空手套白狼,网上不时刷出最新有效的退款理由。

关于黑卡和恶意退款,苹果这边也在不断的优化处理方法,我们也根据用户的一些游戏行为去实时分析识别这些黑卡和恶意用户,进行封号等进一步打击。

汇率差:利用国际汇率的大幅波动,而苹果的汇率更新较慢的特点,像卢布,日元大跌的时候,淘宝上卖家利用汇率差打折售卖游戏币,赚取差价,给游戏iOS收入造成巨大损失。

一般做法是支付前识别异常货币,禁止进行支付,事后发现结算货币为异常货币禁止发货,甚至封号并提示用户后续处理措施。

五、舆情

热词分析:

从官网论坛、百度贴吧、应用市场、公众号、微博……等抓取游戏相关热词。

年度巨献:移动游戏实现技术优化的解决方案详解

通过这些热词监控,我们对用户当前最关注的热词有一个实时的了解,并进行热词的词义分析,分析这个词的情感,到底是正面,还是中性,还是负面,方便我们快速找到游戏体验的问题。

关键词库:

年度巨献:移动游戏实现技术优化的解决方案详解

事先配置好关键词库,然后去抓取这次关键词进行分析。

还有,就是对我们客服工单进行实时分析了。

一口气写了这么多,基本上一些手游用户体验和优化方案都已经讲到了,实在有点长,文笔也有限,作者都不想回头再仔细看一遍了:)

这里特别衷心感谢一起为手游技术不断探索和优化的兄弟姐妹们,感谢你们精益求精的辛苦付出和不断优化!

原文  http://os.51cto.com/art/201601/504580.htm
正文到此结束
Loading...