Skip to content

Commit 61bf4f8

Browse files
feat: add gui
1 parent b941cdd commit 61bf4f8

File tree

10 files changed

+2771
-366
lines changed

10 files changed

+2771
-366
lines changed

Cargo.lock

Lines changed: 2382 additions & 133 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ edition = "2021"
99
axum = "0.7.1"
1010
axum-macros = "0.4.0"
1111
config-file = "0.2.3"
12+
eframe = "0.24.1"
13+
egui = "0.24.1"
1214
log = "0.4.20"
1315
rand = "0.8.5"
1416
reqwest = { version = "0.11.22", features = ["json"] }

assets/icon.png

35.3 KB
Loading

config.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"shock_mode": "LastHitPercentage",
3+
"min_duration": 5,
4+
"max_duration": 15,
5+
"min_intensity": 15,
6+
"max_intensity": 83,
7+
"beep_on_match_start": false,
8+
"beep_on_round_start": true,
9+
"username": "test",
10+
"code": "somesharecode",
11+
"apikey": "1349390485"
12+
}

config.toml

Lines changed: 0 additions & 20 deletions
This file was deleted.

src/api.rs

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
use std::sync::Arc;
2+
3+
use axum::{extract::State, http::StatusCode, routing::post, Json, Router};
4+
use log::info;
5+
use rand::{rngs::StdRng, Rng, SeedableRng};
6+
use tokio::sync::{Mutex, RwLock};
7+
8+
use crate::{
9+
config::{self, Config},
10+
gamestateintegration::{MapPhase, Payload, RoundPhase},
11+
pishock, AppState, GameState, PlayerState,
12+
};
13+
14+
pub async fn run(config: Arc<RwLock<Config>>) {
15+
info!("Sending test beep");
16+
pishock::beep(config.clone(), 1).await;
17+
18+
let state = AppState {
19+
game_state: Arc::from(Mutex::from(GameState::default())),
20+
config: config.clone(),
21+
};
22+
23+
let app = Router::new()
24+
.route("/data", post(read_data))
25+
.with_state(state);
26+
27+
info!("Starting server on {}", "127.0.0.1:3000");
28+
29+
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
30+
.await
31+
.unwrap();
32+
axum::serve(listener, app).await.unwrap();
33+
}
34+
35+
async fn read_data(State(state): State<AppState>, Json(payload): Json<Payload>) -> StatusCode {
36+
let mut game_state = state.game_state.lock().await;
37+
let config = state.config.read().await;
38+
39+
if let Some(provider) = payload.provider {
40+
game_state.steam_id = provider.steamid;
41+
}
42+
43+
if let Some(map) = payload.map {
44+
if game_state.map_phase == MapPhase::Warmup && map.phase == MapPhase::Live {
45+
info!("Match started");
46+
47+
if config.beep_on_match_start {
48+
pishock::beep(state.config.clone(), 2).await;
49+
}
50+
51+
// Reset game state to default
52+
game_state.reset();
53+
}
54+
55+
game_state.map_phase = map.phase;
56+
}
57+
58+
if let Some(round) = payload.round {
59+
if game_state.round_phase == RoundPhase::Freezetime && round.phase == RoundPhase::Live {
60+
if config.beep_on_round_start {
61+
info!("Round started");
62+
pishock::beep(state.config.clone(), 1).await;
63+
}
64+
}
65+
66+
game_state.round_phase = round.phase;
67+
}
68+
69+
if game_state.map_phase != MapPhase::Live {
70+
return StatusCode::OK;
71+
}
72+
73+
if let Some(player) = payload.player {
74+
if player.steamid != game_state.steam_id {
75+
return StatusCode::OK;
76+
}
77+
78+
if let Some(player_state) = &mut game_state.player_state {
79+
if player_state.health > player.state.health && player.state.health > 0 {
80+
// Took damage and survived
81+
82+
/*
83+
println!("Player took damage, vibrating");
84+
85+
let diff = player_state.health - player.state.health;
86+
87+
let res = pishock::post(
88+
&config,
89+
pishock::PiShockOp::Vibrate {
90+
intensity: diff,
91+
duration: 1,
92+
},
93+
)
94+
.await;
95+
96+
match res {
97+
Ok(code) => println!("Vibrated with code {}", code),
98+
Err(e) => println!("Error while vibrating: {}", e),
99+
};
100+
*/
101+
}
102+
103+
if player.match_stats.deaths > player_state.deaths {
104+
// Died
105+
106+
// Github Copilot is based
107+
// let res = pishock::post(&api_state, pishock::PiShockOp::Shock { intensity: 100, duration: 1 }).await;
108+
109+
info!("Player died, shocking");
110+
111+
match config.shock_mode {
112+
config::ShockMode::Random => {
113+
let mut rng = StdRng::from_entropy();
114+
let intensity = rng.gen_range(config.min_intensity..=config.max_intensity);
115+
let duration = rng.gen_range(config.min_duration..=config.max_duration);
116+
117+
pishock::shock(state.config.clone(), intensity, duration).await;
118+
}
119+
config::ShockMode::LastHitPercentage => {
120+
let intensity = (player_state.health as f32 / 100.0
121+
* config.max_intensity as f32)
122+
as i32;
123+
let duration = (player_state.health as f32 / 100.0
124+
* config.max_duration as f32)
125+
as i32;
126+
127+
pishock::shock(state.config.clone(), intensity, duration).await;
128+
}
129+
};
130+
}
131+
132+
player_state.health = player.state.health;
133+
player_state.armor = player.state.armor;
134+
player_state.kills = player.match_stats.kills;
135+
player_state.deaths = player.match_stats.deaths;
136+
} else {
137+
println!("Player state initialized");
138+
139+
game_state.player_state = Some(PlayerState {
140+
health: player.state.health,
141+
armor: player.state.armor,
142+
kills: player.match_stats.kills,
143+
deaths: player.match_stats.deaths,
144+
});
145+
}
146+
}
147+
148+
StatusCode::OK
149+
}

src/config.rs

Lines changed: 6 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
use std::{fs::OpenOptions, io::Write};
22

33
use log::error;
4-
use serde::Deserialize;
4+
use serde::{Deserialize, Serialize};
55

6-
#[derive(Deserialize, Debug, Clone, PartialEq, Eq)]
7-
#[serde(rename_all = "snake_case")]
6+
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
87
pub enum ShockMode {
98
Random,
109
LastHitPercentage,
1110
}
1211

13-
#[derive(Deserialize, Debug, Clone)]
12+
#[derive(Deserialize, Serialize, Debug, Clone, Eq, PartialEq)]
1413
pub struct Config {
1514
pub shock_mode: ShockMode,
1615
pub min_duration: i32,
@@ -79,42 +78,13 @@ impl Config {
7978
let mut file = OpenOptions::new()
8079
.create(true)
8180
.write(true)
81+
.truncate(true)
8282
.open(path)
8383
.expect(format!("Failed to open config file, {}", path).as_str());
8484

85-
let raw = format!(
86-
"# Shock mode, one of; random, last_hit_percentage
87-
shock_mode = \"random\"
88-
# Minimum duration of the shock
89-
min_duration = {}
90-
# Maximum duration of the shock
91-
max_duration = {}
92-
# Minimum intensity of the shock, 1-100
93-
min_intensity = {}
94-
# Maximum intensity of the shock, 1-100
95-
max_intensity = {}
96-
# Beep when match starts
97-
beep_on_match_start = {}
98-
# Beep when round starts
99-
beep_on_round_start = {}
100-
# PiShock username to access the api
101-
username = \"{}\"
102-
# PiShock share code to access the api
103-
code = \"{}\"
104-
# PiShock api key to access the api
105-
apikey = \"{}\"",
106-
self.min_duration,
107-
self.max_duration,
108-
self.min_intensity,
109-
self.max_intensity,
110-
self.beep_on_match_start,
111-
self.beep_on_round_start,
112-
self.username,
113-
self.code,
114-
self.apikey
115-
);
85+
let json = serde_json::to_string_pretty(self).expect("Failed to serialize config");
11686

117-
file.write_all(raw.as_bytes())
87+
file.write_all(json.as_bytes())
11888
.expect("Failed to write config file");
11989
}
12090
}

0 commit comments

Comments
 (0)