iovxw

在 Android 模拟器上运行光遇

有钱还是直接买个 iPad 吧

Sky: Children of The Light 这游戏, 可以说是对高级用户十分不友好了

在 Android 上, 它只提供 arm64-v8a 的 binary, 直接拒绝高性能的 x86 平板以及模拟器

它还不允许你自己调高画质, 有一个画质上限, 由厂商根据机型来决定你最高能跑什么画质

而这个机型列表还不够全, 让你只能拿着顶级的 SoC 跑着 480p 30 帧的画面, 那云都是一团一团的马赛克

对于一个靠画面的步行模拟游戏来说, 这不能忍

所以这两天我折腾了一下在 PC 上运行它, 争取能在客厅躺在沙发上用电视玩最高画质


运行环境的选择

光遇要求 Android 10 以上的 arm64 环境

这直接劝退了一大波游戏专用 Android 模拟器, 因为他们都跑着 Android 9 甚至 Android 8

甚至 Android-x86, 都还卡在 Android 8.1 上

不过理论上, 只需要一个 x86_64/arm64 的 Android 10 即可, 所以如果你已经有这种环境, 可以跳过下面的安装部分了

为什么 x86 可以? 感谢 Native Bridge, 在新版 Android 上我们可以无需任何配置直接在 x86 上运行 arm 的 binary

这里我使用的是 Android Emulator, 配置过程如下:

安装 Android Emulator

不管是直接用 Android Studio 自带的, 还是从软件源装, 总之装上它

版本需要 > 30.0 不然 arm 翻译不好使

创建 AVD

创建一个 AVD, 机器型号随便选一个带 Google Play 认证的

然后注意, 镜像要选 Android 11 x86_64 Google Play 版本

Android 10 我没测试过, 总之选新但又不是那么新的

一定要确认 ABI 是 _64, Android Studio 里默认给你的可能是 32 位, 跑不了 arm64

还有就是要 Google Play 版, 不要默认的 Google API 版

Google Play 版因为认证, 会限制你修改模拟器硬件配置, 但我们可以跳过它直接修改配置文件

而用 Google API 版的话, 需要手动安装 GMS 框架, 比改两行配置麻烦得多

修改 AVD 配置

打开 ~/.android/avd/*.avd/config.ini, * 是你 AVD 的名字

确保如下几项设置

disk.dataPartition.size = 10G # 一般 5G 够用, 但考虑到要存多份游戏 apk, 大点较好
hw.gpu.enabled = yes
hw.gpu.mode = host # 使用硬件 gpu
hw.ramSize = 16384 # 内存我直接上了 16G, 8G 好像也够用
hw.cpu.ncore = 6 # CPU 核心数, 多给吧

搞清楚 emulator 的位置

根据你的安装方式, 确定你可以从终端运行 AVD emulator, 因为后面需要手动加参数

Android Studio 安装的默认位置是 ~/Android/Sdk/tools/emulator

然后就可以开始下一步, 配置环境了


运行环境的配置

ROOT

对, 需要 Root, 最好是 Magisk, 这样就可以直接使用下面我写的 Magisk Module 了

对于 AVD, 请参考 https://github.com/shakalaca/MagiskOnEmulator

这里有一个预先 patch 好的 ramdisk.img https://github.com/iovxw/BINARIES/releases/tag/ramdisk-avd30

对应的是 AVD x86_64 API 30 with Google Play, Magisk 23.0

如果是相同版本的话可以直接拿去替换

启用 GLES 3.1

如果你的显卡及驱动够新, 应该是不用这一步的

但在某些情况下, 哪怕够新了模拟器也不给你 3.1, 然后运行游戏就会出现以下画面:

通过 glxinfo | grep 'OpenGL ES' 查看当前显卡及驱动的 GLES 版本:

$ glxinfo | grep 'OpenGL ES'
OpenGL ES profile version string: OpenGL ES 3.2 Mesa 21.2.3
OpenGL ES profile shading language version string: OpenGL ES GLSL ES 3.20
OpenGL ES profile extensions:

我的显卡是 UHD 630, Intel 用了好几代的核心显卡, 是支持 GLES 3.2 的

看一下模拟器现在的 GLES 版本:

$ adb shell getprop ro.opengles.version
196608

查一下文档, 版本号对应如下:

ro.opengles.version=65535 # OpenGL ES 1.0
ro.opengles.version=65536 # OpenGL ES 1.1
ro.opengles.version=131072 # OpenGL ES 2.0
ro.opengles.version=196608 # OpenGL ES 3.0
ro.opengles.version=196609 # OpenGL ES 3.1
ro.opengles.version=196610 # OpenGL ES 3.2

现在模拟器的是 3.0 版本, 而 host 支持的是 3.2

有文档说要模拟 GLES 3.0, 需要将显卡 GLES 的升级到 >= 3.2

但我们要模拟 3.1, 很明显至少不能通过升级 host 的 GLES 版本达成, 因为现在最新的 GLES 版本就是 3.2

那就只能通过一点点魔法强行启用 3.1 了, 反正不会爆炸

BTW: 如果你的 GLES 版本甚至没到 3, 而你很确定你的显卡支持它

就去 Android Emulator 的 system-image 目录, 找到对应 image 的 advancedFeatures.ini

确认 GLESDynamicVersion = on 这一项是存在的, 如果没有就加上

BTW2: 如果按照上面的安装, advancedFeatures.ini 的位置是 ~/Android/Sdk/system-images/android-30/google_apis_playstore/x86_64

启用的方法很简单, 把 ro.opengles.version 设为 196609 就行了

但注意必须在开机初始化阶段就设置, 不然没用

这里可以写个 app 检测 (顺带一提用 CPU-Z 检测到的版本没用, 它是直接读 props 的)

ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
System.out.println(Double.parseDouble(configurationInfo.getGlEsVersion()));

如果不会设置也不用担心, 后面我写了个 Magisk 模块, 直接刷上就可以了

启用 AEP

光有 GLES 3.1 还不够, 你看它图里还要求 Extension Pack

那我们就给它 Extension Pack, Android Extension Pack (AEP)

AVD 的镜像默认是没有启用这个 feature 的, 如果你使用的镜像有, 可以跳过这步

创建 /vendor/etc/permissions/android.hardware.opengles.aep.xml

内容为:

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<!-- This is the standard feature indicating that the device supports the
     Android Extension Pack features. -->
<permissions>
    <feature name="android.hardware.opengles.aep" />
</permissions>

这一步我和上一步一起写了个 Magisk 模块完成, 参见: https://github.com/iovxw/eanble-gles3_1_and_aep/releases/latest

安装游戏

现在可以安装游戏了, 但不能直接从 Google Play 装, x86 设备会提示不兼容 (虽然确实可以运行)

但毕竟条条大路, 可以从其他设备下载后提取, 或者 TapTap 国际版是可以直接安装的

https://www.taptap.io/app/82226

注意 TapTap 国际版屏蔽了大陆 IP

然后这里我上传了一份目前最新版本的 apk, 不保证更新

如果你想要分享, TapTap apk 的储存位置在 /data/data/com.taptap.global/files/taptap/tmp

安装到最后时可能会出错, 记得检查你的磁盘空间是否够用

如果想知道具体的出错原因, 进 adb shellpm install 安装 apk

启动游戏

可能会崩, 多来几次. 确保内存什么的没满

一般崩掉的原因是 main loop 过长时间无响应, 换个更强的机器可能解决问题

作为参考我的机器是 Intel i7 8700 + SM961, 性能主要就是吃这俩

我这 CPU 主频够用但是 SSD 看起来没手机加载快, 可能需要换个硬盘虚拟化方式

不过重开个四五次大概率就可以了, 让缓存什么的准备好

这时游戏里的画面等级是最低的, 全是马赛克

并且最高只能点开两个闪电, 点闪电的时候可能会崩, 是正常现象, 下次启动画面就已经修改过了

但这里我们不需要手动点闪电, 直接进入下一步:

解锁画质设置

编辑 /data/data/com.tgc.sky.android/shared_prefs/com.tgc.sky.android_preferences.xml

修改下面三项

<string name="quality_mode_preference">Presentation</string>
<string name="device_capability_gpu_rating">10000000</string>
<string name="device_capability_hash_id">1</string>

device_capability_gpu_rating 随便设置一个足够高的值, 作为参考: iPhone 11 Pro 的值是 60000

启动游戏, 现在我们是满画质了

可以看到地面的纹理细节, 模型精细程度也还可以

远处的草地仍然没加载, 云也还是马赛克, 但程度差了很多

分辨率应该是原生, 帧率游戏本身上限是 120

接入手柄

Android Emulator 可以把 USB 设备传给 AVD, 不过我没找到图形化操作方式, 用命令的话参数如下:

# 模拟器程序路径, 默认是这里
~/Android/Sdk/tools/emulator \
    # 改成你的 AVD 的名字
    -avd Nexus_5X_API_30 \
    # 关掉快照
    -no-snapstorage \
    # 关掉对内存的 mmap, 能显著减少游戏加载时卡死的概率, 以及省掉硬盘上的内存等大空间
    -feature -QuickbootFileBacked \
    # 接下来的参数是传给 qemu 的
    -qemu \
    # 添加一个 USB 2.0 控制器
    -device usb-ehci,id=ehci \
    # 把手柄传进去
    -device usb-host,bus=ehci.0,vendorid=0x045e,productid=0x028e

手柄的 vendorid productid 可以用 lsusb 查看

Bus 001 Device 019: ID 045e:028e Microsoft Corp. Xbox360 Controller

待续

device_capability_gpu_rating 的设置会在游戏重启时被重置, 所以需要每次启动前都修改配置

但其实完全可以通过模拟设备型号, 来免掉这一步骤

不过目前需求已经满足了, 有时间再折腾吧

附: 文末彩蛋