99 lines
2.5 KiB
Rust
99 lines
2.5 KiB
Rust
use std::{
|
|
ffi::{CStr, c_char},
|
|
fs::File,
|
|
};
|
|
|
|
use bincode::{Decode, Encode};
|
|
|
|
#[derive(Decode, Encode, Clone)]
|
|
#[repr(C)]
|
|
pub struct PlayerStat {
|
|
kills: u32,
|
|
deaths: u32,
|
|
team_damage: u32,
|
|
}
|
|
|
|
#[derive(Decode, Encode, Clone, Default)]
|
|
#[repr(C)]
|
|
pub struct ItemStat {
|
|
item_name: String,
|
|
item_count: u32,
|
|
}
|
|
|
|
#[derive(Decode, Encode, Clone)]
|
|
#[repr(C)]
|
|
pub struct Player {
|
|
player_id: String,
|
|
player_stats: PlayerStat,
|
|
player_items: [ItemStat; 256],
|
|
}
|
|
|
|
impl Default for Player {
|
|
fn default() -> Self {
|
|
Self {
|
|
player_id: String::new(),
|
|
player_stats: PlayerStat {
|
|
kills: 0,
|
|
deaths: 0,
|
|
team_damage: 0,
|
|
},
|
|
player_items: std::array::from_fn(|_| ItemStat::default()),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
/// # Safety
|
|
/// `player_id` must be a valid, null-terminated C string pointer.
|
|
pub unsafe extern "C" fn get_player_stats(player_id: *const c_char) -> *const Player {
|
|
let player_id = unsafe { CStr::from_ptr(player_id) }
|
|
.to_string_lossy()
|
|
.into_owned();
|
|
|
|
let db_location = "./stats.data";
|
|
|
|
let player_stats: Vec<Player> = match File::open(db_location) {
|
|
Ok(mut data) => bincode::decode_from_std_read(&mut data, bincode::config::standard())
|
|
.unwrap_or_default(),
|
|
Err(_) => Vec::new(),
|
|
};
|
|
|
|
player_stats
|
|
.iter()
|
|
.find(|p| p.player_id == player_id)
|
|
.unwrap_or(&Player::default())
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
/// # Safety
|
|
/// `player` must be a valid pointer to a `Player` struct.
|
|
pub unsafe extern "C" fn save_player_stats(player: *const Player) -> bool {
|
|
let player = unsafe { &*player };
|
|
let db_location = "./stats.data";
|
|
|
|
let mut player_stats: Vec<Player> = match File::open(db_location) {
|
|
Ok(mut data) => bincode::decode_from_std_read(&mut data, bincode::config::standard())
|
|
.unwrap_or_default(),
|
|
Err(_) => Vec::new(),
|
|
};
|
|
|
|
// Find and update existing player or add new player
|
|
if let Some(existing_player) = player_stats
|
|
.iter_mut()
|
|
.find(|p| p.player_id == player.player_id)
|
|
{
|
|
*existing_player = player.clone();
|
|
} else {
|
|
player_stats.push(player.clone());
|
|
}
|
|
|
|
// Save updated stats
|
|
match File::create(db_location) {
|
|
Ok(mut file) => {
|
|
bincode::encode_into_std_write(&player_stats, &mut file, bincode::config::standard())
|
|
.is_ok()
|
|
}
|
|
Err(_) => false,
|
|
}
|
|
}
|