13 KiB
本地存储管理
**本文档引用文件** - [config.json](file://assets/resources/config.json) - [Oops.ts](file://extensions/oops-plugin-framework/assets/core/Oops.ts) - [Root.ts](file://extensions/oops-plugin-framework/assets/core/Root.ts) - [StorageManager.ts](file://extensions/oops-plugin-framework/assets/core/common/storage/StorageManager.ts) - [Initialize.ts](file://assets/script/game/initialize/Initialize.ts) - [SingletonModuleComp.ts](file://assets/script/game/common/SingletonModuleComp.ts) - [WxCloudApi.ts](file://assets/script/game/wx_clound_client_api/WxCloudApi.ts) - [Main.ts](file://assets/script/Main.ts)目录
简介
本文档深入解析基于 Cocos 引擎的 heros 项目中的本地存储机制。重点围绕 config.json 文件中的核心配置项,包括 version、package、localDataKey、localDataIv、httpServer、httpTimeout 和 frameRate 的作用、加载时机及使用场景。文档详细阐述了基于 crypto-es 库的本地数据加密存储方案的设计思路,以及如何通过 localDataKey 和 localDataIv 实现数据保护。同时,分析了本地缓存与云端数据的优先级策略,以及在离线模式下的容错处理机制。
Section sources
项目结构
项目采用模块化设计,主要结构如下:
assets/resources/config.json:核心配置文件,包含游戏版本、包名、加密密钥、网络地址等全局配置。assets/script/:存放所有 TypeScript 脚本,其中game/initialize/是游戏初始化逻辑的核心。extensions/oops-plugin-framework/:项目所依赖的Oops框架,提供了本地存储、网络、ECS 等核心功能的封装。assets/resources/language/json/:多语言资源文件。build-templates/wechatgame/cloud_functions/:微信云函数相关配置。
Section sources
核心配置项解析
config.json 文件位于 assets/resources/ 目录下,是整个游戏的配置中心。其 config 对象下的各个字段具有明确的用途。
{
"config": {
"version": "1.0.0",
"package": "com.oops.game",
"localDataKey": "oops",
"localDataIv": "framework",
"httpServer": "http://192.168.0.150/main/",
"httpTimeout": 10000,
"frameRate": 60
}
}
version: 标识当前游戏的版本号。此信息可用于版本控制、热更新判断以及与云端数据进行兼容性校验。package: 定义游戏的包标识符,遵循反向域名命名规则。在发布到应用商店或进行平台集成时,此标识符必须全局唯一。localDataKey: 本地数据加密所使用的密钥(Key)。该密钥与localDataIv一起,作为crypto-es库进行 AES 加密的参数,确保存储在用户设备上的数据安全。localDataIv: 本地数据加密所使用的初始化向量(Initialization Vector)。它增加了加密的随机性,即使相同的数据在不同时间加密,其密文也会不同,从而提高安全性。httpServer: 指定 HTTP 请求的服务器基础地址。所有通过oops.http模块发起的请求,其 URL 都会以此地址为前缀。httpTimeout: 设置 HTTP 请求的超时时间(单位:毫秒)。当网络请求超过此时间仍未收到响应时,将被视为失败,防止应用因网络问题而长时间无响应。frameRate: 定义游戏的帧率,即每秒渲染的帧数。较高的帧率(如 60)能提供更流畅的视觉体验,但对设备性能要求更高;较低的帧率(如 30)则更省电,适合性能较弱的设备。
Section sources
本地数据加密机制
项目的本地数据加密方案基于 crypto-es 库实现,由 Oops 框架的 StorageManager 类进行封装。
设计思路
- 依赖库:项目通过
package.json明确依赖了crypto-es库,这是一个轻量级的 JavaScript 加密库,支持 AES 等多种加密算法。 - 框架集成:
Oops框架在Root.ts的onLoad方法中,通过oops.config.game读取config.json中的localDataKey和localDataIv,并调用oops.storage.init()方法进行初始化。 - 条件加密:根据
Oops框架的设计,在开发调试模式(DEBUG为true)下,数据以明文形式存储,便于开发者调试。而在发布模式下,数据会自动使用 AES 算法进行加密后存储。
加密实现
StorageManager 类在初始化后,会拦截所有对 sys.localStorage 的读写操作。当调用 set 方法存储数据时,它会:
- 将 JavaScript 对象序列化为 JSON 字符串。
- 使用
localDataKey作为密钥,localDataIv作为初始化向量,通过crypto-es的 AES 算法对字符串进行加密。 - 将加密后的密文(通常为 Base64 编码)存储到
localStorage中。
当调用 get 方法读取数据时,流程则相反:
- 从
localStorage中读取密文。 - 使用相同的密钥和初始化向量进行解密。
- 将解密后的明文 JSON 字符串反序列化为 JavaScript 对象并返回。
flowchart TD
A[调用 oops.storage.set(key, value)] --> B[序列化为JSON]
B --> C[使用localDataKey和localDataIv进行AES加密]
C --> D[Base64编码]
D --> E[存入localStorage]
F[调用 oops.storage.get(key)] --> G[从localStorage读取]
G --> H[Base64解码]
H --> I[使用localDataKey和localDataIv进行AES解密]
I --> J[反序列化为对象]
J --> K[返回数据]
Diagram sources
Section sources
配置加载与初始化流程
游戏的配置加载和初始化是一个有序的过程,由 Main.ts 和 Root.ts 共同驱动。
流程图
sequenceDiagram
participant Main as Main.ts
participant Root as Root.ts
participant Config as config.json
participant Storage as StorageManager
participant Initialize as Initialize.ts
Main->>Root : director.loadScene("main")
Root->>Root : onLoad()
Root->>Root : 加载config.json资源
Root->>Root : 解析JsonAsset
loop 初始化框架模块
Root->>Root : oops.config.game = new GameConfig(config)
Root->>Root : oops.http.server = oops.config.game.httpServer
Root->>Root : oops.http.timeout = oops.config.game.httpTimeout
Root->>Storage : oops.storage.init(localDataKey, localDataIv)
Root->>Root : game.frameRate = oops.config.game.frameRate
end
Root->>Root : enabled = true
Root->>Root : init() 和 run()
Root->>Initialize : smc.initialize = ecs.getEntity<Initialize>(Initialize)
Initialize->>Initialize : protected init()
Initialize->>Initialize : loadCustom -> loadLanguage
Initialize->>Storage : oops.storage.get("language")
alt 语言存在
Initialize->>Initialize : 使用存储的语言
else 语言不存在
Initialize->>Initialize : 默认设为"zh"
Initialize->>Storage : oops.storage.set("language", "zh")
end
Initialize->>Initialize : 继续加载公共资源和游戏数据
Diagram sources
Section sources
本地缓存与云端数据策略
项目采用了一套混合数据存储策略,结合了本地缓存和云端同步,以平衡性能、用户体验和数据安全。
优先级策略
- 本地优先(读取):游戏启动时,会优先从本地存储中读取用户偏好设置,如语言选择 (
oops.storage.get("language"))。这确保了即使在离线状态下,用户也能获得个性化的体验。 - 云端优先(写入与同步):对于核心的游戏进度数据(如金币、英雄信息、出战阵容),项目优先使用云端存储。在微信客户端中,通过
WxCloudApi与微信云函数交互,实现数据的持久化和跨设备同步。
数据同步流程
- 初始化同步:在
Initialize.ts的loadGameDataUnified方法中,程序首先判断是否为微信客户端。如果是,则调用loadFromCloud(),通过WxCloudApi.login()获取云端数据,并用overrideLocalDataWithRemote()方法覆盖本地的smc(SingletonModuleComp) 单例数据。 - 运行时同步:在游戏运行过程中,当用户数据发生变化(如获得金币、升级英雄),会立即调用
WxCloudApi.save()将最新数据保存到云端,确保数据的实时性和安全性。
graph TD
A[游戏启动] --> B{是否为微信客户端?}
B -- 是 --> C[调用 WxCloudApi.login()]
C --> D{登录成功?}
D -- 是 --> E[获取云端数据]
E --> F[覆盖本地 smc 数据]
D -- 否 --> G[使用本地调试数据]
B -- 否 --> G
F --> H[进入游戏]
G --> H
Diagram sources
Section sources
性能与网络配置
除了数据存储,config.json 中的配置也直接影响游戏的性能和网络行为。
frameRate对性能的影响:frameRate设置为 60,意味着游戏引擎会尽量每秒更新和渲染 60 帧。这能提供非常流畅的动画效果,但会持续占用较高的 CPU 和 GPU 资源,可能导致设备发热和耗电加快。开发者需要在流畅度和性能消耗之间做出权衡,对于性能要求不高的场景,可以考虑降低此值。httpServer与httpTimeout的用途:httpServer定义了所有 HTTP 请求的根地址,实现了请求地址的集中管理,便于在开发、测试和生产环境之间切换。httpTimeout是一个关键的容错配置,它防止了因网络延迟或服务器无响应而导致的 UI 卡死。当请求超时后,应用可以捕获错误并给出友好的提示,提升用户体验。
Section sources
故障处理机制
项目在数据处理和网络通信方面设计了多层次的容错机制。
- 本地存储容错:在
Initialize.ts中读取语言设置时,代码明确检查了oops.storage.get("language")的返回值是否为null或空字符串。如果不存在,则使用默认值"zh"并将其写回存储。这是一种典型的“降级”策略,确保了关键配置的可用性。 - 云端数据容错:
loadFromCloud和loadFromLocalDebug方法都使用了try-catch语句包裹。当云端登录或数据获取失败时,程序会捕获异常,记录错误日志,并尝试使用本地调试数据作为后备方案,避免游戏因数据加载失败而无法启动。 - 网络请求容错:
httpTimeout配置本身就是一种网络容错。此外,WxCloudApi的调用通常会检查返回的code字段(如200表示成功),并根据不同的错误码(如-3参数错误,-6资源不足)执行相应的处理逻辑,例如提示用户或回滚操作。
Section sources
结论
该项目的本地存储机制设计完善,通过 config.json 实现了配置的集中化管理。利用 Oops 框架和 crypto-es 库,实现了安全的本地数据加密。项目采用了“本地缓存 + 云端同步”的混合策略,既保证了离线可用性和启动速度,又确保了核心数据的安全与跨设备同步。整个初始化流程清晰,配置项的加载和应用时机合理,并且在各个环节都考虑了容错处理,构建了一个健壮、可靠的游戏数据管理方案。