arcdps/
globals.rs
1use crate::{
4 exports::{
5 has_e3_log_file, has_e8_log_window, log_to_file, log_to_window,
6 raw::{
7 Export0, Export10, Export3, Export5, Export6, Export7, Export8, Export9,
8 ExportAddExtension, ExportFreeExtension, ExportListExtension,
9 },
10 },
11 imgui,
12 util::{exported_proc, Share},
13};
14use std::{
15 ffi::c_void,
16 mem::transmute,
17 ptr::{self, NonNull},
18 sync::{
19 atomic::{AtomicU32, Ordering},
20 OnceLock,
21 },
22};
23use windows::{
24 core::Interface,
25 Win32::{
26 Foundation::HMODULE,
27 Graphics::{Direct3D11::ID3D11Device, Dxgi::IDXGISwapChain},
28 },
29};
30
31pub static ARC_GLOBALS: OnceLock<ArcGlobals> = OnceLock::new();
33
34#[derive(Debug)]
37pub struct ArcGlobals {
38 pub handle: HMODULE,
40
41 pub version: Option<&'static str>,
43
44 pub e0: Option<Export0>,
46
47 pub e3: Option<Export3>,
49
50 pub e5: Option<Export5>,
52
53 pub e6: Option<Export6>,
55
56 pub e7: Option<Export7>,
58
59 pub e8: Option<Export8>,
61
62 pub e9: Option<Export9>,
64
65 pub e10: Option<Export10>,
67
68 pub add_extension: Option<ExportAddExtension>,
70
71 pub free_extension: Option<ExportFreeExtension>,
73
74 pub list_extension: Option<ExportListExtension>,
76}
77
78impl ArcGlobals {
79 pub unsafe fn new(handle: HMODULE, version: Option<&'static str>) -> Self {
81 #![allow(clippy::missing_transmute_annotations)]
82 Self {
83 handle,
84 version,
85 e0: transmute(exported_proc(handle, "e0\0")),
86 e3: transmute(exported_proc(handle, "e3\0")),
87 e5: transmute(exported_proc(handle, "e5\0")),
88 e6: transmute(exported_proc(handle, "e6\0")),
89 e7: transmute(exported_proc(handle, "e7\0")),
90 e8: transmute(exported_proc(handle, "e8\0")),
91 e9: transmute(exported_proc(handle, "e9\0")),
92 e10: transmute(exported_proc(handle, "e10\0")),
93 add_extension: transmute(exported_proc(handle, "addextension2\0")),
94 free_extension: transmute(exported_proc(handle, "freeextension2\0")),
95 list_extension: transmute(exported_proc(handle, "listextension\0")),
96 }
97 }
98
99 pub unsafe fn init(handle: HMODULE, version: Option<&'static str>) -> &'static Self {
101 ARC_GLOBALS.get_or_init(|| Self::new(handle, version))
102 }
103
104 #[inline]
106 pub fn get() -> &'static Self {
107 Self::try_get().expect("arcdps globals not initialized")
108 }
109
110 #[inline]
112 pub fn try_get() -> Option<&'static Self> {
113 ARC_GLOBALS.get()
114 }
115}
116
117unsafe impl Send for ArcGlobals {}
118
119unsafe impl Sync for ArcGlobals {}
120
121pub type MallocFn = unsafe extern "C" fn(size: usize, user_data: *mut c_void) -> *mut c_void;
122
123pub type FreeFn = unsafe extern "C" fn(ptr: *mut c_void, user_data: *mut c_void);
124
125pub static IG_CONTEXT: OnceLock<Share<imgui::Context>> = OnceLock::new();
127
128pub unsafe fn init_imgui(
130 ctx: *mut imgui::sys::ImGuiContext,
131 malloc: Option<MallocFn>,
132 free: Option<FreeFn>,
133) {
134 imgui::sys::igSetCurrentContext(ctx);
135 imgui::sys::igSetAllocatorFunctions(malloc, free, ptr::null_mut());
136 IG_CONTEXT.get_or_init(|| Share(imgui::Context::current()));
137}
138
139pub static D3D_VERSION: AtomicU32 = AtomicU32::new(0);
141
142#[inline]
146pub fn d3d_version() -> u32 {
147 D3D_VERSION.load(Ordering::Relaxed)
148}
149
150pub static DXGI_SWAP_CHAIN: OnceLock<Share<NonNull<c_void>>> = OnceLock::new();
152
153#[inline]
155pub fn dxgi_swap_chain() -> Option<IDXGISwapChain> {
156 DXGI_SWAP_CHAIN.get().map(|share| {
157 unsafe { IDXGISwapChain::from_raw_borrowed(&share.0.as_ptr()) }
158 .expect("invalid swap chain")
159 .clone()
160 })
161}
162
163#[inline]
165pub fn d3d11_device() -> Option<ID3D11Device> {
166 let swap_chain = dxgi_swap_chain()?;
167 unsafe { swap_chain.GetDevice() }.ok()
168}
169
170pub unsafe fn init_dxgi(id3d: *const c_void, d3d_version: u32, name: &'static str) {
172 D3D_VERSION.store(d3d_version, Ordering::Relaxed);
173 if d3d_version == 11 {
174 if let Some(id3d) = NonNull::new(id3d.cast_mut()) {
175 let ptr = id3d.as_ptr();
176 let swap_chain =
177 unsafe { IDXGISwapChain::from_raw_borrowed(&ptr) }.expect("invalid swap chain");
178
179 if let Err(err) = swap_chain.GetDevice::<ID3D11Device>() {
180 let msg = &format!("{name} error: failed to get d3d11 device: {err}");
181 if has_e3_log_file() {
182 let _ = log_to_file(msg);
183 }
184 if has_e8_log_window() {
185 let _ = log_to_window(msg);
186 }
187 }
188
189 DXGI_SWAP_CHAIN.get_or_init(|| Share(id3d));
190 }
191 }
192}