Init
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
2400
Cargo.lock
generated
Normal file
2400
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
20
Cargo.toml
Normal file
20
Cargo.toml
Normal file
@@ -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"]
|
||||||
8
build.rs
Normal file
8
build.rs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fn main() {
|
||||||
|
cynic_codegen::register_schema("startgg")
|
||||||
|
.from_sdl_file("schemas/startgg.gql")
|
||||||
|
.unwrap()
|
||||||
|
.as_default()
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
BIN
font/achemine_bold.ttf
Normal file
BIN
font/achemine_bold.ttf
Normal file
Binary file not shown.
BIN
font/achemine_italic.ttf
Normal file
BIN
font/achemine_italic.ttf
Normal file
Binary file not shown.
BIN
font/achemine_regular.ttf
Normal file
BIN
font/achemine_regular.ttf
Normal file
Binary file not shown.
BIN
font/vcr.ttf
Normal file
BIN
font/vcr.ttf
Normal file
Binary file not shown.
2733
schemas/startgg.gql
Normal file
2733
schemas/startgg.gql
Normal file
File diff suppressed because it is too large
Load Diff
181
src/main.rs
Normal file
181
src/main.rs
Normal file
@@ -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<u32>,
|
||||||
|
fullscreen: Option<bool>,
|
||||||
|
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<sdl2::video::Window> , queues : &Vec<smashrequest::SmashQueue>,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<dyn std::error::Error>> {
|
||||||
|
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::<SmashQueue>::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<sdl2::video::Window> = 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::SmashQueue>= 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
59
src/smashquery.rs
Normal file
59
src/smashquery.rs
Normal file
@@ -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<Tournament>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::Scalar, Debug)]
|
||||||
|
#[cynic(graphql_type = "ID")]
|
||||||
|
struct IntegerId(u32);
|
||||||
|
|
||||||
|
#[derive(cynic::QueryFragment, Debug)]
|
||||||
|
pub struct Tournament {
|
||||||
|
pub id: Option<IntegerId>,
|
||||||
|
pub name: Option<String>,
|
||||||
|
pub stream_queue: Option<Vec<Option<StreamQueue>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryFragment, Debug)]
|
||||||
|
pub struct StreamQueue {
|
||||||
|
pub sets: Option<Vec<Option<Set>>>,
|
||||||
|
pub id: Option<String>,
|
||||||
|
pub stream: Option<Streams>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryFragment, Debug)]
|
||||||
|
pub struct Set {
|
||||||
|
pub id: Option<IntegerId>,
|
||||||
|
pub full_round_text: Option<String>,
|
||||||
|
pub round: Option<i32>,
|
||||||
|
pub state: Option<i32>,
|
||||||
|
pub total_games: Option<i32>,
|
||||||
|
#[arguments(includeByes: false)]
|
||||||
|
pub slots: Option<Vec<Option<SetSlot>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryFragment, Debug)]
|
||||||
|
pub struct SetSlot {
|
||||||
|
pub entrant: Option<Entrant>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryFragment, Debug)]
|
||||||
|
pub struct Entrant {
|
||||||
|
pub id: Option<IntegerId>,
|
||||||
|
pub name: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryFragment, Debug)]
|
||||||
|
pub struct Streams {
|
||||||
|
pub stream_name: Option<String>,
|
||||||
|
}
|
||||||
110
src/smashrequest.rs
Normal file
110
src/smashrequest.rs
Normal file
@@ -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<Match>
|
||||||
|
}
|
||||||
|
|
||||||
|
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<MyQuery>{
|
||||||
|
|
||||||
|
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<SmashQueue> {
|
||||||
|
let mut queues :Vec<SmashQueue> = Vec::new();
|
||||||
|
let query = request_stream_queue(tournament,key);
|
||||||
|
let st :Vec<StreamQueue> = 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<Set> = s.sets.unwrap().into_iter().filter(|x| x.is_some()).map(|x| x.unwrap()).collect();
|
||||||
|
for set in sets {
|
||||||
|
|
||||||
|
let slot: Vec<SetSlot> = 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;
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user