FireflySR/gameserver/src/game/world/mod.rs

167 lines
5 KiB
Rust

pub mod entity;
mod group;
pub use group::SceneGroup;
use std::sync::atomic::{AtomicU32, Ordering};
use common::data::{
level::{GroupLoadSide, LevelAnchorInfo},
LEVEL_TABLE,
};
use proto::{AvatarType, VectorBin};
use self::entity::{EntityType, SceneActor, SceneEntity, SceneProp};
#[derive(Default)]
pub struct GameWorld {
pub entry_id: u32,
pub plane_id: u32,
pub floor_id: u32,
pub leader_entity_id: u32,
pub scene_group_list: Vec<SceneGroup>,
entity_counter: AtomicU32,
}
impl GameWorld {
pub fn new(entry_id: u32, plane_id: u32, floor_id: u32) -> Self {
Self {
entry_id,
plane_id,
floor_id,
leader_entity_id: 0,
scene_group_list: Vec::new(),
entity_counter: AtomicU32::new(0),
}
}
pub fn is_actor(&self, entity_id: u32) -> bool {
if let Some(group) = self.scene_group_list.iter().find(|g| g.id == 0) {
group.actor_list.iter().any(|a| a.entity_id() == entity_id)
} else {
false
}
}
pub fn add_player_actor(
&mut self,
uid: u32,
avatar_id: u32,
pos: Option<&VectorBin>,
rot: Option<&VectorBin>,
) {
let mut actor = SceneActor::new(
EntityType::Actor as u32 * 1000000 + self.next_entity_id(),
uid,
avatar_id,
AvatarType::AvatarFormalType.into(),
);
if let (Some(pos), Some(rot)) = (pos, rot) {
actor.set_position(pos.x, pos.y, pos.z);
actor.set_rotation(rot.x, rot.y, rot.z);
} else {
let anchor = self.get_player_start_position();
actor.set_position(
(anchor.pos_x * 1000.0) as i32,
(anchor.pos_y * 1000.0) as i32,
(anchor.pos_z * 1000.0) as i32,
);
actor.set_rotation(
(anchor.rot_x * 1000.0) as i32,
(anchor.rot_y * 1000.0) as i32,
(anchor.rot_z * 1000.0) as i32,
);
}
self.leader_entity_id = actor.entity_id();
if let Some(group) = self.scene_group_list.iter_mut().find(|g| g.id == 0) {
group.actor_list.push(actor);
} else {
self.scene_group_list.push(SceneGroup {
id: 0,
actor_list: vec![actor],
prop_list: Vec::new(),
});
}
}
pub fn init_groups(&mut self) {
let floor = LEVEL_TABLE.level_floors.get(&self.floor_id).unwrap();
for group_instance in floor
.group_instance_list
.iter()
.filter(|inst| !inst.is_delete)
{
let level_group = LEVEL_TABLE
.get_level_group(self.floor_id, group_instance.id)
.unwrap();
if level_group.load_side == GroupLoadSide::Client {
continue;
}
let mut prop_entity_list = Vec::new();
if let Some(prop_list) = level_group.prop_list.as_ref() {
for level_prop in prop_list {
if !level_prop.load_on_initial {
continue;
}
// For now, spawn only calyxes
if level_prop.cocoon_id == 0 {
continue;
}
let mut prop = SceneProp::new(
EntityType::Prop as u32 * 1000000 + self.next_entity_id(),
group_instance.id,
level_prop.id,
level_prop.prop_id,
);
prop.set_position(
(level_prop.pos_x * 1000.0) as i32,
(level_prop.pos_y * 1000.0) as i32,
(level_prop.pos_z * 1000.0) as i32,
);
prop.set_rotation(
(level_prop.rot_x * 1000.0) as i32,
(level_prop.rot_y * 1000.0) as i32,
(level_prop.rot_z * 1000.0) as i32,
);
prop_entity_list.push(prop);
}
}
self.scene_group_list.push(SceneGroup {
id: group_instance.id,
prop_list: prop_entity_list,
actor_list: Vec::new(),
});
}
}
fn get_player_start_position(&self) -> &LevelAnchorInfo {
let floor = LEVEL_TABLE.level_floors.get(&self.floor_id).unwrap();
let group_instance = &floor.group_instance_list[floor.start_group_index as usize];
let group = LEVEL_TABLE
.get_level_group(self.floor_id, group_instance.id)
.unwrap();
&group
.anchor_list
.as_ref()
.unwrap()
.iter()
.find(|a| a.id == floor.start_anchor_id)
.unwrap()
}
fn next_entity_id(&self) -> u32 {
self.entity_counter.fetch_add(1, Ordering::SeqCst) + 1
}
}