Implement movement handling and last player position saving

This commit is contained in:
xeon 2024-09-01 21:34:51 +03:00
parent d1de5685ae
commit 574aaa5469
16 changed files with 979 additions and 389 deletions

View file

@ -1,10 +1,22 @@
use std::{fmt::Display, rc::Rc};
use data::math_def::Vector3;
use proto::{ProtEntityType, SceneEntityInfo};
use data::math_def::{Coordinate, Vector3};
use proto::{MotionState, ProtEntityType, Retcode, SceneEntityInfo};
use crate::player::Player;
#[allow(dead_code)]
pub struct MotionContext {
pub scene_time_ms: u64,
pub reliable_seq: u32,
pub is_reliable: bool,
pub exclude_uid: u32,
pub is_notify: bool,
pub interval_velocity: u32,
pub sync_uid_vec: Vec<u32>,
pub is_do_move: bool,
}
pub trait Entity {
fn get_entity_type(&self) -> ProtEntityType;
fn get_group_id(&self) -> u32;
@ -14,6 +26,10 @@ pub trait Entity {
fn rotation(&self) -> &Vector3;
fn set_position(&mut self, pos: Vector3);
fn set_rotation(&mut self, rot: Vector3);
fn set_coordinate(&mut self, _coordinate: Coordinate) {}
fn get_coordinate(&self) -> Coordinate {
Coordinate::default()
}
fn get_owner_player(&self) -> Option<Rc<Player>>;
fn is_on_scene(&self) -> bool {
@ -43,6 +59,37 @@ pub trait Entity {
}
}
fn set_motion_info(
&mut self,
motion_info: &proto::MotionInfo,
motion_context: &MotionContext,
) -> Result<(), Retcode> {
self.set_motion_info_base(motion_info, motion_context)
}
fn set_motion_info_base(
&mut self,
motion_info: &proto::MotionInfo,
_motion_context: &MotionContext,
) -> Result<(), Retcode> {
match motion_info.state() {
MotionState::MotionNone => (),
_ => {
let _speed = motion_info.speed.clone().unwrap_or_default();
let rot = motion_info.rot.as_ref().unwrap();
let pos = motion_info.pos.as_ref().unwrap();
self.set_rotation(Vector3::from_client(rot));
self.set_position(Vector3::from_client(pos));
// TODO: Entity::checkMoveSpeed
}
}
// TODO: broadcast
Ok(())
}
fn to_client(&self, _scene_entity_info: &mut SceneEntityInfo) {}
}

View file

@ -1,6 +1,6 @@
mod entity;
pub use entity::Entity;
pub use entity::{Entity, MotionContext};
pub mod entity_mgr;
pub mod entity_utils;
mod vision_context;

View file

@ -0,0 +1,61 @@
use std::{error::Error, rc::Rc};
use common::net::tools::Packet;
use prost::Message;
use proto::{CombatTypeArgument, EntityMoveInfo};
use crate::player::Player;
use super::{get_proto, scene_handler};
pub fn on_combat_invocations_notify(
player: &Rc<Player>,
packet: Packet,
) -> Result<(), Box<dyn Error>> {
let notify = get_proto!(packet, CombatInvocationsNotify);
for entry in notify.invoke_list {
match entry.argument_type() {
CombatTypeArgument::EntityMove => {
let Ok(entity_move_info) = EntityMoveInfo::decode(&*entry.combat_data) else {
tracing::warn!("combat invoke type: proto::EntityMoveInfo fail to parse, len:{}, base64:{}, player:{}", entry.combat_data.len(), rbase64::encode(&*entry.combat_data), player.uid);
return Ok(());
};
let (cur_scene, cur_avatar) = {
(
player
.player_scene_comp
.borrow()
.get_cur_scene()
.unwrap()
.clone(),
player
.player_avatar_comp
.borrow()
.get_cur_avatar()
.unwrap()
.clone(),
)
};
let mut sync_uid_vec = Vec::new();
if let Err(ret) = scene_handler::process_entity_move_info(
cur_scene,
player,
cur_avatar,
&entity_move_info,
&mut sync_uid_vec,
) {
tracing::warn!("process_entity_move_info fails, ret:{ret:?}");
}
}
unhandled => tracing::warn!(
"wrong combat type, player:{}, type:{unhandled:?}",
player.uid,
),
}
}
Ok(())
}

View file

@ -1,4 +1,5 @@
pub mod avatar_handler;
pub mod fight_handler;
pub mod login_handler;
pub mod player_handler;
pub mod player_misc_handler;
@ -44,10 +45,12 @@ game_packet_handlers! {
PlayerMiscHandler::PingReq;
PlayerHandler::SetPlayerBornDataReq;
PlayerHandler::PlayerLogoutReq;
PlayerHandler::UnionCmdNotify;
SceneHandler::EnterSceneReadyReq;
SceneHandler::SceneInitFinishReq;
SceneHandler::EnterSceneDoneReq;
SceneHandler::PostEnterSceneReq;
AvatarHandler::SetUpAvatarTeamReq;
AvatarHandler::ChangeAvatarReq;
FightHandler::CombatInvocationsNotify;
}

View file

@ -1,6 +1,6 @@
use std::{error::Error, rc::Rc};
use common::net::tools::Packet;
use common::{net::tools::Packet, tools::time_utils};
use proto::{PlayerLogoutReason, ServerDisconnectClientNotify, SetPlayerBornDataRsp};
use crate::player::Player;
@ -38,3 +38,36 @@ pub fn on_player_logout_req(player: &Rc<Player>, packet: Packet) -> Result<(), B
Ok(())
}
pub fn on_union_cmd_notify(player: &Rc<Player>, packet: Packet) -> Result<(), Box<dyn Error>> {
// TODO: PlayerHandler::checkUnionFrequent
let notify = get_proto!(packet, UnionCmdNotify);
for cmd in notify.cmd_list {
let last_time = time_utils::get_now_ms();
let err = super::process_packet(
player,
Packet {
cmd_id: cmd.message_id as u16,
recv_vec: cmd.body,
head: proto::PacketHead::default(),
},
)
.err();
let time = time_utils::get_now_ms();
tracing::info!(
"|UnionSubCmd|{}|{}|{}|",
player.uid,
cmd.message_id,
time - last_time
);
if let Some(err) = err {
tracing::warn!("UnionSubCmd process failed: {err:?}");
}
}
Ok(())
}

View file

@ -1,11 +1,18 @@
use std::{error::Error, rc::Rc};
use std::{cell::RefCell, error::Error, rc::Rc};
use common::net::tools::Packet;
use data::math_def::Vector3;
use proto::{
EnterSceneDoneRsp, EnterSceneReadyRsp, PostEnterSceneRsp, Retcode, SceneInitFinishRsp,
EnterSceneDoneRsp, EnterSceneReadyRsp, EntityMoveInfo, PostEnterSceneRsp, Retcode,
SceneInitFinishRsp,
};
use crate::player::Player;
use crate::{
creature::{Creature, LifeState},
entity::{Entity, MotionContext},
player::{avatar::Avatar, Player},
scene::Scene,
};
use super::get_proto;
@ -68,3 +75,51 @@ pub fn on_post_enter_scene_req(player: &Rc<Player>, packet: Packet) -> Result<()
Ok(())
}
pub fn process_entity_move_info(
scene: Rc<RefCell<Scene>>,
player: &Rc<Player>,
cur_avatar: Rc<RefCell<Avatar>>,
move_info: &EntityMoveInfo,
_sync_uid_vec: &mut Vec<u32>,
) -> Result<(), Retcode> {
if move_info.entity_id == cur_avatar.borrow().entity_id() {
if cur_avatar.borrow().get_life_state() != LifeState::LifeAlive {
tracing::info!(
"avatar is not alive:{}",
cur_avatar.borrow() as std::cell::Ref<dyn Entity>
);
return Err(Retcode::RetFail);
}
} else {
return Err(Retcode::RetFail); // TODO: non cur avatar also has some handling
}
let motion_info = move_info.motion_info.as_ref().unwrap();
let (Some(pos), Some(rot)) = (motion_info.pos.as_ref(), motion_info.rot.as_ref()) else {
return Ok(());
};
let context = MotionContext {
scene_time_ms: move_info.scene_time as u64,
reliable_seq: move_info.reliable_seq,
is_reliable: move_info.is_reliable,
exclude_uid: player.uid,
is_notify: false,
is_do_move: true,
interval_velocity: 0,
sync_uid_vec: Vec::new(),
};
scene.borrow_mut().entity_move_to(
cur_avatar.clone() as Rc<RefCell<dyn Entity>>,
Vector3::from_client(pos),
Vector3::from_client(rot),
);
let _ = cur_avatar
.borrow_mut()
.set_motion_info(motion_info, &context);
Ok(())
}

View file

@ -3,7 +3,11 @@ use std::{
rc::{Rc, Weak},
};
use data::{math_def::Vector3, prop_type::PROP_LEVEL, ElementType, FightPropType};
use data::{
math_def::{Coordinate, Vector3},
prop_type::PROP_LEVEL,
ElementType, FightPropType,
};
use proto::{
avatar_bin::{self, Detail},
AbilitySyncStateInfo, AnimatorParameterValueInfoPair, AvatarBin, AvatarExcelInfo, Cjnoehnhdgl,
@ -14,7 +18,7 @@ use proto::{
use crate::{
ability::AbilityComp,
creature::{property::PropValueMap, Creature, FightPropComp, LifeState},
entity::Entity,
entity::{Entity, MotionContext},
item::EquipComp,
player::{item::Item, Player},
skill::SkillComp,
@ -243,6 +247,7 @@ pub struct BaseAvatar {
pub rot: Vector3,
pub last_valid_pos: Vector3,
pub last_valid_rot: Vector3,
pub coordinate: Coordinate,
}
impl BaseAvatar {
@ -426,6 +431,26 @@ impl Entity for Avatar {
self.base_avatar_mut().rot = rot;
}
fn set_coordinate(&mut self, coordinate: Coordinate) {
self.base_avatar_mut().coordinate = coordinate;
}
fn get_coordinate(&self) -> Coordinate {
self.base_avatar().coordinate.clone()
}
fn set_motion_info(
&mut self,
motion_info: &proto::MotionInfo,
motion_context: &MotionContext,
) -> Result<(), proto::Retcode> {
self.set_motion_info_base(motion_info, motion_context)?;
self.set_last_valid_position(Vector3::from_client(motion_info.pos.as_ref().unwrap()));
self.set_last_valid_rotation(Vector3::from_client(motion_info.rot.as_ref().unwrap()));
Ok(())
}
fn to_client(&self, scene_entity_info: &mut SceneEntityInfo) {
scene_entity_info.entity_id = self.entity_id();
scene_entity_info.entity_type = self.get_entity_type().into();

View file

@ -23,8 +23,8 @@ use proto::{
EnterSceneDoneReq, EnterSceneDoneRsp, EnterScenePeerNotify, EnterSceneReadyReq, EnterType,
MpLevelEntityInfo, PacketHead, PingReq, PingRsp, PlayerData, PlayerDataBin, PlayerDataNotify,
PlayerEnterSceneInfoNotify, PlayerEnterSceneNotify, PlayerLoginRsp, PostEnterSceneReq,
PostEnterSceneRsp, ResVersionConfig, Retcode, SavePlayerDataReq, SceneInitFinishReq,
SetPlayerBornDataReq, TeamEnterSceneInfo, VisionType, YSMessage,
PostEnterSceneRsp, Retcode, SavePlayerDataReq, SceneInitFinishReq, SetPlayerBornDataReq,
TeamEnterSceneInfo, VisionType, YSMessage,
};
use rand::RngCore;

View file

@ -2,7 +2,7 @@ use std::{cell::RefCell, collections::BTreeMap, rc::Rc};
use crate::entity::Entity;
use super::region::Region;
use super::{region::Region, visitor::Visitor};
#[derive(Default)]
pub struct Grid {
@ -30,6 +30,12 @@ impl Grid {
self.region_vec.push(region);
}
pub fn accept(&self, visitor: &mut Visitor) {
self.entity_map
.values()
.for_each(|e| visitor.visit_entity(&e));
}
pub fn get_all_entity(&self) -> Vec<Rc<RefCell<dyn Entity>>> {
self.entity_map.values().map(|a| a.clone()).collect()
}

View file

@ -5,7 +5,7 @@ use proto::ProtEntityType;
use crate::entity::Entity;
use super::{grid::Grid, region::Region, VisionLevelType};
use super::{grid::Grid, region::Region, visitor::Visitor, VisionLevelType};
#[allow(unused)]
pub struct GridMgr {
@ -21,6 +21,10 @@ impl GridMgr {
self.grid_map.entry((x, y)).or_insert_with(Grid::default)
}
pub fn find_grid(&self, x: i32, y: i32) -> Option<&Grid> {
self.grid_map.get(&(x, y))
}
pub fn place_entity(
&mut self,
entity: Rc<RefCell<dyn Entity>>,
@ -47,6 +51,115 @@ impl GridMgr {
grid.del_entity(entity);
}
pub fn entity_move_to(&mut self, entity: &Rc<RefCell<dyn Entity>>, coordinate: &Coordinate) {
let prev_coordinate = entity.borrow().get_coordinate();
if *coordinate == prev_coordinate {
return;
}
let prev_grid = self.get_grid(prev_coordinate.x, prev_coordinate.y);
prev_grid.del_entity(entity);
let grid = self.get_grid(coordinate.x, coordinate.y);
grid.add_entity(entity.clone());
entity.borrow_mut().set_coordinate(coordinate.clone());
}
pub fn visit_diff_grids(
&self,
center1: &Coordinate,
center2: &Coordinate,
t1: &mut Visitor,
t2: &mut Visitor,
) {
let sight_radius = self.sight_radius as i32;
let left_x1 = center1.x - sight_radius;
let right_x1 = center1.x + sight_radius;
let low_y1 = center1.y - sight_radius;
let up_y1 = center1.y + sight_radius;
let left_x2 = center2.x - sight_radius;
let right_x2 = center2.x + sight_radius;
let low_y2 = center2.y - sight_radius;
let up_y2 = center2.y + sight_radius;
if right_x1 >= left_x2 && right_x2 >= left_x1 && up_y1 >= low_y2 && up_y2 >= low_y1 {
let mut low_y = low_y1;
let mut up_y = up_y1;
if center1.y >= center2.y {
if center1.y > center2.y {
for j in up_y1..up_y2 {
for i in left_x1..=right_x1 {
self.visit_grid(i, j, t1);
}
}
for j in low_y2..low_y1 {
for i in left_x2..=right_x2 {
self.visit_grid(i, j, t2);
}
}
low_y = low_y1;
up_y = up_y2;
}
} else {
for j in low_y1..low_y2 {
for i in left_x1..=right_x1 {
self.visit_grid(i, j, t1);
}
}
for j in up_y2..up_y1 {
for i in left_x2..=right_x2 {
self.visit_grid(i, j, t2);
}
}
low_y = low_y2;
up_y = up_y1;
}
for j in low_y..=up_y {
if center1.x >= center2.x {
if center1.x > center2.x {
for i in left_x2..left_x1 {
self.visit_grid(i, j, t2);
}
for i in right_x1..right_x2 {
self.visit_grid(i, j, t1);
}
}
} else {
for i in left_x1..left_x2 {
self.visit_grid(i, j, t1);
}
for i in right_x2..right_x1 {
self.visit_grid(i, j, t2);
}
}
}
} else {
for i in left_x1..=right_x1 {
for j in low_y1..=up_y1 {
self.visit_grid(i, j, t1);
}
}
for i in left_x2..=right_x2 {
for j in low_y2..=up_y2 {
self.visit_grid(i, j, t2);
}
}
}
}
pub fn visit_grid(&self, x: i32, y: i32, visitor: &mut Visitor) {
if let Some(grid) = self.find_grid(x, y) {
grid.accept(visitor);
}
}
#[allow(dead_code)]
pub fn place_region(&mut self, region: Region, coordinate: Coordinate) -> Result<(), ()> {
let grid = self.get_grid(coordinate.x, coordinate.y);

View file

@ -10,6 +10,7 @@ mod scene;
pub mod scene_mgr;
mod scene_sight_comp;
mod scene_team;
mod visitor;
pub use mp_level_entity::MPLevelEntity;
pub use player_scene_comp::{EnterSceneState, PlayerSceneComp};

View file

@ -268,6 +268,59 @@ impl Scene {
.insert(uid, player_location);
}
pub fn entity_move_to(&mut self, entity: Rc<RefCell<dyn Entity>>, pos: Vector3, rot: Vector3) {
if !entity.borrow().is_on_scene() {
tracing::info!("entity is not on scene {}", entity.borrow());
return;
}
let sight_comp = self.base_mut().sight_comp.as_mut().unwrap();
let mut meet_entity_vec = Vec::new();
let mut miss_entity_vec = Vec::new();
sight_comp.entity_move_to(
entity.clone(),
pos.clone(),
&mut miss_entity_vec,
&mut meet_entity_vec,
);
if let Some(player) = entity.borrow().get_owner_player() {
player.send_proto(SceneEntityDisappearNotify {
param: 0,
disappear_type: VisionType::VisionMiss.into(),
entity_list: miss_entity_vec
.into_iter()
.map(|e| e.borrow().entity_id())
.collect(),
});
player.send_proto(SceneEntityAppearNotify {
param: 0,
appear_type: VisionType::VisionMeet.into(),
entity_list: meet_entity_vec
.into_iter()
.map(|e| {
let mut appear_entity_info = SceneEntityInfo::default();
e.borrow().to_client(&mut appear_entity_info);
appear_entity_info
})
.collect(),
});
if player.uid == self.base().owner_uid() {
let base_mut = self.base_mut();
let owner_location = &mut base_mut.owner_player_location;
owner_location.cur_pos = pos.clone();
owner_location.cur_rot = rot.clone();
owner_location.last_valid_pos = pos.clone();
owner_location.last_valid_rot = rot.clone();
}
}
}
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}");

View file

@ -1,12 +1,15 @@
use std::{cell::RefCell, collections::HashMap, rc::Rc};
use data::math_def::{Coordinate, Vector2};
use data::math_def::{Coordinate, Vector2, Vector3};
use num_enum::FromPrimitive;
use proto::Retcode;
use proto::{ProtEntityType, Retcode};
use crate::entity::Entity;
use super::grid_mgr::GridMgr;
use super::{
grid_mgr::GridMgr,
visitor::{Visitor, VisitorType},
};
#[derive(Debug, Default, Clone, Copy, FromPrimitive)]
#[repr(u32)]
@ -52,6 +55,20 @@ impl SceneSightComp {
}
}
pub fn entity_move_to(
&mut self,
entity: Rc<RefCell<dyn Entity>>,
dest_pos: Vector3,
miss_entity_vec: &mut Vec<Rc<RefCell<dyn Entity>>>,
meet_entity_vec: &mut Vec<Rc<RefCell<dyn Entity>>>,
) {
match self {
Self::Grid(grid_comp) => {
grid_comp.entity_move_to(entity, dest_pos, miss_entity_vec, meet_entity_vec)
}
}
}
pub fn pos_to_coordinate(&self, range_type: VisionLevelType, pos: &Vector2) -> Coordinate {
match self {
Self::Grid(grid_comp) => grid_comp.pos_to_coordinate(range_type, pos),
@ -177,6 +194,66 @@ impl SceneGridComp {
grid_mgr.remove_entity(entity, coordinate);
}
pub fn entity_move_to(
&mut self,
entity: Rc<RefCell<dyn Entity>>,
dest_pos: Vector3,
miss_entity_vec: &mut Vec<Rc<RefCell<dyn Entity>>>,
meet_entity_vec: &mut Vec<Rc<RefCell<dyn Entity>>>,
) {
let range_type = self.get_vision_level_type(&entity);
let pos = Vector2 {
x: dest_pos.x,
y: dest_pos.z,
};
let coordinate = self.pos_to_coordinate(range_type, &pos);
let grid_mgr = &mut self.grid_mgr_arr[range_type as usize];
grid_mgr.entity_move_to(&entity, &coordinate);
let mut miss_visitor = Visitor::new(VisitorType::Entity, entity.clone());
let mut meet_visitor = Visitor::new(VisitorType::Entity, entity.clone());
if entity.borrow().get_entity_type() == ProtEntityType::ProtEntityAvatar {
let prev_pos = entity.borrow().position().clone();
self.visit_diff_grids(&prev_pos, &dest_pos, &mut miss_visitor, &mut meet_visitor);
}
miss_entity_vec.extend(miss_visitor.get_entity_vec().iter().cloned());
meet_entity_vec.extend(meet_visitor.get_entity_vec().iter().cloned());
}
pub fn visit_diff_grids(
&self,
from_pos: &Vector3,
to_pos: &Vector3,
miss_visitor: &mut Visitor,
meet_visitor: &mut Visitor,
) {
for (i, grid_mgr) in self.grid_mgr_arr.iter().enumerate() {
let c1 = self.pos_to_coordinate(
VisionLevelType::from_primitive(i as u32),
&Vector2 {
x: from_pos.x,
y: from_pos.z,
},
);
let c2 = self.pos_to_coordinate(
VisionLevelType::from_primitive(i as u32),
&Vector2 {
x: to_pos.x,
y: to_pos.z,
},
);
if c1 != c2 {
grid_mgr.visit_diff_grids(&c1, &c2, miss_visitor, meet_visitor);
}
}
}
pub fn pos_to_coordinate(&self, range_type: VisionLevelType, pos: &Vector2) -> Coordinate {
let grid_width = Self::get_grid_width(range_type);
Coordinate {

View file

@ -0,0 +1,62 @@
use std::{cell::RefCell, rc::Rc};
use proto::ProtEntityType;
use crate::entity::Entity;
pub struct Visitor {
visitor_type: VisitorType,
visitor_entity: Rc<RefCell<dyn Entity>>,
entity_vec: Vec<Rc<RefCell<dyn Entity>>>,
}
pub enum VisitorType {
Entity,
// Gather,
// Authority,
}
impl Visitor {
pub fn new(visitor_type: VisitorType, entity: Rc<RefCell<dyn Entity>>) -> Self {
Self {
visitor_type,
visitor_entity: entity,
entity_vec: Vec::new(),
}
}
pub fn visit_entity(&mut self, entity: &Rc<RefCell<dyn Entity>>) {
if self.can_add_entity(entity) {
self.entity_vec.push(entity.clone());
}
}
pub fn get_entity_vec(&self) -> &Vec<Rc<RefCell<dyn Entity>>> {
&self.entity_vec
}
fn can_add_entity(&self, entity: &Rc<RefCell<dyn Entity>>) -> bool {
match self.visitor_type {
VisitorType::Entity => {
let visitor_entity_type = self.visitor_entity.borrow().get_entity_type();
let entity_type = entity.borrow().get_entity_type();
if entity_type == ProtEntityType::ProtEntityEyePoint {
if visitor_entity_type != ProtEntityType::ProtEntityAvatar
&& visitor_entity_type != ProtEntityType::ProtEntityEyePoint
{
return true;
}
}
if entity_type > ProtEntityType::ProtEntityEyePoint
|| entity_type == ProtEntityType::ProtEntityWeather
{
return false;
}
}
}
entity.borrow().entity_id() != self.visitor_entity.borrow().entity_id()
}
}

View file

@ -34,6 +34,14 @@ impl Vector3 {
}
}
pub fn from_client(client: &Vector) -> Self {
Self {
x: client.x,
y: client.y,
z: client.z,
}
}
pub fn to_bin(&self) -> VectorBin {
VectorBin {
x: self.x,

File diff suppressed because it is too large Load diff