initial commit
This commit is contained in:
commit
ccc3c01f2a
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/target
|
1503
Cargo.lock
generated
Normal file
1503
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
9
Cargo.toml
Normal file
9
Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "cs2_gsi"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
rocket = { version = "=0.5.0-rc.3", features = ["json"] }
|
23
gamestate_integration_consolesample.cfg
Normal file
23
gamestate_integration_consolesample.cfg
Normal file
@ -0,0 +1,23 @@
|
||||
"Observer All Players v.1"
|
||||
{
|
||||
"uri" "http://127.0.0.01:8000/gsi"
|
||||
"timeout" "5.0"
|
||||
"buffer" "0.1"
|
||||
"throttle" "0.1"
|
||||
"heartbeat" "30.0"
|
||||
"auth"
|
||||
{
|
||||
"token" "Q79v5tcxVQ8u"
|
||||
}
|
||||
"data"
|
||||
{
|
||||
"map_round_wins" "1" // history of round wins
|
||||
"map" "1" // mode, map, phase, team scores
|
||||
"player_id" "1" // steamid
|
||||
"player_match_stats" "1" // scoreboard info
|
||||
"player_state" "1" // armor, flashed, equip_value, health, etc.
|
||||
"player_weapons" "1" // list of player weapons and weapon state
|
||||
"provider" "1" // info about the game providing info
|
||||
"round" "1" // round phase and the winning team
|
||||
}
|
||||
}
|
123
src/gamestate.rs
Normal file
123
src/gamestate.rs
Normal file
@ -0,0 +1,123 @@
|
||||
use rocket::serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct GamestateData {
|
||||
pub provider: Provider,
|
||||
pub auth: Auth,
|
||||
// pub map: Option<Map>,
|
||||
pub round: Option<Round>,
|
||||
pub player: Option<Player>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct Provider {
|
||||
pub name: String,
|
||||
pub appid: u16,
|
||||
pub version: u16,
|
||||
pub steamid: String,
|
||||
pub timestamp: u64,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct Auth {
|
||||
pub token: String
|
||||
}
|
||||
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct Map {
|
||||
pub mode: String,
|
||||
pub name: String,
|
||||
pub phase: String,
|
||||
pub round: u16,
|
||||
pub team_ct: Team,
|
||||
pub team_t: Team,
|
||||
pub num_matches_to_win_series: u16,
|
||||
pub current_spectators: u16,
|
||||
pub souvenirs_total: u16,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct Team {
|
||||
pub score: u16,
|
||||
pub consecutive_round_losses: u16,
|
||||
pub timeouts_remaining: u16,
|
||||
pub matches_won_this_series: u16,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct Player {
|
||||
pub clan: Option<String>,
|
||||
pub spectarget: Option<String>,
|
||||
pub steamid: String,
|
||||
pub name: String,
|
||||
pub activity: String,
|
||||
// pub match_stats: MatchStats,
|
||||
pub state: Option<State>,
|
||||
// pub weapons: Weapons,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct MatchStats {
|
||||
pub kills: u16,
|
||||
pub assists: u16,
|
||||
pub deaths: u16,
|
||||
pub mvps: u16,
|
||||
pub score: u16,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct State {
|
||||
pub health: u16,
|
||||
pub armor: u16,
|
||||
pub helmet: bool,
|
||||
pub flashed: u16,
|
||||
pub smoked: u16,
|
||||
pub burning: u16,
|
||||
pub money: u16,
|
||||
pub round_kills: u16,
|
||||
pub round_killhs: u16,
|
||||
pub equip_value: u16,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct Weapons {
|
||||
pub weapon_0: Weapon,
|
||||
pub weapon_1: Weapon,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct Weapon {
|
||||
pub name: String,
|
||||
pub paintkit: String,
|
||||
pub type_: String,
|
||||
pub ammo_clip: u16,
|
||||
pub ammo_clip_max: u16,
|
||||
pub ammo_reserve: u16,
|
||||
pub state: String,
|
||||
// pub ammo_type: String,
|
||||
// pub stat_trak: u16,
|
||||
// pub weapon_type: String,
|
||||
// pub weapon_state: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct Round {
|
||||
pub phase: String,
|
||||
pub bomb: Option<String>,
|
||||
// pub win_team: String,
|
||||
// pub bomb_planted: bool,
|
||||
// pub round_wins: RoundWins,
|
||||
}
|
||||
|
99
src/main.rs
Normal file
99
src/main.rs
Normal file
@ -0,0 +1,99 @@
|
||||
#[macro_use]
|
||||
extern crate rocket;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::AtomicU16;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
|
||||
use rocket::serde::json::{json, Json, Value};
|
||||
use std::thread;
|
||||
|
||||
mod gamestate;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct State {
|
||||
flashed: Arc<AtomicU16>,
|
||||
bomb_planted: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl State {
|
||||
fn new() -> State {
|
||||
State {
|
||||
flashed: Arc::new(AtomicU16::new(0)),
|
||||
bomb_planted: Arc::new(AtomicBool::new(false)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[post("/gsi", data = "<data>")]
|
||||
fn gsi(data: Json<gamestate::GamestateData>, gobal_state: &rocket::State<State>) -> Value {
|
||||
let flashed = match &data.player {
|
||||
Some(player) => match &player.state {
|
||||
Some(state) => state.flashed,
|
||||
None => 0,
|
||||
},
|
||||
None => 0,
|
||||
};
|
||||
|
||||
gobal_state.flashed.store(flashed, Ordering::Relaxed);
|
||||
|
||||
let planted = match &data.round {
|
||||
Some(round) => match &round.bomb {
|
||||
Some(bomb) => match bomb.as_str() {
|
||||
"planted" => true,
|
||||
_ => false,
|
||||
},
|
||||
None => false,
|
||||
},
|
||||
None => false,
|
||||
};
|
||||
|
||||
gobal_state.bomb_planted.store(planted, Ordering::Relaxed);
|
||||
|
||||
json!({ "status": "ok"})
|
||||
}
|
||||
|
||||
fn build_led_package(len: u32, color: (u8, u8, u8)) -> Vec<u8> {
|
||||
let mut packet: Vec<u8> = vec![1, 1];
|
||||
|
||||
// loop through leds
|
||||
for i in 0..len {
|
||||
packet.push(i as u8);
|
||||
packet.push(color.0);
|
||||
packet.push(color.1);
|
||||
packet.push(color.2);
|
||||
}
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
#[launch]
|
||||
fn rocket() -> _ {
|
||||
let state: State = State::new();
|
||||
let state_clone = state.clone();
|
||||
let addr = "192.168.0.59:21324";
|
||||
|
||||
thread::spawn(move || {
|
||||
let socket = std::net::UdpSocket::bind("0.0.0.0:0").unwrap();
|
||||
loop {
|
||||
thread::sleep(std::time::Duration::from_millis(50));
|
||||
|
||||
let flashed = u8::try_from(state_clone.flashed.load(Ordering::Relaxed)).unwrap_or(0);
|
||||
if flashed > 0 {
|
||||
let packet = build_led_package(36, (flashed, flashed, flashed));
|
||||
socket.send_to(&packet, addr).unwrap();
|
||||
continue;
|
||||
}
|
||||
|
||||
let planted = state_clone.bomb_planted.load(Ordering::Relaxed);
|
||||
|
||||
if planted {
|
||||
let packet = build_led_package(36, (255, 0, 0));
|
||||
socket.send_to(&packet, addr).unwrap();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
rocket::build().manage(state).mount("/", routes![gsi])
|
||||
}
|
Loading…
Reference in New Issue
Block a user