Somehow I managed to make a vtable correctly

This commit is contained in:
Artemis Tosini 2024-04-24 06:26:02 +00:00
parent ca5ff139ac
commit 164d6409db
Signed by: artemist
GPG key ID: EE5227935FE3FF18
7 changed files with 439 additions and 13 deletions

46
Cargo.lock generated
View file

@ -65,6 +65,16 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "ctor"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "env_filter"
version = "0.1.0"
@ -106,6 +116,24 @@ version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
[[package]]
name = "proc-macro2"
version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.10.4"
@ -135,6 +163,23 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
[[package]]
name = "syn"
version = "2.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "utf8parse"
version = "0.2.1"
@ -145,6 +190,7 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
name = "vapore-client"
version = "0.0.0"
dependencies = [
"ctor",
"env_logger",
"log",
]

View file

@ -6,5 +6,6 @@ edition = "2021"
crate-type = ["cdylib"]
[dependencies]
log = "0.4"
ctor = "0.2"
env_logger = "0.11"
log = "0.4"

23
client/src/abi/mod.rs Normal file
View file

@ -0,0 +1,23 @@
pub mod steam_client;
pub use steam_client::*;
pub mod steam_utils;
pub use steam_utils::*;
pub type SteamPipe = i32;
pub type SteamUser = i32;
#[repr(u32)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum AccountType {
Invalid = 0,
Individual = 1,
Multiseat = 2,
GameServer = 3,
AnonGameServer = 4,
Pending = 5,
ContentServer = 6,
Clan = 7,
Chat = 8,
ConsoleUser = 9,
AnonUser = 10,
}

View file

@ -0,0 +1,276 @@
#![allow(non_snake_case)]
use std::ffi::{c_char, c_void, CStr};
use std::ptr;
use log::warn;
use super::{AccountType, ISteamUtils, SteamPipe, SteamUser};
/// The initial steam interface from CreateInterface
#[repr(C)]
pub struct ISteamClient {
pub vtbl: ISteamClientVtbl,
pub version: u32,
}
impl ISteamClient {
pub fn new(version: &CStr) -> Option<Box<Self>> {
let (vtbl, version) = match version.to_bytes() {
b"SteamClient017" => (
ISteamClientVtbl {
ver017: &STEAM_CLIENT_017_VTBL_DEFAULT as *const ISteamClient017Vtbl,
},
17,
),
b"SteamClient020" => (
ISteamClientVtbl {
ver020: &STEAM_CLIENT_020_VTBL_DEFAULT as *const ISteamClient020Vtbl,
},
20,
),
_ => return None,
};
Some(Box::new(Self { vtbl, version }))
}
}
/// Vtable for any version of steam client
#[repr(C)]
pub union ISteamClientVtbl {
pub ver017: *const ISteamClient017Vtbl,
pub ver020: *const ISteamClient020Vtbl,
}
/// Vtable for SteamClient017
#[repr(C)]
pub struct ISteamClient017Vtbl {
pub CreateSteamPipe: extern "C" fn(self_ptr: *mut ISteamClient) -> SteamPipe,
pub BReleaseSteamPipe: extern "C" fn(self_ptr: *mut ISteamClient, pipe: SteamPipe) -> bool,
pub ConnectToGlobalUser:
extern "C" fn(self_ptr: *mut ISteamClient, pipe: SteamPipe) -> SteamUser,
pub CreateLocalUser: extern "C" fn(
self_ptr: *mut ISteamClient,
pipe: *const SteamPipe,
account_type: AccountType,
) -> SteamUser,
pub ReleaseUser: *const c_void,
pub GetISteamUser: *const c_void,
pub GetISteamGameServer: *const c_void,
pub SetLocalIPBinding: *const c_void,
pub GetISteamFriends: *const c_void,
pub GetISteamUtils: extern "C" fn(
self_ptr: *mut ISteamClient,
pipe: SteamPipe,
version: *const c_char,
) -> *const ISteamUtils,
pub GetISteamMatchmaking: *const c_void,
pub GetISteamMatchmakingServers: *const c_void,
pub GetISteamGenericInterface: *const c_void,
pub GetISteamUserStats: *const c_void,
pub GetISteamGameServerStats: *const c_void,
pub GetISteamApps: *const c_void,
pub GetISteamNetworking: *const c_void,
pub GetISteamRemoteStorage: *const c_void,
pub GetISteamScreenshots: *const c_void,
pub RunFrame: *const c_void,
pub GetIPCCallCount: *const c_void,
pub SetWarningMessageHook: *const c_void,
pub BShutdownIfAllPipesClosed: *const c_void,
pub GetISteamHTTP: *const c_void,
pub DEPRECATED_GetISteamUnifiedMessages: *const c_void,
pub GetISteamController: *const c_void,
pub GetISteamUGC: *const c_void,
pub GetISteamAppList: *const c_void,
pub GetISteamMusic: *const c_void,
pub GetISteamMusicRemote: *const c_void,
pub GetISteamHTMLSurface: *const c_void,
pub DEPRECATED_Set_SteamAPI_CPostAPIResultInProcess: *const c_void,
pub DEPRECATED_Remove_SteamAPI_CPostAPIResultInProcess: *const c_void,
pub Set_SteamAPI_CCheckCallbackRegisteredInProcess: *const c_void,
pub GetISteamInventory: *const c_void,
pub GetISteamVideo: *const c_void,
pub GetISteamParentalSettings: *const c_void,
}
const STEAM_CLIENT_017_VTBL_DEFAULT: ISteamClient017Vtbl = ISteamClient017Vtbl {
CreateSteamPipe,
BReleaseSteamPipe,
ConnectToGlobalUser,
CreateLocalUser,
ReleaseUser: ptr::null(),
GetISteamUser: ptr::null(),
GetISteamGameServer: ptr::null(),
SetLocalIPBinding: ptr::null(),
GetISteamFriends: ptr::null(),
GetISteamUtils,
GetISteamMatchmaking: ptr::null(),
GetISteamMatchmakingServers: ptr::null(),
GetISteamGenericInterface: ptr::null(),
GetISteamUserStats: ptr::null(),
GetISteamGameServerStats: ptr::null(),
GetISteamApps: ptr::null(),
GetISteamNetworking: ptr::null(),
GetISteamRemoteStorage: ptr::null(),
GetISteamScreenshots: ptr::null(),
RunFrame: ptr::null(),
GetIPCCallCount: ptr::null(),
SetWarningMessageHook: ptr::null(),
BShutdownIfAllPipesClosed: ptr::null(),
GetISteamHTTP: ptr::null(),
DEPRECATED_GetISteamUnifiedMessages: ptr::null(),
GetISteamController: ptr::null(),
GetISteamUGC: ptr::null(),
GetISteamAppList: ptr::null(),
GetISteamMusic: ptr::null(),
GetISteamMusicRemote: ptr::null(),
GetISteamHTMLSurface: ptr::null(),
DEPRECATED_Set_SteamAPI_CPostAPIResultInProcess: ptr::null(),
DEPRECATED_Remove_SteamAPI_CPostAPIResultInProcess: ptr::null(),
Set_SteamAPI_CCheckCallbackRegisteredInProcess: ptr::null(),
GetISteamInventory: ptr::null(),
GetISteamVideo: ptr::null(),
GetISteamParentalSettings: ptr::null(),
};
/// Vtable for SteamClient020
#[repr(C)]
pub struct ISteamClient020Vtbl {
pub CreateSteamPipe: extern "C" fn(self_ptr: *mut ISteamClient) -> SteamPipe,
pub BReleaseSteamPipe: extern "C" fn(self_ptr: *mut ISteamClient, pipe: SteamPipe) -> bool,
pub ConnectToGlobalUser:
extern "C" fn(self_ptr: *mut ISteamClient, pipe: SteamPipe) -> SteamUser,
pub CreateLocalUser: extern "C" fn(
self_ptr: *mut ISteamClient,
pipe: *const SteamPipe,
account_type: AccountType,
) -> SteamUser,
pub ReleaseUser: *const c_void,
pub GetISteamUser: *const c_void,
pub GetISteamGameServer: *const c_void,
pub SetLocalIPBinding: *const c_void,
pub GetISteamFriends: *const c_void,
pub GetISteamUtils: extern "C" fn(
self_ptr: *mut ISteamClient,
pipe: SteamPipe,
version: *const c_char,
) -> *const ISteamUtils,
pub GetISteamMatchmaking: *const c_void,
pub GetISteamMatchmakingServers: *const c_void,
pub GetISteamGenericInterface: *const c_void,
pub GetISteamUserStats: *const c_void,
pub GetISteamGameServerStats: *const c_void,
pub GetISteamApps: *const c_void,
pub GetISteamNetworking: *const c_void,
pub GetISteamRemoteStorage: *const c_void,
pub GetISteamScreenshots: *const c_void,
pub GetISteamGameSearch: *const c_void,
pub RunFrame: *const c_void,
pub GetIPCCallCount: *const c_void,
pub SetWarningMessageHook: *const c_void,
pub BShutdownIfAllPipesClosed: *const c_void,
pub GetISteamHTTP: *const c_void,
pub DEPRECATED_GetISteamUnifiedMessages: *const c_void,
pub GetISteamController: *const c_void,
pub GetISteamUGC: *const c_void,
pub GetISteamAppList: *const c_void,
pub GetISteamMusic: *const c_void,
pub GetISteamMusicRemote: *const c_void,
pub GetISteamHTMLSurface: *const c_void,
pub DEPRECATED_Set_SteamAPI_CPostAPIResultInProcess: *const c_void,
pub DEPRECATED_Remove_SteamAPI_CPostAPIResultInProcess: *const c_void,
pub Set_SteamAPI_CCheckCallbackRegisteredInProcess: *const c_void,
pub GetISteamInventory: *const c_void,
pub GetISteamVideo: *const c_void,
pub GetISteamParentalSettings: *const c_void,
pub GetISteamInput: *const c_void,
pub GetISteamParties: *const c_void,
pub GetISteamRemotePlay: *const c_void,
pub DestroyAllInterfaces: *const c_void,
}
const STEAM_CLIENT_020_VTBL_DEFAULT: ISteamClient020Vtbl = ISteamClient020Vtbl {
CreateSteamPipe,
BReleaseSteamPipe,
ConnectToGlobalUser,
CreateLocalUser,
ReleaseUser: ptr::null(),
GetISteamUser: ptr::null(),
GetISteamGameServer: ptr::null(),
SetLocalIPBinding: ptr::null(),
GetISteamFriends: ptr::null(),
GetISteamUtils,
GetISteamMatchmaking: ptr::null(),
GetISteamMatchmakingServers: ptr::null(),
GetISteamGenericInterface: ptr::null(),
GetISteamUserStats: ptr::null(),
GetISteamGameServerStats: ptr::null(),
GetISteamApps: ptr::null(),
GetISteamNetworking: ptr::null(),
GetISteamRemoteStorage: ptr::null(),
GetISteamScreenshots: ptr::null(),
GetISteamGameSearch: ptr::null(),
RunFrame: ptr::null(),
GetIPCCallCount: ptr::null(),
SetWarningMessageHook: ptr::null(),
BShutdownIfAllPipesClosed: ptr::null(),
GetISteamHTTP: ptr::null(),
DEPRECATED_GetISteamUnifiedMessages: ptr::null(),
GetISteamController: ptr::null(),
GetISteamUGC: ptr::null(),
GetISteamAppList: ptr::null(),
GetISteamMusic: ptr::null(),
GetISteamMusicRemote: ptr::null(),
GetISteamHTMLSurface: ptr::null(),
DEPRECATED_Set_SteamAPI_CPostAPIResultInProcess: ptr::null(),
DEPRECATED_Remove_SteamAPI_CPostAPIResultInProcess: ptr::null(),
Set_SteamAPI_CCheckCallbackRegisteredInProcess: ptr::null(),
GetISteamInventory: ptr::null(),
GetISteamVideo: ptr::null(),
GetISteamParentalSettings: ptr::null(),
GetISteamInput: ptr::null(),
GetISteamParties: ptr::null(),
GetISteamRemotePlay: ptr::null(),
DestroyAllInterfaces: ptr::null(),
};
extern "C" fn CreateSteamPipe(self_ptr: *mut ISteamClient) -> SteamPipe {
warn!("STUB: ISteamClient::CreateSteamPipe({:?})", self_ptr);
0
}
extern "C" fn BReleaseSteamPipe(self_ptr: *mut ISteamClient, pipe: SteamPipe) -> bool {
warn!(
"STUB: ISteamClient::BReleaseSteamPipe({:?}, {})",
self_ptr, pipe
);
false
}
extern "C" fn ConnectToGlobalUser(self_ptr: *mut ISteamClient, pipe: SteamPipe) -> SteamUser {
warn!(
"STUB: ISteamClient::ConnectToGlobalUser({:?}, {})",
self_ptr, pipe
);
0
}
extern "C" fn CreateLocalUser(
self_ptr: *mut ISteamClient,
pipe: *const SteamPipe,
account_type: AccountType,
) -> SteamUser {
warn!(
"STUB: ISteamClient::CreateLocalUser({:?}, {:?}, {:?})",
self_ptr, pipe, account_type
);
0
}
extern "C" fn GetISteamUtils(
self_ptr: *mut ISteamClient,
pipe: SteamPipe,
version: *const c_char,
) -> *const ISteamUtils {
warn!(
"STUB: ISteamClient::GetISteamUtils({:?}, {}, {:?})",
self_ptr, pipe, version
);
ptr::null()
}

View file

@ -0,0 +1,59 @@
#![allow(non_snake_case)]
use std::ffi::c_void;
/// Various weird steam utility functions
#[repr(C)]
pub struct ISteamUtils {
pub vtbl: ISteamUtilsVtbl,
pub version: u32,
}
/// Vtable for any version of SteamUtils
#[repr(C)]
pub union ISteamUtilsVtbl {
pub ver017: *const ISteamUtils010Vtbl,
}
/// Vtable for ISteamUtils010
#[repr(C)]
pub struct ISteamUtils010Vtbl {
pub GetSecondsSinceAppActive: *const c_void,
pub GetSecondsSinceComputerActive: *const c_void,
pub GetConnectedUniverse: *const c_void,
pub GetServerRealTime: *const c_void,
pub GetIPCountry: *const c_void,
pub GetImageSize: *const c_void,
pub GetImageRGBA: *const c_void,
pub GetCSERIPPort: *const c_void,
pub GetCurrentBatteryPower: *const c_void,
pub GetAppID: *const c_void,
pub SetOverlayNotificationPosition: *const c_void,
pub IsAPICallCompleted: *const c_void,
pub GetAPICallFailureReason: *const c_void,
pub GetAPICallResult: *const c_void,
pub RunFrame: *const c_void,
pub GetIPCCallCount: *const c_void,
pub SetWarningMessageHook: *const c_void,
pub IsOverlayEnabled: *const c_void,
pub BOverlayNeedsPresent: *const c_void,
pub CheckFileSignature: *const c_void,
pub ShowGamepadTextInput: *const c_void,
pub GetEnteredGamepadTextLength: *const c_void,
pub GetEnteredGamepadTextInput: *const c_void,
pub GetSteamUILanguage: *const c_void,
pub IsSteamRunningInVR: *const c_void,
pub SetOverlayNotificationInset: *const c_void,
pub IsSteamInBigPictureMode: *const c_void,
pub StartVRDashboard: *const c_void,
pub IsVRHeadsetStreamingEnabled: *const c_void,
pub SetVRHeadsetStreamingEnabled: *const c_void,
pub IsSteamChinaLauncher: *const c_void,
pub InitFilterText: *const c_void,
pub FilterText: *const c_void,
pub GetIPv6ConnectivityState: *const c_void,
pub IsSteamRunningOnSteamDeck: *const c_void,
pub ShowFloatingGamepadTextInput: *const c_void,
pub SetGameLauncherMode: *const c_void,
pub DismissFloatingGamepadTextInput: *const c_void,
pub DismissGamepadTextInput: *const c_void,
}

View file

@ -1,14 +1,7 @@
pub fn add(left: usize, right: usize) -> usize {
left + right
}
pub mod abi;
pub mod loader;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
#[ctor::ctor]
fn init() {
env_logger::init();
}

28
client/src/loader.rs Normal file
View file

@ -0,0 +1,28 @@
use std::{
ffi::{c_char, CStr},
ptr,
};
use log::trace;
use crate::abi::ISteamClient;
/// Lookup a new interface, should be the first function called
/// # Safety
/// version_ptr must be null or a null-terminated string
#[no_mangle]
pub unsafe extern "C" fn CreateInterface(version_ptr: *const c_char) -> *const ISteamClient {
if version_ptr.is_null() {
trace!("CreateInterface(nullptr)");
return ptr::null();
}
// SAFETY: We already know it's not null, there's not much else we can do
let version = unsafe { CStr::from_ptr(version_ptr) };
trace!("CreateInterface({:?})", version);
match ISteamClient::new(version) {
// TODO: figure out how the hell to deallocate this
Some(bx) => Box::leak(bx),
None => ptr::null(),
}
}