This is getting so stupidly complicated
This commit is contained in:
parent
91ec035439
commit
bef66328f7
197
src/api/event.rs
197
src/api/event.rs
|
@ -220,7 +220,11 @@ mod test {
|
|||
|
||||
mod team_game {
|
||||
use super::{
|
||||
free_for_all_game::{FreeForAllGame, FreeForAllGameSpec, FreeForAllGameUpdate},
|
||||
free_for_all_game::{
|
||||
FreeForAllGame, FreeForAllGameSpec, FreeForAllGameUpdate,
|
||||
FreeForAllGameUpdateParticipants, FreeForAllGameUpdateRanking,
|
||||
FreeForAllGameUpdateRewards,
|
||||
},
|
||||
*,
|
||||
};
|
||||
|
||||
|
@ -252,9 +256,32 @@ mod team_game {
|
|||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct TeamGameUpdate {
|
||||
#[serde(flatten)]
|
||||
inner: FreeForAllGameUpdate,
|
||||
pub enum TeamGameUpdateInner {
|
||||
/// Add or replace a team with the given name and array of members
|
||||
SetTeam { team: String, members: Vec<String> },
|
||||
|
||||
/// Remove team with given name
|
||||
RemoveTeam(String),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
#[serde(untagged)]
|
||||
pub enum TeamGameFfaInheritedUpdate {
|
||||
/// Change the ranking and scores
|
||||
Ranking(FreeForAllGameUpdateRanking),
|
||||
/// Update rewards
|
||||
Rewards(FreeForAllGameUpdateRewards),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
#[serde(untagged)]
|
||||
pub enum TeamGameUpdate {
|
||||
/// Team specific updates
|
||||
Team(TeamGameUpdateInner),
|
||||
/// Inherited from FreeForAllGame
|
||||
Ffa(TeamGameFfaInheritedUpdate),
|
||||
}
|
||||
|
||||
impl EventTrait for TeamGame {
|
||||
|
@ -262,15 +289,8 @@ mod team_game {
|
|||
type Update = TeamGameUpdate;
|
||||
|
||||
fn from_spec(spec: TeamGameSpec) -> Self {
|
||||
let players: Vec<String> = spec
|
||||
.teams
|
||||
.values()
|
||||
.map(|v| v.iter().cloned())
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
let ffa_game_spec = FreeForAllGameSpec {
|
||||
players,
|
||||
participants: spec.teams.keys().cloned().collect(),
|
||||
win_rewards: spec.win_rewards,
|
||||
lose_rewards: spec.lose_rewards,
|
||||
};
|
||||
|
@ -282,7 +302,34 @@ mod team_game {
|
|||
}
|
||||
|
||||
fn apply_update(&mut self, update: Self::Update) -> Result<(), PartyError> {
|
||||
self.ffa_game.apply_update(update.inner)
|
||||
match update {
|
||||
TeamGameUpdate::Ffa(update) => match update {
|
||||
TeamGameFfaInheritedUpdate::Ranking(u) => {
|
||||
self.ffa_game.apply_update(FreeForAllGameUpdate::Ranking(u))
|
||||
}
|
||||
TeamGameFfaInheritedUpdate::Rewards(u) => {
|
||||
self.ffa_game.apply_update(FreeForAllGameUpdate::Rewards(u))
|
||||
}
|
||||
},
|
||||
TeamGameUpdate::Team(update) => match update {
|
||||
TeamGameUpdateInner::SetTeam { team, members } => {
|
||||
self.ffa_game
|
||||
.apply_update(FreeForAllGameUpdate::Participants(
|
||||
FreeForAllGameUpdateParticipants::AddParticipant(team.clone()),
|
||||
))?;
|
||||
self.teams.insert(team, members);
|
||||
Ok(())
|
||||
}
|
||||
TeamGameUpdateInner::RemoveTeam(team) => {
|
||||
self.ffa_game
|
||||
.apply_update(FreeForAllGameUpdate::Participants(
|
||||
FreeForAllGameUpdateParticipants::RemoveParticipant(team.clone()),
|
||||
))?;
|
||||
self.teams.remove(&team);
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn outcome(&self) -> EventOutcome {
|
||||
|
@ -305,22 +352,33 @@ mod team_game {
|
|||
}
|
||||
|
||||
mod free_for_all_game {
|
||||
use std::collections::HashSet;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub enum FreeForAllGameRanking {
|
||||
/// Ranking of players by user id (first element is first place, second element is second
|
||||
/// Ranking of participants by user id or team name (first element is first place, second element is second
|
||||
/// place, etc.)
|
||||
Ranking(Vec<String>),
|
||||
/// Score based ranking of players by user id
|
||||
/// Score based ranking of participants/teams
|
||||
Scores(HashMap<String, i64>),
|
||||
}
|
||||
|
||||
impl FreeForAllGameRanking {
|
||||
pub fn is_valid(&self, participants: &HashSet<String>) -> bool {
|
||||
match self {
|
||||
Self::Ranking(v) => v.iter().all(|p| participants.contains(p)),
|
||||
Self::Scores(m) => m.keys().all(|p| participants.contains(p)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct FreeForAllGame {
|
||||
/// Ranking of players by user id (first element is first place, second element is second
|
||||
/// Ranking of participants by user id or team name (first element is first place, second element is second
|
||||
/// place, etc.)
|
||||
ranking: Option<FreeForAllGameRanking>,
|
||||
|
||||
|
@ -341,7 +399,7 @@ mod free_for_all_game {
|
|||
#[serde(crate = "rocket::serde")]
|
||||
pub struct FreeForAllGameSpec {
|
||||
/// Array of user ids that participate in the game
|
||||
pub(crate) players: Vec<String>,
|
||||
pub(crate) participants: HashSet<String>,
|
||||
|
||||
/// Rewards for winning the game (first element for first place, second element for second
|
||||
/// place, etc.)
|
||||
|
@ -355,14 +413,49 @@ mod free_for_all_game {
|
|||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub enum FreeForAllGameUpdate {
|
||||
pub enum FreeForAllGameUpdateRanking {
|
||||
/// Replace the current ranking with the given ranking
|
||||
Ranking(FreeForAllGameRanking),
|
||||
SetRanking(FreeForAllGameRanking),
|
||||
|
||||
/// If the current ranking is of type `Scores`, apply the given score deltas
|
||||
ScoreDelta(HashMap<String, i64>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub enum FreeForAllGameUpdateRewards {
|
||||
/// Set rewards for winning the game
|
||||
SetWinRewards(Vec<i64>),
|
||||
|
||||
/// Set rewards for losing the game
|
||||
SetLoseRewards(Vec<i64>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub enum FreeForAllGameUpdateParticipants {
|
||||
/// Set list of participants participating in the game
|
||||
SetParticipants(HashSet<String>),
|
||||
|
||||
/// Add participant by id
|
||||
AddParticipant(String),
|
||||
|
||||
/// Remove participant by id
|
||||
RemoveParticipant(String),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
#[serde(untagged)]
|
||||
pub enum FreeForAllGameUpdate {
|
||||
/// Change the ranking and scores
|
||||
Ranking(FreeForAllGameUpdateRanking),
|
||||
/// Update rewards
|
||||
Rewards(FreeForAllGameUpdateRewards),
|
||||
/// Update participants
|
||||
Participants(FreeForAllGameUpdateParticipants),
|
||||
}
|
||||
|
||||
impl EventTrait for FreeForAllGame {
|
||||
type Spec = FreeForAllGameSpec;
|
||||
type Update = FreeForAllGameUpdate;
|
||||
|
@ -376,19 +469,63 @@ mod free_for_all_game {
|
|||
|
||||
fn apply_update(&mut self, update: Self::Update) -> Result<(), PartyError> {
|
||||
match update {
|
||||
FreeForAllGameUpdate::Ranking(r) => self.ranking = Some(r),
|
||||
FreeForAllGameUpdate::ScoreDelta(d) => match &mut self.ranking {
|
||||
FreeForAllGameUpdate::Ranking(update) => match update {
|
||||
FreeForAllGameUpdateRanking::SetRanking(r) => {
|
||||
if !r.is_valid(&self.spec.participants) {
|
||||
return Err(PartyError::Unknown("invalid ranking, all participants mentioned in ranking must be participating".into()));
|
||||
}
|
||||
self.ranking = Some(r)
|
||||
}
|
||||
FreeForAllGameUpdateRanking::ScoreDelta(d) => match &mut self.ranking {
|
||||
Some(FreeForAllGameRanking::Ranking(_)) | None => {
|
||||
return Err(PartyError::Unknown("cannot apply score delta".into()))
|
||||
}
|
||||
Some(FreeForAllGameRanking::Scores(s)) => {
|
||||
for (player, delta) in d.iter() {
|
||||
if let Some(value) = s.get(player) {
|
||||
s.insert(player.clone(), value + delta);
|
||||
for (participant, delta) in d.iter() {
|
||||
if let Some(value) = s.get(participant) {
|
||||
s.insert(participant.clone(), value + delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
FreeForAllGameUpdate::Participants(update) => match update {
|
||||
FreeForAllGameUpdateParticipants::AddParticipant(id) => {
|
||||
self.spec.participants.insert(id);
|
||||
}
|
||||
FreeForAllGameUpdateParticipants::RemoveParticipant(id) => {
|
||||
self.spec.participants.remove(&id);
|
||||
|
||||
if !self
|
||||
.ranking
|
||||
.as_ref()
|
||||
.map(|r| r.is_valid(&self.spec.participants))
|
||||
.unwrap_or(true)
|
||||
{
|
||||
self.spec.participants.insert(id);
|
||||
return Err(PartyError::Unknown("cannot remove participant, all participants mentioned in ranking must be participating".into()));
|
||||
}
|
||||
}
|
||||
FreeForAllGameUpdateParticipants::SetParticipants(participants) => {
|
||||
if !self
|
||||
.ranking
|
||||
.as_ref()
|
||||
.map(|r| r.is_valid(&participants))
|
||||
.unwrap_or(true)
|
||||
{
|
||||
return Err(PartyError::Unknown("invalid list of participants, all participants mentioned in ranking must be participating".into()));
|
||||
}
|
||||
self.spec.participants = participants;
|
||||
}
|
||||
},
|
||||
FreeForAllGameUpdate::Rewards(update) => match update {
|
||||
FreeForAllGameUpdateRewards::SetWinRewards(rewards) => {
|
||||
self.spec.win_rewards = rewards;
|
||||
}
|
||||
FreeForAllGameUpdateRewards::SetLoseRewards(rewards) => {
|
||||
self.spec.lose_rewards = rewards;
|
||||
}
|
||||
},
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -406,14 +543,14 @@ mod free_for_all_game {
|
|||
|
||||
let mut points = HashMap::new();
|
||||
|
||||
for (player, reward) in ranking.iter().zip(self.spec.win_rewards.iter()) {
|
||||
let score = points.get(player).unwrap_or(&0);
|
||||
points.insert(player.clone(), score + reward);
|
||||
for (participant, reward) in ranking.iter().zip(self.spec.win_rewards.iter()) {
|
||||
let score = points.get(participant).unwrap_or(&0);
|
||||
points.insert(participant.clone(), score + reward);
|
||||
}
|
||||
|
||||
for (player, reward) in ranking.iter().rev().zip(self.spec.lose_rewards.iter()) {
|
||||
let score = points.get(player).unwrap_or(&0);
|
||||
points.insert(player.clone(), score + reward);
|
||||
for (participant, reward) in ranking.iter().rev().zip(self.spec.lose_rewards.iter()) {
|
||||
let score = points.get(participant).unwrap_or(&0);
|
||||
points.insert(participant.clone(), score + reward);
|
||||
}
|
||||
|
||||
EventOutcome { points }
|
||||
|
|
Loading…
Reference in New Issue