trigger-rs/crates/game-server/src/session/mod.rs
2025-02-21 14:03:43 +03:00

280 lines
8.3 KiB
Rust

use std::{
collections::HashMap,
sync::{Mutex, RwLock},
};
use tracing::warn;
use trigger_database::entity::scene_info;
use trigger_logic::scene::ESceneType;
use trigger_protocol::util::ProtocolUnit;
use trigger_sv::{
message::{
AvailableServerProtocolMessage, BindClientSessionMessage, ChangeGameStateMessage,
ForwardClientProtocolMessage, GameStateData, UnbindClientSessionMessage,
},
net::{ServerNetworkManager, ServerType},
};
use crate::logic::{scene_util, NapPlayer};
pub mod message;
pub struct GameSession {
network_mgr: &'static ServerNetworkManager,
bound_server_map: RwLock<HashMap<ServerType, u32>>,
pub id: u64,
pub player_uid: u32,
pub current_state: Mutex<Option<SessionGameStateInfo>>,
}
pub struct SessionGameStateInfo {
pub scene_uid: i64,
pub state_server: ServerType,
pub prepared_game_state_data: Option<GameStateData>,
pub state_confirm_response: Option<AvailableServerProtocolMessage>,
}
impl GameSession {
pub fn new(
network_mgr: &'static ServerNetworkManager,
id: u64,
player_uid: u32,
gate_id: u32,
) -> Self {
Self {
network_mgr,
bound_server_map: RwLock::new(HashMap::from([(ServerType::GateServer, gate_id)])),
id,
player_uid,
current_state: Mutex::new(None),
}
}
pub async fn change_game_state(
&self,
ack_request_id: u32,
response: impl Into<ProtocolUnit>,
game_state_data: GameStateData,
scene: &scene_info::Model,
player: &mut NapPlayer,
set_back_scene: bool,
) {
self.unload_current_game_state().await;
let scene_type = ESceneType::try_from(scene.scene_type).expect("invalid scene type");
let state_server = scene_util::get_scene_logic_simulation_server_type(scene_type)
.unwrap_or_else(|| todo!("scene type {scene_type:?}"));
let response = AvailableServerProtocolMessage {
session_id: self.id,
ack_request_id,
notifies: Vec::new(),
response: Some(response.into()),
};
*self.current_state.lock().unwrap() = Some(SessionGameStateInfo {
scene_uid: scene.scene_uid,
state_server,
prepared_game_state_data: Some(game_state_data),
state_confirm_response: Some(response),
});
if set_back_scene {
player.scene_model.push_current_scene(&scene).await;
} else {
player.scene_model.set_current_scene(&scene).await;
}
self.bind_server(state_server, 0).await;
}
pub async fn on_game_state_loaded(&self, notifies: Vec<ProtocolUnit>) {
if let Some(mut response) = self.get_awaiting_state_response() {
response.notifies = notifies;
self.network_mgr
.send_to(ServerType::GateServer, 0, response)
.await;
}
}
fn get_awaiting_state_response(&self) -> Option<AvailableServerProtocolMessage> {
self.current_state
.lock()
.unwrap()
.as_mut()
.map(|state| state.state_confirm_response.take())
.flatten()
}
pub fn get_cur_scene_uid(&self) -> Option<i64> {
self.current_state
.lock()
.unwrap()
.as_ref()
.map(|state| state.scene_uid)
}
pub fn get_cur_state_server(&self) -> Option<ServerType> {
self.current_state
.lock()
.unwrap()
.as_ref()
.map(|state| state.state_server)
}
async fn unload_current_game_state(&self) {
if let Some(server_type) = self.get_cur_state_server() {
self.unbind_server(server_type).await;
}
}
async fn on_game_state_server_bound(&self) {
if let Some(state_server) = self.get_cur_state_server() {
if let Some(message) = self.build_change_game_state_message() {
self.network_mgr
.send_to(
state_server,
self.get_bound_server_of_type(state_server).unwrap(),
message,
)
.await;
}
}
}
fn build_change_game_state_message(&self) -> Option<ChangeGameStateMessage> {
let mut current_state = self.current_state.lock().unwrap();
let Some(state) = current_state.as_mut() else {
return None;
};
let data = match state.prepared_game_state_data.take() {
Some(data) => data,
None => {
panic!(
"simulation server {:?} is bound, but game state data is not set!",
state.state_server
)
}
};
Some(ChangeGameStateMessage {
session_id: self.id,
scene_uid: state.scene_uid,
data,
})
}
pub async fn bind_server(&self, server_type: ServerType, server_id: u32) {
self.network_mgr
.send_to(
server_type,
server_id,
BindClientSessionMessage {
session_id: self.id,
player_uid: self.player_uid,
},
)
.await;
}
pub async fn unbind_server(&self, server_type: ServerType) {
if let Some(server_id) = self.get_bound_server_of_type(server_type) {
self.bound_server_map.write().unwrap().remove(&server_type);
self.network_mgr
.send_to(
server_type,
server_id,
UnbindClientSessionMessage {
session_id: self.id,
},
)
.await;
}
}
pub async fn unbind_all_servers(&self, unbind_gateway: bool) {
let server_map = std::mem::take(&mut *self.bound_server_map.write().unwrap());
for (server_type, server_id) in server_map.into_iter() {
if server_type != ServerType::GateServer || unbind_gateway {
self.network_mgr
.send_to(
server_type,
server_id,
UnbindClientSessionMessage {
session_id: self.id,
},
)
.await;
}
}
}
pub async fn on_server_bound(&self, server_type: ServerType, server_id: u32) {
self.bound_server_map
.write()
.unwrap()
.insert(server_type, server_id);
if let Some(state_server) = self.get_cur_state_server() {
if state_server == server_type {
self.on_game_state_server_bound().await;
}
}
}
pub async fn forward_client_message<Message: Into<ProtocolUnit>>(
&self,
message: Message,
destination: ServerType,
request_id: u32,
) {
let server_id = self
.bound_server_map
.read()
.unwrap()
.get(&destination)
.copied();
if let Some(server_id) = server_id {
self.network_mgr
.send_to(
destination,
server_id,
ForwardClientProtocolMessage {
session_id: self.id,
request_id,
message: message.into(),
},
)
.await;
} else {
warn!(
"forward_client_message: server {:?} is not bound! session_id: {}, request_id: {}",
destination, self.id, request_id
);
}
}
pub fn calc_offline_verify_value(&self, login_random: u32) -> u32 {
5_u32
.wrapping_mul(rotate_right(
self.player_uid ^ login_random,
2 * (self.player_uid & 1) + 17,
))
.wrapping_sub(430675100)
}
pub fn get_bound_server_of_type(&self, server_type: ServerType) -> Option<u32> {
self.bound_server_map
.read()
.unwrap()
.get(&server_type)
.copied()
}
}
#[inline(always)]
const fn rotate_right(value: u32, count: u32) -> u32 {
(value >> count) | (value << (32 - count))
}