more commands, unlock only default avatars at beginning

Implement 'avatar add' command
Implemented 'player procedure' command
This commit is contained in:
xeon 2024-07-23 18:12:05 +03:00
parent 4b86d62d3f
commit 370f141f88
5 changed files with 149 additions and 38 deletions

View file

@ -0,0 +1,53 @@
use data::tables;
use proto::{AddAvatarPerformType, AddAvatarScNotify, PlayerSyncScNotify};
use crate::ServerState;
pub async fn add(args: &[&str], state: &ServerState) -> Result<String, Box<dyn std::error::Error>> {
const USAGE: &str = "Usage: avatar add [player_uid] [avatar_id]";
if args.len() != 2 {
return Ok(USAGE.to_string());
}
let uid = args[0].parse::<u32>()?;
let avatar_id = args[1].parse::<u32>()?;
let Some(player_lock) = state.player_mgr.get_player(uid).await else {
return Ok(String::from("player not found"));
};
if !tables::avatar_base_template_tb::iter().any(|tmpl| tmpl.id == avatar_id) {
return Ok(format!("avatar with id {avatar_id} doesn't exist"));
}
let (session_id, avatar_sync) = {
let mut player = player_lock.lock().await;
player.role_model.add_avatar(avatar_id);
(player.current_session_id(), player.role_model.avatar_sync())
};
if let Some(session) = session_id.map(|id| state.session_mgr.get(id)).flatten() {
session
.notify(AddAvatarScNotify {
avatar_id,
perform_type: AddAvatarPerformType::Gacha.into(),
..Default::default()
})
.await?;
session
.notify(PlayerSyncScNotify {
avatar: Some(avatar_sync),
..Default::default()
})
.await?;
} else {
state.player_mgr.save_and_remove(uid).await;
}
Ok(format!(
"successfully added avatar {avatar_id} to player {uid}"
))
}

View file

@ -5,6 +5,7 @@ use rustyline_async::{Readline, ReadlineEvent, SharedWriter};
use crate::ServerState;
mod avatar;
mod player;
pub struct CommandManager {
@ -80,5 +81,7 @@ impl CommandManager {
commands! {
player::avatar "[player_uid] [avatar_id]" "changes player avatar for main city";
player::nickname "[player_uid] [nickname]" "changes player nickname";
player::procedure "[player_uid] [procedure_id]" "changes current beginner procedure id, parameter -1 can be used for skipping it";
avatar::add "[player_uid] [avatar_id]" "gives avatar with specified id to player";
}
}

View file

@ -21,7 +21,7 @@ pub async fn avatar(
};
if !tables::avatar_base_template_tb::iter().any(|tmpl| tmpl.id == avatar_id) {
return Ok(format!("section with id {avatar_id} doesn't exist"));
return Ok(format!("avatar with id {avatar_id} doesn't exist"));
}
let should_save = {
@ -72,15 +72,13 @@ pub async fn nickname(
)
};
if let Some(session_id) = session_id {
if let Some(session) = state.session_mgr.get(session_id) {
if let Some(session) = session_id.map(|id| state.session_mgr.get(id)).flatten() {
session
.notify(PlayerSyncScNotify {
basic_info: Some(basic_info),
..Default::default()
})
.await?;
}
} else {
state.player_mgr.save_and_remove(uid).await;
}
@ -89,3 +87,43 @@ pub async fn nickname(
"successfully changed player {uid} nickname to {nickname}"
))
}
pub async fn procedure(
args: &[&str],
state: &ServerState,
) -> Result<String, Box<dyn std::error::Error>> {
const USAGE: &str = "Usage: player procedure [uid] [procedure_id]";
if args.len() != 2 {
return Ok(USAGE.to_string());
}
let uid = args[0].parse::<u32>()?;
let procedure_id = args[1].parse::<i32>()?;
if procedure_id != -1
&& !tables::procedure_config_template_tb::iter()
.any(|tmpl| tmpl.procedure_id == procedure_id)
{
return Ok(format!("procedure_id {procedure_id} doesn't exist"));
}
let Some(player_lock) = state.player_mgr.get_player(uid).await else {
return Ok(String::from("player not found"));
};
let session_id = {
let mut player = player_lock.lock().await;
player.basic_data_model.beginner_procedure_id = procedure_id;
player.current_session_id()
};
if session_id.is_none() {
state.player_mgr.save_and_remove(uid).await;
}
Ok(format!(
"successfully changed procedure_id to {procedure_id}"
))
}

View file

@ -1,5 +1,4 @@
use data::tables;
use proto::RoleModelBin;
use proto::{AvatarSync, RoleModelBin};
use crate::logic::role::Avatar;
@ -10,16 +9,34 @@ pub struct RoleModel {
impl Default for RoleModel {
fn default() -> Self {
Self {
avatar_list: tables::avatar_base_template_tb::iter()
.map(|a| a.id)
.filter(|tmpl_id| *tmpl_id < 2000)
.map(|tmpl_id| Avatar::new(tmpl_id))
avatar_list: Self::DEFAULT_AVATARS
.iter()
.map(|tmpl_id| Avatar::new(*tmpl_id))
.collect(),
}
}
}
impl RoleModel {
const DEFAULT_AVATARS: [u32; 2] = [1011, 1081];
pub fn add_avatar(&mut self, template_id: u32) {
if !self
.avatar_list
.iter()
.any(|a| a.template_id == template_id)
{
self.avatar_list.push(Avatar::new(template_id));
}
}
pub fn avatar_sync(&self) -> AvatarSync {
AvatarSync {
avatar_list: self.avatar_list.iter().map(Avatar::to_client).collect(),
..Default::default()
}
}
pub fn from_bin(bin: RoleModelBin) -> Self {
Self {
avatar_list: bin.avatar_list.into_iter().map(Avatar::from_bin).collect(),

View file

@ -2260,7 +2260,7 @@ pub struct PlayerSyncScNotify {
#[prost(message, optional, tag = "7")]
pub aklfkgodkde: ::core::option::Option<Dbjpegchcch>,
#[prost(message, optional, tag = "8")]
pub hpebckigilk: ::core::option::Option<Ibgbjekpnnb>,
pub avatar: ::core::option::Option<AvatarSync>,
#[prost(message, optional, tag = "9")]
pub oalcbialjcp: ::core::option::Option<Lokebkejkad>,
#[prost(message, optional, tag = "10")]
@ -2865,8 +2865,8 @@ pub struct Cbjppjfbabb {
#[derive(proto_gen::XorFields)]
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Cbegnphfokb {
#[prost(enumeration = "Nnhipbjjhpn", tag = "11")]
pub struct AddAvatarScNotify {
#[prost(enumeration = "AddAvatarPerformType", tag = "11")]
pub perform_type: i32,
#[prost(bool, tag = "2")]
pub aobemkmdkgo: bool,
@ -13667,7 +13667,7 @@ pub struct Falmoffnjhn {
#[derive(proto_gen::XorFields)]
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Ibgbjekpnnb {
pub struct AvatarSync {
#[prost(message, repeated, tag = "11")]
pub avatar_list: ::prost::alloc::vec::Vec<AvatarInfo>,
#[prost(uint32, repeated, tag = "14")]
@ -29107,7 +29107,7 @@ pub struct Hklkphimdcd {
#[prost(enumeration = "TimePeriodType", tag = "4")]
pub feanogfdcjh: i32,
#[prost(enumeration = "AvatarType", tag = "5")]
pub hpebckigilk: i32,
pub avatar: i32,
}
#[derive(proto_gen::CmdID)]
#[derive(proto_gen::XorFields)]
@ -37619,7 +37619,7 @@ impl Iojdgcmbnmj {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum Fjfehdiinkj {
Dcljkmhcfdh = 0,
None = 0,
Cpehddkeocl = 1,
Ceemppmehlf = 2,
}
@ -37630,7 +37630,7 @@ impl Fjfehdiinkj {
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
pub fn as_str_name(&self) -> &'static str {
match self {
Fjfehdiinkj::Dcljkmhcfdh => "FJFEHDIINKJ_DCLJKMHCFDH",
Fjfehdiinkj::None => "FJFEHDIINKJ_NONE",
Fjfehdiinkj::Cpehddkeocl => "FJFEHDIINKJ_CPEHDDKEOCL",
Fjfehdiinkj::Ceemppmehlf => "FJFEHDIINKJ_CEEMPPMEHLF",
}
@ -37638,7 +37638,7 @@ impl Fjfehdiinkj {
/// Creates an enum from field names used in the ProtoBuf definition.
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
match value {
"FJFEHDIINKJ_DCLJKMHCFDH" => Some(Self::Dcljkmhcfdh),
"FJFEHDIINKJ_NONE" => Some(Self::None),
"FJFEHDIINKJ_CPEHDDKEOCL" => Some(Self::Cpehddkeocl),
"FJFEHDIINKJ_CEEMPPMEHLF" => Some(Self::Ceemppmehlf),
_ => None,
@ -37649,29 +37649,29 @@ impl Fjfehdiinkj {
#[derive(proto_gen::XorFields)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum Nnhipbjjhpn {
Dcljkmhcfdh = 0,
Dcldpjgpkag = 1,
Kcaachafbnc = 2,
pub enum AddAvatarPerformType {
None = 0,
ShowPopup = 1,
Gacha = 2,
}
impl Nnhipbjjhpn {
impl AddAvatarPerformType {
/// 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 {
Nnhipbjjhpn::Dcljkmhcfdh => "NNHIPBJJHPN_DCLJKMHCFDH",
Nnhipbjjhpn::Dcldpjgpkag => "NNHIPBJJHPN_DCLDPJGPKAG",
Nnhipbjjhpn::Kcaachafbnc => "NNHIPBJJHPN_KCAACHAFBNC",
AddAvatarPerformType::None => "ADD_AVATAR_PERFORM_TYPE_NONE",
AddAvatarPerformType::ShowPopup => "ADD_AVATAR_PERFORM_TYPE_SHOW_POPUP",
AddAvatarPerformType::Gacha => "ADD_AVATAR_PERFORM_TYPE_GACHA",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
match value {
"NNHIPBJJHPN_DCLJKMHCFDH" => Some(Self::Dcljkmhcfdh),
"NNHIPBJJHPN_DCLDPJGPKAG" => Some(Self::Dcldpjgpkag),
"NNHIPBJJHPN_KCAACHAFBNC" => Some(Self::Kcaachafbnc),
"ADD_AVATAR_PERFORM_TYPE_NONE" => Some(Self::None),
"ADD_AVATAR_PERFORM_TYPE_SHOW_POPUP" => Some(Self::ShowPopup),
"ADD_AVATAR_PERFORM_TYPE_GACHA" => Some(Self::Gacha),
_ => None,
}
}
@ -44829,7 +44829,7 @@ impl Cmmembfifpk {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum Onmblkkmfje {
Dcljkmhcfdh = 0,
None = 0,
Njkogaelffh = 2,
Dbldnilkljk = 3,
Lcdlmcjihee = 4,
@ -44842,7 +44842,7 @@ impl Onmblkkmfje {
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
pub fn as_str_name(&self) -> &'static str {
match self {
Onmblkkmfje::Dcljkmhcfdh => "ONMBLKKMFJE_DCLJKMHCFDH",
Onmblkkmfje::None => "ONMBLKKMFJE_NONE",
Onmblkkmfje::Njkogaelffh => "ONMBLKKMFJE_NJKOGAELFFH",
Onmblkkmfje::Dbldnilkljk => "ONMBLKKMFJE_DBLDNILKLJK",
Onmblkkmfje::Lcdlmcjihee => "ONMBLKKMFJE_LCDLMCJIHEE",
@ -44852,7 +44852,7 @@ impl Onmblkkmfje {
/// Creates an enum from field names used in the ProtoBuf definition.
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
match value {
"ONMBLKKMFJE_DCLJKMHCFDH" => Some(Self::Dcljkmhcfdh),
"ONMBLKKMFJE_NONE" => Some(Self::None),
"ONMBLKKMFJE_NJKOGAELFFH" => Some(Self::Njkogaelffh),
"ONMBLKKMFJE_DBLDNILKLJK" => Some(Self::Dbldnilkljk),
"ONMBLKKMFJE_LCDLMCJIHEE" => Some(Self::Lcdlmcjihee),