diff --git a/Justfile b/Justfile new file mode 100644 index 00000000..f63b526e --- /dev/null +++ b/Justfile @@ -0,0 +1,5 @@ +run: + cd noita-proxy && NP_APPID=480 NP_SKIP_MOD_CHECK=1 cargo run + +run2: + cd noita-proxy && NP_APPID=480 NP_SKIP_MOD_CHECK=1 NP_NOITA_ADDR=127.0.0.1:21252 cargo run \ No newline at end of file diff --git a/noita-proxy/src/messages.rs b/noita-proxy/src/messages.rs index babc0cfe..68942263 100644 --- a/noita-proxy/src/messages.rs +++ b/noita-proxy/src/messages.rs @@ -1,6 +1,6 @@ use bitcode::{Decode, Encode}; -use crate::GameSettings; +use crate::{net::world::world_model::ChunkDelta, GameSettings}; #[derive(Debug, Decode, Encode)] pub enum NetMsg { @@ -8,4 +8,5 @@ pub enum NetMsg { StartGame { settings: GameSettings }, ModRaw { data: Vec }, ModCompressed { data: Vec }, + WorldDeltas { deltas: Vec }, } diff --git a/noita-proxy/src/net.rs b/noita-proxy/src/net.rs index 684083a3..48248a79 100644 --- a/noita-proxy/src/net.rs +++ b/noita-proxy/src/net.rs @@ -27,6 +27,14 @@ pub(crate) fn ws_encode_proxy(key: &'static str, value: impl Display) -> tungste tungstenite::Message::Binary(buf) } +pub fn ws_encode_proxy_bin(key: u8, data: &[u8]) -> tungstenite::Message { + let mut buf = Vec::new(); + buf.push(3); + buf.push(key); + buf.extend(data); + tungstenite::Message::Binary(buf) +} + pub(crate) fn ws_encode_mod(peer: omni::OmniPeerId, data: &[u8]) -> tungstenite::Message { let mut buf = Vec::new(); buf.push(1u8); @@ -211,6 +219,7 @@ impl NetManager { state.try_ws_write(ws_encode_proxy("leave", id)); } omni::OmniNetworkEvent::Message { src, data } => { + // TODO move all compression here. let Ok(net_msg) = bitcode::decode::(&data) else { continue; }; @@ -233,6 +242,13 @@ impl NetManager { state.try_ws_write(ws_encode_mod(src, &decompressed)); } } + NetMsg::WorldDeltas { deltas } => { + state.world.handle_deltas(deltas); + let updates = state.world.get_noita_updates(); + for update in updates { + state.try_ws_write(ws_encode_proxy_bin(0, &update)); + } + } } } } @@ -365,7 +381,8 @@ impl NetManager { } // world end 1 => { - state.world.add_end(); + let deltas = state.world.add_end(); + self.broadcast(&NetMsg::WorldDeltas { deltas }, Reliability::Reliable); } key => { error!("Unknown bin msg from mod: {:?}", key) diff --git a/noita-proxy/src/net/world.rs b/noita-proxy/src/net/world.rs index 245f2234..3511fd47 100644 --- a/noita-proxy/src/net/world.rs +++ b/noita-proxy/src/net/world.rs @@ -1,5 +1,4 @@ use serde::{Deserialize, Serialize}; -use std::{fs::File, io::BufWriter}; use world_model::WorldModel; pub use world_model::encoding::NoitaWorldUpdate; @@ -30,9 +29,22 @@ impl WorldManager { self.model.apply_noita_update(&update); } - pub fn add_end(&mut self) { + pub fn add_end(&mut self) -> Vec { + let deltas = self.model.get_all_deltas(); + self.model.reset_change_tracking(); + deltas // bincode::serialize_into(&mut self.writer, &WorldUpdateKind::End).unwrap(); } + + pub fn handle_deltas(&mut self, deltas: Vec) { + self.model.apply_all_deltas(&deltas); + } + + pub fn get_noita_updates(&mut self) -> Vec> { + let updates = self.model.get_all_noita_updates(); + self.model.reset_change_tracking(); + updates + } } #[cfg(test)] diff --git a/noita-proxy/src/net/world/world_model.rs b/noita-proxy/src/net/world/world_model.rs index 50ad66e9..8c69e236 100644 --- a/noita-proxy/src/net/world/world_model.rs +++ b/noita-proxy/src/net/world/world_model.rs @@ -3,7 +3,6 @@ use chunk::{Chunk, Pixel, PixelFlags}; use encoding::{NoitaWorldUpdate, PixelRun, PixelRunner}; use image::{Rgb, RgbImage}; use rustc_hash::{FxHashMap, FxHashSet}; -use std::collections::HashSet; mod chunk; pub mod encoding; @@ -16,7 +15,7 @@ pub struct WorldModel { chunks: FxHashMap, pub mats: FxHashSet, palette: MatPalette, - changed_chunks: HashSet, + changed_chunks: FxHashSet, } struct MatPalette { @@ -128,8 +127,22 @@ impl WorldModel { runner.to_noita(x, y, (w - 1) as u8, (h - 1) as u8) } + pub fn get_all_noita_updates(&self) -> Vec> { + let mut updates = Vec::new(); + for chunk_coord in &self.changed_chunks { + let update = self.get_noita_update( + chunk_coord.0 * (CHUNK_SIZE as i32), + chunk_coord.1 * (CHUNK_SIZE as i32), + CHUNK_SIZE as u32, + CHUNK_SIZE as u32, + ); + updates.push(update.save()); + } + updates + } + fn apply_chunk_delta(&mut self, delta: &ChunkDelta) { - // TODO: Also mark as updated? + self.changed_chunks.insert(delta.chunk_coord); let chunk = self.chunks.entry(delta.chunk_coord).or_default(); let mut offset = 0; for run in &delta.runs { diff --git a/quant.ew/files/src/net.lua b/quant.ew/files/src/net.lua index 228b264c..06b9d077 100644 --- a/quant.ew/files/src/net.lua +++ b/quant.ew/files/src/net.lua @@ -10,6 +10,8 @@ local reactor = pollnet.Reactor() local net_handling = dofile_once("mods/quant.ew/files/src/net_handling.lua") local net = {} +net.net_handling = net_handling + ctx.lib.net = net function net.update() @@ -104,6 +106,13 @@ function net.init() else print("Could not deserialize: "..item) end + elseif string.byte(msg, 1, 1) == 2 then + msg_decoded = { + kind = "proxy", + peer_id = nil, + key = string.byte(msg, 2, 2), + value = string.sub(msg, 3), + } else print("Unknown msg") end diff --git a/quant.ew/files/src/system/world_sync2.lua b/quant.ew/files/src/system/world_sync2.lua index 7fcfa006..b77b2acb 100644 --- a/quant.ew/files/src/system/world_sync2.lua +++ b/quant.ew/files/src/system/world_sync2.lua @@ -74,7 +74,7 @@ function world_sync.on_world_update_host() end end - if GameGetFrameNum() % 10 == 0 then + if GameGetFrameNum() % 30 == 0 then rect_optimiser:scan() for crect in rect.parts(rect_optimiser:iterate(), 256) do @@ -111,4 +111,8 @@ function world_sync.handle_world_data(world_data) end end +net.net_handling.proxy[0] = function(_, value) + world_sync.handle_world_data(value) +end + return world_sync \ No newline at end of file diff --git a/quant.ew/init.lua b/quant.ew/init.lua index aade4789..996d141d 100755 --- a/quant.ew/init.lua +++ b/quant.ew/init.lua @@ -17,7 +17,7 @@ local inventory_helper = dofile_once("mods/quant.ew/files/src/inventory_helper.l local pretty = dofile_once("mods/quant.ew/files/lib/pretty_print.lua") local perk_fns = dofile_once("mods/quant.ew/files/src/perk_fns.lua") -ctx.dofile_and_add_hooks("mods/quant.ew/files/src/world_sync.lua") +-- ctx.dofile_and_add_hooks("mods/quant.ew/files/src/world_sync.lua") ctx.dofile_and_add_hooks("mods/quant.ew/files/src/item_sync.lua") ctx.dofile_and_add_hooks("mods/quant.ew/files/src/system/enemy_sync.lua")