From a15dbf5c632006361368531865491a2e119be146 Mon Sep 17 00:00:00 2001 From: darkstack <1835601+darkstack@users.noreply.github.com> Date: Mon, 24 Mar 2025 01:13:30 +0100 Subject: [PATCH] Init --- .gitignore | 1 + Cargo.lock | 2400 ++++++++++++++++++++++++++++++++ Cargo.toml | 20 + build.rs | 8 + font/achemine_bold.ttf | Bin 0 -> 14956 bytes font/achemine_italic.ttf | Bin 0 -> 15416 bytes font/achemine_regular.ttf | Bin 0 -> 14792 bytes font/vcr.ttf | Bin 0 -> 75864 bytes schemas/startgg.gql | 2733 +++++++++++++++++++++++++++++++++++++ smash.gql | 2733 +++++++++++++++++++++++++++++++++++++ src/main.rs | 181 +++ src/smashquery.rs | 59 + src/smashrequest.rs | 110 ++ 13 files changed, 8245 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 build.rs create mode 100644 font/achemine_bold.ttf create mode 100644 font/achemine_italic.ttf create mode 100644 font/achemine_regular.ttf create mode 100644 font/vcr.ttf create mode 100644 schemas/startgg.gql create mode 100644 smash.gql create mode 100644 src/main.rs create mode 100644 src/smashquery.rs create mode 100644 src/smashrequest.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..051a993 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,2400 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aead" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" +dependencies = [ + "generic-array", +] + +[[package]] +name = "aes" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" +dependencies = [ + "aes-soft", + "aesni", + "cipher", +] + +[[package]] +name = "aes-gcm" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5278b5fabbb9bd46e24aa69b2fdea62c99088e0a950a9be40e3e0101298f88da" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "aes-soft" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" +dependencies = [ + "cipher", + "opaque-debug", +] + +[[package]] +name = "aesni" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" +dependencies = [ + "cipher", + "opaque-debug", +] + +[[package]] +name = "aliasable" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" + +[[package]] +name = "anyhow" +version = "1.0.97" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" + +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand 2.3.0", + "futures-lite 2.6.0", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" +dependencies = [ + "async-channel 2.3.1", + "async-executor", + "async-io", + "async-lock", + "blocking", + "futures-lite 2.6.0", + "once_cell", +] + +[[package]] +name = "async-io" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" +dependencies = [ + "async-lock", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite 2.6.0", + "parking", + "polling", + "rustix", + "slab", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener 5.4.0", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-std" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "730294c1c08c2e0f85759590518f6333f0d5a0a766a27d519c1b244c3dfd8a24" +dependencies = [ + "async-channel 1.9.0", + "async-global-executor", + "async-io", + "async-lock", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite 2.6.0", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "async-trait" +version = "0.1.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "base-x" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "beef" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blocking" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +dependencies = [ + "async-channel 2.3.1", + "async-task", + "futures-io", + "futures-lite 2.6.0", + "piper", +] + +[[package]] +name = "bumpalo" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" + +[[package]] +name = "bytes" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "c_vec" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd7a427adc0135366d99db65b36dae9237130997e560ed61118041fb72be6e8" + +[[package]] +name = "cc" +version = "1.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cipher" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +dependencies = [ + "generic-array", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const_fn" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f8a2ca5ac02d09563609681103aada9e1777d54fc57a5acd7a41404f9c93b6e" + +[[package]] +name = "cookie" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951" +dependencies = [ + "aes-gcm", + "base64", + "hkdf", + "hmac", + "percent-encoding", + "rand 0.8.5", + "sha2", + "time", + "version_check", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpuid-bool" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-mac" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "ctr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" +dependencies = [ + "cipher", +] + +[[package]] +name = "curl" +version = "0.4.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9fb4d13a1be2b58f14d60adba57c9834b78c62fd86c3e76a148f732686e9265" +dependencies = [ + "curl-sys", + "libc", + "openssl-probe", + "openssl-sys", + "schannel", + "socket2", + "windows-sys 0.52.0", +] + +[[package]] +name = "curl-sys" +version = "0.4.80+curl-8.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55f7df2eac63200c3ab25bde3b2268ef2ee56af3d238e76d61f01c3c49bff734" +dependencies = [ + "cc", + "libc", + "libnghttp2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", + "windows-sys 0.52.0", +] + +[[package]] +name = "cynic" +version = "3.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c99c59968c8aa7f90d84240ab6ded4d3864125ce36b5b044554542cebc974946" +dependencies = [ + "cynic-proc-macros", + "ref-cast", + "serde", + "serde_json", + "static_assertions", + "surf", + "thiserror", +] + +[[package]] +name = "cynic-codegen" +version = "3.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "332695dddff7f260dfda1e97502b6440d443816f576994548b7751494991d2e3" +dependencies = [ + "cynic-parser", + "darling", + "once_cell", + "ouroboros", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 2.0.100", + "thiserror", +] + +[[package]] +name = "cynic-parser" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbb0f21f2f8d3134c2e887a16564c165694231f48b6ae2769193299081ecf662" +dependencies = [ + "indexmap", + "lalrpop-util", + "logos", +] + +[[package]] +name = "cynic-proc-macros" +version = "3.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7880789c425a73aff3ba286b2a9c794f330d4770769a42a1493d6175e4606c1" +dependencies = [ + "cynic-codegen", + "darling", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.11.1", + "syn 2.0.100", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" +dependencies = [ + "event-listener 5.4.0", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "flume" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bebadab126f8120d410b677ed95eee4ba6eb7c6dd8e34a5ec88a08050e26132" +dependencies = [ + "futures-core", + "futures-sink", + "spinning_top", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-lite" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" +dependencies = [ + "fastrand 2.3.0", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "ghash" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97304e4cd182c3846f7575ced3890c53012ce534ad9114046b0a9e00bb30a375" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + +[[package]] +name = "hkdf" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" +dependencies = [ + "digest", + "hmac", +] + +[[package]] +name = "hmac" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" +dependencies = [ + "crypto-mac", + "digest", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes 1.10.1", + "fnv", + "itoa", +] + +[[package]] +name = "http-client" +version = "6.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1947510dc91e2bf586ea5ffb412caad7673264e14bb39fb9078da114a94ce1a5" +dependencies = [ + "async-std", + "async-trait", + "cfg-if", + "http-types", + "isahc", + "log", +] + +[[package]] +name = "http-types" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e9b187a72d63adbfba487f48095306ac823049cb504ee195541e91c7775f5ad" +dependencies = [ + "anyhow", + "async-channel 1.9.0", + "async-std", + "base64", + "cookie", + "futures-lite 1.13.0", + "infer", + "pin-project-lite", + "rand 0.7.3", + "serde", + "serde_json", + "serde_qs", + "serde_urlencoded", + "url", +] + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "infer" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac" + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "isahc" +version = "0.9.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2948a0ce43e2c2ef11d7edf6816508998d99e13badd1150be0914205df9388a" +dependencies = [ + "bytes 0.5.6", + "crossbeam-utils", + "curl", + "curl-sys", + "flume", + "futures-lite 1.13.0", + "http", + "log", + "once_cell", + "slab", + "sluice", + "tracing", + "tracing-futures", + "url", + "waker-fn", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + +[[package]] +name = "ladose-caller" +version = "0.1.0" +dependencies = [ + "async-std", + "cynic", + "cynic-codegen", + "sdl2", + "serde", + "surf", + "toml", +] + +[[package]] +name = "lalrpop-util" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8d05b3fe34b8bd562c338db725dfa9beb9451a48f65f129ccb9538b48d2c93b" +dependencies = [ + "rustversion", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.171" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" + +[[package]] +name = "libnghttp2-sys" +version = "0.1.11+1.64.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b6c24e48a7167cffa7119da39d577fa482e66c688a4aac016bee862e1a713c4" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "libz-sys" +version = "1.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "litemap" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +dependencies = [ + "value-bag", +] + +[[package]] +name = "logos" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7251356ef8cb7aec833ddf598c6cb24d17b689d20b993f9d11a3d764e34e6458" +dependencies = [ + "logos-derive", +] + +[[package]] +name = "logos-codegen" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59f80069600c0d66734f5ff52cc42f2dabd6b29d205f333d61fd7832e9e9963f" +dependencies = [ + "beef", + "fnv", + "lazy_static", + "proc-macro2", + "quote", + "regex-syntax", + "syn 2.0.100", +] + +[[package]] +name = "logos-derive" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24fb722b06a9dc12adb0963ed585f19fc61dc5413e6a9be9422ef92c091e731d" +dependencies = [ + "logos-codegen", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "once_cell" +version = "1.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "ouroboros" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59" +dependencies = [ + "aliasable", + "ouroboros_macro", + "static_assertions", +] + +[[package]] +name = "ouroboros_macro" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0" +dependencies = [ + "heck", + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand 2.3.0", + "futures-io", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "polling" +version = "3.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "polyval" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" +dependencies = [ + "cpuid-bool", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + +[[package]] +name = "proc-macro2" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", + "version_check", + "yansi", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.15", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "ref-cast" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.9.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sdl2" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b498da7d14d1ad6c839729bd4ad6fc11d90a57583605f3b4df2cd709a9cd380" +dependencies = [ + "bitflags 1.3.2", + "c_vec", + "lazy_static", + "libc", + "sdl2-sys", +] + +[[package]] +name = "sdl2-sys" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "951deab27af08ed9c6068b7b0d05a93c91f0a8eb16b6b816a5e73452a43521d3" +dependencies = [ + "cfg-if", + "libc", + "version-compare", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_qs" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6" +dependencies = [ + "percent-encoding", + "serde", + "thiserror", +] + +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +dependencies = [ + "sha1_smol", +] + +[[package]] +name = "sha1_smol" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer", + "cfg-if", + "cpufeatures", + "digest", + "opaque-debug", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "sluice" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7400c0eff44aa2fcb5e31a5f24ba9716ed90138769e4977a2ba6014ae63eb5" +dependencies = [ + "async-channel 1.9.0", + "futures-core", + "futures-io", +] + +[[package]] +name = "smallvec" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" + +[[package]] +name = "socket2" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spinning_top" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0" +dependencies = [ + "lock_api", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "standback" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" +dependencies = [ + "version_check", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stdweb" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +dependencies = [ + "discard", + "rustc_version", + "stdweb-derive", + "stdweb-internal-macros", + "stdweb-internal-runtime", + "wasm-bindgen", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "serde_derive", + "syn 1.0.109", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +dependencies = [ + "base-x", + "proc-macro2", + "quote", + "serde", + "serde_derive", + "serde_json", + "sha1", + "syn 1.0.109", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "surf" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "718b1ae6b50351982dedff021db0def601677f2120938b070eadb10ba4038dd7" +dependencies = [ + "async-std", + "async-trait", + "cfg-if", + "encoding_rs", + "futures-util", + "getrandom 0.2.15", + "http-client", + "http-types", + "log", + "mime_guess", + "once_cell", + "pin-project-lite", + "serde", + "serde_json", + "web-sys", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "time" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" +dependencies = [ + "const_fn", + "libc", + "standback", + "stdweb", + "time-macros", + "version_check", + "winapi", +] + +[[package]] +name = "time-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" +dependencies = [ + "proc-macro-hack", + "time-macros-impl", +] + +[[package]] +name = "time-macros-impl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "standback", + "syn 1.0.109", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "toml" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "universal-hash" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "value-bag" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version-compare" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "waker-fn" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.100", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" +dependencies = [ + "memchr", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..eeae482 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "ladose-caller" +version = "0.1.0" +edition = "2024" + +[dependencies] +cynic = { version = "3", features = ["http-surf"] } +surf = "2" +async-std = "1.10" +toml = "0.8.20" +serde = "1.0.219" +[build-dependencies] +cynic-codegen = { version = "3" } + + + +[dependencies.sdl2] +version = "0.37" +default-features = false +features = ["ttf","image","gfx","mixer"] diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..dc6f2ef --- /dev/null +++ b/build.rs @@ -0,0 +1,8 @@ +fn main() { + cynic_codegen::register_schema("startgg") + .from_sdl_file("schemas/startgg.gql") + .unwrap() + .as_default() + .unwrap(); +} + diff --git a/font/achemine_bold.ttf b/font/achemine_bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..0aa810e4c40ffc861c71929fd863f83ddceee2ff GIT binary patch literal 14956 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
Rz!2SZ+Bg%A+ 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 RK7r^%iN@gJmP?E^j{)Z42>$>8 literal 0 HcmV?d00001 diff --git a/font/achemine_regular.ttf b/font/achemine_regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..84be0af52597ea3ada4e4e9ccbc3025ac5baad10 GIT binary patch literal 14792 zcmZQzWME+6VQ64rW^izG3-L{3zLCVhV7Z2YfkDPUSl_6--RU9&1EU8614BY`ZeoGR zr#2Y|2G%JI42=KM6N?M}|7T!kV6a@mz`($fo>Q6DymR7u1_sU^1_rek8L5dWY&q5~ z3=9ls7#JALGBQ#V*{oTF7#J8?7#J8-GIC2QSjr@BGcYi&U|?W=m6M;GXs_!&hk=0| zWd4ub#EJq&c81vu42&8K3=9f+iMgqtO>XrwFc_3DFfhdx&03XZa`F5&Um3WWUobE*FkE7+-T|Zkm;IMwzQQ~S!I?>i!J0{j zL7z#7L61p?L7S18!5XBONsB>;NsB=nL^IxJP-WI-Fkz}=;9yE&h+*ntFkpJZ5W^JA z5W}R!5W}>M!GP%@Lkyz?LkyD?g8-8lLkx2UgE!Mph8U)Q33?ps4)gGL^3Y@e}^%EL6b>~!Itp|0|TQjgAEf0 zgEEshLonk91}i3S1}i2B1}nxS1}P>%1|ueShG0f!1{+4^|7A?f48e@@3<1m?48b6A zCP%RPU?wjHE5>|=V8(+Cnv63Tq?nu;0vLZY@G&bhh%^3R5N7!UGiUU~I?0&)mtN%Us4_1?Gd|0~9Wxum}c)!T+;hw{kEjgWW0t zaVyBZAk4`8|1j81&I|z{H!%NZuwv9VGWGG9gY3zHoK1K2JH1_mZ=1_q{!5VII785kHRFfcGKXJBB~ zfVhKkJp%(MT)<%h3WtSIv*H;T7&)PS{Kvq+ya{3^$S+{E9t;eOKNuL844~nq3r;@_ zOsNbEOpOc-OhFKTGn|HmIrCSjS-}XJQG$U1hQZ+n3PTVEg(DP$>|^}Gz`z7D{|f^H zhz-I_tPn9Kkl)#%;vm0HWnciul`R7U(?kXaCQxYv3iqj?JP*dq3=E)hl|cqt()?gx z2D4-sSQzdwFfbS~C@`=v2r+mu)G@R&Ol6qPFo$6^!)}HH3?~`RF+5;+#PFKo9m5xf zpA5elgB3&+Bo$;8loZtdgGvtt1|No2hDk_zPC)fMhwBLf>yd%z`TzL;qyKmQU-*Ci z|LOmG|F8SM>i^>Z^Z)n#@BQETzx{vH|GNLR3=9u~9(X=*f8hMU8thWAH}DdCD6*9d z=?n~vY~aEeEWrpWok1APgA$Ak49qO7Z0sDIT--doeEb4}Lc$`VV&W2#QqnTAa`Fm_ zO3Es#YU&!ATG~3g40`$ohDOFFre@|AmR8m_ws!Uoj!w=lu5Rugo?hNQzJC4zfkD9` zp<&?>kx|hxv2pPUAd7N9L|#4v14BVkVQ~oqLn%n0jDdlnyaL2xU`T~fc*u;*M20K| zhRSq?wB!_qBrGbk8FI0Rq6#T6q%q83c*W?#xQX!w;}0e=CJQDXrV^$mrWs7jm>w~G zVK!i{W1hu)g++$NjAa_j9abh*8`dD!G}b!SU2H~der)sDuCVj4tFT+Km$3J+&tl)h zeun)G2MdP{M*+tMj!&EpoI#v*oRc^=aGv3O#QBShhf9V_hs%k}k1K|21J^TdDee&N zKJHCCT0CJqB|Iy54)8qU)!+@`?czPe`-@MCFO6>k-wwW0d@uMJ_{I43_~ZC<_~-B+ z;r}I|Adn`oPT-ut9YHI>2Eh}8R|Fpjz7b*(5)hIRst{@snjkbsXob)Lp)*1^gq{d1 z;DkoPM#2tMfqudzgBda~F%teCjm?eOjoFpKSXtfJT$$0Z zP%BU?R4`m2P%u~{P@_;IP$O74SixV|Upv60P@(Ydk|iEB9i5qF2^Wts>f_XCnGQJZKmjGEFTr+Z|)&0D`Kas1iE3E=Q()qA`1>hXNQ6FjJA)-#(@qh@_6@H*rmC6>q2{C|sEsRQ`WsTEcXL!JfgJ zfq_*?O`VTX8RAZJJ4R!3Jw|msMo@AxHWCAcuQJHRa!m4!c8sRRB5dq(jK)UxjG}Dp ze2k20U`dc?&6)B|>}AzboD3rz)EsO%MYtGQI9Vmt<;*;^biFmzC9SnItOO+G`8SL6 zMJlL^=*Wrj@UU^P3;*jD5>qn|cQJ64;!>59SCKUjG`5fCV`5}xl-sJVz|I`gF&2uLD-Jj z)I?365#$+2F5_cjHwLAA)XZ=Kdm3kCu=?M@$j0;ylv~9?hS)Kg8-r4o9FzDuM`Iy* zEy-|wQ+81e#fqwj83s88d4?IcGWApPtKC51%*bH)zk}f~R6p1)>c)_iYN)6##%`t` zE~zaqWa3!iR-K=spLr|8Fs~rTApKDlsG7853}IZsbPi;G7!w$^L2VpiMNvgvM&o~H8MR}<@#Fdb8^c|Oc95IImDFHa zgKe_Bwzj;ywl`vYoEF)SC$}CMIIa0WP}F z^-QJM*riQ$bxow%*`!PvGs`9gNK5(mmxfdZ8%cAD`%YYH6r5pZndz^u@1JRDmJw{k zz{udlz`)qabdCYkmSI;nHx^W8)ZC%}DKvp8rP6EWUn7vatr!>>KQi55&|qLNH?d=~ zXS4$)L}ev5c6B>Oko!bM_?Y+^`Iy-iMHQ_iG%XcvCA1ZUZLIWNRkaOMtW154B&GGN z6&zKx#n~AdqyBkXnFKf(i)jhSD(fm(+RMrKD#**4c)YQ|&y$zf~#MMn@xmEbY z#dSqw)$EN8JY;p1<6N}8%oT)Xl?BbbRh?tZT#8iZXlr^ns~F1iGBO3TaPXSxni|VU z`AR5@XgTP}8EMFJG7Cg{n}=A*8QOyK0uzJW|KCg^Oy?Mw7%u6k;Ovyfs%fQ@H zKt_x=+*!*~iC9G@RMg)tW~5}}smaeQ9$>8RYayp(8)~c=;ASA@ zm>;U;qU!E%H&IZ;iY5PD!G3JydQ~G?vBLaFSE>2}&X3+cp zjqyLz4F-M&c?M9A5|jkNfd;A=L9GN(?f}(L%;1vWj>#NS!oiX!J0xK+stBpb2nx$< ziW@uFtB7eTh={2eNLl%KI_m`5t4U~@%9?ws*!XE_cv~xrsu;+GJ1g5qFwW+bP}Go+ z){y44)Yq}e<&sv>k&@Gq<+n37bpCf*T;JV5)k;r^M>^P1&rM%KLf2VG(L__8M=i!$ z&&x!H0o2yf{{Ib}hqys)9Y#Ht;c(m9YpmR|s@BkaElm(F#^(YWK5obal74_5J%?NW?BS-$2(; z&cfe7E6`3&!lO0MqrcEyNCKW77|t{PW8enWD#)c4Gg1lG3N67vr5FgqOESiCPT;}R9_%Qxs zvSZ+2U=TJ{6=!7^XJyx6T&(qx1||k=hKr2<880$0Gq5u- zfU=jUqNt)a{glDzDAe>{v`q&ccmj-GagYXU`4+|X~BSjqxIYAF8St(sxWqoH89YY)KR-`tw$^UQ6?BIM5#=yV` z%D!yuY@noMZpUb@3a&TQU}?$Rjv3tK0n0czC50 zMHG1Wg;^Oj<;=WwwTu`=t&NoQBv{ya^zGc0WX$Dt*ac*btz>QEom}(%v=m)4Jk;zJ zgatIUwT0u_!!$HvrsW3Igy=BdVP$c!w$>Nr6EYOnwu!Ws)z(rqkk+$PGWF6E;o>;2 zpb-$E8|I{; zU0GOMnc0}J;$O1ozZYH!|E!n`9xgliGobG0sX~r1y?~fqAlDUS4i5xeh1|uueWj+ypZ3Q`15jHngHZDa6GZQZ{ zW}y^s{SbQLw~1n)hk=A;yt`3|y0WB^nXQUz zWt6FIcvGl%g9ek4k+PV5ew0m?pPsa62$vuan|4%3Y)E&qnXwbN>;Z+v7N)BVLSWmJ z_?XxQp@oi#9uu>Ynz|sU#(|VMjLw`2sv3eaK5FjCwlbRTiKdQuHa2-SZmk*i`q7!-$q8=f0r3!{<$!n3%nEXpCJ%bAAr2Y52K=>vY@e`qM)&$GL!1R=?MvpnF$GuzW+8eo%?rz(cmwr zO%=nyz_5qu9Jsw`ET|llkN`@apmfQ|An^Yi;}NEF48jZy;!0|u{vSA93K|QF@G)I7 zOV%_{^3>I}kmrt-vWnr7mkyOtkk+=4WqkEd(JBU9p+nrm#dMB=71WLdg;h)fqu;+E zrgMK=!R=pf1_owXNd3yF%nXLY#?p+&!pcmWn67%>W#W&N$bR!AT_T!E>F+%z#lQEN z&i&obdO_6&=grRYCotI}txPd`r9aFoS zXQqoowx71PU$#TXl)w2#@f~52-EoG7v8|!O-6<9fOyKlo%5;^12h>+*R08K)a4Sj; zoS2o7le4Chk)*VhibrsWuY!quf^Mdmh z#;+6LXdPxQ1&S+>zk;Fu(qv%3>n}D?Plk^XpXZXJ*0|l~5W?@l%B|YvzDpTF(_B!0 zrZZh-5Ma;-*$?$6qzk~TEC?#yA(@t4SeaRmS(}kjTh2^c+(cB#!B}2O*JfgZxT(2` zsA-~?uAsWT{*9`2Y#iJIyuKi>e`aCgk~Y>*HzcXfn0hNXNl7WFJ4JG_^NR~aNoxwo>&Y4D@=9??>bRO3 zc^gZLii8SFSeok?2ug5Ch>AL!>G@eIfZ~S{)R$!91lJ7=ipqk@ri!AkNzxVc_wMa}2Uz_p_LSGMXHuBL!meu`s4NMA;|{u_o|qxSH9xt8yi<2rAje za>?r3JG;m+uK4F=;A3vhlXe5eF|5}h;pq3ruk$*PLehiEZHcVCwADJ#NurM$PE32Cte>AJl zW3s9j2em1b|9@jV!}yPZkHLz8K~;$zGzJ20LYdhzf(Axlbqc7DY0Ze*uoIVKlw}l= zV-ja%QF%1Ug^#)2rlHZ}E2B7EY8QhovUmMTX5u}orqW`>@I zl6pRgMjDCgjHU8ED$_YRGUB2G6d4`63lHuOToUSQ83omBwbUKuWc2-v4MH8%v|Yorj6L+k z7`MBaN$4nv?9y;EmJ{c97Xf?HJ=H-@(K-;E$Qc==7#J8QG2LJgV_*OeD#|i~ato-G zGKLHii8JOZ80x9^^~DAS1&3?di7=H(m>Zh8{tIPX?P?sDBFqJzRWtf8!}y=^AANQz&? zPQ+16#?(vSNneOtM3Qfwgt4}?45zk~oTdb~sSdv=F9#E2xUrd;v4OSqzm>A~rpkiq zcDfoCe7t(9GJ1kqj@k~|qTDP@OpHG4YC7tUx{^}-qWr?#Y)q0YJkp?vPX!rHFJ|3IrLm>6sr7#NN--C*Eh5MW>sM(UWEiW>_m+i1wjYJ#wMY%J3x z2vbvb{y!d2n*Cq)Uxwi{Sg!(_USUvC0k0E56$+b!rmU<6$fzjEPy=UY4M78Gc~xPy zSWbkwf9~k2DSPkP|IYk1JOip90{(wvRD!f6&B3FCh}0}-yq1wuScpfEQ$a*kLPlRnB({@B zN|cwC)sdT%PuWTbG;IztBbb4K*@E#O11Ru~#KfU(3PEK-l)y*f7>gR4F$P%%^Yh7T z7%M7UYfHxRiOUHXIDw)A!HQ)vV*F=fFQFwb1c?Xa_(5TRiAe+3Mc}w+{D&p(MM;T! z#xF5QQO^L*|4i(R{~+Zkchjc#D5OT&Iz{miB8JOj&U|tN$%>Px+VC(8j}FnE>*;+C3s|j zk5LrV;s@86Fz<-)F>L@9Z{RXpK!h(?Tn$vbA&PE)w9<{~97^d1@|zmt53qf(o+Na# z23DR5DhuK+O|_$Ra2KY0Jb#@SO;HL{a2jRIV`2j3B1SbnCU!PaPzM1NKjMs$Vmj)I zT%w@zIm(-H1`7+17@wTszvql!VvH<6i>MeF88rWYW1PkK57Z|Ig$8(B7ZekEO!|zV zc`!&N!w#(&K(jQUDF!~KoBH8eYVz)CA}X?iJi?NEhSH{*QgTMlDw^(!s!~QOie@~* zQoJUz#%kj7ChlA!68_@SoWk;={GxoEEPNcI^7=}u7OKJmf?fhbimHNQe4H!-oWk;Y z%1V}+;tY%oQvbg(wlPfxr9D<9JtkX5(DZ^iXnFxuSb|0i#Q7K*`3)RY`2z!E*Q{aU zSCW@d;Zu^e;*vM@(EQ+9rn}hnn~;{0xB$0@053Q_gYxGG#xJ0{0G2=P7;PCr4IX7S z@ZgJ}@mfA{S!mXYWirZBveuD^T`8+34lT$2@x-Koau1^iq|M3rmhlT{tlk*XsylZe zdBVi#1B_q(B{9zX$HTw~8qs6sVf=#G-sGvSj93|4T^&|k6~2nG@n1dTmw!c!eP9eK z<`@`3eNx7!kogsJc4c98V{vd9^rI!XCJx4xptur-jJ!b87bs1D<^hxp zd=%tO4D}>Mbfi=@9i(Lq_4TABtyCFvm81kk1o=hWr9=fqg~X&m?qz21{Qr&VF?bG2 z9Mn=|MH+=w#KC5o2_4@3cMqKbAL!MBPF=xhaJW%#K9Y%HFwOrPGcIBT%^`!=B0wg% zAhU*Mut`HzqycTXAR{|yARA@=_1_;1Ax7*|vN#qafWw*p|2IZ`Mln#H6o<}ez=lxf z%bBQ)i>sT+L1``|HdqW)uj?|LV~#XWJ6#)11ix1`2OMm}Y0T@4308G}Fr%XoR&Xj`KoD|tnmP!sD& zS=neuV|P8#zgHcd1r-ey6%7>y92vJeT1x6F3hx3nq9ypM|7)>)c)6D<>3>*v$Ol8cIgwz;R7#IZD89Eqv7>@k^4<0X*0E=rt#r3g@uV&C= zIKsg6|11LoqdW5?1~vvR1_ohvWpiV3Wp-mh zf12r>kQ!)aPJoS}15_+w5pR12k^uEJWx#z+du)A8cF=+h$V4P`cof><1p z{ZM5mT@HR_17SH0QGPX1MQ$M;5iwB-4n9svDKSNh}JybqnCJA9C6>SM+32sh) z6E0REK0ZMfW=(EIAyyUpNNZT%_5XiRzF~X`_NO}o1IVAOpykb&;;TW+p|PlM11*$< zi{B7ZV}O{m#uF4SO#crvFfiJJ=i*Vry%7@bJ+ZM&OOtzg{J`B3h&fE`VD|)q-O~m# z=Kp^NaJvI69u5}o_ych#x;R)pxPAPYc{|fd20jLLXpDe+h@eVI6x6{1_bEX$Ns6E$ z7BFVwlJ(O{ERZw_wp4J^mh#aHEca7eHqFpkfpPi2y^I?FZZLW>#d33Z^jfC)=&v<_Adh?B$YABL%a(1Cs<7llM`baY%E<|xuzv8 zf$3Zi$fJx58=0IKXG7)8joCM*wRAB#^?)Rq7_6Bh8S}yGn8ZP2r-+pq%1AXLqn@;y znzXc<+F1}SrKZLdsU{_*swyR=2BSeX@iDA}uM$;d@PV=!8Tc6{LD@_U>A zh8Iva3xgP=E|ks6z{3~^WwSAeG0p_7l4ap!U|{e9_w*TAI2jljL61R!!I7bqp@boop_HMBL4m=Ep@^ZBA&(&+%uZz}V#s4iWGG@tVbEh>&`8!) z2=;S!(@`)oFfi9sa4aoJEiF=TDk{y(S8z%#%1bOt(PLonVen<}VhCXHUfHq#`A zGiWeqGH5YqGw3krGUziHFc>lzF&HzLFqkr!F_<%0Fjz8JF<3L$FxWEKG1xOWFgP+e zF*q~0Ft{?fF}O2$FnBU}F?fUH-H*YaA%G!}A&4QEA%r26A&eoMA%Y>2A&McIA%-EA zA&w!QA%P*0k%f_!k&Tg^k%N(wk&9s^!zzZg45t}V8O}0fF=R93GZZouFcdKqGn6q@ zGt@IQFl=DtX5?YyW#nVzXB1!*WE5f)W)xu*WfWr+XOv)+WRzl*W|RSshsrZ5Fe)-C zF)A~vFsd@DF{(3aFlsVtF={jFFzPbuG3qlKFd8x%F&Z*F~&0{FeWl4F(xynFs3r5F{U$SFlI7lF=jL7Fy=DmG3GNC zFcvZvF%~nHFqSfwF_tq{Fjg{FF;+9yFxE2GG1fCSFg7waF*Y-{Ft#$bF}5>yFm^I_ zF?O@1=TsJC7(yr`_R_pe0|N_F2yF@FTN*?8CQuqCZw}=y>P6_Za~K1r#t5dy$Pg-J1hdNsW`z;V3L}^~ zMlkKhFzv=L?ZzS3n8~IvlTBeJo5D;sg_&#$GuaGgvKh=|GnmO{ zFq6$-CY!-bHiMaL1~b_lrrjK-%N(Z59Hz@0rq}|e*aD{50;bpkrq}{zg#}y}%<&d5 z$6LZ2ZwWKd66SbIn8}tflPzH;Tf$7Xgqds!GZ~h8jbN$Q$N*}fkpa{kBLk>8Mg~xG zj0~XW7#Tp#F*1O<&p{~x?tkrBkZxKQI0 Qh(45Pd;mmWVys>d0O}iScK`qY literal 0 HcmV?d00001 diff --git a/font/vcr.ttf b/font/vcr.ttf new file mode 100644 index 0000000000000000000000000000000000000000..dcca687a434d5c7b6a3027e65e0b7d8728b25c71 GIT binary patch literal 75864 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 E0C5zG4gdfE literal 0 HcmV?d00001 diff --git a/schemas/startgg.gql b/schemas/startgg.gql new file mode 100644 index 0000000..1b3b959 --- /dev/null +++ b/schemas/startgg.gql @@ -0,0 +1,2733 @@ +type Query { + """ + Returns the authenticated user + """ + currentUser: User + """ + Returns an entrant given its id + """ + entrant(id: ID!): Entrant + """ + Returns an event given its id or slug + """ + event(id: ID, slug: String): Event + """ + Returns a league given its id or slug + """ + league(id: ID, slug: String): League + """ + Paginated, filterable list of leagues + """ + leagues(query: LeagueQuery!): LeagueConnection + """ + Returns a participant given its id + """ + participant(id: ID!, isAdmin: Boolean): Participant + """ + Returns a phase given its id + """ + phase(id: ID): Phase + """ + Returns a phase group given its id + """ + phaseGroup(id: ID): PhaseGroup + """ + Returns a player given an id + """ + player(id: ID!): Player + """ + Returns a phase seed given its id + """ + seed(id: ID): Seed + """ + Returns a set given its id + """ + set(id: ID!): Set + """ + A shop entity + """ + shop(id: ID, slug: String): Shop + """ + Returns an stream given its id + """ + stream(id: ID!): Streams + """ + Returns all the stream queues for a given tournament + """ + streamQueue(tournamentId: ID!, includePlayerStreams: Boolean): [StreamQueue] + """ + Returns a team given its id + """ + team(id: ID, slug: String, inviteCode: String): Team + """ + Returns a tournament given its id or slug + """ + tournament(id: ID, slug: String): Tournament + """ + Paginated, filterable list of tournaments + """ + tournaments(query: TournamentQuery!): TournamentConnection + """ + Returns a user given a user slug of the form user/abc123, or id + """ + user(id: ID, slug: String): User + """ + Returns a videogame given its id + """ + videogame(id: ID, slug: String): Videogame + """ + Returns paginated list of videogames matching the search criteria. + """ + videogames(query: VideogameQuery!): VideogameConnection +} + +""" +A user +""" +type User { + """ + Authorizations to external services (i.e. Twitch, Twitter) + """ + authorizations(types: [SocialConnectionType]): [ProfileAuthorization] + id: ID + bio: String + """ + Public facing user birthday that respects user publishing settings + """ + birthday: String + """ + Uniquely identifying token for user. Same as the hashed part of the slug + """ + discriminator: String + email: String + """ + Events this user has competed in + """ + events(query: UserEventsPaginationQuery): EventConnection + genderPronoun: String + images(type: String): [Image] + """ + Leagues this user has competed in + """ + leagues(query: UserLeaguesPaginationQuery): LeagueConnection + """ + Public location info for this user + """ + location: Address + """ + Public facing user name that respects user publishing settings + """ + name: String + """ + player for user + """ + player: Player + slug: String + """ + Tournaments this user is organizing or competing in + """ + tournaments(query: UserTournamentsPaginationQuery): TournamentConnection +} + +""" +Represents the name of the third-party social service (e.g Twitter) for OAuth +""" +enum SocialConnectionType { + """ + + """ + TWITTER + """ + + """ + TWITCH + """ + + """ + DISCORD + """ + + """ + MIXER + """ + + """ + XBOX +} + +""" +An OAuth ProfileAuthorization object +""" +type ProfileAuthorization { + id: ID + """ + The id given by the external service + """ + externalId: String + """ + The username given by the external service (including discriminator if discord) + """ + externalUsername: String + stream: Stream + """ + The name of the external service providing this auth i.e. "twitch" + """ + type: AuthorizationType + url: String +} + +""" +A Stream object +""" +type Stream { + id: ID + """ + Whether the stream is currently live. May be slightly delayed. + """ + isOnline: Boolean + """ + The name of the stream + """ + name: String + """ + The name of the external service providing this auth i.e. "twitch" + """ + type: StreamType +} + +""" +Represents the type of stream service +""" +enum StreamType { + """ + + """ + TWITCH + """ + + """ + MIXER + """ + + """ + YOUTUBE +} + +""" +Represents the name of the third-party service (e.g Twitter) for OAuth +""" +enum AuthorizationType { + """ + + """ + TWITTER + """ + + """ + TWITCH + """ + + """ + STEAM + """ + + """ + DISCORD + """ + + """ + XBOX + """ + + """ + EPIC + """ + + """ + BATTLENET + """ + + """ + MIXER +} + +input UserEventsPaginationQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String + filter: UserEventsPaginationFilter +} + +input UserEventsPaginationFilter { + videogameId: [ID] + eventType: Int + minEntrantCount: Int + maxEntrantCount: Int + location: LocationFilterType + search: PaginationSearchType +} + +input LocationFilterType { + countryCode: String + state: String + city: String +} + +input PaginationSearchType { + fieldsToSearch: [String] + searchString: String +} + +type EventConnection { + pageInfo: PageInfo + nodes: [Event] +} + +type PageInfo { + total: Int + totalPages: Int + page: Int + perPage: Int + sortBy: String + filter: JSON +} + +""" +The `JSON` scalar type represents JSON values as specified by + [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). +""" +scalar JSON + +""" +An event in a tournament +""" +type Event { + id: ID + """ + How long before the event start will the check-in end (in seconds) + """ + checkInBuffer: Int + """ + How long the event check-in will last (in seconds) + """ + checkInDuration: Int + """ + Whether check-in is enabled for this event + """ + checkInEnabled: Boolean + """ + Rough categorization of event tier, denoting relative importance in the competitive scene + """ + competitionTier: Int + """ + When the event was created (unix timestamp) + """ + createdAt: Timestamp + """ + Last date attendees are able to create teams for team events + """ + deckSubmissionDeadline: Timestamp + """ + Maximum number of participants each Entrant can have + """ + entrantSizeMax: Int @deprecated(reason: "Migrate to teamRosterSize") + """ + Minimum number of participants each Entrant can have + """ + entrantSizeMin: Int @deprecated(reason: "Migrate to teamRosterSize") + """ + The entrants that belong to an event, paginated by filter criteria + """ + entrants(query: EventEntrantPageQuery): EntrantConnection + """ + Whether the event has decks + """ + hasDecks: Boolean + """ + Are player tasks enabled for this event + """ + hasTasks: Boolean + images(type: String): [Image] + """ + Whether the event is an online event or not + """ + isOnline: Boolean + league: League + """ + Markdown field for match rules/instructions + """ + matchRulesMarkdown: String + """ + Title of event set by organizer + """ + name: String + """ + Gets the number of entrants in this event + """ + numEntrants: Int + """ + The phase groups that belong to an event. + """ + phaseGroups: [PhaseGroup] + """ + The phases that belong to an event. + """ + phases( + """ + Filter phases by state. If not specified will default to all phases + """ + state: ActivityState + """ + Optionally only return results for this phase + """ + phaseId: ID + ): [Phase] + """ + TO settings for prizing + """ + prizingInfo: JSON + publishing: JSON + """ + Markdown field for event rules/instructions + """ + rulesMarkdown: String + """ + Id of the event ruleset + """ + rulesetId: Int + """ + Settings pulled from the event ruleset, if one exists + """ + rulesetSettings: JSON @deprecated(reason: "Use ruleset") + """ + Paginated sets for this Event + """ + sets( + page: Int + perPage: Int + """ + How to sort these sets + """ + sortType: SetSortType + """ + Supported filter options to filter down set results. + """ + filters: SetFilters + ): SetConnection + slug: String + """ + Paginated list of standings + """ + standings(query: StandingPaginationQuery!): StandingConnection + """ + When does this event start? + """ + startAt: Timestamp + """ + The state of the Event. + """ + state: ActivityState + """ + Paginated stations on this event + """ + stations(query: StationFilter): StationsConnection + """ + Last date attendees are able to create teams for team events + """ + teamManagementDeadline: Timestamp + """ + If this is a teams event, returns whether or not teams can set custom names + """ + teamNameAllowed: Boolean + """ + Team roster size requirements + """ + teamRosterSize: TeamRosterSize + tournament: Tournament + """ + The type of the event, whether an entrant will have one participant or multiple + """ + type: Int + """ + When the event was last modified (unix timestamp) + """ + updatedAt: Timestamp + """ + Whether the event uses the new EventSeeds for seeding + """ + useEventSeeds: Boolean + """ + The entrant (if applicable) for a given user in this event + """ + userEntrant( + """ + User to get entrant for. Defaults to currently logged in user. + """ + userId: ID + ): Entrant + videogame: Videogame + """ + The waves being used by the event + """ + waves( + """ + Waves filtered by phaseId, returns all if not set. + """ + phaseId: ID + ): [Wave] +} + +""" +Represents a Unix Timestamp. Supports up to 53 bit int values, + as that is JavaScript's internal memory allocation for integer values. +""" +scalar Timestamp + +input EventEntrantPageQuery { + page: Int + perPage: Int + sortBy: String + filter: EventEntrantPageQueryFilter +} + +input EventEntrantPageQueryFilter { + name: String +} + +type EntrantConnection { + pageInfo: PageInfo + nodes: [Entrant] +} + +""" +An entrant in an event +""" +type Entrant { + id: ID + event: Event + """ + Entrant's seed number in the first phase of the event. + """ + initialSeedNum: Int + isDisqualified: Boolean + """ + The entrant name as it appears in bracket: gamerTag of the participant or team name + """ + name: String + """ + Paginated sets for this entrant + """ + paginatedSets( + page: Int + perPage: Int + """ + How to sort these sets + """ + sortType: SetSortType + """ + Supported filter options to filter down set results. + """ + filters: SetFilters + ): SetConnection + participants: [Participant] + seeds: [Seed] + skill: Int + """ + Standing for this entrant given an event. All entrants queried must be in the same event (for now). + """ + standing: Standing + stream: Streams @deprecated(reason: "DEPRECATED. Use streams instead, which supports multiple stream types and teams.") + streams: [Streams] + """ + Team linked to this entrant, if one exists + """ + team: Team +} + +""" +Different sort type configurations used when displaying multiple sets +""" +enum SetSortType { + """ + Sets will not be sorted. + """ + NONE + """ + Sets are sorted in the suggested order that they be called to be played. The order of completed sets is reversed. + """ + CALL_ORDER + """ + Sets are sorted by relevancy dependent on the state and progress of the event. + """ + MAGIC + """ + Sets are sorted in the order that they were started. + """ + RECENT + """ + Deprecated. This is equivalent to CALL_ORDER + """ + STANDARD + """ + Sets sorted by round and identifier + """ + ROUND +} + +input SetFilters { + """ + Only return Sets for these Entrants + """ + entrantIds: [ID] + """ + Only return Sets for this Entrant size. For example, to fetch 1v1 Sets only, filter by an entrantSize of 1 + """ + entrantSize: [Int] + """ + Only return Sets that have an attached VOD + """ + hasVod: Boolean + """ + Do not return empty Sets. For example, set this to true to filter out sets that are waiting for progressions. + """ + hideEmpty: Boolean + """ + Return sets that contain a bye + """ + showByes: Boolean + """ + Only return Sets that are in an Online event. If omitted, Sets for both online and offline Events are returned + """ + isEventOnline: Boolean + """ + Only return Sets in certain geographical areas. + """ + location: SetFilterLocation + """ + Only return Sets for these Participants + """ + participantIds: [ID] + """ + Only return Sets in these PhaseGroups + """ + phaseGroupIds: [ID] + """ + Only return Sets in these Phases + """ + phaseIds: [ID] + """ + Only return Sets in these Events + """ + eventIds: [ID] + """ + Only return Sets in these Tournaments + """ + tournamentIds: [ID] + """ + Only return Sets for these Players + """ + playerIds: [ID] + """ + Only return Sets for these Rounds + """ + roundNumber: Int + """ + Only returns Sets that are in these states + """ + state: [Int] + """ + Only return Sets that are assigned to these Station IDs + """ + stationIds: [ID] + """ + Only return Sets that are assigned to these Station numbers + """ + stationNumbers: [Int] + """ + Only return sets created or updated since this timestamp + """ + updatedAfter: Timestamp +} + +""" +Filter Sets by geographical constraints. +""" +input SetFilterLocation { + """ + Only return Sets in this state. Only applicable to US states + """ + state: String + """ + Only return Sets in this country. Expects a valid two-letter country code + """ + country: String + distanceFrom: SetFilterLocationDistanceFrom +} + +""" +Only return Sets that are a certain distance away from a specified point +""" +input SetFilterLocationDistanceFrom { + """ + Point at which to perform distance calculation + """ + point: SetFilterLocationDistanceFromPoint + """ + Distance from the point to include results in + """ + radius: String +} + +input SetFilterLocationDistanceFromPoint { + lat: Float + lon: Float +} + +type SetConnection { + pageInfo: PageInfo + nodes: [Set] +} + +""" +A set +""" +type Set { + id: ID + """ + The time this set was marked as completed + """ + completedAt: Timestamp + """ + The time this set was created + """ + createdAt: Timestamp + displayScore(mainEntrantId: ID): String + """ + Event that this set belongs to. + """ + event: Event + """ + Full round text of this set. + """ + fullRoundText: String + game(orderNum: Int!): Game + games: [Game] + """ + Whether this set contains a placeholder entrant + """ + hasPlaceholder: Boolean + """ + The letters that describe a unique identifier within the pool. Eg. F, AT + """ + identifier: String + images(type: String): [Image] + lPlacement: Int + """ + Phase group that this Set belongs to. + """ + phaseGroup: PhaseGroup + """ + The sets that are affected from resetting this set + """ + resetAffectedData: ResetAffectedData + """ + The round number of the set. Negative numbers are losers bracket + """ + round: Int + """ + Indicates whether the set is in best of or total games mode. This instructs + which field is used to figure out how many games are in this set. + """ + setGamesType: Int + """ + A possible spot in a set. Use this to get all entrants in a set. Use this for all bracket types (FFA, elimination, etc) + """ + slots(includeByes: Boolean = false): [SetSlot] + """ + The start time of the Set. If there is no startAt time on the Set, will pull it from phaseGroup rounds configuration. + """ + startAt: Timestamp + startedAt: Timestamp + state: Int + """ + Tournament event station for a set + """ + station: Stations + """ + Tournament event stream for a set + """ + stream: Streams + """ + If setGamesType is in total games mode, this defined the number of games in the set. + """ + totalGames: Int + """ + Url of a VOD for this set + """ + vodUrl: String + wPlacement: Int + winnerId: Int +} + +""" +A game represents a single game within a set. +""" +type Game { + id: ID + """ + Score of entrant 1. For smash, this is equivalent to stocks remaining. + """ + entrant1Score: Int + """ + Score of entrant 2. For smash, this is equivalent to stocks remaining. + """ + entrant2Score: Int + images(type: String): [Image] + orderNum: Int + """ + Selections for this game such as character, etc. + """ + selections: [GameSelection] + """ + The stage that this game was played on (if applicable) + """ + stage: Stage + state: Int + winnerId: Int +} + +""" +An image +""" +type Image { + id: ID + height: Float + ratio: Float + type: String + url: String + width: Float +} + +""" +A selection for this game. i.e. character/stage selection, etc +""" +type GameSelection { + """ + If this is a character selection, returns the selected character. + """ + character: Character + id: ID + """ + The entrant who this selection is for + """ + entrant: Entrant + orderNum: Int + """ + The participant who this selection is for. This is only populated if there are + selections for multiple participants of a single entrant + """ + participant: Participant + selectionType: GameSelectionType + selectionValue: Int +} + +""" +A character in a videogame +""" +type Character { + id: ID + images(type: String): [Image] + """ + Name of Character + """ + name: String +} + +""" +A participant of a tournament; either a spectator or competitor +""" +type Participant { + id: ID + """ + If this participant was checked-in by admin + """ + checkedIn: Boolean + """ + The time this participant was checked-in by admin + """ + checkedInAt: Timestamp + """ + Info for connected accounts to external services. + """ + connectedAccounts: JSON + """ + Contact Info selected during registration. Falls back to User.location and/or + User.name if necessary. These fields are for admin use only. If you are not a + tournament admin or the participant being queried, these fields will be null. + Do not display this information publicly. + """ + contactInfo: ContactInfo + """ + Email of the user, only available to admins within 18 months of tournament completion for tournament administrators. + """ + email: String + """ + Entrants associated with this Participant, if applicable + """ + entrants: [Entrant] + """ + The events this participant registered for within a Tournament. + """ + events: [Event] + """ + The tag that was used when the participant registered, e.g. Mang0 + """ + gamerTag: String + images(type: String): [Image] + player: Player + """ + The prefix that the user set for this Tournament, e.g. C9 + """ + prefix: String + """ + Tournament Admin viewable field. Shows details for required social connections + """ + requiredConnections: [ProfileAuthorization] + """ + The user this participant is associated to. + """ + user: User + """ + If this participant is verified as actually being in the tournament + """ + verified: Boolean +} + +""" +Name, address, etc +""" +type ContactInfo { + id: ID + """ + Participant City Name + """ + city: String + """ + Participant Country Name + """ + country: String + """ + Participant Country (region) id + """ + countryId: Int + name: String + """ + First Name + """ + nameFirst: String + """ + Last Name + """ + nameLast: String + """ + Participant State Name + """ + state: String + """ + Participant State (region) id + """ + stateId: Int + """ + Zip or Postal Code + """ + zipcode: String +} + +""" +A player +""" +type Player { + id: ID + gamerTag: String + prefix: String + """ + Most recent active & published rankings + """ + rankings(limit: Int, videogameId: ID): [PlayerRank] + """ + Recent sets for this player. + """ + recentSets( + """ + Use this to get H2H history between two players + """ + opponentId: ID + ): [Set] @deprecated(reason: "Use the sets field instead.") + """ + Recent standings + """ + recentStandings( + videogameId: ID + """ + Number of recent standings to fetch. Default value is 3. Maximum value is 20. + """ + limit: Int + ): [Standing] + """ + Set history for this player. + """ + sets( + page: Int + perPage: Int + """ + Supported filter options to filter down set results. + """ + filters: SetFilters + ): SetConnection + user: User +} + +""" +A player's ranks +""" +type PlayerRank { + id: ID + """ + The player's placement on the ranking + """ + rank: Int + title: String +} + +""" +A standing indicates the placement of something within a container. +""" +type Standing { + id: ID + """ + The containing entity that contextualizes this standing. Event standings, for + example, represent an entrant's standing in the entire event vs. Set standings + which is an entrant's standing in only a single set within an event. + """ + container: StandingContainer + """ + If the entity this standing is assigned to can be resolved into an entrant, this will provide the entrant. + """ + entrant: Entrant + isFinal: Boolean + """ + Metadata that goes along with this standing. Can take on different forms based on standing group type and settings. + """ + metadata: JSON + placement: Int + """ + The player(s) tied to this standing's entity + """ + player: Player + standing: Int @deprecated(reason: "The \"placement\" field is identical and will eventually replace \"standing\"") + stats: StandingStats + totalPoints: Float +} + +""" +The containing entity that this standing is for +""" +union StandingContainer = Tournament | Event | PhaseGroup | Set + +""" +A tournament +""" +type Tournament { + id: ID + addrState: String + """ + Admin-only view of admins for this tournament + """ + admins( + """ + Which roles to show + """ + roles: [String] + ): [User] + city: String + countryCode: String + """ + When the tournament was created (unix timestamp) + """ + createdAt: Timestamp + currency: String + """ + When the tournament ends + """ + endAt: Timestamp + """ + When does event registration close + """ + eventRegistrationClosesAt: Timestamp + events(limit: Int, filter: EventFilter): [Event] + """ + True if tournament has at least one offline event + """ + hasOfflineEvents: Boolean + hasOnlineEvents: Boolean + hashtag: String + images(type: String): [Image] + """ + True if tournament has at least one online event + """ + isOnline: Boolean + """ + Is tournament registration open + """ + isRegistrationOpen: Boolean + lat: Float + links: TournamentLinks + lng: Float + mapsPlaceId: String + """ + The tournament name + """ + name: String + """ + Number of attendees including spectators, if public + """ + numAttendees: Int + """ + The user who created the tournament + """ + owner: User + """ + Paginated, queryable list of participants + """ + participants(query: ParticipantPaginationQuery!, isAdmin: Boolean): ParticipantConnection + postalCode: String + primaryContact: String + primaryContactType: String + """ + Publishing settings for this tournament + """ + publishing: JSON + """ + When does registration for the tournament end + """ + registrationClosesAt: Timestamp + rules: String + """ + The short slug used to form the url + """ + shortSlug: String + """ + The slug used to form the url + """ + slug: String + """ + When the tournament Starts + """ + startAt: Timestamp + """ + State of the tournament, can be ActivityState::CREATED, ActivityState::ACTIVE, or ActivityState::COMPLETED + """ + state: Int + stations(page: Int, perPage: Int): StationsConnection + streamQueue: [StreamQueue] + streams: [Streams] + """ + When is the team creation deadline + """ + teamCreationClosesAt: Timestamp + """ + Paginated, queryable list of teams + """ + teams(query: TeamPaginationQuery!): TeamConnection + """ + The timezone of the tournament + """ + timezone: String + """ + The type of tournament from TournamentType + """ + tournamentType: Int + """ + When the tournament was last modified (unix timestamp) + """ + updatedAt: Timestamp + """ + Build Tournament URL + """ + url( + """ + Tournament tab to add to URL + """ + tab: String + """ + Generate a relative URL. Defaults to true. Setting to false will generate an absolute URL + """ + relative: Boolean = true + ): String + venueAddress: String + venueName: String + """ + List of all waves in this tournament + """ + waves: [Wave] +} + +input EventFilter { + videogameId: [ID] + type: [Int] + published: Boolean + id: ID + ids: [ID] + slug: String + fantasyEventId: ID + fantasyRosterHash: String +} + +type TournamentLinks { + facebook: String + discord: String +} + +input ParticipantPaginationQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String + filter: ParticipantPageFilter +} + +input ParticipantPageFilter { + id: ID + ids: [ID] + eventIds: [ID] + search: PaginationSearchType + gamerTag: String + unpaid: Boolean + incompleteTeam: Boolean + missingDeck: Boolean + checkedIn: Boolean + notCheckedIn: Boolean +} + +type ParticipantConnection { + pageInfo: PageInfo + nodes: [Participant] +} + +type StationsConnection { + pageInfo: PageInfo + nodes: [Stations] +} + +""" +Stations, such as a stream setup, at an event +""" +type Stations { + id: ID + canAutoAssign: Boolean + clusterNumber: String + clusterPrefix: Int + enabled: Boolean + identifier: Int + numSetups: Int + number: Int + prefix: String + queue: JSON + queueDepth: Int + state: Int + updatedAt: Timestamp +} + +""" +A Stream queue object +""" +type StreamQueue { + id: String + """ + The sets on the stream + """ + sets: [Set] + """ + The stream on the queue + """ + stream: Streams +} + +""" +Tournament Stream +""" +type Streams { + id: ID + enabled: Boolean + followerCount: Int + isOnline: Boolean + numSetups: Int + parentStreamId: Int + streamGame: String + streamId: String + streamLogo: String + streamName: String + streamSource: StreamSource + streamStatus: String + streamType: Int + streamTypeId: Int +} + +""" +Represents the source of a stream +""" +enum StreamSource { + """ + Stream is on twitch.tv channel + """ + TWITCH + """ + Stream is on smashcast.tv channel + """ + HITBOX + """ + Stream is on a stream.me channel + """ + STREAMME + """ + Stream is on a mixer.com channel + """ + MIXER + """ + Stream is on a youtube.com channel + """ + YOUTUBE +} + +input TeamPaginationQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String + filter: TeamPaginationFilter +} + +input TeamPaginationFilter { + globalTeamId: ID + eventState: ActivityState + eventId: ID + eventIds: [ID] + minEntrantCount: Int + maxEntrantCount: Int + search: PaginationSearchType + type: Int + tournamentId: ID + memberStatus: [TeamMemberStatus] + videogameId: [ID] + isLeague: Boolean + upcoming: Boolean + past: Boolean + rosterComplete: Boolean + rosterIncomplete: Boolean +} + +""" +Represents the state of an activity +""" +enum ActivityState { + """ + Activity is created + """ + CREATED + """ + Activity is active or in progress + """ + ACTIVE + """ + Activity is done + """ + COMPLETED + """ + Activity is ready to be started + """ + READY + """ + Activity is invalid + """ + INVALID + """ + Activity, like a set, has been called to start + """ + CALLED + """ + Activity is queued to run + """ + QUEUED +} + +""" +Membership status of a team member +""" +enum TeamMemberStatus { + """ + + """ + UNKNOWN + """ + + """ + ACCEPTED + """ + + """ + INVITED + """ + + """ + REQUEST + """ + + """ + ALUM + """ + + """ + HIATUS + """ + + """ + OPEN_SPOT +} + +type TeamConnection { + pageInfo: PageInfo + nodes: [Team] +} + +""" +A team, either at the global level or within the context of an event +""" +interface Team { + id: ID + """ + Uniquely identifying token for team. Same as the hashed part of the slug + """ + discriminator: String + entrant: Entrant @deprecated(reason: "Use the entrant field off the EventTeam type") + event: Event @deprecated(reason: "Use the event field off the EventTeam type") + images(type: String): [Image] + members(status: [TeamMemberStatus]): [TeamMember] + name: String +} + +""" +A member of a team +""" +type TeamMember { + id: ID + isAlternate: Boolean + isCaptain: Boolean + """ + The type of the team member + """ + memberType: TeamMemberType + participant: Participant + player: Player + """ + The status of the team member + """ + status: TeamMemberStatus +} + +""" +Membership type of a team member +""" +enum TeamMemberType { + """ + + """ + PLAYER + """ + + """ + STAFF +} + +""" +A wave in a tournament +""" +type Wave { + id: ID + """ + The Wave Identifier + """ + identifier: String + """ + Unix time the wave is scheduled to start. + """ + startAt: Timestamp +} + +""" +A group within a phase +""" +type PhaseGroup { + id: ID + """ + The bracket type of this group's phase. + """ + bracketType: BracketType + """ + URL for this phase groups's bracket. + """ + bracketUrl: String + """ + Unique identifier for this group within the context of its phase + """ + displayIdentifier: String + """ + For the given phase group, this is the start time of the first round that occurs in the group. + """ + firstRoundTime: Timestamp + numRounds: Int + paginatedSeeds(query: SeedPaginationQuery!, eventId: ID): SeedConnection @deprecated(reason: "Please use 'seeds', which is now paginated") + """ + Paginated sets on this phaseGroup + """ + paginatedSets( + page: Int + perPage: Int + """ + How to sort these sets + """ + sortType: SetSortType + """ + Supported filter options to filter down set results. + """ + filters: SetFilters + ): SetConnection @deprecated(reason: "Please use 'sets', which is now paginated") + """ + The phase associated with this phase group + """ + phase: Phase + """ + The progressions out of this phase group + """ + progressionsOut: [Progression] + rounds: [Round] + seedMap: JSON + """ + Paginated seeds for this phase group + """ + seeds(query: SeedPaginationQuery!, eventId: ID): SeedConnection + """ + Paginated sets on this phaseGroup + """ + sets( + page: Int + perPage: Int + """ + How to sort these sets + """ + sortType: SetSortType + """ + Supported filter options to filter down set results. + """ + filters: SetFilters + ): SetConnection + """ + Paginated list of standings + """ + standings(query: StandingGroupStandingPageFilter): StandingConnection + """ + Unix time the group is scheduled to start. This info could also be on the wave instead. + """ + startAt: Timestamp + state: Int + tiebreakOrder: JSON + wave: Wave +} + +""" +The type of Bracket format that a Phase is configured with. +""" +enum BracketType { + """ + + """ + SINGLE_ELIMINATION + """ + + """ + DOUBLE_ELIMINATION + """ + + """ + ROUND_ROBIN + """ + + """ + SWISS + """ + + """ + EXHIBITION + """ + + """ + CUSTOM_SCHEDULE + """ + + """ + MATCHMAKING + """ + + """ + ELIMINATION_ROUNDS + """ + + """ + RACE + """ + + """ + CIRCUIT +} + +input SeedPaginationQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String + filter: SeedPageFilter +} + +input SeedPageFilter { + id: ID + entrantName: String + checkInState: [Int] + phaseGroupId: [ID] + eventCheckInGroupId: ID + phaseId: [ID] + eventId: ID + search: PaginationSearchType +} + +type SeedConnection { + pageInfo: PageInfo + nodes: [Seed] +} + +""" +A seed for an entrant +""" +type Seed { + id: ID + """ + Map of Participant ID to checked in boolean + """ + checkedInParticipants: JSON + entrant: Entrant + groupSeedNum: Int + isBye: Boolean + phase: Phase + phaseGroup: PhaseGroup + placeholderName: String + placement: Int + """ + The player(s) associated with this seed's entrant + """ + players: [Player] + progressionSeedId: Int + """ + Source progression information + """ + progressionSource: Progression + seedNum: Int + """ + Entrant's win/loss record for this standing. Scores do not include byes. + """ + setRecordWithoutByes(phaseGroupId: ID!): JSON + standings( + """ + The container of the standing groups to get standings for. If null, will return all standings. + """ + containerType: String + ): [Standing] +} + +""" +A phase in an event +""" +type Phase { + id: ID + """ + The bracket type of this phase. + """ + bracketType: BracketType + """ + The Event that this phase belongs to + """ + event: Event + """ + Number of phase groups in this phase + """ + groupCount: Int + """ + Is the phase an exhibition or not. + """ + isExhibition: Boolean + """ + Name of phase e.g. Round 1 Pools + """ + name: String + """ + The number of seeds this phase contains. + """ + numSeeds: Int + paginatedSeeds(query: SeedPaginationQuery!, eventId: ID): SeedConnection @deprecated(reason: "Please use 'seeds' instead") + """ + Phase groups under this phase, paginated + """ + phaseGroups(query: PhaseGroupPageQuery): PhaseGroupConnection + """ + The relative order of this phase within an event + """ + phaseOrder: Int + """ + Paginated seeds for this phase + """ + seeds(query: SeedPaginationQuery!, eventId: ID): SeedConnection + """ + Paginated sets for this Phase + """ + sets( + page: Int + perPage: Int + """ + How to sort these sets + """ + sortType: SetSortType + """ + Supported filter options to filter down set results. + """ + filters: SetFilters + ): SetConnection + """ + State of the phase + """ + state: ActivityState + waves: [Wave] +} + +input PhaseGroupPageQuery { + page: Int + perPage: Int + sortBy: String + entrantIds: [ID] + filter: PhaseGroupPageQueryFilter +} + +input PhaseGroupPageQueryFilter { + id: [ID] + waveId: ID +} + +type PhaseGroupConnection { + pageInfo: PageInfo + nodes: [PhaseGroup] +} + +""" +A connection between a placement in an origin phase group to a destination seed. +""" +type Progression { + id: ID + originOrder: Int + originPhase: Phase + originPhaseGroup: PhaseGroup + originPlacement: Int +} + +""" +A round within a phase group +""" +type Round { + id: ID + """ + If applicable, bestOf is the number of games + one must win a majority out of to win a set in this round + """ + bestOf: Int + """ + Indicates this round's order in the phase group + """ + number: Int + """ + The time that this round is scheduled to start at + """ + startAt: Timestamp +} + +input StandingGroupStandingPageFilter { + page: Int + perPage: Int + sortBy: String +} + +type StandingConnection { + pageInfo: PageInfo + nodes: [Standing] +} + +""" +Any stats related to this standing. This type is experimental and very likely to change in the future. +""" +type StandingStats { + score: Score +} + +""" +The score that led to this standing being awarded. The meaning of this field can +vary by standing type and is not used for some standing types. +""" +type Score { + """ + The name of this score. e.g. "Kills" or "Stocks" + """ + label: String + """ + The raw score value + """ + value: Float + """ + Like value, but formatted for race format events. Formatted according to the race config for the front end to use. + """ + displayValue: String +} + +""" +The type of selection i.e. is it for a character or something else +""" +enum GameSelectionType { + """ + Character selection + """ + CHARACTER +} + +""" +Video Stage +""" +type Stage { + id: ID + """ + Stage name + """ + name: String +} + +type ResetAffectedData { + affectedSetCount: Int + affectedSets: [Set] + affectedPhaseGroupCount: Int +} + +""" +A slot in a set where a seed currently or will eventually exist in order to participate in the set. +""" +type SetSlot { + id: ID + entrant: Entrant + """ + Pairs with prereqType, is the ID of the prereq. + """ + prereqId: String + """ + Given a set prereq type, defines the placement required in the origin set to end up in this slot. + """ + prereqPlacement: Int + """ + Describes where the entity in this slot comes from. + """ + prereqType: String + seed: Seed + """ + The index of the slot. Unique per set. + """ + slotIndex: Int + """ + The standing within this set for the seed currently assigned to this slot. + """ + standing: Standing +} + +""" +A league +""" +type League { + id: ID + addrState: String + city: String + countryCode: String + """ + When the tournament was created (unix timestamp) + """ + createdAt: Timestamp + currency: String + """ + When the tournament ends + """ + endAt: Timestamp + entrantCount: Int + eventOwners(query: EventOwnersQuery): EventOwnerConnection + """ + When does event registration close + """ + eventRegistrationClosesAt: Timestamp + """ + Paginated list of events in a league + """ + events(query: LeagueEventsQuery): EventConnection + """ + Hacked "progression" into this final event + """ + finalEventId: Int @deprecated(reason: "No longer used") + """ + True if tournament has at least one offline event + """ + hasOfflineEvents: Boolean + hasOnlineEvents: Boolean + hashtag: String + images(type: String): [Image] + """ + True if tournament has at least one online event + """ + isOnline: Boolean + lat: Float + links: TournamentLinks + lng: Float + mapsPlaceId: String + """ + The tournament name + """ + name: String + """ + Top X number of people in the standings who progress to final event + """ + numProgressingToFinalEvent: Int @deprecated(reason: "No longer used") + numUniquePlayers: Int + postalCode: String + primaryContact: String + primaryContactType: String + """ + Publishing settings for this tournament + """ + publishing: JSON + """ + When does registration for the tournament end + """ + registrationClosesAt: Timestamp + rules: String + """ + The short slug used to form the url + """ + shortSlug: String + """ + Whether standings for this league should be visible + """ + showStandings: Boolean + slug: String + """ + Paginated list of standings + """ + standings(query: StandingGroupStandingPageFilter): StandingConnection + """ + When the tournament Starts + """ + startAt: Timestamp + """ + State of the tournament, can be ActivityState::CREATED, ActivityState::ACTIVE, or ActivityState::COMPLETED + """ + state: Int + """ + When is the team creation deadline + """ + teamCreationClosesAt: Timestamp + tiers: [EventTier] + """ + The timezone of the tournament + """ + timezone: String + """ + The type of tournament from TournamentType + """ + tournamentType: Int + """ + When the tournament was last modified (unix timestamp) + """ + updatedAt: Timestamp + """ + Build Tournament URL + """ + url( + """ + Tournament tab to add to URL + """ + tab: String + """ + Generate a relative URL. Defaults to true. Setting to false will generate an absolute URL + """ + relative: Boolean = true + ): String + venueAddress: String + venueName: String + videogames: [Videogame] +} + +input EventOwnersQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String +} + +type EventOwnerConnection { + pageInfo: PageInfo + nodes: [EventOwner] +} + +""" +Name and Gamertag of the owner of an event in a league +""" +type EventOwner { + eventId: ID + email: String + gamerTag: String + fullName: String +} + +input LeagueEventsQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String + filter: LeagueEventsFilter +} + +input LeagueEventsFilter { + search: PaginationSearchType + pointMappingGroupIds: [ID] + tierIds: [ID] + userId: ID + upcoming: Boolean + leagueEntrantId: ID +} + +""" +Used for league application tiers +""" +type EventTier { + id: ID + """ + Name of this tier + """ + name: String +} + +""" +A videogame +""" +type Videogame { + id: ID + """ + All characters for this videogame + """ + characters: [Character] + displayName: String + images(type: String): [Image] + name: String + slug: String + """ + All stages for this videogame + """ + stages: [Stage] +} + +input StandingPaginationQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String + filter: StandingPageFilter +} + +input StandingPageFilter { + id: ID + ids: [ID] + search: PaginationSearchType +} + +input StationFilter { + page: Int + perPage: Int +} + +""" +Team roster size requirements +""" +type TeamRosterSize { + maxAlternates: Int + maxPlayers: Int + minAlternates: Int + minPlayers: Int +} + +input UserLeaguesPaginationQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String + filter: UserLeaguesPaginationFilter +} + +input UserLeaguesPaginationFilter { + videogameId: [ID] + upcoming: Boolean + past: Boolean + search: PaginationSearchType +} + +type LeagueConnection { + pageInfo: PageInfo + nodes: [League] +} + +""" +A user's address +""" +type Address { + id: ID + city: String + country: String + countryId: Int + state: String + stateId: Int +} + +input UserTournamentsPaginationQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String + filter: UserTournamentsPaginationFilter +} + +input UserTournamentsPaginationFilter { + past: Boolean + upcoming: Boolean + search: PaginationSearchType + videogameId: [ID] + tournamentView: String + excludeId: [ID] +} + +type TournamentConnection { + pageInfo: PageInfo + nodes: [Tournament] +} + +input LeagueQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String + filter: LeaguePageFilter + sort: TournamentPaginationSort +} + +input LeaguePageFilter { + id: ID + ids: [ID] + """ + ID of the user that owns this league. + """ + ownerId: ID + afterDate: Timestamp + beforeDate: Timestamp + computedUpdatedAt: Timestamp + name: String + isFeatured: Boolean + hasBannerImages: Boolean + activeShops: Boolean + past: Boolean + published: Boolean + publiclySearchable: Boolean + upcoming: Boolean + videogameIds: [ID] +} + +enum TournamentPaginationSort { + """ + + """ + startAt + """ + + """ + endAt + """ + + """ + eventRegistrationClosesAt + """ + + """ + computedUpdatedAt +} + +""" +A shop +""" +type Shop { + id: ID + levels(query: ShopLevelsQuery): ShopLevelConnection + messages(query: ShopOrderMessagesQuery): ShopOrderMessageConnection + name: String + slug: String + url: String +} + +input ShopLevelsQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String +} + +type ShopLevelConnection { + pageInfo: PageInfo + nodes: [ShopLevel] +} + +""" +A shop level +""" +type ShopLevel { + id: ID + currAmount: Float + description: String + goalAmount: Float + images(type: String): [Image] + name: String +} + +input ShopOrderMessagesQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String +} + +type ShopOrderMessageConnection { + pageInfo: PageInfo + nodes: [ShopOrderMessage] +} + +""" +The message and player info for a shop order +""" +type ShopOrderMessage { + id: ID + """ + The player's gamertag. Returns null if anonymous message type + """ + gamertag: String + """ + The order message + """ + message: String + """ + The player's name. Returns null unless name & tag display is selected + """ + name: String + """ + The player who left the comment + """ + player: Player + """ + The total order amount + """ + total: Float +} + +input TournamentQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String + filter: TournamentPageFilter + sort: TournamentPaginationSort +} + +input TournamentPageFilter { + id: ID + ids: [ID] + """ + ID of the user that owns this tournament. + """ + ownerId: ID + """ + If true, filter to only tournaments the currently authed user is an admin of + """ + isCurrentUserAdmin: Boolean + countryCode: String + addrState: String + location: TournamentLocationFilter + afterDate: Timestamp + beforeDate: Timestamp + computedUpdatedAt: Timestamp + name: String + venueName: String + isFeatured: Boolean + isLeague: Boolean + hasBannerImages: Boolean + activeShops: Boolean + regOpen: Boolean + past: Boolean + published: Boolean + publiclySearchable: Boolean + staffPicks: Boolean + hasOnlineEvents: Boolean + topGames: TopGameFilter + upcoming: Boolean + videogameIds: [ID] + sortByScore: Boolean +} + +input TournamentLocationFilter { + """ + Latitude, Longitude + """ + distanceFrom: String + """ + e.g. 50mi + """ + distance: String +} + +input TopGameFilter { + """ + Array of which # top game you want to filter on.e.g. [2, 3] will filter on the 2nd and 3rd top games + """ + gameNums: [Int] +} + +input VideogameQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String + filter: VideogamePageFilter +} + +input VideogamePageFilter { + id: [ID] + name: String + forUser: ID +} + +type VideogameConnection { + pageInfo: PageInfo + nodes: [Videogame] +} + +type Mutation { + """ + Delete a phase by id + """ + deletePhase(phaseId: ID!): Boolean + """ + Delete a station by id + """ + deleteStation(stationId: ID!): Boolean + """ + Delete a wave by id + """ + deleteWave(waveId: ID!): Boolean + """ + Generate tournament registration Token on behalf of user + """ + generateRegistrationToken(registration: TournamentRegistrationInput!, userId: ID!): String + """ + Update a set to called state + """ + markSetCalled(setId: ID!): Set + """ + Update a set to called state + """ + markSetInProgress(setId: ID!): Set + """ + Register for tournament + """ + registerForTournament(registration: TournamentRegistrationInput, registrationToken: String): Participant + """ + Report set winner or game stats for a H2H bracket set. If winnerId is + supplied, mark set as complete. gameData parameter will overwrite any existing + reported game data. + """ + reportBracketSet(setId: ID!, winnerId: ID, isDQ: Boolean, gameData: [BracketSetGameDataInput]): [Set] + """ + Resets set to initial state, can affect other sets and phase groups + """ + resetSet(setId: ID!, resetDependentSets: Boolean): Set + """ + Automatically attempt to resolve all schedule conflicts. Returns a list of changed seeds + """ + resolveScheduleConflicts(tournamentId: ID!, options: ResolveConflictsOptions): [Seed] + """ + Swap two seed ids in a phase + """ + swapSeeds(phaseId: ID!, seed1Id: ID!, seed2Id: ID!): [Seed] + """ + Update game stats for a H2H bracket set. Set winner cannot be changed with + this function, use the resetSet mutation instead. + """ + updateBracketSet(setId: ID!, winnerId: ID, isDQ: Boolean, gameData: [BracketSetGameDataInput]): Set + """ + Update set of phase groups in a phase + """ + updatePhaseGroups(groupConfigs: [PhaseGroupUpdateInput]!): [PhaseGroup] + """ + Update the seeding for a phase + """ + updatePhaseSeeding(phaseId: ID!, seedMapping: [UpdatePhaseSeedInfo]!, options: UpdatePhaseSeedingOptions): Phase + """ + Create or update a Phase + """ + upsertPhase(phaseId: ID, eventId: ID, payload: PhaseUpsertInput!): Phase + """ + Add or update a station by id + """ + upsertStation(stationId: ID, tournamentId: ID, fields: StationUpsertInput!): Stations + """ + Add or update a wave by id + """ + upsertWave(waveId: ID, tournamentId: ID, fields: WaveUpsertInput!): Wave +} + +input TournamentRegistrationInput { + eventIds: [ID] +} + +""" +Game specific H2H set data such as character, stage, and stock info +""" +input BracketSetGameDataInput { + """ + Entrant ID of game winner + """ + winnerId: ID + """ + Game number + """ + gameNum: Int! + """ + Score for entrant 1 (if applicable). For smash, this is stocks remaining. + """ + entrant1Score: Int + """ + Score for entrant 2 (if applicable). For smash, this is stocks remaining. + """ + entrant2Score: Int + """ + ID of the stage that was played for this game (if applicable) + """ + stageId: ID + """ + List of selections for the game, typically character selections. + """ + selections: [BracketSetGameSelectionInput] +} + +""" +Game specific H2H selections made by the entrants, such as character info +""" +input BracketSetGameSelectionInput { + """ + Entrant ID that made selection + """ + entrantId: ID! + """ + Character selected by this entrant for this game. + """ + characterId: Int +} + +input ResolveConflictsOptions { + lockedSeeds: [ResolveConflictsLockedSeedConfig] +} + +input ResolveConflictsLockedSeedConfig { + eventId: ID! + numSeeds: Int! +} + +input PhaseGroupUpdateInput { + phaseGroupId: ID! + stationId: ID + waveId: ID +} + +input UpdatePhaseSeedInfo { + seedId: ID! + seedNum: ID! + phaseGroupId: ID +} + +input UpdatePhaseSeedingOptions { + """ + Validate that seedMapping exactly accounts for all entrants in the phase + """ + strictMode: Boolean +} + +input PhaseUpsertInput { + """ + The name of the Phase. For example, "Top 8" or "Pools" + """ + name: String + """ + The number of pools to configure for the Phase. Only applies to brackets that support pools + """ + groupCount: Int + bracketType: BracketType +} + +input StationUpsertInput { + number: Int! + clusterId: ID +} + +input WaveUpsertInput { + identifier: String! + startAt: Timestamp! + endAt: Timestamp! +} + +""" +A set of actions available for an entity to take +""" +interface ActionSet { + id: ID +} + +""" +Bracket-specific configuration +""" +interface BracketConfig { + id: ID + bracketType: BracketType +} + +""" +Comparison operator +""" +enum Comparator { + """ + + """ + GREATER_THAN + """ + + """ + GREATER_THAN_OR_EQUAL + """ + + """ + EQUAL + """ + + """ + LESS_THAN_OR_EQUAL + """ + + """ + LESS_THAN +} + +""" +An event-level Team, in the context of some competition +""" +type EventTeam implements Team { + id: ID + """ + Uniquely identifying token for team. Same as the hashed part of the slug + """ + discriminator: String + entrant: Entrant @deprecated(reason: "Use the entrant field off the EventTeam type") + event: Event @deprecated(reason: "Use the event field off the EventTeam type") + globalTeam: GlobalTeam + images(type: String): [Image] + members(status: [TeamMemberStatus]): [TeamMember] + name: String +} + +""" +Global Team +""" +type GlobalTeam implements Team { + id: ID + """ + Uniquely identifying token for team. Same as the hashed part of the slug + """ + discriminator: String + entrant: Entrant @deprecated(reason: "Use the entrant field off the EventTeam type") + event: Event @deprecated(reason: "Use the event field off the EventTeam type") + eventTeams(query: TeamPaginationQuery): EventTeamConnection + images(type: String): [Image] + """ + Leagues-level teams for leagues this team is competing in + """ + leagueTeams(query: TeamPaginationQuery): EventTeamConnection + members(status: [TeamMemberStatus]): [TeamMember] + name: String +} + +type EventTeamConnection { + pageInfo: PageInfo + nodes: [EventTeam] +} + +""" +Match-level configuration +""" +interface MatchConfig { + id: ID + bracketType: BracketType +} + +""" +Different options available for verifying player-reported match results +""" +enum MatchConfigVerificationMethod { + """ + + """ + TWITCH + """ + + """ + STREAM_ME + """ + + """ + ANY + """ + + """ + MIXER + """ + + """ + YOUTUBE +} + +""" +Race specific bracket configuration +""" +type RaceBracketConfig implements BracketConfig { + automaticEndTime: Timestamp + id: ID + automaticStartTime: Timestamp + bracketType: BracketType + goalTargetComparator: Comparator + goalTargetValue: String + limitMode: RaceLimitMode + limitValue: Int + raceType: RaceType +} + +""" +Enforces limits on the amount of allowable Race submissions +""" +enum RaceLimitMode { + """ + + """ + BEST_ALL + """ + + """ + FIRST_ALL + """ + + """ + PLAYTIME +} + +""" +Race type +""" +enum RaceType { + """ + + """ + GOALS + """ + + """ + TIMED +} + +""" +Race specific match configuration +""" +type RaceMatchConfig implements MatchConfig { + id: ID + bracketType: BracketType + """ + Can players report results? + """ + playerReportingEnabled: Boolean + """ + Accepted methods of verification that players can use + """ + verificationMethods: [MatchConfigVerificationMethod] + """ + Are players required to submit verification of their reported results? + """ + verificationRequired: Boolean +} + +""" +A set of actions available for a team to take +""" +type TeamActionSet implements ActionSet { + id: ID +} + diff --git a/smash.gql b/smash.gql new file mode 100644 index 0000000..1b3b959 --- /dev/null +++ b/smash.gql @@ -0,0 +1,2733 @@ +type Query { + """ + Returns the authenticated user + """ + currentUser: User + """ + Returns an entrant given its id + """ + entrant(id: ID!): Entrant + """ + Returns an event given its id or slug + """ + event(id: ID, slug: String): Event + """ + Returns a league given its id or slug + """ + league(id: ID, slug: String): League + """ + Paginated, filterable list of leagues + """ + leagues(query: LeagueQuery!): LeagueConnection + """ + Returns a participant given its id + """ + participant(id: ID!, isAdmin: Boolean): Participant + """ + Returns a phase given its id + """ + phase(id: ID): Phase + """ + Returns a phase group given its id + """ + phaseGroup(id: ID): PhaseGroup + """ + Returns a player given an id + """ + player(id: ID!): Player + """ + Returns a phase seed given its id + """ + seed(id: ID): Seed + """ + Returns a set given its id + """ + set(id: ID!): Set + """ + A shop entity + """ + shop(id: ID, slug: String): Shop + """ + Returns an stream given its id + """ + stream(id: ID!): Streams + """ + Returns all the stream queues for a given tournament + """ + streamQueue(tournamentId: ID!, includePlayerStreams: Boolean): [StreamQueue] + """ + Returns a team given its id + """ + team(id: ID, slug: String, inviteCode: String): Team + """ + Returns a tournament given its id or slug + """ + tournament(id: ID, slug: String): Tournament + """ + Paginated, filterable list of tournaments + """ + tournaments(query: TournamentQuery!): TournamentConnection + """ + Returns a user given a user slug of the form user/abc123, or id + """ + user(id: ID, slug: String): User + """ + Returns a videogame given its id + """ + videogame(id: ID, slug: String): Videogame + """ + Returns paginated list of videogames matching the search criteria. + """ + videogames(query: VideogameQuery!): VideogameConnection +} + +""" +A user +""" +type User { + """ + Authorizations to external services (i.e. Twitch, Twitter) + """ + authorizations(types: [SocialConnectionType]): [ProfileAuthorization] + id: ID + bio: String + """ + Public facing user birthday that respects user publishing settings + """ + birthday: String + """ + Uniquely identifying token for user. Same as the hashed part of the slug + """ + discriminator: String + email: String + """ + Events this user has competed in + """ + events(query: UserEventsPaginationQuery): EventConnection + genderPronoun: String + images(type: String): [Image] + """ + Leagues this user has competed in + """ + leagues(query: UserLeaguesPaginationQuery): LeagueConnection + """ + Public location info for this user + """ + location: Address + """ + Public facing user name that respects user publishing settings + """ + name: String + """ + player for user + """ + player: Player + slug: String + """ + Tournaments this user is organizing or competing in + """ + tournaments(query: UserTournamentsPaginationQuery): TournamentConnection +} + +""" +Represents the name of the third-party social service (e.g Twitter) for OAuth +""" +enum SocialConnectionType { + """ + + """ + TWITTER + """ + + """ + TWITCH + """ + + """ + DISCORD + """ + + """ + MIXER + """ + + """ + XBOX +} + +""" +An OAuth ProfileAuthorization object +""" +type ProfileAuthorization { + id: ID + """ + The id given by the external service + """ + externalId: String + """ + The username given by the external service (including discriminator if discord) + """ + externalUsername: String + stream: Stream + """ + The name of the external service providing this auth i.e. "twitch" + """ + type: AuthorizationType + url: String +} + +""" +A Stream object +""" +type Stream { + id: ID + """ + Whether the stream is currently live. May be slightly delayed. + """ + isOnline: Boolean + """ + The name of the stream + """ + name: String + """ + The name of the external service providing this auth i.e. "twitch" + """ + type: StreamType +} + +""" +Represents the type of stream service +""" +enum StreamType { + """ + + """ + TWITCH + """ + + """ + MIXER + """ + + """ + YOUTUBE +} + +""" +Represents the name of the third-party service (e.g Twitter) for OAuth +""" +enum AuthorizationType { + """ + + """ + TWITTER + """ + + """ + TWITCH + """ + + """ + STEAM + """ + + """ + DISCORD + """ + + """ + XBOX + """ + + """ + EPIC + """ + + """ + BATTLENET + """ + + """ + MIXER +} + +input UserEventsPaginationQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String + filter: UserEventsPaginationFilter +} + +input UserEventsPaginationFilter { + videogameId: [ID] + eventType: Int + minEntrantCount: Int + maxEntrantCount: Int + location: LocationFilterType + search: PaginationSearchType +} + +input LocationFilterType { + countryCode: String + state: String + city: String +} + +input PaginationSearchType { + fieldsToSearch: [String] + searchString: String +} + +type EventConnection { + pageInfo: PageInfo + nodes: [Event] +} + +type PageInfo { + total: Int + totalPages: Int + page: Int + perPage: Int + sortBy: String + filter: JSON +} + +""" +The `JSON` scalar type represents JSON values as specified by + [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). +""" +scalar JSON + +""" +An event in a tournament +""" +type Event { + id: ID + """ + How long before the event start will the check-in end (in seconds) + """ + checkInBuffer: Int + """ + How long the event check-in will last (in seconds) + """ + checkInDuration: Int + """ + Whether check-in is enabled for this event + """ + checkInEnabled: Boolean + """ + Rough categorization of event tier, denoting relative importance in the competitive scene + """ + competitionTier: Int + """ + When the event was created (unix timestamp) + """ + createdAt: Timestamp + """ + Last date attendees are able to create teams for team events + """ + deckSubmissionDeadline: Timestamp + """ + Maximum number of participants each Entrant can have + """ + entrantSizeMax: Int @deprecated(reason: "Migrate to teamRosterSize") + """ + Minimum number of participants each Entrant can have + """ + entrantSizeMin: Int @deprecated(reason: "Migrate to teamRosterSize") + """ + The entrants that belong to an event, paginated by filter criteria + """ + entrants(query: EventEntrantPageQuery): EntrantConnection + """ + Whether the event has decks + """ + hasDecks: Boolean + """ + Are player tasks enabled for this event + """ + hasTasks: Boolean + images(type: String): [Image] + """ + Whether the event is an online event or not + """ + isOnline: Boolean + league: League + """ + Markdown field for match rules/instructions + """ + matchRulesMarkdown: String + """ + Title of event set by organizer + """ + name: String + """ + Gets the number of entrants in this event + """ + numEntrants: Int + """ + The phase groups that belong to an event. + """ + phaseGroups: [PhaseGroup] + """ + The phases that belong to an event. + """ + phases( + """ + Filter phases by state. If not specified will default to all phases + """ + state: ActivityState + """ + Optionally only return results for this phase + """ + phaseId: ID + ): [Phase] + """ + TO settings for prizing + """ + prizingInfo: JSON + publishing: JSON + """ + Markdown field for event rules/instructions + """ + rulesMarkdown: String + """ + Id of the event ruleset + """ + rulesetId: Int + """ + Settings pulled from the event ruleset, if one exists + """ + rulesetSettings: JSON @deprecated(reason: "Use ruleset") + """ + Paginated sets for this Event + """ + sets( + page: Int + perPage: Int + """ + How to sort these sets + """ + sortType: SetSortType + """ + Supported filter options to filter down set results. + """ + filters: SetFilters + ): SetConnection + slug: String + """ + Paginated list of standings + """ + standings(query: StandingPaginationQuery!): StandingConnection + """ + When does this event start? + """ + startAt: Timestamp + """ + The state of the Event. + """ + state: ActivityState + """ + Paginated stations on this event + """ + stations(query: StationFilter): StationsConnection + """ + Last date attendees are able to create teams for team events + """ + teamManagementDeadline: Timestamp + """ + If this is a teams event, returns whether or not teams can set custom names + """ + teamNameAllowed: Boolean + """ + Team roster size requirements + """ + teamRosterSize: TeamRosterSize + tournament: Tournament + """ + The type of the event, whether an entrant will have one participant or multiple + """ + type: Int + """ + When the event was last modified (unix timestamp) + """ + updatedAt: Timestamp + """ + Whether the event uses the new EventSeeds for seeding + """ + useEventSeeds: Boolean + """ + The entrant (if applicable) for a given user in this event + """ + userEntrant( + """ + User to get entrant for. Defaults to currently logged in user. + """ + userId: ID + ): Entrant + videogame: Videogame + """ + The waves being used by the event + """ + waves( + """ + Waves filtered by phaseId, returns all if not set. + """ + phaseId: ID + ): [Wave] +} + +""" +Represents a Unix Timestamp. Supports up to 53 bit int values, + as that is JavaScript's internal memory allocation for integer values. +""" +scalar Timestamp + +input EventEntrantPageQuery { + page: Int + perPage: Int + sortBy: String + filter: EventEntrantPageQueryFilter +} + +input EventEntrantPageQueryFilter { + name: String +} + +type EntrantConnection { + pageInfo: PageInfo + nodes: [Entrant] +} + +""" +An entrant in an event +""" +type Entrant { + id: ID + event: Event + """ + Entrant's seed number in the first phase of the event. + """ + initialSeedNum: Int + isDisqualified: Boolean + """ + The entrant name as it appears in bracket: gamerTag of the participant or team name + """ + name: String + """ + Paginated sets for this entrant + """ + paginatedSets( + page: Int + perPage: Int + """ + How to sort these sets + """ + sortType: SetSortType + """ + Supported filter options to filter down set results. + """ + filters: SetFilters + ): SetConnection + participants: [Participant] + seeds: [Seed] + skill: Int + """ + Standing for this entrant given an event. All entrants queried must be in the same event (for now). + """ + standing: Standing + stream: Streams @deprecated(reason: "DEPRECATED. Use streams instead, which supports multiple stream types and teams.") + streams: [Streams] + """ + Team linked to this entrant, if one exists + """ + team: Team +} + +""" +Different sort type configurations used when displaying multiple sets +""" +enum SetSortType { + """ + Sets will not be sorted. + """ + NONE + """ + Sets are sorted in the suggested order that they be called to be played. The order of completed sets is reversed. + """ + CALL_ORDER + """ + Sets are sorted by relevancy dependent on the state and progress of the event. + """ + MAGIC + """ + Sets are sorted in the order that they were started. + """ + RECENT + """ + Deprecated. This is equivalent to CALL_ORDER + """ + STANDARD + """ + Sets sorted by round and identifier + """ + ROUND +} + +input SetFilters { + """ + Only return Sets for these Entrants + """ + entrantIds: [ID] + """ + Only return Sets for this Entrant size. For example, to fetch 1v1 Sets only, filter by an entrantSize of 1 + """ + entrantSize: [Int] + """ + Only return Sets that have an attached VOD + """ + hasVod: Boolean + """ + Do not return empty Sets. For example, set this to true to filter out sets that are waiting for progressions. + """ + hideEmpty: Boolean + """ + Return sets that contain a bye + """ + showByes: Boolean + """ + Only return Sets that are in an Online event. If omitted, Sets for both online and offline Events are returned + """ + isEventOnline: Boolean + """ + Only return Sets in certain geographical areas. + """ + location: SetFilterLocation + """ + Only return Sets for these Participants + """ + participantIds: [ID] + """ + Only return Sets in these PhaseGroups + """ + phaseGroupIds: [ID] + """ + Only return Sets in these Phases + """ + phaseIds: [ID] + """ + Only return Sets in these Events + """ + eventIds: [ID] + """ + Only return Sets in these Tournaments + """ + tournamentIds: [ID] + """ + Only return Sets for these Players + """ + playerIds: [ID] + """ + Only return Sets for these Rounds + """ + roundNumber: Int + """ + Only returns Sets that are in these states + """ + state: [Int] + """ + Only return Sets that are assigned to these Station IDs + """ + stationIds: [ID] + """ + Only return Sets that are assigned to these Station numbers + """ + stationNumbers: [Int] + """ + Only return sets created or updated since this timestamp + """ + updatedAfter: Timestamp +} + +""" +Filter Sets by geographical constraints. +""" +input SetFilterLocation { + """ + Only return Sets in this state. Only applicable to US states + """ + state: String + """ + Only return Sets in this country. Expects a valid two-letter country code + """ + country: String + distanceFrom: SetFilterLocationDistanceFrom +} + +""" +Only return Sets that are a certain distance away from a specified point +""" +input SetFilterLocationDistanceFrom { + """ + Point at which to perform distance calculation + """ + point: SetFilterLocationDistanceFromPoint + """ + Distance from the point to include results in + """ + radius: String +} + +input SetFilterLocationDistanceFromPoint { + lat: Float + lon: Float +} + +type SetConnection { + pageInfo: PageInfo + nodes: [Set] +} + +""" +A set +""" +type Set { + id: ID + """ + The time this set was marked as completed + """ + completedAt: Timestamp + """ + The time this set was created + """ + createdAt: Timestamp + displayScore(mainEntrantId: ID): String + """ + Event that this set belongs to. + """ + event: Event + """ + Full round text of this set. + """ + fullRoundText: String + game(orderNum: Int!): Game + games: [Game] + """ + Whether this set contains a placeholder entrant + """ + hasPlaceholder: Boolean + """ + The letters that describe a unique identifier within the pool. Eg. F, AT + """ + identifier: String + images(type: String): [Image] + lPlacement: Int + """ + Phase group that this Set belongs to. + """ + phaseGroup: PhaseGroup + """ + The sets that are affected from resetting this set + """ + resetAffectedData: ResetAffectedData + """ + The round number of the set. Negative numbers are losers bracket + """ + round: Int + """ + Indicates whether the set is in best of or total games mode. This instructs + which field is used to figure out how many games are in this set. + """ + setGamesType: Int + """ + A possible spot in a set. Use this to get all entrants in a set. Use this for all bracket types (FFA, elimination, etc) + """ + slots(includeByes: Boolean = false): [SetSlot] + """ + The start time of the Set. If there is no startAt time on the Set, will pull it from phaseGroup rounds configuration. + """ + startAt: Timestamp + startedAt: Timestamp + state: Int + """ + Tournament event station for a set + """ + station: Stations + """ + Tournament event stream for a set + """ + stream: Streams + """ + If setGamesType is in total games mode, this defined the number of games in the set. + """ + totalGames: Int + """ + Url of a VOD for this set + """ + vodUrl: String + wPlacement: Int + winnerId: Int +} + +""" +A game represents a single game within a set. +""" +type Game { + id: ID + """ + Score of entrant 1. For smash, this is equivalent to stocks remaining. + """ + entrant1Score: Int + """ + Score of entrant 2. For smash, this is equivalent to stocks remaining. + """ + entrant2Score: Int + images(type: String): [Image] + orderNum: Int + """ + Selections for this game such as character, etc. + """ + selections: [GameSelection] + """ + The stage that this game was played on (if applicable) + """ + stage: Stage + state: Int + winnerId: Int +} + +""" +An image +""" +type Image { + id: ID + height: Float + ratio: Float + type: String + url: String + width: Float +} + +""" +A selection for this game. i.e. character/stage selection, etc +""" +type GameSelection { + """ + If this is a character selection, returns the selected character. + """ + character: Character + id: ID + """ + The entrant who this selection is for + """ + entrant: Entrant + orderNum: Int + """ + The participant who this selection is for. This is only populated if there are + selections for multiple participants of a single entrant + """ + participant: Participant + selectionType: GameSelectionType + selectionValue: Int +} + +""" +A character in a videogame +""" +type Character { + id: ID + images(type: String): [Image] + """ + Name of Character + """ + name: String +} + +""" +A participant of a tournament; either a spectator or competitor +""" +type Participant { + id: ID + """ + If this participant was checked-in by admin + """ + checkedIn: Boolean + """ + The time this participant was checked-in by admin + """ + checkedInAt: Timestamp + """ + Info for connected accounts to external services. + """ + connectedAccounts: JSON + """ + Contact Info selected during registration. Falls back to User.location and/or + User.name if necessary. These fields are for admin use only. If you are not a + tournament admin or the participant being queried, these fields will be null. + Do not display this information publicly. + """ + contactInfo: ContactInfo + """ + Email of the user, only available to admins within 18 months of tournament completion for tournament administrators. + """ + email: String + """ + Entrants associated with this Participant, if applicable + """ + entrants: [Entrant] + """ + The events this participant registered for within a Tournament. + """ + events: [Event] + """ + The tag that was used when the participant registered, e.g. Mang0 + """ + gamerTag: String + images(type: String): [Image] + player: Player + """ + The prefix that the user set for this Tournament, e.g. C9 + """ + prefix: String + """ + Tournament Admin viewable field. Shows details for required social connections + """ + requiredConnections: [ProfileAuthorization] + """ + The user this participant is associated to. + """ + user: User + """ + If this participant is verified as actually being in the tournament + """ + verified: Boolean +} + +""" +Name, address, etc +""" +type ContactInfo { + id: ID + """ + Participant City Name + """ + city: String + """ + Participant Country Name + """ + country: String + """ + Participant Country (region) id + """ + countryId: Int + name: String + """ + First Name + """ + nameFirst: String + """ + Last Name + """ + nameLast: String + """ + Participant State Name + """ + state: String + """ + Participant State (region) id + """ + stateId: Int + """ + Zip or Postal Code + """ + zipcode: String +} + +""" +A player +""" +type Player { + id: ID + gamerTag: String + prefix: String + """ + Most recent active & published rankings + """ + rankings(limit: Int, videogameId: ID): [PlayerRank] + """ + Recent sets for this player. + """ + recentSets( + """ + Use this to get H2H history between two players + """ + opponentId: ID + ): [Set] @deprecated(reason: "Use the sets field instead.") + """ + Recent standings + """ + recentStandings( + videogameId: ID + """ + Number of recent standings to fetch. Default value is 3. Maximum value is 20. + """ + limit: Int + ): [Standing] + """ + Set history for this player. + """ + sets( + page: Int + perPage: Int + """ + Supported filter options to filter down set results. + """ + filters: SetFilters + ): SetConnection + user: User +} + +""" +A player's ranks +""" +type PlayerRank { + id: ID + """ + The player's placement on the ranking + """ + rank: Int + title: String +} + +""" +A standing indicates the placement of something within a container. +""" +type Standing { + id: ID + """ + The containing entity that contextualizes this standing. Event standings, for + example, represent an entrant's standing in the entire event vs. Set standings + which is an entrant's standing in only a single set within an event. + """ + container: StandingContainer + """ + If the entity this standing is assigned to can be resolved into an entrant, this will provide the entrant. + """ + entrant: Entrant + isFinal: Boolean + """ + Metadata that goes along with this standing. Can take on different forms based on standing group type and settings. + """ + metadata: JSON + placement: Int + """ + The player(s) tied to this standing's entity + """ + player: Player + standing: Int @deprecated(reason: "The \"placement\" field is identical and will eventually replace \"standing\"") + stats: StandingStats + totalPoints: Float +} + +""" +The containing entity that this standing is for +""" +union StandingContainer = Tournament | Event | PhaseGroup | Set + +""" +A tournament +""" +type Tournament { + id: ID + addrState: String + """ + Admin-only view of admins for this tournament + """ + admins( + """ + Which roles to show + """ + roles: [String] + ): [User] + city: String + countryCode: String + """ + When the tournament was created (unix timestamp) + """ + createdAt: Timestamp + currency: String + """ + When the tournament ends + """ + endAt: Timestamp + """ + When does event registration close + """ + eventRegistrationClosesAt: Timestamp + events(limit: Int, filter: EventFilter): [Event] + """ + True if tournament has at least one offline event + """ + hasOfflineEvents: Boolean + hasOnlineEvents: Boolean + hashtag: String + images(type: String): [Image] + """ + True if tournament has at least one online event + """ + isOnline: Boolean + """ + Is tournament registration open + """ + isRegistrationOpen: Boolean + lat: Float + links: TournamentLinks + lng: Float + mapsPlaceId: String + """ + The tournament name + """ + name: String + """ + Number of attendees including spectators, if public + """ + numAttendees: Int + """ + The user who created the tournament + """ + owner: User + """ + Paginated, queryable list of participants + """ + participants(query: ParticipantPaginationQuery!, isAdmin: Boolean): ParticipantConnection + postalCode: String + primaryContact: String + primaryContactType: String + """ + Publishing settings for this tournament + """ + publishing: JSON + """ + When does registration for the tournament end + """ + registrationClosesAt: Timestamp + rules: String + """ + The short slug used to form the url + """ + shortSlug: String + """ + The slug used to form the url + """ + slug: String + """ + When the tournament Starts + """ + startAt: Timestamp + """ + State of the tournament, can be ActivityState::CREATED, ActivityState::ACTIVE, or ActivityState::COMPLETED + """ + state: Int + stations(page: Int, perPage: Int): StationsConnection + streamQueue: [StreamQueue] + streams: [Streams] + """ + When is the team creation deadline + """ + teamCreationClosesAt: Timestamp + """ + Paginated, queryable list of teams + """ + teams(query: TeamPaginationQuery!): TeamConnection + """ + The timezone of the tournament + """ + timezone: String + """ + The type of tournament from TournamentType + """ + tournamentType: Int + """ + When the tournament was last modified (unix timestamp) + """ + updatedAt: Timestamp + """ + Build Tournament URL + """ + url( + """ + Tournament tab to add to URL + """ + tab: String + """ + Generate a relative URL. Defaults to true. Setting to false will generate an absolute URL + """ + relative: Boolean = true + ): String + venueAddress: String + venueName: String + """ + List of all waves in this tournament + """ + waves: [Wave] +} + +input EventFilter { + videogameId: [ID] + type: [Int] + published: Boolean + id: ID + ids: [ID] + slug: String + fantasyEventId: ID + fantasyRosterHash: String +} + +type TournamentLinks { + facebook: String + discord: String +} + +input ParticipantPaginationQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String + filter: ParticipantPageFilter +} + +input ParticipantPageFilter { + id: ID + ids: [ID] + eventIds: [ID] + search: PaginationSearchType + gamerTag: String + unpaid: Boolean + incompleteTeam: Boolean + missingDeck: Boolean + checkedIn: Boolean + notCheckedIn: Boolean +} + +type ParticipantConnection { + pageInfo: PageInfo + nodes: [Participant] +} + +type StationsConnection { + pageInfo: PageInfo + nodes: [Stations] +} + +""" +Stations, such as a stream setup, at an event +""" +type Stations { + id: ID + canAutoAssign: Boolean + clusterNumber: String + clusterPrefix: Int + enabled: Boolean + identifier: Int + numSetups: Int + number: Int + prefix: String + queue: JSON + queueDepth: Int + state: Int + updatedAt: Timestamp +} + +""" +A Stream queue object +""" +type StreamQueue { + id: String + """ + The sets on the stream + """ + sets: [Set] + """ + The stream on the queue + """ + stream: Streams +} + +""" +Tournament Stream +""" +type Streams { + id: ID + enabled: Boolean + followerCount: Int + isOnline: Boolean + numSetups: Int + parentStreamId: Int + streamGame: String + streamId: String + streamLogo: String + streamName: String + streamSource: StreamSource + streamStatus: String + streamType: Int + streamTypeId: Int +} + +""" +Represents the source of a stream +""" +enum StreamSource { + """ + Stream is on twitch.tv channel + """ + TWITCH + """ + Stream is on smashcast.tv channel + """ + HITBOX + """ + Stream is on a stream.me channel + """ + STREAMME + """ + Stream is on a mixer.com channel + """ + MIXER + """ + Stream is on a youtube.com channel + """ + YOUTUBE +} + +input TeamPaginationQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String + filter: TeamPaginationFilter +} + +input TeamPaginationFilter { + globalTeamId: ID + eventState: ActivityState + eventId: ID + eventIds: [ID] + minEntrantCount: Int + maxEntrantCount: Int + search: PaginationSearchType + type: Int + tournamentId: ID + memberStatus: [TeamMemberStatus] + videogameId: [ID] + isLeague: Boolean + upcoming: Boolean + past: Boolean + rosterComplete: Boolean + rosterIncomplete: Boolean +} + +""" +Represents the state of an activity +""" +enum ActivityState { + """ + Activity is created + """ + CREATED + """ + Activity is active or in progress + """ + ACTIVE + """ + Activity is done + """ + COMPLETED + """ + Activity is ready to be started + """ + READY + """ + Activity is invalid + """ + INVALID + """ + Activity, like a set, has been called to start + """ + CALLED + """ + Activity is queued to run + """ + QUEUED +} + +""" +Membership status of a team member +""" +enum TeamMemberStatus { + """ + + """ + UNKNOWN + """ + + """ + ACCEPTED + """ + + """ + INVITED + """ + + """ + REQUEST + """ + + """ + ALUM + """ + + """ + HIATUS + """ + + """ + OPEN_SPOT +} + +type TeamConnection { + pageInfo: PageInfo + nodes: [Team] +} + +""" +A team, either at the global level or within the context of an event +""" +interface Team { + id: ID + """ + Uniquely identifying token for team. Same as the hashed part of the slug + """ + discriminator: String + entrant: Entrant @deprecated(reason: "Use the entrant field off the EventTeam type") + event: Event @deprecated(reason: "Use the event field off the EventTeam type") + images(type: String): [Image] + members(status: [TeamMemberStatus]): [TeamMember] + name: String +} + +""" +A member of a team +""" +type TeamMember { + id: ID + isAlternate: Boolean + isCaptain: Boolean + """ + The type of the team member + """ + memberType: TeamMemberType + participant: Participant + player: Player + """ + The status of the team member + """ + status: TeamMemberStatus +} + +""" +Membership type of a team member +""" +enum TeamMemberType { + """ + + """ + PLAYER + """ + + """ + STAFF +} + +""" +A wave in a tournament +""" +type Wave { + id: ID + """ + The Wave Identifier + """ + identifier: String + """ + Unix time the wave is scheduled to start. + """ + startAt: Timestamp +} + +""" +A group within a phase +""" +type PhaseGroup { + id: ID + """ + The bracket type of this group's phase. + """ + bracketType: BracketType + """ + URL for this phase groups's bracket. + """ + bracketUrl: String + """ + Unique identifier for this group within the context of its phase + """ + displayIdentifier: String + """ + For the given phase group, this is the start time of the first round that occurs in the group. + """ + firstRoundTime: Timestamp + numRounds: Int + paginatedSeeds(query: SeedPaginationQuery!, eventId: ID): SeedConnection @deprecated(reason: "Please use 'seeds', which is now paginated") + """ + Paginated sets on this phaseGroup + """ + paginatedSets( + page: Int + perPage: Int + """ + How to sort these sets + """ + sortType: SetSortType + """ + Supported filter options to filter down set results. + """ + filters: SetFilters + ): SetConnection @deprecated(reason: "Please use 'sets', which is now paginated") + """ + The phase associated with this phase group + """ + phase: Phase + """ + The progressions out of this phase group + """ + progressionsOut: [Progression] + rounds: [Round] + seedMap: JSON + """ + Paginated seeds for this phase group + """ + seeds(query: SeedPaginationQuery!, eventId: ID): SeedConnection + """ + Paginated sets on this phaseGroup + """ + sets( + page: Int + perPage: Int + """ + How to sort these sets + """ + sortType: SetSortType + """ + Supported filter options to filter down set results. + """ + filters: SetFilters + ): SetConnection + """ + Paginated list of standings + """ + standings(query: StandingGroupStandingPageFilter): StandingConnection + """ + Unix time the group is scheduled to start. This info could also be on the wave instead. + """ + startAt: Timestamp + state: Int + tiebreakOrder: JSON + wave: Wave +} + +""" +The type of Bracket format that a Phase is configured with. +""" +enum BracketType { + """ + + """ + SINGLE_ELIMINATION + """ + + """ + DOUBLE_ELIMINATION + """ + + """ + ROUND_ROBIN + """ + + """ + SWISS + """ + + """ + EXHIBITION + """ + + """ + CUSTOM_SCHEDULE + """ + + """ + MATCHMAKING + """ + + """ + ELIMINATION_ROUNDS + """ + + """ + RACE + """ + + """ + CIRCUIT +} + +input SeedPaginationQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String + filter: SeedPageFilter +} + +input SeedPageFilter { + id: ID + entrantName: String + checkInState: [Int] + phaseGroupId: [ID] + eventCheckInGroupId: ID + phaseId: [ID] + eventId: ID + search: PaginationSearchType +} + +type SeedConnection { + pageInfo: PageInfo + nodes: [Seed] +} + +""" +A seed for an entrant +""" +type Seed { + id: ID + """ + Map of Participant ID to checked in boolean + """ + checkedInParticipants: JSON + entrant: Entrant + groupSeedNum: Int + isBye: Boolean + phase: Phase + phaseGroup: PhaseGroup + placeholderName: String + placement: Int + """ + The player(s) associated with this seed's entrant + """ + players: [Player] + progressionSeedId: Int + """ + Source progression information + """ + progressionSource: Progression + seedNum: Int + """ + Entrant's win/loss record for this standing. Scores do not include byes. + """ + setRecordWithoutByes(phaseGroupId: ID!): JSON + standings( + """ + The container of the standing groups to get standings for. If null, will return all standings. + """ + containerType: String + ): [Standing] +} + +""" +A phase in an event +""" +type Phase { + id: ID + """ + The bracket type of this phase. + """ + bracketType: BracketType + """ + The Event that this phase belongs to + """ + event: Event + """ + Number of phase groups in this phase + """ + groupCount: Int + """ + Is the phase an exhibition or not. + """ + isExhibition: Boolean + """ + Name of phase e.g. Round 1 Pools + """ + name: String + """ + The number of seeds this phase contains. + """ + numSeeds: Int + paginatedSeeds(query: SeedPaginationQuery!, eventId: ID): SeedConnection @deprecated(reason: "Please use 'seeds' instead") + """ + Phase groups under this phase, paginated + """ + phaseGroups(query: PhaseGroupPageQuery): PhaseGroupConnection + """ + The relative order of this phase within an event + """ + phaseOrder: Int + """ + Paginated seeds for this phase + """ + seeds(query: SeedPaginationQuery!, eventId: ID): SeedConnection + """ + Paginated sets for this Phase + """ + sets( + page: Int + perPage: Int + """ + How to sort these sets + """ + sortType: SetSortType + """ + Supported filter options to filter down set results. + """ + filters: SetFilters + ): SetConnection + """ + State of the phase + """ + state: ActivityState + waves: [Wave] +} + +input PhaseGroupPageQuery { + page: Int + perPage: Int + sortBy: String + entrantIds: [ID] + filter: PhaseGroupPageQueryFilter +} + +input PhaseGroupPageQueryFilter { + id: [ID] + waveId: ID +} + +type PhaseGroupConnection { + pageInfo: PageInfo + nodes: [PhaseGroup] +} + +""" +A connection between a placement in an origin phase group to a destination seed. +""" +type Progression { + id: ID + originOrder: Int + originPhase: Phase + originPhaseGroup: PhaseGroup + originPlacement: Int +} + +""" +A round within a phase group +""" +type Round { + id: ID + """ + If applicable, bestOf is the number of games + one must win a majority out of to win a set in this round + """ + bestOf: Int + """ + Indicates this round's order in the phase group + """ + number: Int + """ + The time that this round is scheduled to start at + """ + startAt: Timestamp +} + +input StandingGroupStandingPageFilter { + page: Int + perPage: Int + sortBy: String +} + +type StandingConnection { + pageInfo: PageInfo + nodes: [Standing] +} + +""" +Any stats related to this standing. This type is experimental and very likely to change in the future. +""" +type StandingStats { + score: Score +} + +""" +The score that led to this standing being awarded. The meaning of this field can +vary by standing type and is not used for some standing types. +""" +type Score { + """ + The name of this score. e.g. "Kills" or "Stocks" + """ + label: String + """ + The raw score value + """ + value: Float + """ + Like value, but formatted for race format events. Formatted according to the race config for the front end to use. + """ + displayValue: String +} + +""" +The type of selection i.e. is it for a character or something else +""" +enum GameSelectionType { + """ + Character selection + """ + CHARACTER +} + +""" +Video Stage +""" +type Stage { + id: ID + """ + Stage name + """ + name: String +} + +type ResetAffectedData { + affectedSetCount: Int + affectedSets: [Set] + affectedPhaseGroupCount: Int +} + +""" +A slot in a set where a seed currently or will eventually exist in order to participate in the set. +""" +type SetSlot { + id: ID + entrant: Entrant + """ + Pairs with prereqType, is the ID of the prereq. + """ + prereqId: String + """ + Given a set prereq type, defines the placement required in the origin set to end up in this slot. + """ + prereqPlacement: Int + """ + Describes where the entity in this slot comes from. + """ + prereqType: String + seed: Seed + """ + The index of the slot. Unique per set. + """ + slotIndex: Int + """ + The standing within this set for the seed currently assigned to this slot. + """ + standing: Standing +} + +""" +A league +""" +type League { + id: ID + addrState: String + city: String + countryCode: String + """ + When the tournament was created (unix timestamp) + """ + createdAt: Timestamp + currency: String + """ + When the tournament ends + """ + endAt: Timestamp + entrantCount: Int + eventOwners(query: EventOwnersQuery): EventOwnerConnection + """ + When does event registration close + """ + eventRegistrationClosesAt: Timestamp + """ + Paginated list of events in a league + """ + events(query: LeagueEventsQuery): EventConnection + """ + Hacked "progression" into this final event + """ + finalEventId: Int @deprecated(reason: "No longer used") + """ + True if tournament has at least one offline event + """ + hasOfflineEvents: Boolean + hasOnlineEvents: Boolean + hashtag: String + images(type: String): [Image] + """ + True if tournament has at least one online event + """ + isOnline: Boolean + lat: Float + links: TournamentLinks + lng: Float + mapsPlaceId: String + """ + The tournament name + """ + name: String + """ + Top X number of people in the standings who progress to final event + """ + numProgressingToFinalEvent: Int @deprecated(reason: "No longer used") + numUniquePlayers: Int + postalCode: String + primaryContact: String + primaryContactType: String + """ + Publishing settings for this tournament + """ + publishing: JSON + """ + When does registration for the tournament end + """ + registrationClosesAt: Timestamp + rules: String + """ + The short slug used to form the url + """ + shortSlug: String + """ + Whether standings for this league should be visible + """ + showStandings: Boolean + slug: String + """ + Paginated list of standings + """ + standings(query: StandingGroupStandingPageFilter): StandingConnection + """ + When the tournament Starts + """ + startAt: Timestamp + """ + State of the tournament, can be ActivityState::CREATED, ActivityState::ACTIVE, or ActivityState::COMPLETED + """ + state: Int + """ + When is the team creation deadline + """ + teamCreationClosesAt: Timestamp + tiers: [EventTier] + """ + The timezone of the tournament + """ + timezone: String + """ + The type of tournament from TournamentType + """ + tournamentType: Int + """ + When the tournament was last modified (unix timestamp) + """ + updatedAt: Timestamp + """ + Build Tournament URL + """ + url( + """ + Tournament tab to add to URL + """ + tab: String + """ + Generate a relative URL. Defaults to true. Setting to false will generate an absolute URL + """ + relative: Boolean = true + ): String + venueAddress: String + venueName: String + videogames: [Videogame] +} + +input EventOwnersQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String +} + +type EventOwnerConnection { + pageInfo: PageInfo + nodes: [EventOwner] +} + +""" +Name and Gamertag of the owner of an event in a league +""" +type EventOwner { + eventId: ID + email: String + gamerTag: String + fullName: String +} + +input LeagueEventsQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String + filter: LeagueEventsFilter +} + +input LeagueEventsFilter { + search: PaginationSearchType + pointMappingGroupIds: [ID] + tierIds: [ID] + userId: ID + upcoming: Boolean + leagueEntrantId: ID +} + +""" +Used for league application tiers +""" +type EventTier { + id: ID + """ + Name of this tier + """ + name: String +} + +""" +A videogame +""" +type Videogame { + id: ID + """ + All characters for this videogame + """ + characters: [Character] + displayName: String + images(type: String): [Image] + name: String + slug: String + """ + All stages for this videogame + """ + stages: [Stage] +} + +input StandingPaginationQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String + filter: StandingPageFilter +} + +input StandingPageFilter { + id: ID + ids: [ID] + search: PaginationSearchType +} + +input StationFilter { + page: Int + perPage: Int +} + +""" +Team roster size requirements +""" +type TeamRosterSize { + maxAlternates: Int + maxPlayers: Int + minAlternates: Int + minPlayers: Int +} + +input UserLeaguesPaginationQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String + filter: UserLeaguesPaginationFilter +} + +input UserLeaguesPaginationFilter { + videogameId: [ID] + upcoming: Boolean + past: Boolean + search: PaginationSearchType +} + +type LeagueConnection { + pageInfo: PageInfo + nodes: [League] +} + +""" +A user's address +""" +type Address { + id: ID + city: String + country: String + countryId: Int + state: String + stateId: Int +} + +input UserTournamentsPaginationQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String + filter: UserTournamentsPaginationFilter +} + +input UserTournamentsPaginationFilter { + past: Boolean + upcoming: Boolean + search: PaginationSearchType + videogameId: [ID] + tournamentView: String + excludeId: [ID] +} + +type TournamentConnection { + pageInfo: PageInfo + nodes: [Tournament] +} + +input LeagueQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String + filter: LeaguePageFilter + sort: TournamentPaginationSort +} + +input LeaguePageFilter { + id: ID + ids: [ID] + """ + ID of the user that owns this league. + """ + ownerId: ID + afterDate: Timestamp + beforeDate: Timestamp + computedUpdatedAt: Timestamp + name: String + isFeatured: Boolean + hasBannerImages: Boolean + activeShops: Boolean + past: Boolean + published: Boolean + publiclySearchable: Boolean + upcoming: Boolean + videogameIds: [ID] +} + +enum TournamentPaginationSort { + """ + + """ + startAt + """ + + """ + endAt + """ + + """ + eventRegistrationClosesAt + """ + + """ + computedUpdatedAt +} + +""" +A shop +""" +type Shop { + id: ID + levels(query: ShopLevelsQuery): ShopLevelConnection + messages(query: ShopOrderMessagesQuery): ShopOrderMessageConnection + name: String + slug: String + url: String +} + +input ShopLevelsQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String +} + +type ShopLevelConnection { + pageInfo: PageInfo + nodes: [ShopLevel] +} + +""" +A shop level +""" +type ShopLevel { + id: ID + currAmount: Float + description: String + goalAmount: Float + images(type: String): [Image] + name: String +} + +input ShopOrderMessagesQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String +} + +type ShopOrderMessageConnection { + pageInfo: PageInfo + nodes: [ShopOrderMessage] +} + +""" +The message and player info for a shop order +""" +type ShopOrderMessage { + id: ID + """ + The player's gamertag. Returns null if anonymous message type + """ + gamertag: String + """ + The order message + """ + message: String + """ + The player's name. Returns null unless name & tag display is selected + """ + name: String + """ + The player who left the comment + """ + player: Player + """ + The total order amount + """ + total: Float +} + +input TournamentQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String + filter: TournamentPageFilter + sort: TournamentPaginationSort +} + +input TournamentPageFilter { + id: ID + ids: [ID] + """ + ID of the user that owns this tournament. + """ + ownerId: ID + """ + If true, filter to only tournaments the currently authed user is an admin of + """ + isCurrentUserAdmin: Boolean + countryCode: String + addrState: String + location: TournamentLocationFilter + afterDate: Timestamp + beforeDate: Timestamp + computedUpdatedAt: Timestamp + name: String + venueName: String + isFeatured: Boolean + isLeague: Boolean + hasBannerImages: Boolean + activeShops: Boolean + regOpen: Boolean + past: Boolean + published: Boolean + publiclySearchable: Boolean + staffPicks: Boolean + hasOnlineEvents: Boolean + topGames: TopGameFilter + upcoming: Boolean + videogameIds: [ID] + sortByScore: Boolean +} + +input TournamentLocationFilter { + """ + Latitude, Longitude + """ + distanceFrom: String + """ + e.g. 50mi + """ + distance: String +} + +input TopGameFilter { + """ + Array of which # top game you want to filter on.e.g. [2, 3] will filter on the 2nd and 3rd top games + """ + gameNums: [Int] +} + +input VideogameQuery { + page: Int = 1 + """ + How many nodes to return for the page. Maximum value of 500 + """ + perPage: Int = 25 + sortBy: String + filter: VideogamePageFilter +} + +input VideogamePageFilter { + id: [ID] + name: String + forUser: ID +} + +type VideogameConnection { + pageInfo: PageInfo + nodes: [Videogame] +} + +type Mutation { + """ + Delete a phase by id + """ + deletePhase(phaseId: ID!): Boolean + """ + Delete a station by id + """ + deleteStation(stationId: ID!): Boolean + """ + Delete a wave by id + """ + deleteWave(waveId: ID!): Boolean + """ + Generate tournament registration Token on behalf of user + """ + generateRegistrationToken(registration: TournamentRegistrationInput!, userId: ID!): String + """ + Update a set to called state + """ + markSetCalled(setId: ID!): Set + """ + Update a set to called state + """ + markSetInProgress(setId: ID!): Set + """ + Register for tournament + """ + registerForTournament(registration: TournamentRegistrationInput, registrationToken: String): Participant + """ + Report set winner or game stats for a H2H bracket set. If winnerId is + supplied, mark set as complete. gameData parameter will overwrite any existing + reported game data. + """ + reportBracketSet(setId: ID!, winnerId: ID, isDQ: Boolean, gameData: [BracketSetGameDataInput]): [Set] + """ + Resets set to initial state, can affect other sets and phase groups + """ + resetSet(setId: ID!, resetDependentSets: Boolean): Set + """ + Automatically attempt to resolve all schedule conflicts. Returns a list of changed seeds + """ + resolveScheduleConflicts(tournamentId: ID!, options: ResolveConflictsOptions): [Seed] + """ + Swap two seed ids in a phase + """ + swapSeeds(phaseId: ID!, seed1Id: ID!, seed2Id: ID!): [Seed] + """ + Update game stats for a H2H bracket set. Set winner cannot be changed with + this function, use the resetSet mutation instead. + """ + updateBracketSet(setId: ID!, winnerId: ID, isDQ: Boolean, gameData: [BracketSetGameDataInput]): Set + """ + Update set of phase groups in a phase + """ + updatePhaseGroups(groupConfigs: [PhaseGroupUpdateInput]!): [PhaseGroup] + """ + Update the seeding for a phase + """ + updatePhaseSeeding(phaseId: ID!, seedMapping: [UpdatePhaseSeedInfo]!, options: UpdatePhaseSeedingOptions): Phase + """ + Create or update a Phase + """ + upsertPhase(phaseId: ID, eventId: ID, payload: PhaseUpsertInput!): Phase + """ + Add or update a station by id + """ + upsertStation(stationId: ID, tournamentId: ID, fields: StationUpsertInput!): Stations + """ + Add or update a wave by id + """ + upsertWave(waveId: ID, tournamentId: ID, fields: WaveUpsertInput!): Wave +} + +input TournamentRegistrationInput { + eventIds: [ID] +} + +""" +Game specific H2H set data such as character, stage, and stock info +""" +input BracketSetGameDataInput { + """ + Entrant ID of game winner + """ + winnerId: ID + """ + Game number + """ + gameNum: Int! + """ + Score for entrant 1 (if applicable). For smash, this is stocks remaining. + """ + entrant1Score: Int + """ + Score for entrant 2 (if applicable). For smash, this is stocks remaining. + """ + entrant2Score: Int + """ + ID of the stage that was played for this game (if applicable) + """ + stageId: ID + """ + List of selections for the game, typically character selections. + """ + selections: [BracketSetGameSelectionInput] +} + +""" +Game specific H2H selections made by the entrants, such as character info +""" +input BracketSetGameSelectionInput { + """ + Entrant ID that made selection + """ + entrantId: ID! + """ + Character selected by this entrant for this game. + """ + characterId: Int +} + +input ResolveConflictsOptions { + lockedSeeds: [ResolveConflictsLockedSeedConfig] +} + +input ResolveConflictsLockedSeedConfig { + eventId: ID! + numSeeds: Int! +} + +input PhaseGroupUpdateInput { + phaseGroupId: ID! + stationId: ID + waveId: ID +} + +input UpdatePhaseSeedInfo { + seedId: ID! + seedNum: ID! + phaseGroupId: ID +} + +input UpdatePhaseSeedingOptions { + """ + Validate that seedMapping exactly accounts for all entrants in the phase + """ + strictMode: Boolean +} + +input PhaseUpsertInput { + """ + The name of the Phase. For example, "Top 8" or "Pools" + """ + name: String + """ + The number of pools to configure for the Phase. Only applies to brackets that support pools + """ + groupCount: Int + bracketType: BracketType +} + +input StationUpsertInput { + number: Int! + clusterId: ID +} + +input WaveUpsertInput { + identifier: String! + startAt: Timestamp! + endAt: Timestamp! +} + +""" +A set of actions available for an entity to take +""" +interface ActionSet { + id: ID +} + +""" +Bracket-specific configuration +""" +interface BracketConfig { + id: ID + bracketType: BracketType +} + +""" +Comparison operator +""" +enum Comparator { + """ + + """ + GREATER_THAN + """ + + """ + GREATER_THAN_OR_EQUAL + """ + + """ + EQUAL + """ + + """ + LESS_THAN_OR_EQUAL + """ + + """ + LESS_THAN +} + +""" +An event-level Team, in the context of some competition +""" +type EventTeam implements Team { + id: ID + """ + Uniquely identifying token for team. Same as the hashed part of the slug + """ + discriminator: String + entrant: Entrant @deprecated(reason: "Use the entrant field off the EventTeam type") + event: Event @deprecated(reason: "Use the event field off the EventTeam type") + globalTeam: GlobalTeam + images(type: String): [Image] + members(status: [TeamMemberStatus]): [TeamMember] + name: String +} + +""" +Global Team +""" +type GlobalTeam implements Team { + id: ID + """ + Uniquely identifying token for team. Same as the hashed part of the slug + """ + discriminator: String + entrant: Entrant @deprecated(reason: "Use the entrant field off the EventTeam type") + event: Event @deprecated(reason: "Use the event field off the EventTeam type") + eventTeams(query: TeamPaginationQuery): EventTeamConnection + images(type: String): [Image] + """ + Leagues-level teams for leagues this team is competing in + """ + leagueTeams(query: TeamPaginationQuery): EventTeamConnection + members(status: [TeamMemberStatus]): [TeamMember] + name: String +} + +type EventTeamConnection { + pageInfo: PageInfo + nodes: [EventTeam] +} + +""" +Match-level configuration +""" +interface MatchConfig { + id: ID + bracketType: BracketType +} + +""" +Different options available for verifying player-reported match results +""" +enum MatchConfigVerificationMethod { + """ + + """ + TWITCH + """ + + """ + STREAM_ME + """ + + """ + ANY + """ + + """ + MIXER + """ + + """ + YOUTUBE +} + +""" +Race specific bracket configuration +""" +type RaceBracketConfig implements BracketConfig { + automaticEndTime: Timestamp + id: ID + automaticStartTime: Timestamp + bracketType: BracketType + goalTargetComparator: Comparator + goalTargetValue: String + limitMode: RaceLimitMode + limitValue: Int + raceType: RaceType +} + +""" +Enforces limits on the amount of allowable Race submissions +""" +enum RaceLimitMode { + """ + + """ + BEST_ALL + """ + + """ + FIRST_ALL + """ + + """ + PLAYTIME +} + +""" +Race type +""" +enum RaceType { + """ + + """ + GOALS + """ + + """ + TIMED +} + +""" +Race specific match configuration +""" +type RaceMatchConfig implements MatchConfig { + id: ID + bracketType: BracketType + """ + Can players report results? + """ + playerReportingEnabled: Boolean + """ + Accepted methods of verification that players can use + """ + verificationMethods: [MatchConfigVerificationMethod] + """ + Are players required to submit verification of their reported results? + """ + verificationRequired: Boolean +} + +""" +A set of actions available for a team to take +""" +type TeamActionSet implements ActionSet { + id: ID +} + diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..bf6dfdd --- /dev/null +++ b/src/main.rs @@ -0,0 +1,181 @@ +extern crate sdl2; +mod smashquery; +mod smashrequest; + + +use sdl2::pixels::{Color, PixelFormatEnum}; +use sdl2::event::Event; +use sdl2::keyboard::Keycode; +use sdl2::rect::Rect; +use sdl2::render::{Canvas, TextureQuery}; +use smashrequest::SmashQueue; + +use std::sync::{Arc, Mutex}; +use std::time::Duration; +use std::fs; +use serde::Deserialize; + + +#[derive(Deserialize,Clone)] +struct Config { + tournament: String, + update: Option, + fullscreen: Option, + smash_key: String, + +} + +impl Config { + fn new() -> Self { + Self { tournament: String::new(), update: Some(1),fullscreen:Some(false), smash_key: String::new() } + } +} + + +pub fn render(canvas : &mut Canvas , queues : &Vec,font : &sdl2::ttf::Font<'_, '_> ){ + + + let texture_creator = canvas.texture_creator(); + let mut backline_text = texture_creator.create_texture_streaming(PixelFormatEnum::RGB24, 1, 1).map_err(|e| e.to_string()).unwrap(); + + backline_text.with_lock(None, |buffer : &mut [u8], pitch: usize| { + buffer[1] = 5; + buffer[1] = 30; + buffer[2] = 66; + }).unwrap(); + + let mut y : u32 = 0; + let mut index = 0; + for sq in queues { + + + let surface = font.render(sq.name.as_str()).blended(Color::RGBA(255, 255, 0, 255)).map_err(|e| e.to_string()).unwrap(); + let text = texture_creator.create_texture_from_surface(&surface).unwrap(); + let textq : TextureQuery = text.query(); + let _ = canvas.copy(&text, None, Rect::new(0, y.try_into().map_err(|_| 0).unwrap(), textq.width, textq.height)); + + y += textq.height+10; + + + for current_match in &sq.matches { + + index += 1; + let switch_col : bool = index%2 == 0; + + let var_name = format!("{} vs {}", ¤t_match.player1, current_match.player2); + let surface = font.render(var_name.as_str()).blended(Color::RGBA(255, 255, 255, 255)).map_err(|e| e.to_string()).unwrap(); + let text = texture_creator.create_texture_from_surface(&surface).unwrap(); + let textq : TextureQuery = text.query(); + + if switch_col { + let _ = canvas.copy(&backline_text, None, Rect::new(0, y.try_into().map_err(|_| 0).unwrap(), canvas.viewport().width(), textq.height)); + } + + + let _ = canvas.copy(&text, None, Rect::new(0, y.try_into().map_err(|e| 0).unwrap(), textq.width, textq.height)); + y += textq.height + 5; + } + + + } + +} + + +pub fn main() -> Result<(), Box> { + println!("Read config"); + let config_file = fs::read_to_string("config.toml"); + + let config : Config = if config_file.is_ok() { + toml::from_str(&config_file.unwrap()).unwrap() + } else { + Config::new() + }; + + println!("{}",config.tournament); + if config.tournament.is_empty(){ + println!("Empty Tournament , Exiting."); + return Ok(()); + } + + let fullscreen = match config.fullscreen { + Some(v) => v, + None => false + }; + + println!("Fullscreen : {}",fullscreen); + println!("Done"); + let test = Arc::new(Mutex::new(Vec::::new())); + + let sdl_context = sdl2::init().unwrap(); + let video_subsystem = sdl_context.video().unwrap(); + + let mut build = video_subsystem.window("LaDOSE-SNCF", 1280, 720); + if fullscreen { + build.fullscreen(); + } + else { + build.position_centered(); + } + let window = build + .build() + .unwrap(); + + let mut canvas: Canvas = window.into_canvas().build().unwrap(); + let ttf_context = sdl2::ttf::init().unwrap(); + let font : sdl2::ttf::Font<'_, '_> = ttf_context.load_font("font/achemine_bold.ttf", 30).unwrap(); + + let stream_queues : Vec= smashrequest::get_matches(config.tournament.as_str(),config.smash_key.as_str()); + + let timer = sdl_context.timer()?; + + + + + + let test_clone = Arc::clone(&test); + + let _timer_cb = &timer.add_timer(1,Box::new(move || { + println!("timer"); + let data = smashrequest::get_matches(config.tournament.as_str(), config.smash_key.as_str()); + println!("{:?}", data); + let mut a = test_clone.lock().unwrap(); + if a.len()>1 { + a.clear(); + } + else{ + a.clone_from(&data); + } + println!("{:?}",a); + return config.update.ok_or(10).unwrap()*1000; + }) + ); + + + canvas.set_draw_color(Color::RGB(0, 255, 255)); + canvas.clear(); + canvas.present(); + let mut event_pump = sdl_context.event_pump().unwrap(); + 'running: loop { + canvas.set_draw_color(Color::RGB(0,136,206)); + canvas.clear(); + let test_c = Arc::clone(&test); + let a = test_c.lock().unwrap(); + render(&mut canvas,&a,&font); + //render(&mut canvas,&stream_queues,&font); + timer.ticks(); + for event in event_pump.poll_iter() { + match event { + Event::Quit {..} | + Event::KeyDown { keycode: Some(Keycode::Escape), .. } => { + break 'running Ok(()); + }, + _ => {} + } + } + // The rest of the game loop goes here... + + canvas.present(); + ::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60)); + } +} diff --git a/src/smashquery.rs b/src/smashquery.rs new file mode 100644 index 0000000..b407c65 --- /dev/null +++ b/src/smashquery.rs @@ -0,0 +1,59 @@ +#[cynic::schema("startgg")] +mod schema {} + +#[derive(cynic::QueryVariables, Debug)] +pub struct MyQueryVariables<'a> { + pub slug: Option<&'a str>, +} + +#[derive(cynic::QueryFragment, Debug)] +#[cynic(graphql_type = "Query", variables = "MyQueryVariables")] +pub struct MyQuery { + #[arguments(slug: $slug)] + pub tournament: Option, +} + +#[derive(cynic::Scalar, Debug)] +#[cynic(graphql_type = "ID")] +struct IntegerId(u32); + +#[derive(cynic::QueryFragment, Debug)] +pub struct Tournament { + pub id: Option, + pub name: Option, + pub stream_queue: Option>>, +} + +#[derive(cynic::QueryFragment, Debug)] +pub struct StreamQueue { + pub sets: Option>>, + pub id: Option, + pub stream: Option, +} + +#[derive(cynic::QueryFragment, Debug)] +pub struct Set { + pub id: Option, + pub full_round_text: Option, + pub round: Option, + pub state: Option, + pub total_games: Option, + #[arguments(includeByes: false)] + pub slots: Option>>, +} + +#[derive(cynic::QueryFragment, Debug)] +pub struct SetSlot { + pub entrant: Option, +} + +#[derive(cynic::QueryFragment, Debug)] +pub struct Entrant { + pub id: Option, + pub name: Option, +} + +#[derive(cynic::QueryFragment, Debug)] +pub struct Streams { + pub stream_name: Option, +} diff --git a/src/smashrequest.rs b/src/smashrequest.rs new file mode 100644 index 0000000..6a9579c --- /dev/null +++ b/src/smashrequest.rs @@ -0,0 +1,110 @@ +use crate::smashquery::{MyQuery, MyQueryVariables, Set, SetSlot,StreamQueue}; +use cynic::{http::SurfExt, GraphQlResponse, QueryBuilder}; + +static URL_SMASH: &str = "https://api.start.gg/gql/alpha"; + +#[derive(Debug,Clone)] +pub struct Match { + pub player1 : String, + pub player2 : String, + pub station : String, + pub round : i32, + pub full_round_test: String +} + +#[derive(Debug,Clone)] +pub struct SmashQueue { + pub name : String, + pub matches : Vec +} + +impl Match { + pub fn new() -> Self { + Self { player1: String::from(""), player2: String::from("") , station: String::from("") , round: 0 , full_round_test: String::from("")} + } + +} + +impl SmashQueue{ + pub fn new() -> Self{ + Self { name:String::from(""),matches : vec![] } + } +} +fn request_stream_queue(tournament :&str, key : &str ) -> GraphQlResponse{ + + let resp = async_std::task::block_on(async { + + let query = MyQuery::build(MyQueryVariables + { + slug:Some(tournament) + } ); + + let resp = surf::post(URL_SMASH).header("Authorization", key).run_graphql(query).await.unwrap(); + return resp; + }); + + return resp; + +} + +pub fn get_matches(tournament : &str, key : &str) -> Vec { + let mut queues :Vec = Vec::new(); + let query = request_stream_queue(tournament,key); + let st :Vec = query.data.unwrap() + .tournament.unwrap() + .stream_queue.unwrap().into_iter() + .filter(|x| x.is_some()).map(|x| x.unwrap()).collect(); + + for s in st { + let mut current_queue = SmashQueue { + name : s.stream.unwrap().stream_name.unwrap_or(String::from("Stream Queue Not Named")), + matches : Vec::new() }; + + if s.sets.is_some() { + let sets : Vec = s.sets.unwrap().into_iter().filter(|x| x.is_some()).map(|x| x.unwrap()).collect(); + for set in sets { + + let slot: Vec = set.slots.unwrap().into_iter().filter(|x| x.is_some()).map(|x| x.unwrap()).collect(); + let mut iter = slot.into_iter(); + let p1 = iter.next(); + let p2 = iter.next(); + + + let p1name = match p1 { + Some(x) => match x.entrant { + Some(n) => n.name.unwrap(), + _ => String::new() + }, + _ => String::new() + }; + + + let p2name = match p2 { + Some(x) => match x.entrant { + Some(n) => n.name.unwrap(), + _ => String::new() + }, + _ => String::new() + }; + + + if !(p1name.is_empty() & p2name.is_empty()){ + + let mat = Match { full_round_test : String::from(set.full_round_text.unwrap()) , + player1: String::from(p1name), + player2: String::from(p2name), + round: set.round.unwrap(), + station: String::from("LOL") + }; + + current_queue.matches.push(mat); + } + + } + + } + queues.push(current_queue) + } + return queues; +} +