Teleport Map & Switching Dynamic Wallpaper Support, Gacha optimization #2
26 changed files with 65870 additions and 924 deletions
62086
assets/FileCfg/ItemTemplateTb.json
Normal file
62086
assets/FileCfg/ItemTemplateTb.json
Normal file
File diff suppressed because it is too large
Load diff
29
assets/FileCfg/QuickAccessTemplateTb.json
Normal file
29
assets/FileCfg/QuickAccessTemplateTb.json
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"QuickAccessIndex": 1,
|
||||||
|
"QuickFuncID": 1005,
|
||||||
|
"RequiredUnlockIDs": [
|
||||||
|
1005
|
||||||
|
],
|
||||||
|
"EFPBDDJIJBO": 1040140154,
|
||||||
|
"BOKMLGNMJPB": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"QuickAccessIndex": 2,
|
||||||
|
"QuickFuncID": 1022,
|
||||||
|
"RequiredUnlockIDs": [
|
||||||
|
1022
|
||||||
|
],
|
||||||
|
"EFPBDDJIJBO": 1040140049,
|
||||||
|
"BOKMLGNMJPB": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"QuickAccessIndex": 3,
|
||||||
|
"QuickFuncID": 1009,
|
||||||
|
"RequiredUnlockIDs": [
|
||||||
|
1009
|
||||||
|
],
|
||||||
|
"EFPBDDJIJBO": 1050060115,
|
||||||
|
"BOKMLGNMJPB": null
|
||||||
|
}
|
||||||
|
]
|
112
assets/FileCfg/QuickFuncTemplateTb.json
Normal file
112
assets/FileCfg/QuickFuncTemplateTb.json
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"BtnID": 1001,
|
||||||
|
"BOMNEKHOGIH": "",
|
||||||
|
"PECPFBBOGKO": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BtnID": 1002,
|
||||||
|
"BOMNEKHOGIH": "",
|
||||||
|
"PECPFBBOGKO": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BtnID": 1003,
|
||||||
|
"BOMNEKHOGIH": "",
|
||||||
|
"PECPFBBOGKO": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BtnID": 1004,
|
||||||
|
"BOMNEKHOGIH": "",
|
||||||
|
"PECPFBBOGKO": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BtnID": 1005,
|
||||||
|
"BOMNEKHOGIH": "UI/Sprite/A1DynamicLoad/MainCityMenus/Packer/BtnInterKnot.png",
|
||||||
|
"PECPFBBOGKO": "UI/Sprite/A1DynamicLoad/MainCityMenus/Packer/BtnInterKnot.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BtnID": 1006,
|
||||||
|
"BOMNEKHOGIH": "",
|
||||||
|
"PECPFBBOGKO": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BtnID": 1007,
|
||||||
|
"BOMNEKHOGIH": "",
|
||||||
|
"PECPFBBOGKO": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BtnID": 1008,
|
||||||
|
"BOMNEKHOGIH": "",
|
||||||
|
"PECPFBBOGKO": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BtnID": 1009,
|
||||||
|
"BOMNEKHOGIH": "UI/Sprite/A1DynamicLoad/MainCityMenus/Packer/BtnGuide.png",
|
||||||
|
"PECPFBBOGKO": "UI/Sprite/A1DynamicLoad/MainCityMenus/Packer/BtnGuide.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BtnID": 1010,
|
||||||
|
"BOMNEKHOGIH": "",
|
||||||
|
"PECPFBBOGKO": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BtnID": 1011,
|
||||||
|
"BOMNEKHOGIH": "",
|
||||||
|
"PECPFBBOGKO": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BtnID": 1013,
|
||||||
|
"BOMNEKHOGIH": "",
|
||||||
|
"PECPFBBOGKO": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BtnID": 1014,
|
||||||
|
"BOMNEKHOGIH": "",
|
||||||
|
"PECPFBBOGKO": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BtnID": 1015,
|
||||||
|
"BOMNEKHOGIH": "",
|
||||||
|
"PECPFBBOGKO": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BtnID": 1016,
|
||||||
|
"BOMNEKHOGIH": "",
|
||||||
|
"PECPFBBOGKO": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BtnID": 1017,
|
||||||
|
"BOMNEKHOGIH": "",
|
||||||
|
"PECPFBBOGKO": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BtnID": 1018,
|
||||||
|
"BOMNEKHOGIH": "",
|
||||||
|
"PECPFBBOGKO": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BtnID": 1019,
|
||||||
|
"BOMNEKHOGIH": "",
|
||||||
|
"PECPFBBOGKO": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BtnID": 1020,
|
||||||
|
"BOMNEKHOGIH": "",
|
||||||
|
"PECPFBBOGKO": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BtnID": 1021,
|
||||||
|
"BOMNEKHOGIH": "UI/Sprite/A1DynamicLoad/MainCityMenus/Packer/BtnCamera.png",
|
||||||
|
"PECPFBBOGKO": "UI/Sprite/A1DynamicLoad/MainCityMenus/Packer/BtnCamera.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BtnID": 1022,
|
||||||
|
"BOMNEKHOGIH": "UI/Sprite/A1DynamicLoad/MainCityMenus/Packer/BtnMessage.png",
|
||||||
|
"PECPFBBOGKO": "UI/Sprite/A1DynamicLoad/MainCityMenus/Packer/BtnMessage.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"BtnID": 1023,
|
||||||
|
"BOMNEKHOGIH": "",
|
||||||
|
"PECPFBBOGKO": ""
|
||||||
|
}
|
||||||
|
]
|
2008
assets/FileCfg/TeleportConfigTemplateTb.json
Normal file
2008
assets/FileCfg/TeleportConfigTemplateTb.json
Normal file
File diff suppressed because it is too large
Load diff
|
@ -150,7 +150,7 @@
|
||||||
{
|
{
|
||||||
"gacha_schedule_id": 5001001,
|
"gacha_schedule_id": 5001001,
|
||||||
"gacha_parent_schedule_id": 5001,
|
"gacha_parent_schedule_id": 5001,
|
||||||
"comment": "1.0, Full, Persistent, Bangboo",
|
"comment": "1.1, Full, Persistent, Bangboo",
|
||||||
"gacha_type": 5,
|
"gacha_type": 5,
|
||||||
"cost_item_id": 112, // 邦布券
|
"cost_item_id": 112, // 邦布券
|
||||||
"start_time": "2024-07-04T06:00:00+08:00",
|
"start_time": "2024-07-04T06:00:00+08:00",
|
||||||
|
@ -168,6 +168,7 @@
|
||||||
],
|
],
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:Bangboo": {
|
"Standard:Bangboo": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_BANGBOO",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
54002, // 阿全
|
54002, // 阿全
|
||||||
54005, // 艾米莉安
|
54005, // 艾米莉安
|
||||||
|
@ -180,8 +181,10 @@
|
||||||
"category_weight": 1
|
"category_weight": 1
|
||||||
},
|
},
|
||||||
"Event-Exclusive:Bangboo": {
|
"Event-Exclusive:Bangboo": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_BANGBOO",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
54004, // 巴特勒
|
54004, // 巴特勒
|
||||||
|
54012, // 阿崔巡查
|
||||||
],
|
],
|
||||||
"is_promotional_items": true,
|
"is_promotional_items": true,
|
||||||
"category_weight": 1
|
"category_weight": 1
|
||||||
|
@ -199,6 +202,7 @@
|
||||||
],
|
],
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:Bangboo": {
|
"Standard:Bangboo": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_BANGBOO",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
53001, // 企鹅布
|
53001, // 企鹅布
|
||||||
53003, // 寻宝布
|
53003, // 寻宝布
|
||||||
|
@ -224,6 +228,7 @@
|
||||||
"probability_model_tag": "get-B",
|
"probability_model_tag": "get-B",
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:W-Engine": {
|
"Standard:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
12001, // 「月相」-望
|
12001, // 「月相」-望
|
||||||
12002, // 「月相」-晦
|
12002, // 「月相」-晦
|
||||||
|
@ -267,6 +272,7 @@
|
||||||
],
|
],
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:Agent": {
|
"Standard:Agent": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_CHARACTER",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
1021, // 猫又
|
1021, // 猫又
|
||||||
1101, // 珂蕾妲
|
1101, // 珂蕾妲
|
||||||
|
@ -278,6 +284,7 @@
|
||||||
"category_weight": 50
|
"category_weight": 50
|
||||||
},
|
},
|
||||||
"Event-Exclusive:Agent": {
|
"Event-Exclusive:Agent": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_CHARACTER",
|
||||||
"is_promotional_items": true,
|
"is_promotional_items": true,
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
1191, // 艾莲
|
1191, // 艾莲
|
||||||
|
@ -300,6 +307,7 @@
|
||||||
],
|
],
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:Agent": {
|
"Standard:Agent": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_CHARACTER",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
1011, // 安比
|
1011, // 安比
|
||||||
1031, // 妮可
|
1031, // 妮可
|
||||||
|
@ -312,6 +320,7 @@
|
||||||
"category_weight": 3525
|
"category_weight": 3525
|
||||||
},
|
},
|
||||||
"Event-Exclusive:Agent": {
|
"Event-Exclusive:Agent": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_CHARACTER",
|
||||||
"is_promotional_items": true,
|
"is_promotional_items": true,
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
1111, // 安东
|
1111, // 安东
|
||||||
|
@ -320,6 +329,7 @@
|
||||||
"category_weight": 3525
|
"category_weight": 3525
|
||||||
},
|
},
|
||||||
"Standard:W-Engine": {
|
"Standard:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
13001, // 街头巨星
|
13001, // 街头巨星
|
||||||
13002, // 时光切片
|
13002, // 时光切片
|
||||||
|
@ -352,6 +362,7 @@
|
||||||
"probability_model_tag": "get-B",
|
"probability_model_tag": "get-B",
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:W-Engine": {
|
"Standard:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
12001, // 「月相」-望
|
12001, // 「月相」-望
|
||||||
12002, // 「月相」-晦
|
12002, // 「月相」-晦
|
||||||
|
@ -398,6 +409,7 @@
|
||||||
],
|
],
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:W-Engine": {
|
"Standard:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
14102, // 钢铁肉垫
|
14102, // 钢铁肉垫
|
||||||
14110, // 燃狱齿轮
|
14110, // 燃狱齿轮
|
||||||
|
@ -409,6 +421,7 @@
|
||||||
"category_weight": 25
|
"category_weight": 25
|
||||||
},
|
},
|
||||||
"Event-Exclusive:W-Engine": {
|
"Event-Exclusive:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
14119, // 深海访客
|
14119, // 深海访客
|
||||||
],
|
],
|
||||||
|
@ -433,6 +446,7 @@
|
||||||
],
|
],
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:Agent": {
|
"Standard:Agent": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_CHARACTER",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
1011, // 安比
|
1011, // 安比
|
||||||
1031, // 妮可
|
1031, // 妮可
|
||||||
|
@ -447,6 +461,7 @@
|
||||||
"category_weight": 3750
|
"category_weight": 3750
|
||||||
},
|
},
|
||||||
"Standard:W-Engine": {
|
"Standard:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
13001, // 街头巨星
|
13001, // 街头巨星
|
||||||
13002, // 时光切片
|
13002, // 时光切片
|
||||||
|
@ -468,6 +483,7 @@
|
||||||
"category_weight": 13125
|
"category_weight": 13125
|
||||||
},
|
},
|
||||||
"Event-Exclusive:W-Engine": {
|
"Event-Exclusive:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
13113, // 含羞恶面
|
13113, // 含羞恶面
|
||||||
13111, // 旋钻机-赤轴
|
13111, // 旋钻机-赤轴
|
||||||
|
@ -485,6 +501,7 @@
|
||||||
"probability_model_tag": "get-B",
|
"probability_model_tag": "get-B",
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:W-Engine": {
|
"Standard:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
12001, // 「月相」-望
|
12001, // 「月相」-望
|
||||||
12002, // 「月相」-晦
|
12002, // 「月相」-晦
|
||||||
|
@ -528,6 +545,7 @@
|
||||||
],
|
],
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:Agent": {
|
"Standard:Agent": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_CHARACTER",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
1021, // 猫又
|
1021, // 猫又
|
||||||
1101, // 珂蕾妲
|
1101, // 珂蕾妲
|
||||||
|
@ -539,6 +557,7 @@
|
||||||
"category_weight": 50
|
"category_weight": 50
|
||||||
},
|
},
|
||||||
"Event-Exclusive:Agent": {
|
"Event-Exclusive:Agent": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_CHARACTER",
|
||||||
"is_promotional_items": true,
|
"is_promotional_items": true,
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
1241 // 朱鸢
|
1241 // 朱鸢
|
||||||
|
@ -558,6 +577,7 @@
|
||||||
],
|
],
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:Agent": {
|
"Standard:Agent": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_CHARACTER",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
1011, // 安比
|
1011, // 安比
|
||||||
1061, // 可琳
|
1061, // 可琳
|
||||||
|
@ -570,6 +590,7 @@
|
||||||
"category_weight": 3525
|
"category_weight": 3525
|
||||||
},
|
},
|
||||||
"Event-Exclusive:Agent": {
|
"Event-Exclusive:Agent": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_CHARACTER",
|
||||||
"is_promotional_items": true,
|
"is_promotional_items": true,
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
1031, // 妮可
|
1031, // 妮可
|
||||||
|
@ -578,6 +599,7 @@
|
||||||
"category_weight": 3525
|
"category_weight": 3525
|
||||||
},
|
},
|
||||||
"Standard:W-Engine": {
|
"Standard:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
13001, // 街头巨星
|
13001, // 街头巨星
|
||||||
13002, // 时光切片
|
13002, // 时光切片
|
||||||
|
@ -610,6 +632,7 @@
|
||||||
"probability_model_tag": "get-B",
|
"probability_model_tag": "get-B",
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:W-Engine": {
|
"Standard:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
12001, // 「月相」-望
|
12001, // 「月相」-望
|
||||||
12002, // 「月相」-晦
|
12002, // 「月相」-晦
|
||||||
|
@ -653,6 +676,7 @@
|
||||||
],
|
],
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:W-Engine": {
|
"Standard:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
14102, // 钢铁肉垫
|
14102, // 钢铁肉垫
|
||||||
14110, // 燃狱齿轮
|
14110, // 燃狱齿轮
|
||||||
|
@ -664,6 +688,7 @@
|
||||||
"category_weight": 25
|
"category_weight": 25
|
||||||
},
|
},
|
||||||
"Event-Exclusive:W-Engine": {
|
"Event-Exclusive:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
14124 // 防暴者VI型
|
14124 // 防暴者VI型
|
||||||
],
|
],
|
||||||
|
@ -683,6 +708,7 @@
|
||||||
],
|
],
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:Agent": {
|
"Standard:Agent": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_CHARACTER",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
1011, // 安比
|
1011, // 安比
|
||||||
1031, // 妮可
|
1031, // 妮可
|
||||||
|
@ -697,6 +723,7 @@
|
||||||
"category_weight": 3750
|
"category_weight": 3750
|
||||||
},
|
},
|
||||||
"Standard:W-Engine": {
|
"Standard:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
13007, // 正版变身器
|
13007, // 正版变身器
|
||||||
13002, // 时光切片
|
13002, // 时光切片
|
||||||
|
@ -718,6 +745,7 @@
|
||||||
"category_weight": 13125
|
"category_weight": 13125
|
||||||
},
|
},
|
||||||
"Event-Exclusive:W-Engine": {
|
"Event-Exclusive:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
13103, // 聚宝箱
|
13103, // 聚宝箱
|
||||||
13112, // 比格气缸
|
13112, // 比格气缸
|
||||||
|
@ -735,6 +763,7 @@
|
||||||
"probability_model_tag": "get-B",
|
"probability_model_tag": "get-B",
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:W-Engine": {
|
"Standard:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
12001, // 「月相」-望
|
12001, // 「月相」-望
|
||||||
12002, // 「月相」-晦
|
12002, // 「月相」-晦
|
||||||
|
@ -780,6 +809,7 @@
|
||||||
],
|
],
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:Agent": {
|
"Standard:Agent": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_CHARACTER",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
1021, // 猫又
|
1021, // 猫又
|
||||||
1101, // 珂蕾妲
|
1101, // 珂蕾妲
|
||||||
|
@ -791,6 +821,7 @@
|
||||||
"category_weight": 50
|
"category_weight": 50
|
||||||
},
|
},
|
||||||
"Event-Exclusive:Agent": {
|
"Event-Exclusive:Agent": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_CHARACTER",
|
||||||
"is_promotional_items": true,
|
"is_promotional_items": true,
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
1251, // 青衣
|
1251, // 青衣
|
||||||
|
@ -810,6 +841,7 @@
|
||||||
],
|
],
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:Agent": {
|
"Standard:Agent": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_CHARACTER",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
1011, // 安比
|
1011, // 安比
|
||||||
1031, // 妮可
|
1031, // 妮可
|
||||||
|
@ -823,6 +855,7 @@
|
||||||
"category_weight": 3525
|
"category_weight": 3525
|
||||||
},
|
},
|
||||||
"Event-Exclusive:Agent": {
|
"Event-Exclusive:Agent": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_CHARACTER",
|
||||||
"is_promotional_items": true,
|
"is_promotional_items": true,
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
1131, // 苍角
|
1131, // 苍角
|
||||||
|
@ -831,6 +864,7 @@
|
||||||
"category_weight": 3525
|
"category_weight": 3525
|
||||||
},
|
},
|
||||||
"Standard:W-Engine": {
|
"Standard:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
13001, // 街头巨星
|
13001, // 街头巨星
|
||||||
13002, // 时光切片
|
13002, // 时光切片
|
||||||
|
@ -864,6 +898,7 @@
|
||||||
"probability_model_tag": "get-B",
|
"probability_model_tag": "get-B",
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:W-Engine": {
|
"Standard:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
12001, // 「月相」-望
|
12001, // 「月相」-望
|
||||||
12002, // 「月相」-晦
|
12002, // 「月相」-晦
|
||||||
|
@ -907,6 +942,7 @@
|
||||||
],
|
],
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:W-Engine": {
|
"Standard:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
14102, // 钢铁肉垫
|
14102, // 钢铁肉垫
|
||||||
14110, // 燃狱齿轮
|
14110, // 燃狱齿轮
|
||||||
|
@ -918,6 +954,7 @@
|
||||||
"category_weight": 25
|
"category_weight": 25
|
||||||
},
|
},
|
||||||
"Event-Exclusive:W-Engine": {
|
"Event-Exclusive:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
14125, // 玉壶青冰
|
14125, // 玉壶青冰
|
||||||
],
|
],
|
||||||
|
@ -937,6 +974,7 @@
|
||||||
],
|
],
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:Agent": {
|
"Standard:Agent": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_CHARACTER",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
1011, // 安比
|
1011, // 安比
|
||||||
1031, // 妮可
|
1031, // 妮可
|
||||||
|
@ -949,6 +987,7 @@
|
||||||
"category_weight": 3750
|
"category_weight": 3750
|
||||||
},
|
},
|
||||||
"Standard:W-Engine": {
|
"Standard:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
13001, // 街头巨星
|
13001, // 街头巨星
|
||||||
13002, // 时光切片
|
13002, // 时光切片
|
||||||
|
@ -971,6 +1010,7 @@
|
||||||
"category_weight": 13125
|
"category_weight": 13125
|
||||||
},
|
},
|
||||||
"Event-Exclusive:W-Engine": {
|
"Event-Exclusive:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
13113, // 含羞恶面
|
13113, // 含羞恶面
|
||||||
13127, // 维序者-特化型
|
13127, // 维序者-特化型
|
||||||
|
@ -988,6 +1028,7 @@
|
||||||
"probability_model_tag": "get-B",
|
"probability_model_tag": "get-B",
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:W-Engine": {
|
"Standard:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
12001, // 「月相」-望
|
12001, // 「月相」-望
|
||||||
12002, // 「月相」-晦
|
12002, // 「月相」-晦
|
||||||
|
@ -1031,6 +1072,7 @@
|
||||||
],
|
],
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:Agent": {
|
"Standard:Agent": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_CHARACTER",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
1021, // 猫又
|
1021, // 猫又
|
||||||
1101, // 珂蕾妲
|
1101, // 珂蕾妲
|
||||||
|
@ -1042,6 +1084,7 @@
|
||||||
"category_weight": 50
|
"category_weight": 50
|
||||||
},
|
},
|
||||||
"Event-Exclusive:Agent": {
|
"Event-Exclusive:Agent": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_CHARACTER",
|
||||||
"is_promotional_items": true,
|
"is_promotional_items": true,
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
1261, // 简
|
1261, // 简
|
||||||
|
@ -1061,6 +1104,7 @@
|
||||||
],
|
],
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:Agent": {
|
"Standard:Agent": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_CHARACTER",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
1011, // 安比
|
1011, // 安比
|
||||||
1031, // 妮可
|
1031, // 妮可
|
||||||
|
@ -1074,6 +1118,7 @@
|
||||||
"category_weight": 3525
|
"category_weight": 3525
|
||||||
},
|
},
|
||||||
"Event-Exclusive:Agent": {
|
"Event-Exclusive:Agent": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_CHARACTER",
|
||||||
"is_promotional_items": true,
|
"is_promotional_items": true,
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
1271, // 赛斯
|
1271, // 赛斯
|
||||||
|
@ -1082,6 +1127,7 @@
|
||||||
"category_weight": 3525
|
"category_weight": 3525
|
||||||
},
|
},
|
||||||
"Standard:W-Engine": {
|
"Standard:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
13001, // 街头巨星
|
13001, // 街头巨星
|
||||||
13002, // 时光切片
|
13002, // 时光切片
|
||||||
|
@ -1115,6 +1161,7 @@
|
||||||
"probability_model_tag": "get-B",
|
"probability_model_tag": "get-B",
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:W-Engine": {
|
"Standard:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
12001, // 「月相」-望
|
12001, // 「月相」-望
|
||||||
12002, // 「月相」-晦
|
12002, // 「月相」-晦
|
||||||
|
@ -1158,6 +1205,7 @@
|
||||||
],
|
],
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:W-Engine": {
|
"Standard:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
14102, // 钢铁肉垫
|
14102, // 钢铁肉垫
|
||||||
14110, // 燃狱齿轮
|
14110, // 燃狱齿轮
|
||||||
|
@ -1169,6 +1217,7 @@
|
||||||
"category_weight": 25
|
"category_weight": 25
|
||||||
},
|
},
|
||||||
"Event-Exclusive:W-Engine": {
|
"Event-Exclusive:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
14126, // 淬锋钳刺
|
14126, // 淬锋钳刺
|
||||||
],
|
],
|
||||||
|
@ -1188,6 +1237,7 @@
|
||||||
],
|
],
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:Agent": {
|
"Standard:Agent": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_CHARACTER",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
1011, // 安比
|
1011, // 安比
|
||||||
1031, // 妮可
|
1031, // 妮可
|
||||||
|
@ -1200,6 +1250,7 @@
|
||||||
"category_weight": 3750
|
"category_weight": 3750
|
||||||
},
|
},
|
||||||
"Standard:W-Engine": {
|
"Standard:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
13001, // 街头巨星
|
13001, // 街头巨星
|
||||||
13002, // 时光切片
|
13002, // 时光切片
|
||||||
|
@ -1222,6 +1273,7 @@
|
||||||
"category_weight": 13125
|
"category_weight": 13125
|
||||||
},
|
},
|
||||||
"Event-Exclusive:W-Engine": {
|
"Event-Exclusive:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
13127, // 维序者-特化型
|
13127, // 维序者-特化型
|
||||||
13113, // 含羞恶面
|
13113, // 含羞恶面
|
||||||
|
@ -1239,6 +1291,7 @@
|
||||||
"probability_model_tag": "get-B",
|
"probability_model_tag": "get-B",
|
||||||
"categories": {
|
"categories": {
|
||||||
"Standard:W-Engine": {
|
"Standard:W-Engine": {
|
||||||
|
"item_type": "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
"item_ids": [
|
"item_ids": [
|
||||||
12001, // 「月相」-望
|
12001, // 「月相」-望
|
||||||
12002, // 「月相」-晦
|
12002, // 「月相」-晦
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
use chrono::{prelude::Local, DateTime};
|
use chrono::{prelude::Local, DateTime};
|
||||||
use proto::GachaAddedItemType;
|
|
||||||
use serde::{Deserialize, Deserializer};
|
use serde::{Deserialize, Deserializer};
|
||||||
use tracing;
|
use tracing;
|
||||||
|
|
||||||
|
@ -152,13 +151,64 @@ impl DiscountPolicyCollection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub enum GachaAddedItemType {
|
||||||
|
#[default]
|
||||||
|
None = 0,
|
||||||
|
Weapon = 1,
|
||||||
|
Character = 2,
|
||||||
|
Bangboo = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GachaAddedItemType {
|
||||||
|
pub fn as_str_name(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
GachaAddedItemType::None => "GACHA_ADDED_ITEM_TYPE_NONE",
|
||||||
|
GachaAddedItemType::Weapon => "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||||
|
GachaAddedItemType::Character => "GACHA_ADDED_ITEM_TYPE_CHARACTER",
|
||||||
|
GachaAddedItemType::Bangboo => "GACHA_ADDED_ITEM_TYPE_BANGBOO",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
|
||||||
|
match value {
|
||||||
|
"GACHA_ADDED_ITEM_TYPE_NONE" => Some(Self::None),
|
||||||
|
"GACHA_ADDED_ITEM_TYPE_WEAPON" => Some(Self::Weapon),
|
||||||
|
"GACHA_ADDED_ITEM_TYPE_CHARACTER" => Some(Self::Character),
|
||||||
|
"GACHA_ADDED_ITEM_TYPE_BANGBOO" => Some(Self::Bangboo),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<i32> for GachaAddedItemType {
|
||||||
|
fn from(value: i32) -> Self {
|
||||||
|
match value {
|
||||||
|
1 => Self::Weapon,
|
||||||
|
2 => Self::Character,
|
||||||
|
3 => Self::Bangboo,
|
||||||
|
_ => Self::None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<i32> for GachaAddedItemType {
|
||||||
|
fn into(self) -> i32 {
|
||||||
|
match self {
|
||||||
|
Self::Weapon => 1,
|
||||||
|
Self::Character => 2,
|
||||||
|
Self::Bangboo => 3,
|
||||||
|
Self::None => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Deserialize)]
|
#[derive(Debug, Default, Deserialize)]
|
||||||
pub struct GachaCategoryInfo {
|
pub struct GachaCategoryInfo {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub is_promotional_items: bool,
|
pub is_promotional_items: bool,
|
||||||
pub item_ids: Vec<u32>,
|
pub item_ids: Vec<u32>,
|
||||||
pub category_weight: u32,
|
pub category_weight: u32,
|
||||||
#[serde(default, deserialize_with = "from_str")]
|
#[serde(deserialize_with = "from_str")]
|
||||||
pub item_type: GachaAddedItemType,
|
pub item_type: GachaAddedItemType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
10
nap_data/src/tables/item_template.rs
Normal file
10
nap_data/src/tables/item_template.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
template_id!(Item u32 id);
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "PascalCase")]
|
||||||
|
pub struct ItemTemplate {
|
||||||
|
#[serde(rename = "ID")]
|
||||||
|
pub id: ItemID,
|
||||||
|
}
|
|
@ -94,4 +94,8 @@ template_tables! {
|
||||||
SubAreaDataTemplate;
|
SubAreaDataTemplate;
|
||||||
VariableDataTemplate;
|
VariableDataTemplate;
|
||||||
OnceRewardTemplate;
|
OnceRewardTemplate;
|
||||||
|
QuickAccessTemplate;
|
||||||
|
QuickFuncTemplate;
|
||||||
|
TeleportConfigTemplate;
|
||||||
|
ItemTemplate;
|
||||||
}
|
}
|
||||||
|
|
11
nap_data/src/tables/quick_access_template.rs
Normal file
11
nap_data/src/tables/quick_access_template.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
template_id!(QuickAccess u32 quick_func_id);
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "PascalCase")]
|
||||||
|
pub struct QuickAccessTemplate {
|
||||||
|
pub quick_access_index: u32,
|
||||||
|
#[serde(rename = "QuickFuncID")]
|
||||||
|
pub quick_func_id: QuickAccessID,
|
||||||
|
}
|
10
nap_data/src/tables/quick_func_template.rs
Normal file
10
nap_data/src/tables/quick_func_template.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
template_id!(QuickFunc u32 btn_id);
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "PascalCase")]
|
||||||
|
pub struct QuickFuncTemplate {
|
||||||
|
#[serde(rename = "BtnID")]
|
||||||
|
pub btn_id: QuickFuncID,
|
||||||
|
}
|
11
nap_data/src/tables/teleport_config_template.rs
Normal file
11
nap_data/src/tables/teleport_config_template.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
template_id!(TeleportConfig i32 teleport_id);
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "PascalCase")]
|
||||||
|
pub struct TeleportConfigTemplate {
|
||||||
|
#[serde(rename = "TeleportID")]
|
||||||
|
pub teleport_id: TeleportConfigID,
|
||||||
|
pub client_visible: u32,
|
||||||
|
}
|
125
nap_gameserver/src/commands/gacha.rs
Normal file
125
nap_gameserver/src/commands/gacha.rs
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
use data::{gacha::global_gacha_config, tables::ItemID};
|
||||||
|
|
||||||
|
use crate::ServerState;
|
||||||
|
|
||||||
|
use super::ArgSlice;
|
||||||
|
|
||||||
|
pub async fn up(
|
||||||
|
args: ArgSlice<'_>,
|
||||||
|
state: &ServerState,
|
||||||
|
) -> Result<String, Box<dyn std::error::Error>> {
|
||||||
|
const USAGE: &str = "Usage: gacha up [player_uid] (start a gacha UP setting guide (available for Bangboo pool))";
|
||||||
|
|
||||||
|
if args.len() == 0 {
|
||||||
|
return Ok(USAGE.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let uid = args[0].parse::<u32>()?;
|
||||||
|
|
||||||
|
let Some(player_lock) = state.player_mgr.get_player(uid).await else {
|
||||||
|
return Ok(String::from("player not found"));
|
||||||
|
};
|
||||||
|
|
||||||
|
let gachaconf = global_gacha_config();
|
||||||
|
let pool_list: Vec<(u32, &String)> = gachaconf
|
||||||
|
.character_gacha_pool_list
|
||||||
|
.iter()
|
||||||
|
.filter(|pool| {
|
||||||
|
pool.gacha_items.iter().any(|rarity_items| {
|
||||||
|
rarity_items
|
||||||
|
.category_guarantee_policy_tags
|
||||||
|
.iter()
|
||||||
|
.map(|tag| gachaconf.category_guarantee_policy_map.get(tag).unwrap())
|
||||||
|
.any(|policy| policy.chooseable)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.map(|pool| (pool.gacha_schedule_id, &pool.comment))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
if args.len() == 1 {
|
||||||
|
return Ok(format!(
|
||||||
|
"{}\n{}\n{}",
|
||||||
|
"Choose a target gacha pool first:",
|
||||||
|
pool_list
|
||||||
|
.iter()
|
||||||
|
.map(|(id, comment)| format!("- gacha_schedule_id: {id} ({comment})"))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n"),
|
||||||
|
"Use 'gacha up [player_uid] [gacha_schedule_id]' to continue."
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let target_pool_id = args[1].parse::<u32>()?;
|
||||||
|
let accepted_pool_id_list = pool_list.into_iter().map(|(id, _)| id).collect::<Vec<_>>();
|
||||||
|
if !accepted_pool_id_list.contains(&target_pool_id) {
|
||||||
|
return Ok(String::from("Gacha Pool not found or not allowed to set UP. Use gacha up [player_uid] to view available pool ids."));
|
||||||
|
}
|
||||||
|
let target_pool = gachaconf
|
||||||
|
.character_gacha_pool_list
|
||||||
|
.iter()
|
||||||
|
.filter(|pool| pool.gacha_schedule_id == target_pool_id)
|
||||||
|
.last()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let chooseable_items: Vec<(ItemID, &String)> = target_pool
|
||||||
|
.gacha_items
|
||||||
|
.iter()
|
||||||
|
.filter(|rarity_items| {
|
||||||
|
rarity_items
|
||||||
|
.category_guarantee_policy_tags
|
||||||
|
.iter()
|
||||||
|
.map(|tag| gachaconf.category_guarantee_policy_map.get(tag).unwrap())
|
||||||
|
.any(|policy| policy.chooseable)
|
||||||
|
})
|
||||||
|
.map(|items| {
|
||||||
|
items
|
||||||
|
.categories
|
||||||
|
.iter()
|
||||||
|
.map(|(category_tag, category)| {
|
||||||
|
category
|
||||||
|
.item_ids
|
||||||
|
.iter()
|
||||||
|
.map(|id| (ItemID::new_unchecked(id.clone()), category_tag))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.concat()
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.concat();
|
||||||
|
if args.len() == 2 {
|
||||||
|
return Ok(format!(
|
||||||
|
"{}\n{}\nUse 'gacha up [player_uid] {target_pool_id} [item_id]' to set your UP.",
|
||||||
|
"Choose the UP item you want:",
|
||||||
|
chooseable_items
|
||||||
|
.iter()
|
||||||
|
.map(|(item_id, category_tag)| format!("- ID {item_id} (category: {category_tag})"))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let accepted_ids = chooseable_items
|
||||||
|
.iter()
|
||||||
|
.map(|(item_id, _)| item_id.value())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let item_id = args[2].parse::<u32>()?;
|
||||||
|
if !accepted_ids.contains(&item_id) {
|
||||||
|
return Ok(format!("Item ID not found or not included in UP list. Use gacha up [player_uid] {target_pool_id} to view available item ids."));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut player = player_lock.lock().await;
|
||||||
|
if player
|
||||||
|
.gacha_model
|
||||||
|
.choose_gacha_up(target_pool, &ItemID::new_unchecked(item_id))
|
||||||
|
{
|
||||||
|
Ok(format!(
|
||||||
|
"successfully set your gacha pool: {} (comment: {}) 100% UP to {item_id}. Close & Open Gacha Page to see result.",
|
||||||
|
target_pool.gacha_schedule_id, target_pool.comment
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(format!(
|
||||||
|
"failed to set your gacha pool: {} (comment: {}) 100% UP to {item_id} (unexpected maybe bug)",
|
||||||
|
target_pool.gacha_schedule_id, target_pool.comment
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ use rustyline_async::{Readline, ReadlineEvent, SharedWriter};
|
||||||
use crate::ServerState;
|
use crate::ServerState;
|
||||||
|
|
||||||
mod avatar;
|
mod avatar;
|
||||||
|
mod gacha;
|
||||||
mod item;
|
mod item;
|
||||||
mod player;
|
mod player;
|
||||||
|
|
||||||
|
@ -88,5 +89,6 @@ impl CommandManager {
|
||||||
avatar::add "[player_uid] [avatar_id]" "gives avatar with specified id to player";
|
avatar::add "[player_uid] [avatar_id]" "gives avatar with specified id to player";
|
||||||
item::add_weapon "[player_uid] [weapon_id]" "gives weapon with specified id to player";
|
item::add_weapon "[player_uid] [weapon_id]" "gives weapon with specified id to player";
|
||||||
player::kick "[player_uid] [reason]" "kick the specified player (reason is optional)";
|
player::kick "[player_uid] [reason]" "kick the specified player (reason is optional)";
|
||||||
|
gacha::up "[player_uid]" "start a gacha UP setting guide (available for Bangboo pool)";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::logic::{EOperator, ESystem};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use data::tables;
|
use data::tables::{self, QuickFuncID};
|
||||||
|
|
||||||
pub async fn on_get_tips_info(
|
pub async fn on_get_tips_info(
|
||||||
_session: &NetSession,
|
_session: &NetSession,
|
||||||
|
@ -21,23 +21,34 @@ pub async fn on_get_client_systems_info(
|
||||||
player: &mut Player,
|
player: &mut Player,
|
||||||
_req: GetClientSystemsInfoCsReq,
|
_req: GetClientSystemsInfoCsReq,
|
||||||
) -> NetResult<GetClientSystemsInfoScRsp> {
|
) -> NetResult<GetClientSystemsInfoScRsp> {
|
||||||
Ok(GetClientSystemsInfoScRsp {
|
let mut post_girl_data = PostGirlData {
|
||||||
retcode: Retcode::RetSucc.into(),
|
|
||||||
info: Some(ClientSystemsInfo {
|
|
||||||
post_girl_data: Some(PostGirlData {
|
|
||||||
selected_post_girl_id_list: tables::post_girl_config_template_tb::iter()
|
|
||||||
.map(|template| template.id.value())
|
|
||||||
.collect(),
|
|
||||||
post_girl_list: tables::post_girl_config_template_tb::iter()
|
post_girl_list: tables::post_girl_config_template_tb::iter()
|
||||||
.map(|template| PostGirlItem {
|
.map(|template| PostGirlItem {
|
||||||
template_id: template.id.value(),
|
template_id: template.id.value(),
|
||||||
unlock_time: 1000,
|
unlock_time: 1720052644,
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
};
|
||||||
|
if let Some(post_girl_id) = player.basic_data_model.selected_post_girl_id {
|
||||||
|
post_girl_data
|
||||||
|
.selected_post_girl_id_list
|
||||||
|
.push(post_girl_id.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(GetClientSystemsInfoScRsp {
|
||||||
|
retcode: Retcode::RetSucc.into(),
|
||||||
|
info: Some(ClientSystemsInfo {
|
||||||
|
post_girl_data: Some(post_girl_data),
|
||||||
unlock_data: Some(player.lock_model.to_client()),
|
unlock_data: Some(player.lock_model.to_client()),
|
||||||
hbhfjgbahgf: Some(Aboegnnepmi::default()),
|
calling_card_data: Some(CallingCardData::default()),
|
||||||
|
teleport_data: Some(TeleportData {
|
||||||
|
unlock_id_list: tables::teleport_config_template_tb::iter()
|
||||||
|
.filter(|template| template.client_visible > 0)
|
||||||
|
.map(|template| template.teleport_id.value())
|
||||||
|
.collect(),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
@ -183,3 +194,70 @@ pub async fn on_interact_with_scene_object(
|
||||||
retcode: Retcode::RetSucc.into(),
|
retcode: Retcode::RetSucc.into(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn on_mod_quick_menu(
|
||||||
|
_session: &NetSession,
|
||||||
|
_player: &mut Player,
|
||||||
|
_req: ModQuickMenuCsReq,
|
||||||
|
) -> NetResult<ModQuickMenuScRsp> {
|
||||||
|
let mut quick_access_data_list: Vec<QuickAccessData> = vec![];
|
||||||
|
for data in _req.quick_access_data_list.iter() {
|
||||||
|
quick_access_data_list.push(
|
||||||
|
_player
|
||||||
|
.lock_model
|
||||||
|
.mod_quick_access(data.quick_access_index, QuickFuncID::new(data.btn_id)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_session
|
||||||
|
.notify(PlayerSyncScNotify {
|
||||||
|
client_systems_sync: Some(ClientSystemsSync {
|
||||||
|
quick_access_data_list: _player.lock_model.quick_access_to_client(),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(ModQuickMenuScRsp {
|
||||||
|
retcode: Retcode::RetSucc.into(),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn on_change_post_girl(
|
||||||
|
_session: &NetSession,
|
||||||
|
_player: &mut Player,
|
||||||
|
_req: ChangePostGirlCsReq,
|
||||||
|
) -> NetResult<ChangePostGirlScRsp> {
|
||||||
|
if _req.new_selected_post_girl_id_list.len() != 1 {
|
||||||
|
return Ok(ChangePostGirlScRsp {
|
||||||
|
retcode: Retcode::RetFail.into(),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
};
|
||||||
|
match tables::PostGirlConfigID::new(*_req.new_selected_post_girl_id_list.get(0).unwrap()) {
|
||||||
|
Some(post_girl_id) => {
|
||||||
|
_player.basic_data_model.selected_post_girl_id = Some(post_girl_id);
|
||||||
|
_session
|
||||||
|
.notify(PlayerSyncScNotify {
|
||||||
|
client_systems_sync: Some(ClientSystemsSync {
|
||||||
|
post_girl_data: Some(PostGirlSync {
|
||||||
|
selected_post_girl_id_list: vec![post_girl_id.value()],
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
Ok(ChangePostGirlScRsp {
|
||||||
|
retcode: Retcode::RetSucc.into(),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
None => Ok(ChangePostGirlScRsp {
|
||||||
|
retcode: Retcode::RetFail.into(),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,19 +1,18 @@
|
||||||
use std::{
|
|
||||||
cmp::min,
|
|
||||||
collections::{
|
|
||||||
hash_map::Entry::{Occupied, Vacant},
|
|
||||||
HashSet,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
use data::{
|
use data::{
|
||||||
gacha::{gacha_config::*, global_gacha_config},
|
gacha::{
|
||||||
tables::{AvatarBaseID, WeaponID},
|
gacha_config::{CharacterGachaPool, GachaAddedItemType},
|
||||||
|
global_gacha_config,
|
||||||
|
},
|
||||||
|
tables::{AvatarBaseID, ItemID, WeaponID},
|
||||||
};
|
};
|
||||||
|
use proto::{GainItemInfo, GetGachaDataScRsp};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::{
|
||||||
|
handlers::core::NetError,
|
||||||
|
logic::{item::ItemModel, role::RoleModel},
|
||||||
|
};
|
||||||
use chrono::{DateTime, Local};
|
use chrono::{DateTime, Local};
|
||||||
use proto::*;
|
|
||||||
|
|
||||||
pub async fn on_get_gacha_data(
|
pub async fn on_get_gacha_data(
|
||||||
_session: &NetSession,
|
_session: &NetSession,
|
||||||
|
@ -32,7 +31,7 @@ pub async fn on_get_gacha_data(
|
||||||
Ok(GetGachaDataScRsp {
|
Ok(GetGachaDataScRsp {
|
||||||
retcode: Retcode::RetSucc.into(),
|
retcode: Retcode::RetSucc.into(),
|
||||||
gacha_type: req.gacha_type,
|
gacha_type: req.gacha_type,
|
||||||
gacha_data: Some(generate_all_gacha_info(_player, &Local::now())),
|
gacha_data: Some(_player.gacha_model.to_client(&Local::now())),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,101 +50,58 @@ pub async fn on_do_gacha(
|
||||||
&gachaconf.character_gacha_pool_list,
|
&gachaconf.character_gacha_pool_list,
|
||||||
&req.gacha_parent_schedule_id,
|
&req.gacha_parent_schedule_id,
|
||||||
&pull_time,
|
&pull_time,
|
||||||
);
|
)?;
|
||||||
if let None = target_pool {
|
|
||||||
tracing::info!(
|
|
||||||
"refuse gacha because: pool of parent_schedule_id {} not found",
|
|
||||||
req.gacha_parent_schedule_id
|
|
||||||
);
|
|
||||||
return Ok(DoGachaScRsp {
|
|
||||||
retcode: Retcode::RetFail.into(),
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
};
|
|
||||||
let target_pool = target_pool.unwrap();
|
|
||||||
|
|
||||||
// tracing::info!("cost_item_count: {}", req.cost_item_count);
|
// tracing::info!("cost_item_count: {}", req.cost_item_count);
|
||||||
let mut pull_count = if req.cost_item_count > 1 { 10 } else { 1 };
|
let pull_count = if req.cost_item_count > 1 { 10 } else { 1 };
|
||||||
let cost_count = pull_count;
|
let mut cost_count = gacha_model.get_actual_cost_count(target_pool, &pull_count);
|
||||||
|
if pull_count != req.cost_item_count {
|
||||||
if pull_count == 10 {
|
|
||||||
let discount_tag = &gachaconf.common_properties.ten_pull_discount_tag;
|
|
||||||
if target_pool.discount_policy_tags.contains(&discount_tag) {
|
|
||||||
let gacha_bin = &mut gacha_model.gacha_bin;
|
|
||||||
let status_bin = gacha_bin
|
|
||||||
.gacha_status_map
|
|
||||||
.get_mut(&target_pool.sharing_guarantee_info_category)
|
|
||||||
.unwrap();
|
|
||||||
let discount_policy = gachaconf
|
|
||||||
.discount_policies
|
|
||||||
.ten_pull_discount_map
|
|
||||||
.get(discount_tag)
|
|
||||||
.unwrap();
|
|
||||||
let usage = status_bin.discount_usage_map.get_mut(discount_tag).unwrap();
|
|
||||||
if *usage < discount_policy.use_limit {
|
|
||||||
*usage += 1;
|
|
||||||
// cost_count = discount_policy.discounted_prize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if cost_count != req.cost_item_count {
|
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
"refuse gacha because: expected cost item {cost_count}, found {}",
|
"refuse gacha because: expected cost item {cost_count}, found {}",
|
||||||
req.cost_item_count
|
req.cost_item_count
|
||||||
);
|
);
|
||||||
return Ok(DoGachaScRsp {
|
return Err(NetError::from(Retcode::RetFail));
|
||||||
retcode: Retcode::RetFail.into(),
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
// TODO: cost resource
|
// TODO: cost resource
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut gain_item_list: Vec<GainItemInfo> = vec![];
|
let mut gain_item_list: Vec<GainItemInfo> = vec![];
|
||||||
while pull_count > 0 {
|
while cost_count > 0 {
|
||||||
let pull_result = gacha_model.perform_pull_pool(&pull_time, target_pool);
|
let pull_result = gacha_model.perform_pull_pool(&pull_time, target_pool);
|
||||||
let extra_item_bin = pull_result.extra_item_bin.clone().unwrap();
|
|
||||||
let uid = match GachaAddedItemType::try_from(pull_result.item_type) {
|
let uid = add_item(
|
||||||
Ok(enum_val) => match enum_val {
|
role_model,
|
||||||
GachaAddedItemType::Weapon => match WeaponID::new(pull_result.obtained_item_id) {
|
item_model,
|
||||||
Some(id) => item_model.add_weapon(id).value(),
|
&pull_result.obtained_item_id,
|
||||||
None => 0,
|
&pull_result.item_type,
|
||||||
},
|
)?;
|
||||||
GachaAddedItemType::Character => {
|
let (mut extra_item_id, mut extra_item_count) = (0, 0);
|
||||||
match AvatarBaseID::new(pull_result.obtained_item_id) {
|
if let Some(extra_resources) = &pull_result.extra_resources {
|
||||||
Some(id) => {
|
(extra_item_id, extra_item_count) = (
|
||||||
role_model.add_avatar(id);
|
extra_resources.extra_item_id.value(),
|
||||||
0
|
extra_resources.extra_item_count.clone(),
|
||||||
}
|
|
||||||
None => 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => 0,
|
|
||||||
},
|
|
||||||
Err(_err) => 0,
|
|
||||||
};
|
|
||||||
if extra_item_bin.extra_item_id != 0 {
|
|
||||||
item_model.add_resource(
|
|
||||||
extra_item_bin.extra_item_id,
|
|
||||||
extra_item_bin.extra_item_count,
|
|
||||||
);
|
);
|
||||||
|
item_model.add_resource(extra_item_id, extra_item_count);
|
||||||
}
|
}
|
||||||
gain_item_list.push(GainItemInfo {
|
gain_item_list.push(GainItemInfo {
|
||||||
item_id: pull_result.obtained_item_id,
|
item_id: pull_result.obtained_item_id.value(),
|
||||||
extra_item_id: extra_item_bin.extra_item_id,
|
extra_item_id,
|
||||||
extra_item_count: extra_item_bin.extra_item_count,
|
extra_item_count,
|
||||||
uid,
|
uid,
|
||||||
num: 1,
|
num: 1,
|
||||||
..GainItemInfo::default()
|
..GainItemInfo::default()
|
||||||
});
|
});
|
||||||
pull_count -= 1;
|
cost_count -= 1;
|
||||||
gacha_model.gacha_bin.gacha_records.push(pull_result);
|
gacha_model.gacha_records.push(pull_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_session
|
||||||
|
.notify(construct_sync(role_model, item_model))
|
||||||
|
.await?;
|
||||||
Ok(DoGachaScRsp {
|
Ok(DoGachaScRsp {
|
||||||
retcode: Retcode::RetSucc.into(),
|
retcode: Retcode::RetSucc.into(),
|
||||||
gain_item_list,
|
gain_item_list,
|
||||||
gacha_data: Some(generate_all_gacha_info(_player, &pull_time)),
|
gacha_data: Some(gacha_model.to_client(&pull_time)),
|
||||||
cost_item_count: req.cost_item_count,
|
cost_item_count: req.cost_item_count,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -156,123 +112,31 @@ pub async fn on_gacha_free_agent(
|
||||||
req: GachaFreeAgentCsReq,
|
req: GachaFreeAgentCsReq,
|
||||||
) -> NetResult<GachaFreeAgentScRsp> {
|
) -> NetResult<GachaFreeAgentScRsp> {
|
||||||
let gachaconf = global_gacha_config();
|
let gachaconf = global_gacha_config();
|
||||||
|
let gacha_model = &mut _player.gacha_model;
|
||||||
let role_model = &mut _player.role_model;
|
let role_model = &mut _player.role_model;
|
||||||
|
let item_model = &mut _player.item_model;
|
||||||
let pull_time = Local::now();
|
let pull_time = Local::now();
|
||||||
let target_pool = get_gacha_pool(
|
let target_pool = get_gacha_pool(
|
||||||
&gachaconf.character_gacha_pool_list,
|
&gachaconf.character_gacha_pool_list,
|
||||||
&req.gacha_parent_schedule_id,
|
&req.gacha_parent_schedule_id,
|
||||||
&pull_time,
|
&pull_time,
|
||||||
);
|
)?;
|
||||||
if let None = target_pool {
|
|
||||||
tracing::info!(
|
|
||||||
"refuse free agent because: pool of parent_schedule_id {} not found",
|
|
||||||
req.gacha_parent_schedule_id
|
|
||||||
);
|
|
||||||
return Ok(GachaFreeAgentScRsp {
|
|
||||||
retcode: Retcode::RetFail.into(),
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
};
|
|
||||||
let target_pool = target_pool.unwrap();
|
|
||||||
let gacha_bin = &mut _player.gacha_model.gacha_bin;
|
|
||||||
let sharing_guarantee_category_tag = &target_pool.sharing_guarantee_info_category;
|
|
||||||
let status_bin = gacha_bin
|
|
||||||
.gacha_status_map
|
|
||||||
.get_mut(sharing_guarantee_category_tag)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut free_select_policy: Option<&FreeSelectItem> = None;
|
let item_id = ItemID::new(req.avatar_id);
|
||||||
let mut free_select_progress: u32 = 0;
|
if let None = item_id {
|
||||||
let mut free_select_required_pull: u32 = 0;
|
return Err(NetError::from(Retcode::RetFail));
|
||||||
for discount_policy_tag in target_pool.discount_policy_tags.iter() {
|
|
||||||
if gachaconf
|
|
||||||
.discount_policies
|
|
||||||
.free_select_map
|
|
||||||
.contains_key(discount_policy_tag)
|
|
||||||
{
|
|
||||||
let policy = gachaconf
|
|
||||||
.discount_policies
|
|
||||||
.free_select_map
|
|
||||||
.get(discount_policy_tag)
|
|
||||||
.unwrap();
|
|
||||||
let free_select_demand_idx = usize::try_from(
|
|
||||||
*(status_bin
|
|
||||||
.discount_usage_map
|
|
||||||
.get(&policy.free_select_usage_record_tag)
|
|
||||||
.unwrap()),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
if policy.milestones.len() <= free_select_demand_idx {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
let item_id = item_id.unwrap();
|
||||||
|
|
||||||
let free_select_actual_progress = status_bin
|
let item_type = gacha_model.request_free_agent(target_pool, &item_id);
|
||||||
.discount_usage_map
|
if item_type == GachaAddedItemType::None {
|
||||||
.get(&policy.free_select_progress_record_tag)
|
return Err(NetError::from(Retcode::RetFail));
|
||||||
.unwrap();
|
|
||||||
free_select_policy = Some(policy);
|
|
||||||
free_select_required_pull = policy
|
|
||||||
.milestones
|
|
||||||
.get(free_select_demand_idx)
|
|
||||||
.unwrap()
|
|
||||||
.to_owned();
|
|
||||||
free_select_progress = min(free_select_required_pull, *free_select_actual_progress);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
let _ = add_item(role_model, item_model, &item_id, &item_type);
|
||||||
|
|
||||||
if let None = free_select_policy {
|
_session
|
||||||
tracing::info!(
|
.notify(construct_sync(role_model, item_model))
|
||||||
"refuse free agent because: pool of parent_schedule_id {} hasn't defined free agent discount yet (or used up chance)",
|
.await?;
|
||||||
req.gacha_parent_schedule_id
|
|
||||||
);
|
|
||||||
return Ok(GachaFreeAgentScRsp {
|
|
||||||
retcode: Retcode::RetFail.into(),
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
} else if free_select_progress < free_select_required_pull {
|
|
||||||
tracing::info!(
|
|
||||||
"refuse free agent because: use pulled {free_select_progress} (after last free agent) in parent_schedule_id {}, required {free_select_required_pull}",
|
|
||||||
req.gacha_parent_schedule_id
|
|
||||||
);
|
|
||||||
return Ok(GachaFreeAgentScRsp {
|
|
||||||
retcode: Retcode::RetFail.into(),
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let free_select_policy = free_select_policy.unwrap();
|
|
||||||
let mut has_demanded_item = false;
|
|
||||||
for rarity_items in target_pool.gacha_items.iter() {
|
|
||||||
if rarity_items.rarity != free_select_policy.rarity {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (category_tag, category) in rarity_items.categories.iter() {
|
|
||||||
if !free_select_policy.category_tags.contains(category_tag) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
has_demanded_item |= category.item_ids.contains(&req.avatar_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !has_demanded_item {
|
|
||||||
tracing::info!(
|
|
||||||
"refuse free agent because: pool of parent_schedule_id {} doesn't have demanded item {}",
|
|
||||||
req.gacha_parent_schedule_id, req.avatar_id
|
|
||||||
);
|
|
||||||
return Ok(GachaFreeAgentScRsp {
|
|
||||||
retcode: Retcode::RetFail.into(),
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
role_model.add_avatar(AvatarBaseID::new(req.avatar_id).unwrap());
|
|
||||||
(*status_bin
|
|
||||||
.discount_usage_map
|
|
||||||
.get_mut(&free_select_policy.free_select_usage_record_tag)
|
|
||||||
.unwrap()) += 1;
|
|
||||||
(*status_bin
|
|
||||||
.discount_usage_map
|
|
||||||
.get_mut(&free_select_policy.free_select_progress_record_tag)
|
|
||||||
.unwrap()) -= free_select_required_pull;
|
|
||||||
|
|
||||||
Ok(GachaFreeAgentScRsp {
|
Ok(GachaFreeAgentScRsp {
|
||||||
retcode: Retcode::RetSucc.into(),
|
retcode: Retcode::RetSucc.into(),
|
||||||
})
|
})
|
||||||
|
@ -290,330 +154,82 @@ pub async fn on_choose_gacha_up(
|
||||||
&gachaconf.character_gacha_pool_list,
|
&gachaconf.character_gacha_pool_list,
|
||||||
&req.gacha_parent_schedule_id,
|
&req.gacha_parent_schedule_id,
|
||||||
&pull_time,
|
&pull_time,
|
||||||
);
|
)?;
|
||||||
if let None = target_pool {
|
|
||||||
return Ok(ChooseGachaUpScRsp {
|
|
||||||
retcode: Retcode::RetFail.into(),
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
};
|
|
||||||
let target_pool = target_pool.unwrap();
|
|
||||||
|
|
||||||
for rarity_items in target_pool.gacha_items.iter() {
|
let item_id = ItemID::new(req.item_id);
|
||||||
if rarity_items.rarity != gachaconf.common_properties.s_item_rarity {
|
if let None = item_id {
|
||||||
continue;
|
return Err(NetError::from(Retcode::RetFail));
|
||||||
}
|
|
||||||
for guarantee_policy_tag in rarity_items.category_guarantee_policy_tags.iter() {
|
|
||||||
let category_guarantee_policy = gachaconf
|
|
||||||
.category_guarantee_policy_map
|
|
||||||
.get(guarantee_policy_tag)
|
|
||||||
.unwrap();
|
|
||||||
if !category_guarantee_policy.chooseable {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let mut up_category: Option<&String> = None;
|
|
||||||
for (category_tag, category) in rarity_items.categories.iter() {
|
|
||||||
if category.item_ids.contains(&req.item_id) {
|
|
||||||
up_category = Some(category_tag);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let None = up_category {
|
|
||||||
return Ok(ChooseGachaUpScRsp {
|
|
||||||
retcode: Retcode::RetFail.into(),
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
};
|
|
||||||
let up_category = up_category.unwrap();
|
|
||||||
|
|
||||||
let progress_bin = gacha_model
|
|
||||||
.gacha_bin
|
|
||||||
.gacha_status_map
|
|
||||||
.get_mut(&target_pool.sharing_guarantee_info_category)
|
|
||||||
.unwrap()
|
|
||||||
.rarity_status_map
|
|
||||||
.get_mut(&rarity_items.rarity)
|
|
||||||
.unwrap();
|
|
||||||
match progress_bin
|
|
||||||
.categories_chosen_guarantee_item_map
|
|
||||||
.entry(guarantee_policy_tag.clone())
|
|
||||||
{
|
|
||||||
Occupied(mut occupied_entry) => {
|
|
||||||
occupied_entry.insert(req.item_id);
|
|
||||||
}
|
|
||||||
Vacant(vacant_entry) => {
|
|
||||||
vacant_entry.insert(req.item_id);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
match progress_bin
|
|
||||||
.categories_chosen_guarantee_category_map
|
|
||||||
.entry(up_category.clone())
|
|
||||||
{
|
|
||||||
Occupied(mut occupied_entry) => {
|
|
||||||
occupied_entry.insert(up_category.clone());
|
|
||||||
}
|
|
||||||
Vacant(vacant_entry) => {
|
|
||||||
vacant_entry.insert(up_category.clone());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return Ok(ChooseGachaUpScRsp {
|
|
||||||
retcode: Retcode::RetSucc.into(),
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
let item_id = item_id.unwrap();
|
||||||
|
|
||||||
Ok(ChooseGachaUpScRsp {
|
Ok(ChooseGachaUpScRsp {
|
||||||
retcode: Retcode::RetFail.into(),
|
retcode: if gacha_model.choose_gacha_up(target_pool, &item_id) {
|
||||||
|
Retcode::RetSucc.into()
|
||||||
|
} else {
|
||||||
|
Retcode::RetFail.into()
|
||||||
|
},
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn generate_gacha_info_from_pool(
|
|
||||||
gacha_bin: &GachaModelBin,
|
|
||||||
target_pool: &CharacterGachaPool,
|
|
||||||
common_properties: &GachaCommonProperties,
|
|
||||||
) -> Gacha {
|
|
||||||
let gachaconf = data::gacha::global_gacha_config();
|
|
||||||
let sharing_guarantee_category_tag = &target_pool.sharing_guarantee_info_category;
|
|
||||||
let status_bin = gacha_bin
|
|
||||||
.gacha_status_map
|
|
||||||
.get(sharing_guarantee_category_tag)
|
|
||||||
.unwrap();
|
|
||||||
let pity_s = status_bin
|
|
||||||
.rarity_status_map
|
|
||||||
.get(&common_properties.s_item_rarity)
|
|
||||||
.unwrap()
|
|
||||||
.pity;
|
|
||||||
let pity_a = status_bin
|
|
||||||
.rarity_status_map
|
|
||||||
.get(&common_properties.a_item_rarity)
|
|
||||||
.unwrap()
|
|
||||||
.pity;
|
|
||||||
|
|
||||||
let mut discount_ten_roll_prize: u32 = 0;
|
|
||||||
let mut discount_avaliable_num: u32 = 0;
|
|
||||||
let mut advanced_s_guarantee: u32 = 0;
|
|
||||||
let mut free_select_progress: u32 = 0;
|
|
||||||
let mut free_select_required_pull: u32 = 0;
|
|
||||||
let mut free_select_policy: Option<&FreeSelectItem> = None;
|
|
||||||
for discount_policy_tag in target_pool.discount_policy_tags.iter() {
|
|
||||||
if common_properties.newcomer_advanced_s_tag == *discount_policy_tag {
|
|
||||||
let policy = gachaconf
|
|
||||||
.discount_policies
|
|
||||||
.advanced_guarantee_map
|
|
||||||
.get(discount_policy_tag)
|
|
||||||
.unwrap();
|
|
||||||
if status_bin
|
|
||||||
.discount_usage_map
|
|
||||||
.get(discount_policy_tag)
|
|
||||||
.unwrap()
|
|
||||||
< &policy.use_limit
|
|
||||||
{
|
|
||||||
advanced_s_guarantee = policy.guarantee_pity - pity_s + 1;
|
|
||||||
}
|
|
||||||
} else if common_properties.ten_pull_discount_tag == *discount_policy_tag {
|
|
||||||
let policy = gachaconf
|
|
||||||
.discount_policies
|
|
||||||
.ten_pull_discount_map
|
|
||||||
.get(discount_policy_tag)
|
|
||||||
.unwrap();
|
|
||||||
let discount_usage = status_bin
|
|
||||||
.discount_usage_map
|
|
||||||
.get(discount_policy_tag)
|
|
||||||
.unwrap();
|
|
||||||
if discount_usage < &policy.use_limit {
|
|
||||||
discount_ten_roll_prize = policy.discounted_prize;
|
|
||||||
discount_avaliable_num = policy.use_limit - discount_usage;
|
|
||||||
}
|
|
||||||
} else if gachaconf
|
|
||||||
.discount_policies
|
|
||||||
.free_select_map
|
|
||||||
.contains_key(discount_policy_tag)
|
|
||||||
{
|
|
||||||
let policy = gachaconf
|
|
||||||
.discount_policies
|
|
||||||
.free_select_map
|
|
||||||
.get(discount_policy_tag)
|
|
||||||
.unwrap();
|
|
||||||
let free_select_demand_idx = usize::try_from(
|
|
||||||
*(status_bin
|
|
||||||
.discount_usage_map
|
|
||||||
.get(&policy.free_select_usage_record_tag)
|
|
||||||
.unwrap()),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
if policy.milestones.len() <= free_select_demand_idx {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let free_select_actual_progress = status_bin
|
|
||||||
.discount_usage_map
|
|
||||||
.get(&policy.free_select_progress_record_tag)
|
|
||||||
.unwrap();
|
|
||||||
free_select_policy = Some(policy);
|
|
||||||
free_select_required_pull = policy
|
|
||||||
.milestones
|
|
||||||
.get(free_select_demand_idx)
|
|
||||||
.unwrap()
|
|
||||||
.to_owned();
|
|
||||||
free_select_progress = min(free_select_required_pull, *free_select_actual_progress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut up_s_item_list: Vec<u32> = vec![];
|
|
||||||
let mut up_a_item_list: Vec<u32> = vec![];
|
|
||||||
let mut free_select_item_list: Vec<u32> = vec![];
|
|
||||||
let mut chooseable_up_list: Vec<u32> = vec![];
|
|
||||||
let mut chosen_up_item: u32 = 0;
|
|
||||||
let mut s_guarantee: u32 = 0;
|
|
||||||
let mut a_guarantee: u32 = 0;
|
|
||||||
for rarity_items in target_pool.gacha_items.iter() {
|
|
||||||
let mut chooseable_up_included_category_tags: Option<&HashSet<String>> = None;
|
|
||||||
let mut chooseable_policy_tag: Option<&String> = None;
|
|
||||||
for guarantee_policy_tag in rarity_items.category_guarantee_policy_tags.iter() {
|
|
||||||
let category_guarantee_policy = gachaconf
|
|
||||||
.category_guarantee_policy_map
|
|
||||||
.get(guarantee_policy_tag)
|
|
||||||
.unwrap();
|
|
||||||
if !category_guarantee_policy.chooseable {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
chooseable_policy_tag = Some(guarantee_policy_tag);
|
|
||||||
chooseable_up_included_category_tags =
|
|
||||||
Some(&category_guarantee_policy.included_category_tags);
|
|
||||||
if let Some(item) = status_bin
|
|
||||||
.rarity_status_map
|
|
||||||
.get(&rarity_items.rarity)
|
|
||||||
.unwrap()
|
|
||||||
.categories_chosen_guarantee_item_map
|
|
||||||
.get(guarantee_policy_tag)
|
|
||||||
{
|
|
||||||
chosen_up_item = item.clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (category_tag, category) in rarity_items.categories.iter() {
|
|
||||||
let probability_model = gachaconf
|
|
||||||
.probability_model_map
|
|
||||||
.get(&rarity_items.probability_model_tag)
|
|
||||||
.unwrap();
|
|
||||||
let maximum_pity = &probability_model.maximum_guarantee_pity;
|
|
||||||
if rarity_items.rarity == common_properties.s_item_rarity {
|
|
||||||
if category.is_promotional_items {
|
|
||||||
up_s_item_list = category.item_ids.clone();
|
|
||||||
}
|
|
||||||
// tracing::info!("pity_s: {pity_s}");
|
|
||||||
// thread 'tokio-runtime-worker' panicked at nap_gameserver\src\handlers\gacha.rs:369:31:
|
|
||||||
// attempt to subtract with overflow
|
|
||||||
s_guarantee = maximum_pity - min(pity_s, maximum_pity.clone()) + 1;
|
|
||||||
}
|
|
||||||
if rarity_items.rarity == common_properties.a_item_rarity {
|
|
||||||
if category.is_promotional_items {
|
|
||||||
up_a_item_list = category.item_ids.clone();
|
|
||||||
}
|
|
||||||
// tracing::info!("pity_a: {pity_a}");
|
|
||||||
a_guarantee = maximum_pity - min(pity_a, maximum_pity.clone()) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(val) = free_select_policy {
|
|
||||||
if val.rarity == rarity_items.rarity && val.category_tags.contains(category_tag) {
|
|
||||||
free_select_item_list.append(&mut category.item_ids.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(tags) = chooseable_up_included_category_tags {
|
|
||||||
if tags.contains(category_tag) {
|
|
||||||
chooseable_up_list.append(&mut category.item_ids.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(_priority_policy_tag) = chooseable_policy_tag {
|
|
||||||
// if let Some(item) = status_bin
|
|
||||||
// .rarity_status_map
|
|
||||||
// .get(&rarity_items.rarity)
|
|
||||||
// .unwrap()
|
|
||||||
// .categories_chosen_guarantee_item_map
|
|
||||||
// .get(priority_policy_tag)
|
|
||||||
// {
|
|
||||||
if rarity_items.rarity == gachaconf.common_properties.s_item_rarity {
|
|
||||||
up_s_item_list = vec![];
|
|
||||||
} else if rarity_items.rarity == gachaconf.common_properties.a_item_rarity {
|
|
||||||
up_a_item_list = vec![];
|
|
||||||
}
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let need_item_info_list: Vec<NeedItemInfo> = vec![NeedItemInfo {
|
|
||||||
need_item_id: target_pool.cost_item_id,
|
|
||||||
need_item_count: 1,
|
|
||||||
}];
|
|
||||||
|
|
||||||
let mut result = Gacha {
|
|
||||||
gacha_schedule_id: target_pool.gacha_schedule_id,
|
|
||||||
gacha_parent_schedule_id: target_pool.gacha_parent_schedule_id,
|
|
||||||
gacha_type: target_pool.gacha_type,
|
|
||||||
start_timestamp: target_pool.start_time.timestamp(),
|
|
||||||
end_timestamp: target_pool.end_time.timestamp(),
|
|
||||||
discount_avaliable_num,
|
|
||||||
discount_ten_roll_prize,
|
|
||||||
advanced_s_guarantee,
|
|
||||||
s_guarantee,
|
|
||||||
a_guarantee,
|
|
||||||
need_item_info_list,
|
|
||||||
free_select_progress,
|
|
||||||
free_select_required_pull,
|
|
||||||
free_select_item_list,
|
|
||||||
chosen_up_item,
|
|
||||||
// nammdglepbk: 563,
|
|
||||||
// hgmcofcjmbg: 101,
|
|
||||||
// akggbhgkifd: chooseable_up_list.clone(),
|
|
||||||
chooseable_up_list,
|
|
||||||
..Gacha::default()
|
|
||||||
};
|
|
||||||
if up_s_item_list.len() > 0 {
|
|
||||||
result.up_s_item_list = up_s_item_list;
|
|
||||||
}
|
|
||||||
if up_a_item_list.len() > 0 {
|
|
||||||
result.up_a_item_list = up_a_item_list;
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_all_gacha_info(_player: &Player, now: &DateTime<Local>) -> GachaData {
|
|
||||||
let gachaconf = global_gacha_config();
|
|
||||||
let gacha_bin = &_player.gacha_model.gacha_bin;
|
|
||||||
let mut gacha_list: Vec<Gacha> = vec![];
|
|
||||||
for target_pool in gachaconf.character_gacha_pool_list.iter() {
|
|
||||||
if target_pool.is_still_open(now) {
|
|
||||||
gacha_list.push(generate_gacha_info_from_pool(
|
|
||||||
&gacha_bin,
|
|
||||||
target_pool,
|
|
||||||
&gachaconf.common_properties,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// tracing::info!("gacha_list: {:?}", gacha_list);
|
|
||||||
GachaData {
|
|
||||||
random_number: 6167,
|
|
||||||
gacha_pool: Some(GachaPool { gacha_list }),
|
|
||||||
..GachaData::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_gacha_pool<'conf>(
|
fn get_gacha_pool<'conf>(
|
||||||
character_gacha_pool_list: &'conf Vec<CharacterGachaPool>,
|
character_gacha_pool_list: &'conf Vec<CharacterGachaPool>,
|
||||||
gacha_parent_schedule_id: &u32,
|
gacha_parent_schedule_id: &u32,
|
||||||
pull_time: &DateTime<Local>,
|
pull_time: &DateTime<Local>,
|
||||||
) -> Option<&'conf CharacterGachaPool> {
|
) -> NetResult<&'conf CharacterGachaPool> {
|
||||||
for target_pool in character_gacha_pool_list.iter() {
|
for target_pool in character_gacha_pool_list.iter() {
|
||||||
if &target_pool.gacha_parent_schedule_id == gacha_parent_schedule_id
|
if &target_pool.gacha_parent_schedule_id == gacha_parent_schedule_id
|
||||||
&& target_pool.is_still_open(pull_time)
|
&& target_pool.is_still_open(pull_time)
|
||||||
{
|
{
|
||||||
return Some(target_pool);
|
return Ok(target_pool);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
tracing::info!(
|
||||||
|
"refuse gacha op because: pool of parent_schedule_id {} not found or isn't in open time",
|
||||||
|
gacha_parent_schedule_id
|
||||||
|
);
|
||||||
|
Err(NetError::from(Retcode::RetFail))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return is item UID (weapon specific)
|
||||||
|
fn add_item(
|
||||||
|
role_model: &mut RoleModel,
|
||||||
|
item_model: &mut ItemModel,
|
||||||
|
item_id: &ItemID,
|
||||||
|
item_type: &GachaAddedItemType,
|
||||||
|
) -> NetResult<u32> {
|
||||||
|
match item_type {
|
||||||
|
GachaAddedItemType::Character => match AvatarBaseID::new(item_id.value()) {
|
||||||
|
Some(avatar_id) => {
|
||||||
|
role_model.add_avatar(avatar_id);
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
tracing::info!("add item failed for avatar id {item_id}");
|
||||||
|
Err(NetError::from(Retcode::RetFail))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
GachaAddedItemType::Weapon => match WeaponID::new(item_id.value()) {
|
||||||
|
Some(weapon_id) => Ok(item_model.add_weapon(weapon_id).value()),
|
||||||
|
None => {
|
||||||
|
tracing::info!("add item failed for weapon id {item_id}");
|
||||||
|
Err(NetError::from(Retcode::RetFail))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
GachaAddedItemType::Bangboo => Ok(0),
|
||||||
|
_ => {
|
||||||
|
tracing::info!(
|
||||||
|
"add item failed due to undefined item type (from {item_id}) in configuration"
|
||||||
|
);
|
||||||
|
Err(NetError::from(Retcode::RetFail))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn construct_sync(role_model: &RoleModel, item_model: &ItemModel) -> PlayerSyncScNotify {
|
||||||
|
PlayerSyncScNotify {
|
||||||
|
avatar: Some(role_model.avatar_sync()),
|
||||||
|
item_sync: Some(item_model.item_sync()),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,6 +126,9 @@ req_handlers! {
|
||||||
gacha::DoGacha;
|
gacha::DoGacha;
|
||||||
gacha::ChooseGachaUp;
|
gacha::ChooseGachaUp;
|
||||||
gacha::GachaFreeAgent;
|
gacha::GachaFreeAgent;
|
||||||
|
player::ModNickname;
|
||||||
|
client_systems::ModQuickMenu;
|
||||||
|
client_systems::ChangePostGirl;
|
||||||
}
|
}
|
||||||
|
|
||||||
notify_handlers! {
|
notify_handlers! {
|
||||||
|
|
|
@ -58,6 +58,25 @@ pub async fn on_get_player_transaction(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn on_mod_nickname(
|
||||||
|
session: &NetSession,
|
||||||
|
_player: &mut Player,
|
||||||
|
_req: ModNicknameCsReq,
|
||||||
|
) -> NetResult<ModNicknameScRsp> {
|
||||||
|
_player.basic_data_model.nick_name = Some(_req.nick_name.to_string());
|
||||||
|
session
|
||||||
|
.notify(PlayerSyncScNotify {
|
||||||
|
basic_info: Some(_player.basic_data_model.player_basic_info()),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(ModNicknameScRsp {
|
||||||
|
retcode: Retcode::RetSucc.into(),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn on_keep_alive(
|
pub async fn on_keep_alive(
|
||||||
_session: &NetSession,
|
_session: &NetSession,
|
||||||
_player: &mut Player,
|
_player: &mut Player,
|
||||||
|
|
440
nap_gameserver/src/logic/gacha/client_op.rs
Normal file
440
nap_gameserver/src/logic/gacha/client_op.rs
Normal file
|
@ -0,0 +1,440 @@
|
||||||
|
use data::gacha::gacha_config::*;
|
||||||
|
use data::gacha::global_gacha_config;
|
||||||
|
use data::tables::ItemID;
|
||||||
|
|
||||||
|
use chrono::{DateTime, Local};
|
||||||
|
use proto::{Gacha, GachaData, GachaPool, NeedItemInfo};
|
||||||
|
use std::{
|
||||||
|
cmp::min,
|
||||||
|
collections::{
|
||||||
|
hash_map::Entry::{Occupied, Vacant},
|
||||||
|
HashSet,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::GachaModel;
|
||||||
|
|
||||||
|
impl GachaModel {
|
||||||
|
pub fn to_client(&self, now: &DateTime<Local>) -> GachaData {
|
||||||
|
let gachaconf = global_gacha_config();
|
||||||
|
let mut gacha_list: Vec<Gacha> = vec![];
|
||||||
|
for target_pool in gachaconf.character_gacha_pool_list.iter() {
|
||||||
|
if target_pool.is_still_open(now) {
|
||||||
|
gacha_list.push(
|
||||||
|
self.generate_gacha_info_from_pool(target_pool, &gachaconf.common_properties),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// tracing::info!("gacha_list: {:?}", gacha_list);
|
||||||
|
GachaData {
|
||||||
|
random_number: 6167,
|
||||||
|
gacha_pool: Some(GachaPool { gacha_list }),
|
||||||
|
..GachaData::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_gacha_info_from_pool(
|
||||||
|
&self,
|
||||||
|
target_pool: &CharacterGachaPool,
|
||||||
|
common_properties: &GachaCommonProperties,
|
||||||
|
) -> Gacha {
|
||||||
|
let gachaconf = data::gacha::global_gacha_config();
|
||||||
|
let sharing_guarantee_category_tag = &target_pool.sharing_guarantee_info_category;
|
||||||
|
let status_bin = self
|
||||||
|
.gacha_status_map
|
||||||
|
.get(sharing_guarantee_category_tag)
|
||||||
|
.unwrap();
|
||||||
|
let pity_s = status_bin
|
||||||
|
.rarity_status_map
|
||||||
|
.get(&common_properties.s_item_rarity)
|
||||||
|
.unwrap()
|
||||||
|
.pity;
|
||||||
|
let pity_a = status_bin
|
||||||
|
.rarity_status_map
|
||||||
|
.get(&common_properties.a_item_rarity)
|
||||||
|
.unwrap()
|
||||||
|
.pity;
|
||||||
|
|
||||||
|
let mut discount_ten_roll_prize: u32 = 0;
|
||||||
|
let mut discount_avaliable_num: u32 = 0;
|
||||||
|
let mut advanced_s_guarantee: u32 = 0;
|
||||||
|
let mut free_select_progress: u32 = 0;
|
||||||
|
let mut free_select_required_pull: u32 = 0;
|
||||||
|
let mut free_select_policy: Option<&FreeSelectItem> = None;
|
||||||
|
for discount_policy_tag in target_pool.discount_policy_tags.iter() {
|
||||||
|
if common_properties.newcomer_advanced_s_tag == *discount_policy_tag {
|
||||||
|
let policy = gachaconf
|
||||||
|
.discount_policies
|
||||||
|
.advanced_guarantee_map
|
||||||
|
.get(discount_policy_tag)
|
||||||
|
.unwrap();
|
||||||
|
if status_bin
|
||||||
|
.discount_usage_map
|
||||||
|
.get(discount_policy_tag)
|
||||||
|
.unwrap()
|
||||||
|
< &policy.use_limit
|
||||||
|
{
|
||||||
|
advanced_s_guarantee = policy.guarantee_pity - pity_s + 1;
|
||||||
|
}
|
||||||
|
} else if common_properties.ten_pull_discount_tag == *discount_policy_tag {
|
||||||
|
let policy = gachaconf
|
||||||
|
.discount_policies
|
||||||
|
.ten_pull_discount_map
|
||||||
|
.get(discount_policy_tag)
|
||||||
|
.unwrap();
|
||||||
|
let discount_usage = status_bin
|
||||||
|
.discount_usage_map
|
||||||
|
.get(discount_policy_tag)
|
||||||
|
.unwrap();
|
||||||
|
if discount_usage < &policy.use_limit {
|
||||||
|
discount_ten_roll_prize = policy.discounted_prize;
|
||||||
|
discount_avaliable_num = policy.use_limit - discount_usage;
|
||||||
|
}
|
||||||
|
} else if gachaconf
|
||||||
|
.discount_policies
|
||||||
|
.free_select_map
|
||||||
|
.contains_key(discount_policy_tag)
|
||||||
|
{
|
||||||
|
let policy = gachaconf
|
||||||
|
.discount_policies
|
||||||
|
.free_select_map
|
||||||
|
.get(discount_policy_tag)
|
||||||
|
.unwrap();
|
||||||
|
let free_select_demand_idx = usize::try_from(
|
||||||
|
*(status_bin
|
||||||
|
.discount_usage_map
|
||||||
|
.get(&policy.free_select_usage_record_tag)
|
||||||
|
.unwrap()),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
if policy.milestones.len() <= free_select_demand_idx {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let free_select_actual_progress = status_bin
|
||||||
|
.discount_usage_map
|
||||||
|
.get(&policy.free_select_progress_record_tag)
|
||||||
|
.unwrap();
|
||||||
|
free_select_policy = Some(policy);
|
||||||
|
free_select_required_pull = policy
|
||||||
|
.milestones
|
||||||
|
.get(free_select_demand_idx)
|
||||||
|
.unwrap()
|
||||||
|
.to_owned();
|
||||||
|
free_select_progress = min(free_select_required_pull, *free_select_actual_progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut up_s_item_list: Vec<u32> = vec![];
|
||||||
|
let mut up_a_item_list: Vec<u32> = vec![];
|
||||||
|
let mut free_select_item_list: Vec<u32> = vec![];
|
||||||
|
let mut chooseable_up_list: Vec<u32> = vec![];
|
||||||
|
let mut chosen_up_item: u32 = 0;
|
||||||
|
let mut s_guarantee: u32 = 0;
|
||||||
|
let mut a_guarantee: u32 = 0;
|
||||||
|
for rarity_items in target_pool.gacha_items.iter() {
|
||||||
|
let mut chooseable_up_included_category_tags: Option<&HashSet<String>> = None;
|
||||||
|
let mut chooseable_policy_tag: Option<&String> = None;
|
||||||
|
for guarantee_policy_tag in rarity_items.category_guarantee_policy_tags.iter() {
|
||||||
|
let category_guarantee_policy = gachaconf
|
||||||
|
.category_guarantee_policy_map
|
||||||
|
.get(guarantee_policy_tag)
|
||||||
|
.unwrap();
|
||||||
|
if !category_guarantee_policy.chooseable {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
chooseable_policy_tag = Some(guarantee_policy_tag);
|
||||||
|
chooseable_up_included_category_tags =
|
||||||
|
Some(&category_guarantee_policy.included_category_tags);
|
||||||
|
if let Some(item) = status_bin
|
||||||
|
.rarity_status_map
|
||||||
|
.get(&rarity_items.rarity)
|
||||||
|
.unwrap()
|
||||||
|
.categories_chosen_guarantee_item_map
|
||||||
|
.get(guarantee_policy_tag)
|
||||||
|
{
|
||||||
|
chosen_up_item = item.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (category_tag, category) in rarity_items.categories.iter() {
|
||||||
|
let probability_model = gachaconf
|
||||||
|
.probability_model_map
|
||||||
|
.get(&rarity_items.probability_model_tag)
|
||||||
|
.unwrap();
|
||||||
|
let maximum_pity = &probability_model.maximum_guarantee_pity;
|
||||||
|
if rarity_items.rarity == common_properties.s_item_rarity {
|
||||||
|
if category.is_promotional_items {
|
||||||
|
up_s_item_list = category.item_ids.clone();
|
||||||
|
}
|
||||||
|
// tracing::info!("pity_s: {pity_s}");
|
||||||
|
// thread 'tokio-runtime-worker' panicked at nap_gameserver\src\handlers\gacha.rs:369:31:
|
||||||
|
// attempt to subtract with overflow
|
||||||
|
s_guarantee = maximum_pity - min(pity_s, maximum_pity.clone()) + 1;
|
||||||
|
}
|
||||||
|
if rarity_items.rarity == common_properties.a_item_rarity {
|
||||||
|
if category.is_promotional_items {
|
||||||
|
up_a_item_list = category.item_ids.clone();
|
||||||
|
}
|
||||||
|
// tracing::info!("pity_a: {pity_a}");
|
||||||
|
a_guarantee = maximum_pity - min(pity_a, maximum_pity.clone()) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(val) = free_select_policy {
|
||||||
|
if val.rarity == rarity_items.rarity && val.category_tags.contains(category_tag)
|
||||||
|
{
|
||||||
|
free_select_item_list.append(&mut category.item_ids.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(tags) = chooseable_up_included_category_tags {
|
||||||
|
if tags.contains(category_tag) {
|
||||||
|
chooseable_up_list.append(&mut category.item_ids.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(_priority_policy_tag) = chooseable_policy_tag {
|
||||||
|
// if let Some(item) = status_bin
|
||||||
|
// .rarity_status_map
|
||||||
|
// .get(&rarity_items.rarity)
|
||||||
|
// .unwrap()
|
||||||
|
// .categories_chosen_guarantee_item_map
|
||||||
|
// .get(priority_policy_tag)
|
||||||
|
// {
|
||||||
|
if rarity_items.rarity == gachaconf.common_properties.s_item_rarity {
|
||||||
|
up_s_item_list = chooseable_up_list.clone();
|
||||||
|
} else if rarity_items.rarity == gachaconf.common_properties.a_item_rarity {
|
||||||
|
up_a_item_list = vec![];
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let need_item_info_list: Vec<NeedItemInfo> = vec![NeedItemInfo {
|
||||||
|
need_item_id: target_pool.cost_item_id,
|
||||||
|
need_item_count: 1,
|
||||||
|
}];
|
||||||
|
|
||||||
|
let mut result = Gacha {
|
||||||
|
gacha_schedule_id: target_pool.gacha_schedule_id,
|
||||||
|
gacha_parent_schedule_id: target_pool.gacha_parent_schedule_id,
|
||||||
|
gacha_type: target_pool.gacha_type,
|
||||||
|
start_timestamp: target_pool.start_time.timestamp(),
|
||||||
|
end_timestamp: target_pool.end_time.timestamp(),
|
||||||
|
discount_avaliable_num,
|
||||||
|
discount_ten_roll_prize,
|
||||||
|
advanced_s_guarantee,
|
||||||
|
s_guarantee,
|
||||||
|
a_guarantee,
|
||||||
|
need_item_info_list,
|
||||||
|
free_select_progress,
|
||||||
|
free_select_required_pull,
|
||||||
|
free_select_item_list,
|
||||||
|
chosen_up_item,
|
||||||
|
// nammdglepbk: 563,
|
||||||
|
// hgmcofcjmbg: 101,
|
||||||
|
// akggbhgkifd: chooseable_up_list.clone(),
|
||||||
|
chooseable_up_list,
|
||||||
|
..Gacha::default()
|
||||||
|
};
|
||||||
|
if up_s_item_list.len() > 0 {
|
||||||
|
result.up_s_item_list = up_s_item_list;
|
||||||
|
}
|
||||||
|
if up_a_item_list.len() > 0 {
|
||||||
|
result.up_a_item_list = up_a_item_list;
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the actual item cost count (counting discount).
|
||||||
|
pub fn get_actual_cost_count<'bin, 'conf>(
|
||||||
|
&'bin mut self,
|
||||||
|
target_pool: &'conf CharacterGachaPool,
|
||||||
|
pull_count: &u32,
|
||||||
|
) -> u32 {
|
||||||
|
let gachaconf = global_gacha_config();
|
||||||
|
|
||||||
|
if *pull_count == 10 {
|
||||||
|
let discount_tag = &gachaconf.common_properties.ten_pull_discount_tag;
|
||||||
|
if target_pool.discount_policy_tags.contains(&discount_tag) {
|
||||||
|
let status_bin = self
|
||||||
|
.gacha_status_map
|
||||||
|
.get_mut(&target_pool.sharing_guarantee_info_category)
|
||||||
|
.unwrap();
|
||||||
|
let discount_policy = gachaconf
|
||||||
|
.discount_policies
|
||||||
|
.ten_pull_discount_map
|
||||||
|
.get(discount_tag)
|
||||||
|
.unwrap();
|
||||||
|
let usage = status_bin.discount_usage_map.get_mut(discount_tag).unwrap();
|
||||||
|
if *usage < discount_policy.use_limit {
|
||||||
|
*usage += 1;
|
||||||
|
return discount_policy.discounted_prize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pull_count.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn request_free_agent<'bin, 'conf>(
|
||||||
|
&'bin mut self,
|
||||||
|
target_pool: &'conf CharacterGachaPool,
|
||||||
|
item_id: &ItemID,
|
||||||
|
) -> GachaAddedItemType {
|
||||||
|
let gachaconf = global_gacha_config();
|
||||||
|
let sharing_guarantee_category_tag = &target_pool.sharing_guarantee_info_category;
|
||||||
|
let status_bin = self
|
||||||
|
.gacha_status_map
|
||||||
|
.get_mut(sharing_guarantee_category_tag)
|
||||||
|
.unwrap();
|
||||||
|
let item_id = item_id.value();
|
||||||
|
|
||||||
|
let mut free_select_policy: Option<&FreeSelectItem> = None;
|
||||||
|
let mut free_select_progress: u32 = 0;
|
||||||
|
let mut free_select_required_pull: u32 = 0;
|
||||||
|
for discount_policy_tag in target_pool.discount_policy_tags.iter() {
|
||||||
|
if gachaconf
|
||||||
|
.discount_policies
|
||||||
|
.free_select_map
|
||||||
|
.contains_key(discount_policy_tag)
|
||||||
|
{
|
||||||
|
let policy = gachaconf
|
||||||
|
.discount_policies
|
||||||
|
.free_select_map
|
||||||
|
.get(discount_policy_tag)
|
||||||
|
.unwrap();
|
||||||
|
let free_select_demand_idx = usize::try_from(
|
||||||
|
*(status_bin
|
||||||
|
.discount_usage_map
|
||||||
|
.get(&policy.free_select_usage_record_tag)
|
||||||
|
.unwrap()),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
if policy.milestones.len() <= free_select_demand_idx {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let free_select_actual_progress = status_bin
|
||||||
|
.discount_usage_map
|
||||||
|
.get(&policy.free_select_progress_record_tag)
|
||||||
|
.unwrap();
|
||||||
|
free_select_policy = Some(policy);
|
||||||
|
free_select_required_pull = policy
|
||||||
|
.milestones
|
||||||
|
.get(free_select_demand_idx)
|
||||||
|
.unwrap()
|
||||||
|
.to_owned();
|
||||||
|
free_select_progress = min(free_select_required_pull, *free_select_actual_progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let None = free_select_policy {
|
||||||
|
tracing::info!(
|
||||||
|
"refuse free agent because: pool of parent_schedule_id {} hasn't defined free agent discount yet (or used up chance)",
|
||||||
|
target_pool.gacha_parent_schedule_id
|
||||||
|
);
|
||||||
|
return GachaAddedItemType::None;
|
||||||
|
} else if free_select_progress < free_select_required_pull {
|
||||||
|
tracing::info!(
|
||||||
|
"refuse free agent because: use pulled {free_select_progress} (after last free agent) in parent_schedule_id {}, required {free_select_required_pull}",
|
||||||
|
target_pool.gacha_parent_schedule_id
|
||||||
|
);
|
||||||
|
return GachaAddedItemType::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let free_select_policy = free_select_policy.unwrap();
|
||||||
|
let mut item_type: GachaAddedItemType = GachaAddedItemType::None;
|
||||||
|
for rarity_items in target_pool.gacha_items.iter() {
|
||||||
|
if rarity_items.rarity != free_select_policy.rarity {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (category_tag, category) in rarity_items.categories.iter() {
|
||||||
|
if !free_select_policy.category_tags.contains(category_tag) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if category.item_ids.contains(&item_id) {
|
||||||
|
item_type = category.item_type.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if item_type != GachaAddedItemType::None {
|
||||||
|
(*status_bin
|
||||||
|
.discount_usage_map
|
||||||
|
.get_mut(&free_select_policy.free_select_usage_record_tag)
|
||||||
|
.unwrap()) += 1;
|
||||||
|
(*status_bin
|
||||||
|
.discount_usage_map
|
||||||
|
.get_mut(&free_select_policy.free_select_progress_record_tag)
|
||||||
|
.unwrap()) -= free_select_required_pull;
|
||||||
|
}
|
||||||
|
item_type
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn choose_gacha_up<'bin, 'conf>(
|
||||||
|
&'bin mut self,
|
||||||
|
target_pool: &'conf CharacterGachaPool,
|
||||||
|
item_id: &ItemID,
|
||||||
|
) -> bool {
|
||||||
|
let gachaconf = global_gacha_config();
|
||||||
|
let item_id = item_id.value();
|
||||||
|
for rarity_items in target_pool.gacha_items.iter() {
|
||||||
|
for guarantee_policy_tag in rarity_items.category_guarantee_policy_tags.iter() {
|
||||||
|
let category_guarantee_policy = gachaconf
|
||||||
|
.category_guarantee_policy_map
|
||||||
|
.get(guarantee_policy_tag)
|
||||||
|
.unwrap();
|
||||||
|
if !category_guarantee_policy.chooseable {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let mut up_category: Option<&String> = None;
|
||||||
|
for (category_tag, category) in rarity_items.categories.iter() {
|
||||||
|
if category.item_ids.contains(&item_id) {
|
||||||
|
up_category = Some(category_tag);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let None = up_category {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let up_category = up_category.unwrap();
|
||||||
|
|
||||||
|
let progress_bin = self
|
||||||
|
.gacha_status_map
|
||||||
|
.get_mut(&target_pool.sharing_guarantee_info_category)
|
||||||
|
.unwrap()
|
||||||
|
.rarity_status_map
|
||||||
|
.get_mut(&rarity_items.rarity)
|
||||||
|
.unwrap();
|
||||||
|
match progress_bin
|
||||||
|
.categories_chosen_guarantee_item_map
|
||||||
|
.entry(guarantee_policy_tag.clone())
|
||||||
|
{
|
||||||
|
Occupied(mut occupied_entry) => {
|
||||||
|
occupied_entry.insert(item_id);
|
||||||
|
}
|
||||||
|
Vacant(vacant_entry) => {
|
||||||
|
vacant_entry.insert(item_id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match progress_bin
|
||||||
|
.categories_chosen_guarantee_category_map
|
||||||
|
.entry(up_category.clone())
|
||||||
|
{
|
||||||
|
Occupied(mut occupied_entry) => {
|
||||||
|
occupied_entry.insert(up_category.clone());
|
||||||
|
}
|
||||||
|
Vacant(vacant_entry) => {
|
||||||
|
vacant_entry.insert(up_category.clone());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,20 +1,25 @@
|
||||||
|
use super::record::*;
|
||||||
|
use super::stat::*;
|
||||||
use data::gacha;
|
use data::gacha;
|
||||||
use data::gacha::gacha_config::*;
|
use data::gacha::gacha_config::*;
|
||||||
use proto::*;
|
use data::tables::ItemID;
|
||||||
|
|
||||||
use chrono::{DateTime, Local};
|
use chrono::{DateTime, Local};
|
||||||
|
use proto::GachaModelBin;
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::hash::{BuildHasher, Hash};
|
use std::hash::{BuildHasher, Hash};
|
||||||
|
|
||||||
pub struct GachaModel {
|
pub struct GachaModel {
|
||||||
pub gacha_bin: GachaModelBin,
|
pub gacha_status_map: HashMap<String, GachaStatus>,
|
||||||
|
pub gacha_records: Vec<GachaRecord>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for GachaModel {
|
impl Default for GachaModel {
|
||||||
fn default() -> GachaModel {
|
fn default() -> GachaModel {
|
||||||
let result = GachaModel {
|
let result = GachaModel {
|
||||||
gacha_bin: GachaModelBin::default(),
|
gacha_status_map: HashMap::new(),
|
||||||
|
gacha_records: vec![],
|
||||||
};
|
};
|
||||||
result.post_deserialize()
|
result.post_deserialize()
|
||||||
}
|
}
|
||||||
|
@ -22,19 +27,37 @@ impl Default for GachaModel {
|
||||||
|
|
||||||
impl GachaModel {
|
impl GachaModel {
|
||||||
pub fn from_bin(gacha_bin: GachaModelBin) -> Self {
|
pub fn from_bin(gacha_bin: GachaModelBin) -> Self {
|
||||||
let result = Self { gacha_bin };
|
let result = Self {
|
||||||
|
gacha_status_map: gacha_bin
|
||||||
|
.gacha_status_map
|
||||||
|
.into_iter()
|
||||||
|
.map(|(k, v)| (k, GachaStatus::from_bin(v)))
|
||||||
|
.collect(),
|
||||||
|
gacha_records: gacha_bin
|
||||||
|
.gacha_records
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| GachaRecord::from_bin(x))
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
result.post_deserialize()
|
result.post_deserialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_bin(&self) -> GachaModelBin {
|
pub fn to_bin(&self) -> GachaModelBin {
|
||||||
self.gacha_bin.clone()
|
GachaModelBin {
|
||||||
|
gacha_status_map: self
|
||||||
|
.gacha_status_map
|
||||||
|
.iter()
|
||||||
|
.map(|(k, v)| (k.clone(), v.to_bin()))
|
||||||
|
.collect(),
|
||||||
|
gacha_records: self.gacha_records.iter().map(|x| x.to_bin()).collect(),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn post_deserialize(mut self) -> GachaModel {
|
pub fn post_deserialize(mut self) -> GachaModel {
|
||||||
let gachaconf = gacha::global_gacha_config();
|
let gachaconf = gacha::global_gacha_config();
|
||||||
for gacha_pool in gachaconf.character_gacha_pool_list.iter() {
|
for gacha_pool in gachaconf.character_gacha_pool_list.iter() {
|
||||||
let gacha_comp_bin = &mut self.gacha_bin;
|
let mut gacha_status_map = &mut self.gacha_status_map;
|
||||||
let mut gacha_status_map = &mut gacha_comp_bin.gacha_status_map;
|
|
||||||
let status_bin = get_or_add(
|
let status_bin = get_or_add(
|
||||||
&mut gacha_status_map,
|
&mut gacha_status_map,
|
||||||
&gacha_pool.sharing_guarantee_info_category,
|
&gacha_pool.sharing_guarantee_info_category,
|
||||||
|
@ -97,11 +120,11 @@ impl GachaModel {
|
||||||
&'bin mut self,
|
&'bin mut self,
|
||||||
pull_time: &DateTime<Local>,
|
pull_time: &DateTime<Local>,
|
||||||
target_pool: &'conf CharacterGachaPool,
|
target_pool: &'conf CharacterGachaPool,
|
||||||
) -> GachaRecordBin {
|
) -> GachaRecord {
|
||||||
let mut gacha_bin = &mut self.gacha_bin;
|
|
||||||
let (rarity_items, progress_bin, status_bin, probability_model) =
|
let (rarity_items, progress_bin, status_bin, probability_model) =
|
||||||
determine_rarity(&gacha_bin, target_pool);
|
self.determine_rarity(target_pool);
|
||||||
let (category_tag, category) = determine_category(rarity_items, progress_bin, target_pool);
|
let (category_tag, category) =
|
||||||
|
self.determine_category(rarity_items, progress_bin, target_pool);
|
||||||
let result = determine_gacha_result(
|
let result = determine_gacha_result(
|
||||||
pull_time,
|
pull_time,
|
||||||
category,
|
category,
|
||||||
|
@ -110,29 +133,19 @@ impl GachaModel {
|
||||||
progress_bin,
|
progress_bin,
|
||||||
rarity_items,
|
rarity_items,
|
||||||
);
|
);
|
||||||
update_pity(&mut gacha_bin, rarity_items, probability_model, target_pool);
|
self.update_pity(rarity_items, probability_model, target_pool);
|
||||||
update_category_guarantee_info(&mut gacha_bin, rarity_items, &category_tag, target_pool);
|
self.update_category_guarantee_info(rarity_items, &category_tag, target_pool);
|
||||||
update_discount(&mut gacha_bin, target_pool, &category_tag, rarity_items);
|
self.update_discount(target_pool, &category_tag, rarity_items);
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn get_or_add<'a, K: Eq + PartialEq + Hash + Clone, V: Default, S: BuildHasher>(
|
|
||||||
map: &'a mut HashMap<K, V, S>,
|
|
||||||
key: &K,
|
|
||||||
) -> &'a mut V {
|
|
||||||
if !map.contains_key(key) {
|
|
||||||
map.insert(key.clone(), V::default());
|
|
||||||
}
|
|
||||||
map.get_mut(key).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rand_rarity<'bin, 'conf>(
|
fn rand_rarity<'bin, 'conf>(
|
||||||
|
&'bin self,
|
||||||
target_pool: &'conf CharacterGachaPool,
|
target_pool: &'conf CharacterGachaPool,
|
||||||
status_bin: &'bin GachaStatusBin,
|
status_bin: &'bin GachaStatus,
|
||||||
) -> (
|
) -> (
|
||||||
&'conf GachaAvailableItemsInfo,
|
&'conf GachaAvailableItemsInfo,
|
||||||
&'bin GachaProgressBin,
|
&'bin GachaProgress,
|
||||||
&'conf ProbabilityModel,
|
&'conf ProbabilityModel,
|
||||||
) {
|
) {
|
||||||
let gachaconf = gacha::global_gacha_config();
|
let gachaconf = gacha::global_gacha_config();
|
||||||
|
@ -155,16 +168,16 @@ fn rand_rarity<'bin, 'conf>(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn determine_rarity<'bin, 'conf>(
|
fn determine_rarity<'bin, 'conf>(
|
||||||
gacha_bin: &'bin GachaModelBin,
|
&'bin self,
|
||||||
target_pool: &'conf CharacterGachaPool,
|
target_pool: &'conf CharacterGachaPool,
|
||||||
) -> (
|
) -> (
|
||||||
&'conf GachaAvailableItemsInfo,
|
&'conf GachaAvailableItemsInfo,
|
||||||
&'bin GachaProgressBin,
|
&'bin GachaProgress,
|
||||||
&'bin GachaStatusBin,
|
&'bin GachaStatus,
|
||||||
&'conf ProbabilityModel,
|
&'conf ProbabilityModel,
|
||||||
) {
|
) {
|
||||||
let gachaconf = gacha::global_gacha_config();
|
let gachaconf = gacha::global_gacha_config();
|
||||||
let status_bin = gacha_bin
|
let status_bin = self
|
||||||
.gacha_status_map
|
.gacha_status_map
|
||||||
.get(&target_pool.sharing_guarantee_info_category)
|
.get(&target_pool.sharing_guarantee_info_category)
|
||||||
.expect(&format!(
|
.expect(&format!(
|
||||||
|
@ -172,7 +185,7 @@ fn determine_rarity<'bin, 'conf>(
|
||||||
target_pool.sharing_guarantee_info_category
|
target_pool.sharing_guarantee_info_category
|
||||||
));
|
));
|
||||||
let (mut rarity_items, mut progress_bin, mut probability_model) =
|
let (mut rarity_items, mut progress_bin, mut probability_model) =
|
||||||
rand_rarity(target_pool, &status_bin);
|
self.rand_rarity(target_pool, &status_bin);
|
||||||
|
|
||||||
// We should take AdvancedGuarantee discount into consideration.
|
// We should take AdvancedGuarantee discount into consideration.
|
||||||
for discount_tag in target_pool.discount_policy_tags.iter() {
|
for discount_tag in target_pool.discount_policy_tags.iter() {
|
||||||
|
@ -195,8 +208,7 @@ fn determine_rarity<'bin, 'conf>(
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let higher_progress_bin =
|
let higher_progress_bin = status_bin
|
||||||
status_bin
|
|
||||||
.rarity_status_map
|
.rarity_status_map
|
||||||
.get(&discount.rarity)
|
.get(&discount.rarity)
|
||||||
.expect(&format!(
|
.expect(&format!(
|
||||||
|
@ -226,8 +238,9 @@ fn determine_rarity<'bin, 'conf>(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn determine_category<'bin, 'conf>(
|
fn determine_category<'bin, 'conf>(
|
||||||
|
&'bin self,
|
||||||
rarity_items: &'conf GachaAvailableItemsInfo,
|
rarity_items: &'conf GachaAvailableItemsInfo,
|
||||||
progress_bin: &'bin GachaProgressBin,
|
progress_bin: &'bin GachaProgress,
|
||||||
target_pool: &'conf CharacterGachaPool,
|
target_pool: &'conf CharacterGachaPool,
|
||||||
) -> (String, &'conf GachaCategoryInfo) {
|
) -> (String, &'conf GachaCategoryInfo) {
|
||||||
let gachaconf = gacha::global_gacha_config();
|
let gachaconf = gacha::global_gacha_config();
|
||||||
|
@ -313,14 +326,138 @@ fn determine_category<'bin, 'conf>(
|
||||||
panic!("No category is chosen.");
|
panic!("No category is chosen.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_pity<'bin, 'conf>(
|
||||||
|
&'bin mut self,
|
||||||
|
rarity_items: &'conf GachaAvailableItemsInfo,
|
||||||
|
probability_model: &'conf ProbabilityModel,
|
||||||
|
target_pool: &'conf CharacterGachaPool,
|
||||||
|
) {
|
||||||
|
let status_bin = self
|
||||||
|
.gacha_status_map
|
||||||
|
.get_mut(&target_pool.sharing_guarantee_info_category)
|
||||||
|
.unwrap();
|
||||||
|
for (rarity, rarity_status) in status_bin.rarity_status_map.iter_mut() {
|
||||||
|
if (rarity == &rarity_items.rarity)
|
||||||
|
|| (probability_model.clear_status_on_higher_rarity_pulled
|
||||||
|
&& rarity < &rarity_items.rarity)
|
||||||
|
{
|
||||||
|
rarity_status.pity = 1;
|
||||||
|
} else {
|
||||||
|
rarity_status.pity += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_category_guarantee_info<'bin, 'conf>(
|
||||||
|
&'bin mut self,
|
||||||
|
rarity_items: &'conf GachaAvailableItemsInfo,
|
||||||
|
category_tag: &String,
|
||||||
|
target_pool: &'conf CharacterGachaPool,
|
||||||
|
) {
|
||||||
|
let gachaconf = gacha::global_gacha_config();
|
||||||
|
let status_bin = self
|
||||||
|
.gacha_status_map
|
||||||
|
.get_mut(&target_pool.sharing_guarantee_info_category)
|
||||||
|
.unwrap();
|
||||||
|
let progress_bin = status_bin
|
||||||
|
.rarity_status_map
|
||||||
|
.get_mut(&rarity_items.rarity)
|
||||||
|
.unwrap();
|
||||||
|
for policy_tag in rarity_items.category_guarantee_policy_tags.iter() {
|
||||||
|
let policy = gachaconf
|
||||||
|
.category_guarantee_policy_map
|
||||||
|
.get(policy_tag)
|
||||||
|
.unwrap();
|
||||||
|
// TODO: Chooseable guarantee not implemented
|
||||||
|
let prev_failure = progress_bin
|
||||||
|
.categories_progress_map
|
||||||
|
.get_mut(policy_tag)
|
||||||
|
.expect(&format!(
|
||||||
|
"post_deserialize forgot StatusBin/rarity_status_map[{}]/categories_progress_map: {}",
|
||||||
|
rarity_items.rarity, policy_tag
|
||||||
|
));
|
||||||
|
if policy.included_category_tags.contains(category_tag) {
|
||||||
|
*prev_failure = 0;
|
||||||
|
} else {
|
||||||
|
*prev_failure += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_discount<'bin, 'conf>(
|
||||||
|
&'bin mut self,
|
||||||
|
target_pool: &'conf CharacterGachaPool,
|
||||||
|
category_tag: &String,
|
||||||
|
rarity_items: &GachaAvailableItemsInfo,
|
||||||
|
) {
|
||||||
|
let gachaconf = gacha::global_gacha_config();
|
||||||
|
for (policy_tag, policy) in gachaconf.discount_policies.must_gain_item_map.iter() {
|
||||||
|
if *category_tag != policy.category_tag {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if !target_pool.discount_policy_tags.contains(policy_tag) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let status_bin = self
|
||||||
|
.gacha_status_map
|
||||||
|
.get_mut(&target_pool.sharing_guarantee_info_category)
|
||||||
|
.unwrap();
|
||||||
|
let usage = status_bin.discount_usage_map.get_mut(policy_tag).unwrap();
|
||||||
|
if *usage < policy.use_limit {
|
||||||
|
*usage += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (policy_tag, policy) in gachaconf.discount_policies.advanced_guarantee_map.iter() {
|
||||||
|
if rarity_items.rarity != policy.rarity {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if !target_pool.discount_policy_tags.contains(policy_tag) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let status_bin = self
|
||||||
|
.gacha_status_map
|
||||||
|
.get_mut(&target_pool.sharing_guarantee_info_category)
|
||||||
|
.unwrap();
|
||||||
|
let usage = status_bin.discount_usage_map.get_mut(policy_tag).unwrap();
|
||||||
|
if *usage < policy.use_limit {
|
||||||
|
*usage += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (policy_tag, policy) in gachaconf.discount_policies.free_select_map.iter() {
|
||||||
|
if !target_pool.discount_policy_tags.contains(policy_tag) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let status_bin = self
|
||||||
|
.gacha_status_map
|
||||||
|
.get_mut(&target_pool.sharing_guarantee_info_category)
|
||||||
|
.unwrap();
|
||||||
|
let progress = status_bin
|
||||||
|
.discount_usage_map
|
||||||
|
.get_mut(&policy.free_select_progress_record_tag)
|
||||||
|
.unwrap();
|
||||||
|
*progress += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_or_add<'a, K: Eq + PartialEq + Hash + Clone, V: Default, S: BuildHasher>(
|
||||||
|
map: &'a mut HashMap<K, V, S>,
|
||||||
|
key: &K,
|
||||||
|
) -> &'a mut V {
|
||||||
|
if !map.contains_key(key) {
|
||||||
|
map.insert(key.clone(), V::default());
|
||||||
|
}
|
||||||
|
map.get_mut(key).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
fn determine_gacha_result<'bin, 'conf>(
|
fn determine_gacha_result<'bin, 'conf>(
|
||||||
pull_time: &DateTime<Local>,
|
pull_time: &DateTime<Local>,
|
||||||
category: &'conf GachaCategoryInfo,
|
category: &'conf GachaCategoryInfo,
|
||||||
target_pool: &'conf CharacterGachaPool,
|
target_pool: &'conf CharacterGachaPool,
|
||||||
status_bin: &'bin GachaStatusBin,
|
status_bin: &'bin GachaStatus,
|
||||||
progress_bin: &'bin GachaProgressBin,
|
progress_bin: &'bin GachaProgress,
|
||||||
rarity_items: &'conf GachaAvailableItemsInfo,
|
rarity_items: &'conf GachaAvailableItemsInfo,
|
||||||
) -> GachaRecordBin {
|
) -> GachaRecord {
|
||||||
let gachaconf = gacha::global_gacha_config();
|
let gachaconf = gacha::global_gacha_config();
|
||||||
let item_pool_len = category.item_ids.len() as u32;
|
let item_pool_len = category.item_ids.len() as u32;
|
||||||
let mut item_id: Option<&u32> = None;
|
let mut item_id: Option<&u32> = None;
|
||||||
|
@ -361,7 +498,7 @@ fn determine_gacha_result<'bin, 'conf>(
|
||||||
.get(rand::thread_rng().gen_range(0..item_pool_len) as usize)
|
.get(rand::thread_rng().gen_range(0..item_pool_len) as usize)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
};
|
};
|
||||||
let mut extra_item_id: u32 = 0;
|
let mut extra_item_id: Option<ItemID> = None;
|
||||||
let mut extra_item_count: u32 = 0;
|
let mut extra_item_count: u32 = 0;
|
||||||
|
|
||||||
for extra_items_policy_tag in rarity_items.extra_items_policy_tags.iter() {
|
for extra_items_policy_tag in rarity_items.extra_items_policy_tags.iter() {
|
||||||
|
@ -372,134 +509,23 @@ fn determine_gacha_result<'bin, 'conf>(
|
||||||
// TODO: apply_on_owned_count in a context with bag
|
// TODO: apply_on_owned_count in a context with bag
|
||||||
// TODO: That's what RoleModel should do, not me.
|
// TODO: That's what RoleModel should do, not me.
|
||||||
if extra_items_policy.apply_on_owned_count == 0 {
|
if extra_items_policy.apply_on_owned_count == 0 {
|
||||||
extra_item_id = extra_items_policy.id;
|
extra_item_id = ItemID::new(extra_items_policy.id);
|
||||||
extra_item_count = extra_items_policy.count;
|
extra_item_count = extra_items_policy.count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let extra_item_bin = GachaExtraItemBin {
|
let extra_resources = match extra_item_id {
|
||||||
extra_item_id,
|
Some(item_id) => Some(GachaExtraResources {
|
||||||
|
extra_item_id: item_id,
|
||||||
extra_item_count,
|
extra_item_count,
|
||||||
currently_gained: 0,
|
}),
|
||||||
|
None => None,
|
||||||
};
|
};
|
||||||
GachaRecordBin {
|
GachaRecord {
|
||||||
pull_timestamp: pull_time.timestamp(),
|
pull_timestamp: pull_time.timestamp(),
|
||||||
obtained_item_id: item_id.clone(),
|
obtained_item_id: ItemID::new_unchecked(item_id.clone()),
|
||||||
gacha_id: target_pool.gacha_schedule_id.clone(),
|
gacha_id: target_pool.gacha_schedule_id.clone(),
|
||||||
progress_map: status_bin.rarity_status_map.clone(),
|
progress_map: status_bin.rarity_status_map.clone(),
|
||||||
extra_item_bin: Some(extra_item_bin),
|
extra_resources,
|
||||||
item_type: category.item_type.into(),
|
item_type: category.item_type.clone(),
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_pity<'bin, 'conf>(
|
|
||||||
gacha_bin: &'bin mut GachaModelBin,
|
|
||||||
rarity_items: &'conf GachaAvailableItemsInfo,
|
|
||||||
probability_model: &'conf ProbabilityModel,
|
|
||||||
target_pool: &'conf CharacterGachaPool,
|
|
||||||
) {
|
|
||||||
let status_bin = gacha_bin
|
|
||||||
.gacha_status_map
|
|
||||||
.get_mut(&target_pool.sharing_guarantee_info_category)
|
|
||||||
.unwrap();
|
|
||||||
for (rarity, rarity_status) in status_bin.rarity_status_map.iter_mut() {
|
|
||||||
if (rarity == &rarity_items.rarity)
|
|
||||||
|| (probability_model.clear_status_on_higher_rarity_pulled
|
|
||||||
&& rarity < &rarity_items.rarity)
|
|
||||||
{
|
|
||||||
rarity_status.pity = 1;
|
|
||||||
} else {
|
|
||||||
rarity_status.pity += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_category_guarantee_info<'bin, 'conf>(
|
|
||||||
gacha_bin: &'bin mut GachaModelBin,
|
|
||||||
rarity_items: &'conf GachaAvailableItemsInfo,
|
|
||||||
category_tag: &String,
|
|
||||||
target_pool: &'conf CharacterGachaPool,
|
|
||||||
) {
|
|
||||||
let gachaconf = gacha::global_gacha_config();
|
|
||||||
let status_bin = gacha_bin
|
|
||||||
.gacha_status_map
|
|
||||||
.get_mut(&target_pool.sharing_guarantee_info_category)
|
|
||||||
.unwrap();
|
|
||||||
let progress_bin = status_bin
|
|
||||||
.rarity_status_map
|
|
||||||
.get_mut(&rarity_items.rarity)
|
|
||||||
.unwrap();
|
|
||||||
for policy_tag in rarity_items.category_guarantee_policy_tags.iter() {
|
|
||||||
let policy = gachaconf
|
|
||||||
.category_guarantee_policy_map
|
|
||||||
.get(policy_tag)
|
|
||||||
.unwrap();
|
|
||||||
// TODO: Chooseable guarantee not implemented
|
|
||||||
let prev_failure = progress_bin
|
|
||||||
.categories_progress_map
|
|
||||||
.get_mut(policy_tag)
|
|
||||||
.expect(&format!(
|
|
||||||
"post_deserialize forgot StatusBin/rarity_status_map[{}]/categories_progress_map: {}",
|
|
||||||
rarity_items.rarity, policy_tag
|
|
||||||
));
|
|
||||||
if policy.included_category_tags.contains(category_tag) {
|
|
||||||
*prev_failure = 0;
|
|
||||||
} else {
|
|
||||||
*prev_failure += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_discount<'bin, 'conf>(
|
|
||||||
gacha_bin: &'bin mut GachaModelBin,
|
|
||||||
target_pool: &'conf CharacterGachaPool,
|
|
||||||
category_tag: &String,
|
|
||||||
rarity_items: &GachaAvailableItemsInfo,
|
|
||||||
) {
|
|
||||||
let gachaconf = gacha::global_gacha_config();
|
|
||||||
for (policy_tag, policy) in gachaconf.discount_policies.must_gain_item_map.iter() {
|
|
||||||
if *category_tag != policy.category_tag {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if !target_pool.discount_policy_tags.contains(policy_tag) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let status_bin = gacha_bin
|
|
||||||
.gacha_status_map
|
|
||||||
.get_mut(&target_pool.sharing_guarantee_info_category)
|
|
||||||
.unwrap();
|
|
||||||
let usage = status_bin.discount_usage_map.get_mut(policy_tag).unwrap();
|
|
||||||
if *usage < policy.use_limit {
|
|
||||||
*usage += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (policy_tag, policy) in gachaconf.discount_policies.advanced_guarantee_map.iter() {
|
|
||||||
if rarity_items.rarity != policy.rarity {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if !target_pool.discount_policy_tags.contains(policy_tag) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let status_bin = gacha_bin
|
|
||||||
.gacha_status_map
|
|
||||||
.get_mut(&target_pool.sharing_guarantee_info_category)
|
|
||||||
.unwrap();
|
|
||||||
let usage = status_bin.discount_usage_map.get_mut(policy_tag).unwrap();
|
|
||||||
if *usage < policy.use_limit {
|
|
||||||
*usage += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (policy_tag, policy) in gachaconf.discount_policies.free_select_map.iter() {
|
|
||||||
if !target_pool.discount_policy_tags.contains(policy_tag) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let status_bin = gacha_bin
|
|
||||||
.gacha_status_map
|
|
||||||
.get_mut(&target_pool.sharing_guarantee_info_category)
|
|
||||||
.unwrap();
|
|
||||||
let progress = status_bin
|
|
||||||
.discount_usage_map
|
|
||||||
.get_mut(&policy.free_select_progress_record_tag)
|
|
||||||
.unwrap();
|
|
||||||
*progress += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
mod client_op;
|
||||||
mod gacha_model;
|
mod gacha_model;
|
||||||
mod record;
|
mod record;
|
||||||
|
mod stat;
|
||||||
|
|
||||||
pub use gacha_model::GachaModel;
|
pub use gacha_model::GachaModel;
|
|
@ -0,0 +1,85 @@
|
||||||
|
use data::gacha::gacha_config::*;
|
||||||
|
use data::tables::ItemID;
|
||||||
|
|
||||||
|
use proto::{GachaExtraItemBin, GachaRecordBin};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use super::stat::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct GachaExtraResources {
|
||||||
|
pub extra_item_id: ItemID,
|
||||||
|
pub extra_item_count: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GachaExtraResources {
|
||||||
|
pub fn from_bin_opt(bin_opt: Option<GachaExtraItemBin>) -> Option<Self> {
|
||||||
|
match bin_opt {
|
||||||
|
None => None,
|
||||||
|
Some(bin) => {
|
||||||
|
let item_id_opt = ItemID::new(bin.extra_item_id);
|
||||||
|
match item_id_opt {
|
||||||
|
None => None,
|
||||||
|
Some(extra_item_id) => Some(Self {
|
||||||
|
extra_item_id,
|
||||||
|
extra_item_count: bin.extra_item_count,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bin_opt(opt: &Option<Self>) -> Option<GachaExtraItemBin> {
|
||||||
|
match opt {
|
||||||
|
None => None,
|
||||||
|
Some(this) => Some(GachaExtraItemBin {
|
||||||
|
extra_item_id: this.extra_item_id.value(),
|
||||||
|
extra_item_count: this.extra_item_count.clone(),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct GachaRecord {
|
||||||
|
pub pull_timestamp: i64,
|
||||||
|
pub obtained_item_id: ItemID,
|
||||||
|
pub gacha_id: u32,
|
||||||
|
/// The progress BEFORE this gacha is performed. key is rarity.
|
||||||
|
pub progress_map: HashMap<u32, GachaProgress>,
|
||||||
|
pub extra_resources: Option<GachaExtraResources>,
|
||||||
|
pub item_type: GachaAddedItemType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GachaRecord {
|
||||||
|
pub fn from_bin(bin: GachaRecordBin) -> Self {
|
||||||
|
Self {
|
||||||
|
pull_timestamp: bin.pull_timestamp,
|
||||||
|
obtained_item_id: ItemID::new_unchecked(bin.obtained_item_id),
|
||||||
|
gacha_id: bin.gacha_id,
|
||||||
|
progress_map: bin
|
||||||
|
.progress_map
|
||||||
|
.into_iter()
|
||||||
|
.map(|(k, v)| (k, GachaProgress::from_bin(v)))
|
||||||
|
.collect(),
|
||||||
|
extra_resources: GachaExtraResources::from_bin_opt(bin.extra_item_bin),
|
||||||
|
item_type: GachaAddedItemType::from(bin.item_type),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bin(&self) -> GachaRecordBin {
|
||||||
|
GachaRecordBin {
|
||||||
|
pull_timestamp: self.pull_timestamp.clone(),
|
||||||
|
obtained_item_id: self.obtained_item_id.value(),
|
||||||
|
gacha_id: self.gacha_id.clone(),
|
||||||
|
progress_map: self
|
||||||
|
.progress_map
|
||||||
|
.iter()
|
||||||
|
.map(|(k, v)| (k.clone(), v.to_bin()))
|
||||||
|
.collect(),
|
||||||
|
extra_item_bin: GachaExtraResources::to_bin_opt(&self.extra_resources),
|
||||||
|
item_type: self.item_type.clone().into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
73
nap_gameserver/src/logic/gacha/stat.rs
Normal file
73
nap_gameserver/src/logic/gacha/stat.rs
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
use proto::*;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone)]
|
||||||
|
pub struct GachaProgress {
|
||||||
|
/// The pity (counting how many pulls) of this pull (in previous record) or the next pull (in status).
|
||||||
|
pub pity: u32,
|
||||||
|
/// The failure times of this category.
|
||||||
|
pub categories_progress_map: HashMap<String, u32>,
|
||||||
|
/// The selected priority (category) for a Chooseable category.
|
||||||
|
pub categories_chosen_guarantee_category_map: HashMap<String, String>,
|
||||||
|
/// The selectedpriority (a specified item) for a Chooseable category.
|
||||||
|
pub categories_chosen_guarantee_item_map: HashMap<String, u32>,
|
||||||
|
/// The failure times for selected priority (a specified item).
|
||||||
|
pub categories_chosen_guarantee_progress_map: HashMap<String, u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GachaProgress {
|
||||||
|
pub fn from_bin(bin: GachaProgressBin) -> Self {
|
||||||
|
Self {
|
||||||
|
pity: bin.pity,
|
||||||
|
categories_progress_map: bin.categories_progress_map,
|
||||||
|
categories_chosen_guarantee_category_map: bin.categories_chosen_guarantee_category_map,
|
||||||
|
categories_chosen_guarantee_item_map: bin.categories_chosen_guarantee_item_map,
|
||||||
|
categories_chosen_guarantee_progress_map: bin.categories_chosen_guarantee_progress_map,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bin(&self) -> GachaProgressBin {
|
||||||
|
GachaProgressBin {
|
||||||
|
pity: self.pity,
|
||||||
|
categories_progress_map: self.categories_progress_map.clone(),
|
||||||
|
categories_chosen_guarantee_category_map: self
|
||||||
|
.categories_chosen_guarantee_category_map
|
||||||
|
.clone(),
|
||||||
|
categories_chosen_guarantee_item_map: self.categories_chosen_guarantee_item_map.clone(),
|
||||||
|
categories_chosen_guarantee_progress_map: self
|
||||||
|
.categories_chosen_guarantee_progress_map
|
||||||
|
.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone)]
|
||||||
|
pub struct GachaStatus {
|
||||||
|
pub rarity_status_map: HashMap<u32, GachaProgress>,
|
||||||
|
pub discount_usage_map: HashMap<String, u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GachaStatus {
|
||||||
|
pub fn from_bin(bin: GachaStatusBin) -> Self {
|
||||||
|
Self {
|
||||||
|
rarity_status_map: bin
|
||||||
|
.rarity_status_map
|
||||||
|
.into_iter()
|
||||||
|
.map(|(k, v)| (k, GachaProgress::from_bin(v)))
|
||||||
|
.collect(),
|
||||||
|
discount_usage_map: bin.discount_usage_map,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bin(&self) -> GachaStatusBin {
|
||||||
|
GachaStatusBin {
|
||||||
|
rarity_status_map: self
|
||||||
|
.rarity_status_map
|
||||||
|
.iter()
|
||||||
|
.map(|(k, v)| (k.clone(), v.to_bin()))
|
||||||
|
.collect(),
|
||||||
|
discount_usage_map: self.discount_usage_map.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
use data::tables::{AvatarBaseID, ProcedureConfigID};
|
use data::tables::{AvatarBaseID, PostGirlConfigID, ProcedureConfigID};
|
||||||
use proto::{BasicDataModelBin, PlayerBasicInfo};
|
use proto::{BasicDataModelBin, PlayerBasicInfo};
|
||||||
|
|
||||||
pub struct BasicDataModel {
|
pub struct BasicDataModel {
|
||||||
|
@ -8,6 +8,7 @@ pub struct BasicDataModel {
|
||||||
pub nick_name: Option<String>,
|
pub nick_name: Option<String>,
|
||||||
pub frontend_avatar_id: Option<AvatarBaseID>,
|
pub frontend_avatar_id: Option<AvatarBaseID>,
|
||||||
pub beginner_procedure_id: Option<ProcedureConfigID>,
|
pub beginner_procedure_id: Option<ProcedureConfigID>,
|
||||||
|
pub selected_post_girl_id: Option<PostGirlConfigID>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for BasicDataModel {
|
impl Default for BasicDataModel {
|
||||||
|
@ -19,6 +20,7 @@ impl Default for BasicDataModel {
|
||||||
nick_name: None,
|
nick_name: None,
|
||||||
frontend_avatar_id: None,
|
frontend_avatar_id: None,
|
||||||
beginner_procedure_id: Some(ProcedureConfigID::new_unchecked(1)),
|
beginner_procedure_id: Some(ProcedureConfigID::new_unchecked(1)),
|
||||||
|
selected_post_girl_id: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,6 +39,10 @@ impl BasicDataModel {
|
||||||
avatar_id,
|
avatar_id,
|
||||||
frontend_avatar_id: avatar_id,
|
frontend_avatar_id: avatar_id,
|
||||||
kbjleelonfe: self.profile_icon,
|
kbjleelonfe: self.profile_icon,
|
||||||
|
has_nickname: match &self.nick_name {
|
||||||
|
Some(_name) => 1,
|
||||||
|
None => 0,
|
||||||
|
},
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,6 +60,7 @@ impl BasicDataModel {
|
||||||
1.. => ProcedureConfigID::new(bin.beginner_procedure_id as u32),
|
1.. => ProcedureConfigID::new(bin.beginner_procedure_id as u32),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
|
selected_post_girl_id: PostGirlConfigID::new(bin.selected_post_girl_id),
|
||||||
nick_name: match bin.nick_name.is_empty() {
|
nick_name: match bin.nick_name.is_empty() {
|
||||||
true => None,
|
true => None,
|
||||||
false => Some(bin.nick_name),
|
false => Some(bin.nick_name),
|
||||||
|
@ -75,6 +82,10 @@ impl BasicDataModel {
|
||||||
.beginner_procedure_id
|
.beginner_procedure_id
|
||||||
.map(|i| i.value() as i32)
|
.map(|i| i.value() as i32)
|
||||||
.unwrap_or(-1),
|
.unwrap_or(-1),
|
||||||
|
selected_post_girl_id: match self.selected_post_girl_id {
|
||||||
|
Some(post_girl_id) => post_girl_id.value(),
|
||||||
|
None => 0
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
use std::collections::BTreeSet;
|
use std::collections::{BTreeSet, HashMap};
|
||||||
|
|
||||||
use data::tables::UnlockConfigID;
|
use data::tables::{quick_access_template_tb, QuickFuncID, UnlockConfigID};
|
||||||
use proto::{LockModelBin, UnlockData};
|
use proto::{LockModelBin, QuickAccessData, QuickAccessType, UnlockData};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct LockModel {
|
pub struct LockModel {
|
||||||
unlock_list: BTreeSet<UnlockConfigID>,
|
unlock_list: BTreeSet<UnlockConfigID>,
|
||||||
|
quick_access_list: HashMap<u32, QuickFuncID>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LockModel {
|
impl LockModel {
|
||||||
|
@ -16,6 +17,11 @@ impl LockModel {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(UnlockConfigID::new_unchecked)
|
.map(UnlockConfigID::new_unchecked)
|
||||||
.collect(),
|
.collect(),
|
||||||
|
quick_access_list: bin
|
||||||
|
.quick_access_list
|
||||||
|
.into_iter()
|
||||||
|
.map(|(k, v)| (k, QuickFuncID::new_unchecked(v)))
|
||||||
|
.collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,10 +33,39 @@ impl LockModel {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|i| i.value())
|
.map(|i| i.value())
|
||||||
.collect(),
|
.collect(),
|
||||||
|
quick_access_list: self
|
||||||
|
.quick_access_list
|
||||||
|
.iter()
|
||||||
|
.map(|(k, v)| (k.clone(), v.value()))
|
||||||
|
.collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn quick_access_to_client(&self) -> Vec<QuickAccessData> {
|
||||||
|
let mut quick_access_data_list: Vec<QuickAccessData> = vec![];
|
||||||
|
for quick_access in quick_access_template_tb::iter() {
|
||||||
|
quick_access_data_list.push(QuickAccessData {
|
||||||
|
r#type: QuickAccessType::Direct.into(),
|
||||||
|
quick_access_index: quick_access.quick_access_index,
|
||||||
|
btn_id: quick_access.quick_func_id.value(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for quick_access_index in 1..8 {
|
||||||
|
let mut btn_id = 0;
|
||||||
|
if let Some(id) = self.quick_access_list.get(&quick_access_index) {
|
||||||
|
btn_id = id.value();
|
||||||
|
}
|
||||||
|
quick_access_data_list.push(QuickAccessData {
|
||||||
|
r#type: QuickAccessType::QuickMenu.into(),
|
||||||
|
quick_access_index,
|
||||||
|
btn_id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
quick_access_data_list
|
||||||
|
}
|
||||||
|
|
||||||
pub fn to_client(&self) -> UnlockData {
|
pub fn to_client(&self) -> UnlockData {
|
||||||
|
|
||||||
UnlockData {
|
UnlockData {
|
||||||
unlock_id_list: self
|
unlock_id_list: self
|
||||||
.unlock_list
|
.unlock_list
|
||||||
|
@ -38,6 +73,7 @@ impl LockModel {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|i| i.value())
|
.map(|i| i.value())
|
||||||
.collect(),
|
.collect(),
|
||||||
|
quick_access_data_list: self.quick_access_to_client(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,4 +85,28 @@ impl LockModel {
|
||||||
pub fn is_unlock(&self, id: UnlockConfigID) -> bool {
|
pub fn is_unlock(&self, id: UnlockConfigID) -> bool {
|
||||||
self.unlock_list.contains(&id)
|
self.unlock_list.contains(&id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mod_quick_access(&mut self, index: u32, id: Option<QuickFuncID>) -> QuickAccessData {
|
||||||
|
let btn_id = match id {
|
||||||
|
Some(quick_access_id) => {
|
||||||
|
if self.quick_access_list.contains_key(&index) {
|
||||||
|
*self.quick_access_list.get_mut(&index).unwrap() = quick_access_id;
|
||||||
|
} else {
|
||||||
|
self.quick_access_list.insert(index, quick_access_id);
|
||||||
|
}
|
||||||
|
quick_access_id.value()
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
if self.quick_access_list.contains_key(&index) {
|
||||||
|
self.quick_access_list.remove(&index);
|
||||||
|
}
|
||||||
|
0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
QuickAccessData {
|
||||||
|
r#type: QuickAccessType::QuickMenu.into(),
|
||||||
|
quick_access_index: index,
|
||||||
|
btn_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1267,7 +1267,7 @@ pub struct Lekadbbedgd {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Ijkfhelddih {
|
pub struct NewbieGroupData {
|
||||||
#[prost(int32, repeated, tag = "5")]
|
#[prost(int32, repeated, tag = "5")]
|
||||||
pub unlock_id_list: ::prost::alloc::vec::Vec<i32>,
|
pub unlock_id_list: ::prost::alloc::vec::Vec<i32>,
|
||||||
}
|
}
|
||||||
|
@ -2250,13 +2250,13 @@ pub struct PlayerSyncScNotify {
|
||||||
#[prost(message, optional, tag = "2")]
|
#[prost(message, optional, tag = "2")]
|
||||||
pub kophiimbjek: ::core::option::Option<Feecjgonjfm>,
|
pub kophiimbjek: ::core::option::Option<Feecjgonjfm>,
|
||||||
#[prost(message, optional, tag = "3")]
|
#[prost(message, optional, tag = "3")]
|
||||||
pub gbfdodbmboh: ::core::option::Option<Efadpnfaelh>,
|
pub client_systems_sync: ::core::option::Option<ClientSystemsSync>,
|
||||||
#[prost(message, optional, tag = "4")]
|
#[prost(message, optional, tag = "4")]
|
||||||
pub ejechecjicb: ::core::option::Option<Iapdkahajkn>,
|
pub ejechecjicb: ::core::option::Option<Iapdkahajkn>,
|
||||||
#[prost(message, optional, tag = "5")]
|
#[prost(message, optional, tag = "5")]
|
||||||
pub fphameaeean: ::core::option::Option<Mbokdhgpobc>,
|
pub fphameaeean: ::core::option::Option<Mbokdhgpobc>,
|
||||||
#[prost(message, optional, tag = "6")]
|
#[prost(message, optional, tag = "6")]
|
||||||
pub ogcaaminman: ::core::option::Option<Ecpbnceekbi>,
|
pub quest_data_sync: ::core::option::Option<QuestDataSync>,
|
||||||
#[prost(message, optional, tag = "7")]
|
#[prost(message, optional, tag = "7")]
|
||||||
pub aklfkgodkde: ::core::option::Option<Dbjpegchcch>,
|
pub aklfkgodkde: ::core::option::Option<Dbjpegchcch>,
|
||||||
#[prost(message, optional, tag = "8")]
|
#[prost(message, optional, tag = "8")]
|
||||||
|
@ -2278,7 +2278,7 @@ pub struct PlayerSyncScNotify {
|
||||||
#[prost(bool, tag = "46")]
|
#[prost(bool, tag = "46")]
|
||||||
pub pibodcappln: bool,
|
pub pibodcappln: bool,
|
||||||
#[prost(message, optional, tag = "82")]
|
#[prost(message, optional, tag = "82")]
|
||||||
pub coagpnjkncf: ::core::option::Option<Bmhfpdagadk>,
|
pub collect_map_sync: ::core::option::Option<CollectMapSync>,
|
||||||
#[prost(message, optional, tag = "162")]
|
#[prost(message, optional, tag = "162")]
|
||||||
pub hffkhegeifp: ::core::option::Option<Lachoecdhnc>,
|
pub hffkhegeifp: ::core::option::Option<Lachoecdhnc>,
|
||||||
#[prost(message, optional, tag = "260")]
|
#[prost(message, optional, tag = "260")]
|
||||||
|
@ -2296,7 +2296,7 @@ pub struct PlayerSyncScNotify {
|
||||||
#[prost(message, optional, tag = "915")]
|
#[prost(message, optional, tag = "915")]
|
||||||
pub dcdddgnhdjj: ::core::option::Option<Dpiceolgbfi>,
|
pub dcdddgnhdjj: ::core::option::Option<Dpiceolgbfi>,
|
||||||
#[prost(message, optional, tag = "1085")]
|
#[prost(message, optional, tag = "1085")]
|
||||||
pub hlcjedhdlfo: ::core::option::Option<Ipimhifmfni>,
|
pub work_bench_sync: ::core::option::Option<WorkBenchSync>,
|
||||||
#[prost(message, optional, tag = "1142")]
|
#[prost(message, optional, tag = "1142")]
|
||||||
pub ahpalhhnkdc: ::core::option::Option<Bnaicfpiiag>,
|
pub ahpalhhnkdc: ::core::option::Option<Bnaicfpiiag>,
|
||||||
#[prost(message, optional, tag = "1440")]
|
#[prost(message, optional, tag = "1440")]
|
||||||
|
@ -2306,7 +2306,7 @@ pub struct PlayerSyncScNotify {
|
||||||
#[prost(message, optional, tag = "1705")]
|
#[prost(message, optional, tag = "1705")]
|
||||||
pub oijhohooded: ::core::option::Option<Edlekkbcaia>,
|
pub oijhohooded: ::core::option::Option<Edlekkbcaia>,
|
||||||
#[prost(message, optional, tag = "1728")]
|
#[prost(message, optional, tag = "1728")]
|
||||||
pub pofhalhdikf: ::core::option::Option<Oaoecalella>,
|
pub vhs_store_sync: ::core::option::Option<VhsStoreSync>,
|
||||||
}
|
}
|
||||||
#[derive(proto_gen::CmdID)]
|
#[derive(proto_gen::CmdID)]
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
|
@ -3025,7 +3025,7 @@ pub struct PlayerBasicInfo {
|
||||||
pub ififobofjhd: bool,
|
pub ififobofjhd: bool,
|
||||||
#[xor(12709)]
|
#[xor(12709)]
|
||||||
#[prost(uint32, tag = "8")]
|
#[prost(uint32, tag = "8")]
|
||||||
pub pmjdniklpgc: u32,
|
pub has_nickname: u32,
|
||||||
#[xor(8317)]
|
#[xor(8317)]
|
||||||
#[prost(uint32, tag = "2")]
|
#[prost(uint32, tag = "2")]
|
||||||
pub level: u32,
|
pub level: u32,
|
||||||
|
@ -3210,7 +3210,7 @@ pub struct UnlockData {
|
||||||
#[prost(int32, repeated, tag = "1")]
|
#[prost(int32, repeated, tag = "1")]
|
||||||
pub unlock_id_list: ::prost::alloc::vec::Vec<i32>,
|
pub unlock_id_list: ::prost::alloc::vec::Vec<i32>,
|
||||||
#[prost(message, repeated, tag = "3")]
|
#[prost(message, repeated, tag = "3")]
|
||||||
pub ppfekhgdpbo: ::prost::alloc::vec::Vec<Jmkeekhhheb>,
|
pub quick_access_data_list: ::prost::alloc::vec::Vec<QuickAccessData>,
|
||||||
#[prost(int32, repeated, tag = "6")]
|
#[prost(int32, repeated, tag = "6")]
|
||||||
pub kefeekedhii: ::prost::alloc::vec::Vec<i32>,
|
pub kefeekedhii: ::prost::alloc::vec::Vec<i32>,
|
||||||
}
|
}
|
||||||
|
@ -3910,17 +3910,17 @@ pub struct Hmchpbjljen {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Ooofknbkhel {
|
pub struct TarotCardData {
|
||||||
#[prost(int32, repeated, tag = "2")]
|
#[prost(int32, repeated, tag = "2")]
|
||||||
pub fpmfdgjhchm: ::prost::alloc::vec::Vec<i32>,
|
pub fpmfdgjhchm: ::prost::alloc::vec::Vec<i32>,
|
||||||
#[prost(int32, repeated, tag = "5")]
|
#[prost(int32, repeated, tag = "5")]
|
||||||
pub llnmdibojio: ::prost::alloc::vec::Vec<i32>,
|
pub not_viewed_list: ::prost::alloc::vec::Vec<i32>,
|
||||||
#[prost(int32, repeated, tag = "9")]
|
#[prost(int32, repeated, tag = "9")]
|
||||||
pub ihnjbpcpfkf: ::prost::alloc::vec::Vec<i32>,
|
pub ihnjbpcpfkf: ::prost::alloc::vec::Vec<i32>,
|
||||||
#[prost(message, repeated, tag = "11")]
|
#[prost(message, repeated, tag = "11")]
|
||||||
pub ofdfjpflbie: ::prost::alloc::vec::Vec<Ifndfopgcph>,
|
pub ofdfjpflbie: ::prost::alloc::vec::Vec<Ifndfopgcph>,
|
||||||
#[prost(int32, repeated, tag = "13")]
|
#[prost(int32, repeated, tag = "13")]
|
||||||
pub nkggmfpghgi: ::prost::alloc::vec::Vec<i32>,
|
pub obtained_list: ::prost::alloc::vec::Vec<i32>,
|
||||||
}
|
}
|
||||||
#[derive(proto_gen::CmdID)]
|
#[derive(proto_gen::CmdID)]
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
|
@ -5396,7 +5396,7 @@ pub struct Icgeifjjpma {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Aboegnnepmi {
|
pub struct CallingCardData {
|
||||||
#[prost(uint32, repeated, tag = "11")]
|
#[prost(uint32, repeated, tag = "11")]
|
||||||
pub ocfaaakaomg: ::prost::alloc::vec::Vec<u32>,
|
pub ocfaaakaomg: ::prost::alloc::vec::Vec<u32>,
|
||||||
#[prost(uint32, repeated, tag = "8")]
|
#[prost(uint32, repeated, tag = "8")]
|
||||||
|
@ -5983,7 +5983,7 @@ pub struct Dgfbapkibje {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Jfkllcaiafj {
|
pub struct InterKnotSync {
|
||||||
#[prost(uint32, repeated, tag = "2")]
|
#[prost(uint32, repeated, tag = "2")]
|
||||||
pub gbcaeaicghd: ::prost::alloc::vec::Vec<u32>,
|
pub gbcaeaicghd: ::prost::alloc::vec::Vec<u32>,
|
||||||
#[prost(uint32, repeated, tag = "3")]
|
#[prost(uint32, repeated, tag = "3")]
|
||||||
|
@ -8738,7 +8738,7 @@ pub struct Ojdhiaepnad {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Mjhicllmahe {
|
pub struct CheckItemSync {
|
||||||
#[prost(uint32, repeated, tag = "1")]
|
#[prost(uint32, repeated, tag = "1")]
|
||||||
pub aighoeokkab: ::prost::alloc::vec::Vec<u32>,
|
pub aighoeokkab: ::prost::alloc::vec::Vec<u32>,
|
||||||
}
|
}
|
||||||
|
@ -9359,11 +9359,11 @@ pub struct Ijkgfnpobob {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Glinfkmgjoj {
|
pub struct CurseData {
|
||||||
#[prost(int32, repeated, tag = "5")]
|
#[prost(int32, repeated, tag = "5")]
|
||||||
pub llnmdibojio: ::prost::alloc::vec::Vec<i32>,
|
pub not_viewed_list: ::prost::alloc::vec::Vec<i32>,
|
||||||
#[prost(int32, repeated, tag = "8")]
|
#[prost(int32, repeated, tag = "8")]
|
||||||
pub nkggmfpghgi: ::prost::alloc::vec::Vec<i32>,
|
pub obtained_list: ::prost::alloc::vec::Vec<i32>,
|
||||||
}
|
}
|
||||||
#[derive(proto_gen::CmdID)]
|
#[derive(proto_gen::CmdID)]
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
|
@ -10437,7 +10437,7 @@ pub struct Abnehcbnadl {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Baodmddgagi {
|
pub struct CallingCardSync {
|
||||||
#[prost(uint32, repeated, tag = "5")]
|
#[prost(uint32, repeated, tag = "5")]
|
||||||
pub ocfaaakaomg: ::prost::alloc::vec::Vec<u32>,
|
pub ocfaaakaomg: ::prost::alloc::vec::Vec<u32>,
|
||||||
#[prost(uint32, repeated, tag = "3")]
|
#[prost(uint32, repeated, tag = "3")]
|
||||||
|
@ -10701,9 +10701,9 @@ pub struct Abjkiejnbak {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Oacoekjapel {
|
pub struct ChangePostGirlCsReq {
|
||||||
#[prost(uint32, repeated, tag = "4")]
|
#[prost(uint32, repeated, tag = "4")]
|
||||||
pub fndfaabfafb: ::prost::alloc::vec::Vec<u32>,
|
pub new_selected_post_girl_id_list: ::prost::alloc::vec::Vec<u32>,
|
||||||
}
|
}
|
||||||
#[derive(proto_gen::CmdID)]
|
#[derive(proto_gen::CmdID)]
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
|
@ -11109,7 +11109,7 @@ pub struct Geemkgcbcng {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Oaoecalella {
|
pub struct VhsStoreSync {
|
||||||
#[prost(message, optional, tag = "11")]
|
#[prost(message, optional, tag = "11")]
|
||||||
pub cfaiklmcfkb: ::core::option::Option<Aimmcpelead>,
|
pub cfaiklmcfkb: ::core::option::Option<Aimmcpelead>,
|
||||||
#[prost(bool, tag = "13")]
|
#[prost(bool, tag = "13")]
|
||||||
|
@ -11366,7 +11366,7 @@ pub struct Acpgildhoed {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Idbdhebkcgg {
|
pub struct ModQuickMenuScRsp {
|
||||||
#[xor(13685)]
|
#[xor(13685)]
|
||||||
#[prost(int32, tag = "1")]
|
#[prost(int32, tag = "1")]
|
||||||
pub retcode: i32,
|
pub retcode: i32,
|
||||||
|
@ -12173,9 +12173,9 @@ pub struct Mbfcgalihdj {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Dpnalcomaii {
|
pub struct ModQuickMenuCsReq {
|
||||||
#[prost(message, repeated, tag = "13")]
|
#[prost(message, repeated, tag = "13")]
|
||||||
pub ppfekhgdpbo: ::prost::alloc::vec::Vec<Jmkeekhhheb>,
|
pub quick_access_data_list: ::prost::alloc::vec::Vec<QuickAccessData>,
|
||||||
}
|
}
|
||||||
#[derive(proto_gen::CmdID)]
|
#[derive(proto_gen::CmdID)]
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
|
@ -12649,7 +12649,7 @@ pub struct Akkbhjhoiao {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Fikgjigadki {
|
pub struct ModNicknameCsReq {
|
||||||
#[xor(13081)]
|
#[xor(13081)]
|
||||||
#[prost(uint32, tag = "12")]
|
#[prost(uint32, tag = "12")]
|
||||||
pub avatar_id: u32,
|
pub avatar_id: u32,
|
||||||
|
@ -12839,7 +12839,7 @@ pub struct Okkjjhonnik {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Hgdnnkfjcmc {
|
pub struct MusicPlayerSync {
|
||||||
#[xor(12784)]
|
#[xor(12784)]
|
||||||
#[prost(uint32, tag = "11")]
|
#[prost(uint32, tag = "11")]
|
||||||
pub mhgnhkmhlgj: u32,
|
pub mhgnhkmhlgj: u32,
|
||||||
|
@ -13605,7 +13605,7 @@ pub struct Bhomgogkadj {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Dmhpnnmggnm {
|
pub struct TrashbinHermitSync {
|
||||||
#[prost(message, repeated, tag = "15")]
|
#[prost(message, repeated, tag = "15")]
|
||||||
pub klbehoieibi: ::prost::alloc::vec::Vec<Ddplihlfngg>,
|
pub klbehoieibi: ::prost::alloc::vec::Vec<Ddplihlfngg>,
|
||||||
}
|
}
|
||||||
|
@ -16157,41 +16157,59 @@ pub struct Fihgfkkpnae {
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct ClientSystemsInfo {
|
pub struct ClientSystemsInfo {
|
||||||
#[prost(message, optional, tag = "1")]
|
#[prost(message, optional, tag = "1")]
|
||||||
pub ilplibfdina: ::core::option::Option<Ipijdhhpbci>,
|
pub teleport_data: ::core::option::Option<TeleportData>,
|
||||||
#[prost(message, optional, tag = "2")]
|
#[prost(message, optional, tag = "2")]
|
||||||
pub aklfkgodkde: ::core::option::Option<Iggbdkbgphj>,
|
pub aklfkgodkde: ::core::option::Option<Iggbdkbgphj>,
|
||||||
#[prost(message, optional, tag = "3")]
|
#[prost(message, optional, tag = "3")]
|
||||||
pub ipfhhabegii: ::core::option::Option<Lcnicjccpde>,
|
pub ipfhhabegii: ::core::option::Option<Lcnicjccpde>,
|
||||||
#[prost(message, optional, tag = "4")]
|
#[prost(message, optional, tag = "4")]
|
||||||
pub post_girl_data: ::core::option::Option<PostGirlData>,
|
pub post_girl_data: ::core::option::Option<PostGirlData>,
|
||||||
|
/// 音乐播放器,主要是收录列表。里面有个 enum 是不是循环模式的意思?
|
||||||
|
///
|
||||||
#[prost(message, optional, tag = "6")]
|
#[prost(message, optional, tag = "6")]
|
||||||
pub djhjojekegc: ::core::option::Option<Knohmlebcbm>,
|
pub music_player_data: ::core::option::Option<MusicPlayerData>,
|
||||||
|
/// 这个应该是解锁鸣徽之类的了。需要进一步研究
|
||||||
|
///
|
||||||
#[prost(message, optional, tag = "7")]
|
#[prost(message, optional, tag = "7")]
|
||||||
pub mhehfjdgkbd: ::core::option::Option<Ooofknbkhel>,
|
pub tarot_card_data: ::core::option::Option<TarotCardData>,
|
||||||
|
/// 这个大概跟剧情有关,下面有个表是已经玩过的过场 ID. 这个过场特指漫画式和几个人放屏幕上的对话式,要是给一个共性就是都可以跳过的
|
||||||
|
///
|
||||||
#[prost(message, optional, tag = "8")]
|
#[prost(message, optional, tag = "8")]
|
||||||
pub mopogebpbeo: ::core::option::Option<Oaljbkehldb>,
|
pub mopogebpbeo: ::core::option::Option<Oaljbkehldb>,
|
||||||
#[prost(message, optional, tag = "9")]
|
#[prost(message, optional, tag = "9")]
|
||||||
pub njidcmpcojg: ::core::option::Option<Ijkfhelddih>,
|
pub newbie_group_data: ::core::option::Option<NewbieGroupData>,
|
||||||
#[prost(message, optional, tag = "10")]
|
#[prost(message, optional, tag = "10")]
|
||||||
pub unlock_data: ::core::option::Option<UnlockData>,
|
pub unlock_data: ::core::option::Option<UnlockData>,
|
||||||
#[prost(message, optional, tag = "11")]
|
#[prost(message, optional, tag = "11")]
|
||||||
pub geoagplahii: ::core::option::Option<NewsStandData>,
|
pub geoagplahii: ::core::option::Option<NewsStandData>,
|
||||||
#[prost(message, optional, tag = "12")]
|
#[prost(message, optional, tag = "12")]
|
||||||
pub trashbin_hermit_data: ::core::option::Option<TrashbinHermitData>,
|
pub trashbin_hermit_data: ::core::option::Option<TrashbinHermitData>,
|
||||||
|
/// 猜测是收藏列表
|
||||||
|
///
|
||||||
#[prost(message, optional, tag = "13")]
|
#[prost(message, optional, tag = "13")]
|
||||||
pub obfepjfnlgi: ::core::option::Option<Jcdicmoemef>,
|
pub collect_data: ::core::option::Option<CollectData>,
|
||||||
|
/// 侵蚀症状..? 大概是曾获得过的意思
|
||||||
|
///
|
||||||
#[prost(message, optional, tag = "14")]
|
#[prost(message, optional, tag = "14")]
|
||||||
pub mkhjcnbgedm: ::core::option::Option<Glinfkmgjoj>,
|
pub curse_data: ::core::option::Option<CurseData>,
|
||||||
|
/// 绳网数据。大概有浏览过的帖子和发表了的回复之类
|
||||||
|
///
|
||||||
#[prost(message, optional, tag = "15")]
|
#[prost(message, optional, tag = "15")]
|
||||||
pub olgibdhglkg: ::core::option::Option<Gfkfedpdede>,
|
pub inter_knot_data: ::core::option::Option<InterKnotData>,
|
||||||
|
/// 成就数据
|
||||||
|
///
|
||||||
#[prost(message, optional, tag = "41")]
|
#[prost(message, optional, tag = "41")]
|
||||||
pub nhmefdfdmfi: ::core::option::Option<Abkjgdcbglg>,
|
pub achievement_data: ::core::option::Option<AchievementData>,
|
||||||
#[prost(message, repeated, tag = "200")]
|
#[prost(message, repeated, tag = "200")]
|
||||||
pub gpfoecchico: ::prost::alloc::vec::Vec<Hmchpbjljen>,
|
pub gpfoecchico: ::prost::alloc::vec::Vec<Hmchpbjljen>,
|
||||||
|
/// 这个大概是喵吉长官的完成数据。不打算管
|
||||||
|
///
|
||||||
#[prost(message, optional, tag = "621")]
|
#[prost(message, optional, tag = "621")]
|
||||||
pub aigkcfkaadf: ::core::option::Option<Efokkbbamai>,
|
pub check_item_data: ::core::option::Option<CheckItemData>,
|
||||||
|
/// 好像是名片数据
|
||||||
|
///
|
||||||
#[prost(message, optional, tag = "800")]
|
#[prost(message, optional, tag = "800")]
|
||||||
pub hbhfjgbahgf: ::core::option::Option<Aboegnnepmi>,
|
pub calling_card_data: ::core::option::Option<CallingCardData>,
|
||||||
#[prost(map = "uint32, int32", tag = "864")]
|
#[prost(map = "uint32, int32", tag = "864")]
|
||||||
pub oomkaabgbmb: ::std::collections::HashMap<u32, i32>,
|
pub oomkaabgbmb: ::std::collections::HashMap<u32, i32>,
|
||||||
#[prost(message, optional, tag = "1228")]
|
#[prost(message, optional, tag = "1228")]
|
||||||
|
@ -18201,7 +18219,7 @@ pub struct GetMonthCardDayRewardCsReq {}
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Ipijdhhpbci {
|
pub struct TeleportData {
|
||||||
#[prost(int32, repeated, tag = "2")]
|
#[prost(int32, repeated, tag = "2")]
|
||||||
pub jmjmkpakijj: ::prost::alloc::vec::Vec<i32>,
|
pub jmjmkpakijj: ::prost::alloc::vec::Vec<i32>,
|
||||||
#[prost(int32, repeated, tag = "15")]
|
#[prost(int32, repeated, tag = "15")]
|
||||||
|
@ -20150,41 +20168,41 @@ pub struct Ocdbdmkhcjl {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Efadpnfaelh {
|
pub struct ClientSystemsSync {
|
||||||
#[prost(uint32, repeated, tag = "1")]
|
#[prost(uint32, repeated, tag = "1")]
|
||||||
pub hgfaaejijhk: ::prost::alloc::vec::Vec<u32>,
|
pub teleport_id_sync: ::prost::alloc::vec::Vec<u32>,
|
||||||
#[prost(message, optional, tag = "2")]
|
#[prost(message, optional, tag = "2")]
|
||||||
pub ofmndhbgdof: ::core::option::Option<Mgicaigalme>,
|
pub ofmndhbgdof: ::core::option::Option<Mgicaigalme>,
|
||||||
#[prost(message, optional, tag = "3")]
|
#[prost(message, optional, tag = "3")]
|
||||||
pub olgibdhglkg: ::core::option::Option<Jfkllcaiafj>,
|
pub inter_knot_data: ::core::option::Option<InterKnotSync>,
|
||||||
#[prost(message, optional, tag = "4")]
|
#[prost(message, optional, tag = "4")]
|
||||||
pub djhjojekegc: ::core::option::Option<Hgdnnkfjcmc>,
|
pub music_player_data: ::core::option::Option<MusicPlayerSync>,
|
||||||
#[prost(uint32, repeated, tag = "5")]
|
#[prost(uint32, repeated, tag = "5")]
|
||||||
pub eccpblmlgjd: ::prost::alloc::vec::Vec<u32>,
|
pub eccpblmlgjd: ::prost::alloc::vec::Vec<u32>,
|
||||||
#[prost(int32, repeated, tag = "6")]
|
#[prost(int32, repeated, tag = "6")]
|
||||||
pub nefkjpdkgkg: ::prost::alloc::vec::Vec<i32>,
|
pub newbie_group_sync: ::prost::alloc::vec::Vec<i32>,
|
||||||
#[prost(uint32, repeated, tag = "7")]
|
#[prost(uint32, repeated, tag = "7")]
|
||||||
pub phnclmchljo: ::prost::alloc::vec::Vec<u32>,
|
pub phnclmchljo: ::prost::alloc::vec::Vec<u32>,
|
||||||
#[prost(message, optional, tag = "8")]
|
#[prost(message, optional, tag = "8")]
|
||||||
pub nhmefdfdmfi: ::core::option::Option<Jdbfjibpilf>,
|
pub achievement_data: ::core::option::Option<AchievementSync>,
|
||||||
#[prost(int32, repeated, tag = "9")]
|
#[prost(int32, repeated, tag = "9")]
|
||||||
pub eghlpajmnmj: ::prost::alloc::vec::Vec<i32>,
|
pub unlock_id_sync: ::prost::alloc::vec::Vec<i32>,
|
||||||
#[prost(message, repeated, tag = "11")]
|
#[prost(message, repeated, tag = "11")]
|
||||||
pub ppfekhgdpbo: ::prost::alloc::vec::Vec<Jmkeekhhheb>,
|
pub quick_access_data_list: ::prost::alloc::vec::Vec<QuickAccessData>,
|
||||||
#[prost(uint32, repeated, tag = "12")]
|
#[prost(uint32, repeated, tag = "12")]
|
||||||
pub mbpddlclekm: ::prost::alloc::vec::Vec<u32>,
|
pub teleport_area_id_sync: ::prost::alloc::vec::Vec<u32>,
|
||||||
#[prost(uint32, repeated, tag = "13")]
|
#[prost(uint32, repeated, tag = "13")]
|
||||||
pub ooiblmdebdf: ::prost::alloc::vec::Vec<u32>,
|
pub ooiblmdebdf: ::prost::alloc::vec::Vec<u32>,
|
||||||
#[prost(message, optional, tag = "14")]
|
#[prost(message, optional, tag = "14")]
|
||||||
pub trashbin_hermit_data: ::core::option::Option<Dmhpnnmggnm>,
|
pub trashbin_hermit_data: ::core::option::Option<TrashbinHermitSync>,
|
||||||
#[prost(message, optional, tag = "15")]
|
#[prost(message, optional, tag = "15")]
|
||||||
pub geoagplahii: ::core::option::Option<Noggnmadkfj>,
|
pub geoagplahii: ::core::option::Option<Noggnmadkfj>,
|
||||||
#[prost(message, optional, tag = "201")]
|
#[prost(message, optional, tag = "201")]
|
||||||
pub post_girl_data: ::core::option::Option<Jakchjjkccg>,
|
pub post_girl_data: ::core::option::Option<PostGirlSync>,
|
||||||
#[prost(message, optional, tag = "281")]
|
#[prost(message, optional, tag = "281")]
|
||||||
pub aigkcfkaadf: ::core::option::Option<Mjhicllmahe>,
|
pub check_item_data: ::core::option::Option<CheckItemSync>,
|
||||||
#[prost(message, optional, tag = "576")]
|
#[prost(message, optional, tag = "576")]
|
||||||
pub hbhfjgbahgf: ::core::option::Option<Baodmddgagi>,
|
pub calling_card_data: ::core::option::Option<CallingCardSync>,
|
||||||
#[prost(message, repeated, tag = "719")]
|
#[prost(message, repeated, tag = "719")]
|
||||||
pub gpfoecchico: ::prost::alloc::vec::Vec<Hmchpbjljen>,
|
pub gpfoecchico: ::prost::alloc::vec::Vec<Hmchpbjljen>,
|
||||||
#[prost(message, optional, tag = "947")]
|
#[prost(message, optional, tag = "947")]
|
||||||
|
@ -20554,7 +20572,7 @@ pub struct Poceahbflhh {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Gfkfedpdede {
|
pub struct InterKnotData {
|
||||||
#[prost(uint32, repeated, tag = "2")]
|
#[prost(uint32, repeated, tag = "2")]
|
||||||
pub gbcaeaicghd: ::prost::alloc::vec::Vec<u32>,
|
pub gbcaeaicghd: ::prost::alloc::vec::Vec<u32>,
|
||||||
#[prost(message, repeated, tag = "6")]
|
#[prost(message, repeated, tag = "6")]
|
||||||
|
@ -21557,11 +21575,11 @@ pub struct Jlmgodmceei {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Jcdicmoemef {
|
pub struct CollectData {
|
||||||
#[prost(int32, repeated, tag = "5")]
|
#[prost(int32, repeated, tag = "5")]
|
||||||
pub nkggmfpghgi: ::prost::alloc::vec::Vec<i32>,
|
pub obtained_list: ::prost::alloc::vec::Vec<i32>,
|
||||||
#[prost(int32, repeated, tag = "10")]
|
#[prost(int32, repeated, tag = "10")]
|
||||||
pub llnmdibojio: ::prost::alloc::vec::Vec<i32>,
|
pub not_viewed_list: ::prost::alloc::vec::Vec<i32>,
|
||||||
}
|
}
|
||||||
#[derive(proto_gen::CmdID)]
|
#[derive(proto_gen::CmdID)]
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
|
@ -21643,7 +21661,7 @@ pub struct Maiibgeljck {}
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Mlcoggemeon {
|
pub struct ChangePostGirlScRsp {
|
||||||
#[xor(1039)]
|
#[xor(1039)]
|
||||||
#[prost(int32, tag = "15")]
|
#[prost(int32, tag = "15")]
|
||||||
pub retcode: i32,
|
pub retcode: i32,
|
||||||
|
@ -22121,7 +22139,7 @@ pub struct Nlahgfcdang {
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Kakpeoaekgb {
|
pub struct Kakpeoaekgb {
|
||||||
#[prost(uint32, repeated, tag = "2")]
|
#[prost(uint32, repeated, tag = "2")]
|
||||||
pub nkggmfpghgi: ::prost::alloc::vec::Vec<u32>,
|
pub obtained_list: ::prost::alloc::vec::Vec<u32>,
|
||||||
#[prost(uint32, repeated, tag = "12")]
|
#[prost(uint32, repeated, tag = "12")]
|
||||||
pub ihnjbpcpfkf: ::prost::alloc::vec::Vec<u32>,
|
pub ihnjbpcpfkf: ::prost::alloc::vec::Vec<u32>,
|
||||||
#[prost(message, repeated, tag = "14")]
|
#[prost(message, repeated, tag = "14")]
|
||||||
|
@ -25132,7 +25150,7 @@ pub struct Fiplebkibam {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Goemgnfnmbj {
|
pub struct ModNicknameScRsp {
|
||||||
#[xor(2680)]
|
#[xor(2680)]
|
||||||
#[prost(int32, tag = "14")]
|
#[prost(int32, tag = "14")]
|
||||||
pub retcode: i32,
|
pub retcode: i32,
|
||||||
|
@ -25528,21 +25546,21 @@ pub struct Bhdmjhjmagn {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Jmkeekhhheb {
|
pub struct QuickAccessData {
|
||||||
#[xor(1243)]
|
#[xor(1243)]
|
||||||
#[prost(uint32, tag = "9")]
|
#[prost(uint32, tag = "9")]
|
||||||
pub bdccceafoak: u32,
|
pub quick_access_index: u32,
|
||||||
#[prost(enumeration = "Ihjpmaigida", tag = "14")]
|
#[prost(enumeration = "QuickAccessType", tag = "14")]
|
||||||
pub r#type: i32,
|
pub r#type: i32,
|
||||||
#[xor(8904)]
|
#[xor(8904)]
|
||||||
#[prost(uint32, tag = "15")]
|
#[prost(uint32, tag = "15")]
|
||||||
pub kabhjlklfla: u32,
|
pub btn_id: u32,
|
||||||
}
|
}
|
||||||
#[derive(proto_gen::CmdID)]
|
#[derive(proto_gen::CmdID)]
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Jakchjjkccg {
|
pub struct PostGirlSync {
|
||||||
#[prost(uint32, repeated, tag = "3")]
|
#[prost(uint32, repeated, tag = "3")]
|
||||||
pub selected_post_girl_id_list: ::prost::alloc::vec::Vec<u32>,
|
pub selected_post_girl_id_list: ::prost::alloc::vec::Vec<u32>,
|
||||||
#[prost(uint32, repeated, tag = "5")]
|
#[prost(uint32, repeated, tag = "5")]
|
||||||
|
@ -25971,7 +25989,7 @@ pub struct Pkamllhinjh {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Abkjgdcbglg {
|
pub struct AchievementData {
|
||||||
#[prost(message, repeated, tag = "13")]
|
#[prost(message, repeated, tag = "13")]
|
||||||
pub emldeipfmma: ::prost::alloc::vec::Vec<Gokcdfmheel>,
|
pub emldeipfmma: ::prost::alloc::vec::Vec<Gokcdfmheel>,
|
||||||
}
|
}
|
||||||
|
@ -28136,7 +28154,7 @@ pub struct Cedamedgpaj {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Efokkbbamai {
|
pub struct CheckItemData {
|
||||||
#[prost(uint32, repeated, tag = "3")]
|
#[prost(uint32, repeated, tag = "3")]
|
||||||
pub aighoeokkab: ::prost::alloc::vec::Vec<u32>,
|
pub aighoeokkab: ::prost::alloc::vec::Vec<u32>,
|
||||||
}
|
}
|
||||||
|
@ -29373,7 +29391,7 @@ pub struct Dchlkminkdl {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Bmhfpdagadk {
|
pub struct CollectMapSync {
|
||||||
#[prost(int32, repeated, tag = "1")]
|
#[prost(int32, repeated, tag = "1")]
|
||||||
pub oeaialfmgng: ::prost::alloc::vec::Vec<i32>,
|
pub oeaialfmgng: ::prost::alloc::vec::Vec<i32>,
|
||||||
#[prost(int32, repeated, tag = "3")]
|
#[prost(int32, repeated, tag = "3")]
|
||||||
|
@ -29846,7 +29864,7 @@ pub struct Cmheepmblfb {}
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Adkopojpgdl {
|
pub struct Adkopojpgdl {
|
||||||
#[prost(message, optional, tag = "1")]
|
#[prost(message, optional, tag = "1")]
|
||||||
pub ogcaaminman: ::core::option::Option<StringEntry>,
|
pub quest_data_sync: ::core::option::Option<StringEntry>,
|
||||||
#[prost(enumeration = "Iojdgcmbnmj", tag = "2")]
|
#[prost(enumeration = "Iojdgcmbnmj", tag = "2")]
|
||||||
pub ghggdeglhka: i32,
|
pub ghggdeglhka: i32,
|
||||||
#[prost(enumeration = "QuestStatus", tag = "3")]
|
#[prost(enumeration = "QuestStatus", tag = "3")]
|
||||||
|
@ -32078,7 +32096,7 @@ pub struct Labeghdefnk {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Ecpbnceekbi {
|
pub struct QuestDataSync {
|
||||||
#[prost(message, optional, tag = "1")]
|
#[prost(message, optional, tag = "1")]
|
||||||
pub khlflpbafip: ::core::option::Option<Fgddalkmick>,
|
pub khlflpbafip: ::core::option::Option<Fgddalkmick>,
|
||||||
#[prost(message, optional, tag = "2")]
|
#[prost(message, optional, tag = "2")]
|
||||||
|
@ -33166,7 +33184,7 @@ pub struct Ekiechelnjg {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Ipimhifmfni {
|
pub struct WorkBenchSync {
|
||||||
#[prost(uint32, repeated, tag = "10")]
|
#[prost(uint32, repeated, tag = "10")]
|
||||||
pub docddodnlon: ::prost::alloc::vec::Vec<u32>,
|
pub docddodnlon: ::prost::alloc::vec::Vec<u32>,
|
||||||
#[prost(uint32, repeated, tag = "4")]
|
#[prost(uint32, repeated, tag = "4")]
|
||||||
|
@ -33474,7 +33492,7 @@ pub struct Ddjecikoocn {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Knohmlebcbm {
|
pub struct MusicPlayerData {
|
||||||
#[xor(13457)]
|
#[xor(13457)]
|
||||||
#[prost(uint32, tag = "13")]
|
#[prost(uint32, tag = "13")]
|
||||||
pub mhgnhkmhlgj: u32,
|
pub mhgnhkmhlgj: u32,
|
||||||
|
@ -34261,7 +34279,7 @@ pub struct Jelnghnjbph {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct Jdbfjibpilf {
|
pub struct AchievementSync {
|
||||||
#[prost(message, repeated, tag = "15")]
|
#[prost(message, repeated, tag = "15")]
|
||||||
pub emldeipfmma: ::prost::alloc::vec::Vec<Gokcdfmheel>,
|
pub emldeipfmma: ::prost::alloc::vec::Vec<Gokcdfmheel>,
|
||||||
}
|
}
|
||||||
|
@ -37711,29 +37729,29 @@ impl Monopkiegjo {
|
||||||
#[derive(proto_gen::XorFields)]
|
#[derive(proto_gen::XorFields)]
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
pub enum Ihjpmaigida {
|
pub enum QuickAccessType {
|
||||||
Mdmamoibbhc = 0,
|
None = 0,
|
||||||
Opbobdiclco = 1,
|
Direct = 1,
|
||||||
Apfhncfijli = 2,
|
QuickMenu = 2,
|
||||||
}
|
}
|
||||||
impl Ihjpmaigida {
|
impl QuickAccessType {
|
||||||
/// String value of the enum field names used in the ProtoBuf definition.
|
/// String value of the enum field names used in the ProtoBuf definition.
|
||||||
///
|
///
|
||||||
/// The values are not transformed in any way and thus are considered stable
|
/// The values are not transformed in any way and thus are considered stable
|
||||||
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
|
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
|
||||||
pub fn as_str_name(&self) -> &'static str {
|
pub fn as_str_name(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Ihjpmaigida::Mdmamoibbhc => "IHJPMAIGIDA_MDMAMOIBBHC",
|
QuickAccessType::None => "QUICK_ACCESS_TYPE_NONE",
|
||||||
Ihjpmaigida::Opbobdiclco => "IHJPMAIGIDA_OPBOBDICLCO",
|
QuickAccessType::Direct => "QUICK_ACCESS_TYPE_DIRECT",
|
||||||
Ihjpmaigida::Apfhncfijli => "IHJPMAIGIDA_APFHNCFIJLI",
|
QuickAccessType::QuickMenu => "QUICK_ACCESS_TYPE_QUICK_MENU",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Creates an enum from field names used in the ProtoBuf definition.
|
/// Creates an enum from field names used in the ProtoBuf definition.
|
||||||
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
|
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
|
||||||
match value {
|
match value {
|
||||||
"IHJPMAIGIDA_MDMAMOIBBHC" => Some(Self::Mdmamoibbhc),
|
"QUICK_ACCESS_TYPE_NONE" => Some(Self::None),
|
||||||
"IHJPMAIGIDA_OPBOBDICLCO" => Some(Self::Opbobdiclco),
|
"QUICK_ACCESS_TYPE_DIRECT" => Some(Self::Direct),
|
||||||
"IHJPMAIGIDA_APFHNCFIJLI" => Some(Self::Apfhncfijli),
|
"QUICK_ACCESS_TYPE_QUICK_MENU" => Some(Self::QuickMenu),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,12 +14,16 @@ pub struct BasicDataModelBin {
|
||||||
pub frontend_avatar_id: i32,
|
pub frontend_avatar_id: i32,
|
||||||
#[prost(int32, tag = "6")]
|
#[prost(int32, tag = "6")]
|
||||||
pub beginner_procedure_id: i32,
|
pub beginner_procedure_id: i32,
|
||||||
|
#[prost(uint32, tag = "7")]
|
||||||
|
pub selected_post_girl_id: u32,
|
||||||
}
|
}
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct LockModelBin {
|
pub struct LockModelBin {
|
||||||
#[prost(int32, repeated, tag = "1")]
|
#[prost(int32, repeated, tag = "1")]
|
||||||
pub unlock_list: ::prost::alloc::vec::Vec<i32>,
|
pub unlock_list: ::prost::alloc::vec::Vec<i32>,
|
||||||
|
#[prost(map = "uint32, uint32", tag = "2")]
|
||||||
|
pub quick_access_list: ::std::collections::HashMap<u32, u32>,
|
||||||
}
|
}
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
|
Loading…
Reference in a new issue