optimize des more

This commit is contained in:
bgkillas 2025-03-09 21:08:40 -04:00
parent 3dcd6b4ec8
commit bf71bde27f
4 changed files with 105 additions and 71 deletions

View file

@ -12,8 +12,8 @@ use interest::InterestTracker;
use noita_api::raw::game_get_frame_num; use noita_api::raw::game_get_frame_num;
use noita_api::serialize::serialize_entity; use noita_api::serialize::serialize_entity;
use noita_api::{ use noita_api::{
DamageModelComponent, EntityID, LuaComponent, PositionSeedComponent, ProjectileComponent, DamageModelComponent, EntityID, ItemCostComponent, LuaComponent, PositionSeedComponent,
VariableStorageComponent, ProjectileComponent, VariableStorageComponent,
}; };
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use shared::des::DesToProxy::UpdatePositions; use shared::des::DesToProxy::UpdatePositions;
@ -55,15 +55,14 @@ pub(crate) struct EntitySync {
delta_sync_rate: usize, delta_sync_rate: usize,
kill_later: Vec<(EntityID, Option<PeerId>)>, kill_later: Vec<(EntityID, Option<PeerId>)>,
timer: u128, timer: u128,
to_track: Vec<EntityID>,
} }
impl EntitySync { impl EntitySync {
/*pub(crate) fn has_gid(&self, gid: Gid) -> bool { /*pub(crate) fn has_gid(&self, gid: Gid) -> bool {
self.local_diff_model.has_gid(gid) || self.remote_models.values().any(|r| r.has_gid(gid)) self.local_diff_model.has_gid(gid) || self.remote_models.values().any(|r| r.has_gid(gid))
}*/ }*/
pub(crate) fn track_entity(&mut self, ent: EntityID) { pub(crate) fn track_entity(&mut self, ent: EntityID) {
let _ = self let _ = self.local_diff_model.track_and_upload_entity(ent);
.local_diff_model
.track_and_upload_entity(ent, Gid(rand::random()));
} }
pub(crate) fn notrack_entity(&mut self, ent: EntityID) { pub(crate) fn notrack_entity(&mut self, ent: EntityID) {
self.dont_track.insert(ent); self.dont_track.insert(ent);
@ -101,6 +100,7 @@ impl Default for EntitySync {
delta_sync_rate: 0, delta_sync_rate: 0,
kill_later: Vec::new(), kill_later: Vec::new(),
timer: 0, timer: 0,
to_track: Vec::new(),
} }
} }
} }
@ -413,8 +413,7 @@ impl EntitySync {
let entity = entity.ok_or_eyre("Passed entity 0 into cross call")?; let entity = entity.ok_or_eyre("Passed entity 0 into cross call")?;
// It might be already tracked in case of tablet telekinesis, no need to track it again. // It might be already tracked in case of tablet telekinesis, no need to track it again.
if !self.local_diff_model.is_entity_tracked(entity) { if !self.local_diff_model.is_entity_tracked(entity) {
self.local_diff_model self.local_diff_model.track_and_upload_entity(entity)?;
.track_and_upload_entity(entity, Gid(rand::random()))?;
} }
Ok(()) Ok(())
} }
@ -495,8 +494,13 @@ impl Module for EntitySync {
return Ok(()); return Ok(());
} }
if self.should_be_tracked(entity)? { if self.should_be_tracked(entity)? {
let gid = Gid(rand::random()); if let Some(cost) = entity.try_get_first_component::<ItemCostComponent>(None)? {
self.local_diff_model.track_and_upload_entity(entity, gid)?; if cost.stealable()? {
cost.set_stealable(false)?;
entity.get_var_or_default("ew_was_stealable")?;
}
}
self.to_track.push(entity);
} }
Ok(()) Ok(())
} }
@ -535,12 +539,19 @@ impl Module for EntitySync {
self.look_current_entity = EntityID::max_in_use()?; self.look_current_entity = EntityID::max_in_use()?;
self.local_diff_model.enable_later()?; self.local_diff_model.enable_later()?;
self.local_diff_model.phys_later()?; self.local_diff_model.phys_later()?;
self.local_diff_model.update_pending_authority()?; let t = self.local_diff_model.update_pending_authority()?;
for ent in self.look_current_entity.0.get() + 1..=EntityID::max_in_use()?.0.get() { for ent in self.look_current_entity.0.get() + 1..=EntityID::max_in_use()?.0.get() {
if let Ok(ent) = EntityID::try_from(ent) { if let Ok(ent) = EntityID::try_from(ent) {
self.on_new_entity(ent, false)?; self.on_new_entity(ent, false)?;
} }
} }
let start = std::time::Instant::now();
while let Some(entity) = self.to_track.pop() {
self.local_diff_model.track_and_upload_entity(entity)?;
if start.elapsed().as_micros() + t > 2000 {
break;
}
}
let tmr = std::time::Instant::now(); let tmr = std::time::Instant::now();
{ {
let (diff, dead) = self let (diff, dead) = self
@ -554,63 +565,63 @@ impl Module for EntitySync {
let new_intersects = self.interest_tracker.got_any_new_interested(); let new_intersects = self.interest_tracker.got_any_new_interested();
if !new_intersects.is_empty() { if !new_intersects.is_empty() {
let init = self.local_diff_model.make_init(); let init = self.local_diff_model.make_init();
for peer in &new_intersects { send_remotedes(
send_remotedes( ctx,
ctx, true,
true, Destination::Peers(new_intersects.clone()),
Destination::Peer(*peer), RemoteDes::EntityUpdate(init),
RemoteDes::EntityUpdate(init.clone()), )?;
)?;
}
} }
// FIXME (perf): allow a Destination that can send to several peers at once, to prevent cloning and stuff. let proj = std::mem::take(&mut self.pending_fired_projectiles);
for peer in self.interest_tracker.iter_interested() { if !proj.is_empty() {
if !self.pending_fired_projectiles.is_empty() { send_remotedes(
send_remotedes( ctx,
ctx, true,
true, Destination::Peers(self.interest_tracker.iter_interested().collect()),
Destination::Peer(peer), RemoteDes::Projectiles(proj),
RemoteDes::Projectiles(self.pending_fired_projectiles.clone()), )?;
)?;
}
if new_intersects.contains(&peer) {
continue;
}
if !diff.is_empty() {
send_remotedes(
ctx,
true,
Destination::Peer(peer),
RemoteDes::EntityUpdate(diff.clone()),
)?;
}
} }
for peer in ctx.player_map.clone().left_values() { if !diff.is_empty() {
if !self.interest_tracker.contains(*peer) send_remotedes(
&& *peer != my_peer_id() ctx,
&& !dead.is_empty() true,
{ Destination::Peers(
send_remotedes( self.interest_tracker
ctx, .iter_interested()
true, .filter(|p| !new_intersects.contains(p))
Destination::Peer(*peer), .collect(),
RemoteDes::DeadEntities(dead.clone()), ),
)?; RemoteDes::EntityUpdate(diff),
} )?;
}
if !dead.is_empty() {
send_remotedes(
ctx,
true,
Destination::Peers(
ctx.player_map
.left_values()
.filter(|p| {
!self.interest_tracker.contains(**p)
&& **p != my_peer_id()
&& !dead.is_empty()
})
.cloned()
.collect(),
),
RemoteDes::DeadEntities(dead),
)?;
} }
Arc::make_mut(&mut self.pending_fired_projectiles).clear();
if frame_num.saturating_sub(self.delta_sync_rate) % self.real_sync_rate if frame_num.saturating_sub(self.delta_sync_rate) % self.real_sync_rate
== self.real_sync_rate - 1 == self.real_sync_rate - 1
{ {
let lids = self.local_diff_model.get_lids(); let lids = self.local_diff_model.get_lids();
for peer in self.interest_tracker.iter_interested() { send_remotedes(
send_remotedes( ctx,
ctx, true,
true, Destination::Peers(self.interest_tracker.iter_interested().collect()),
Destination::Peer(peer), RemoteDes::AllEntities(lids),
RemoteDes::AllEntities(lids.clone()), )?;
)?
}
} }
} }
if frame_num > 120 { if frame_num > 120 {
@ -675,7 +686,7 @@ impl Module for EntitySync {
} }
let ms = tmr.elapsed().as_micros(); let ms = tmr.elapsed().as_micros();
self.timer += ms; self.timer += ms + start.elapsed().as_micros() + t;
if frame_num.saturating_sub(self.delta_sync_rate) % self.real_sync_rate if frame_num.saturating_sub(self.delta_sync_rate) % self.real_sync_rate
== self.real_sync_rate - 1 == self.real_sync_rate - 1
{ {

View file

@ -597,7 +597,7 @@ impl LocalDiffModelTracker {
if n == 1 { if n == 1 {
if let Some(cost) = entity.try_get_first_component::<ItemCostComponent>(None)? { if let Some(cost) = entity.try_get_first_component::<ItemCostComponent>(None)? {
let (cx, cy) = noita_api::raw::game_get_camera_pos()?; let (cx, cy) = noita_api::raw::game_get_camera_pos()?;
if (cx as f32 - x).powi(2) + (cy as f32 - y).powi(2) < 512.0 * 512.0 { if (cx as f32 - x).powi(2) + (cy as f32 - y).powi(2) < 256.0 * 256.0 {
cost.set_stealable(true)?; cost.set_stealable(true)?;
entity.remove_component(*var)?; entity.remove_component(*var)?;
} }
@ -607,7 +607,7 @@ impl LocalDiffModelTracker {
vel.set_air_friction(0.55)?; vel.set_air_friction(0.55)?;
} }
} else if n == 0 { } else if n == 0 {
var.set_value_int(16)?; var.set_value_int(32)?;
if let Some(vel) = entity.try_get_first_component::<VelocityComponent>(None)? { if let Some(vel) = entity.try_get_first_component::<VelocityComponent>(None)? {
vel.set_gravity_y(0.0)?; vel.set_gravity_y(0.0)?;
vel.set_air_friction(10.0)?; vel.set_air_friction(10.0)?;
@ -912,11 +912,8 @@ impl LocalDiffModel {
Ok(lid) Ok(lid)
} }
pub(crate) fn track_and_upload_entity( pub(crate) fn track_and_upload_entity(&mut self, entity: EntityID) -> eyre::Result<()> {
&mut self, let gid = Gid(rand::random());
entity: EntityID,
gid: Gid,
) -> eyre::Result<()> {
let lid = self.track_entity(entity, gid)?; let lid = self.track_entity(entity, gid)?;
self.upload.insert(lid); self.upload.insert(lid);
Ok(()) Ok(())
@ -964,7 +961,7 @@ impl LocalDiffModel {
Ok(()) Ok(())
} }
pub(crate) fn update_pending_authority(&mut self) -> eyre::Result<()> { pub(crate) fn update_pending_authority(&mut self) -> eyre::Result<u128> {
let start = Instant::now(); let start = Instant::now();
while let Some(entity_data) = self.tracker.pending_authority.pop() { while let Some(entity_data) = self.tracker.pending_authority.pop() {
let entity = spawn_entity_by_data( let entity = spawn_entity_by_data(
@ -1033,11 +1030,11 @@ impl LocalDiffModel {
self.dont_upload.insert(lid); self.dont_upload.insert(lid);
// Don't handle too much in one frame to avoid stutters. // Don't handle too much in one frame to avoid stutters.
if start.elapsed().as_millis() > 2 { if start.elapsed().as_micros() > 2000 {
break; break;
} }
} }
Ok(()) Ok(start.elapsed().as_micros())
} }
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]

View file

@ -881,6 +881,11 @@ impl NetManager {
fn do_message_request(&self, request: impl Into<MessageRequest<NetMsg>>) { fn do_message_request(&self, request: impl Into<MessageRequest<NetMsg>>) {
let request: MessageRequest<NetMsg> = request.into(); let request: MessageRequest<NetMsg> = request.into();
match request.dst { match request.dst {
Destination::Peers(peers) => {
for peer in peers {
self.send(peer, &request.msg, request.reliability);
}
}
Destination::Peer(peer) => { Destination::Peer(peer) => {
self.send(peer, &request.msg, request.reliability); self.send(peer, &request.msg, request.reliability);
} }
@ -1128,6 +1133,21 @@ impl NetManager {
let destination = destination.convert::<OmniPeerId>(); let destination = destination.convert::<OmniPeerId>();
let reliability = Reliability::from_reliability_bool(reliable); let reliability = Reliability::from_reliability_bool(reliable);
match destination { match destination {
Destination::Peers(peers) => {
if !peers.is_empty() {
if peers.len() == 1 {
self.send(peers[0], &NetMsg::RemoteMsg(message), reliability)
} else {
for peer in peers {
self.send(
peer,
&NetMsg::RemoteMsg(message.clone()),
reliability,
)
}
}
}
}
Destination::Peer(peer) => { Destination::Peer(peer) => {
self.send(peer, &NetMsg::RemoteMsg(message), reliability) self.send(peer, &NetMsg::RemoteMsg(message), reliability)
} }

View file

@ -104,6 +104,7 @@ impl PeerId {
#[derive(Encode, Decode, Debug, PartialEq, Eq)] #[derive(Encode, Decode, Debug, PartialEq, Eq)]
pub enum Destination<PeerType> { pub enum Destination<PeerType> {
Peers(Vec<PeerType>),
Peer(PeerType), Peer(PeerType),
Host, Host,
Broadcast, Broadcast,
@ -113,9 +114,14 @@ impl<T> Destination<T> {
pub fn convert<A>(self) -> Destination<A> pub fn convert<A>(self) -> Destination<A>
where where
A: From<T>, A: From<T>,
T: Copy,
T: Clone,
{ {
match self { match self {
Destination::Peer(p) => Destination::Peer(p.into()), Destination::Peer(p) => Destination::Peer(p.into()),
Destination::Peers(p) => {
Destination::Peers(p.iter().cloned().map(|p| p.into()).collect())
}
Destination::Host => Destination::Host, Destination::Host => Destination::Host,
Destination::Broadcast => Destination::Broadcast, Destination::Broadcast => Destination::Broadcast,
} }