feat: initial commit - Dota 2 egui overlay with GSI, OpenDota API, SQLite cache and recommendation engine
Made-with: Cursor
This commit is contained in:
95
src/overlay/views/in_game.rs
Normal file
95
src/overlay/views/in_game.rs
Normal file
@@ -0,0 +1,95 @@
|
||||
use egui::Ui;
|
||||
use crate::constants::chinese_hero_name;
|
||||
use crate::state::{HeroState, Recommendations};
|
||||
|
||||
/// Render the in-game view with item build recommendations.
|
||||
pub fn render(ui: &mut Ui, hero: &HeroState, recommendations: &Recommendations) {
|
||||
// ---- Header ----
|
||||
ui.horizontal(|ui| {
|
||||
ui.heading(
|
||||
egui::RichText::new("出装推荐")
|
||||
.color(egui::Color32::from_rgb(255, 200, 50))
|
||||
.size(18.0),
|
||||
);
|
||||
if recommendations.is_loading {
|
||||
ui.spinner();
|
||||
}
|
||||
});
|
||||
|
||||
// Hero name (Chinese preferred)
|
||||
if let Some(name) = &hero.hero_name {
|
||||
let display = hero
|
||||
.hero_id
|
||||
.and_then(chinese_hero_name)
|
||||
.unwrap_or_else(|| name.strip_prefix("npc_dota_hero_").unwrap_or(name));
|
||||
ui.horizontal(|ui| {
|
||||
ui.colored_label(egui::Color32::LIGHT_GRAY, "英雄: ");
|
||||
ui.label(
|
||||
egui::RichText::new(display)
|
||||
.color(egui::Color32::WHITE)
|
||||
.strong(),
|
||||
);
|
||||
ui.colored_label(egui::Color32::GRAY, format!("Lv.{}", hero.level));
|
||||
if !hero.alive {
|
||||
ui.colored_label(egui::Color32::RED, " [阵亡]");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ui.separator();
|
||||
|
||||
// ---- Error ----
|
||||
if let Some(err) = &recommendations.last_error {
|
||||
ui.colored_label(egui::Color32::RED, format!("⚠ {}", err));
|
||||
return;
|
||||
}
|
||||
|
||||
if recommendations.item_builds.is_empty() {
|
||||
if recommendations.is_loading {
|
||||
ui.colored_label(egui::Color32::GRAY, "正在加载出装数据...");
|
||||
} else if hero.hero_id.is_none() {
|
||||
ui.colored_label(egui::Color32::GRAY, "等待英雄信息...");
|
||||
} else {
|
||||
ui.colored_label(egui::Color32::GRAY, "暂无出装数据");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// ---- Item phases ----
|
||||
for phase in &recommendations.item_builds {
|
||||
ui.collapsing(
|
||||
egui::RichText::new(&phase.phase_name)
|
||||
.color(egui::Color32::from_rgb(255, 210, 80))
|
||||
.size(13.0),
|
||||
|ui| {
|
||||
egui::Grid::new(format!("items_{}", &phase.phase_name))
|
||||
.num_columns(2)
|
||||
.striped(true)
|
||||
.min_col_width(100.0)
|
||||
.show(ui, |ui| {
|
||||
ui.colored_label(egui::Color32::GRAY, "物品");
|
||||
ui.colored_label(egui::Color32::GRAY, "流行度");
|
||||
ui.end_row();
|
||||
|
||||
for item in &phase.items {
|
||||
ui.label(&item.display_name);
|
||||
let color = popularity_color(item.popularity_pct);
|
||||
ui.colored_label(color, format!("{:.0}%", item.popularity_pct));
|
||||
ui.end_row();
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
ui.add_space(2.0);
|
||||
}
|
||||
}
|
||||
|
||||
fn popularity_color(pct: f32) -> egui::Color32 {
|
||||
if pct >= 40.0 {
|
||||
egui::Color32::from_rgb(100, 230, 100)
|
||||
} else if pct >= 20.0 {
|
||||
egui::Color32::from_rgb(220, 220, 80)
|
||||
} else {
|
||||
egui::Color32::from_rgb(180, 180, 180)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user