Seems to work now. Still have several things to fix tho.

This commit is contained in:
IQuant 2024-07-31 12:37:29 +03:00
parent 25130c0316
commit fd84404a39
7 changed files with 60 additions and 96 deletions

View file

@ -22,6 +22,9 @@ run: add_dylib_debug
run2: add_dylib_debug
cd noita-proxy && NP_APPID=480 NP_SKIP_MOD_CHECK=1 NP_NOITA_ADDR=127.0.0.1:21252 cargo run -- --launch-cmd "wine noita.exe -gamemode 0"
run2-alt: add_dylib_debug
cd noita-proxy && NP_APPID=480 NP_SKIP_MOD_CHECK=1 NP_NOITA_ADDR=127.0.0.1:21252 cargo run
run3: add_dylib_debug
cd noita-proxy && NP_APPID=480 NP_SKIP_MOD_CHECK=1 NP_NOITA_ADDR=127.0.0.1:21253 cargo run -- --launch-cmd "wine noita.exe -gamemode 0"

View file

@ -229,28 +229,26 @@ impl NetManager {
state.try_ws_write(ws_encode_mod(src, &decompressed));
}
}
NetMsg::WorldDelta { delta: deltas } => {
state.world.handle_deltas(deltas);
}
NetMsg::WorldFrame => {
let updates = state.world.get_noita_updates();
for update in updates {
state.try_ws_write(ws_encode_proxy_bin(0, &update));
}
}
NetMsg::WorldMessage(msg) => state.world.handle_msg(src, msg),
}
}
}
}
// TODO: Are we really reading only one message per loop?
if let Some(ws) = &mut state.ws {
let msg = ws.read();
self.handle_mod_message(msg, &mut state);
}
for msg in state.world.get_emitted_msgs() {
self.do_message_request(msg)
}
state.world.update();
let updates = state.world.get_noita_updates();
for update in updates {
state.try_ws_write(ws_encode_proxy_bin(0, &update));
}
}
Ok(())
}
@ -435,16 +433,7 @@ impl NetManager {
}
// world end
1 => {
let deltas = state.world.add_end();
let limit = if self.peer.is_steam() {
1024 * 1024
} else {
30000
};
for delta in deltas.split(limit) {
self.broadcast(&NetMsg::WorldDelta { delta }, Reliability::Reliable);
}
self.broadcast(&NetMsg::WorldFrame, Reliability::Reliable);
state.world.add_end();
}
key => {
error!("Unknown bin msg from mod: {:?}", key)

View file

@ -23,8 +23,6 @@ pub enum NetMsg {
StartGame { settings: GameSettings },
ModRaw { data: Vec<u8> },
ModCompressed { data: Vec<u8> },
WorldDelta { delta: WorldDelta },
WorldFrame,
WorldMessage(WorldNetMessage),
}

View file

@ -3,7 +3,7 @@ use std::mem;
use bitcode::{Decode, Encode};
use rustc_hash::{FxHashMap, FxHashSet};
use serde::{Deserialize, Serialize};
use tracing::{info, warn};
use tracing::{debug, info, warn};
use world_model::{ChunkCoord, ChunkData, ChunkDelta, WorldModel};
pub use world_model::encoding::NoitaWorldUpdate;
@ -87,8 +87,8 @@ impl WorldDelta {
#[derive(Debug, PartialEq, Eq)]
enum ChunkState {
/// Chunk isn't synced yet.
Unsynced,
/// Chunk isn't synced yet, but will request authority for it.
RequestAuthority,
/// Transitioning into Listening or Authority state.
WaitingForAuthority,
/// Listening for chunk updates from this peer.
@ -96,7 +96,7 @@ enum ChunkState {
/// Sending chunk updates to these listeners.
Authority { listeners: FxHashSet<OmniPeerId> },
/// Chunk is to be cleaned up.
Unloaded,
UnloadPending,
}
impl ChunkState {
fn authority() -> ChunkState {
@ -106,14 +106,14 @@ impl ChunkState {
}
}
pub struct WorldManager {
pub(crate) struct WorldManager {
is_host: bool,
my_peer_id: OmniPeerId,
/// We receive changes from other clients here, intending to send them to Noita.
inbound_model: WorldModel,
/// We use that to create changes to be sent to other clients.
outbound_model: WorldModel,
/// Current
/// Stores chunks that aren't under any authority.
chunk_storage: FxHashMap<ChunkCoord, ChunkData>,
/// Who is the current chunk authority.
authority_map: FxHashMap<ChunkCoord, OmniPeerId>,
@ -129,7 +129,7 @@ pub struct WorldManager {
}
impl WorldManager {
pub fn new(is_host: bool, my_peer_id: OmniPeerId) -> Self {
pub(crate) fn new(is_host: bool, my_peer_id: OmniPeerId) -> Self {
WorldManager {
is_host,
my_peer_id,
@ -149,8 +149,7 @@ impl WorldManager {
self.outbound_model.apply_noita_update(&update);
}
pub(crate) fn add_end(&mut self) -> WorldDelta {
let deltas = self.outbound_model.get_all_deltas();
pub(crate) fn add_end(&mut self) {
let updated_chunks = self
.outbound_model
.updated_chunks()
@ -162,13 +161,12 @@ impl WorldManager {
self.chunk_updated_locally(chunk);
}
self.outbound_model.reset_change_tracking();
WorldDelta(deltas)
}
fn chunk_updated_locally(&mut self, chunk: ChunkCoord) {
let entry = self.chunk_state.entry(chunk).or_insert_with(|| {
info!("Created entry for {chunk:?}");
ChunkState::Unsynced
debug!("Created entry for {chunk:?}");
ChunkState::RequestAuthority
});
let mut emit_queue = Vec::new();
self.chunk_last_update.insert(chunk, self.current_update);
@ -193,7 +191,7 @@ impl WorldManager {
pub(crate) fn update(&mut self) {
let mut emit_queue = Vec::new();
let unload_limit = 60;
let unload_limit = 1;
for (&chunk, state) in self.chunk_state.iter_mut() {
let chunk_last_update = self
@ -202,7 +200,7 @@ impl WorldManager {
.copied()
.unwrap_or_default();
match state {
ChunkState::Unsynced => {
ChunkState::RequestAuthority => {
emit_queue.push((
Destination::Host,
WorldNetMessage::RequestAuthority { chunk },
@ -219,12 +217,12 @@ impl WorldManager {
Destination::Peer(*authority),
WorldNetMessage::ListenStopRequest { chunk },
));
*state = ChunkState::Unloaded;
*state = ChunkState::UnloadPending;
}
}
ChunkState::Authority { listeners } => {
ChunkState::Authority { listeners: _ } => {
if self.current_update - chunk_last_update > unload_limit {
info!("Unloading [authority] chunk {chunk:?}");
info!("Unloading [authority] chunk {chunk:?} (updates: {chunk_last_update} {})", self.current_update);
emit_queue.push((
Destination::Host,
WorldNetMessage::RelinquishAuthority {
@ -232,10 +230,10 @@ impl WorldManager {
chunk_data: self.outbound_model.get_chunk_data(chunk),
},
));
*state = ChunkState::Unloaded;
*state = ChunkState::UnloadPending;
}
}
ChunkState::Unloaded => {}
ChunkState::UnloadPending => {}
}
}
@ -243,7 +241,7 @@ impl WorldManager {
self.emit_msg(dst, msg)
}
self.chunk_state
.retain(|_chunk, state| *state != ChunkState::Unloaded);
.retain(|_chunk, state| *state != ChunkState::UnloadPending);
}
pub(crate) fn handle_deltas(&mut self, deltas: WorldDelta) {
@ -259,6 +257,7 @@ impl WorldManager {
pub(crate) fn reset(&mut self) {
self.inbound_model.reset();
self.outbound_model.reset();
self.chunk_storage.clear();
}
pub(crate) fn get_emitted_msgs(&mut self) -> Vec<MessageRequest<WorldNetMessage>> {
@ -335,7 +334,10 @@ impl WorldManager {
if let Some(chunk_data) = chunk_data {
self.chunk_storage.insert(chunk, chunk_data);
}
// TODO notify others?
self.emit_msg(
Destination::Broadcast,
WorldNetMessage::ListenAuthorityRelinquished { chunk },
)
}
WorldNetMessage::AuthorityAlreadyTaken { chunk, authority } => {
@ -376,7 +378,7 @@ impl WorldManager {
}
}
WorldNetMessage::ListenUpdate { delta } => {
let Some(ChunkState::Listening { authority }) =
let Some(ChunkState::Listening { authority: _ }) =
self.chunk_state.get_mut(&delta.chunk_coord)
else {
warn!(
@ -385,9 +387,10 @@ impl WorldManager {
);
return;
};
self.inbound_model.apply_chunk_delta(&delta);
}
WorldNetMessage::ListenAuthorityRelinquished { chunk } => {
self.chunk_state.insert(chunk, ChunkState::Unsynced);
self.chunk_state.insert(chunk, ChunkState::UnloadPending);
}
}
}

View file

@ -163,7 +163,7 @@ impl WorldModel {
updates
}
fn apply_chunk_delta(&mut self, delta: &ChunkDelta) {
pub(crate) fn apply_chunk_delta(&mut self, delta: &ChunkDelta) {
self.updated_chunks.insert(delta.chunk_coord);
let chunk = self.chunks.entry(delta.chunk_coord).or_default();
let mut offset = 0;
@ -177,7 +177,7 @@ impl WorldModel {
}
}
pub fn get_chunk_delta(
pub(crate) fn get_chunk_delta(
&self,
chunk_coord: ChunkCoord,
ignore_changed: bool,

Binary file not shown.

After

Width:  |  Height:  |  Size: 557 B

View file

@ -19,66 +19,37 @@ local KEY_WORLD_END = 1
local CHUNK_SIZE = 128
local function chunk_producer()
local initialized_chunks = {}
local sent_anything = false
for _, player_data in pairs(ctx.players) do
if not EntityGetIsAlive(player_data.entity) then
goto continue
end
local px, py = EntityGetTransform(player_data.entity)
local ocx, ocy = math.floor(px / CHUNK_SIZE), math.floor(py / CHUNK_SIZE)
for cx = ocx-1,ocx+1 do
for cy = ocy-1,ocy+1 do
local chunk_id = cx.." "..cy
if initialized_chunks[chunk_id] == nil then
local crect = rect.Rectangle(cx * CHUNK_SIZE, cy * CHUNK_SIZE, (cx+1) * CHUNK_SIZE, (cy+1) * CHUNK_SIZE)
if DoesWorldExistAt(crect.left, crect.top, crect.right, crect.bottom) then
-- GamePrint("Sending chunk "..chunk_id)
initialized_chunks[chunk_id] = true
coroutine.yield(crect)
end
end
end
end
::continue::
end
end
local producer_coro = nil
local sent_anything = false
function world_sync.on_world_update_host()
function world_sync.on_world_update()
local grid_world = world_ffi.get_grid_world()
local chunk_map = grid_world.vtable.get_chunk_map(grid_world)
local thread_impl = grid_world.mThreadImpl
if producer_coro == nil then
producer_coro = coroutine.wrap(chunk_producer)
end
if GameGetFrameNum() % 1 == 0 then
local crect = producer_coro()
if crect == nil then
producer_coro = nil
if GameGetFrameNum() % 10 == 0 then
local player_data = ctx.my_player
if not EntityGetIsAlive(player_data.entity) then
return
end
local px, py = EntityGetTransform(player_data.entity)
local ocx, ocy = math.floor(px / CHUNK_SIZE), math.floor(py / CHUNK_SIZE)
local area = world.encode_area(chunk_map, crect.left, crect.top, crect.right, crect.bottom, encoded_area)
if area ~= nil then
local str = ffi.string(area, world.encoded_size(area))
net.proxy_bin_send(KEY_WORLD_FRAME, str)
sent_anything = true
for cx = ocx-2,ocx+2 do
for cy = ocy-2,ocy+2 do
local crect = rect.Rectangle(cx * CHUNK_SIZE, cy * CHUNK_SIZE, (cx+1) * CHUNK_SIZE, (cy+1) * CHUNK_SIZE)
if DoesWorldExistAt(crect.left, crect.top, crect.right, crect.bottom) then
local area = world.encode_area(chunk_map, crect.left, crect.top, crect.right, crect.bottom, encoded_area)
if area ~= nil then
if ctx.proxy_opt.debug then
GameCreateSpriteForXFrames("mods/quant.ew/files/debug/box_128x128.png", crect.left+64, crect.top + 64, true, 0, 0, 11, true)
end
local str = ffi.string(area, world.encoded_size(area))
net.proxy_bin_send(KEY_WORLD_FRAME, str)
end
end
end
end
if GameGetFrameNum() % 4 == 0 then
net.proxy_bin_send(KEY_WORLD_END, "")
end
net.proxy_bin_send(KEY_WORLD_END, "")
end
end