All current work
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
mod models;
|
||||
mod registry;
|
||||
|
||||
use registry::ContentRegistry;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("=== Elysium Game Core Backend ===");
|
||||
|
||||
let mut registry = ContentRegistry::new();
|
||||
|
||||
if let Err(e) = registry.load_from_dir("data") {
|
||||
eprintln!("Ошибка при загрузке реестра данных: {}", e);
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
println!("\n--- Проверка загруженных данных ---");
|
||||
|
||||
for (id, unit) in ®istry.units {
|
||||
println!("\n[Юнит]: {} ({})", unit.name, id);
|
||||
println!(" Размер: {}", unit.size);
|
||||
println!(" Тэги: {:?}", unit.tags);
|
||||
println!(
|
||||
" Витальность: HP={}, Morale={}, Mana={}, Stamina={}",
|
||||
unit.stats.max_hp, unit.stats.max_morale, unit.stats.max_mana, unit.stats.max_stamina
|
||||
);
|
||||
println!(
|
||||
" Характеристики: Интеллект={}, Сила={}, Ловкость={}, Скорость={}",
|
||||
unit.special.intellect, unit.special.strengh, unit.special.agility, unit.special.speed
|
||||
);
|
||||
println!(" Реакция на смерть (on_death): {:?}", unit.strategy.on_death.actions);
|
||||
println!(" Контратака (counter): {:?}", unit.strategy.counter.actions);
|
||||
|
||||
println!(" Доступные экшены (в порядке приоритета):");
|
||||
for action_id in &unit.actions {
|
||||
if let Some(action) = registry.actions.get(action_id) {
|
||||
let act_type = action.action_type.as_deref().unwrap_or("Normal");
|
||||
println!(
|
||||
" -> Экшен: '{}' [Тип: {}, Дальность: {}, На старт боя: {}]",
|
||||
action.name, act_type, action.targeting.range, action.cost.on_battle_start
|
||||
);
|
||||
|
||||
for effect_link in &action.effects {
|
||||
if let Some(effect) = registry.effects.get(&effect_link.id) {
|
||||
println!(
|
||||
" * Эффект: '{}' [Служебный: {}, Категория: '{}', Базовый: {}, Множитель: {}]",
|
||||
effect.name,
|
||||
effect.service,
|
||||
effect.category,
|
||||
effect.base_amount,
|
||||
effect_link.multiplier
|
||||
);
|
||||
} else {
|
||||
eprintln!(" * [ОШИБКА] Эффект '{}' не найден в реестре!", effect_link.id);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
eprintln!(" -> [ОШИБКА] Экшен '{}' не найден в реестре!", action_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// ==================== EFFECT ====================
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct EffectDefinition {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
|
||||
#[serde(default)]
|
||||
pub service: bool,
|
||||
|
||||
pub category: String,
|
||||
|
||||
#[serde(default)]
|
||||
pub damage_type: Option<String>,
|
||||
|
||||
pub base_amount: f32,
|
||||
pub stat_source: Option<String>,
|
||||
pub resist_stat: Option<String>,
|
||||
pub target_stat: Option<String>,
|
||||
pub target_tag: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
pub duration: Option<u32>,
|
||||
|
||||
// Триггерные экшены и спавн
|
||||
#[serde(default)]
|
||||
pub on_trigger_action: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub on_expire_action: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub on_death_action: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub spawn: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub effects: Vec<String>,
|
||||
}
|
||||
|
||||
// ==================== ACTION ====================
|
||||
// #[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
// pub enum RangeType {
|
||||
// Instant,
|
||||
// SelfTarget, // Подходит для RangeType = "Self"
|
||||
// Line,
|
||||
// Circle,
|
||||
// }
|
||||
|
||||
// #[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
// pub enum TargetType {
|
||||
// SelfTarget, // Подходит под "Self" в TOML
|
||||
// Enemy,
|
||||
// Ally,
|
||||
// Empty,
|
||||
// Object,
|
||||
// Fort,
|
||||
// }
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct TargetingRule {
|
||||
pub range: u32,
|
||||
pub range_type: String, // String для поддержки кастомных и гибких "Self", "Line" и т.д.
|
||||
pub radius: u32,
|
||||
pub target: String, // String для гибкости ("Self", "Enemy", "Ally", etc.)
|
||||
#[serde(default)]
|
||||
pub required_tags: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub forbidden_tags: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct ActionCost {
|
||||
#[serde(default)]
|
||||
pub health: i32,
|
||||
#[serde(default)]
|
||||
pub mana: i32,
|
||||
#[serde(default)]
|
||||
pub stamina: i32,
|
||||
#[serde(default)]
|
||||
pub on_battle_start: u32, // Боеприпас на старт боя
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct EffectLink {
|
||||
pub id: String,
|
||||
#[serde(default = "default_multiplier")]
|
||||
pub multiplier: f32,
|
||||
}
|
||||
|
||||
fn default_multiplier() -> f32 {
|
||||
1.0
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ActionDefinition {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
|
||||
#[serde(rename = "type", default)]
|
||||
pub action_type: Option<String>, // Опциональный тип ("Service" и т.д.)
|
||||
pub tags: Vec<String>,
|
||||
pub targeting: TargetingRule,
|
||||
pub cost: ActionCost,
|
||||
pub effects: Vec<EffectLink>,
|
||||
}
|
||||
|
||||
// ==================== UNIT & STATS ====================
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct VitalStats {
|
||||
pub max_hp: i32,
|
||||
pub max_morale: i32,
|
||||
pub max_mana: i32,
|
||||
pub max_stamina: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct AmmoStats {
|
||||
#[serde(default)]
|
||||
pub max_ammo_spears: u32,
|
||||
#[serde(default)]
|
||||
pub max_ammo_arrows: u32,
|
||||
#[serde(default)]
|
||||
pub max_ammo_misc: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SpecialStats {
|
||||
pub intellect: i32,
|
||||
pub strengh: i32,
|
||||
pub agility: i32,
|
||||
pub speed: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct ResistsStats {
|
||||
#[serde(default)]
|
||||
pub pierce_armor: i32,
|
||||
#[serde(default)]
|
||||
pub slash_armor: i32,
|
||||
#[serde(default)]
|
||||
pub blunt_armor: i32,
|
||||
#[serde(default)]
|
||||
pub hack_armor: i32,
|
||||
#[serde(default)]
|
||||
pub magic_armor: i32,
|
||||
#[serde(default)]
|
||||
pub fire_armor: i32,
|
||||
#[serde(default)]
|
||||
pub frost_armor: i32,
|
||||
#[serde(default)]
|
||||
pub lightning_armor: i32,
|
||||
#[serde(default)]
|
||||
pub light_armor: i32,
|
||||
#[serde(default)]
|
||||
pub dark_armor: i32,
|
||||
#[serde(default)]
|
||||
pub blight_armor: i32
|
||||
}
|
||||
|
||||
// ==================== STRATEGY & REACTIONS ====================
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum PositionPriority {
|
||||
Frontline,
|
||||
Backline,
|
||||
Rear,
|
||||
Stationary
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum TargetPositionPriority {
|
||||
Frontline,
|
||||
Backline,
|
||||
Rear,
|
||||
Any,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum TargetCriterion {
|
||||
Closest,
|
||||
MaxDanger,
|
||||
MinDanger,
|
||||
LowestHP,
|
||||
Any
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct TargetPriorityConfig {
|
||||
pub position: TargetPositionPriority,
|
||||
pub criterion: TargetCriterion,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct Thresholds {
|
||||
#[serde(default)]
|
||||
pub flee_hp_pct: u32,
|
||||
#[serde(default)]
|
||||
pub flee_morale_pct: u32,
|
||||
#[serde(default)]
|
||||
pub min_stamina_reserve: i32,
|
||||
#[serde(default)]
|
||||
pub min_mana_reserve: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct ReactionBlock {
|
||||
#[serde(default)]
|
||||
pub actions: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct LowHealthBlock {
|
||||
#[serde(default)]
|
||||
pub actions: Vec<String>,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct OverwatchBlock {
|
||||
#[serde(default)]
|
||||
pub radius: u32,
|
||||
#[serde(default)]
|
||||
pub actions: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct AuraBlock {
|
||||
#[serde(default)]
|
||||
pub radius: u32,
|
||||
#[serde(default)]
|
||||
pub effects: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct StrategyConfig {
|
||||
pub position_priority: PositionPriority,
|
||||
pub target_priority: TargetPriorityConfig,
|
||||
pub thresholds: Thresholds,
|
||||
|
||||
// Новые блоки реакций
|
||||
#[serde(default)]
|
||||
pub counter: ReactionBlock,
|
||||
#[serde(default)]
|
||||
pub overwatch: OverwatchBlock,
|
||||
#[serde(default)]
|
||||
pub on_death: ReactionBlock,
|
||||
#[serde(default)]
|
||||
pub aura: AuraBlock,
|
||||
#[serde(default)]
|
||||
pub low_health: LowHealthBlock
|
||||
}
|
||||
|
||||
// ==================== UNIT TEMPLATE ====================
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct UnitTemplate {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
|
||||
#[serde(default = "default_size")]
|
||||
pub size: String,
|
||||
|
||||
#[serde(default)]
|
||||
pub tags: Vec<String>,
|
||||
|
||||
pub actions: Vec<String>,
|
||||
|
||||
pub stats: VitalStats,
|
||||
|
||||
#[serde(default)]
|
||||
pub ammo: Option<AmmoStats>,
|
||||
|
||||
pub special: SpecialStats,
|
||||
pub resists: ResistsStats,
|
||||
|
||||
pub strategy: StrategyConfig,
|
||||
}
|
||||
|
||||
fn default_size() -> String {
|
||||
"normal".to_string()
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use crate::models::{ActionDefinition, EffectDefinition, UnitTemplate};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ContentRegistry {
|
||||
pub units: HashMap<String, UnitTemplate>,
|
||||
pub actions: HashMap<String, ActionDefinition>,
|
||||
pub effects: HashMap<String, EffectDefinition>,
|
||||
}
|
||||
|
||||
impl ContentRegistry {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn load_from_dir<P: AsRef<Path>>(&mut self, base_dir: P) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let base = base_dir.as_ref();
|
||||
|
||||
// 1. Загружаем Эффекты
|
||||
let effects_path = base.join("effects");
|
||||
if effects_path.exists() {
|
||||
for entry in fs::read_dir(effects_path)? {
|
||||
let path = entry?.path();
|
||||
if path.is_file() && path.extension().and_then(|s| s.to_str()) == Some("toml") {
|
||||
let content = fs::read_to_string(&path)?;
|
||||
let effect: EffectDefinition = toml::from_str(&content)?;
|
||||
self.effects.insert(effect.id.clone(), effect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Загружаем Экшены
|
||||
let actions_path = base.join("actions");
|
||||
if actions_path.exists() {
|
||||
for entry in fs::read_dir(actions_path)? {
|
||||
let path = entry?.path();
|
||||
if path.is_file() && path.extension().and_then(|s| s.to_str()) == Some("toml") {
|
||||
let content = fs::read_to_string(&path)?;
|
||||
let action: ActionDefinition = toml::from_str(&content)?;
|
||||
self.actions.insert(action.id.clone(), action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Загружаем Юнитов
|
||||
let units_path = base.join("units");
|
||||
if units_path.exists() {
|
||||
for entry in fs::read_dir(units_path)? {
|
||||
let path = entry?.path();
|
||||
if path.is_file() && path.extension().and_then(|s| s.to_str()) == Some("toml") {
|
||||
let content = fs::read_to_string(&path)?;
|
||||
let unit: UnitTemplate = toml::from_str(&content)?;
|
||||
self.units.insert(unit.id.clone(), unit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("=== Реестр успешно загружен ===");
|
||||
println!(" - Эффектов: {}", self.effects.len());
|
||||
println!(" - Экшенов: {}", self.actions.len());
|
||||
println!(" - Юнитов: {}", self.units.len());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user