Gacha System implementation #1
5 changed files with 104 additions and 10 deletions
|
@ -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)]
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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 }),
|
||||||
|
|
|
@ -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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue