xunkong / KeqingNiuza

刻记牛杂店
MIT License
517 stars 53 forks source link

关于规范祈愿记录导出格式的建议 #53

Closed Scighost closed 2 years ago

Scighost commented 2 years ago

原神2.3版本的新卡池「角色活动祈愿-2」的 gacha_type=400 ,考虑到以后可能会出更多的卡池,我认为可以制定一个各软件通用的祈愿记录导出格式的规范,方便各个软件间的数据互通。也包含了我的一点私货

通用格式需要考虑兼容性和拓展性,现有软件中用户基数最大的 genshin-wish-export 使用了Excel文件作为导出格式,所以我认为把Excel文件作为通用格式的基础是最合理的。刻记牛杂店 在此基础上新增了一列 祈愿 Id ,保存了这一重要的字段。

在兼容上述格式的前提下考虑拓展性,可以把共享保底的数据放在同一个表中,新增一列 祈愿类型 ,既不丢失原始数据,也能直观展示抽卡记录和保底情况。同时新增一个 原始数据 表,方便软件的导入。

具体规范如下(同一表中的数据以 Id 升序排列):

Excel表名及内容 如果有新的卡池种类,就新增祈愿表 表名 内容
统计分析 尽情发挥
角色活动祈愿 301, 400
武器活动祈愿 302
常驻祈愿 200
新手祈愿 100
原始数据 全部数据
祈愿表结构 共享保底的池子根据祈愿类型区分 时间 名称 类别 星级 总次数 保底内 祈愿 Id 祈愿类型
2021-02-17 18:45:09 以理服人 武器 3 233 77 1613556360008291100 301
原始数据表结构 以官方json结构为标准,现有字段按字母顺序排列 count gacha_type id item_id item_type lang name rank_type time uid
1 301 1613556360008291100 武器 zh-cn 以理服人 3 2021-02-17 18:45:09 123456789

以我自己的祈愿记录为例子:原神祈愿记录_123456789.xlsx

以上仅为提出想法时的草案,更详细更规范的内容看下一条

Lightczx commented 2 years ago

https://github.com/DGP-Studio/Snap.Genshin/blob/main/Developer/StandardExcelFormat.md

Scighost commented 2 years ago

@biuuu @Lightczx @sunfkny @TremblingMoeNew @voderl 您好,我是「刻记牛杂店」的作者,邀请你们来共同讨论《祈愿记录导出格式的规范》,更详细的内容参考: https://github.com/DGP-Studio/Snap.Genshin/blob/main/Developer/StandardExcelFormat.md

Lightczx commented 2 years ago

🖐️

Scighost commented 2 years ago
现有争议如下: 我认为为了保持兼容性,祈愿表的 星级祈愿类型 之间应保留 总次数保底内,@Lightczx 认为 祈愿类型祈愿 Id 更重要,应放在 总次数保底内 之前。 1 2 3 4 5 6
我支持的顺序 星级 总次数 保底内 祈愿类型 祈愿 Id
@Lightczx 支持的顺序 星级 祈愿类型 祈愿 Id 总次数 保底内
biuuu commented 2 years ago

导出 Excel 最开始的目的是方便玩家查看,从这一点来看 祈愿 Id祈愿类型 的重要性会低一些。

  1. 祈愿 Id:在用户看来只是一串无意义的数字,而且工具之间传输数据获取 Id 肯定是优先使用原始数据表
  2. 祈愿类型:在用户点进对应表格时其实已经提前知道祈愿类型了,只是需要区分是 301 还是 400。但纯数字对用户来说体验还是不好,最好是展示为如“卡池1”、“卡池2”这样的文本。

我认为在已经添加原始数据表表的情况下,祈愿表应该更注重可读性。

关于 uid:考虑到用户可能会对 uid 的暴露比较敏感,我倾向于不在 Excel 文件的任何位置保存 uid。

Lightczx commented 2 years ago
@biuuu 直接显示数字id确实不够直观 我认为这样的名称较为合适 gacha_type 名称
100 新手祈愿
200 奔行世间
301 角色活动
302 神铸赋形
400 角色活动-2

而不是

gacha_type 名称
100 新手祈愿
200 奔行世间
301 角色活动祈愿
302 神铸赋形
400 角色活动祈愿-2
Lightczx commented 2 years ago

相关的标准已经更新到 v1.2 https://github.com/DGP-Studio/Snap.Genshin/blob/main/Developer/StandardExcelFormat.md

sunfkny commented 2 years ago

@Lightczx

祈愿表结构里的 物品类型 对应的内容写错了,应该是item_type而不是gacha_type

祈愿类型这一栏建议同步游戏卡池左上角和历史记录页面的祈愿类型,标准 v1.2 这种卡池名和卡池类型混用还删掉祈愿二字我觉得会造成困扰

Scighost commented 2 years ago

@Lightczx

祈愿表结构里的 物品类型 对应的内容写错了,应该是item_type而不是gacha_type

祈愿类型这一栏建议同步游戏卡池左上角和历史记录页面的祈愿类型,标准 v1.2 这种卡池名和卡池类型混用还删掉祈愿二字我觉得会造成困扰

支持。奔行世间神铸赋形 是和 浪涌之瞬深秘之息 相对应的卡池名,而不是类型名,两者混用不合适。

另外我认为表名应该使用全称而不是简称。

Lightczx commented 2 years ago

整合了各位的意见又修订了一版 v1.3 https://github.com/DGP-Studio/Snap.Genshin/blob/main/Developer/StandardExcelFormat.md

biuuu commented 2 years ago

祈愿表的表头是有 key 的,目前使用的是:

['time', 'name', 'type', 'rank', 'total', 'pity']

对应

时间 | 名称 | 类别 | 星级 | 总次数 | 保底内 -- | -- | -- | -- | -- | --
Lightczx commented 2 years ago

我认为 总次数 与 保底内并不是必要的内容,用户可以自行计算

Scighost commented 2 years ago

我认为 总次数 与 保底内并不是必要的内容,用户可以自行计算

反对,我认为保底内很有必要,Excel算这个老麻烦了; 总次数可以不需要,Excel有列序号。

Lightczx commented 2 years ago

“保底内” 这个名称让人产生疑惑,虽然观察表的内容可以理解其含义,但是第一次看还是让人有些不明所以

Scighost commented 2 years ago

保底内表达的是连续多少抽没有出5星,感觉不太好用一个简单通俗的名词描述这个概念,懂的都懂吧。 水位?已垫抽数?

Lightczx commented 2 years ago

保底内表达的是连续多少抽没有出5星,感觉不太好用一个简单通俗的名词描述这个概念,懂的都懂吧。 水位?已垫抽数?

这样的话我认为祈愿表不需要强制包含这两个字段了,只需要确保最基础的5个字段存在即可

Lightczx commented 2 years ago

目前v 1.3 https://github.com/DGP-Studio/Snap.Genshin/blob/main/Developer/StandardExcelFormat.md 的内容与上述意见没有冲突的地方,在三天后如果没有反对意见那我们就按 v1.3 的规范开始适配了

Scighost commented 2 years ago

同意现版本,但是我还希望能够加上一条支持导出为官方格式的json文件,一次性交换数据的话这个读写比较方便。

Lightczx commented 2 years ago

我觉得@sunfkny 的储存格式就非常适合作为导出json的格式

sunfkny commented 2 years ago

我现在的格式是这样的

{
    "gachaType": {
        "100": "新手祈愿",
        "200": "常驻祈愿",
        "301": "角色活动祈愿",
        "302": "武器活动祈愿"
    },
    "gachaLog": {
        "100": [],
        "200": [],
        "301": [],
        "302": []
    },
    "uid": "100000000"
}

这里没有400是因为100,200,301,302是getGachaLog的查询参数,gachaType有改动,之前放的是getConfigList返回的内容,现在官方弃用了就从简了,我觉得甚至可以不要

此外,为了扩展性用数字做key不太好,是不是可以考虑改为

{
    "gacha_log_list": [
        {
            "gacha_type": 100,
            "gacha_log": []
        },
        {
            "gacha_type": 200,
            "gacha_log": []
        },
        {
            "gacha_type": 301,
            "gacha_log": []
        },
        {
            "gacha_type": 302,
            "gacha_log": []
        }
    ],
    "uid": "100000000"
}
Lightczx commented 2 years ago

单个物品内部已经存在gacha_typeuid 字段了

{
    "uid": "-",
    "gacha_type": "-",
    "item_id": "",
    "count": "1",
    "time": "-",
    "name": "-",
    "lang": "-",
    "item_type": "-",
    "rank_type": "-",
    "id": "-"
}

所以我觉得没有必要再嵌套一层额外的type的wrapper 直接将所有数据列在一个大列表里面就可以了, 针对早于1.3的数据可以按顺序与时间生成一个近似id值

我建议的json格式如下

[
    { },
    { },
...
]
sunfkny commented 2 years ago

uid确实可以不要

但是大列表有一个问题,无法表示301查询到400的情况(实际上301或400查询到的是既有301又有400的结果,官方也只用了301查询),物品内部gacha_type与查询时候的gacha_type不是对应的 假设官方加了个角色活动祈愿-3,没有适配的情况下这种大列表会导致数据不显示,统计抽数也会乱,分开只是没有 gacha_type 转义名称但是能显示能统计感觉稍微好一点

Lightczx commented 2 years ago

@Scighost @biuuu

Lightczx commented 2 years ago

我确实也发现如果没有预设的卡池id值做一个wrapper,导入会变得困难,uid倒是可以probe出来

Lightczx commented 2 years ago

注意一下导出的Excel格式内 原始数据表的 各项值类型应为String

Scighost commented 2 years ago

单个物品内部已经存在gacha_typeuid 字段了

{
    "uid": "-",
    "gacha_type": "-",
    "item_id": "",
    "count": "1",
    "time": "-",
    "name": "-",
    "lang": "-",
    "item_type": "-",
    "rank_type": "-",
    "id": "-"
}

所以我觉得没有必要再嵌套一层额外的type的wrapper 直接将所有数据列在一个大列表里面就可以了, 针对早于1.3的数据可以按顺序与时间生成一个近似id值

我建议的json格式如下

[
    { },
    { },
...
]

我觉得这个方案比较好,json文件应该只用来数据交换,一个大列表完全可以看作Excel原始数据表的另一种形式。

uid确实可以不要

但是大列表有一个问题,无法表示301查询到400的情况(实际上301或400查询到的是既有301又有400的结果,官方也只用了301查询),物品内部gacha_type与查询时候的gacha_type不是对应的 假设官方加了个角色活动祈愿-3,没有适配的情况下这种大列表会导致数据不显示,统计抽数也会乱,分开只是没有 gacha_type 转义名称但是能显示能统计感觉稍微好一点

各软件都有自己的存储数据和统计数据的方式,这个和用于交换数据的json文件并不冲突。

TremblingMoeNew commented 2 years ago

我认为应该注意一下各工具的历史兼容性问题,还有过往导出的excel的兼容性问题 像biuuu的本地用户记录就只直接保留了time、item_type、rank_type和name四个字段(而不只是1.3版本前的没保留),对gacha_type做了间接保存但也没做301和400的区分,关键是抛掉了id;我的也抛掉了gacha_type,没做301和400的区分。 原始数据表应当至少规定好time、name、id、gacha_type、item_type、rank_type的绝对位置(最好是所有域都定好绝对位置)便于软件的检索,没id就直接空着,一行一行扫过去检查哪个是哪个也不方便;不区分301和400的是全输出成301还是? 另外,json里个人建议加一个域,在里面注明软件、导出时间、uid及该软件缺失的关键数据项 还有就是以前的excel怎么办

Scighost commented 2 years ago

我认为应该注意一下各工具的历史兼容性问题,还有过往导出的excel的兼容性问题 还有就是以前的excel怎么办

以前的Excel文件中的前四列也是 时间名称类别星级 ,和新规范保持一致。 biuuu 的不知道从哪个版本开始已经保存了 id

抛掉了 gacha_type

我看你的记录文件完整保存了从米哈游api上获取的所有字段。

原始数据表应当至少规定好time、name、id、gacha_type、item_type、rank_type的绝对位置(最好是所有域都定好绝对位置)便于软件的检索,没id就直接空着,一行一行扫过去检查哪个是哪个也不方便;不区分301和400的是全输出成301还是?

同意,原始数据表部分列的值可以为空,但是要把那一列留着;我认为可以按字母升序排列(仅现有字段,api加了字段后可以排在最后)。

另外,json里个人建议加一个域,在里面注明软件、导出时间、uid及该软件缺失的关键数据项

可以再加一个规范版本号,Excel里也可以加上这个。

另外,不考虑一下规范正式确定时重置为 1.0 版本吗?

TremblingMoeNew commented 2 years ago

我看你的记录文件完整保存了从米哈游api上获取的所有字段。

并没有,我的301和400是存到同一个"poolType": 301的banner项里的,同版本的301和400池被我当成一个池子处理了,没做额外兼容…

Scighost commented 2 years ago

我看你的记录文件完整保存了从米哈游api上获取的所有字段。

并没有,我的301和400是存到同一个"poolType": 301的banner项里的,同版本的301和400池被我当成一个池子处理了,没做额外兼容…

看错人了,我以为是 sunfkny。🤣 400 池子才开没几天,现在改完全没有影响。

TremblingMoeNew commented 2 years ago

400 池子才开没几天,现在改完全没有影响。

算了,紧急更新一下吧,把当前这个池子强制重扫了……

TremblingMoeNew commented 2 years ago

biuuu 的不知道从哪个版本开始已经保存了 id

看了一下,五天前…… https://github.com/biuuu/genshin-wish-export/commit/261cda1568e373df818e83f7e0db60bbd4206a19 既然biuuu也加上了那问题倒也不大了,就是1.5版本前中期及之前的还是缺了的,他这部分id如果输出时随便编恐怕会造成更严重的问题 我的建议是,这些缺漏的id(包括之前牛杂店标记为isLostId==true的)就直接空着/默认值好了,没必要把自己编的随机值导出来,真那样是有一定的合并风险的

sunfkny commented 2 years ago

我的建议是,这些缺漏的id(包括之前牛杂店标记为isLostId==true的)就直接空着/默认值好了,没必要把自己编的随机值导出来,真那样是有一定的合并风险的

导出来问题也不大,大家编出来的的id应该都是1000不知道多少个0001开始的,判断一下就行

Scighost commented 2 years ago

我的软件逻辑决定了每条记录必须要有 id ,没有 id 的记录从 10...01 开始,并不是随机的。 还有 IsLostId 这个字段已经被我去掉了。

TremblingMoeNew commented 2 years ago

我的软件逻辑决定了每条记录必须要有 id ,没有 id 的记录从 10...01 开始,并不是随机的。 还有 IsLostId 这个字段已经被我去掉了。

果不其然的在二段导入测试中寄了,虽说这个操作正常发生的概率不高( #57 生成的数据表不设这一项、交给各软件自己生成罢了() 当然要是定一个小于多少的全部视作软件自己生成的倒也行

sunfkny commented 2 years ago

当然要是定一个小于多少的全部视作软件自己生成的倒也行

有幸保留了每次的历史,保存了我开服第一抽的id,小于1600000000000000000都可以视为补全生成的id,当成空值就行了

{
    "uid": "100205551",
    "gacha_type": "100",
    "item_id": "",
    "count": "1",
    "time": "2020-09-15 12:12:52",
    "name": "以理服人",
    "lang": "zh-cn",
    "item_type": "武器",
    "rank_type": "3",
    "id": "1600099200004770203"
}
Lightczx commented 2 years ago

现有的id生成规则似乎不容易兼容, 因为不同软件的补全id生成规律有冲突 最好是App自己提供一个全量刷新的方法来规避新老物品重叠的问题 导出的json不应该存在无id需要被导入App去补全的情况

Lightczx commented 2 years ago

经过考虑后我觉得还是

[
    {
        "type": 100,
        "log": []
    }
    ...
]

这样最好,因为米哈游一但增加卡池如果不及时适配, 单个列表导入的数据就会有部分未知gacha_type 的物品被忽略 而保存外围的gacha_type值允许物品被划分入同一个池中,至少在导入时不会丢失数据

Lightczx commented 2 years ago

另外,不考虑一下规范正式确定时重置为 1.0 版本吗?

我会在 json格式统一后更新至 2.0

TremblingMoeNew commented 2 years ago

不同软件的补全id生成规律有冲突

所以上面才建议在导出文件里直接把自己补全的这部分id给扔了(小于1.6E18的给扔了也行……不对外服不一定是这个值,但按照<1.1E18扔掉应该不会错),其他程序在自己导入的时候再根据自己的规则给补上

经过考虑后我觉得还是

[
    {
        "type": 100,
        "log": []
    }
    ...
]

这样最好,因为米哈游一但增加卡池如果不及时适配, 单个列表导入的数据就会有部分未知gacha_type 的物品被忽略 而保存外围的gacha_type值允许物品被划分入同一个池中,至少在导入时不会丢失数据

可以,不过excel那边的原始数据也得加一个对应的域

{
   "header":{
        "software":"xxxxxx",
        "software_version":"xxxxxxx",
        "game_version":"xxxxxxx",
        "export_date":"xxxxxxxx",
        "uid":"xxxxxx"
    },
   "gacha":[
        {
            "gacha_type":301,
            "logs":[
                {
                    "gacha_type":400,
                    "name":"xxx",
                    "time":"xxxxxx",
                    "item_type":"xxx",
                    "rank_type":"xxx",
                    "id":"xxxx"
                }
            ]
        }
    ]
}

大概这样?count什么的可以等需要了再补

lang其实是个问题,因为几个有单位数据库的其实都是严格限制输入语言的

TremblingMoeNew commented 2 years ago

因为几个有单位数据库的其实都是严格限制输入语言的

顺便,刚用法语测了下 好像只有牛杂店没在查询时限制语言、用户用啥就是啥,而且牛杂店还正好怕这个,于是就又炸了() biuuu限制语言,但是是支持其他语言的,也就是说会在这个问题上带来麻烦

DGP因为我.NET版本不够没法试,看了下代码感觉也会出问题

Lightczx commented 2 years ago

因为几个有单位数据库的其实都是严格限制输入语言的

顺便,刚用法语测了下 好像只有牛杂店没在查询时限制语言、用户用啥就是啥,而且牛杂店还正好怕这个,于是就又炸了() biuuu限制语言,但是是支持其他语言的,也就是说会在这个问题上带来麻烦

DGP因为我.NET版本不够没法试,看了下代码感觉也会出问题

sg本身就不打算支持国际化

Lightczx commented 2 years ago

在Excel中增加域不是好办法,并不是所有编程语言都有库能读取Excel的域,关于UIGF格式的版本问题其实不需要在表内嵌入额外数据,本身设计的初衷就是为了能向后兼容

TremblingMoeNew commented 2 years ago
count gacha_type id ident_type item_id item_type lang name rank_type time
100/200/301/302
TremblingMoeNew commented 2 years ago

关于UIGF格式的版本问题其实不需要在表内嵌入额外数据

UIG(W)F没必要,其更侧重于给用户的输出与展示,也受限于Excel的形式 但json版并不是给用户直接阅读的,其作用是数据的备份以及各工具间的数据交换。加一个header属性,在里面注明一些基本信息,并且(如果需要的话)拿来做纪录备份、向内添加一些本工具额外需要的信息,不也挺好的吗 json版应该有一个可区分的独立名字 还有现在这个“可交换统一格式祈愿记录工作簿格式”太长了,是不是应该有一个中文简称

TremblingMoeNew commented 2 years ago

或者json里也可以在每一条纪录项上加上ident_type,这样两边的纪录格式就统一了

{
   "header":{
        "software":"xxxxxx",
        "software_version":"xxxxxxx",
        "game_version":"xxxxxxx",
        "export_date":"xxxxxxxx",
        "lang":"zh_cn",
        "uid":"xxxxxx"
    },
   "logs":[
        {
              "gacha_type":400,
              "name":"xxx",
              "time":"xxxxxx",
              "ident_type":301
              "item_type":"xxx",
              "rank_type":"xxx",
              "id":"xxxx"
        }
    ]
}

countlang(但应该在header里注明)和item_id(甚至于id)在反序列化时应允许被忽略 同一份文件中不应当出现纪录的lang不统一的情况

Lightczx commented 2 years ago

不能在官方的json格式内部注入属于自己的字段,一旦官方新增了同名字段就可能会出现无法兼容的情况

Lightczx commented 2 years ago

json额外信息的问题其实没有必要,那都是各个App导入之后可以自己生成,自己去保存的东西,不应当因为互换json数据而去影响各个App的内部储存实现

TremblingMoeNew commented 2 years ago

不能在官方的json格式内部注入属于自己的字段,一旦官方新增了同名字段就可能会出现无法兼容的情况

用一个官方几乎不可能用的字段名称就行,比如_identtypeuigf_ident_type这种

不应当因为互换json数据而去影响各个App的内部储存实现

Lightczx commented 2 years ago

出于交流讨论的便利性我决定将此issue转换为discussion以便楼中楼针对性回答