answer the client when it asks for the sector state
RequestSectorStateMessage, 12903, one vint of client tick, sent through sendUdpMessage and so arriving on tcp like everything else. we were ignoring it. it matters because of how the client builds models. the factory marks a freshly created object at [obj+0x14], and only for those does LogicGameObjectManager::decode call the listener at [mgr+0x28] that builds the visual. every later snapshot matches the same object by global id and reuses it, so the flag is never set again - an object that was decoded before the battle screen installed its listener stays invisible for the whole battle while still walking and fighting. that is the tower archers and the invisible units; the knight shows because the client creates that one itself, after the screen is up. the client asks for the state when it is ready, and now it gets it.
This commit is contained in:
parent
e9894d9838
commit
8699a6884d
7 changed files with 46 additions and 1 deletions
|
|
@ -114,7 +114,7 @@ impl BattleSession {
|
|||
}
|
||||
})
|
||||
}
|
||||
fn snapshot_message(&mut self) -> Option<WireMessage> {
|
||||
pub fn snapshot_message(&mut self) -> Option<WireMessage> {
|
||||
let snapshot = self.mode.snapshot().ok()?;
|
||||
let report = verify_snapshot(&snapshot);
|
||||
let unit = self
|
||||
|
|
@ -344,6 +344,11 @@ impl BattleRegistry {
|
|||
session.push_outbound(message);
|
||||
}
|
||||
}
|
||||
pub async fn resend(&self, account: AccountRef) -> Option<WireMessage> {
|
||||
let handle = self.session(account).await?;
|
||||
let mut session = handle.lock().await;
|
||||
session.snapshot_message()
|
||||
}
|
||||
pub async fn send(&self, account: AccountRef, message: WireMessage) {
|
||||
if let Some(handle) = self.session(account).await {
|
||||
handle.lock().await.push_outbound(message);
|
||||
|
|
|
|||
|
|
@ -481,6 +481,9 @@ impl GameApi for GameService {
|
|||
self.running_battles.answer_emote(account).await;
|
||||
Ok(())
|
||||
}
|
||||
async fn request_sector_state(&self, account: AccountRef) -> RpcResult<Vec<WireMessage>> {
|
||||
Ok(self.running_battles.resend(account).await.into_iter().collect())
|
||||
}
|
||||
async fn sector_command(&self, account: AccountRef, payload: Vec<u8>) -> RpcResult<()> {
|
||||
let Ok(sector) = SectorCommandMessage::from_bytes(&payload) else {
|
||||
return Ok(());
|
||||
|
|
@ -567,6 +570,9 @@ impl RpcService for GameService {
|
|||
GameRequest::BattleTick { account } => Ok(GameResponse::messages(
|
||||
self.battle_tick(account).await?,
|
||||
)),
|
||||
GameRequest::RequestSectorState { account } => Ok(GameResponse::messages(
|
||||
self.request_sector_state(account).await?,
|
||||
)),
|
||||
GameRequest::SectorCommand { account, payload } => {
|
||||
self.sector_command(account, payload).await?;
|
||||
Ok(GameResponse::Empty)
|
||||
|
|
|
|||
|
|
@ -147,6 +147,13 @@ impl GameApi for RemoteGame {
|
|||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
async fn request_sector_state(&self, account: AccountRef) -> RpcResult<Vec<WireMessage>> {
|
||||
Ok(self
|
||||
.client
|
||||
.call(&GameRequest::RequestSectorState { account })
|
||||
.await?
|
||||
.into_messages())
|
||||
}
|
||||
async fn disconnect(&self, account: AccountRef) -> RpcResult<()> {
|
||||
self.client
|
||||
.call(&GameRequest::Disconnect { account })
|
||||
|
|
|
|||
|
|
@ -99,6 +99,19 @@ impl MessageManager {
|
|||
self.stop_battle_ticker();
|
||||
self.push_home(HomeRequestKind::GoHome).await
|
||||
}
|
||||
message_type::REQUEST_SECTOR_STATE => {
|
||||
let Some(account) = self.account else {
|
||||
return Ok(());
|
||||
};
|
||||
tracing::info!(peer = %self.peer, "client asked for the sector state");
|
||||
match self.backends.game.request_sector_state(account).await {
|
||||
Ok(replies) => self.push_wire_messages(replies).await?,
|
||||
Err(error) => {
|
||||
tracing::warn!(peer = %self.peer, %error, "could not serve the sector state")
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
message_type::SECTOR_COMMAND => {
|
||||
let Some(account) = self.account else {
|
||||
return Ok(());
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ mod matchmake;
|
|||
mod out_of_sync;
|
||||
mod own_home_data;
|
||||
mod battle_event;
|
||||
mod request_sector_state;
|
||||
mod sector_command;
|
||||
mod sector_state;
|
||||
mod server_error;
|
||||
|
|
@ -35,6 +36,7 @@ pub use matchmake::{CancelMatchmakeDoneMessage, HomeLogicStoppedMessage, StopHom
|
|||
pub use out_of_sync::OutOfSyncMessage;
|
||||
pub use own_home_data::OwnHomeDataMessage;
|
||||
pub use battle_event::{BattleEventMessage, SendBattleEventMessage};
|
||||
pub use request_sector_state::RequestSectorStateMessage;
|
||||
pub use sector_command::SectorCommandMessage;
|
||||
pub use sector_state::SectorStateMessage;
|
||||
pub use server_error::ServerErrorMessage;
|
||||
|
|
@ -53,6 +55,7 @@ pub mod message_type {
|
|||
pub const START_MISSION: u16 = 14104;
|
||||
pub const HOME_LOGIC_STOPPED: u16 = 14105;
|
||||
pub const CANCEL_MATCHMAKE: u16 = 14107;
|
||||
pub const REQUEST_SECTOR_STATE: u16 = 12903;
|
||||
pub const SECTOR_COMMAND: u16 = 12904;
|
||||
pub const SEND_BATTLE_EVENT: u16 = 12951;
|
||||
pub const BATTLE_EVENT: u16 = 22952;
|
||||
|
|
|
|||
7
crates/logic/src/messages/request_sector_state.rs
Normal file
7
crates/logic/src/messages/request_sector_state.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
use titan::Message;
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Message)]
|
||||
#[message(id = 12903, direction = "client", name = "RequestSectorStateMessage")]
|
||||
pub struct RequestSectorStateMessage {
|
||||
#[codec(vint)]
|
||||
pub client_tick: i32,
|
||||
}
|
||||
|
|
@ -56,6 +56,9 @@ pub enum GameRequest {
|
|||
BattleTick {
|
||||
account: AccountRef,
|
||||
},
|
||||
RequestSectorState {
|
||||
account: AccountRef,
|
||||
},
|
||||
SectorCommand {
|
||||
account: AccountRef,
|
||||
#[serde(with = "crate::base64::serde_bytes")]
|
||||
|
|
@ -117,5 +120,6 @@ pub trait GameApi: Send + Sync + 'static {
|
|||
async fn battle_event(&self, account: AccountRef, payload: Vec<u8>) -> RpcResult<()>;
|
||||
async fn cancel_matchmake(&self, account: AccountRef) -> RpcResult<()>;
|
||||
async fn sector_command(&self, account: AccountRef, payload: Vec<u8>) -> RpcResult<()>;
|
||||
async fn request_sector_state(&self, account: AccountRef) -> RpcResult<Vec<WireMessage>>;
|
||||
async fn disconnect(&self, account: AccountRef) -> RpcResult<()>;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue