XilonenImpact/gameserver/src/scene/scene.rs
2024-08-26 15:29:56 +03:00

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
}
}