Gacha System implementation #1

Merged
xeon merged 7 commits from YYHEggEgg/JaneDoe-ZS:master into master 2024-08-04 11:41:24 +00:00
5 changed files with 104 additions and 10 deletions
Showing only changes of commit 05e8ef740d - Show all commits

View file

@ -1,7 +1,8 @@
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use chrono::{prelude::Local, DateTime}; use chrono::{prelude::Local, DateTime};
use serde::Deserialize; use proto::GachaAddedItemType;
use serde::{Deserialize, Deserializer};
use tracing; use tracing;
#[derive(Debug, Default, Deserialize)] #[derive(Debug, Default, Deserialize)]
@ -147,6 +148,21 @@ pub struct GachaCategoryInfo {
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")]
pub item_type: GachaAddedItemType,
}
pub fn from_str<'de, D>(deserializer: D) -> Result<GachaAddedItemType, D::Error>
where
D: Deserializer<'de>,
{
let s: String = Deserialize::deserialize(deserializer)?;
let result = GachaAddedItemType::from_str_name(&s);
match result {
Some(val) => Ok(val),
None => Ok(GachaAddedItemType::None)
}
} }
#[derive(Debug, Default, Deserialize)] #[derive(Debug, Default, Deserialize)]

View file

@ -138,12 +138,13 @@ pub async fn kick(
} }
let uid = args[0].parse::<u32>()?; let uid = args[0].parse::<u32>()?;
let default_reason = DisconnectReason::ServerKick.into();
let reason = match args.get(1) { let reason = match args.get(1) {
Some(arg) => match arg.parse::<i32>() { Some(arg) => match arg.parse::<i32>() {
Ok(val) => val, Ok(val) => val,
Err(_err) => 1, Err(_err) => default_reason,
}, },
None => 1, None => default_reason,
}; };
let reason_str = match DisconnectReason::try_from(reason) { let reason_str = match DisconnectReason::try_from(reason) {
Ok(converted_enum) => converted_enum.as_str_name().to_owned(), Ok(converted_enum) => converted_enum.as_str_name().to_owned(),

View file

@ -1,8 +1,11 @@
use data::gacha::{gacha_config::*, global_gacha_config}; use data::{
gacha::{gacha_config::*, global_gacha_config},
tables::{AvatarBaseID, WeaponID},
};
use proto::*;
use super::*; use super::*;
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,
@ -33,6 +36,8 @@ pub async fn on_do_gacha(
) -> NetResult<DoGachaScRsp> { ) -> NetResult<DoGachaScRsp> {
let gachaconf = global_gacha_config(); let gachaconf = global_gacha_config();
let gacha_model = &mut _player.gacha_model; let gacha_model = &mut _player.gacha_model;
let item_model = &mut _player.item_model;
let role_model = &mut _player.role_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,
@ -47,9 +52,9 @@ pub async fn on_do_gacha(
}; };
let target_pool = target_pool.unwrap(); let target_pool = target_pool.unwrap();
// TODO: Validate cost_item_count // tracing::info!("cost_item_count: {}", req.cost_item_count);
// tracing::info!("cost_item_count: {}", body.cost_item_count);
let mut pull_count = if req.cost_item_count > 1 { 10 } else { 1 }; let mut pull_count = if req.cost_item_count > 1 { 10 } else { 1 };
let mut cost_count = pull_count;
if pull_count == 10 { if pull_count == 10 {
let discount_tag = &gachaconf.common_properties.ten_pull_discount_tag; let discount_tag = &gachaconf.common_properties.ten_pull_discount_tag;
@ -67,18 +72,53 @@ pub async fn on_do_gacha(
let usage = status_bin.discount_usage_map.get_mut(discount_tag).unwrap(); let usage = status_bin.discount_usage_map.get_mut(discount_tag).unwrap();
if *usage < discount_policy.use_limit { if *usage < discount_policy.use_limit {
*usage += 1; *usage += 1;
cost_count = discount_policy.discounted_prize;
} }
} }
} }
if cost_count != req.cost_item_count {
return Ok(DoGachaScRsp {
retcode: Retcode::RetFail.into(),
..Default::default()
});
} else {
// TODO: cost resource
}
let mut gain_item_list: Vec<GainItemInfo> = vec![]; let mut gain_item_list: Vec<GainItemInfo> = vec![];
while pull_count > 0 { while pull_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.unwrap(); let extra_item_bin = pull_result.extra_item_bin.unwrap();
let uid = match GachaAddedItemType::try_from(pull_result.item_type) {
Ok(enum_val) => match enum_val {
GachaAddedItemType::Weapon => match WeaponID::new(pull_result.obtained_item_id) {
Some(id) => item_model.add_weapon(id).value(),
None => 0,
},
GachaAddedItemType::Character => {
match AvatarBaseID::new(pull_result.obtained_item_id) {
Some(id) => {
role_model.add_avatar(id);
0
}
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,
);
}
gain_item_list.push(GainItemInfo { gain_item_list.push(GainItemInfo {
item_id: pull_result.obtained_item_id, item_id: pull_result.obtained_item_id,
extra_item_id: extra_item_bin.extra_item_id, extra_item_id: extra_item_bin.extra_item_id,
extra_item_count: extra_item_bin.extra_item_count, extra_item_count: extra_item_bin.extra_item_count,
uid,
num: 1, num: 1,
..GainItemInfo::default() ..GainItemInfo::default()
}); });
@ -193,9 +233,9 @@ fn generate_gacha_info_from_pool(
s_guarantee, s_guarantee,
a_guarantee, a_guarantee,
need_item_info_list, need_item_info_list,
// iehkehofjop: target_pool.gacha_parent_schedule_id, lpklhoobkbh: target_pool.gacha_parent_schedule_id,
// eggcehlgkii: 223, nammdglepbk: 593,
// ijoahiepmfo: 101, hgmcofcjmbg: 101,
..Gacha::default() ..Gacha::default()
} }
} }
@ -211,6 +251,8 @@ fn generate_all_gacha_info(_player: &Player) -> GachaData {
&gachaconf.common_properties, &gachaconf.common_properties,
)); ));
} }
// tracing::info!("gacha_list: {:?}", gacha_list);
GachaData { GachaData {
random_number: 0, random_number: 0,
gacha_pool: Some(GachaPool { gacha_list }), gacha_pool: Some(GachaPool { gacha_list }),

View file

@ -295,6 +295,7 @@ fn determine_gacha_result<'bin, 'conf>(
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_item_bin: Some(extra_item_bin),
item_type: category.item_type.into(),
} }
} }

View file

@ -162,6 +162,8 @@ pub struct GachaRecordBin {
pub progress_map: ::std::collections::HashMap<u32, GachaProgressBin>, pub progress_map: ::std::collections::HashMap<u32, GachaProgressBin>,
#[prost(message, optional, tag = "5")] #[prost(message, optional, tag = "5")]
pub extra_item_bin: ::core::option::Option<GachaExtraItemBin>, pub extra_item_bin: ::core::option::Option<GachaExtraItemBin>,
#[prost(enumeration = "GachaAddedItemType", tag = "6")]
pub item_type: i32,
} }
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
@ -204,3 +206,35 @@ pub struct PlayerDataBin {
#[prost(message, optional, tag = "6")] #[prost(message, optional, tag = "6")]
pub gacha_model: ::core::option::Option<GachaModelBin>, pub gacha_model: ::core::option::Option<GachaModelBin>,
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum GachaAddedItemType {
None = 0,
Weapon = 1,
Character = 2,
Bangboo = 3,
}
impl GachaAddedItemType {
/// 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
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
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",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
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,
}
}
}