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:
@@ -0,0 +1,56 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
pub struct Migration;
|
||||
|
||||
impl MigrationName for Migration {
|
||||
fn name(&self) -> &str {
|
||||
"m20251228_000001_create_score_table"
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
// Define how to apply this migration: Create the Scores table.
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(crate::schema::multiplayer_game_score::Entity)
|
||||
.col(
|
||||
ColumnDef::new(crate::schema::multiplayer_game_score::Column::Id)
|
||||
.integer()
|
||||
.not_null()
|
||||
.auto_increment()
|
||||
.primary_key(),
|
||||
)
|
||||
.col(ColumnDef::new(crate::schema::multiplayer_game_score::Column::PlayerId).integer().not_null())
|
||||
.foreign_key(
|
||||
ForeignKey::create()
|
||||
.name("fk-scores-player_id")
|
||||
.from(crate::schema::multiplayer_game_score::Entity, crate::schema::multiplayer_game_score::Column::PlayerId)
|
||||
.to(crate::schema::multiplayer_game_player::Entity, crate::schema::multiplayer_game_player::Column::Id),
|
||||
)
|
||||
.col(ColumnDef::new(crate::schema::multiplayer_game_score::Column::CreationTime).big_integer().not_null())
|
||||
.col(ColumnDef::new(crate::schema::multiplayer_game_score::Column::IsClaimed).boolean().default(false))
|
||||
.col(ColumnDef::new(crate::schema::multiplayer_game_score::Column::Kills).integer().default(0))
|
||||
.col(ColumnDef::new(crate::schema::multiplayer_game_score::Column::Deaths).integer().default(0))
|
||||
.col(ColumnDef::new(crate::schema::multiplayer_game_score::Column::Assists).integer().default(0))
|
||||
.col(ColumnDef::new(crate::schema::multiplayer_game_score::Column::HealAssists).integer().default(0))
|
||||
.col(ColumnDef::new(crate::schema::multiplayer_game_score::Column::Healed).integer().default(0))
|
||||
.col(ColumnDef::new(crate::schema::multiplayer_game_score::Column::ReceivedHealed).integer().default(0))
|
||||
.col(ColumnDef::new(crate::schema::multiplayer_game_score::Column::Damaged).integer().default(0))
|
||||
.col(ColumnDef::new(crate::schema::multiplayer_game_score::Column::ReceivedDamaged).integer().default(0))
|
||||
.col(ColumnDef::new(crate::schema::multiplayer_game_score::Column::Crystals).integer().default(0))
|
||||
.col(ColumnDef::new(crate::schema::multiplayer_game_score::Column::Total).integer().default(0))
|
||||
.to_owned(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
// Define how to rollback this migration: Drop the Scores table.
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.drop_table(Table::drop().table(crate::schema::multiplayer_game_score::Entity).to_owned())
|
||||
.await
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ mod m20250713_000002_create_player_table;
|
||||
mod m20250722_000001_create_game_event_table;
|
||||
mod m20250816_000001_add_fake_players;
|
||||
mod m20250918_000001_add_player_variant;
|
||||
mod m20251228_000001_create_score_table;
|
||||
|
||||
pub struct Migrator;
|
||||
|
||||
@@ -31,6 +32,7 @@ impl MigratorTrait for Migrator {
|
||||
Box::new(m20250722_000001_create_game_event_table::Migration),
|
||||
Box::new(m20250816_000001_add_fake_players::Migration),
|
||||
Box::new(m20250918_000001_add_player_variant::Migration),
|
||||
Box::new(m20251228_000001_create_score_table::Migration),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ pub mod sanction;
|
||||
pub mod multiplayer_game;
|
||||
pub mod multiplayer_game_player;
|
||||
pub mod game_event;
|
||||
pub mod multiplayer_game_score;
|
||||
|
||||
pub fn parse_int_csv(s: &str) -> Vec<u32> {
|
||||
s.split(',').filter_map(|i_as_s| {
|
||||
|
||||
@@ -31,6 +31,8 @@ pub enum Relation {
|
||||
to = "super::user::Column::Id"
|
||||
)]
|
||||
User,
|
||||
#[sea_orm(has_one = "super::multiplayer_game_score::Entity")]
|
||||
Score,
|
||||
}
|
||||
|
||||
impl Related<super::multiplayer_game::Entity> for Entity {
|
||||
@@ -45,6 +47,12 @@ impl Related<super::user::Entity> for Entity {
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::multiplayer_game_score::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Score.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
|
||||
|
||||
39
rc_database/src/schema/multiplayer_game_score.rs
Normal file
39
rc_database/src/schema/multiplayer_game_score.rs
Normal file
@@ -0,0 +1,39 @@
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "scores")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
pub player_id: i32,
|
||||
pub creation_time: i64, // seconds since unix epoch
|
||||
pub is_claimed: bool,
|
||||
pub kills: i32,
|
||||
pub deaths: i32,
|
||||
pub assists: i32,
|
||||
pub heal_assists: i32,
|
||||
pub healed: i32,
|
||||
pub received_healed: i32,
|
||||
pub damaged: i32,
|
||||
pub received_damaged: i32,
|
||||
pub crystals: i32,
|
||||
pub total: i32,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "super::multiplayer_game_player::Entity",
|
||||
from = "Column::PlayerId",
|
||||
to = "super::multiplayer_game_player::Column::Id"
|
||||
)]
|
||||
Player,
|
||||
}
|
||||
|
||||
impl Related<super::multiplayer_game_player::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Player.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
@@ -110,6 +110,35 @@ impl Database {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn update_user_aux_by_user_id_and_descriptor_custom(&self, user_id: i32, descriptor: crate::schema::user_aux::Descriptor, custom: impl (FnOnce(&crate::schema::user_aux::Model) -> Option<crate::schema::user_aux::ActiveModel>) + Send + 'static) -> Result<Option<crate::schema::user_aux::Model>, sea_orm::DbErr> {
|
||||
self.orm.transaction(|txn| {
|
||||
Box::pin(async move {
|
||||
let opt = crate::schema::user_aux::Entity::find()
|
||||
.filter(crate::schema::user_aux::Column::UserId.eq(user_id))
|
||||
.filter(crate::schema::user_aux::Column::Descriptor.eq(descriptor))
|
||||
.one(txn)
|
||||
.await?;
|
||||
|
||||
if let Some(model) = opt {
|
||||
if let Some(updated_model) = custom(&model) {
|
||||
Ok(Some(crate::schema::user_aux::Entity::update(updated_model)
|
||||
.exec(txn)
|
||||
.await?))
|
||||
} else {
|
||||
Ok(Some(model))
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
})
|
||||
}).await.map_err(|e| {
|
||||
match e {
|
||||
sea_orm::TransactionError::Connection(db) => db,
|
||||
sea_orm::TransactionError::Transaction(txn) => txn,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn perms_by_user_id(&self, user_id: i32) -> Result<Option<crate::schema::permissions::Model>, sea_orm::DbErr> {
|
||||
crate::schema::permissions::Entity::find()
|
||||
.filter(crate::schema::permissions::Column::UserId.eq(user_id))
|
||||
@@ -404,7 +433,7 @@ impl Database {
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub async fn players_by_game_id_and_completion(&self, game_id: i32) -> Result<Vec<crate::schema::multiplayer_game_player::Model>, sea_orm::DbErr> {
|
||||
pub async fn players_by_game_id(&self, game_id: i32) -> Result<Vec<crate::schema::multiplayer_game_player::Model>, sea_orm::DbErr> {
|
||||
Ok(crate::schema::multiplayer_game_player::Entity::find()
|
||||
.find_also_related(crate::schema::multiplayer_game::Entity)
|
||||
.filter(crate::schema::multiplayer_game::Column::Id.eq(game_id))
|
||||
@@ -415,11 +444,33 @@ impl Database {
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub async fn player_by_user_id_and_game_guid(&self, user_id: i32, game_guid: i64) -> Result<Option<crate::schema::multiplayer_game_player::Model>, sea_orm::DbErr> {
|
||||
Ok(crate::schema::multiplayer_game::Entity::find()
|
||||
.find_also_related(crate::schema::multiplayer_game_player::Entity)
|
||||
.filter(crate::schema::multiplayer_game::Column::Guid.eq(game_guid))
|
||||
.filter(crate::schema::multiplayer_game_player::Column::UserId.eq(user_id))
|
||||
//.order_by_asc(crate::schema::multiplayer_game::Column::CreationTime)
|
||||
.one(&self.orm)
|
||||
.await?
|
||||
.and_then(|(_, player)| player))
|
||||
}
|
||||
|
||||
pub async fn insert_players(&self, entities: Vec<crate::schema::multiplayer_game_player::ActiveModel>) -> Result<(), sea_orm::DbErr> {
|
||||
crate::schema::multiplayer_game_player::Entity::insert_many(entities.into_iter()).exec(&self.orm).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn player_claim(&self, player_id: i32, is_claimed: bool) -> Result<(), sea_orm::DbErr> {
|
||||
crate::schema::multiplayer_game_player::Entity::update(crate::schema::multiplayer_game_player::ActiveModel {
|
||||
id: sea_orm::ActiveValue::Set(player_id),
|
||||
is_claimed: sea_orm::Set(is_claimed),
|
||||
..Default::default()
|
||||
})
|
||||
.exec(&self.orm)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn game_event_at_time(&self, time: i64, variant: crate::schema::game_event::EventVariant) -> Result<Option<crate::schema::game_event::Model>, sea_orm::DbErr> {
|
||||
crate::schema::game_event::Entity::find()
|
||||
.filter(crate::schema::game_event::Column::Start.lte(time))
|
||||
@@ -434,6 +485,53 @@ impl Database {
|
||||
entity.insert(&self.orm).await
|
||||
}
|
||||
|
||||
pub async fn score_by_player_id(&self, player_id: i32) -> Result<Option<crate::schema::multiplayer_game_score::Model>, sea_orm::DbErr> {
|
||||
crate::schema::multiplayer_game_score::Entity::find()
|
||||
.filter(crate::schema::multiplayer_game_score::Column::PlayerId.eq(player_id))
|
||||
.one(&self.orm)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn score_by_user_id_and_claimed_oldest(&self, user_id: i32, is_claimed: bool) -> Result<Option<crate::schema::multiplayer_game_score::Model>, sea_orm::DbErr> {
|
||||
crate::schema::multiplayer_game_player::Entity::find()
|
||||
.find_also_related(crate::schema::multiplayer_game_score::Entity)
|
||||
.filter(crate::schema::multiplayer_game_player::Column::UserId.eq(user_id))
|
||||
.filter(crate::schema::multiplayer_game_score::Column::IsClaimed.eq(is_claimed))
|
||||
.order_by_asc(crate::schema::multiplayer_game_player::Column::CreationTime)
|
||||
.one(&self.orm)
|
||||
.await
|
||||
.map(|opt| opt.and_then(|(_player, score)| score))
|
||||
}
|
||||
|
||||
pub async fn insert_score(&self, entity: crate::schema::multiplayer_game_score::ActiveModel) -> Result<crate::schema::multiplayer_game_score::Model, sea_orm::DbErr> {
|
||||
entity.insert(&self.orm).await
|
||||
}
|
||||
|
||||
pub async fn update_score(&self, entity: crate::schema::multiplayer_game_score::ActiveModel) -> Result<crate::schema::multiplayer_game_score::Model, sea_orm::DbErr> {
|
||||
crate::schema::multiplayer_game_score::Entity::update(entity).exec(&self.orm).await
|
||||
}
|
||||
|
||||
pub async fn score_claim(&self, score_id: i32) -> Result<(), sea_orm::DbErr> {
|
||||
crate::schema::multiplayer_game_score::Entity::update(crate::schema::multiplayer_game_score::ActiveModel {
|
||||
id: sea_orm::ActiveValue::Set(score_id),
|
||||
is_claimed: sea_orm::Set(true),
|
||||
..Default::default()
|
||||
})
|
||||
.exec(&self.orm)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn count_score_by_user_id_and_claimed(&self, user_id: i32, is_claimed: bool) -> Result<u64, sea_orm::DbErr> {
|
||||
crate::schema::multiplayer_game_player::Entity::find()
|
||||
.find_also_related(crate::schema::multiplayer_game_score::Entity)
|
||||
.filter(crate::schema::multiplayer_game_player::Column::UserId.eq(user_id))
|
||||
.filter(crate::schema::multiplayer_game_score::Column::IsClaimed.eq(is_claimed))
|
||||
.order_by_asc(crate::schema::multiplayer_game_player::Column::CreationTime)
|
||||
.count(&self.orm)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn metrics(&self) -> super::DatabaseMetrics {
|
||||
self.metrics.lock().unwrap().snapshot()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user