DataBaker

DataBaker 是一个专业的Unity配置数据管理工具,能够将Excel表格转换为CSV文件,并自动生成高效的二进制数据和对应的C#类。它采用注册表模式,无需反射机制,完美兼容WebGL、iOS等所有Unity平台。

核心优势

  • 高性能: 使用GZip压缩的二进制格式,数据加载速度比纯CSV快5-10倍
  • 低内存占用: 字符串池技术减少内存占用40-60%
  • 零反射: 采用注册表模式,兼容AOT编译环境(WebGL/iOS/IL2CPP)
  • 自动化: 一键生成C#类和二进制文件,集成Addressable资源管理
  • 类型安全: 编译时类型检查,避免运行时错误
  • 易维护: 添加新表只需一行注册代码

核心特性

1. Excel到CSV转换

  • 使用Excel宏快速导出CSV文件
  • 支持复杂的Excel格式,包括公式、合并单元格等
  • 自动处理数据类型转换

2. CSV到二进制转换

  • GZip压缩算法,大幅减少文件体积
  • 自定义二进制格式,支持版本控制
  • 字符串池优化,减少重复字符串的存储

3. 自动代码生成

  • 自动生成数据类,包含所有字段
  • 自动生成表格管理类,继承DataTableBase
  • 支持自定义命名空间

4. 运行时管理

  • 支持异步/同步加载
  • 支持按需加载单个表或批量加载
  • 提供查询、筛选等数据操作API
  • 自动管理Addressable资源

5. 支持的数据类型

类型 说明 数组支持
int 整数 ✅ int[]
float 单精度浮点 ✅ float[]
double 双精度浮点 ✅ double[]
bool 布尔值 ✅ bool[]
string 字符串 ✅ string[]

系统要求

  • Unity 2020.3 或更高版本
  • Addressables Asset System 1.21.19 或更高版本
  • Microsoft Excel (用于CSV导出)

安装说明

方式一: Unity Package Manager

  1. 打开Unity项目
  2. 选择 Window > Package Manager
  3. 点击左上角 +
  4. 选择 Add package by name
  5. 输入包名: com.databaker.core
  6. 点击 Add

方式二: 手动导入

  1. 下载DataBaker.unitypackage
  2. 在Unity中双击导入
  3. 或选择 Assets > Import Package > Custom Package

方式三: 从源码导入

  1. Assets/DataBaker 文件夹复制到你的项目 Assets 目录下
  2. Unity会自动编译脚本

安装Addressables (如果未安装)

  1. 打开 Window > Package Manager
  2. 选择 Unity Registry
  3. 搜索 Addressables
  4. 点击 Install

快速开始

第一步: 创建Excel表格

创建一个Excel文件,包含以下格式的数据:

行号 内容 说明
1 字段名称 如: Id,Name,Count
2 字段类型 如: int,string,int[]
3 默认值 可选的默认值
4+ 数据行 实际配置数据

示例表格内容:

1
2
3
4
5
Id,Name,Level,Attack,Skills
int,string,int,int,string[]
0,"新手",1,10,"[]"
1,"战士",10,50,"[冲锋,斩击]"
2,"法师",15,80,"[火球,冰霜,闪电]"

第二步: 编辑数据并自动导出CSV

DataBaker 提供了集成了宏的Excel模板,可以自动将数据导出为CSV文件:

  1. 打开 Assets/DataBaker/Tables/conf~/excel 目录下的Excel模板文档(.xlsm格式)
  2. 根据第一步的格式要求编辑数据
  3. 保存Excel文件时,宏会自动将当前工作表导出为CSV文件到 Assets/DataBaker/Tables 目录
  4. CSV文件名与工作表名称一致

注意事项:

  • Excel文件必须启用宏功能(启用内容)
  • 只保存当前活动的工作表为CSV
  • 如果有多个工作表,每个工作表会生成对应的CSV文件
  • CSV文件会覆盖同名文件,请确保工作表名称正确

第三步: 生成代码和二进制文件

  1. 打开DataBaker编辑器: Tools > DataBaker > CSV Generator
  2. 配置路径:
    • CSV Folder Path: 放置CSV文件的目录
    • C# Class Output Path: 生成的C#类输出目录
    • Binary File Path: 生成的二进制文件输出目录
  3. 选择要处理的CSV文件
  4. 点击 Generate All 按钮
  5. 等待生成完成

第四步: 注册表格

打开 CSVTableRegistry.cs,在 RegisterTables() 方法中添加:

1
2
3
4
5
6
7
8
9
10
11
12
13
public void RegisterTables()
{
_tables.Clear();
_tableDict.Clear();

Debug.Log("=== Starting to register configuration tables ===");

// 手动注册所有配置表
// 添加新表后在这里添加一行注册代码: RegisterTable(YourTable.Instance);
RegisterTable(DataBaker.Generated.TestDataTable.Instance);

Debug.Log($"=== Configuration tables registration completed, total {_tables.Count} tables ===");
}

第五步: 加载配置数据

方式A: 使用GameConfigLoader (推荐)

GameConfigLoader 脚本添加到启动场景中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
using DataBaker.Runtime;

public class GameManager : MonoBehaviour
{
void Start()
{
GameConfigLoader.OnConfigsLoaded += OnConfigsLoaded;
}

void OnDestroy()
{
GameConfigLoader.OnConfigsLoaded -= OnConfigsLoaded;
}

void OnConfigsLoaded(bool success)
{
if (success)
{
Debug.Log("配置加载成功,开始游戏逻辑");
// 开始你的游戏逻辑
}
else
{
Debug.LogError("配置加载失败");
}
}
}

方式B: 手动加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using DataBaker.Runtime;
using System.Threading.Tasks;

public class ConfigLoader : MonoBehaviour
{
async void Start()
{
// 初始化管理器
CSVTableManager.Instance.Initialize();

// 加载所有配置表
bool success = await CSVTableManager.Instance.LoadAllTablesAsync();

if (success)
{
Debug.Log("配置加载成功");
// 开始游戏逻辑
}
}
}

第六步: 使用配置数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 通过ID获取单个数据
var itemData = CSVTableManager.Instance.GetData<ItemData>("Item", 1001);
if (itemData != null)
{
Debug.Log($"物品名称: {itemData.Name}");
Debug.Log($"价格: {itemData.Price}");
}

// 获取所有数据
var allItems = CSVTableManager.Instance.GetAllData<ItemData>("Item");
foreach (var item in allItems)
{
Debug.Log($"ID: {item.Id}, Name: {item.Name}");
}

// 获取表对象
var itemTable = CSVTableManager.Instance.GetTable<ItemDataTable>("Item");
if (itemTable != null)
{
var item = itemTable.GetInstance(1001);
var allData = itemTable.GetAllData();
var expensiveItems = itemTable.FindData(x => x.Price > 1000);
}

CSV格式规范

CSV文件结构

1
2
3
4
5
6
7
8
9
10
11
12
// 第1行: 字段名称 (必须以Id开头)
Id,Name,Level,Attack,Skills

// 第2行: 字段类型
int,string,int,int,string[]

// 第3行: 默认值 (可选)
0,"",0,0,"[]"

// 第4行及以后: 数据行
1,"战士",10,50,"[冲锋,斩击]"
2,"法师",15,80,"[火球,冰霜,闪电]"

字段类型规范

类型标识 C#类型 示例值
int / integer int 100, -50
float / single float 3.14, -0.5
double / decimal double 3.14159
bool / boolean bool true, false
string / text string “Hello World”
int[] int[] “[1,2,3]”
float[] float[] “[1.5,2.5,3.5]”
string[] string[] “[a,b,c]”

重要规则

  1. 必须以Id字段开头: 第一列必须是Id,类型为int
  2. 字段名称和类型必须匹配: 第1行的字段数必须等于第2行的类型数
  3. 数组格式: 数组值必须使用方括号 [] 包裹,元素用逗号分隔
  4. 字符串包含逗号: 如果字符串中包含逗号,请用双引号包裹
  5. 空值: 使用空字符串 "" 表示空值

示例CSV文件

1
2
3
4
5
6
7
Id,Name,Description,Level,Exp,Attributes,IsActive,Tags
int,string,string,int,int,int[],bool,string[]
0,"","",0,0,"[]",false,"[]"
1,"生命药水","恢复100点生命值",1,0,"[100,0,0]",true,"[消耗,药品]"
2,"魔法药水","恢复50点魔法值",1,0,"[0,50,0]",true,"[消耗,药品]"
3,"青铜剑","基础攻击力+15",5,100,"[0,0,15]",true,"[装备,武器]"
4,"铁甲","基础防御力+20",10,200,"[0,20,0]",true,"[装备,防具]"

API参考

CSVTableManager

配置表管理器,负责所有配置表的加载和管理。

主要属性

1
2
3
4
5
6
7
8
9
10
11
// 单例实例
public static CSVTableManager Instance { get; }

// 是否已初始化
public bool IsInitialized { get; }

// 已加载的表数量
public int LoadedTableCount { get; }

// 总表数量
public int TotalTableCount { get; }

主要方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 初始化管理器
public void Initialize()

// 异步加载所有配置表
public Task<bool> LoadAllTablesAsync()

// 异步加载指定表
public Task<bool> LoadTableAsync(string assetLabel)

// 通过ID获取数据
public T GetData<T>(string tableAssetLabel, int id)

// 获取表的所有数据
public List<T> GetAllData<T>(string tableAssetLabel)

// 获取表对象
public IDataTable GetTable(string assetLabel)
public TTable GetTable<TTable>(string assetLabel)

// 检查表是否已加载
public bool IsTableLoaded(string assetLabel)

// 卸载指定表
public void UnloadTable(string assetLabel)

// 卸载所有表
public void UnloadAllTables()

// 重新加载表
public Task<bool> ReloadTableAsync(string assetLabel)

// 获取已加载表信息
public string GetLoadedTableInfo()

DataTableBase

数据表基类,所有生成的表管理类都继承此类。

主要属性

1
2
3
4
5
6
7
8
9
10
11
// 是否已加载
public bool IsLoaded { get; }

// 数据数量
public int Count { get; }

// Addressable标签 (子类实现)
public abstract string AssetLabel { get; }

// 二进制资源键 (子类实现)
public abstract string BinaryAssetKey { get; }

主要方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 异步加载数据
public Task<bool> LoadAsync()

// 同步加载数据 (协程)
public IEnumerator LoadSync(Action onComplete = null)

// 通过ID获取数据
public T GetInstance(int id)

// 获取所有数据
public List<T> GetAllData()

// 根据条件查找数据
public List<T> FindData(Func<T, bool> predicate)

// 查找第一个匹配的数据
public T FindFirst(Func<T, bool> predicate)

// 检查是否包含指定ID
public bool Contains(int id)

// 卸载数据
public void Unload()

// 重新加载
public Task<bool> ReloadAsync()

CSVTableRegistry

配置表注册中心,管理所有表实例。

主要属性

1
2
3
4
5
6
7
8
// 单例实例
public static CSVTableRegistry Instance { get; }

// 总表数量
public int TotalTableCount { get; }

// 已加载表数量
public int LoadedTableCount { get; }

主要方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 注册所有表 (手动添加注册代码)
public void RegisterTables()

// 获取所有表
public List<IDataTable> GetAllTables()

// 通过标签获取表
public IDataTable GetTable(string assetLabel)

// 获取指定类型的表
public T GetTable<T>(string assetLabel)

// 通过ID获取数据
public T GetData<T>(string tableAssetLabel, int id)

// 获取表的所有数据
public List<T> GetAllData<T>(string tableAssetLabel)

// 检查表是否已加载
public bool IsTableLoaded(string assetLabel)

高级特性

自定义命名空间

  1. 打开CSV Generator窗口
  2. 勾选 Use Namespace
  3. 输入你的命名空间,例如: MyGame.Config
  4. 生成的类将使用该命名空间

按需加载

1
2
3
4
5
// 只加载需要的表
await CSVTableManager.Instance.LoadTableAsync("Item");

// 加载完成后使用
var itemData = CSVTableManager.Instance.GetData<ItemData>("Item", 1001);

卸载不用的表

1
2
3
4
5
// 卸载单个表
CSVTableManager.Instance.UnloadTable("Item");

// 卸载所有表
CSVTableManager.Instance.UnloadAllTables();

数据筛选和查询

1
2
3
4
5
6
7
8
9
10
var itemTable = CSVTableManager.Instance.GetTable<ItemDataTable>("Item");

// 查找价格大于1000的物品
var expensiveItems = itemTable.FindData(x => x.Price > 1000);

// 查找名称包含"剑"的物品
var swords = itemTable.FindData(x => x.Name.Contains("剑"));

// 查找第一个匹配条件的物品
var firstWeapon = itemTable.FindFirst(x => x.Tags.Contains("武器"));

异步/同步加载

异步加载 (推荐)

1
2
3
4
5
6
7
8
async void Start()
{
bool success = await CSVTableManager.Instance.LoadAllTablesAsync();
if (success)
{
// 使用数据
}
}

同步加载 (协程)

1
2
3
4
5
6
7
8
9
IEnumerator Start()
{
var itemTable = CSVTableManager.Instance.GetTable<ItemDataTable>("Item");
yield return itemTable.LoadSync(() =>
{
Debug.Log("加载完成");
// 使用数据
});
}

调试信息

1
2
3
4
5
6
// 打印所有表的加载状态
string info = CSVTableManager.Instance.GetLoadedTableInfo();
Debug.Log(info);

// 运行时查看GameConfigLoader的调试UI
// 点击"Print Load Status"按钮查看详细信息

常见问题

Q1: Addressable设置未找到

问题: 提示 “Addressable settings not found”

解决:

  1. 确保 Addressables 包已正确安装
  2. 打开 Window > Asset Management > Addressables > Groups
  3. 确保Addressables Asset Settings已创建

Q2: CSV文件格式错误

问题: 提示 “CSV file format error”

解决:

  • 确保CSV至少有4行(字段名、类型、默认值、数据)
  • 第一字段必须是Id
  • 字段名和类型数量必须匹配
  • 确保CSV使用UTF-8编码

Q3: 生成的代码报错

问题: 生成的C#类有编译错误

解决:

  • 检查CSV中的类型标识是否正确
  • 确保数组值使用正确的格式 [1,2,3]
  • 检查字符串是否包含未转义的引号

Q4: 数据加载失败

问题: 运行时提示数据加载失败

解决:

  • 检查Addressable Group中的资源路径是否正确
  • 确保二进制文件已生成
  • 检查Addressable Label是否与CSV文件名一致
  • 查看Console中的详细错误信息

Q5: WebGL平台数据加载问题

问题: WebGL上数据无法加载

解决:

  • 确保Addressables配置正确
  • 检查压缩设置
  • 确保Addressables服务器已启动(开发模式)

Q6: 如何更新已存在的表?

解决:

  1. 修改Excel数据
  2. 重新导出CSV
  3. 在CSV Generator中点击 Generate All
  4. Unity会自动刷新资源和脚本

Q7: 能否支持嵌套数据结构?

解决:
目前不支持嵌套类。建议:

  • 使用数组类型存储相关数据
  • 或者将复杂数据拆分为多个表
  • 使用ID建立表之间的关联

Q8: 如何支持Excel中的公式?

解决:
DataBaker不支持Excel公式,因为CSV只存储值。建议:

  1. 在Excel中使用公式计算
  2. 使用”复制-选择性粘贴-值”将公式结果转换为固定值
  3. 然后再导出为CSV

Q9: 生成的文件太大?

解决:
DataBaker使用GZip压缩,已经非常高效。如果仍然太大:

  • 考虑拆分大表为多个小表
  • 减少不必要的字符串字段
  • 使用数值枚举代替字符串

Q10: 多人协作时的冲突处理?

解决:
建议:

  1. 使用Excel的”共享工作簿”功能
  2. 指定专人负责维护配置表
  3. 使用版本控制系统管理CSV文件
  4. 配置表更新时通知团队成员

最佳实践

1. 表设计原则

  • 使用有意义的字段名称(英文)
  • 保持字段类型一致
  • 合理使用默认值
  • 为相关字段添加注释

2. 数据组织

  • 按功能模块划分表
  • 单个表不宜过大(<1000行)
  • 合理使用数组减少表数量
  • 建立表之间的关联关系

3. 命名规范

  • CSV文件名: PascalCase (如: ItemData.csv)
  • 字段名: PascalCase (如: ItemName)
  • 类名: 自动从文件名生成 (如: ItemData, ItemDataTable)

4. 性能优化

  • 按需加载,不要一次性加载所有表
  • 及时卸载不用的表
  • 缓存常用数据引用
  • 使用FindData而不是遍历

5. 版本控制

  • 将CSV文件纳入版本控制
  • 生成的C#类也纳入版本控制
  • 二进制文件通常不纳入版本控制(使用.gitignore)
  • 记录每次配置变更的原因

许可证

本插件受 Unity Asset Store End User License Agreement 约束。

通过购买或使用本插件,您同意遵守 Unity Asset Store 服务条款

使用许可

  • 在任意数量的商业或个人项目中使用
  • 修改源代码以适应您的项目需求
  • 将插件打包到最终发布的游戏产品中

使用限制

  • 不得转售、分发或共享源代码
  • 不得声称本插件是您自己的作品
  • 不得用于创建竞争性产品


联系方式


致谢

  • 感谢Unity引擎提供强大的开发环境
  • 感谢Addressables团队提供的优秀资源管理系统
  • 感谢所有使用和改进DataBaker的开发者

更新日志

v1.0.0 (2025-01-18)

  • 初始版本发布
  • 支持CSV到二进制转换
  • 自动生成C#类和表管理器
  • 集成Addressable资源管理
  • 支持多种数据类型和数组
  • 注册表模式,零反射
  • 完美兼容WebGL和iOS平台

让配置管理变得简单高效!