LuaDB - Kingdom Come Deliverance II Lua Persistence Module
This module provides SQLite-based Lua data persistence for Kingdom Come: Deliverance II mod developers, supporting two storage modes:
-
Global : Data persists across all game saves (independent of the game save).
-
Local : Bound to the game save, data is associated with a specific game save file:
- Automatically saved when the game is saved.
- Automatically loaded when the game loads that save.
- Install Ultimate ASI Loader
- Place the
.asifile of this mod and ASI loader in the game root directory (whereKingdomCome.exeresides)
Use DB.Create to create a database object, then use the methods of that object to store and retrieve data.
DB will automatically convert key, value into JSON strings for storage, and automatically parse JSON strings back into lua objects when reading.
You can now store any Lua object encodable by json.lua! Including tables, strings, numbers, booleans, etc.
Strings in objects are no longer limited by character sets.
local myDB = DB.Create("MyAwesomeMod") -- Use your Mod name or a unique enough string that won't conflict as the namespace
myDB.Set("player_health", 85.6)
myDB:Set("has_dragon_sword", true) -- myDB allows both .call and :call syntax
-- Test storage/retrieval of complex large objects
local test = {
a = 1,
b = "nihao",
c = {
d = 2,
e = "shijie",
f = {
g = 3,
h = "非ASCII字符"
}
},
d = string.rep("a", 1000)
}
myDB.Set("test", test)
-- Global APIs (Cross-save)
myDB.SetG("settings", {volume = 0.8, fullscreen = true})
local settings = myDB.GetG("settings") -- return table {volume = 0.8, fullscreen = true}YourMod = YourMod or (function()
-- Make LuaDB an enhancement for mods, allowing users to opt for LuaDB to achieve persistence.
local db = LuaDB and DB and select(2, pcall(DB.Create,"YourMod"))
return {
version = "__VERSION__",
localData = db and db.L or {},
globalData = db and db.G or {}
}
end)()
function YourMod:Init()
local settingA = YourMod.localData.settingA
local settingB = YourMod.globalData.settingB
-- do something with settings
end
function YourMod:Save()
YourMod.localData.settingA = "valueA"
YourMod.globalData.settingB = { a = 1, b = 2 }
-- save settings
end
function YourMod:DoSomething()
local settingA = YourMod.localData.settingA
local settingB = YourMod.globalData.settingB
-- do something with settings
-- update settings if something changed
YourMod.localData.settingA = settingA
YourMod.globalData.settingB = settingB
end
YourMod:Init()DB.Get(key)- Get local key valueDB.Set(key, value)- Set local key valueDB.Del(key)- Delete local key valueDB.Exi(key)- Check if local key existsDB.All()- Get all local key valuesDB.GetG(key)- Get global key valueDB.SetG(key, value)- Set global key valueDB.DelG(key)- Delete global key valueDB.ExiG(key)- Check if global key existsDB.AllG()- Get all global key valuesDB.Dump()- Print all data (Note: $1~9 in strings will be treated as color characters)DB.Create("Your MOD")- Create a namespace instance
All methods support both . Call and : Call syntax, which can be selected according to personal preferences.
DB("Your MOD")- Equivalent toDB.Create("Your MOD")DB.key/DB["key"]- Access local key value (invalid if the method with the same name exists)DB.L.key/DB.L["key"]- Always access local key value, If you are not sure whether your key conflicts with an existing method nameDB.G.key/DB.G["key"]- Always access global key value, If you are not sure whether your key conflicts with an existing method name
- Namespace names cannot contain colons, "namespace:" will be used as a key prefix in the database to isolate data from different mods.
- When the key name is the same as an existing method, direct access will call the method instead of the key value, use. L or. G instead.
- All values will be automatically JSON encoded/decoded (the game has built-in json.lua V0.1.1).
- The JSON string size of a single object should not exceed 1 billion bytes (approximately 953MB), otherwise Sqlite will report an error "string or blob too big," making it impossible to store.
- When using
Dump(), $0~9 in strings will be parsed as color codes by the console. The in-game console cannot display non-ASCII characters, and DEBUG log data will be truncated to prevent lag.
-- Store data (automatically bound to current save)
LuaDB.Set(key, value)
-- Retrieve data
local value = LuaDB.Get(key)
-- Delete data
LuaDB.Del(key)
-- Check key existence
local exists = LuaDB.Exi(key)-- Store global data
LuaDB.SetG(key, value)
-- Retrieve global data
local value = LuaDB.GetG(key)
-- Delete global data
LuaDB.DelG(key)
-- Check global key existence
local exists = LuaDB.ExiG(key)-- View all stored data in console
LuaDB.Dump()- Key : must be a string
- Value : can be a boolean, number, or string
| Type | Storage Format | Notes |
|---|---|---|
| Boolean | 0/1 | 0 represents false |
| Number | Single-precision float | |
| String | Latin1 encoding | After testing, it can save a string of 10MB |
-- Save-associated data example
LuaDB.Set("player_health", 85.6)
LuaDB.Set("has_dragon_sword", true)
-- Global data example
LuaDB.SetG("global_kill_count", 42)
LuaDB.SetG("ending_unlocked", "bad_ending")
-- View data in console
LuaDB.Dump()cmake -B build -G "Visual Studio 17 2022" -DSQLITECPP_RUN_CPPLINT=OFFcmake --build build --config Release
- Uses SQLite3 database named
kcd2db.dbin game root - Operation logs stored in
kcd2db.login game root - If launched with
-console, debug output will also appear in a separate console window
This mod heavily utilizes reverse-engineered game internals and may be affected by game updates. If experiencing crashes
after game updates, try removing the mod file (or rename .asi extension to disable).
Want to know how I found the offset? Check out this How to find the address of gEnv
LuaDB - 天国拯救2 Lua 数据持久化模块
本模块为《天国拯救2》Mod开发者提供基于Sqlite 的 Lua 数据存储解决方案,支持两种存储模式:
-
全局:数据在所有游戏存档中持久存在(独立于游戏存档)。
-
本地:绑定到游戏存档,数据与特定的游戏存档文件关联:
- 游戏保存时自动保存。
- 游戏加载该存档时自动加载。
- 安装 终极 ASI 加载器
- 将本Mod的
.asi文件与ASI加载器共同放置于游戏根目录(KingdomCome.exe所在目录)
使用 DB.Create 创建一个数据库对象,然后使用该对象的方法进行数据存储和读取。
DB将自动把key,value转换为json字符串进行存储,读取时自动解析json字符串还原为lua对象。
你现在可以存储任何可以通过json.lua编码的Lua对象了!,包括table,string,number,boolean等等,对象中的字符串也不再有字符集限制
local myDB = DB.Create("MyAwesomeMod") -- 使用你的 Mod 名或者一个足够独特不会冲突的字符串作为命名空间
myDB.Set("player_health", 85.6)
myDB:Set("has_dragon_sword", true) -- myDB 允许.调用 和 :调用 语法
-- 测试复杂大对象的存储/读取
local test = {
a = 1,
b = "nihao",
c = {
d = 2,
e = "shijie",
f = {
g = 3,
h = "测试字符"
}
},
d = string.rep("a", 1000)
}
myDB.Set("test", test)
-- 全局API(跨存档)
myDB.SetG("settings", {volume = 0.8, fullscreen = true})
local settings = myDB.GetG("settings") -- return table {volume = 0.8, fullscreen = true}YourMod = YourMod or (function()
-- 使 LuaDB 成为MOD的增强功能,使用户可以选择 LuaDB 实现持久性。
local db = LuaDB and DB and select(2, pcall(DB.Create,"YourMod"))
return {
version = "__VERSION__",
localData = db and db.L or {},
globalData = db and db.G or {}
}
end)()
function YourMod:Init()
local settingA = YourMod.localData.settingA
local settingB = YourMod.globalData.settingB
-- do something with settings
end
function YourMod:Save()
YourMod.localData.settingA = "valueA"
YourMod.globalData.settingB = { a = 1, b = 2 }
-- save settings
end
function YourMod:DoSomething()
local settingA = YourMod.localData.settingA
local settingB = YourMod.globalData.settingB
-- do something with settings
-- update settings if something changed
YourMod.localData.settingA = settingA
YourMod.globalData.settingB = settingB
end
YourMod:Init()DB.Get(key)- 获取本地键值DB.Set(key, value)- 设置本地键值DB.Del(key)- 删除本地键值DB.Exi(key)- 检查本地键是否存在DB.All()- 获取所有本地键值DB.GetG(key)- 获取全局键值DB.SetG(key, value)- 设置全局键值DB.DelG(key)- 删除全局键值DB.ExiG(key)- 检查全局键是否存在DB.AllG()- 获取所有全局键值DB.Dump()- 打印所有数据(注意: 字符串中的$1~9会被当作颜色字符)DB.Create("Your MOD")- 创建命名空间实例
所有的方法都同时支持 . 调用和 : 调用语法,可以根据个人喜好选择使用
DB("你的MOD")- 等同于DB.Create("你的MOD")DB.key/DB["key"]- 访问本地键值(若存在同名方法则无效)DB.L.key/DB.L["key"]- 始终访问本地键值,适用于不确定键名是否与现有方法名冲突时DB.G.key/DB.G["key"]- 始终访问全局键值,适用于不确定键名是否与现有方法名冲突时
- 命名空间名称不能包含冒号,“namespace:”将作为数据库中的键前缀,用于隔离不同模组的数据。
- 当键名与现有方法同名时,直接访问将调用方法而不是键值,请使用.L或.G代替。
- 所有值将自动进行JSON编码/解码(游戏内置了json.lua V0.1.1)。
- 单个对象的JSON字符串大小不应超过10亿字节(约953MB),否则Sqlite会报错“字符串或二进制数据过大”,导致无法存储。
- 使用
Dump()时,字符串中的$0~9将被控制台解析为颜色代码。游戏内控制台无法显示非ASCII字符,DEBUG日志数据将被截断以防止卡顿。
-- 存储数据(自动关联当前存档)
LuaDB.Set(key, value)
-- 获取数据
local value = LuaDB.Get(key)
-- 删除数据
LuaDB.Del(key)
-- 检查键是否存在
local exists = LuaDB.Exi(key)-- 存储全局数据
LuaDB.SetG(key, value)
-- 获取全局数据
local value = LuaDB.GetG(key)
-- 删除全局数据
LuaDB.DelG(key)
-- 检查全局键是否存在
local exists = LuaDB.ExiG(key)-- 控制台查看所有存储数据
LuaDB.Dump()- Key : 必须是字符串
- Value : 可以是布尔值、数字或字符串
| 类型 | 存储格式 | 说明 |
|---|---|---|
| 布尔值 | 0/1 | 0表示false |
| 数字 | 单精度浮点 | |
| 字符串 | Latin1 编码 | 经过测试,它可以保存一个10MB字符串 |
-- 存档关联数据示例
LuaDB.Set("player_health", 85.6)
LuaDB.Set("has_dragon_sword", true)
-- 全局数据示例
LuaDB.SetG("global_kill_count", 42)
LuaDB.SetG("ending_unlocked", "bad_ending")
-- 控制台查看数据
LuaDB.Dump()cmake -B build -G "Visual Studio 17 2022" -DSQLITECPP_RUN_CPPLINT=OFFcmake --build build --config Release
- 使用位于游戏根目录下名为
kcd2db.db的 SQLite3 数据库 - 操作日志存储在游戏根目录下的
kcd2db.log文件中 - 如果使用
-console参数启动,调试输出也会显示在单独的控制台窗口中
由于本MOD大量使用反汇编的游戏内部细节,可能会受到游戏更新的影响,如遇到更新后游戏崩溃问题,请尝试删除本MOD文件(或将后缀名
.asi改为其他后缀名)。