---
# System prepended metadata

title: Battle Code Update Spec

---

# Battle Code Update Spec

This spec is to completely rewrite the code for handling Ranked and Practice mode battles. Initially we will not touch tournament / brawl / challenge battles and we can update those later.

We should make a new API endpoint which is mostly a copy of the existing `/battles/battle_tx` API endpoint that will handle ranked and practice battles and other battle types can still use the old endpoint.

I make use of Redis heavily in this spec because a lot of this data only needs to be stored temporarily while the battle is active, and then only the final results need to be stored in the DB and it's ok if data is lost if Redis fails. If there is a better way to do this to support the scale we need then go ahead and do that. **We want to design this system to be able to handle potentially hundreds of millions of battles per day**.

When a `find_match` call comes in, we should first verify that the player doesn't have an outstanding `find_match` record or active battle by checking Redis. If not, then we should store the following info in Redis:

from `find_match` call data:
- `player`
- `match_type`
- `tx_id`
- `created_date`

from `players` table:
- `rating`
- `league`
- `recent_opponents`
- `account_type`
- `group_name`

The `matchmaker` code can then be updated to pull the list of the above objects from Redis and do the matchmaking just the same as before. 

If a record is found that has passed the expiration time without being matched, the record should be removed from Redis and a socket message sent to the player that no match was found.

When two players are matched, it should delete the two records that were matched from Redis and create a new battle record to be stored in Redis with the following info:

- `id` (this should be something unique across our entire system)
- `created_date`
- `player_1`
- `queue_tx_id_1`
- `player_2`
- `queue_tx_id_2`
- `match_type`
- `mana_cap`
- `ruleset`
- `inactive`
- `leaderboard`

The mana cap, ruleset, and inactive splinters should be determined randomly seeded with both queue transaction ids. Socket messages should also be sent to both players to indicate they were matched with the id and other battle info (mana cap, ruleset, and inactive splinters).

At this point both players can submit their teams. When a team is submitted, the battle record can be looked up by the `id` specified in the `submit_team` call data, and it should be locked to prevent race conditions if both players submit at the same time. Then the record in Redis can be updated with `team_1` or `team_2` properties depending upon which player submitted their team.

When the second team is submitted then both teams should be validated (as normal) and the battle can be resolved as described below. There will also need to be a process that checks the list of active battles in Redis to find any that are expired (current time > `created_date` + battle expiration seconds from config) without both teams having been submitted and resolve those battles. When both players have submitted their teams or the timer has expired, then the battle record can be removed from Redis.

To resolve a battle, first check if both players submitted valid teams. If neither player submitted a valid team then the battle can be resolved as a draw. If only one player submitted a valid team then that player is the winner. If both players submitted valid teams then the battle is resolved as normal using both of the queue tx ids as the seed for the random number generator.

The results of the battle should be stored in the DB in a new table with the columns shown below. Additionally, socket messages should be sent to both players with the battle result info.

`battles2`
- `id`
- `created_date`
- `player_1`
- `queue_tx_id_1`
- `player_2`
- `queue_tx_id_2`
- `match_type`
- `mana_cap`
- `ruleset`
- `inactive`
- `leaderboard`
- `team_1`
- `team_2`
- `winner`
- `player_1_rating_initial`
- `player_2_rating_initial`
- `player_1_rating_final`
- `player_2_rating_final`
- `details` (should we store this big JSON blob somewhere else?)
- `rshares`
- `rshares_detail` (previously `dec_info`, could potentially be added in with `details` data)
- `reward_tokens` (previously `reward_dec`)
