mirror of
https://github.com/RustySamovar/RustySamovar.git
synced 2024-11-25 11:36:46 +00:00
Implement basic entity (de)spawning (gadgets, mobs, npcs)
This commit is contained in:
parent
8b6f33421c
commit
b83363fd6d
@ -1,13 +1,22 @@
|
||||
use std::collections::HashMap;
|
||||
use std::result::Result;
|
||||
use std::sync::Arc;
|
||||
|
||||
use lua_serde::from_file;
|
||||
|
||||
#[macro_use]
|
||||
use packet_processor::*;
|
||||
use crate::utils::IdManager;
|
||||
|
||||
use super::scene_config;
|
||||
|
||||
use super::scene_config::Group;
|
||||
use super::scene_config::Block;
|
||||
use super::scene_config::Scene;
|
||||
pub use super::scene_config::Group;
|
||||
pub use super::scene_config::Block;
|
||||
pub use super::scene_config::Scene;
|
||||
pub use super::scene_config::Vector;
|
||||
pub use super::scene_config::Monster;
|
||||
pub use super::scene_config::Npc;
|
||||
pub use super::scene_config::Gadget;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InternalSceneData {
|
||||
@ -22,6 +31,7 @@ pub struct InternalBlockData {
|
||||
pub block_id: u32,
|
||||
pub block: Block,
|
||||
pub groups: HashMap<u32,InternalGroupData>,
|
||||
pub entities: HashMap<u32, Arc<Entity>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -33,9 +43,25 @@ pub struct InternalGroupData {
|
||||
// No extra data here
|
||||
}
|
||||
|
||||
#[derive(Debug,Clone)]
|
||||
pub enum EntityType {
|
||||
Monster(Monster),
|
||||
Npc(Npc),
|
||||
Gadget(Gadget),
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Debug,Clone)]
|
||||
pub struct Entity {
|
||||
pub entity_id: u32,
|
||||
pub group_id: u32,
|
||||
pub block_id: u32,
|
||||
pub entity: EntityType,
|
||||
}
|
||||
|
||||
/// Implementation of utility functions
|
||||
impl InternalSceneData {
|
||||
pub fn get_block_by_pos(&self, pos: &proto::Vector) -> Result<&InternalBlockData, String> {
|
||||
pub fn get_block_by_pos(&self, pos: &Vector) -> Result<&InternalBlockData, String> {
|
||||
for (key, value) in self.scene.block_rects.iter() {
|
||||
if value.contains(pos.x, pos.z) {
|
||||
let id = self.scene.blocks[&key];
|
||||
@ -45,6 +71,96 @@ impl InternalSceneData {
|
||||
|
||||
return Err(format!("Block in coords {}, {} not found!", pos.x, pos.z));
|
||||
}
|
||||
|
||||
pub fn get_block_by_id(&self, block_id: u32) -> Result<&InternalBlockData, String> {
|
||||
match self.blocks.get(&block_id) {
|
||||
Some(block) => Ok(block),
|
||||
None => Err(format!("Block with ID {} not found!", block_id)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Entity {
|
||||
pub fn pos(&self) -> Vector {
|
||||
match &self.entity {
|
||||
EntityType::Monster(m) => m.pos.clone(),
|
||||
EntityType::Npc(n) => n.pos.clone(),
|
||||
EntityType::Gadget(g) => g.pos.clone(),
|
||||
_ => panic!("Unsupported entity type!"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rot(&self) -> Vector {
|
||||
match &self.entity {
|
||||
EntityType::Monster(m) => m.rot.clone(),
|
||||
EntityType::Npc(n) => n.rot.clone(),
|
||||
EntityType::Gadget(g) => g.rot.clone(),
|
||||
_ => panic!("Unsupported entity type!"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn speed(&self) -> Vector {
|
||||
// TODO!
|
||||
Vector { x: 0.0, y: 0.0, z: 0.0 }
|
||||
}
|
||||
|
||||
pub fn etype(&self) -> i32 {
|
||||
(match &self.entity {
|
||||
EntityType::Monster(_) => proto::ProtEntityType::ProtEntityMonster,
|
||||
EntityType::Npc(n) => proto::ProtEntityType::ProtEntityNpc,
|
||||
EntityType::Gadget(g) => proto::ProtEntityType::ProtEntityGadget,
|
||||
_ => panic!("Unsupported entity type!"),
|
||||
}) as i32
|
||||
}
|
||||
|
||||
pub fn convert(&self) -> proto::SceneEntityInfo {
|
||||
let mut sei = build!(SceneEntityInfo {
|
||||
entity_id: self.entity_id,
|
||||
entity_type: self.etype(),
|
||||
motion_info: Some(build!(MotionInfo {
|
||||
pos: Some((&self.pos()).into()),
|
||||
rot: Some((&self.rot()).into()),
|
||||
speed: Some((&self.speed()).into()),
|
||||
})),
|
||||
animator_para_list: vec![],
|
||||
entity_client_data: Some(build!(EntityClientData {})),
|
||||
entity_authority_info: Some(build!(EntityAuthorityInfo {
|
||||
renderer_changed_info: Some(build!(EntityRendererChangedInfo{})),
|
||||
ai_info: Some(build!(SceneEntityAiInfo {
|
||||
is_ai_open: true, // TODO!
|
||||
born_pos: Some((&self.pos()).into()),
|
||||
})),
|
||||
born_pos: Some((&self.pos()).into()),
|
||||
})),
|
||||
});
|
||||
|
||||
sei.entity = Some(match &self.entity {
|
||||
EntityType::Monster(m) => proto::scene_entity_info::Entity::Monster(build!(SceneMonsterInfo {
|
||||
monster_id: m.monster_id,
|
||||
group_id: self.group_id,
|
||||
config_id: m.config_id,
|
||||
authority_peer_id: 1, // TODO: hardcoded value!
|
||||
born_type: proto::MonsterBornType::MonsterBornDefault as i32, // TODO: hardcoded value!
|
||||
block_id: self.block_id,
|
||||
// TODO: level scaling, weapons!
|
||||
})),
|
||||
EntityType::Npc(n) => proto::scene_entity_info::Entity::Npc(build!(SceneNpcInfo {
|
||||
npc_id: n.npc_id,
|
||||
block_id: self.block_id,
|
||||
})),
|
||||
EntityType::Gadget(g) => proto::scene_entity_info::Entity::Gadget(build!(SceneGadgetInfo {
|
||||
gadget_id: g.gadget_id,
|
||||
group_id: self.group_id,
|
||||
config_id: g.config_id,
|
||||
authority_peer_id: 1, // TODO: hardcoded value!
|
||||
is_enable_interact: true,
|
||||
// TODO: collectibles!
|
||||
})),
|
||||
_ => panic!("Unsupported entity type!"),
|
||||
});
|
||||
|
||||
sei
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -84,13 +200,15 @@ impl LuaManager {
|
||||
}
|
||||
|
||||
fn load_scene(directory: &str, scene_id: u32) -> InternalSceneData {
|
||||
let mut entity_id_counter: u32 = 1;
|
||||
|
||||
let filename = format!(scene_name!(), directory, scene_id, scene_id);
|
||||
|
||||
let scene: Scene = from_file(&filename).unwrap(); // TODO: error handling!
|
||||
|
||||
let blocks = scene.blocks
|
||||
.iter()
|
||||
.map(|(key, block_id)| (*block_id, Self::load_block(directory, scene_id, *block_id)))
|
||||
.map(|(key, block_id)| (*block_id, Self::load_block(directory, scene_id, *block_id, &mut entity_id_counter)))
|
||||
.collect();
|
||||
|
||||
InternalSceneData {
|
||||
@ -100,11 +218,11 @@ impl LuaManager {
|
||||
}
|
||||
}
|
||||
|
||||
fn load_block(directory: &str, scene_id: u32, block_id: u32) -> InternalBlockData {
|
||||
fn load_block(directory: &str, scene_id: u32, block_id: u32, entity_id_counter: &mut u32) -> InternalBlockData {
|
||||
let filename = format!(block_name!(), directory, scene_id, scene_id, block_id);
|
||||
let block: Block = from_file(&filename).unwrap(); // TODO: error handling!
|
||||
|
||||
let groups = if false
|
||||
let groups: HashMap<u32,InternalGroupData> = if false
|
||||
{
|
||||
// TODO: should be this! But some groups are missing
|
||||
block.groups
|
||||
@ -124,15 +242,57 @@ impl LuaManager {
|
||||
groups
|
||||
};
|
||||
|
||||
// TODO: figure out more casual way!
|
||||
let mut entities = HashMap::new();
|
||||
|
||||
for (group_id, igd) in groups.iter() {
|
||||
for (npc_id, npc) in igd.group.npcs.iter() {
|
||||
let entity_id = IdManager::get_entity_id_by_type_and_sub_id(&proto::ProtEntityType::ProtEntityNpc, *entity_id_counter);
|
||||
*entity_id_counter = *entity_id_counter + 1;
|
||||
|
||||
entities.insert(entity_id, Arc::new(Entity {
|
||||
entity_id: entity_id,
|
||||
group_id: *group_id,
|
||||
block_id: block_id,
|
||||
entity: EntityType::Npc(npc.clone()), // TODO: very fucking inefficient!
|
||||
}));
|
||||
}
|
||||
|
||||
for (monster_id, monster) in igd.group.monsters.iter() {
|
||||
let entity_id = IdManager::get_entity_id_by_type_and_sub_id(&proto::ProtEntityType::ProtEntityMonster, *entity_id_counter);
|
||||
*entity_id_counter = *entity_id_counter + 1;
|
||||
|
||||
entities.insert(entity_id, Arc::new(Entity {
|
||||
entity_id: entity_id,
|
||||
group_id: *group_id,
|
||||
block_id: block_id,
|
||||
entity: EntityType::Monster(monster.clone()), // TODO: very fucking inefficient!
|
||||
}));
|
||||
}
|
||||
|
||||
for (gadget_id, gadget) in igd.group.gadgets.iter() {
|
||||
let entity_id = IdManager::get_entity_id_by_type_and_sub_id(&proto::ProtEntityType::ProtEntityGadget, *entity_id_counter);
|
||||
*entity_id_counter = *entity_id_counter + 1;
|
||||
|
||||
entities.insert(entity_id, Arc::new(Entity {
|
||||
entity_id: entity_id,
|
||||
group_id: *group_id,
|
||||
block_id: block_id,
|
||||
entity: EntityType::Gadget(gadget.clone()), // TODO: very fucking inefficient!
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
InternalBlockData {
|
||||
scene_id,
|
||||
block_id,
|
||||
block,
|
||||
groups,
|
||||
entities,
|
||||
}
|
||||
}
|
||||
|
||||
fn load_group(directory: &str, scene_id: u32, block_id: u32, group_id: u32) -> Result<InternalGroupData, std::io::Error> {
|
||||
fn load_group(directory: &str, scene_id: u32, block_id: u32, group_id: u32) -> Result<(InternalGroupData), std::io::Error> {
|
||||
let filename = format!(group_name!(), directory, scene_id, scene_id, group_id);
|
||||
//let group: Group = from_file(&filename).unwrap(); // TODO: error handling!
|
||||
let group: Group = from_file(&filename)?;
|
||||
|
@ -2,3 +2,5 @@ mod lua_manager;
|
||||
mod scene_config;
|
||||
|
||||
pub use self::lua_manager::LuaManager;
|
||||
pub use self::scene_config::Vector;
|
||||
pub use self::lua_manager::Entity;
|
@ -5,7 +5,7 @@ use serde::Deserialize;
|
||||
|
||||
// sceneX.lua
|
||||
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
#[derive(Deserialize, PartialEq, Debug, Clone)]
|
||||
pub struct Vector {
|
||||
#[serde(default)]
|
||||
pub x: f32,
|
||||
@ -49,7 +49,19 @@ impl Vector {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
impl From<&Vector> for proto::Vector {
|
||||
fn from(v: &Vector) -> proto::Vector {
|
||||
proto::Vector { x: v.x, y: v.y, z: v.z }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&proto::Vector> for Vector {
|
||||
fn from(v: &proto::Vector) -> Vector {
|
||||
Vector { x: v.x, y: v.y, z: v.z }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, PartialEq, Debug, Clone)]
|
||||
pub struct BlockRect {
|
||||
pub min: Vector,
|
||||
pub max: Vector,
|
||||
@ -64,7 +76,7 @@ impl BlockRect {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
#[derive(Deserialize, PartialEq, Debug, Clone)]
|
||||
pub struct SceneConfig {
|
||||
pub born_rot: Vector,
|
||||
pub born_pos: Vector,
|
||||
@ -74,7 +86,7 @@ pub struct SceneConfig {
|
||||
pub die_y: f32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
#[derive(Deserialize, PartialEq, Debug, Clone)]
|
||||
pub struct Scene {
|
||||
pub blocks: HashMap<u32,u32>,
|
||||
#[serde(default)]
|
||||
@ -88,12 +100,12 @@ pub struct Scene {
|
||||
|
||||
// sceneX_blockY.lua
|
||||
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
#[derive(Deserialize, PartialEq, Debug, Clone)]
|
||||
pub struct Block {
|
||||
pub groups: HashMap<u32,GroupInfo>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
#[derive(Deserialize, PartialEq, Debug, Clone)]
|
||||
pub struct GroupInfo {
|
||||
pub is_replaceable: Option<ComplicatedBool>,
|
||||
#[serde(default)]
|
||||
@ -104,21 +116,21 @@ pub struct GroupInfo {
|
||||
pub business: Option<Business>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
#[derive(Deserialize, PartialEq, Debug, Clone)]
|
||||
pub struct ComplicatedBool {
|
||||
pub version: u32,
|
||||
pub value: bool,
|
||||
pub new_bin_only: bool,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
#[derive(Deserialize, PartialEq, Debug, Clone)]
|
||||
pub struct Business {
|
||||
pub r#type: u32,
|
||||
}
|
||||
|
||||
// sceneX_groupZ.lua
|
||||
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
#[derive(Deserialize, PartialEq, Debug, Clone)]
|
||||
pub struct Group {
|
||||
pub init_config: Option<GroupInitConfig>,
|
||||
#[serde(default)]
|
||||
@ -140,7 +152,7 @@ pub struct Group {
|
||||
// MovePlatform - Function???
|
||||
}
|
||||
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
#[derive(Deserialize, PartialEq, Debug, Clone)]
|
||||
pub struct Suite {
|
||||
pub rand_weight: u32,
|
||||
|
||||
@ -157,7 +169,7 @@ pub struct Suite {
|
||||
pub monsters: HashMap<u32,u32>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
#[derive(Deserialize, PartialEq, Debug, Clone)]
|
||||
pub struct GroupInitConfig {
|
||||
pub end_suite: Option<u32>,
|
||||
//#[serde(default)]
|
||||
@ -165,14 +177,14 @@ pub struct GroupInitConfig {
|
||||
pub suite: u32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
#[derive(Deserialize, PartialEq, Debug, Clone)]
|
||||
pub struct Variable {
|
||||
pub name: String,
|
||||
pub value: u32,
|
||||
pub no_refresh: bool,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
#[derive(Deserialize, PartialEq, Debug, Clone)]
|
||||
pub struct Monster {
|
||||
pub rot: Vector,
|
||||
pub pos: Vector,
|
||||
@ -181,7 +193,7 @@ pub struct Monster {
|
||||
pub monster_id: u32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
#[derive(Deserialize, PartialEq, Debug, Clone)]
|
||||
pub struct Npc {
|
||||
pub rot: Vector,
|
||||
pub pos: Vector,
|
||||
@ -192,7 +204,7 @@ pub struct Npc {
|
||||
pub room: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
#[derive(Deserialize, PartialEq, Debug, Clone)]
|
||||
pub struct Gadget {
|
||||
pub rot: Vector,
|
||||
pub pos: Vector,
|
||||
@ -215,7 +227,7 @@ pub struct Gadget {
|
||||
pub is_use_point_array: bool,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
#[derive(Deserialize, PartialEq, Debug, Clone)]
|
||||
pub struct ExploreInfo {
|
||||
pub exp: u32,
|
||||
pub name: String,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::sync::{mpsc::{self, Sender, Receiver}, Arc, Mutex};
|
||||
use std::thread;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||
|
||||
use crate::server::IpcMessage;
|
||||
@ -17,20 +17,23 @@ use serde_json::de::Read;
|
||||
use crate::LuaManager;
|
||||
use crate::utils::{IdManager, TimeManager};
|
||||
|
||||
use crate::luamanager::Vector;
|
||||
use crate::luamanager::Entity;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Player {
|
||||
player_id: u32,
|
||||
pos: proto::Vector,
|
||||
pos: Vector,
|
||||
current_scene: u32,
|
||||
current_block: u32,
|
||||
entities: HashMap<u32,Entity>,
|
||||
entities: HashMap<u32, Arc<Entity>>,
|
||||
lua_manager: Arc<LuaManager>,
|
||||
packets_to_send_tx: Sender<IpcMessage>,
|
||||
}
|
||||
|
||||
impl Player {
|
||||
const DESPAWN_DISTANCE: f32 = 10.0;
|
||||
const SPAWN_DISTANCE: f32 = 8.0;
|
||||
const DESPAWN_DISTANCE: f32 = 100.0;
|
||||
const SPAWN_DISTANCE: f32 = Self::DESPAWN_DISTANCE * 0.8;
|
||||
const RESPAWN_TIME: i32 = 10; // In seconds
|
||||
|
||||
pub fn despawn_everything(&self) {
|
||||
@ -53,19 +56,67 @@ impl Player {
|
||||
|
||||
pub fn position_changed(&mut self) {
|
||||
// 1. Go through the list of spawned entities and despawn those that are too far from us
|
||||
// 2. Go through the list of available entities and spawn those that are close to us and their respawn timeout (in case of collectibles and monsters) is over
|
||||
let despawn_list: Vec<u32> = self.entities.iter()
|
||||
.filter(|(k, v)| v.pos().sub(&self.pos).len() > Self::DESPAWN_DISTANCE)
|
||||
.map(|(k, v)| *k)
|
||||
.collect();
|
||||
|
||||
if despawn_list.len() > 0 {
|
||||
for k in despawn_list.iter() {
|
||||
self.entities.remove(&k);
|
||||
}
|
||||
|
||||
// TODO: HACK!
|
||||
let player_id = self.player_id;
|
||||
let metadata = &build!(PacketHead {
|
||||
sent_ms: TimeManager::timestamp(),
|
||||
client_sequence_id: 0,
|
||||
});
|
||||
|
||||
build_and_send!(self, player_id, metadata, SceneEntityDisappearNotify {
|
||||
entity_list: despawn_list,
|
||||
disappear_type: proto::VisionType::VisionMiss as i32,
|
||||
});
|
||||
}
|
||||
|
||||
// 2. Go through the list of available entities and spawn those that are close to us and their respawn timeout (in case of collectibles and monsters) is over
|
||||
let spawned_list: HashSet<u32> = self.entities.iter().map(|(k, v)| *k).collect();
|
||||
|
||||
// TODO: do this once only on block change!
|
||||
let scene = self.lua_manager.get_scene_by_id(self.current_scene).unwrap();
|
||||
let block = match scene.get_block_by_id(self.current_block) { // TODO: this is due to some blocks missing
|
||||
Ok(block) => block,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
let spawn_list: Vec<Arc<Entity>> = block.entities.iter()
|
||||
.filter(|(entity_id, entity)| !spawned_list.contains(entity_id))
|
||||
.filter(|(entity_id, entity)| entity.pos().sub(&self.pos).len() < Self::SPAWN_DISTANCE)
|
||||
.map(|(entity_id, entity)| (*entity).clone())
|
||||
.collect();
|
||||
|
||||
if spawn_list.len() > 0 {
|
||||
// TODO: HACK!
|
||||
let player_id = self.player_id;
|
||||
let metadata = &build!(PacketHead {
|
||||
sent_ms: TimeManager::timestamp(),
|
||||
client_sequence_id: 0,
|
||||
});
|
||||
|
||||
build_and_send!(self, player_id, metadata, SceneEntityAppearNotify {
|
||||
entity_list: spawn_list.iter().map(|e| e.convert()).collect(),
|
||||
appear_type: proto::VisionType::VisionBorn as i32,
|
||||
});
|
||||
|
||||
for entity in spawn_list.into_iter() {
|
||||
self.entities.insert(entity.entity_id, entity.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Gatherable stuff is described in GatherExcelConfigData
|
||||
}
|
||||
|
||||
#[derive(Debug,Clone)]
|
||||
pub struct Entity {
|
||||
entity_id: u32,
|
||||
health: i32,
|
||||
}
|
||||
|
||||
#[packet_processor(
|
||||
CombatInvocationsNotify,
|
||||
)]
|
||||
@ -112,10 +163,13 @@ impl EntitySubsystem {
|
||||
match block {
|
||||
Ok(block) =>
|
||||
if player.current_block != block.block_id {
|
||||
println!("Player {:?} moved to the block {:?}", player, block.block_id);
|
||||
println!("Player {:?} moved to the block {:?}", player.player_id, block.block_id);
|
||||
player.current_block = block.block_id;
|
||||
},
|
||||
Err(_) => {/* TODO? */},
|
||||
Err(_) => {
|
||||
// TODO?
|
||||
player.current_block = 0;
|
||||
},
|
||||
};
|
||||
|
||||
player.position_changed();
|
||||
@ -167,7 +221,7 @@ impl EntitySubsystem {
|
||||
// Avatar moved => update player's position
|
||||
let pos = if let Some(motion_info) = invoke.motion_info.as_ref() {
|
||||
if let Some(pos) = motion_info.pos.as_ref() {
|
||||
pos.clone()
|
||||
pos.into()
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user