make and enable chunk map on clients

This commit is contained in:
bgkillas 2025-03-09 15:10:07 -04:00
parent eaa74dd772
commit 3dcd6b4ec8
5 changed files with 147 additions and 90 deletions

View file

@ -2062,9 +2062,7 @@ impl App {
ConnectedMenu::VoIP,
"VoIP Settings",
);
if netman.peer.is_host() {
ui.selectable_value(&mut self.connected_menu, ConnectedMenu::Map, "Chunk Map");
}
ui.selectable_value(&mut self.connected_menu, ConnectedMenu::Map, "Chunk Map");
if netman.peer.is_steam() {
ui.selectable_value(
&mut self.connected_menu,

View file

@ -29,8 +29,8 @@ use world::{NoitaWorldUpdate, WorldManager};
use crate::lobby_code::LobbyKind;
use crate::mod_manager::{ModmanagerSettings, get_mods};
use crate::net::world::world_model::ChunkCoord;
use crate::net::world::world_model::chunk::{Pixel, PixelFlags};
use crate::net::world::world_model::{ChunkCoord, ChunkData};
use crate::player_cosmetics::{PlayerPngDesc, create_player_png, get_player_skin};
use crate::steam_helper::LobbyExtraData;
use crate::{
@ -378,7 +378,7 @@ impl NetManager {
let audio_settings = self.audio.lock().unwrap().clone();
let audio_state = AudioManager::new(audio_settings);
let (world, rx, sendm) = WorldManager::new(
let (world, rx, recv, sendm, tx) = WorldManager::new(
is_host,
self.peer.my_id(),
self.init_settings.save_state.clone(),
@ -493,11 +493,16 @@ impl NetManager {
to_kick.clear();
for net_event in self.peer.recv() {
self.clone()
.handle_network_event(&mut state, &player_image, net_event);
.handle_network_event(&mut state, &player_image, net_event, &tx);
}
for net_msg in self.loopback_channel.1.try_iter() {
self.clone()
.handle_net_msg(&mut state, &player_image, self.peer.my_id(), net_msg);
self.clone().handle_net_msg(
&mut state,
&player_image,
self.peer.my_id(),
net_msg,
&tx,
);
}
// Handle all available messages from Noita.
while let Some(ws) = &mut state.ms {
@ -576,16 +581,24 @@ impl NetManager {
self.broadcast(&data, Reliability::Reliable);
}
}
let mut map = FxHashMap::default();
while let Ok((ch, img)) = rx.try_recv() {
map.insert(ch, img);
}
if !map.is_empty() {
let chunk_map = &mut self.chunk_map.lock().unwrap();
for (ch, img) in map {
chunk_map.insert(ch, img);
}
}
if self.is_host() {
let mut map = FxHashMap::default();
while let Ok((ch, img)) = rx.try_recv() {
map.insert(ch, img);
while let Ok((ch, c)) = recv.try_recv() {
map.insert(ch, c);
}
if !map.is_empty() {
let chunk_map = &mut self.chunk_map.lock().unwrap();
for (ch, img) in map {
chunk_map.insert(ch, img);
}
let data = NetMsg::MapData(map);
self.broadcast(&data, Reliability::Reliable)
}
}
// Don't do excessive busy-waiting;
@ -603,6 +616,7 @@ impl NetManager {
state: &mut NetInnerState,
player_image: &ImageBuffer<Rgba<u8>, Vec<u8>>,
net_event: omni::OmniNetworkEvent,
tx: &Sender<(ChunkCoord, ChunkData)>,
) {
match net_event {
omni::OmniNetworkEvent::PeerConnected(id) => {
@ -661,7 +675,7 @@ impl NetManager {
else {
return;
};
self.handle_net_msg(state, player_image, src, net_msg);
self.handle_net_msg(state, player_image, src, net_msg, tx);
}
}
}
@ -673,6 +687,7 @@ impl NetManager {
player_image: &ImageBuffer<Rgba<u8>, Vec<u8>>,
src: OmniPeerId,
net_msg: NetMsg,
tx: &Sender<(ChunkCoord, ChunkData)>,
) {
match net_msg {
NetMsg::AudioData(data, global, tx, ty, vol) => {
@ -694,6 +709,11 @@ impl NetManager {
.play_audio(audio, pos, src, data, global, (tx, ty), vol);
}
}
NetMsg::MapData(chunks) => {
for (ch, c) in chunks {
let _ = tx.send((ch, c));
}
}
NetMsg::RequestMods => {
if let Some(n) = &self.init_settings.modmanager_settings.game_save_path {
let res = get_mods(n);

View file

@ -1,8 +1,8 @@
use bitcode::{Decode, Encode};
use crate::{GameSettings, player_cosmetics::PlayerPngDesc};
use super::{omni::OmniPeerId, world::WorldNetMessage};
use crate::net::world::world_model::{ChunkCoord, ChunkData};
use crate::{GameSettings, player_cosmetics::PlayerPngDesc};
use bitcode::{Decode, Encode};
use rustc_hash::FxHashMap;
pub(crate) type Destination = shared::Destination<OmniPeerId>;
@ -35,6 +35,7 @@ pub(crate) enum NetMsg {
RespondFlagMoon(i32, i32, bool),
RespondFlagStevari(i32, i32, OmniPeerId),
AudioData(Vec<Vec<u8>>, bool, i32, i32, f32),
MapData(FxHashMap<ChunkCoord, ChunkData>),
}
impl From<MessageRequest<WorldNetMessage>> for MessageRequest<NetMsg> {

View file

@ -225,55 +225,96 @@ impl WorldManager {
) -> (
Self,
Receiver<(ChunkCoord, RgbaImage)>,
Receiver<(ChunkCoord, ChunkData)>,
Sender<FxHashMap<u16, u32>>,
Sender<(ChunkCoord, ChunkData)>,
) {
let (send, rx) = mpsc::channel::<(ChunkCoord, RgbaImage)>();
let (sendm, rxm) = mpsc::channel::<FxHashMap<u16, u32>>();
let (tx, recv) = mpsc::channel::<(ChunkCoord, ChunkData)>();
if is_host {
thread::spawn(move || {
let mut mats = Default::default();
loop {
while let Ok(mat) = rxm.try_recv() {
mats = mat;
}
while let Ok((c, data)) = recv.try_recv() {
let _ = send.send((c, create_image(data, &mats)));
}
thread::sleep(Duration::from_millis(16));
let (tsx, recv2) = mpsc::channel::<(ChunkCoord, ChunkData)>();
thread::spawn(move || {
let mut mats = Default::default();
loop {
while let Ok(mat) = rxm.try_recv() {
mats = mat;
}
});
}
while let Ok((c, data)) = recv.try_recv() {
if is_host {
let _ = tsx.send((c, data.clone()));
}
let _ = send.send((c, create_image(data, &mats)));
}
thread::sleep(Duration::from_millis(16));
}
});
let chunk_storage = save_state.load().unwrap_or_default();
(
WorldManager {
nice_terraforming: true,
is_host,
my_pos: (i32::MIN / 2, i32::MIN / 2),
cam_pos: (i32::MIN / 2, i32::MIN / 2),
is_notplayer: false,
my_peer_id,
save_state,
inbound_model: Default::default(),
outbound_model: Default::default(),
authority_map: Default::default(),
chunk_storage,
chunk_state: Default::default(),
emitted_messages: Default::default(),
current_update: 0,
chunk_last_update: Default::default(),
last_request_priority: Default::default(),
world_num: 0,
materials: Default::default(),
is_storage_recent: Default::default(),
explosion_pointer: Default::default(),
explosion_data: Default::default(),
explosion_heap: Default::default(),
let (fx, _) = mpsc::channel::<(ChunkCoord, ChunkData)>();
if is_host {
(
WorldManager {
nice_terraforming: true,
is_host,
my_pos: (i32::MIN / 2, i32::MIN / 2),
cam_pos: (i32::MIN / 2, i32::MIN / 2),
is_notplayer: false,
my_peer_id,
save_state,
inbound_model: Default::default(),
outbound_model: Default::default(),
authority_map: Default::default(),
chunk_storage,
chunk_state: Default::default(),
emitted_messages: Default::default(),
current_update: 0,
chunk_last_update: Default::default(),
last_request_priority: Default::default(),
world_num: 0,
materials: Default::default(),
is_storage_recent: Default::default(),
explosion_pointer: Default::default(),
explosion_data: Default::default(),
explosion_heap: Default::default(),
tx,
},
rx,
recv2,
sendm,
fx,
)
} else {
(
WorldManager {
nice_terraforming: true,
is_host,
my_pos: (i32::MIN / 2, i32::MIN / 2),
cam_pos: (i32::MIN / 2, i32::MIN / 2),
is_notplayer: false,
my_peer_id,
save_state,
inbound_model: Default::default(),
outbound_model: Default::default(),
authority_map: Default::default(),
chunk_storage,
chunk_state: Default::default(),
emitted_messages: Default::default(),
current_update: 0,
chunk_last_update: Default::default(),
last_request_priority: Default::default(),
world_num: 0,
materials: Default::default(),
is_storage_recent: Default::default(),
explosion_pointer: Default::default(),
explosion_data: Default::default(),
explosion_heap: Default::default(),
tx: fx,
},
rx,
recv2,
sendm,
tx,
},
rx,
sendm,
)
)
}
}
pub(crate) fn add_update(&mut self, update: NoitaWorldUpdate) {
@ -2467,7 +2508,7 @@ fn get_ray(r: u64) -> u64 {
#[test]
#[serial]
fn test_explosion_img() {
let (mut world, _, _) = WorldManager::new(
let (mut world, _, _, _, _) = WorldManager::new(
true,
OmniPeerId(0),
SaveState::new("/tmp/ew_tmp_save".parse().unwrap()),
@ -2569,7 +2610,7 @@ fn test_explosion_img() {
#[test]
#[serial]
fn test_explosion_img_big() {
let (mut world, _, _) = WorldManager::new(
let (mut world, _, _, _, _) = WorldManager::new(
true,
OmniPeerId(0),
SaveState::new("/tmp/ew_tmp_save".parse().unwrap()),
@ -2638,7 +2679,7 @@ fn test_explosion_img_big() {
#[test]
#[serial]
fn test_explosion_img_big_br() {
let (mut world, _, _) = WorldManager::new(
let (mut world, _, _, _, _) = WorldManager::new(
true,
OmniPeerId(0),
SaveState::new("/tmp/ew_tmp_save".parse().unwrap()),
@ -2714,7 +2755,7 @@ fn test_explosion_img_big_br() {
#[test]
#[serial]
fn test_explosion_img_big_empty() {
let (mut world, _, _) = WorldManager::new(
let (mut world, _, _, _, _) = WorldManager::new(
true,
OmniPeerId(0),
SaveState::new("/tmp/ew_tmp_save".parse().unwrap()),
@ -2773,7 +2814,7 @@ fn test_explosion_img_big_empty() {
#[test]
#[serial]
fn test_explosion_large() {
let (mut world, _, _) = WorldManager::new(
let (mut world, _, _, _, _) = WorldManager::new(
true,
OmniPeerId(0),
SaveState::new("/tmp/ew_tmp_save".parse().unwrap()),
@ -2818,7 +2859,7 @@ fn test_explosion_large() {
#[test]
#[serial]
fn test_cut_img() {
let (mut world, _, _) = WorldManager::new(
let (mut world, _, _, _, _) = WorldManager::new(
true,
OmniPeerId(0),
SaveState::new("/tmp/ew_tmp_save".parse().unwrap()),
@ -2861,7 +2902,7 @@ fn test_cut_img() {
#[test]
#[serial]
fn test_line_img() {
let (mut world, _, _) = WorldManager::new(
let (mut world, _, _, _, _) = WorldManager::new(
true,
OmniPeerId(0),
SaveState::new("/tmp/ew_tmp_save".parse().unwrap()),
@ -2948,7 +2989,7 @@ fn test_line_img() {
#[test]
#[serial]
fn test_circ_img() {
let (mut world, _, _) = WorldManager::new(
let (mut world, _, _, _, _) = WorldManager::new(
true,
OmniPeerId(0),
SaveState::new("/tmp/ew_tmp_save".parse().unwrap()),
@ -2991,7 +3032,7 @@ fn test_circ_img() {
#[test]
#[serial]
fn test_explosion_img_big_many() {
let (mut world, _, _) = WorldManager::new(
let (mut world, _, _, _, _) = WorldManager::new(
true,
OmniPeerId(0),
SaveState::new("/tmp/ew_tmp_save".parse().unwrap()),
@ -3099,7 +3140,7 @@ fn test_explosion_perf() {
let mut total = 0;
let iters = 64;
for _ in 0..iters {
let (mut world, _, _) = WorldManager::new(
let (mut world, _, _, _, _) = WorldManager::new(
true,
OmniPeerId(0),
SaveState::new("/tmp/ew_tmp_save".parse().unwrap()),
@ -3151,7 +3192,7 @@ fn test_explosion_perf_unloaded() {
let iters = 4;
let mut n = 0;
for _ in 0..iters {
let (mut world, _, _) = WorldManager::new(
let (mut world, _, _, _, _) = WorldManager::new(
true,
OmniPeerId(0),
SaveState::new("/tmp/ew_tmp_save".parse().unwrap()),
@ -3219,7 +3260,7 @@ fn test_explosion_perf_large() {
let mut total = 0;
let iters = 16;
for _ in 0..iters {
let (mut world, _, _) = WorldManager::new(
let (mut world, _, _, _, _) = WorldManager::new(
true,
OmniPeerId(0),
SaveState::new("/tmp/ew_tmp_save".parse().unwrap()),
@ -3270,7 +3311,7 @@ fn test_line_perf() {
let mut total = 0;
let iters = 64;
for _ in 0..iters {
let (mut world, _, _) = WorldManager::new(
let (mut world, _, _, _, _) = WorldManager::new(
true,
OmniPeerId(0),
SaveState::new("/tmp/ew_tmp_save".parse().unwrap()),
@ -3309,7 +3350,7 @@ fn test_circle_perf() {
let mut total = 0;
let iters = 64;
for _ in 0..iters {
let (mut world, _, _) = WorldManager::new(
let (mut world, _, _, _, _) = WorldManager::new(
true,
OmniPeerId(0),
SaveState::new("/tmp/ew_tmp_save".parse().unwrap()),
@ -3348,7 +3389,7 @@ fn test_cut_perf() {
let mut total = 0;
let iters = 64;
for _ in 0..iters {
let (mut world, _, _) = WorldManager::new(
let (mut world, _, _, _, _) = WorldManager::new(
true,
OmniPeerId(0),
SaveState::new("/tmp/ew_tmp_save".parse().unwrap()),

View file

@ -3,6 +3,18 @@ local module = {}
local ptt = 0
function module.on_world_update()
if GameGetFrameNum() % 8 == 7 then
local s = ""
for peer, data in pairs(ctx.players) do
local x, y = EntityGetTransform(data.entity)
if x == nil then
return
end
s = s .. " " .. tostring(peer) .. " " .. math.floor(x) .. " " .. math.floor(y)
end
net.proxy_send("players_pos", string.sub(s, 2, -1))
end
if GameGetFrameNum() % 4 ~= 2 then
return
end
@ -62,19 +74,4 @@ function module.on_world_update()
)
end
function module.on_world_update_host()
if GameGetFrameNum() % 8 ~= 2 then
return
end
local s = ""
for peer, data in pairs(ctx.players) do
local x, y = EntityGetTransform(data.entity)
if x == nil then
return
end
s = s .. " " .. tostring(peer) .. " " .. math.floor(x) .. " " .. math.floor(y)
end
net.proxy_send("players_pos", string.sub(s, 2, -1))
end
return module