Sending messages to noita

This commit is contained in:
IQuant 2024-06-05 16:22:03 +03:00
parent 53c213b260
commit 3860f48633
8 changed files with 70 additions and 9 deletions

5
Justfile Normal file
View file

@ -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

View file

@ -1,6 +1,6 @@
use bitcode::{Decode, Encode}; use bitcode::{Decode, Encode};
use crate::GameSettings; use crate::{net::world::world_model::ChunkDelta, GameSettings};
#[derive(Debug, Decode, Encode)] #[derive(Debug, Decode, Encode)]
pub enum NetMsg { pub enum NetMsg {
@ -8,4 +8,5 @@ pub enum NetMsg {
StartGame { settings: GameSettings }, StartGame { settings: GameSettings },
ModRaw { data: Vec<u8> }, ModRaw { data: Vec<u8> },
ModCompressed { data: Vec<u8> }, ModCompressed { data: Vec<u8> },
WorldDeltas { deltas: Vec<ChunkDelta> },
} }

View file

@ -27,6 +27,14 @@ pub(crate) fn ws_encode_proxy(key: &'static str, value: impl Display) -> tungste
tungstenite::Message::Binary(buf) 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 { pub(crate) fn ws_encode_mod(peer: omni::OmniPeerId, data: &[u8]) -> tungstenite::Message {
let mut buf = Vec::new(); let mut buf = Vec::new();
buf.push(1u8); buf.push(1u8);
@ -211,6 +219,7 @@ impl NetManager {
state.try_ws_write(ws_encode_proxy("leave", id)); state.try_ws_write(ws_encode_proxy("leave", id));
} }
omni::OmniNetworkEvent::Message { src, data } => { omni::OmniNetworkEvent::Message { src, data } => {
// TODO move all compression here.
let Ok(net_msg) = bitcode::decode::<NetMsg>(&data) else { let Ok(net_msg) = bitcode::decode::<NetMsg>(&data) else {
continue; continue;
}; };
@ -233,6 +242,13 @@ impl NetManager {
state.try_ws_write(ws_encode_mod(src, &decompressed)); 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 // world end
1 => { 1 => {
state.world.add_end(); let deltas = state.world.add_end();
self.broadcast(&NetMsg::WorldDeltas { deltas }, Reliability::Reliable);
} }
key => { key => {
error!("Unknown bin msg from mod: {:?}", key) error!("Unknown bin msg from mod: {:?}", key)

View file

@ -1,5 +1,4 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{fs::File, io::BufWriter};
use world_model::WorldModel; use world_model::WorldModel;
pub use world_model::encoding::NoitaWorldUpdate; pub use world_model::encoding::NoitaWorldUpdate;
@ -30,9 +29,22 @@ impl WorldManager {
self.model.apply_noita_update(&update); self.model.apply_noita_update(&update);
} }
pub fn add_end(&mut self) { pub fn add_end(&mut self) -> Vec<world_model::ChunkDelta> {
let deltas = self.model.get_all_deltas();
self.model.reset_change_tracking();
deltas
// bincode::serialize_into(&mut self.writer, &WorldUpdateKind::End).unwrap(); // bincode::serialize_into(&mut self.writer, &WorldUpdateKind::End).unwrap();
} }
pub fn handle_deltas(&mut self, deltas: Vec<world_model::ChunkDelta>) {
self.model.apply_all_deltas(&deltas);
}
pub fn get_noita_updates(&mut self) -> Vec<Vec<u8>> {
let updates = self.model.get_all_noita_updates();
self.model.reset_change_tracking();
updates
}
} }
#[cfg(test)] #[cfg(test)]

View file

@ -3,7 +3,6 @@ use chunk::{Chunk, Pixel, PixelFlags};
use encoding::{NoitaWorldUpdate, PixelRun, PixelRunner}; use encoding::{NoitaWorldUpdate, PixelRun, PixelRunner};
use image::{Rgb, RgbImage}; use image::{Rgb, RgbImage};
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use std::collections::HashSet;
mod chunk; mod chunk;
pub mod encoding; pub mod encoding;
@ -16,7 +15,7 @@ pub struct WorldModel {
chunks: FxHashMap<ChunkCoord, Chunk>, chunks: FxHashMap<ChunkCoord, Chunk>,
pub mats: FxHashSet<u16>, pub mats: FxHashSet<u16>,
palette: MatPalette, palette: MatPalette,
changed_chunks: HashSet<ChunkCoord>, changed_chunks: FxHashSet<ChunkCoord>,
} }
struct MatPalette { struct MatPalette {
@ -128,8 +127,22 @@ impl WorldModel {
runner.to_noita(x, y, (w - 1) as u8, (h - 1) as u8) runner.to_noita(x, y, (w - 1) as u8, (h - 1) as u8)
} }
pub fn get_all_noita_updates(&self) -> Vec<Vec<u8>> {
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) { 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 chunk = self.chunks.entry(delta.chunk_coord).or_default();
let mut offset = 0; let mut offset = 0;
for run in &delta.runs { for run in &delta.runs {

View file

@ -10,6 +10,8 @@ local reactor = pollnet.Reactor()
local net_handling = dofile_once("mods/quant.ew/files/src/net_handling.lua") local net_handling = dofile_once("mods/quant.ew/files/src/net_handling.lua")
local net = {} local net = {}
net.net_handling = net_handling
ctx.lib.net = net ctx.lib.net = net
function net.update() function net.update()
@ -104,6 +106,13 @@ function net.init()
else else
print("Could not deserialize: "..item) print("Could not deserialize: "..item)
end 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 else
print("Unknown msg") print("Unknown msg")
end end

View file

@ -74,7 +74,7 @@ function world_sync.on_world_update_host()
end end
end end
if GameGetFrameNum() % 10 == 0 then if GameGetFrameNum() % 30 == 0 then
rect_optimiser:scan() rect_optimiser:scan()
for crect in rect.parts(rect_optimiser:iterate(), 256) do for crect in rect.parts(rect_optimiser:iterate(), 256) do
@ -111,4 +111,8 @@ function world_sync.handle_world_data(world_data)
end end
end end
net.net_handling.proxy[0] = function(_, value)
world_sync.handle_world_data(value)
end
return world_sync return world_sync

View file

@ -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 pretty = dofile_once("mods/quant.ew/files/lib/pretty_print.lua")
local perk_fns = dofile_once("mods/quant.ew/files/src/perk_fns.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/item_sync.lua")
ctx.dofile_and_add_hooks("mods/quant.ew/files/src/system/enemy_sync.lua") ctx.dofile_and_add_hooks("mods/quant.ew/files/src/system/enemy_sync.lua")