Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions crates/darksouls3/mapper-profile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ vftable = "player_ins_vmt"
class = "NS_SPRJ::ReplayGhostIns"
vftable = "replay_ghost_ins_vmt"

[[vmts]]
class = "NS_SPRJ::WorldInfo"
vftable = "world_info_vmt"

[[vmts]]
class = "NS_SPRJ::WorldRes"
vftable = "world_res_vmt"

[[patterns]]
pattern = "48 8b 05 $ { ' } 48 85 c0 74 ? 80 b8 ? ? ? ? ? 0f 95 c0 c3"
captures = ["", "app_menu_new_menu_system_ptr"]
Expand Down
2 changes: 2 additions & 0 deletions crates/darksouls3/src/rva/bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,6 @@ pub struct RvaBundle {
pub register_task: u32,
pub replay_ghost_ins_vmt: u32,
pub sprj_menu_man_ptr: u32,
pub world_info_vmt: u32,
pub world_res_vmt: u32,
}
2 changes: 2 additions & 0 deletions crates/darksouls3/src/rva/rva_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,6 @@ pub const RVAS: RvaBundle = RvaBundle {
register_task: 0xf0fa50,
replay_ghost_ins_vmt: 0x2858aa8,
sprj_menu_man_ptr: 0x4763258,
world_info_vmt: 0x27d7a50,
world_res_vmt: 0x27d7fb8,
};
74 changes: 37 additions & 37 deletions crates/darksouls3/src/sprj/event_flag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ impl TryFrom<u32> for EventFlag {
}
}

impl From<EventFlag> for u32 {
fn from(value: EventFlag) -> u32 {
value.0
}
}

#[repr(C)]
// Source of name: FD4Singleton error handling
/// The singleton that manages the game's event flags.
Expand All @@ -113,8 +119,8 @@ impl SprjEventFlagMan {
let word_index = flag.word() as usize;
self.get_event_zone_mut(flag)
.and_then(|z| {
let old_word = z.words().get(word_index)?;
z.words_mut()[word_index] = if state {
let old_word = z.words.get(word_index)?;
z.words[word_index] = if state {
old_word | (1 << flag.bit())
} else {
old_word & !(1 << flag.bit())
Expand All @@ -128,7 +134,7 @@ impl SprjEventFlagMan {
/// that don't exist.
pub fn get_flag(&self, flag: EventFlag) -> bool {
self.get_event_zone(flag)
.and_then(|z| z.words().get(flag.word() as usize))
.and_then(|z| z.words.get(flag.word() as usize))
.map(|word| (word >> flag.bit()) & 1 == 1)
.unwrap_or_default()
}
Expand Down Expand Up @@ -162,26 +168,22 @@ impl SprjEventFlagMan {

/// Returns the index of the [EventBlock] that contains `flag`.
pub fn get_event_block_index(&self, flag: EventFlag) -> Option<u32> {
if flag.area() == 0 && flag.group() == 0 {
Some(0)
Some(if flag.area() == 0 && flag.group() == 0 {
0
// Safety: If the event man is being accessed safely, the field area
// should be accessible as well.
} else if let Ok(field_area) = unsafe { FieldArea::instance() } {
field_area
.world_res()?
.super_world_info
.area_info()
.iter()
.find(|ai| ai.area_number == flag.area())
.and_then(|ai| {
ai.block_info().iter().find(|bi| {
bi.block_id.group() == flag.group() && bi.block_id.area() == flag.area()
})
})
.map(|bi| bi.world_block_index + 1)
let (_, block_infos) = field_area
.world_info_owner
.area_and_block_info()
.find(|(area_infos, _)| area_infos.area_number == flag.area())?;
let block_info = block_infos.iter().find(|bi| {
bi.block_id.group() == flag.group() && bi.block_id.area() == flag.area()
})?;
block_info.world_block_index + 1
} else {
Some((flag.global_block_index()? + 1).into())
}
(flag.global_block_index()? + 1).into()
})
}
}

Expand All @@ -192,14 +194,22 @@ pub struct FD4VirtualMemoryFlag {
/// Raw backing data for event flags. This is not guaranteed to be organized
/// in any particular way; access events through the dedicated methods
/// instead of directly through this buffer.
pub data: [OwnedPtr<u32>; 2],
///
/// In a literal sense, this struct owns these pointers. However, to ensure
/// Rust's aliasing rules aren't violated, we only expose safe references to
/// them through [EventZone].
pub data: [NonNull<u32>; 2],

/// The length in bytes of the corresponding buffers in [data](Self.data).
pub data_length: [usize; 2],

/// The array of event blocks. The length is stored as a u64 immediately
/// before the head of the array.
pub blocks: OwnedPtr<EventBlock>,
///
/// In a literal sense, this struct owns these pointers. However, to ensure
/// Rust's aliasing rules aren't violated, we only expose safe references to
/// them through [EventRegion].
pub blocks: NonNull<EventBlock>,

/// The event worlds. Only one is active at a time.
pub worlds: [EventWorld; 2],
Expand All @@ -210,7 +220,7 @@ pub struct FD4VirtualMemoryFlag {
/// The index of [self.current_world] in [self.worlds].
pub current_world_index: u32,

pub _unk224: u32,
_unk224: u32,

/// Whether this class's data has been initialized.
pub is_initialized: bool,
Expand Down Expand Up @@ -247,7 +257,7 @@ pub struct EventWorld {
#[repr(C)]
pub struct EventRegion {
/// A pointer to the list of event blocks that are part of this region.
pub blocks: Option<NonNull<EventBlock>>,
pub blocks: Option<OwnedPtr<EventBlock>>,

/// The length of the [blocks](Self.blocks) array.
pub blocks_length: u32,
Expand All @@ -259,6 +269,7 @@ impl EventRegion {
/// Returns the list of blocks that belong to this region.
pub fn blocks(&self) -> &[EventBlock] {
self.blocks
.as_ref()
.map(|blocks| unsafe {
slice::from_raw_parts(blocks.as_ptr(), self.blocks_length as usize)
})
Expand All @@ -268,7 +279,8 @@ impl EventRegion {
/// Returns the mutable list of blocks that belong to this region.
pub fn blocks_mut(&mut self) -> &mut [EventBlock] {
self.blocks
.map(|mut blocks| unsafe {
.as_mut()
.map(|blocks| unsafe {
slice::from_raw_parts_mut(blocks.as_mut(), self.blocks_length as usize)
})
.unwrap_or_default()
Expand All @@ -283,22 +295,10 @@ pub struct EventBlock {

#[repr(C)]
pub struct EventZone {
pub words: NonNull<[u32; 32]>,
pub words: OwnedPtr<[u32; 32]>,
_unka0: u64,
}

impl EventZone {
/// The words in this zone.
pub fn words(&self) -> &[u32] {
unsafe { self.words.as_ref() }
}

/// The mutable words in this zone.
pub fn words_mut(&mut self) -> &mut [u32] {
unsafe { self.words.as_mut() }
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
14 changes: 4 additions & 10 deletions crates/darksouls3/src/sprj/field_area.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
use std::{borrow::Cow, ptr::NonNull};

use super::WorldRes;
use super::WorldInfoOwner;
use crate::rva;
use shared::{FromStatic, InstanceResult};
use shared::*;

#[repr(C)]
pub struct FieldArea {
_vftable: usize,

pub world_res: Option<NonNull<WorldRes>>,
pub world_info_owner: OwnedPtr<WorldInfoOwner>,

_world_res_2: Option<NonNull<WorldRes>>, // Always the same as [world_res], apparently
_world_info_owner_2: NonNull<WorldInfoOwner>, // Always the same as [world_info_owner], apparently

_game_rend: u64,
_unk20: u32,
Expand All @@ -25,12 +25,6 @@ pub struct FieldArea {
_unke8: [u8; 8],
}

impl FieldArea {
pub fn world_res(&self) -> Option<&WorldRes> {
self.world_res.map(|ptr| unsafe { ptr.as_ref() })
}
}

impl FromStatic for FieldArea {
fn name() -> Cow<'static, str> {
"FieldArea".into()
Expand Down
75 changes: 49 additions & 26 deletions crates/darksouls3/src/sprj/world_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ use std::{mem::MaybeUninit, ptr::NonNull, slice};

use bitfield::bitfield;

use shared::UnknownStruct;
use shared::*;

#[repr(C)]
#[derive(Superclass)]
#[superclass(children(WorldRes))]
/// Source of name: RTTI
pub struct WorldInfo {
_vftable: usize,
Expand Down Expand Up @@ -35,7 +37,8 @@ pub struct WorldInfo {
/// Use [Self::block_info] to access this safely.
pub world_block_info_list_ptr: NonNull<WorldBlockInfo>,

_unk28: u8,
/// This name comes from debug data, but the behavior isn't yet well-understood.
pub is_lock: bool,

/// The pool of [WorldAreaInfo]s. Only the first
/// [world_area_info_len](Self::world_area_info_len) are initialized.
Expand Down Expand Up @@ -92,13 +95,42 @@ impl WorldInfo {
)
}
}

/// The currently initialized area infos and their corresponding block
/// infos.
pub fn area_and_block_info(&self) -> impl Iterator<Item = (&WorldAreaInfo, &[WorldBlockInfo])> {
self.area_info().iter().map(|area| {
// Safety: We know there isn't a mutable reference to the block
// info because it's owned by this WorldInfo to which we have an
// immutable reference.
(area, unsafe {
slice::from_raw_parts(area.block_info.as_ptr(), area.block_info_length as usize)
})
})
}

/// The mutable currently initialized area infos and their corresponding
/// block infos.
pub fn area_and_block_info_mut(
&mut self,
) -> impl Iterator<Item = (&mut WorldAreaInfo, &mut [WorldBlockInfo])> {
self.area_info_mut().iter_mut().map(|area| {
// Safety: We know there aren't any other references to the block
// info because it's owned by this WorldInfo to which we have a
// mutable reference.
let blocks = unsafe {
slice::from_raw_parts_mut(area.block_info.as_mut(), area.block_info_length as usize)
};
(area, blocks)
})
}
}

#[repr(C)]
/// Source of name: RTTI
pub struct WorldAreaInfo {
_vftable: usize,
_pad08: [u8; 3],
_unk08: [u8; 3],

/// The area's numeric identifier.
///
Expand All @@ -108,30 +140,20 @@ pub struct WorldAreaInfo {
/// The [WorldInfo] instance that owns this area.
pub owner: NonNull<WorldInfo>,

_unk18: u32,
_unk1c: u32,
/// The index of this area in [WorldInfo::world_area_info].
pub world_area_index: u32,

/// The index of this area's first block in [WorldInfo::world_block_info].
pub world_block_index: u32,

/// The length of the [block_info](Self::block_info) array.
pub block_info_length: u32,

/// The block infos for this [WorldAreaInfo].
pub block_info: NonNull<WorldBlockInfo>,

_unk30: u8,
}

impl WorldAreaInfo {
/// The block infos for this [WorldAreaInfo].
pub fn block_info(&self) -> &[WorldBlockInfo] {
unsafe { slice::from_raw_parts(self.block_info.as_ptr(), self.block_info_length as usize) }
}

/// The mutable block infos for this [WorldAreaInfo].
pub fn block_info_mut(&mut self) -> &mut [WorldBlockInfo] {
unsafe {
slice::from_raw_parts_mut(self.block_info.as_mut(), self.block_info_length as usize)
}
}
/// This name comes from debug data, but the behavior isn't yet well-understood.
pub is_lock: bool,
}

bitfield! {
Expand Down Expand Up @@ -159,7 +181,7 @@ pub struct WorldBlockInfo {
pub owner: NonNull<WorldInfo>,

/// The [WorldAreaInfo] that contains this block.
pub world_area_info: Option<NonNull<WorldAreaInfo>>,
pub world_area_info: NonNull<WorldAreaInfo>,

/// The index of this in [WorldInfo.world_block_info].
///
Expand All @@ -182,9 +204,10 @@ pub struct WorldBlockInfo {
}

#[repr(C)]
#[derive(Subclass)]
/// Source of name: RTTI
pub struct WorldInfoOwner {
pub super_world_info: WorldInfo,
pub struct WorldRes {
pub world_info: WorldInfo,
_unk8: u64,

/// The number of defined entries in [world_area_res](Self::world_area_res).
Expand Down Expand Up @@ -269,8 +292,8 @@ impl WorldRes {
}
}

// WorldRes doesn't add any additional fields.
pub type WorldRes = WorldInfoOwner;
// WorldInfoOwner doesn't add any additional fields.
pub type WorldInfoOwner = WorldRes;

// Source of name: RTTI
pub type WorldAreaRes = UnknownStruct<0x108>;
Expand All @@ -287,6 +310,6 @@ mod test {
assert_eq!(0x38, size_of::<WorldAreaInfo>());
assert_eq!(0x70, size_of::<WorldBlockInfo>());
assert_eq!(0x1298, size_of::<WorldInfo>());
assert_eq!(0xae90, size_of::<WorldInfoOwner>());
assert_eq!(0xae90, size_of::<WorldRes>());
}
}
12 changes: 12 additions & 0 deletions crates/sekiro/mapper-profile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ vftable = "param_res_cap_vmt"
class = "NS_SPRJ::SoloParamRepositoryImp"
vftable = "solo_param_repository_vmt"

[[vmts]]
class = "NS_SPRJ::WorldInfo"
vftable = "world_info_vmt"

[[vmts]]
class = "NS_SPRJ::WorldRes"
vftable = "world_res_vmt"

[[patterns]]
pattern = "48 83 ec 20 48 8d 05 ${ ' } 48 8b f9 48 89 01 48 8b ca 48 8b 02 ff 50 10"
captures = ["", "fd4res_cap_vmt"]
Expand All @@ -34,6 +42,10 @@ captures = ["", "fd4res_cap_vmt"]
pattern = "c6 47 60 00 48 8d 05 $ { ' } 48 89 07 33 f6 48 89 77 68 48 89 77 70 48 89 77 78"
captures = ["", "fd4param_res_cap_vmt"]

[[patterns]]
pattern = "0f 29 74 24 30 40 80 fe 01 0f ? ? ? ? ? 48 8b 05 $ { ' }"
captures = ["", "field_area_ptr"]

[[patterns]]
pattern = "c7 44 24 20 00 00 00 00 48 8b 05 $ { ' } 48 8b 58 08 8b 02"
captures = ["", "game_data_man_ptr"]
Expand Down
Loading