GithubHelp home page GithubHelp logo

squiretournamentservices / squirecore Goto Github PK

View Code? Open in Web Editor NEW
22.0 4.0 3.0 5.64 MB

The backend library used by Squire Tournament Services

License: GNU Affero General Public License v3.0

Rust 99.59% HTML 0.29% Dockerfile 0.12%
rust magic-the-gathering mtg rust-lang

squirecore's People

Contributors

akbulutdora avatar caleblitalien avatar craigslisttrashman avatar dependabot[bot] avatar djpiper28 avatar morganator2000 avatar orblivion avatar thedeveloper101 avatar tylerbloom avatar wrobins6 avatar zbrachinara avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

squirecore's Issues

[Bug]: Infinite loop between front end and back end if tournament is missing.

What went wrong:

When the user tries to access the site in their browser, there is an infinite loop between the front end and the back end if the tournament is missing from the database.

Expected behavior:

An infinite loop should not be possible; I presume there should be some kind of error message presented instead.

[Dev]: Cold Storage Data Structures

Unmet Need:

Tournaments track lots of redundant data that is useful during the tournament, but that data takes up too much space after it is over. Excess data that can be trimmed includes the confirmations and drops in a round, round number to id map and opponents being tracked in the round registry, name to id map in the player reg, deck ordering in the player, and most importantly, everything back a unique identifier for all cards in decks.

Challenges/Considerations:

As stated, only tournament data needs to be in long-term storage, not tournament managers. However, we want to periodically save whole tournaments and their operation logs for regression testing.

[Dev]: Deterministic Pairings

In order for the tournament manager to function properly, a given operations log much deterministically create tournaments. Otherwise, different clients will think different things are happening.

There are two possible solutions. Either, all pairing systems are deterministic or the Pair operation returns a Pairings struct, which the client can then use to CreateMatches. Neither of these is perfect. The first greatly restricts the domain of pairing techniques we can employ. However, the second would require reworking how creating a match interacts with each pairing system. For example, creating a match would have to remove people from the queue of fluid pairings but do nothing during swiss pairings.

[Dev]: Login page prototype

Unmet Need:

SquireWeb needs pages for users to login and register. This should redirect them to the tournament creation page.

[Dev]: User creation prototype

Unmet Need:

SquireWeb needs a page for creating and submitting a new user account. This should include email and password as well as all the components of the squire account struct: display name, sharing permissions, etc.

[Dev]: Handling MTG Cards

Squire Lib is used by many projects, including Squire Desktop, at current it stores a formatted deck list and, cards from MTGJson in memory.

The issue is the repeating of data and, having to store a large JSON file.

Solution 1:

  • Squire lib only stores oracle ids for cards, so a deck will consist of something such as this:
{
  "name": ..., /*name and, deck info*/
  [
    {
      "oracle-id": ...,
      "quantity": 1,
      "sideboard": false
    }, ...
  ]
}
  • Squire core, desktop and, other dependents will then have to store:
    • A map of oracle ids -> card objects
    • A set of indexes for searching (squire desktop most notably)

To recap

  • The squire library would load the map of oracle id -> card objects at launch
  • The squire library dependent (desktop or, core) will store cards and, anything similar.
  • The data can be stored in a minimal json state for squire lib i.e:
{
  [
    {
      "oracle-id": ...,
      "card": {...}
    }
  ]
}

[Dev]: Operations filtering

Unmet Need:

When a user submits a sync request for a tournament, we must verify that the changes that they are submitting for that tournament are allowed to be submitted by them. In other words, players can't submit operations for other players, judges can't submit admin operations, etc. However, if they submit a known operation, they are ok. So, this check should happen after the tournament manager creates the sync processor but before it is processed.

[Bug]: Confirm All Problem

What went wrong:

The confirm all operation confirms matches that have no results.

Expected behavior:

If there is an active match that does not have a result, the operation should fail.

[Dev]: Remove Unwraps

During the first trial run of the new SquireBot, a number of bugs were found whose origins were calls to unwrap. We should make it a goal to remove all (or most) unwrap calls.

[Dev]: Round Metadata

Unmet Need

Currently, rounds don't track any information about the context in which they were created. While this is serviceable, we can do better.

Solution

Rounds should have a new field, say context. This context will be of a new type, RoundContext, whose variants correspond to pairing styles. This will help with queries to rounds. For example, the swiss pairing style would have a "swiss round number" in its context. This way, folks can query "rounds that were pair of the third swiss round."

Challenges/Considerations

There shouldn't be any major challenges with this.

[Bug]: Confirming Empty Results

It is possible to confirm the result of a match without that match having any results (wins or draws). This shouldn't happen.

[Dev]: Record Result Operation

Currently, the record result operation never checks if the player is in the match. The operation should have an additional field for the player's id to ensure that the player is in the round.

[Dev]: Use VecDeque for Operation Syncing

Unmet Need:

Currently, normal Vecs are used to sync tournaments. However, since the sync process requires removing operations from the start of the Vec, it would be more efficient to use a double-ended vector, like VecDeque.

[Bug]: Invoking cargo run from SquireCore instead of squire_core causes a runtime error.

What went wrong:

When opening the server in a browser after attempting to run the backend from the main SquireCore directory, the following runtime error occurs:

thread 'tokio-runtime-worker' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 2, kind: NotFound, message: "No such file or directory" }', squire_core/src/assets.rs:10:14

Expected behavior:

The backend server should be able to be run from anywhere.

To Reproduce:

Invoke cargo run from the main SquireCore directory instead of squire_core, and open the server in your web browser.

[Feat]: Confirm Single Round

Currently, there are operations for confirming a result for one player and confirming all active matches. There should be an operation for totally confirming the result of a single match.

Finalize Tournament Manager

The tournament manager and tournament operations will be the primary way to communicate between the server and client. This needs to be finalized.

[Dev]: Landing page prototype

Unmet Need:

The SquireWeb needs a front landing page. This should include a short bit about what Squire is, links to our Discord and GitHub, and paths to either login or create a user.

[Bug]: Player Registration

What went wrong:

There are two major issues with player registration right now.

One, there is no recourse for repeat player names when registering players (not quests).

Two, there is no way for players to re-register for a tournament. A player could drop and wish to join the tournament again. They should be able to do this.

Solutions:

For the first problem, both the RegisterPlayer and AdminRegisterPlayer operations could take an additional argument, Option<String>. This optional argument will be the player's name should another player already have their name. Note that this should be separate from the player's account.

For the second, a new operation should be added, AdminReRegisterGuest. Since a player's account is already unambiguous, the logic for re-registering players can be added to the existing operations. However, (re-)registering a guest can be rather ambiguous. For that reason, this should be a new operation.

[Bug]: Internal Ids and Syncing

Most of the client-server tournament sync protocol is done. However, there is still one rather large issue remaining. Say client A registers a new player locally, and syncs this with the server (and other clients). This works perfectly fine until they try to use that player's PlayerId in a tournament operation. All Uuids are randomly generated locally. This means that all tournament operations that get stored and synced need to use the non-id varients of their identifiers. I don't believe there is a way to ensure this at the type level, so this should be clearly documented in the TournamentManager.

[Feat]: Tournament Settings Tree

Currently, we can only effectively specify single tournament settings. This is good for adjusting existing tournaments but is cumbersome to use for storing default tournament settings.

We need a structure that contains defaults for all tournament settings. This structure should be able to take a pairing and scoring preset and export a Vec of single tournament settings.

[Dev]: Deck Pruning

Unmet Need:

Deck pruning has been a feature of the Squire tournament model since SquireBot's first tournament, but not much has changed since. Currently, we allow players to submit an arbitrary number of decks regardless of the tournament's max deck count. The idea behind this was to allow for more flexibility for players.

However, this flexibility requires that TOs have the ability to remove excess decks, i.e. deck pruning. While this works, it is a very sharp corner for both TOs and players. A player might be unaware of if they submitted multiple decks. After pruning, this could mean that a player is playing with a deck they submitted but that got pruned. To avoid this, both players and TOs need clearly understand this design decision of SL.

Solution:

Instead, adding a deck (admin or otherwise) should check the player's deck count and reject the request if the deck count already equals the max count.

Challenges/Considerations:

Alternatively, we could do nothing, but that seems ill-advised.

If we do this, all tournaments should have a default max deck count of 1.

[Dev]: Round API Refactor

The API and data model for the results of a round are messy. Currently, a player can record multiple results for themself, but there isn't a way for these results to be cleared. This problem is magnified when admin have to overwrite previous results.

This probably won't require changes to the RoundResult enum, but rather how the Round struct interprets and stores that info.

Relates to #27

[Dev]: Register via Accounts

Squire accounts will be deeply tied to tournaments. Currently, a player's name (a string) is all that's needed to register for a tournament. Once accounts have been established, registration should be more deeply tied to an account. Tournament registration should be changed to take an enum whose variant encodes registering with an account as a guest (a guest is simple to the current registration, just a name).

Moreover, judges and admins should be tracked in a tournament as well. These must be accounts.

[Dev]: Branching Pairings Algorithm

Unmet Need

The greedy pairings algorithm works for pods of more than two players, but not well. This is particularly an issue during swiss tournaments. After just a few rounds, the greedy algorithm can lead to several byes being given. There is a need for more algorithms for pairing.

Solution

One contender for a new algorithm is what I call the "Branching" algorithm. Like the greedy alg, the branching alg is deterministic, but it attempts to maintain multiple pairings possibilities (where the greedy alg only ever maintains a single possible pairing). As the name would suggest, the branching algorithm uses a tree to model possible pairings (notably not a binary tree). Here is how it will work.

We are given a list of players (presumably ordered) and a pod size. For ease, let the list of players be [A, B, C ...] and the pod size be 4. Like the greedy algorithm, we construct pairings one by one. The first player will be inserted at the root of a tree. We now attempt to add B to the tree. If B has already played A, we skip B, and they will be the first player we attempt to pair in the next iteration. Otherwise, we find (at least one) spot for them in the tree. In this case, B will branch from A. At this point, our tree looks like so:

A
|
B

Next, we will try to insert C into the tree. Provided A and C have not played against each other, we can insert C as a branch. For this example, let's say C has played neither A nor B. So, we insert C at the bottom of the branch. This creates the following tree:

A
|
B
| 
C

We now must insert player D. Let's say the D and C have played against each other, so they can't be paired against each other. This will result in a second branch from B, which looks like:

  A
  |
  B
 / \
C   D

Lastly, we will insert E, who has played against none of these players. When inserting E, we will insert E into every branch we can. For every branch that we can't, we create a new branch. In this case, that looks like:

  A
  |
  B
 / \
C   D
|   |
E   E

At this point, we have at least one branch of length 4 (our pod size). So, we will take the leftmost branch as our pairing. So, we have [A, B, C, E]. For this one pairing, this is the same result we would get if using the greedy alg. However, if C and E had played against each other, our tree would give us a pairing of [A, B, D, E] as the tree would look like this:

  A
  |
  B
 /|\
C D E
  |
  E

This alg really shines compared to the greedy alg when you have an early branch, like when B and C have already played against each other. With the greedy algorithm, A and C would never be paired together if B and C were opponents in a different match. This way, we can track possible pairings for [A, B, X, X] and [A, C, X, X] where the greedy alg would just track the first possibility.

To round things out, should the entire list of remaining players be turned into a tree, there is literally no valid pairing for that player left, so they will be unpaired (and given a bye in a Swiss tournament).

An additional note about this alg: For pods of two players, this algorithm will produce the same results as the greedy alg.

Challenges/Considerations

As described, this algorithm doesn't support repair tolerance. It can be adjusted to do so, though. Likely, this would mean tracking a branch's "weight" (equal to its repair count). Any time that count would go up and not go above the tolerance, we allow it but we also branch.

Using the example where A and B have played against each other, we insert B normally, but we would attempt to insert C in a new branch and into the B's branch.

[Dev]: Basic Squire Account

The first step in getting Squire accounts set up will be making the account structs. These should go in squire_lib as we will being using them in the tournament model in order to register players, judges, and admins.

For users, their struct should contain identifying information such as their display name, user name, and Uuid as well as their privacy/sharing information. Notably, authentication material such as a password should not be in the struct.

For organizations, similar identifying information is needed as well as the owner, default judge and admin accounts, and default tournament settings. Eventually, this should also be (optionally) linked to a discord server.

[Dev]: Settings Drop-down

Unmet Need:

In the tournament settings, there are subsets of settings. For example, under "Pairings Settings", there are settings for swiss/f fluid settings (whichever the tournament is using). This swiss/fluid subset of settings should be in drop downs

Solution:

Create drop downs for both the settings categories (general, scoring, and pairings) and for the subcategories (pairing style and scoring style).

[Dev]: Privileged Deck Info

The SquireCore server needs to be selective with who can see deck information. Most tournaments that require deck reg are closed decklist tournaments. Tournaments should store if they are open or closed decklist tournaments. There should be a settings option to toggle that (with a default of closed).

SC should be selective with who can request a decklist. Tournament admin, judges, and the owner of the deck should always be able to see their decklist, but no one else if the tournament is closed decklist. There are a couple of ways of doing this, each with its own downsides. We could selectively strip out deck info from tournaments that are closed decklist based on who is requesting the info. Or we could always strip out this information and require folks to use the get decklist APIs.

[Feat]: Standing Cache

Description:

Currently, standings are always calculated. These should be cached.

The solution you'd like:

The tournament should hold an Option<Standings>. When anything that could affect the standings is changed, the option is turned to None. The get_standings method should return this cache if Some or calculate and store new standings if None.

To cut down on serialization size, this field can be skipped.

[Dev]: Account APIs

Once a basic schema for the accounts is established, squire_core will need CRUD (create, retrieve, update, delete) API endpoints in order to manage accounts. Endpoints for querying accounts are also needed. This will should include endpoints for getting a single account, all accounts, a count of accounts, and eventually searching for accounts.

The request and response structs for these endpoints should be added to squire_sdk. They also need to have tests in squire_core/src/tests.

[Feat]: Rounds Track Player Order

It would be nice to be able to seed seating order. To enable this, each round needs to track the order in which each player was added. This should be an additional field that's a Vec<PlayerId>. There also needs to be a field in the tournament to control this as well as a setting to toggle this behavior.

[Dev]: Tournament Error Pop-up

Unmet Need:

When operations are performed, there is a chance for errors to occur. In this case, we should not just ignore them. Instead, a message should be sent to the tournament viewer component so the error can be translated into a message for the TO to read. That messages should be present as a pop-up.

Solution:

The tournament viewer component's message type should have a variant that is a tournament error. This error then needs to be translated and presented.

[Dev]: Review Tournament Status Checks

Most tournament operations are gated by status checks, i.e. you can't register if the tournament has ended. All these checks need to be reviewed to ensure they are functioning properly. There is a known issue with the check in the regular add_deck method.

[Feat]: Deck checks

Decks are a common thing in larger tournaments. SquireLib should support some method of tracking and recommending deck checks.

[Dev]: Advanced Drop-down Tabs

Unmet Need:

Currently, there are only "simple" tournament tabs in the web frontend. This works for now, but more specialized tabs will be needed in the future. Very roughly, "advanced" tabs are those that display/manipulate TournamentManger details and non-advanced tabs display/manipulate Tournament details.

Solution:

An "Advanced" drop-down tab is added to the set of tournament tabs. From that, various advanced tabs can be selected.

[Feat]: Raw Pairings and Scoring APIs

Description

The SquireCore server should expose APIs for pairing folks without needing to run the tournament through Squire. This would be a rough wrapper around the pairing algorithm functions.

Your Solution

There are endpoint groups, such as api/v1/pairings/calculate, that take all the information needed to provide those calculations. For pairings, a request struct would look like this:

pub struct CalculatePairingsRequest {
  pub alg: PairingAlgorithm,
  pub players: Vec<PlayerId>, // Players are ordered
  pub rounds: HashMap<PlayerId, HashSet<PlayerId>>,
  pub settings: Vec<PairingSettings>,
}

Note that we aren't passing whole Rounds around as we don't want to make others beholden to our Round model. This shouldn't be an issue as additional features like seeded seating orders are done in our Tournament model so that responsibility is on the client.

This isn't an issue for things like PlayerId as they (de)serialize to Uuids.

Pairing Conversation

Currently, there is not a mechanic for a tournament to change its pairings method. This will be useful for when a bracketed pairing system is added and used to cut to top X.

Along with this, pairing systems share common settings. For example, both fluid and swiss tournaments have a match size setting. This should be preserved when switching systems.

[Dev]: Tournament creation prototype

Unmet Need:

SquireWeb needs a tournament creation page. This should allow for all of the different settings to be adjusted. The pairing method can be exclusively swiss for now. This will have to change eventually, though.

[Dev]: Tournament control plane prototype

Unmet Need:

The heart of SquireWeb will be the tournament control plane. For now, this can be relatively simple. We assume that they have edit permissions (if they don't, the backend will catch this so they can't sync).

The control plane needs ways to switch between subtabs for:

  • Tournament Overview
  • Player Registry
  • Round Registry
  • Standings
  • Scoring

Each of these tabs needs to support all relevant operations (player registration, pairing creation, etc).

[Feat]: Cows in Operations

Unmet Need:

Currently, the types used in tournament sync, namely OpSlice, hold vectors of operations. This makes sense since they could, at any point, run into a sync issue and need to return themselves and be (de)serialized. However, we can do slightly better. There is no need for this extra allocation if everything stays local.

To solve this, OpSlices should hold a Cow<'a, [FullOp]> and deserialize into the owned variant. Things that hold an OpSlice, such as a Blockage, are free to restring their slices to be 'static to avoid messy lifetime annotations when they are not needed. Of course, this could be added later if additional performance is needed.

[Bug]: (FFI) Changing minimum and, maximum deck count can cause errors

What went wrong:

When changing the min and, max deck count via tid_update_settings such that new_min > old_max, whilst making sure the new values are valid the method fails.

Expected behavior:

The method should not fail as, the new values would be valid.

General Info:

To Reproduce:

Fix

When new_min >= old_max swap the order of apply setMin and, setMax

[Dev]: No Panics in SquireLib

Unmet Need:

SquireLib forms the base of every Squire service, so it needs to have a solid foundation. Key components of the library (if not the whole library) should use the no_panic macro from the crate of the same name. This will help prevent issues like panics in SquireCore as a source of DoS.

Most panics come from the use of unwrap throughout the codebase. These unwraps should be removed.

Solution:

At a minimum, mark methods that the backend is likely to use with no_panic (from the no_panic crate), namely apply_op.

[Dev]: Auth Methods

Once accounts are established and connected to the functioning of a tournament, authentication for tournament and account endpoints will be needed. This auth should attest that the request is acting on behalf of some account. Not all endpoints need auth, however. Simple queries to view a tournament or an account need no auth. Requests that require mutable access to backing data will always need to be authenticated so that the backing data can ensure that account has permissions to change it.

Eventually, multiple authentication methods will be supported, including Discord and Google auth, but we should also have basic username/password auth as well.

[Dev]: Tournament Sync/Operation Managment Tab

Unmet Need:

In order to give TOs access to actions like rolling back a tournament (a feature of the TournamentManager), we need a separate tab for them to look at the log of tournament actions that have been taken. This should include the full list of operations and some indicator for the location of where the log was last synced.

There will be similar "advanced features" tabs needed in the future too, such as an error log of failed local changes and a tournament merge resolver.

Solution:

Add a new tab in the tournament viewer. Display the log of operations in a similar fashion to how the players and rounds are being displayed. This should include a "selected operation" but an operation filter isn't needed for now.

Challenges/Considerations:

This will very likely require changes to the ClientState trait in squire_sdk. There will need a method to query the operations log of a tournament. There will also need to be a method on the TournamentManger that returns a reference to the operation log.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.