GameStateDB.lua
quick-cocos2d-x3.3版本中,framework/cc/utils/GameState.lua已经提供了GameStateDB.lua中的方法
--本地存储的加密文件
local m = class( "GameStateDB" )
m.ERROR_INVALID_FILE_CONTENTS = -1
m.ERROR_HASH_MISS_MATCH = -2
m.ERROR_STATE_FILE_NOT_FOUND = -3
local crypto = require(cc.PACKAGE_NAME .. ".crypto")
local json = require(cc.PACKAGE_NAME .. ".json")
function m:ctor()
self.encodeSign = "=GS="
self._fileName = "GameStateDB.txt"
self._cbHandle = nil
self.secretKey = nil
end
function m:init(_cbHandle, fileName, secretKey_)
if type(_cbHandle) ~= "function" then
print("m:init() - invalid self._cbHandle")
return false
end
self._cbHandle = _cbHandle
if type(fileName) == "string" then
self._fileName = fileName
end
if type(secretKey_) == "string" then
self.secretKey = secretKey_
end
self._cbHandle({
eventName = "init",
filename = self:getGameStateDBPath(),
isEncrypt = type(self.secretKey) == "string"
})
return true
end
--返回保存是否成功结果及保存存档字符串
function m:save(newValues)
local function encode_(values)
local strValues = json.encode(values)
local md5 = crypto.md5(strValues..self.secretKey) --md5码,用于校验数据的完整性,安全性
local contents = json.encode({md5 = md5, strValues = strValues})
return crypto.encodeBase64(self.encodeSign..contents) --数据加密
end
local values = self._cbHandle({
eventName = "save",
values = newValues,
isEncrypt = type(self.secretKey) == "string"
})
if type(values) ~= "table" then
print("m:save() - listener return invalid data")
return false
end
local filename = self:getGameStateDBPath()
local ret = false
local saveStr = ""
if self.secretKey then
saveStr = encode_(values)
ret = io.writefile(filename, saveStr)
else
saveStr = json.encode(values)
if type(saveStr) == "string" then
ret = io.writefile(filename, saveStr)
end
end
printf("m:save() - update file \"%s\"", filename)
return ret,saveStr
end
function m:load(_strData)
local function isEncodedContents_(contents)
return string.sub(contents, 1, string.len(self.encodeSign)) == self.encodeSign
end
local function decode_(fileContents)
local contents = string.sub(fileContents, string.len(self.encodeSign) + 1)
local j = json.decode(contents)
if type(j) ~= "table" then
print("m:decode_() - invalid contents")
return {errorCode = m.ERROR_INVALID_FILE_CONTENTS}
end
local hash,strValues = j.md5, j.strValues
local testHash = crypto.md5(strValues..self.secretKey)
if testHash ~= hash then
print("m:decode_() - hash miss match")
return {errorCode = m.ERROR_HASH_MISS_MATCH}
end
local values = json.decode(strValues)
if type(values) ~= "table" then
print("m:decode_() - invalid state data")
return {errorCode = m.ERROR_INVALID_FILE_CONTENTS}
end
return {values = values}
end
local contents = nil
if _strData == nil then
local filename = self:getGameStateDBPath()
if not io.exists(filename) then
printf("m:load() - file \"%s\" not found", filename)
return self._cbHandle({eventName = "load", errorCode = m.ERROR_STATE_FILE_NOT_FOUND})
end
contents = io.readfile(filename)
printf("m:load() - get values from \"%s\"", filename)
else
printf("m:load() with function!!!")
contents = _strData
end
--解密
contents = crypto.decodeBase64(contents)
local values
local isEncrypt = false
if self.secretKey and isEncodedContents_(contents) then
local d = decode_(contents)
if d.errorCode then
return self._cbHandle({eventName = "load", errorCode = d.errorCode})
end
values = d.values
isEncrypt = true
else
values = json.decode(contents)
if type(values) ~= "table" then
print("m:load() - invalid data")
return self._cbHandle({eventName = "load", errorCode = m.ERROR_INVALID_FILE_CONTENTS})
end
end
return self._cbHandle({
eventName = "load",
values = values,
isEncrypt = isEncrypt,
time = os.time()
})
end
function m:getGameStateDBPath()
return string.gsub(device.writablePath, "[\\\\/]+$", "") .. "/" .. self._fileName
end
return m
LocalDBMgr.lua
--[[
LocalDBMgr.lua
存储本地数据
数据编码格式:
local data = { a=1,b=2,c=3}
local secretKey = "123"
1.先将data转换成json串s, 然后s 和 secretKey 连接成字符串 c
2.再将c计算md5得到值hash
3.再次以格式 { h = hash, s = s } 编码json 形成 contents
4.将contents进行base64加密
]]
local LocalDBMgr = class( "LocalDBMgr" )
local GameStateDB = require("app.core.GameStateDB").new() --换成GameStateDB的真实路径
--数据文件秘钥(不变化)
local DATA_SER_KEY = "2k7x2023r49mvpus2t616e13c7965b1"
--构造函数
function LocalDBMgr:ctor()
self:init()
local function GameStateCallBackHandle(params)
return params
end
GameStateDB:init( GameStateCallBackHandle, "LocalDBMgr", DATA_SER_KEY )
local path = GameStateDB:getGameStateDBPath()
if not io.exists( path ) then
print("[[ 创建LocalDBMgr ]]")
GameStateDB:save( self.db )
else
self:load()
end
end
--初始化config表
function LocalDBMgr:init()
self.db = {
clientVersion = "1.0.0", -- 客户端版本号
accessToken = "",--微信token
openID = "",--openid
bgState = 1, --背景音乐是否打开
bgValume = 100, --背景音乐大小
soundState = 1, --音效是否打开
soundValume = 100, --音效大小
actImgList = {},--活动图片列表
}
end
--数据存储
function LocalDBMgr:save(_key , _value)
if not _key or not _value then
assert( nil, "LocalDBMgr save key or value is nil! ")
return
end
self.db[ _key .. '' ] = _value
print( "LocalDBMgr save:",_key,_value )
GameStateDB:save( self.db )
end
--数据读取
function LocalDBMgr:read(_key)
if not _key then
assert( nil, "LocalDBMgr read key is nil!" )
return
end
return self.db[ _key .. '' ]
end
--数据加载
function LocalDBMgr:load()
self:init()--只维护self.db中的数据
local data = GameStateDB:load().values.values
for k,v in pairs(self.db) do
if data[k] then
self.db[k] = data[k] --本地数据重置到缓存数据,
end
end
GameStateDB:save( self.db )
end
return LocalDBMgr