Skip to content

Latest commit

 

History

History
316 lines (221 loc) · 12.8 KB

File metadata and controls

316 lines (221 loc) · 12.8 KB

Loxodon Framework Data

license release

开发者 Clark

要求Unity 2018.4或者更高版本

本插件支持从Excel文件中导出数据到Json文件、Lua文件或者LiteDB数据库,以及通过Json.Net将数据转为C#对象。推荐使用LiteDB存储配置数据,这是一个轻量级的NoSQL嵌入式数据库,它本身就支持ORM功能、支持BSON格式、支持数据索引功能,使用起来非常方便。

安装

  • Loxodon Framework Data(必选)

    必选插件,它支持解析excel文件,并且可以从excel文件导出到数据到Lua或者Json文件中。

  • Loxodon Framework Data LiteDB(可选)

    可选插件,它支持将数据导出到LiteDB数据库中,支持ORM,并且自动注册了Color、Vector2、Vector3、Vector4、Vector2Int、Vector3Int、Version等类的序列化和反序列化函数,列如:自动将(1.0,1.0,1.0)字符串转换为C#对象Vector3。如果需要使用LiteDB数据库来存储配表文件,那么必须安装此插件(推荐)。

  • Loxodon Framework Data Newtonsoft.Json(可选)

    可选插件,支持使用Newtonsoft.Json解析Json数据,支持Color、Vector2、Vector3、Vector4、Vector2Int、Vector3Int、Version等类的Json类型转换器。

在Unity项目的Packages目录中找到manifest.json 文件,增加第三方仓库 "https://package.openupm.com"或者"https://registry.npmjs.org"到配置文件中,然后增加"com.vovgou.loxodon-framework-data"到dependencies节点下,然后保存文件,Unity会自动下载安装插件。

{
  "dependencies": {
    ...
    "com.unity.modules.xr": "1.0.0",
    "com.vovgou.loxodon-framework-data": "2.4.9", //必选
    "com.vovgou.loxodon-framework-data-litedb": "2.4.9", //可选
    "com.vovgou.loxodon-framework-data-newtonsoft": "2.4.9" //可选
  },
  "scopedRegistries": [
    {
      "name": "package.openupm.com",
      "url": "https://package.openupm.com",
      "scopes": [
        "com.vovgou",
        "com.openupm"
      ]
    }
  ]
}

Excel数据

Excel文件格式如下:

表头定义

  • 第一行: 字段名称(必选),只能使用英文、数字、中划线或者下划线,首字母不能使用数字,建议采用驼峰命名法。同时也支持路径配置,路径由多个字段组成,字段之间使用点号(.)分割,比如user.firstName,user.lastName。
  • 第二行: 字段类型和列索引(必选),格式:类型(索引),列如:int(index),如果不需要索引则只填写类型即可,字段类型的定义见下文中数据类型章节,字段索引包括唯一索引unique和非唯一索引index,字段索引仅在导出到嵌入式数据库时有效。
  • 第三行: 备注信息(可选)

数据类型

  • 基本数据类型: int, string, float, bool

    bool类型支持字符串的配置方式”true”或者”false”,不区分大小写,也支持数字配置方式1或者0 枚举类型可以使用int类型配置,也可以使用string类型配置,如果上图中的status字段

  • 数组类型: int[], string[], float[], bool[]

    数组元素使用半角的逗号”,”分割,并且自动忽略空格。如int[]数组填写:2,3,4

  • 字典类型: int{}, string[], float{}, bool{}

    字典的多个键值对使用半角的逗号”,”分割,键值对格式为 key=value 的方式。 字典的配置支持两种方式,第一种是如上表的name字段的配置,类型是string{},配置在一个单元格中,这种方式配置必须确保所有的元素都是相同类型;另一种是information的配置,分别配置在多个单元格中,可以单独定义子字段的类型。一般来说很短的文本内容使用第一种方式,比较长的文本内容或者子字段是不同的类型,比如对象配置,则使用第二种方式。

    它们导出到Json格式是一样的,如下:

    {
      "name":{"zh-CN":"克拉克","en-US":"Clark"},
      "information":{"zh-CN":"我是一个程序员","en-US":"I'm a programmer"}
    }
    

    如果需要支持Color、Vector2、Vector3、Vector4、Version等其他类型,请使用string类型存储,在Json序列化时通过自定义的JsonConverter转换为对应的类型。如Color可以存储为"#FF0000",Vector3可以存储为"(1.0,2.0,3.0)"

列索引

列索引支持唯一索引和非唯一索引,仅支持单列索引,不支持联合索引,列索引仅在导出数据到支持索引功能的数据库时有效,导出到json或者lua时忽略索引。

  • 唯一索引

    unique

  • 非唯一索引

    index

导出数据

通过Tools/Loxodon/Excel Export Wizard菜单打开导出向导界面如下图。选择导出处理器,字段行行号,数据类型行号,备注信息的行号,数据起始行号以及导出的文件格式。

点列表右下角的"+"号导入Excel文件列表,排除不需要导出的Sheet表单。点击右下角的Export按钮导出文件。

  • 导出的Json

    导出的Json格式如下,Excel中的每行对应到Json文件中每一行,以换行符分割。

      { "id":1,"username":"clark","name":{ "zh-CN":"克拉克","en-US":"Clark" },"emails":[ "clark1@gmail.com","clark2@gmail.com" ],"information":{ "zh-CN":"我是一个程序员","en-US":"I'm a programmer" },"address":{ "province":"北京","street":"东直门内大街","postcode":"100000" },"status":"OK" }
      { "id":2,"username":"tom","name":{ "zh-CN":"汤姆","en-US":"Tom" },"emails":[ "tom1@gmail.com","tom2@gmail.com" ],"information":{ "zh-CN":"我是一个程序员","en-US":"I'm a programmer" },"address":{ "province":"北京","street":"东直门内大街","postcode":"100000" },"status":"LOCKED" }
    
  • 导出的LiteDB数据

自定义导出工具

可以通过继承ExportProcessor类,定制自己的导出格式,在项目中创建类CustomExportProcessor(类名没有要求,只要继承ExportProcessor就行)如下,在导出工具的Configuration界面会自动出现CustomExportProcessor处理器,选择CustomExportProcessor处理器,则会使用自定义处理器导出。

如下代码,自定义一个了Json格式的表单导出处理器。

public class CustomExportProcessor : ExportProcessor
{
    protected override bool Filter(FileInfo file, ISheet sheet)
    {
        //自定义Sheet表单过滤方法,只导出第一个Sheet
        var workbook = sheet.Workbook;
        if (workbook.GetSheetIndex(sheet) != 0)
            return false;
        return true;
    }

    protected override void DoExportSheet(FileInfo file, ISheet sheet, ISheetReader reader, string outputRoot)
    {
        string filename = string.Format("{0}.json", sheet.SheetName).ToLower();
        string fullname = Path.Combine(outputRoot, filename);
        StringBuilder text = Parse(reader);
        File.WriteAllText(fullname, text.ToString());
        Debug.LogFormat("File:{0} Sheet:{1} OK……", GetRelativePath(file.FullName), sheet.SheetName);
    }

    protected StringBuilder Parse(ISheetReader reader)
    {
        StringBuilder buf = new StringBuilder();
        for (int i = reader.StartLine; i <= reader.TotalCount; i++)
        {
            var data = reader.ReadLine(i);
            if (data == null)
                continue;

            string json = JsonConvert.SerializeObject(data, Formatting.None);
            buf.AppendLine(json);
        }
        return buf;
    }
}

本地化支持

本插件支持本地化配置,如下图中的name字段和infomation字段配置,会解析为一个字典对象,其中的Key是System.Globalization.CultureInfo的Name值,即语言类型,比如简体中文为zh-CN。在C#类中,可以将字典反序列化为LocalizedString对象,LocalizedString对象可以直接通过数据绑定绑定到UI上,并且随Localization模块动态切换语言。

使用示例

入下图所示,导入示例代码。

如果使用Newtomsoft.Json库,请添加宏定义NEWTOMSOFT,与Json加载相关的测试代码生效。如果使用LiteDB数据库,则添加LITEDB宏定义,开启LiteDB数据库加载的示例代码。

Json载入示例

从Json文件加载数据,可以使用各种开源的Json解析库,请自行选择安装即可,下面的示例使用的是Newtonsoft.Json解析库。

public class UserInfo
{
    [JsonProperty("id")]
    public int Id { get; set; }

    [JsonProperty("username")]
    public string Username { get; set; }

    [JsonProperty("name")]
    public LocalizedString Name { get; set; }

    [JsonProperty("emails")]
    public List<string> Emails { get; set; }

    [JsonProperty("information")]
    public LocalizedString Information { get; set; }

    [JsonProperty("address")]
    public Address Address { get; set; }

    [JsonProperty("status")]
    public Status Status { get; set; }
}

public interface IUserInfoRepository
{
    UserInfo GetById(int id);

    UserInfo GetByUsername(string username);
}

public class JsonUserInfoRepository : IUserInfoRepository
{
    private Dictionary<int, UserInfo> idAndUserInfoMapping = new Dictionary<int, UserInfo>();
    private Dictionary<string, UserInfo> usernameAndUserInfoMapping = new Dictionary<string, UserInfo>();
    private bool loaded = false;
    private void LoadAll()
    {
        var text = Resources.Load<TextAsset>("Json/userinfo");
        if (text == null || text.text.Length <= 0)
            return;

        using (StringReader reader = new StringReader(text.text))
        {
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                if (string.IsNullOrWhiteSpace(line))
                    continue;

                UserInfo userInfo = JsonConvert.DeserializeObject<UserInfo>(line);
                if (userInfo == null)
                    continue;

                idAndUserInfoMapping[userInfo.Id] = userInfo;
                usernameAndUserInfoMapping[userInfo.Username] = userInfo;
            }
        }
        this.loaded = true;
    }

    public virtual UserInfo GetById(int id)
    {
        if (!loaded)
            this.LoadAll();

        UserInfo userInfo = null;
        idAndUserInfoMapping.TryGetValue(id, out userInfo);
        return userInfo;
    }

    public virtual UserInfo GetByUsername(string username)
    {
        if (!loaded)
            this.LoadAll();

        UserInfo userInfo = null;
        usernameAndUserInfoMapping.TryGetValue(username, out userInfo);
        return userInfo;
    }
}

LiteDB载入示例

从LiteDB数据库中加载数据,使用方式请查看下面的示例。更多的内容请查看LiteDB官方文档

public class UserInfo
{
    public int Id { get; set; }

    public string Username { get; set; }

    public LocalizedString Name { get; set; }

    public List<string> Emails { get; set; }

    public LocalizedString Information { get; set; }

    public Address Address { get; set; }

    public Status Status { get; set; }
}

public interface IUserInfoRepository
{
    UserInfo GetById(int id);

    UserInfo GetByUsername(string username);
}

public class LiteDBUserInfoRepository : LiteDBRepository<UserInfo>, IUserInfoRepository
{
    public LiteDBUserInfoRepository(ILiteDatabase database) : base(database)
    {
    }

    public UserInfo GetById(int id)
    {
        return GetCollection().FindById(id);
    }

    public UserInfo GetByUsername(string username)
    {
        return GetCollection().FindOne(c => c.Username.Equals(username));
    }
}