1
0
mirror of https://git.ngram.ca/OpenJam/rc-servers synced 2026-08-23 23:08:52 +00:00

Add basic currency support and plumb multiplayer rewards screen #70

This commit is contained in:
NG (Graham)
2025-12-28 18:13:14 -05:00
parent 5e05cbdb59
commit 4ec64a9cd9
26 changed files with 802 additions and 48 deletions

View File

@@ -115,6 +115,7 @@ impl Location {
}
pub(super) struct UserData {
pub score_id: std::sync::atomic::AtomicI64,
pub kills: std::sync::atomic::AtomicU32,
pub deaths: std::sync::atomic::AtomicU32,
pub assists: std::sync::atomic::AtomicU32,
@@ -130,6 +131,7 @@ pub(super) struct UserData {
impl UserData {
fn new() -> Self {
Self {
score_id: std::sync::atomic::AtomicI64::new(i64::MIN),
kills: std::sync::atomic::AtomicU32::new(0),
deaths: std::sync::atomic::AtomicU32::new(0),
assists: std::sync::atomic::AtomicU32::new(0),
@@ -173,6 +175,23 @@ impl UserData {
delta_score: delta.unwrap_or(backup_delta),
}
}
fn as_core(&self) -> oj_rc_core::persist::user::PlayerScore {
let id_maybe = self.score_id.load(std::sync::atomic::Ordering::Relaxed);
oj_rc_core::persist::user::PlayerScore {
id: id_maybe.try_into().ok(),
kills: self.kills.load(std::sync::atomic::Ordering::Relaxed),
deaths: self.deaths.load(std::sync::atomic::Ordering::Relaxed),
assists: self.assists.load(std::sync::atomic::Ordering::Relaxed),
heal_assists: self.heal_assists.load(std::sync::atomic::Ordering::Relaxed),
healed: self.healed.load(std::sync::atomic::Ordering::Relaxed),
received_healed: self.received_healed.load(std::sync::atomic::Ordering::Relaxed),
damaged: self.cubes.load(std::sync::atomic::Ordering::Relaxed),
received_damaged: self.received_cubes.load(std::sync::atomic::Ordering::Relaxed),
crystals: self.crystals.load(std::sync::atomic::Ordering::Relaxed),
total: self.generic_score(),
}
}
}
#[repr(u8)]
@@ -521,6 +540,9 @@ impl <L: super::CustomGameLogic> GenericGamemodeEngine<L> {
).await);
log::debug!("User {} is validated to play game {}", new_user.user.user_id(), game_guid);
let new_user = std::sync::Arc::new(new_user);
if let Err(e) = new_user.user.save_player_connected_status(self.game_guid(), true).await {
log::error!("Failed to mark player {} (user {}) as connected to game {}: {}", id, user_id, self.game_guid(), e);
}
let mut users = self.users.write().await;
users.insert(id, new_user.clone());
for fake_id in new_user.aliases.iter() {
@@ -558,17 +580,16 @@ impl <L: super::CustomGameLogic> GenericGamemodeEngine<L> {
}
}
let is_game_complete = self.is_complete.load(std::sync::atomic::Ordering::Relaxed);
for disconnecter in disconnecting_players {
if !is_game_complete {
self.broadcast(
rlnl::event_code::NetworkEvent::OnAnotherClientDisconnected,
literustlib::packet::Property::ReliableOrdered,
&rlnl::events::ingame::PlayerId { player: disconnecter },
true,
).await;
}
}
if is_game_complete {
// save score to database as they disconnect
// this happens before they return to the main menu
let scores = user_info.counters.as_core();
match conn.user.update_game_score(self.game_guid(), scores).await {
Ok(score_id) => user_info.counters.score_id.store(score_id as i64, std::sync::atomic::Ordering::Relaxed),
Err(e) => {
log::warn!("Failed to save score for player {} (user {}) after end of game {}: {}", player_id, user_id, self.game_guid(), e);
},
}
// in every other case this packet would've already been sent
// this makes the end-of-match "continue" button send you back to the main menu a bit sooner
// (otherwise it waits for the multiplayer server to disconnect via timeout)
@@ -577,6 +598,15 @@ impl <L: super::CustomGameLogic> GenericGamemodeEngine<L> {
literustlib::packet::Property::ReliableOrdered,
&conn.connection.connection,
).await);
} else {
for disconnecter in disconnecting_players {
self.broadcast(
rlnl::event_code::NetworkEvent::OnAnotherClientDisconnected,
literustlib::packet::Property::ReliableOrdered,
&rlnl::events::ingame::PlayerId { player: disconnecter },
true,
).await;
}
}
let mut has_active_connections = false;
@@ -594,6 +624,9 @@ impl <L: super::CustomGameLogic> GenericGamemodeEngine<L> {
}
}
}
if let Err(e) = conn.user.save_player_connected_status(self.game_guid(), false).await {
log::error!("Failed to mark player {} (user {}) as disconnected in game {}: {}", player_id, user_id, self.game_guid(), e);
}
conn.connection.connection.goodbye(&conn.connection.sender).await;
return has_active_connections;
}