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 chrono::{prelude::Local, DateTime};
use serde::Deserialize;
use proto::GachaAddedItemType;
use serde::{Deserialize, Deserializer};
use tracing;
#[derive(Debug, Default, Deserialize)]
@ -147,6 +148,21 @@ pub struct GachaCategoryInfo {
pub is_promotional_items: bool,
pub item_ids: Vec<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)]

View file

@ -138,12 +138,13 @@ pub async fn kick(
}
let uid = args[0].parse::<u32>()?;
let default_reason = DisconnectReason::ServerKick.into();
let reason = match args.get(1) {
Some(arg) => match arg.parse::<i32>() {
Ok(val) => val,
Err(_err) => 1,
Err(_err) => default_reason,
},
None => 1,
None => default_reason,
};
let reason_str = match DisconnectReason::try_from(reason) {
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 chrono::{DateTime, Local};
use proto::*;
pub async fn on_get_gacha_data(
_session: &NetSession,
@ -33,6 +36,8 @@ pub async fn on_do_gacha(
) -> NetResult<DoGachaScRsp> {
let gachaconf = global_gacha_config();
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 target_pool = get_gacha_pool(
&gachaconf.character_gacha_pool_list,
@ -47,9 +52,9 @@ pub async fn on_do_gacha(
};
let target_pool = target_pool.unwrap();
// TODO: Validate cost_item_count
// tracing::info!("cost_item_count: {}", body.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 mut cost_count = pull_count;
if pull_count == 10 {
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();
if *usage < discount_policy.use_limit {
*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![];
while pull_count > 0 {
let pull_result = gacha_model.perform_pull_pool(&pull_time, target_pool);
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 {
item_id: pull_result.obtained_item_id,
extra_item_id: extra_item_bin.extra_item_id,
extra_item_count: extra_item_bin.extra_item_count,
uid,
num: 1,
..GainItemInfo::default()
});
@ -193,9 +233,9 @@ fn generate_gacha_info_from_pool(
s_guarantee,
a_guarantee,
need_item_info_list,
// iehkehofjop: target_pool.gacha_parent_schedule_id,
// eggcehlgkii: 223,
// ijoahiepmfo: 101,
lpklhoobkbh: target_pool.gacha_parent_schedule_id,
nammdglepbk: 593,
hgmcofcjmbg: 101,
..Gacha::default()
}
}
@ -211,6 +251,8 @@ fn generate_all_gacha_info(_player: &Player) -> GachaData {
&gachaconf.common_properties,
));
}
// tracing::info!("gacha_list: {:?}", gacha_list);
GachaData {
random_number: 0,
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(),
progress_map: status_bin.rarity_status_map.clone(),
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>,
#[prost(message, optional, tag = "5")]
pub extra_item_bin: ::core::option::Option<GachaExtraItemBin>,
#[prost(enumeration = "GachaAddedItemType", tag = "6")]
pub item_type: i32,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
@ -204,3 +206,35 @@ pub struct PlayerDataBin {
#[prost(message, optional, tag = "6")]
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,
}
}
}