914 lines
32 KiB
Rust
914 lines
32 KiB
Rust
use std::{
|
|
cell::{Cell, RefCell},
|
|
rc::{Rc, Weak},
|
|
sync::{self, mpsc::Receiver, Arc},
|
|
};
|
|
|
|
use common::{net::tools::Packet, tools::time_utils};
|
|
use data::{
|
|
get_default_world_main_scene_id,
|
|
math_def::Vector3,
|
|
prop_type::{
|
|
PROP_CUR_PERSIST_STAMINA, PROP_IS_FLYABLE, PROP_IS_GAME_TIME_LOCKED,
|
|
PROP_IS_SPRING_AUTO_USE, PROP_IS_TRANSFERABLE, PROP_IS_WEATHER_LOCKED, PROP_MAX_STAMINA,
|
|
PROP_PLAYER_EXP, PROP_PLAYER_HCOIN, PROP_PLAYER_LEVEL, PROP_PLAYER_SCOIN,
|
|
PROP_SPRING_AUTO_USE_PERCENT,
|
|
},
|
|
AvatarUseType,
|
|
};
|
|
|
|
use prost::Message;
|
|
use proto::{
|
|
AbilitySyncStateInfo, AvatarEnterSceneInfo, CmdID, DoSetPlayerBornDataNotify,
|
|
EnterSceneDoneReq, EnterSceneDoneRsp, EnterScenePeerNotify, EnterSceneReadyReq, EnterType,
|
|
MpLevelEntityInfo, PacketHead, PingReq, PingRsp, PlayerData, PlayerDataBin, PlayerDataNotify,
|
|
PlayerEnterSceneInfoNotify, PlayerEnterSceneNotify, PlayerLoginRsp, PostEnterSceneReq,
|
|
PostEnterSceneRsp, Retcode, SavePlayerDataReq, SceneInitFinishReq, SetPlayerBornDataReq,
|
|
TeamEnterSceneInfo, VisionType, YSMessage,
|
|
};
|
|
use rand::RngCore;
|
|
|
|
use crate::{
|
|
creature::{property::append_int_prop_value, Creature, LifeState},
|
|
entity::{Entity, VisionContext},
|
|
gadget::WeaponGadget,
|
|
gameserver_service, handler,
|
|
network::PlayerSessionProxy,
|
|
scene::{EnterSceneState, PlayerSceneComp, Scene},
|
|
};
|
|
|
|
use super::{
|
|
avatar::PlayerAvatarComp, basic::PlayerBasicComp, item::PlayerItemComp, PlayerCoroExec,
|
|
PlayerLoginComp,
|
|
};
|
|
|
|
pub struct Player {
|
|
pub uid: u32,
|
|
session: RefCell<sync::Weak<PlayerSessionProxy>>,
|
|
pub player_basic_comp: Rc<RefCell<PlayerBasicComp>>,
|
|
pub player_login_comp: Rc<RefCell<PlayerLoginComp>>,
|
|
pub player_avatar_comp: Rc<RefCell<PlayerAvatarComp>>,
|
|
pub player_scene_comp: Rc<RefCell<PlayerSceneComp>>,
|
|
pub player_item_comp: Rc<RefCell<PlayerItemComp>>,
|
|
pub peer_id: Cell<u32>,
|
|
last_recv_ping_time: Cell<u64>,
|
|
last_save_time: Cell<u64>,
|
|
is_coro_stopping: Cell<bool>,
|
|
}
|
|
|
|
impl Player {
|
|
pub fn construct_player(uid: u32) -> Self {
|
|
Self {
|
|
uid,
|
|
session: RefCell::new(sync::Weak::new()),
|
|
player_basic_comp: Rc::new(RefCell::new(PlayerBasicComp::default())),
|
|
player_login_comp: Rc::new(RefCell::new(PlayerLoginComp::default())),
|
|
player_avatar_comp: Rc::new(RefCell::new(PlayerAvatarComp::default())),
|
|
player_scene_comp: Rc::new(RefCell::new(PlayerSceneComp::default())),
|
|
player_item_comp: Rc::new(RefCell::new(PlayerItemComp::default())),
|
|
peer_id: Cell::new(0),
|
|
last_recv_ping_time: Cell::new(0),
|
|
last_save_time: Cell::new(0),
|
|
is_coro_stopping: Cell::new(false),
|
|
}
|
|
}
|
|
|
|
pub fn login(
|
|
&self,
|
|
is_new_player: bool,
|
|
is_relogin: bool,
|
|
target_uid: u32,
|
|
target_home_owner_uid: u32,
|
|
is_client_relogin: bool,
|
|
) {
|
|
tracing::info!("Player::login uid:{} is_new_player:{} is_relogin:{} target_uid:{} is_client_relogin:{}", self.uid, is_new_player, is_relogin, target_uid, is_client_relogin);
|
|
|
|
self.update_last_ping_time();
|
|
self.player_scene_comp.borrow_mut().pre_login(is_relogin);
|
|
if is_new_player {
|
|
self.first_login();
|
|
}
|
|
|
|
// TODO: checkLuaShellOnLogin
|
|
|
|
self.player_basic_comp.borrow_mut().on_login(is_new_player);
|
|
self.player_login_comp.borrow_mut().on_login(is_new_player);
|
|
self.player_item_comp.borrow_mut().on_login(is_new_player);
|
|
self.player_avatar_comp.borrow_mut().on_login(is_new_player);
|
|
self.player_scene_comp.borrow_mut().on_login(is_new_player);
|
|
|
|
// TODO: PlayerSceneComp::afterLogin
|
|
|
|
if self.player_avatar_comp.borrow().get_avatar_count() == 0 {
|
|
self.send_proto(DoSetPlayerBornDataNotify::default());
|
|
} else {
|
|
self.init_and_begin_enter_scene(
|
|
false,
|
|
target_uid,
|
|
target_home_owner_uid,
|
|
is_client_relogin,
|
|
);
|
|
}
|
|
}
|
|
|
|
fn first_login(&self) {
|
|
self.player_basic_comp.borrow_mut().on_first_login();
|
|
self.player_avatar_comp.borrow_mut().on_first_login();
|
|
self.player_scene_comp.borrow_mut().on_first_login();
|
|
}
|
|
|
|
pub fn block_stop_coroutine(&self) -> Result<(), ()> {
|
|
if self.is_coro_stopping.get() {
|
|
tracing::error!("block_stop_coroutine called repeated, uid:{}", self.uid);
|
|
return Err(());
|
|
}
|
|
|
|
self.is_coro_stopping.set(true);
|
|
Ok(())
|
|
}
|
|
|
|
fn coroutine_loop(uid: u32, rx: Receiver<Packet>, session: Arc<PlayerSessionProxy>) {
|
|
let player = Rc::new(Self::construct_player(uid));
|
|
player.set_session(session, false);
|
|
|
|
loop {
|
|
if player.is_coro_stopping.get() {
|
|
break;
|
|
}
|
|
|
|
let packet = rx.recv().unwrap();
|
|
|
|
match packet.cmd_id {
|
|
PlayerLoginRsp::CMD_ID => {
|
|
let rsp: PlayerLoginRsp = packet.get_proto().unwrap();
|
|
let player_data = PlayerData::decode(rsp.player_data.as_ref()).unwrap();
|
|
player.from_bin(player_data).unwrap();
|
|
player.init();
|
|
|
|
player.login(rsp.is_new_player, false, 0, 0, false);
|
|
|
|
let rsp = PlayerLoginRsp {
|
|
player_data: Vec::with_capacity(0),
|
|
..rsp
|
|
};
|
|
|
|
player.send_proto(rsp);
|
|
|
|
// First post-login save
|
|
player.save_to_db();
|
|
player.last_save_time.set(time_utils::get_now());
|
|
}
|
|
_ => {
|
|
let _ = handler::process_packet(&player, packet);
|
|
}
|
|
}
|
|
|
|
// TODO: configurable save time?
|
|
if time_utils::get_now() - player.last_save_time.get() > 30 {
|
|
player.save_to_db();
|
|
player.last_save_time.set(time_utils::get_now());
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn start(session: Arc<PlayerSessionProxy>, uid: u32) -> PlayerCoroExec {
|
|
PlayerCoroExec::start(move |rx| Self::coroutine_loop(uid, rx, session.clone()))
|
|
}
|
|
|
|
pub fn set_session(&self, session: Arc<PlayerSessionProxy>, _is_relogin: bool) {
|
|
*self.session.borrow_mut() = Arc::downgrade(&session);
|
|
}
|
|
|
|
pub fn send_proto(&self, proto: impl YSMessage) {
|
|
self.session
|
|
.borrow()
|
|
.upgrade()
|
|
.unwrap()
|
|
.send_packet(Packet {
|
|
cmd_id: proto.get_cmd_id(),
|
|
head: PacketHead::default(),
|
|
recv_vec: proto.encode_to_vec(),
|
|
});
|
|
}
|
|
|
|
pub fn on_ping_req(&self, req: PingReq, rsp: &mut PingRsp) {
|
|
tracing::info!("[PING] uid:{}, seq:{}", self.uid, req.seq);
|
|
rsp.retcode = Retcode::RetSucc.into();
|
|
rsp.seq = req.seq;
|
|
rsp.client_time = req.client_time;
|
|
self.update_last_ping_time();
|
|
}
|
|
|
|
pub fn set_player_born_data(&self, req: SetPlayerBornDataReq) -> Result<(), Retcode> {
|
|
if self.player_avatar_comp.borrow().get_avatar_count() != 0 {
|
|
return Err(Retcode::RetRepeatSetPlayerBornData);
|
|
}
|
|
|
|
self.player_basic_comp
|
|
.borrow()
|
|
.check_nick_name(&req.nick_name)?;
|
|
|
|
if self
|
|
.player_avatar_comp
|
|
.borrow_mut()
|
|
.set_born_avatar(req.avatar_id)
|
|
.is_err()
|
|
{
|
|
return Err(Retcode::RetAvatarIdError);
|
|
}
|
|
|
|
self.player_basic_comp.borrow_mut().nickname = req.nick_name;
|
|
self.init_and_begin_enter_scene(false, 0, 0, false);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn check_is_in_safe_state_for_change_team(&self) -> Result<(), Retcode> {
|
|
Ok(())
|
|
}
|
|
|
|
pub fn init_and_begin_enter_scene(
|
|
&self,
|
|
_is_relogin: bool,
|
|
_target_uid: u32,
|
|
_target_home_owner_uid: u32,
|
|
_is_client_relogin: bool,
|
|
) {
|
|
// Unlock all stuff here
|
|
// TODO: MUIP/GM for this
|
|
|
|
self.player_avatar_comp.borrow_mut().is_flyable = true;
|
|
self.player_avatar_comp.borrow_mut().is_transferable = true;
|
|
self.player_avatar_comp.borrow_mut().is_spring_auto_use = true;
|
|
self.player_avatar_comp.borrow_mut().spring_auto_use_percent = 50;
|
|
|
|
for open_state in data::iter_open_state_data() {
|
|
self.player_basic_comp
|
|
.borrow_mut()
|
|
.open_state_map
|
|
.insert(open_state.id, 1);
|
|
}
|
|
|
|
for avatar in data::iter_avatar_data() {
|
|
if avatar.use_type == AvatarUseType::AvatarFormal {
|
|
if !self.player_avatar_comp.borrow().has_avatar(avatar.id, 1) {
|
|
self.player_avatar_comp
|
|
.borrow_mut()
|
|
.add_formal_avatar(avatar.id, false, 1, 0)
|
|
.unwrap();
|
|
}
|
|
}
|
|
}
|
|
|
|
self.notify_all_data();
|
|
|
|
let cur_scene_id = get_default_world_main_scene_id();
|
|
|
|
let cur_scene = {
|
|
let mut scene_comp = self.player_scene_comp.borrow_mut();
|
|
scene_comp.dest_world_ptr = Some(scene_comp.own_world.clone());
|
|
|
|
let dest_world = scene_comp.own_world.borrow();
|
|
let cur_scene = dest_world.scene_map.get(&cur_scene_id).unwrap().clone();
|
|
cur_scene.borrow_mut().base_mut().cur_world_wtr = Rc::downgrade(&scene_comp.own_world);
|
|
|
|
cur_scene
|
|
};
|
|
|
|
let (pos, rot) = {
|
|
let cur_scene = cur_scene.borrow_mut();
|
|
cur_scene.base().get_last_owner_location()
|
|
};
|
|
|
|
self.begin_enter_scene(
|
|
cur_scene,
|
|
pos,
|
|
rot,
|
|
EnterType::EnterSelf,
|
|
VisionType::VisionMeet,
|
|
);
|
|
}
|
|
|
|
fn begin_enter_scene(
|
|
&self,
|
|
dest_scene_ptr: Rc<RefCell<Scene>>,
|
|
pos: Vector3,
|
|
rot: Vector3,
|
|
enter_type: EnterType,
|
|
vision_type: VisionType,
|
|
) {
|
|
let mut scene_comp = self.player_scene_comp.borrow_mut();
|
|
if scene_comp.enter_scene_state != EnterSceneState::ENTER_SCENE_NONE
|
|
&& scene_comp.enter_scene_state != EnterSceneState::ENTER_SCENE_POST
|
|
{
|
|
tracing::warn!(
|
|
"begin_enter_scene with last one not finish, uid:{}",
|
|
self.uid
|
|
);
|
|
}
|
|
|
|
self.mark_destination(
|
|
&dest_scene_ptr,
|
|
pos.clone(),
|
|
rot,
|
|
enter_type,
|
|
vision_type,
|
|
&mut scene_comp,
|
|
);
|
|
|
|
let enter_scene_token = match scene_comp.enter_scene_token {
|
|
0 => rand::thread_rng().next_u32() & 0xFFFF, // OG: gettid lmfao
|
|
_ => scene_comp.enter_scene_token.wrapping_add(100),
|
|
};
|
|
|
|
scene_comp.enter_scene_token = enter_scene_token;
|
|
|
|
let scene = dest_scene_ptr.borrow();
|
|
let scene_id = scene.base().scene_id;
|
|
let notify = PlayerEnterSceneNotify {
|
|
scene_id,
|
|
pos: Some(pos.to_client()),
|
|
scene_transaction: scene.base().scene_transaction.clone(),
|
|
enter_scene_token,
|
|
scene_begin_time: scene.base().begin_time_ms,
|
|
r#type: enter_type.into(),
|
|
target_uid: self.uid,
|
|
..Default::default()
|
|
};
|
|
|
|
scene_comp.enter_scene_state = EnterSceneState::ENTER_SCENE_NOTIFY;
|
|
|
|
tracing::info!("[EnterScene] BeginEnterScene uid:{} enter_type:{:?} token:{} dest_scene_id:{} pos:{:?} target_uid:{}", self.uid, enter_type, notify.enter_scene_token, scene_id, pos, 0);
|
|
|
|
self.send_proto(notify);
|
|
}
|
|
|
|
pub fn enter_scene_ready(self: &Rc<Self>, req: &EnterSceneReadyReq) -> Result<(), Retcode> {
|
|
{
|
|
let scene_comp = self.player_scene_comp.borrow();
|
|
|
|
if scene_comp.enter_scene_token != req.enter_scene_token {
|
|
tracing::info!(
|
|
"[EnterScene] token not match, client_token:{} server_token:{}",
|
|
req.enter_scene_token,
|
|
scene_comp.enter_scene_token
|
|
);
|
|
|
|
return Err(Retcode::RetEnterSceneTokenInvalid);
|
|
}
|
|
|
|
if scene_comp.enter_scene_state != EnterSceneState::ENTER_SCENE_NOTIFY {
|
|
tracing::warn!("EnterSceneState is not EnterSceneNotify, uid:{}", self.uid);
|
|
return Err(Retcode::RetFail);
|
|
}
|
|
};
|
|
|
|
self.pre_enter_scene()?;
|
|
|
|
let mut scene_comp = self.player_scene_comp.borrow_mut();
|
|
let dest_scene = scene_comp.get_dest_scene().unwrap();
|
|
let dest_scene = dest_scene.borrow();
|
|
let scene = dest_scene.base();
|
|
let notify = EnterScenePeerNotify {
|
|
enter_scene_token: scene_comp.enter_scene_token,
|
|
dest_scene_id: scene_comp.dest_scene_id,
|
|
host_peer_id: scene.get_host_peer_id().unwrap_or_default(),
|
|
peer_id: scene.get_peer_id(self.uid).unwrap_or_default(),
|
|
};
|
|
|
|
tracing::info!(
|
|
"[EnterScene] EnterSceneReady uid:{}, dest_scene_id:{}, peer_id:{}, host_peer_id:{}",
|
|
self.uid,
|
|
notify.dest_scene_id,
|
|
notify.peer_id,
|
|
notify.host_peer_id
|
|
);
|
|
|
|
scene_comp.enter_scene_state = EnterSceneState::ENTER_SCENE_READY;
|
|
self.send_proto(notify);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn scene_init_finish(self: &Rc<Self>, req: &SceneInitFinishReq) -> Result<(), Retcode> {
|
|
let scene_comp = self.player_scene_comp.borrow();
|
|
|
|
if scene_comp.enter_scene_token != req.enter_scene_token {
|
|
tracing::warn!(
|
|
"[ENTER_SCENE] token not match, client_token:{} server_token:{}",
|
|
req.enter_scene_token,
|
|
scene_comp.enter_scene_token
|
|
);
|
|
|
|
return Err(Retcode::RetEnterSceneTokenInvalid);
|
|
}
|
|
|
|
if scene_comp.enter_scene_state != EnterSceneState::ENTER_SCENE_READY {
|
|
tracing::warn!("EnterSceneState is not EnterSceneReady, uid:{}", self.uid);
|
|
return Err(Retcode::RetFail);
|
|
}
|
|
|
|
let dest_pos = scene_comp.dest_pos.clone();
|
|
let dest_rot = scene_comp.dest_rot.clone();
|
|
let enter_type = scene_comp.dest_enter_type;
|
|
let vision_type = scene_comp.dest_vision_type;
|
|
let is_need_enter_world = {
|
|
let Some(dest_scene) = scene_comp.get_dest_scene() else {
|
|
tracing::error!("get_dest_scene failed, uid:{}", self.uid);
|
|
return Err(Retcode::RetFail);
|
|
};
|
|
|
|
let is_reenter_dungeon = match scene_comp.get_cur_scene() {
|
|
Some(_) => false,
|
|
None => matches!(*dest_scene.borrow(), Scene::Dungeon(_)),
|
|
};
|
|
!is_reenter_dungeon
|
|
};
|
|
|
|
drop(scene_comp);
|
|
|
|
if is_need_enter_world {
|
|
let (world_owner_uid, dest_world_ptr) = {
|
|
let scene_comp = self.player_scene_comp.borrow();
|
|
let owner_uid = scene_comp
|
|
.dest_world_ptr
|
|
.as_ref()
|
|
.unwrap()
|
|
.borrow()
|
|
.get_owner_uid();
|
|
let dest_world_ptr = scene_comp.dest_world_ptr.clone().unwrap();
|
|
|
|
(owner_uid, dest_world_ptr)
|
|
};
|
|
|
|
let mut dest_world = dest_world_ptr.borrow_mut();
|
|
|
|
if let Err(ret) = dest_world.player_enter(self) {
|
|
tracing::info!(
|
|
"uid: {} player_enter world fails, owner_uid: {}",
|
|
self.uid,
|
|
world_owner_uid
|
|
);
|
|
return Err(ret);
|
|
}
|
|
}
|
|
|
|
let dest_scene = self.player_scene_comp.borrow().get_dest_scene();
|
|
self.player_enter_scene(dest_scene, dest_pos, dest_rot, enter_type, vision_type)?;
|
|
self.player_scene_comp.borrow_mut().enter_scene_state = EnterSceneState::ENTER_SCENE_INIT;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn enter_scene_done(self: &Rc<Self>, req: &EnterSceneDoneReq) -> Result<(), Retcode> {
|
|
let mut scene_comp = self.player_scene_comp.borrow_mut();
|
|
|
|
if scene_comp.enter_scene_token != req.enter_scene_token {
|
|
tracing::warn!(
|
|
"[ENTER_SCENE] token not match, client_token:{} server_token:{}",
|
|
req.enter_scene_token,
|
|
scene_comp.enter_scene_token
|
|
);
|
|
return Err(Retcode::RetEnterSceneTokenInvalid);
|
|
}
|
|
|
|
if scene_comp.enter_scene_state != EnterSceneState::ENTER_SCENE_INIT {
|
|
tracing::warn!("EnterSceneState is not EnterSceneInit, uid:{}", self.uid);
|
|
return Err(Retcode::RetFail);
|
|
}
|
|
|
|
let Some(cur_scene) = scene_comp.get_cur_scene() else {
|
|
tracing::warn!("get_cur_scene is None, uid:{}", self.uid);
|
|
return Err(Retcode::RetFail);
|
|
};
|
|
|
|
let vision_type = scene_comp.dest_vision_type;
|
|
let dest_pos = scene_comp.dest_pos.clone();
|
|
let dest_rot = scene_comp.dest_rot.clone();
|
|
|
|
let Some(cur_avatar_ptr) = ({
|
|
let avatar_comp = self.player_avatar_comp.borrow();
|
|
avatar_comp.get_cur_avatar()
|
|
}) else {
|
|
tracing::warn!("[EnterScene] get_cur_avatar failed, uid:{}", self.uid);
|
|
return Err(Retcode::RetFail);
|
|
};
|
|
|
|
{
|
|
let mut cur_avatar = cur_avatar_ptr.borrow_mut();
|
|
if cur_avatar.get_life_state() == LifeState::LifeDead {
|
|
cur_avatar.set_life_state(LifeState::LifeAlive);
|
|
|
|
if cur_avatar.get_cur_hp() == 0.0 {
|
|
cur_avatar.set_cur_hp(1.0);
|
|
}
|
|
}
|
|
|
|
cur_avatar.set_position(dest_pos.clone());
|
|
cur_avatar.set_rotation(dest_rot.clone());
|
|
cur_avatar.set_last_valid_position(dest_pos);
|
|
cur_avatar.set_last_valid_rotation(dest_rot);
|
|
}
|
|
|
|
let vision_context = VisionContext::new(vision_type);
|
|
if cur_scene
|
|
.borrow_mut()
|
|
.entity_appear(&(cur_avatar_ptr as Rc<RefCell<dyn Entity>>), vision_context)
|
|
.is_err()
|
|
{
|
|
tracing::warn!("[EnterScene] entity_appear failed, uid:{}", self.uid);
|
|
return Err(Retcode::RetFail);
|
|
}
|
|
|
|
scene_comp.enter_scene_state = EnterSceneState::ENTER_SCENE_DONE;
|
|
// TODO: scene_comp.notify_current_weather();
|
|
|
|
// Why here but ok..
|
|
self.send_proto(EnterSceneDoneRsp {
|
|
retcode: Retcode::RetSucc.into(),
|
|
enter_scene_token: req.enter_scene_token,
|
|
});
|
|
|
|
tracing::info!("[EnterScene] enter_scene_done succ, uid:{}", self.uid);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn post_enter_scene(self: &Rc<Self>, req: &PostEnterSceneReq) -> Result<(), Retcode> {
|
|
{
|
|
let scene_comp = self.player_scene_comp.borrow();
|
|
|
|
if scene_comp.enter_scene_token != req.enter_scene_token {
|
|
tracing::warn!(
|
|
"[ENTER_SCENE] token not match, client_token:{} server_token:{}",
|
|
req.enter_scene_token,
|
|
scene_comp.enter_scene_token
|
|
);
|
|
return Err(Retcode::RetEnterSceneTokenInvalid);
|
|
}
|
|
|
|
if scene_comp.enter_scene_state != EnterSceneState::ENTER_SCENE_DONE {
|
|
tracing::warn!("EnterSceneState is not EnterSceneDone, uid:{}", self.uid);
|
|
return Err(Retcode::RetFail);
|
|
}
|
|
|
|
if scene_comp.get_cur_scene().is_none() {
|
|
tracing::warn!("get_cur_scene is None, uid:{}", self.uid);
|
|
return Err(Retcode::RetFail);
|
|
};
|
|
}
|
|
|
|
self.clear_destination();
|
|
self.player_scene_comp.borrow_mut().enter_scene_state = EnterSceneState::ENTER_SCENE_POST;
|
|
// TODO: self.player_basic_comp.borrow_mut().is_in_transfer = false;
|
|
|
|
tracing::info!("[EnterScene] post_enter_scene succ, uid:{}", self.uid);
|
|
|
|
self.send_proto(PostEnterSceneRsp {
|
|
retcode: Retcode::RetSucc.into(),
|
|
enter_scene_token: req.enter_scene_token,
|
|
});
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn player_enter_scene(
|
|
self: &Rc<Self>,
|
|
dest_scene_ptr: Option<Rc<RefCell<Scene>>>,
|
|
pos: Vector3,
|
|
rot: Vector3,
|
|
_enter_type: EnterType,
|
|
_vision_type: VisionType,
|
|
) -> Result<(), Retcode> {
|
|
let Some(dest_scene_ptr) = dest_scene_ptr else {
|
|
tracing::error!("dest_scene_ptr is None, uid: {}", self.uid);
|
|
return Err(Retcode::RetFail);
|
|
};
|
|
|
|
let cur_avatar_team = self.init_enter_scene_avatar(&mut dest_scene_ptr.borrow_mut())?;
|
|
|
|
let (cur_avatar_team, appear_avatar) = {
|
|
let avatar_comp = self.player_avatar_comp.borrow();
|
|
let avatar_team = avatar_comp
|
|
.avatar_team_map
|
|
.get(&avatar_comp.cur_avatar_team_id)
|
|
.unwrap();
|
|
|
|
let cur_avatar_team = cur_avatar_team
|
|
.iter()
|
|
.map(|guid| avatar_comp.avatar_map.get(guid).unwrap().clone())
|
|
.collect();
|
|
|
|
let appear_avatar = avatar_comp
|
|
.avatar_map
|
|
.get(&avatar_team.borrow().last_cur_avatar_guid)
|
|
.unwrap()
|
|
.clone();
|
|
|
|
(cur_avatar_team, appear_avatar)
|
|
};
|
|
|
|
if dest_scene_ptr
|
|
.borrow_mut()
|
|
.player_enter(self, pos, rot, false, cur_avatar_team, &appear_avatar)
|
|
.is_err()
|
|
{
|
|
tracing::error!("player_enter fails, uid: {}", self.uid);
|
|
return Err(Retcode::RetEnterSceneFail);
|
|
}
|
|
|
|
self.player_scene_comp.borrow_mut().cur_scene_wtr = Rc::downgrade(&dest_scene_ptr);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn notify_player_enter_scene_info(&self, scene: &mut Scene) {
|
|
use crate::entity::Entity;
|
|
// TODO: OG server gets scene from PlayerSceneComp here
|
|
|
|
let cur_avatar_entity_id = {
|
|
let Some(cur_avatar) = self.player_avatar_comp.borrow().get_cur_avatar() else {
|
|
tracing::error!("cur_avatar_ptr is None");
|
|
return;
|
|
};
|
|
|
|
let cur_avatar = cur_avatar.borrow();
|
|
cur_avatar.entity_id()
|
|
};
|
|
|
|
let mut notify = PlayerEnterSceneInfoNotify::default();
|
|
notify.cur_avatar_entity_id = cur_avatar_entity_id;
|
|
notify.enter_scene_token = self.player_scene_comp.borrow().enter_scene_token;
|
|
|
|
{
|
|
let avatar_comp = self.player_avatar_comp.borrow();
|
|
for avatar in avatar_comp.get_cur_avatar_team_vec() {
|
|
let avatar = avatar.borrow();
|
|
let weapon_gadget = avatar
|
|
.base_avatar()
|
|
.equip_comp
|
|
.weapon_gadget
|
|
.as_ref()
|
|
.unwrap();
|
|
|
|
let weapon_gadget = weapon_gadget.borrow();
|
|
notify.avatar_enter_info.push(AvatarEnterSceneInfo {
|
|
avatar_guid: avatar.base_avatar().guid,
|
|
weapon_guid: match &*weapon_gadget {
|
|
WeaponGadget::Avatar(gadget) => gadget.weapon_guid,
|
|
//_ => 0,
|
|
},
|
|
avatar_entity_id: avatar.entity_id(),
|
|
weapon_entity_id: weapon_gadget.entity_id(),
|
|
weapon_ability_info: Some(AbilitySyncStateInfo::default()),
|
|
avatar_ability_info: Some(AbilitySyncStateInfo::default()),
|
|
buff_id_list: Vec::with_capacity(0),
|
|
server_buff_list: Vec::with_capacity(0),
|
|
});
|
|
}
|
|
|
|
let Some(avatar_team_entity) = avatar_comp.team_entity.upgrade() else {
|
|
tracing::error!("team_entity is None");
|
|
return;
|
|
};
|
|
|
|
let mut team_enter_info = TeamEnterSceneInfo::default();
|
|
avatar_team_entity.borrow().to_client(&mut team_enter_info);
|
|
notify.team_enter_info = Some(team_enter_info);
|
|
}
|
|
|
|
let mp_level_entity = scene.get_or_create_mp_level_entity();
|
|
let mut mp_level_entity_info = MpLevelEntityInfo::default();
|
|
mp_level_entity
|
|
.borrow()
|
|
.to_client(&mut mp_level_entity_info);
|
|
|
|
notify.mp_level_entity_info = Some(mp_level_entity_info);
|
|
self.send_proto(notify);
|
|
}
|
|
|
|
fn init_enter_scene_avatar(&self, dest_scene_ptr: &mut Scene) -> Result<Vec<u64>, Retcode> {
|
|
// TODO: special avatars for dungeons/challenges
|
|
|
|
let avatar_comp = self.player_avatar_comp.borrow();
|
|
let cur_avatar_team = avatar_comp.get_cur_avatar_team_with_temp_avatar();
|
|
|
|
let cur_world_ptr = dest_scene_ptr.base_mut().cur_world_wtr.upgrade().unwrap();
|
|
let mut cur_world = cur_world_ptr.borrow_mut();
|
|
|
|
let _team_avatar_vec = cur_world
|
|
.scene_team
|
|
.team_avatar_map
|
|
.get_mut(&self.uid)
|
|
.unwrap();
|
|
|
|
/* TODO: check if this actually should be done here, I doubt tbh
|
|
* cur_avatar_team.iter().for_each(|guid| {
|
|
team_avatar_vec.push(crate::scene::SceneTeamAvatar {
|
|
uid: self.uid,
|
|
avatar_guid: *guid,
|
|
})
|
|
});*/
|
|
|
|
// TODO: avatar_comp.is_all_avatar_dead() -> revive
|
|
|
|
Ok(cur_avatar_team)
|
|
}
|
|
|
|
fn pre_enter_scene(self: &Rc<Self>) -> Result<(), Retcode> {
|
|
let scene_comp = self.player_scene_comp.borrow();
|
|
|
|
let Some(mut dest_world_ptr) = scene_comp.dest_world_ptr.as_ref().map(|d| d.borrow_mut())
|
|
else {
|
|
tracing::error!("dest_world_ptr is None, uid: {}", self.uid);
|
|
return Err(Retcode::RetFail);
|
|
};
|
|
|
|
dest_world_ptr.player_pre_enter(self).map_err(|retcode| {
|
|
tracing::warn!(
|
|
"uid: {} pre-enter world fails, owner: {}",
|
|
self.uid,
|
|
dest_world_ptr.get_owner_uid()
|
|
);
|
|
retcode
|
|
})?;
|
|
|
|
scene_comp
|
|
.get_dest_scene()
|
|
.unwrap()
|
|
.borrow_mut()
|
|
.base_mut()
|
|
.player_pre_enter(self.clone())
|
|
.map_err(|retcode| {
|
|
tracing::warn!("[EnterScene] playerPreEnter failed, uid:{}", self.uid);
|
|
retcode
|
|
})?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn mark_destination(
|
|
&self,
|
|
dest_scene_ptr: &Rc<RefCell<Scene>>,
|
|
pos: Vector3,
|
|
rot: Vector3,
|
|
enter_type: EnterType,
|
|
vision_type: VisionType,
|
|
comp: &mut PlayerSceneComp,
|
|
) {
|
|
comp.dest_pos = pos;
|
|
comp.dest_rot = rot;
|
|
comp.set_dest_scene(Rc::downgrade(dest_scene_ptr));
|
|
comp.dest_enter_type = enter_type;
|
|
comp.dest_vision_type = vision_type;
|
|
}
|
|
|
|
fn clear_destination(&self) {
|
|
let mut comp = self.player_scene_comp.borrow_mut();
|
|
comp.set_dest_scene(Weak::new());
|
|
comp.dest_enter_type = EnterType::EnterNone;
|
|
comp.dest_vision_type = VisionType::VisionNone;
|
|
}
|
|
|
|
fn notify_all_data(&self) {
|
|
self.notify_player_data();
|
|
|
|
self.player_basic_comp.borrow().notify_all_data();
|
|
self.player_item_comp.borrow().notify_all_data();
|
|
self.player_avatar_comp.borrow().notify_all_data();
|
|
}
|
|
|
|
fn notify_player_data(&self) {
|
|
let mut notify = PlayerDataNotify::default();
|
|
|
|
let basic_comp = self.player_basic_comp.borrow();
|
|
let avatar_comp = self.player_avatar_comp.borrow();
|
|
let item_comp = self.player_item_comp.borrow();
|
|
|
|
notify.nick_name = basic_comp.nickname.clone();
|
|
notify.server_time = time_utils::get_now();
|
|
|
|
let map = &mut notify.prop_map;
|
|
append_int_prop_value(
|
|
map,
|
|
PROP_IS_SPRING_AUTO_USE,
|
|
avatar_comp.is_spring_auto_use.into(),
|
|
);
|
|
append_int_prop_value(
|
|
map,
|
|
PROP_SPRING_AUTO_USE_PERCENT,
|
|
avatar_comp.spring_auto_use_percent.into(),
|
|
);
|
|
append_int_prop_value(map, PROP_IS_FLYABLE, avatar_comp.is_flyable.into());
|
|
append_int_prop_value(
|
|
map,
|
|
PROP_IS_TRANSFERABLE,
|
|
avatar_comp.is_transferable.into(),
|
|
);
|
|
append_int_prop_value(
|
|
map,
|
|
PROP_IS_WEATHER_LOCKED,
|
|
basic_comp.is_weather_locked.into(),
|
|
);
|
|
append_int_prop_value(
|
|
map,
|
|
PROP_IS_GAME_TIME_LOCKED,
|
|
basic_comp.is_game_time_locked.into(),
|
|
);
|
|
append_int_prop_value(map, PROP_PLAYER_LEVEL, basic_comp.level.into());
|
|
append_int_prop_value(map, PROP_PLAYER_EXP, basic_comp.exp.into());
|
|
append_int_prop_value(map, PROP_PLAYER_HCOIN, item_comp.hcoin.into());
|
|
append_int_prop_value(map, PROP_PLAYER_SCOIN, item_comp.scoin.into());
|
|
append_int_prop_value(map, PROP_MAX_STAMINA, 10000);
|
|
append_int_prop_value(map, PROP_CUR_PERSIST_STAMINA, 10000);
|
|
|
|
self.send_proto(notify);
|
|
}
|
|
|
|
fn update_last_ping_time(&self) {
|
|
self.last_recv_ping_time.set(time_utils::get_now());
|
|
}
|
|
|
|
pub fn save_to_db(&self) {
|
|
use common::{net::ServiceType, ServiceQualifier};
|
|
let player_data = self.to_bin();
|
|
|
|
if let Err(err) = gameserver_service()
|
|
.service_box
|
|
.push_packet_to_service_blocking(
|
|
ServiceQualifier::Type(ServiceType::Dbgate),
|
|
Packet::new(
|
|
SavePlayerDataReq {
|
|
player_data: player_data.encode_to_vec(),
|
|
save_stat_id: 0, // TODO
|
|
},
|
|
PacketHead {
|
|
user_id: self.uid,
|
|
user_session_id: self
|
|
.session
|
|
.borrow()
|
|
.upgrade()
|
|
.map(|s| s.get_gateserver_session_id())
|
|
.unwrap_or_default(),
|
|
..Default::default()
|
|
},
|
|
),
|
|
)
|
|
{
|
|
tracing::warn!("save_to_db failed, uid: {}, err: {err}", self.uid);
|
|
}
|
|
}
|
|
|
|
pub fn from_bin(&self, data: PlayerData) -> Result<(), prost::DecodeError> {
|
|
// TODO: PlayerData::bin zlib
|
|
let bin = PlayerDataBin::decode(&*data.bin)?;
|
|
|
|
*self.player_basic_comp.borrow_mut() =
|
|
PlayerBasicComp::from_bin(bin.basic_bin.unwrap_or_default());
|
|
*self.player_login_comp.borrow_mut() =
|
|
PlayerLoginComp::from_bin(bin.login_bin.unwrap_or_default());
|
|
*self.player_avatar_comp.borrow_mut() =
|
|
PlayerAvatarComp::from_bin(bin.avatar_bin.unwrap_or_default());
|
|
*self.player_item_comp.borrow_mut() =
|
|
PlayerItemComp::from_bin(bin.item_bin.unwrap_or_default());
|
|
*self.player_scene_comp.borrow_mut() =
|
|
PlayerSceneComp::from_bin(bin.scene_bin.unwrap_or_default());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn to_bin(&self) -> PlayerData {
|
|
let mut bin = PlayerDataBin::default();
|
|
bin.basic_bin = Some(self.player_basic_comp.borrow().to_bin());
|
|
bin.login_bin = Some(self.player_login_comp.borrow().to_bin());
|
|
bin.avatar_bin = Some(self.player_avatar_comp.borrow().to_bin());
|
|
bin.item_bin = Some(self.player_item_comp.borrow().to_bin());
|
|
bin.scene_bin = Some(self.player_scene_comp.borrow().to_bin());
|
|
|
|
let basic_comp = self.player_basic_comp.borrow();
|
|
PlayerData {
|
|
uid: self.uid,
|
|
nickname: basic_comp.nickname.clone(),
|
|
level: basic_comp.level,
|
|
exp: basic_comp.exp,
|
|
bin: bin.encode_to_vec(),
|
|
..Default::default()
|
|
}
|
|
}
|
|
|
|
pub fn init(self: &Rc<Self>) {
|
|
self.player_basic_comp.borrow_mut().set_player(self.clone());
|
|
self.player_login_comp.borrow_mut().set_player(self.clone());
|
|
self.player_avatar_comp
|
|
.borrow_mut()
|
|
.set_player(self.clone());
|
|
self.player_item_comp.borrow_mut().set_player(self.clone());
|
|
self.player_scene_comp.borrow_mut().set_player(self.clone());
|
|
|
|
self.player_basic_comp.borrow_mut().init();
|
|
self.player_login_comp.borrow_mut().init();
|
|
self.player_avatar_comp.borrow_mut().init();
|
|
self.player_item_comp.borrow_mut().init();
|
|
self.player_scene_comp.borrow_mut().init();
|
|
}
|
|
}
|