851 lines
27 KiB
Rust
851 lines
27 KiB
Rust
use std::{
|
|
cell::RefCell,
|
|
collections::{BTreeMap, HashMap},
|
|
rc::{Rc, Weak},
|
|
sync::atomic::{AtomicU32, Ordering},
|
|
};
|
|
|
|
use common::tools::time_utils;
|
|
use data::{
|
|
math_def::{Vector2, Vector3},
|
|
SceneType,
|
|
};
|
|
use proto::{
|
|
EnterType, HostPlayerNotify, ProtEntityType, Retcode, SceneBin, SceneDataNotify,
|
|
SceneEntityAppearNotify, SceneEntityDisappearNotify, SceneEntityInfo, SceneForceUnlockNotify,
|
|
ScenePlayerLocationBin, VisionType,
|
|
};
|
|
use tokio::sync::OnceCell;
|
|
|
|
use crate::{
|
|
entity::{entity_mgr, entity_utils, Entity, VisionContext},
|
|
player::{avatar::Avatar, Player},
|
|
};
|
|
|
|
use super::{
|
|
dungeon_scene::DungeonScene, player_world_scene::PlayerWorldScene, MPLevelEntity, PlayerWorld,
|
|
SceneSightComp,
|
|
};
|
|
|
|
pub enum Scene {
|
|
PlayerWorld(PlayerWorldScene),
|
|
Dungeon(DungeonScene),
|
|
}
|
|
|
|
impl Scene {
|
|
pub fn new(scene_id: u32) -> Self {
|
|
let scene_type = data::iter_scene_data()
|
|
.find(|s| s.id == scene_id)
|
|
.unwrap()
|
|
.r#type;
|
|
|
|
match scene_type {
|
|
SceneType::World => Self::PlayerWorld(PlayerWorldScene::new(scene_id)),
|
|
SceneType::Dungeon => Self::Dungeon(DungeonScene::new(scene_id)),
|
|
_ => panic!("Invalid scene type {scene_type:?}"),
|
|
}
|
|
}
|
|
|
|
pub fn from_bin(scene_id: u32, bin: SceneBin) -> Self {
|
|
let scene_type = data::iter_scene_data()
|
|
.find(|s| s.id == scene_id)
|
|
.unwrap()
|
|
.r#type;
|
|
|
|
match scene_type {
|
|
SceneType::World => Self::PlayerWorld(PlayerWorldScene::from_bin(scene_id, bin)),
|
|
SceneType::Dungeon => Self::Dungeon(DungeonScene::from_bin(scene_id, bin)),
|
|
_ => panic!("Invalid scene type {scene_type:?}"),
|
|
}
|
|
}
|
|
|
|
pub fn to_bin(&self) -> SceneBin {
|
|
match self {
|
|
Self::PlayerWorld(scene) => scene.to_bin(),
|
|
Self::Dungeon(scene) => scene.to_bin(),
|
|
}
|
|
}
|
|
|
|
pub fn base(&self) -> &BaseScene {
|
|
match self {
|
|
Self::PlayerWorld(scene) => &scene.base,
|
|
Self::Dungeon(scene) => &scene.base,
|
|
}
|
|
}
|
|
|
|
pub fn base_mut(&mut self) -> &mut BaseScene {
|
|
match self {
|
|
Self::PlayerWorld(scene) => &mut scene.base,
|
|
Self::Dungeon(scene) => &mut scene.base,
|
|
}
|
|
}
|
|
|
|
pub fn gen_new_entity_id(&self, ty: ProtEntityType) -> u32 {
|
|
self.base().gen_new_entity_id(ty)
|
|
}
|
|
|
|
pub fn init(&mut self) {
|
|
match self {
|
|
Self::PlayerWorld(scene) => scene.init(),
|
|
Self::Dungeon(scene) => scene.init(),
|
|
}
|
|
}
|
|
|
|
pub fn player_enter(
|
|
&mut self,
|
|
player: &Rc<Player>,
|
|
pos: Vector3,
|
|
rot: Vector3,
|
|
is_relogin: bool,
|
|
enter_scene_avatar: Vec<Rc<RefCell<Avatar>>>,
|
|
appear_avatar_ptr: &Rc<RefCell<Avatar>>,
|
|
) -> Result<(), Retcode> {
|
|
let uid = player.uid;
|
|
let Some(_peer_id) = self.base().get_peer_id(uid) else {
|
|
return Err(Retcode::RetFail);
|
|
};
|
|
|
|
self.base_mut()
|
|
.player_map
|
|
.insert(player.uid, Rc::downgrade(player));
|
|
|
|
{
|
|
let Some(host_player) = self
|
|
.base()
|
|
.host_player_wtr
|
|
.as_ref()
|
|
.map(|p| p.upgrade())
|
|
.flatten()
|
|
else {
|
|
return Err(Retcode::RetFail);
|
|
};
|
|
|
|
let mut host_avatar_comp = host_player.player_avatar_comp.borrow_mut();
|
|
if host_avatar_comp.team_entity.upgrade().is_none() {
|
|
let team_entity =
|
|
Rc::new(RefCell::new(entity_mgr::create_avatar_team_entity(self)));
|
|
team_entity.borrow_mut().set_player(player);
|
|
host_avatar_comp.team_entity = Rc::downgrade(&team_entity);
|
|
|
|
self.base_mut()
|
|
.add_gridless_entity(team_entity as Rc<RefCell<dyn Entity>>)?;
|
|
}
|
|
}
|
|
|
|
let mut avatar_comp = player.player_avatar_comp.borrow_mut();
|
|
if let Some(cur_avatar) = avatar_comp.get_cur_avatar() {
|
|
if cur_avatar.borrow().is_on_scene() {
|
|
tracing::error!("[ENTER] last cur avatar is on scene! uid: {}", player.uid);
|
|
}
|
|
}
|
|
|
|
let mut scene_comp = player.player_scene_comp.borrow_mut();
|
|
let dest_enter_type = scene_comp.dest_enter_type;
|
|
let prev_scene_id = scene_comp.cur_scene_id;
|
|
let new_scene_id = self.base().scene_id;
|
|
|
|
scene_comp.cur_scene_id = new_scene_id;
|
|
scene_comp.cur_scene_owner_uid = self.base().owner_uid();
|
|
|
|
drop(scene_comp);
|
|
// SET after: player.player_scene_comp.lock().cur_scene_wtr = self
|
|
|
|
avatar_comp.set_cur_avatar(appear_avatar_ptr);
|
|
drop(avatar_comp);
|
|
|
|
let appear_avatar_guid = {
|
|
let appear_avatar = appear_avatar_ptr.borrow();
|
|
appear_avatar.base_avatar().guid
|
|
};
|
|
|
|
let avatar_guid_vec = enter_scene_avatar
|
|
.iter()
|
|
.map(|a| a.borrow().base_avatar().guid)
|
|
.collect();
|
|
let cur_world_ptr = self.base().cur_world_wtr.upgrade().unwrap();
|
|
cur_world_ptr
|
|
.borrow_mut()
|
|
.scene_team
|
|
.set_player_avatar_team_and_add_to_scene(
|
|
player.uid,
|
|
avatar_guid_vec,
|
|
appear_avatar_guid,
|
|
self,
|
|
false,
|
|
)
|
|
.map_err(|err| {
|
|
tracing::error!(
|
|
"set_player_avatar_team_and_add_to_scene failed, uid:{}",
|
|
player.uid
|
|
);
|
|
err
|
|
})?;
|
|
|
|
if self.base().owner_uid() == player.uid {
|
|
let scene_id = self.base().scene_id;
|
|
|
|
let mut scene_comp = player.player_scene_comp.borrow_mut();
|
|
scene_comp.my_cur_scene_id = scene_id;
|
|
scene_comp.my_cur_player_scene_id = scene_id;
|
|
// TODO: differentiate between home/player scene!
|
|
// scene_comp.my_home_scene_id = scene_id;
|
|
}
|
|
|
|
if prev_scene_id != new_scene_id
|
|
|| is_relogin
|
|
|| dest_enter_type == EnterType::EnterGotoRecreate
|
|
{
|
|
self.notify_scene_and_host_data(player.uid);
|
|
player.notify_player_enter_scene_info(self);
|
|
// Player::setIsDataResVersionChanged(player, 0);
|
|
} else if prev_scene_id == new_scene_id {
|
|
// TODO: for Goto/Jump ('re-enter' current scene)
|
|
// v91 = Player::getAvatarComp(v90);
|
|
// std::function<ForeachPolicy ()(Avatar &)>::function<Scene::playerEnter(Player &,Vector3 const&,Vector3 const&,bool,std::vector<std::shared_ptr<Avatar>> const&,std::shared_ptr<Avatar>)::{lambda(Avatar &)#1},void,void>(
|
|
// (std::function<ForeachPolicy(Avatar&)> *const)&v140,
|
|
// (Scene::playerEnter::<lambda(Avatar&)>)(v7 + 480));
|
|
// PlayerAvatarComp::foreachMyAvatarInSceneTeam(v91, (std::function<ForeachPolicy(Avatar&)> *)&v140);
|
|
}
|
|
|
|
let scene_player_location = ScenePlayerLocation {
|
|
cur_pos: pos.clone(),
|
|
cur_rot: rot.clone(),
|
|
last_valid_pos: pos.clone(),
|
|
last_valid_rot: rot.clone(),
|
|
};
|
|
|
|
self.set_player_location(player.uid, scene_player_location);
|
|
|
|
{
|
|
let avatar_comp = player.player_avatar_comp.borrow();
|
|
let cur_avatar_ptr = avatar_comp.get_cur_avatar().unwrap();
|
|
let mut cur_avatar = cur_avatar_ptr.borrow_mut();
|
|
cur_avatar.set_position(pos.clone());
|
|
cur_avatar.set_rotation(rot.clone());
|
|
cur_avatar.set_last_valid_position(pos);
|
|
cur_avatar.set_last_valid_rotation(rot);
|
|
}
|
|
|
|
// TODO: Scene::notifyAllPlayerInfo();
|
|
cur_world_ptr.borrow().scene_team.notify_scene_team_update();
|
|
|
|
// Scene::notifyAllTeamEntity() -> SyncTeamEntityNotify ?
|
|
// Scene::notifyAllPlayTeamEntity()
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn get_or_create_mp_level_entity(&mut self) -> Rc<RefCell<MPLevelEntity>> {
|
|
if let Some(mp_level_entity) = self.base().mp_level_entity_ptr.as_ref() {
|
|
return mp_level_entity.clone();
|
|
}
|
|
|
|
let mut mp_level_entity = MPLevelEntity::default();
|
|
mp_level_entity.set_authority_peer_id(self.base().get_host_peer_id().unwrap_or_default());
|
|
mp_level_entity.set_entity_id(self.gen_new_entity_id(ProtEntityType::ProtEntityMpLevel));
|
|
|
|
let mp_level_entity_ptr = Rc::new(RefCell::new(mp_level_entity));
|
|
self.add_gridless_entity(mp_level_entity_ptr.clone() as Rc<RefCell<dyn Entity>>)
|
|
.unwrap();
|
|
|
|
self.base_mut().mp_level_entity_ptr = Some(mp_level_entity_ptr.clone());
|
|
mp_level_entity_ptr
|
|
}
|
|
|
|
pub fn set_player_location(&mut self, uid: u32, player_location: ScenePlayerLocation) {
|
|
if self.base().owner_uid() == uid {
|
|
self.base_mut().owner_player_location = player_location.clone();
|
|
}
|
|
|
|
tracing::info!(
|
|
"[ENTER_SCENE] set_player_location, last_valid_pos:{:?}, cur_pos:{:?}",
|
|
player_location.last_valid_pos,
|
|
player_location.cur_pos
|
|
);
|
|
|
|
self.base_mut()
|
|
.player_location_map
|
|
.insert(uid, player_location);
|
|
}
|
|
|
|
fn notify_scene_and_host_data(&self, uid: u32) {
|
|
let Some(player) = self.base().find_player(uid) else {
|
|
tracing::warn!("find_player failed, uid:{uid}");
|
|
return;
|
|
};
|
|
|
|
self.notify_all_unlock_force(player.as_ref());
|
|
self.notify_host_to_player(player.as_ref());
|
|
self.notify_scene_data(player.as_ref());
|
|
|
|
if false
|
|
// if let Some(home_comp) = self.base().get_own_home()
|
|
{
|
|
// home_comp.notify_game_time(player.as_ref());
|
|
} else {
|
|
let own_player = self.base().own_player().unwrap();
|
|
own_player
|
|
.player_basic_comp
|
|
.borrow()
|
|
.notify_game_time(player.as_ref());
|
|
}
|
|
}
|
|
|
|
fn notify_all_unlock_force(&self, player: &Player) {
|
|
player.send_proto(SceneForceUnlockNotify {
|
|
force_id_list: self.base().unlocked_force_list.clone(),
|
|
is_add: false,
|
|
});
|
|
}
|
|
|
|
fn notify_host_to_player(&self, player: &Player) {
|
|
let Some(host_player) = self.base().get_host_player() else {
|
|
tracing::error!("host_player_ptr is None");
|
|
return;
|
|
};
|
|
|
|
player.send_proto(HostPlayerNotify {
|
|
host_uid: host_player.uid,
|
|
host_peer_id: self.base().get_peer_id(host_player.uid).unwrap(),
|
|
});
|
|
}
|
|
|
|
fn notify_scene_data(&self, player: &Player) {
|
|
let mut scene_data_notify = SceneDataNotify::default();
|
|
if self.fill_scene_data_notify(&mut scene_data_notify).is_err() {
|
|
tracing::warn!("fill_scene_data_notify failed");
|
|
return;
|
|
}
|
|
|
|
player.send_proto(scene_data_notify);
|
|
}
|
|
|
|
fn fill_scene_data_notify(&self, _notify: &mut SceneDataNotify) -> Result<(), Retcode> {
|
|
// TODO!
|
|
Ok(())
|
|
}
|
|
|
|
pub fn add_avatar_and_weapon_entity(
|
|
&mut self,
|
|
avatar_ptr: Rc<RefCell<Avatar>>,
|
|
_is_enter_scene: bool,
|
|
) -> Result<(), Retcode> {
|
|
{
|
|
let mut avatar = avatar_ptr.borrow_mut();
|
|
avatar.set_entity_id(self.gen_new_entity_id(ProtEntityType::ProtEntityAvatar));
|
|
|
|
tracing::info!(
|
|
"[LR] add_avatar_and_weapon_entity, avatar_id:{} avatar_guid:{} entity_id:{}",
|
|
avatar.base_avatar().avatar_id,
|
|
avatar.base_avatar().guid,
|
|
avatar.entity_id()
|
|
);
|
|
}
|
|
|
|
self.add_gridless_entity(avatar_ptr.clone() as Rc<RefCell<dyn Entity>>)
|
|
.map_err(|_| {
|
|
tracing::warn!("add_gridless_entity fails");
|
|
Retcode::RetFail
|
|
})?;
|
|
|
|
let ability_comp = {
|
|
let avatar = avatar_ptr.borrow();
|
|
avatar.base_avatar().ability_comp.clone()
|
|
};
|
|
|
|
ability_comp.borrow_mut().init(avatar_ptr.clone());
|
|
|
|
let mut avatar = avatar_ptr.borrow_mut();
|
|
let Some(weapon_gadget) = avatar.base_avatar_mut().equip_comp.weapon_gadget.as_mut() else {
|
|
tracing::error!("missing weapon gadget!");
|
|
return Err(Retcode::RetFail);
|
|
};
|
|
|
|
weapon_gadget
|
|
.borrow_mut()
|
|
.set_entity_id(self.gen_new_entity_id(ProtEntityType::ProtEntityWeapon));
|
|
|
|
self.add_gridless_entity(weapon_gadget.clone() as Rc<RefCell<dyn Entity>>)
|
|
.map_err(|_| {
|
|
tracing::warn!(
|
|
"add_gridless_entity fails, weapon_entity_id:{}",
|
|
weapon_gadget.borrow().entity_id()
|
|
);
|
|
Retcode::RetFail
|
|
})?;
|
|
|
|
weapon_gadget.borrow_mut().init_ability().map_err(|_| {
|
|
tracing::warn!("init_ability fails");
|
|
Retcode::RetFail
|
|
})?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn del_avatar_and_weapon_entity(&mut self, avatar_ptr: Rc<RefCell<Avatar>>) {
|
|
let entity_id = avatar_ptr.borrow().entity_id();
|
|
avatar_ptr.borrow_mut().set_entity_id(0);
|
|
if self
|
|
.del_gridless_entity(avatar_ptr.clone() as Rc<RefCell<dyn Entity>>)
|
|
.is_err()
|
|
{
|
|
tracing::warn!(
|
|
"del_gridless_entity_fails {}",
|
|
avatar_ptr.borrow().get_desc()
|
|
);
|
|
return;
|
|
}
|
|
|
|
let avatar = avatar_ptr.borrow();
|
|
if let Some(gadget) = avatar.base_avatar().equip_comp.weapon_gadget.clone() {
|
|
if self
|
|
.del_gridless_entity(gadget.clone() as Rc<RefCell<dyn Entity>>)
|
|
.is_err()
|
|
{
|
|
tracing::warn!(
|
|
"del_gridless_entity fails, weapon_entity_id:{}",
|
|
gadget.borrow().entity_id()
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
tracing::info!(
|
|
"del_avatar_and_weapon_entity finished, avatar_entity_id:{entity_id}, guid:{}",
|
|
avatar.base_avatar().guid
|
|
);
|
|
}
|
|
|
|
pub fn entity_appear(
|
|
&mut self,
|
|
entity: &Rc<RefCell<dyn Entity>>,
|
|
vision_context: VisionContext,
|
|
) -> Result<(), Retcode> {
|
|
let sight_comp = self.base_mut().sight_comp.as_mut().unwrap();
|
|
let Ok(meet_entity_vec) = sight_comp.place_entity(entity.clone()) else {
|
|
tracing::error!("place_entity fails");
|
|
return Err(Retcode::RetFail);
|
|
};
|
|
|
|
let (pos, entity_id) = {
|
|
let entity = entity.borrow();
|
|
(
|
|
Vector2 {
|
|
x: entity.position().x,
|
|
y: entity.position().z,
|
|
},
|
|
entity.entity_id(),
|
|
)
|
|
};
|
|
|
|
let coordinate =
|
|
sight_comp.pos_to_coordinate(sight_comp.get_vision_level_type(&entity), &pos);
|
|
|
|
tracing::info!(
|
|
"[FY] meet entity vec: {:?} @ {:?}",
|
|
meet_entity_vec
|
|
.iter()
|
|
.map(|a| a.borrow().get_desc())
|
|
.collect::<Vec<_>>(),
|
|
coordinate
|
|
);
|
|
|
|
self.base_mut().entity_map.insert(entity_id, entity.clone());
|
|
|
|
// TODO: PlayerViewMgr
|
|
|
|
if vision_context.vision_type != VisionType::VisionReplaceNoNotify {
|
|
for player_wtr in self.base().player_map.values() {
|
|
if let Some(player) = player_wtr.upgrade() {
|
|
self.notify_entity_appear(&player, &meet_entity_vec, &vision_context)
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn entity_disappear(
|
|
&mut self,
|
|
entity: &Rc<RefCell<dyn Entity>>,
|
|
vision_context: VisionContext,
|
|
) -> Result<(), Retcode> {
|
|
if !entity.borrow().is_on_scene() {
|
|
tracing::info!("entity is not on scene {}", entity.borrow().get_desc());
|
|
return Ok(());
|
|
}
|
|
|
|
self.base_mut()
|
|
.sight_comp
|
|
.as_mut()
|
|
.unwrap()
|
|
.remove_entity(entity);
|
|
|
|
// TODO: disappear nearby entities on avatar death (PROT_ENTITY_AVATAR and not replace)
|
|
if vision_context.vision_type != VisionType::VisionReplaceNoNotify {
|
|
for player_wtr in self.base().player_map.values() {
|
|
if let Some(player) = player_wtr.upgrade() {
|
|
self.notify_entity_disappear(
|
|
&player,
|
|
&[entity.borrow().entity_id()],
|
|
&vision_context,
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn notify_entity_appear(
|
|
&self,
|
|
player: &Player,
|
|
entity_vec: &[Rc<RefCell<dyn Entity>>],
|
|
context: &VisionContext,
|
|
) {
|
|
let mut notify = SceneEntityAppearNotify::default();
|
|
|
|
for entity_ptr in entity_vec {
|
|
let entity = entity_ptr.borrow();
|
|
let mut scene_entity_info = SceneEntityInfo::default();
|
|
entity.to_client(&mut scene_entity_info);
|
|
notify.entity_list.push(scene_entity_info);
|
|
}
|
|
|
|
notify.appear_type = context.vision_type.into();
|
|
notify.param = context.param;
|
|
|
|
player.send_proto(notify);
|
|
}
|
|
|
|
fn notify_entity_disappear(
|
|
&self,
|
|
player: &Player,
|
|
entity_id_vec: &[u32],
|
|
context: &VisionContext,
|
|
) {
|
|
player.send_proto(SceneEntityDisappearNotify {
|
|
entity_list: entity_id_vec.to_vec(),
|
|
disappear_type: context.vision_type.into(),
|
|
param: context.param,
|
|
});
|
|
}
|
|
|
|
fn add_gridless_entity(&mut self, entity: Rc<RefCell<dyn Entity>>) -> Result<(), Retcode> {
|
|
self.base_mut().add_gridless_entity(entity)
|
|
}
|
|
|
|
fn del_gridless_entity(&mut self, entity: Rc<RefCell<dyn Entity>>) -> Result<(), Retcode> {
|
|
self.base_mut().del_gridless_entity(entity)
|
|
}
|
|
|
|
pub fn pre_player_login(&mut self, is_relogin: bool) {
|
|
self.base_mut().pre_player_login(is_relogin);
|
|
}
|
|
|
|
pub fn set_own_player(&self, player: Rc<Player>) {
|
|
self.base().set_own_player(player);
|
|
}
|
|
}
|
|
|
|
#[derive(Default, Clone)]
|
|
pub struct ScenePlayerLocation {
|
|
pub cur_pos: Vector3,
|
|
pub cur_rot: Vector3,
|
|
pub last_valid_pos: Vector3,
|
|
pub last_valid_rot: Vector3,
|
|
}
|
|
|
|
impl ScenePlayerLocation {
|
|
pub fn from_bin(bin: ScenePlayerLocationBin) -> Self {
|
|
Self {
|
|
cur_pos: Vector3::from_bin(bin.cur_pos.unwrap_or_default()),
|
|
cur_rot: Vector3::from_bin(bin.cur_rot.unwrap_or_default()),
|
|
last_valid_pos: Vector3::from_bin(bin.last_valid_pos.unwrap_or_default()),
|
|
last_valid_rot: Vector3::from_bin(bin.last_valid_rot.unwrap_or_default()),
|
|
}
|
|
}
|
|
|
|
pub fn to_bin(&self) -> ScenePlayerLocationBin {
|
|
ScenePlayerLocationBin {
|
|
cur_pos: Some(self.cur_pos.to_bin()),
|
|
cur_rot: Some(self.cur_rot.to_bin()),
|
|
last_valid_pos: Some(self.last_valid_pos.to_bin()),
|
|
last_valid_rot: Some(self.last_valid_rot.to_bin()),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct ScenePlayerPeerInfo {
|
|
pub uid: u32,
|
|
#[allow(unused)]
|
|
pub enter_time: u64,
|
|
}
|
|
|
|
#[derive(Default)]
|
|
pub struct BaseScene {
|
|
own_player: OnceCell<Weak<Player>>,
|
|
pub scene_id: u32,
|
|
pub unlocked_point_list: Vec<u32>,
|
|
pub unlocked_force_list: Vec<u32>,
|
|
pub locked_point_list: Vec<u32>,
|
|
pub owner_player_location: ScenePlayerLocation,
|
|
pub unhide_point_list: Vec<u32>,
|
|
pub scene_transaction: String,
|
|
pub begin_time_ms: u64,
|
|
peer_map: BTreeMap<u32, ScenePlayerPeerInfo>,
|
|
host_player_wtr: Option<Weak<Player>>,
|
|
player_map: HashMap<u32, Weak<Player>>,
|
|
pub cur_world_wtr: Weak<RefCell<PlayerWorld>>,
|
|
pub gridless_entity_map: HashMap<u32, Rc<RefCell<dyn Entity>>>,
|
|
next_entity_index: AtomicU32,
|
|
pub mp_level_entity_ptr: Option<Rc<RefCell<MPLevelEntity>>>,
|
|
pub player_location_map: HashMap<u32, ScenePlayerLocation>,
|
|
pub sight_comp: Option<SceneSightComp>,
|
|
pub entity_map: HashMap<u32, Rc<RefCell<dyn Entity>>>,
|
|
}
|
|
|
|
impl BaseScene {
|
|
pub fn new(scene_id: u32) -> Self {
|
|
Self {
|
|
scene_id,
|
|
..Default::default()
|
|
}
|
|
}
|
|
|
|
pub fn init(&mut self) {
|
|
self.scene_transaction = self.create_scene_transaction_on_init();
|
|
self.begin_time_ms = time_utils::get_now_ms();
|
|
|
|
self.sight_comp = Some(
|
|
SceneSightComp::new_grid(
|
|
Vector2::default(),
|
|
Vector2 {
|
|
// TODO!
|
|
x: 100000.0,
|
|
y: 100000.0,
|
|
},
|
|
)
|
|
.unwrap(),
|
|
);
|
|
}
|
|
|
|
pub fn pre_player_login(&mut self, _is_relogin: bool) {
|
|
// TODO: BlockGroupComp::prePlayerLogin()
|
|
}
|
|
|
|
pub fn player_pre_enter(&mut self, player: Rc<Player>) -> Result<(), Retcode> {
|
|
if self.get_peer_id(player.uid).is_some() {
|
|
tracing::info!("peer_id exist in scene, scene_id:{}", self.scene_id);
|
|
return Ok(());
|
|
}
|
|
|
|
if self.peer_map.len() > 3 {
|
|
tracing::info!("scene is full, scene_id:{}", self.scene_id);
|
|
Err(Retcode::RetMpSceneIsFull)
|
|
} else {
|
|
let mut peer_id = 1;
|
|
self.peer_map.keys().for_each(|id| {
|
|
if peer_id == *id {
|
|
peer_id += 1;
|
|
}
|
|
});
|
|
|
|
if peer_id > 7 {
|
|
tracing::error!("invalid peer_id:{peer_id}");
|
|
return Err(Retcode::RetFail);
|
|
}
|
|
|
|
player.peer_id.set(peer_id);
|
|
self.peer_map.insert(
|
|
peer_id,
|
|
ScenePlayerPeerInfo {
|
|
uid: player.uid,
|
|
enter_time: time_utils::get_now(),
|
|
},
|
|
);
|
|
|
|
if self.host_player_wtr.is_none() {
|
|
self.set_host_player(player.clone());
|
|
}
|
|
|
|
tracing::info!(
|
|
"[EnterScene] player preEnter scene, scene_id:{}",
|
|
self.scene_id
|
|
);
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
pub fn set_host_player(&mut self, player: Rc<Player>) {
|
|
self.host_player_wtr = Some(Rc::downgrade(&player));
|
|
|
|
player.send_proto(HostPlayerNotify {
|
|
host_uid: player.uid,
|
|
host_peer_id: self.get_peer_id(player.uid).unwrap(),
|
|
})
|
|
}
|
|
|
|
pub fn get_peer_id(&self, uid: u32) -> Option<u32> {
|
|
self.peer_map
|
|
.iter()
|
|
.find(|(_, info)| info.uid == uid)
|
|
.map(|(id, _)| *id)
|
|
}
|
|
|
|
pub fn get_host_peer_id(&self) -> Option<u32> {
|
|
self.host_player_wtr
|
|
.clone()
|
|
.map(|w| w.upgrade())?
|
|
.map(|p| self.get_peer_id(p.uid))?
|
|
}
|
|
|
|
pub fn get_host_player(&self) -> Option<Rc<Player>> {
|
|
self.host_player_wtr.clone().map(|w| w.upgrade()).flatten()
|
|
}
|
|
|
|
pub fn find_player(&self, uid: u32) -> Option<Rc<Player>> {
|
|
self.player_map.get(&uid).map(|p| p.upgrade()).flatten()
|
|
}
|
|
|
|
pub fn add_gridless_entity(
|
|
&mut self,
|
|
entity_ptr: Rc<RefCell<dyn Entity>>,
|
|
) -> Result<(), Retcode> {
|
|
let entity_id = entity_ptr.borrow().entity_id();
|
|
tracing::info!("[LR] add_gridless_entity, entity_id:{entity_id}");
|
|
if self.gridless_entity_map.contains_key(&entity_id) {
|
|
tracing::warn!("duplicated gridless entity_id:{entity_id}");
|
|
return Err(Retcode::RetFail);
|
|
}
|
|
|
|
self.gridless_entity_map
|
|
.insert(entity_id, entity_ptr.clone());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn del_gridless_entity(
|
|
&mut self,
|
|
entity_ptr: Rc<RefCell<dyn Entity>>,
|
|
) -> Result<(), Retcode> {
|
|
let entity_id = entity_ptr.borrow().entity_id();
|
|
self.gridless_entity_map.remove(&entity_id);
|
|
tracing::info!("[LR] del_gridless_entity, entity_id:{entity_id}");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn set_player_last_valid_location_on_first_login(&mut self) {
|
|
// Currently hardcoded spawn pos, because no lua.
|
|
|
|
self.owner_player_location.last_valid_pos = Vector3 {
|
|
x: 2747.562,
|
|
y: 194.633,
|
|
z: -1719.386,
|
|
};
|
|
|
|
self.owner_player_location.last_valid_rot = Vector3 {
|
|
x: 0.0,
|
|
y: 307.0,
|
|
z: 0.0,
|
|
};
|
|
}
|
|
|
|
pub fn get_last_owner_location(&self) -> (Vector3, Vector3) {
|
|
(
|
|
self.owner_player_location.last_valid_pos.clone(),
|
|
self.owner_player_location.last_valid_rot.clone(),
|
|
)
|
|
}
|
|
|
|
pub fn gen_new_entity_id(&self, ty: ProtEntityType) -> u32 {
|
|
let mut next_entity_index = self.next_entity_index.load(Ordering::SeqCst);
|
|
let mut is_rewind = false;
|
|
if next_entity_index <= 0xFFFFFE {
|
|
next_entity_index = self.next_entity_index.fetch_add(1, Ordering::SeqCst) + 1;
|
|
} else {
|
|
is_rewind = true;
|
|
next_entity_index = 1;
|
|
self.next_entity_index.store(1, Ordering::SeqCst);
|
|
}
|
|
|
|
if is_rewind {
|
|
tracing::warn!(
|
|
"next_entity_index rewind. scene_id:{} owner_uid:{} scene_time_ms:{}",
|
|
self.scene_id,
|
|
self.owner_uid(),
|
|
self.get_scene_time_ms()
|
|
);
|
|
|
|
// TODO: config->kick_out_on_entity_id_circle
|
|
}
|
|
|
|
entity_utils::get_entity_id(ty, next_entity_index)
|
|
}
|
|
|
|
pub fn get_scene_time_ms(&self) -> u64 {
|
|
time_utils::get_now_ms() - self.begin_time_ms
|
|
}
|
|
|
|
fn create_scene_transaction_on_init(&self) -> String {
|
|
static TRANSACTION_COUNTER: AtomicU32 = AtomicU32::new(0);
|
|
|
|
format!(
|
|
"{}-{}-{}-{}",
|
|
self.scene_id,
|
|
self.owner_uid(),
|
|
time_utils::get_now(),
|
|
TRANSACTION_COUNTER.fetch_add(1, Ordering::SeqCst) + 1
|
|
)
|
|
}
|
|
|
|
pub fn from_bin(scene_id: u32, bin: SceneBin) -> Self {
|
|
Self {
|
|
scene_id,
|
|
scene_transaction: String::new(),
|
|
begin_time_ms: 0,
|
|
own_player: OnceCell::new(),
|
|
unlocked_point_list: bin.unlocked_point_list,
|
|
unlocked_force_list: bin.unlocked_force_list,
|
|
locked_point_list: bin.locked_point_list,
|
|
owner_player_location: ScenePlayerLocation::from_bin(
|
|
bin.owner_player_location.unwrap_or_default(),
|
|
),
|
|
unhide_point_list: bin.unhide_point_list,
|
|
peer_map: BTreeMap::new(),
|
|
host_player_wtr: None,
|
|
player_map: HashMap::new(),
|
|
cur_world_wtr: Weak::new(),
|
|
gridless_entity_map: HashMap::new(),
|
|
next_entity_index: AtomicU32::new(0),
|
|
mp_level_entity_ptr: None,
|
|
player_location_map: HashMap::new(),
|
|
sight_comp: None,
|
|
entity_map: HashMap::new(),
|
|
}
|
|
}
|
|
|
|
pub fn to_bin(&self) -> SceneBin {
|
|
SceneBin {
|
|
unlocked_point_list: self.unlocked_point_list.clone(),
|
|
unlocked_force_list: self.unlocked_force_list.clone(),
|
|
locked_point_list: self.locked_point_list.clone(),
|
|
owner_player_location: Some(self.owner_player_location.to_bin()),
|
|
unhide_point_list: self.unhide_point_list.clone(),
|
|
..Default::default()
|
|
}
|
|
}
|
|
|
|
pub fn own_player(&self) -> Option<Rc<Player>> {
|
|
self.own_player.get().map(|p| p.upgrade())?
|
|
}
|
|
|
|
pub fn set_own_player(&self, player: Rc<Player>) {
|
|
let _ = self.own_player.set(Rc::downgrade(&player));
|
|
}
|
|
|
|
pub fn owner_uid(&self) -> u32 {
|
|
self.own_player().unwrap().uid
|
|
}
|
|
}
|