2025-01-07 Unity 使用 Tip3 —— 游戏保存数据到 Application.persistentDataPath 不生效解决方案更新
文章目录
- 1 问题描述
- 2 老版解决方案(测试可行)
- 2.1 创建 js 脚本
- 2.2 添加 js 引用
- 3 新版解决方案(测试不可行)
- 4 实际问题
WebGL 平台限制了文件访问系统,在 Unity 以前版本中,开发者想要在 WebGL 上保存游戏到本地很不方便。
目前,Unity 新版中给出了一项解决方案,但经测试,该方案目前不可取(截止 2025-01-07)。
- Unity 版本:6000.0.26f1c1
1 问题描述
Unity WebGL 平台中,游戏保存数据到 Application.persistentDataPath 不生效(官方链接:https://docs.unity3d.com/ScriptReference/Application-persistentDataPath.html)。
老版本 Unity 2019.2 官方给出了解释:Unity WebGL 将会话之间必须保留的所有文件(例如 PlayerPrefs 或保存在 persistentDataPath 中的文件)存储到浏览器 IndexedDB。这是一个异步 API,因此不确定何时完成。
2 老版解决方案(测试可行)
借助 js 脚本,在保存后显式写入数据到/idbfs中。
2.1 创建 js 脚本
在项目 /Assets/Plugins/ 目录下创建名为 Save 的 txt 文件,写入如下内容,更改后缀名为 .jslib:
mergeInto(LibraryManager.library, {
// 刷新数据到 IndexedDB
SyncDB: function () {
FS.syncfs(false, function (err) {
if (err) console.log("syncfs error: " + err);
});
}
});
2.2 添加 js 引用
- 在需要使用 js 脚本的 C# 代码块中添加命名空间
System.Runtime.InteropServices;
引用。 - 在需要使用 js 脚本的 C# 代码块中加入外部函数声明。
- 在负责保存的 C# 代码后面加入外部函数调用。
示例:
// 1. 引用命名空间
#if UNITY_WEBGL && !UNITY_EDITOR
using System.Runtime.InteropServices;
#endif
public class TxtHelper
{
// 2. 加入外部函数声明
#if UNITY_WEBGL && !UNITY_EDITOR
[DllImport("__Internal")]
private static extern void SyncDB();
#endif
public static void Save(string filePath, string content)
{
... // Your code here
// 3. 调用外部函数
#if UNITY_WEBGL && !UNITY_EDITOR
SyncDB();
#endif
}
public static string Load(string filePath)
{
...
}
}
参考链接:
- https://blog.csdn.net/mkr67n/article/details/127348730。
- https://blog.csdn.net/xiaotaiyang_gege/article/details/135862196。
3 新版解决方案(测试不可行)
对于较新的 Unity 版本(2021.3.44f1、2022.3.44f1、6000.0.11f1 及以上),有此问题的更新:
- 修复了 Application.persistentDataPath 不会自动持久化的问题,通过添加新的 JS 配置选项“autoSyncPersistentDataPath: true”来启用 Application.persistentDataPath 到 IndexedDB 的自动同步。
- 该选项位于 Builds/Index.html 文件中,取消注释并刷新正在运行的构建页面,问题将得到解决。
即,不需要任何代码操作,只需要打包完成后,将 Builds/Index.html 文件中的第 78 行取消注释即可。
当然,前提是你选择了 WebGL 平台的 Default 模板,如下图所示(其他模板自行探索)。
如果不想每次打包后都修改 Builds/Index.html 文件,也可以直接修改模板中的 Index.html ,一劳永逸。其位置在 S:\Unity Editor\6000.0.26f1c1\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\WebGLTemplates\Default 目录中。
参考链接:
- https://issuetracker.unity3d.com/issues/webgl-streamwriter-not-triggering-syncfs-when-writing-a-file-to-slash-idbfs。
- https://gamedev.stackexchange.com/questions/184369/file-saved-to-indexeddb-lost-unless-we-change-scenes。
4 实际问题
在 Unity 6000.0.26f1c1 版本中,按照步骤将上述第 78 行代码注释后,打包运行时出现如下报错:
报错信息:
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading ‘length’)
at Object.hashName (WebGL.framework.js:9:66347)
at Object.lookupNode (WebGL.framework.js:9:66977)
at Object.rmdir (WebGL.framework.js:9:54898)
at Object.rmdir (WebGL.framework.js:9:2685)
at Object.rmdir (WebGL.framework.js:9:75286)
at ___syscall_rmdir (WebGL.framework.js:9:177933)
at WebGL.wasm:0x14b27f
at WebGL.wasm:0x2610db6
at WebGL.wasm:0x26167f1
at WebGL.wasm:0x30ac93e
at WebGL.wasm:0x30ad59b
at WebGL.wasm:0x26101ae
at WebGL.wasm:0x29c020e
at WebGL.wasm:0x29bca03
at WebGL.wasm:0x29c119d
at WebGL.wasm:0x29c11b3
at WebGL.wasm:0x29b9849
at WebGL.wasm:0x29b6b88
at WebGL.wasm:0x327a445
at WebGL.framework.js:9:142371
at HandleError (WebGL.framework.js:9:142414)
at WebGL.framework.js:9:144075
解决方法是:将 config.autoSyncPersistentDataPath 设置为 false 或将该行注释掉。问题跟踪来源:https://issuetracker.unity3d.com/issues/webgl-typeerror-cannot-read-properties-of-undefined-reading-length-error-is-thrown-when-starting-the-player-when-config-dot-autosyncpersistentdatapath-is-set-to-true。
也就是说,新版解决方案在 Unity 6000.0.26f1c1 版本中失效。
目前退回到使用老版解决方案,测试可行。
WebGL 可真是太好玩辣!