From b4a4b7a4092a03c1519a7779a2f7383e856fc043 Mon Sep 17 00:00:00 2001 From: bgkillas Date: Mon, 20 Jan 2025 21:17:21 -0500 Subject: [PATCH] dont allow duping items, fix poly enemies --- ewext/Cargo.lock | 7 +++ ewext/Cargo.toml | 2 +- ewext/noita_api/Cargo.lock | 7 +++ ewext/noita_api/Cargo.toml | 3 +- ewext/noita_api/src/lib.rs | 51 ++++++++++++++++++++- ewext/src/modules/entity_sync.rs | 29 +++++++++++- ewext/src/modules/entity_sync/diff_model.rs | 13 ++++-- noita-proxy/src/net/des.rs | 11 +++-- shared/src/des.rs | 5 +- 9 files changed, 114 insertions(+), 14 deletions(-) diff --git a/ewext/Cargo.lock b/ewext/Cargo.lock index e38243db..b402bafc 100644 --- a/ewext/Cargo.lock +++ b/ewext/Cargo.lock @@ -38,6 +38,12 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bimap" version = "0.6.3" @@ -203,6 +209,7 @@ dependencies = [ name = "noita_api" version = "0.1.0" dependencies = [ + "base64", "eyre", "libloading", "noita_api_macro", diff --git a/ewext/Cargo.toml b/ewext/Cargo.toml index 5b8154f3..cb86900f 100644 --- a/ewext/Cargo.toml +++ b/ewext/Cargo.toml @@ -28,4 +28,4 @@ bimap = "0.6.3" #enables cross-compilation on older systems (for example, when compiling on ubuntu 20.04) #due to unresolved bug in rust toolchain #https://github.com/rust-lang/rust/issues/79609 -pre2204 = [] +pre2204 = [] \ No newline at end of file diff --git a/ewext/noita_api/Cargo.lock b/ewext/noita_api/Cargo.lock index 9a510e34..b728c4d4 100644 --- a/ewext/noita_api/Cargo.lock +++ b/ewext/noita_api/Cargo.lock @@ -8,6 +8,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bitcode" version = "0.6.3" @@ -98,6 +104,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" name = "noita_api" version = "0.1.0" dependencies = [ + "base64", "eyre", "libloading", "noita_api_macro", diff --git a/ewext/noita_api/Cargo.toml b/ewext/noita_api/Cargo.toml index 9961cdeb..3ac112f1 100644 --- a/ewext/noita_api/Cargo.toml +++ b/ewext/noita_api/Cargo.toml @@ -8,4 +8,5 @@ eyre = "0.6.12" libloading = "0.8.5" noita_api_macro = {path = "../noita_api_macro"} shared = {path = "../../shared"} -strum = "0.26.3" \ No newline at end of file +strum = "0.26.3" +base64 = "0.22.1" \ No newline at end of file diff --git a/ewext/noita_api/src/lib.rs b/ewext/noita_api/src/lib.rs index 3434ecdd..4d57c44d 100644 --- a/ewext/noita_api/src/lib.rs +++ b/ewext/noita_api/src/lib.rs @@ -1,6 +1,8 @@ use crate::lua::{LuaGetValue, LuaPutValue}; use crate::serialize::deserialize_entity; +use base64::Engine; use eyre::{eyre, Context, OptionExt}; +use shared::des::Gid; use shared::{GameEffectData, GameEffectEnum}; use std::collections::HashMap; use std::{ @@ -13,7 +15,6 @@ pub mod serialize; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct EntityID(pub NonZero); - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ComponentID(pub NonZero); @@ -42,6 +43,54 @@ impl EntityID { raw::entity_get_name(self).map(|s| s.to_string()) } + pub fn handle_poly(&self) -> Option { + for ent in self.children(None) { + if let Ok(Some(effect)) = + ent.try_get_first_component_including_disabled::(None) + { + let name = effect.effect().unwrap(); + match name { + GameEffectEnum::Polymorph + | GameEffectEnum::PolymorphRandom + | GameEffectEnum::PolymorphUnstable + | GameEffectEnum::PolymorphCessation => { + if let Ok(data) = + raw::component_get_value::>(effect.0, "mSerializedData") + { + if data.is_empty() { + return None; + } + if let Ok(data) = + base64::engine::general_purpose::STANDARD.decode(data.to_string()) + { + let data = String::from_utf8_lossy(&data) + .chars() + .filter(|c| c.is_ascii_alphanumeric()) + .collect::(); + let mut data = data.split("VariableStorageComponentewgidlid"); + let _ = data.next(); + if let Some(data) = data.next() { + let mut gid = String::new(); + for c in data.chars() { + if c.is_numeric() { + gid.push(c) + } else { + break; + } + } + return Some(Gid(gid.parse::().ok()?)); + } + } + } + return None; + } + _ => {} + } + } + } + None + } + pub fn add_tag(self, tag: impl AsRef) -> eyre::Result<()> { raw::entity_add_tag(self, tag.as_ref().into()) } diff --git a/ewext/src/modules/entity_sync.rs b/ewext/src/modules/entity_sync.rs index 7b5b3cf6..87f4f9e4 100644 --- a/ewext/src/modules/entity_sync.rs +++ b/ewext/src/modules/entity_sync.rs @@ -11,7 +11,7 @@ use diff_model::{entity_is_item, LocalDiffModel, RemoteDiffModel, DES_TAG}; use eyre::{Context, OptionExt}; use interest::InterestTracker; use noita_api::serialize::serialize_entity; -use noita_api::{EntityID, ProjectileComponent}; +use noita_api::{game_print, EntityID, ProjectileComponent, VariableStorageComponent}; use rustc_hash::{FxHashMap, FxHashSet}; use shared::{ des::{ @@ -47,6 +47,7 @@ pub(crate) struct EntitySync { pending_fired_projectiles: Arc>, dont_kill: FxHashSet, + dont_kill_by_gid: FxHashSet, dont_track: FxHashSet, } impl EntitySync { @@ -78,6 +79,7 @@ impl Default for EntitySync { pending_fired_projectiles: Vec::new().into(), dont_kill: Default::default(), + dont_kill_by_gid: Default::default(), dont_track: Default::default(), } } @@ -145,7 +147,27 @@ impl EntitySync { if !entity.is_alive() || self.dont_track.remove(&entity) { continue; } - if entity.has_tag(DES_TAG) && !self.dont_kill.remove(&entity) { + if let Some(gid) = entity.handle_poly() { + game_print(gid.0.to_string()); + game_print(self.local_diff_model.find_by_gid(gid).is_some().to_string()); + self.dont_kill_by_gid.insert(gid); + } + if entity.has_tag(DES_TAG) + && !self.dont_kill.remove(&entity) + && entity + .iter_all_components_of_type_including_disabled::( + None, + )? + .find(|var| var.name().unwrap_or("".into()) == "ew_gid_lid") + .map(|var| { + if let Ok(n) = var.value_string().unwrap().parse::() { + !self.dont_kill_by_gid.remove(&Gid(n)) + } else { + true + } + }) + .unwrap_or(true) + { entity.kill(); continue; } @@ -170,6 +192,9 @@ impl EntitySync { remote.remove_entities() } } + shared::des::ProxyToDes::DeleteEntity(entity) => { + EntityID(entity).kill(); + } } } diff --git a/ewext/src/modules/entity_sync/diff_model.rs b/ewext/src/modules/entity_sync/diff_model.rs index 38ddbe1d..a42cd0ef 100644 --- a/ewext/src/modules/entity_sync/diff_model.rs +++ b/ewext/src/modules/entity_sync/diff_model.rs @@ -134,7 +134,7 @@ impl LocalDiffModelTracker { let entity = self.entity_by_lid(lid)?; if !entity.is_alive() { - self.untrack_entity(ctx, gid, lid)?; + self.untrack_entity(ctx, gid, lid, None)?; return Ok(()); } let item_and_was_picked = info.kind == EntityKind::Item && item_in_inventory(entity)?; @@ -362,10 +362,11 @@ impl LocalDiffModelTracker { ctx: &mut ModuleCtx<'_>, gid: Gid, lid: Lid, + ent: Option>, ) -> Result<(), eyre::Error> { self.pending_removal.push(lid); ctx.net.send(&NoitaOutbound::DesToProxy( - shared::des::DesToProxy::DeleteEntity(gid), + shared::des::DesToProxy::DeleteEntity(gid, ent), ))?; Ok(()) @@ -378,7 +379,7 @@ impl LocalDiffModelTracker { lid: Lid, entity: EntityID, ) -> Result<(), eyre::Error> { - self.untrack_entity(ctx, gid, lid)?; + self.untrack_entity(ctx, gid, lid, Some(entity.0))?; entity.remove_tag(DES_TAG)?; with_entity_scripts(entity, |luac| { luac.set_script_throw_item( @@ -596,7 +597,7 @@ impl LocalDiffModel { .wrap_err("Failed to update local entity") { print_error(error)?; - self.tracker.untrack_entity(ctx, *gid, lid)?; + self.tracker.untrack_entity(ctx, *gid, lid, None)?; } } Ok(()) @@ -1601,6 +1602,10 @@ fn _safe_wandkill(entity: EntityID) -> eyre::Result<()> { lc.set_script_source_file( "mods/quant.ew/files/system/entity_sync_helper/scripts/killself.lua".into(), )?; + entity.set_component_enabled(*lc, true)?; + lc.add_tag("enabled_in_inventory")?; + lc.add_tag("enabled_in_world")?; + lc.add_tag("enabled_in_hand")?; lc.set_execute_on_added(false)?; lc.set_m_next_execution_time(noita_api::raw::game_get_frame_num()? + 1)?; Ok(()) diff --git a/noita-proxy/src/net/des.rs b/noita-proxy/src/net/des.rs index 1e20198b..7151a67d 100644 --- a/noita-proxy/src/net/des.rs +++ b/noita-proxy/src/net/des.rs @@ -76,9 +76,14 @@ impl DesManager { .entities .insert(full_entity_data.gid, full_entity_data); } - DesToProxy::DeleteEntity(gid) => { - self.authority.remove(&gid); - self.entity_storage.entities.remove(&gid); + DesToProxy::DeleteEntity(gid, ent) => { + if self.entity_storage.entities.contains_key(&gid) { + self.authority.remove(&gid); + self.entity_storage.entities.remove(&gid); + } else if let Some(ent) = ent { + self.pending_messages + .push((source, ProxyToDes::DeleteEntity(ent))); + } } DesToProxy::ReleaseAuthority(gid) => { self.authority.remove(&gid); diff --git a/shared/src/des.rs b/shared/src/des.rs index 19e14404..a6113359 100644 --- a/shared/src/des.rs +++ b/shared/src/des.rs @@ -1,3 +1,4 @@ +use std::num::NonZero; use std::sync::Arc; use crate::{GameEffectData, PeerId, WorldPos}; @@ -44,7 +45,7 @@ pub struct UpdatePosition { #[derive(Encode, Decode, Clone)] pub enum DesToProxy { InitOrUpdateEntity(FullEntityData), - DeleteEntity(Gid), + DeleteEntity(Gid, Option>), ReleaseAuthority(Gid), RequestAuthority { pos: WorldPos, radius: i32 }, UpdatePositions(Vec), @@ -56,8 +57,8 @@ pub enum ProxyToDes { /// Got authority over entity. GotAuthority(FullEntityData), RemoveEntities(PeerId), + DeleteEntity(NonZero), } - #[derive(Encode, Decode, Clone)] pub struct InterestRequest { pub pos: WorldPos,