All current work
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
Generated
+2007
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "Rust-Telegram-Obsidian"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
teloxide = { version = "0.17", features = ["macros"] }
|
||||||
|
tokio = { version = "1.0", features = ["full"] }
|
||||||
|
chrono = "0.4" # Для генерации дат
|
||||||
|
anyhow = "1.0"
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
use teloxide::prelude::*;
|
||||||
|
use std::fs;
|
||||||
|
use chrono::Local;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
let bot = Bot::from_env();
|
||||||
|
|
||||||
|
teloxide::repl(bot, |bot: Bot, msg: Message| async move {
|
||||||
|
if let Some(text) = msg.text() {
|
||||||
|
let timestamp = Local::now().format("%Y-%m-%d_%H-%M-%S").to_string();
|
||||||
|
let file_name = format!("TNotes/{}.md", timestamp);
|
||||||
|
|
||||||
|
// Здесь асинхронная запись через tokio::fs
|
||||||
|
if let Err(e) = tokio::fs::write(&file_name, text).await {
|
||||||
|
bot.send_message(msg.chat.id, format!("Ошибка записи: {}", e)).await?;
|
||||||
|
} else {
|
||||||
|
bot.send_message(msg.chat.id, "Заметка создана!").await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
respond(())
|
||||||
|
}).await;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
root = Path.home() / "Projects"
|
||||||
|
|
||||||
|
for git_dir in root.rglob(".git"):
|
||||||
|
if git_dir.is_dir():
|
||||||
|
print(f"Удаляю: {git_dir}")
|
||||||
|
shutil.rmtree(git_dir)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
Generated
+163
@@ -0,0 +1,163 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "elysium"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"toml",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "equivalent"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.17.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "2.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
|
||||||
|
dependencies = [
|
||||||
|
"equivalent",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.8.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.107"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.47"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.229"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
|
||||||
|
dependencies = [
|
||||||
|
"serde_core",
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_core"
|
||||||
|
version = "1.0.229"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.229"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_spanned"
|
||||||
|
version = "0.6.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "3.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.8.23"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_spanned",
|
||||||
|
"toml_datetime",
|
||||||
|
"toml_edit",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_datetime"
|
||||||
|
version = "0.6.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_edit"
|
||||||
|
version = "0.22.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
|
"serde",
|
||||||
|
"serde_spanned",
|
||||||
|
"toml_datetime",
|
||||||
|
"toml_write",
|
||||||
|
"winnow",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_write"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winnow"
|
||||||
|
version = "0.7.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
[package]
|
||||||
|
name = "elysium"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
toml = "0.8"
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
id = "apply_necro_warrior_stats"
|
||||||
|
name = "apply_necro_warrior_stats"
|
||||||
|
type = "Service"
|
||||||
|
tags = []
|
||||||
|
|
||||||
|
[targeting]
|
||||||
|
range = 0
|
||||||
|
range_type = "Self"
|
||||||
|
radius = 0
|
||||||
|
target = "Self"
|
||||||
|
required_tags = []
|
||||||
|
forbidden_tags = []
|
||||||
|
|
||||||
|
[cost]
|
||||||
|
mana = 0
|
||||||
|
stamina = 0
|
||||||
|
on_battle_start = 1
|
||||||
|
|
||||||
|
[[effects]]
|
||||||
|
id = "necro_warrior_stats"
|
||||||
|
multiplier = 1
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
id = "move_step"
|
||||||
|
name = "Шаг"
|
||||||
|
type = "Move"
|
||||||
|
tags = []
|
||||||
|
|
||||||
|
[targeting]
|
||||||
|
range = 1
|
||||||
|
range_type = "Line"
|
||||||
|
radius = 0
|
||||||
|
target = "Empty"
|
||||||
|
required_tags = []
|
||||||
|
forbidden_tags = []
|
||||||
|
|
||||||
|
[cost]
|
||||||
|
mana = 0
|
||||||
|
stamina = 1
|
||||||
|
|
||||||
|
[[effects]]
|
||||||
|
id = "move"
|
||||||
|
multiplier = 1
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
id = "necro_strike"
|
||||||
|
name = "Удар некроманта"
|
||||||
|
type = "Attack"
|
||||||
|
tags = ["ArmedAttack"]
|
||||||
|
|
||||||
|
[targeting]
|
||||||
|
range = 1
|
||||||
|
range_type = "Line"
|
||||||
|
radius = 0
|
||||||
|
target = "Enemy"
|
||||||
|
required_tags = ["Living"]
|
||||||
|
forbidden_tags = ["Undead"]
|
||||||
|
|
||||||
|
[cost]
|
||||||
|
mana = 1
|
||||||
|
stamina = 1
|
||||||
|
|
||||||
|
[[effects]]
|
||||||
|
id = "dark_damage"
|
||||||
|
multiplier = 1.2
|
||||||
|
|
||||||
|
[[effects]]
|
||||||
|
id = "slash_damage"
|
||||||
|
multiplier = 1
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
id = "spawn_corpse"
|
||||||
|
name = "Создать труп"
|
||||||
|
type = "Service"
|
||||||
|
tags = ["ArmedAttack"]
|
||||||
|
|
||||||
|
[targeting]
|
||||||
|
range = 0
|
||||||
|
range_type = "Self"
|
||||||
|
radius = 0
|
||||||
|
target = "Any"
|
||||||
|
required_tags = []
|
||||||
|
forbidden_tags = []
|
||||||
|
|
||||||
|
[cost]
|
||||||
|
mana = 0
|
||||||
|
stamina = 0
|
||||||
|
|
||||||
|
[[effects]]
|
||||||
|
id = "spawn_corpse"
|
||||||
|
multiplier = 1
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
id = "move"
|
||||||
|
name = "Движение"
|
||||||
|
service = true
|
||||||
|
category = "Move"
|
||||||
|
damage_type = "none"
|
||||||
|
base_amount = 1.0
|
||||||
|
stat_source = "none"
|
||||||
|
resist_stat = "none"
|
||||||
|
target_stat = "none"
|
||||||
|
target_tag = "none"
|
||||||
|
on_trigger_action = []
|
||||||
|
on_expire_action = []
|
||||||
|
on_death_action = []
|
||||||
|
spawn = []
|
||||||
|
effects = []
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
id = "dark_damage"
|
||||||
|
name = "Урон тьмы"
|
||||||
|
service = false
|
||||||
|
category = "Damage"
|
||||||
|
damage_type = "dark"
|
||||||
|
base_amount = 10.0
|
||||||
|
stat_source = "intellect"
|
||||||
|
resist_stat = "dark_armor"
|
||||||
|
target_stat = "none"
|
||||||
|
target_tag = "none"
|
||||||
|
on_trigger_action = []
|
||||||
|
on_expire_action = []
|
||||||
|
on_death_action = []
|
||||||
|
spawn = []
|
||||||
|
effects = []
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
id = "necro_warrior_stats"
|
||||||
|
name = "necro_warrior_stats урон"
|
||||||
|
category = "Self_Stats"
|
||||||
|
damage_type = "none"
|
||||||
|
base_amount = 0.0
|
||||||
|
stat_source = "none"
|
||||||
|
resist_stat = "none"
|
||||||
|
target_stat = "none"
|
||||||
|
target_tag = "none"
|
||||||
|
on_trigger_action = []
|
||||||
|
on_expire_action = []
|
||||||
|
on_death_action = []
|
||||||
|
spawn = []
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
id = "slash_damage"
|
||||||
|
name = "Режущий урон"
|
||||||
|
category = "Damage"
|
||||||
|
damage_type = "slash"
|
||||||
|
base_amount = 10.0
|
||||||
|
stat_source = "strength"
|
||||||
|
resist_stat = "slash_armor"
|
||||||
|
target_stat = "none"
|
||||||
|
target_tag = "none"
|
||||||
|
on_trigger_action = []
|
||||||
|
on_expire_action = []
|
||||||
|
on_death_action = []
|
||||||
|
spawn = []
|
||||||
|
effects = []
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
id = "slash_damage"
|
||||||
|
name = "Режущий урон"
|
||||||
|
category = "Damage"
|
||||||
|
damage_type = "slash"
|
||||||
|
base_amount = 10.0
|
||||||
|
stat_source = "strength"
|
||||||
|
resist_stat = "slash_armor"
|
||||||
|
target_stat = "none"
|
||||||
|
target_tag = "none"
|
||||||
|
on_trigger_action = []
|
||||||
|
on_expire_action = []
|
||||||
|
on_death_action = []
|
||||||
|
spawn = []
|
||||||
|
effects = []
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
id = "spawn_corpse"
|
||||||
|
name = "Создать труп"
|
||||||
|
category = "Spawn"
|
||||||
|
damage_type = "none"
|
||||||
|
base_amount = 1
|
||||||
|
stat_source = "none"
|
||||||
|
resist_stat = "none"
|
||||||
|
target_stat = "none"
|
||||||
|
target_tag = "none"
|
||||||
|
on_trigger_action = []
|
||||||
|
on_expire_action = []
|
||||||
|
on_death_action = []
|
||||||
|
spawn = ["corpse"]
|
||||||
|
effects = []
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
id = "corpse"
|
||||||
|
name = "Труп"
|
||||||
|
tags = ["Corpse"]
|
||||||
|
size = "none"
|
||||||
|
|
||||||
|
|
||||||
|
actions = [
|
||||||
|
]
|
||||||
|
|
||||||
|
[stats]
|
||||||
|
max_hp = 0
|
||||||
|
max_morale = 0
|
||||||
|
max_mana = 0
|
||||||
|
max_stamina = 0
|
||||||
|
|
||||||
|
[ammo]
|
||||||
|
max_ammo_spears = 0
|
||||||
|
max_ammo_arrows = 0
|
||||||
|
max_ammo_misc = 0
|
||||||
|
|
||||||
|
[special]
|
||||||
|
intellect = 0
|
||||||
|
strengh = 0
|
||||||
|
agility = 0
|
||||||
|
speed = 0
|
||||||
|
|
||||||
|
[resists]
|
||||||
|
pierce_armor = 0
|
||||||
|
slash_armor = 0
|
||||||
|
blunt_armor = 0
|
||||||
|
magic_armor = 0
|
||||||
|
fire_armor = 0
|
||||||
|
frost_armor = 0
|
||||||
|
lightning_armor = 0
|
||||||
|
light_armor = 0
|
||||||
|
dark_armor = 0
|
||||||
|
blight_armor = 0
|
||||||
|
|
||||||
|
[strategy]
|
||||||
|
position_priority = "Stationary"
|
||||||
|
|
||||||
|
[strategy.target_priority]
|
||||||
|
position = "Any"
|
||||||
|
criterion = "Any"
|
||||||
|
|
||||||
|
[strategy.thresholds]
|
||||||
|
flee_hp_pct = 0
|
||||||
|
flee_morale_pct = 0
|
||||||
|
min_stamina_reserve = 0
|
||||||
|
min_mana_reserve = 0
|
||||||
|
|
||||||
|
[strategy.counter]
|
||||||
|
actions = []
|
||||||
|
|
||||||
|
[strategy.overwatch]
|
||||||
|
radius = 0
|
||||||
|
actions = []
|
||||||
|
|
||||||
|
[strategy.on_death]
|
||||||
|
actions = []
|
||||||
|
|
||||||
|
[stategy.low_health]
|
||||||
|
actions = []
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
id = "necro_warrior"
|
||||||
|
name = "Некромант-воин"
|
||||||
|
tags = ["Undead", "Humanoid"]
|
||||||
|
size = "normal"
|
||||||
|
|
||||||
|
|
||||||
|
actions = [
|
||||||
|
"apply_necro_warrior_stats",
|
||||||
|
"necro_strike",
|
||||||
|
"move_step"
|
||||||
|
]
|
||||||
|
|
||||||
|
[stats]
|
||||||
|
max_hp = 30
|
||||||
|
max_morale = 100
|
||||||
|
max_mana = 10
|
||||||
|
max_stamina = 20
|
||||||
|
|
||||||
|
[ammo]
|
||||||
|
max_ammo_spears = 0
|
||||||
|
max_ammo_arrows = 0
|
||||||
|
max_ammo_misc = 0
|
||||||
|
|
||||||
|
[special]
|
||||||
|
intellect = 10
|
||||||
|
strengh = 10
|
||||||
|
agility = 10
|
||||||
|
speed = 5
|
||||||
|
|
||||||
|
[resists]
|
||||||
|
pierce_armor = 0
|
||||||
|
slash_armor = 0
|
||||||
|
blunt_armor = 0
|
||||||
|
magic_armor = 0
|
||||||
|
fire_armor = 0
|
||||||
|
frost_armor = 0
|
||||||
|
lightning_armor = 0
|
||||||
|
light_armor = 0
|
||||||
|
dark_armor = 0
|
||||||
|
blight_armor = 0
|
||||||
|
|
||||||
|
[strategy]
|
||||||
|
position_priority = "Frontline"
|
||||||
|
|
||||||
|
[strategy.target_priority]
|
||||||
|
position = "Frontline"
|
||||||
|
criterion = "MaxDanger"
|
||||||
|
|
||||||
|
[strategy.thresholds]
|
||||||
|
flee_hp_pct = 15
|
||||||
|
flee_morale_pct = 0
|
||||||
|
min_stamina_reserve = 0
|
||||||
|
min_mana_reserve = 0
|
||||||
|
|
||||||
|
[strategy.counter]
|
||||||
|
actions = ["necro_strike"]
|
||||||
|
|
||||||
|
[strategy.overwatch]
|
||||||
|
radius = 0
|
||||||
|
actions = []
|
||||||
|
|
||||||
|
[strategy.on_death]
|
||||||
|
actions = ["spawn_corpse"]
|
||||||
|
|
||||||
|
[strategy.aura]
|
||||||
|
radius = 0
|
||||||
|
effects = []
|
||||||
|
|
||||||
|
[stategy.low_health]
|
||||||
|
actions = []
|
||||||
@@ -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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
Generated
+7
@@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pet-creature-backend-rust"
|
||||||
|
version = "0.1.0"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "pet-creature-backend-rust"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fn main() {
|
||||||
|
println!("Hello, world!");
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
Generated
+5751
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
|||||||
|
[package]
|
||||||
|
name = "bevy_test"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bevy = "0.17"
|
||||||
|
rand = "0.9"
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 686 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
@@ -0,0 +1,128 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy::window::PrimaryWindow;
|
||||||
|
|
||||||
|
const ENEMY_SPEED: f32 = 100.0;
|
||||||
|
const ENEMY_SIZE: f32 = 40.0;
|
||||||
|
|
||||||
|
const HOME_X: f32 = -400.0;
|
||||||
|
const SPAWN_X: f32 = 400.0;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
struct Enemy;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
App::new()
|
||||||
|
.add_plugins(DefaultPlugins)
|
||||||
|
.add_systems(Startup, setup)
|
||||||
|
.add_systems(
|
||||||
|
Update,
|
||||||
|
(
|
||||||
|
spawn_enemies,
|
||||||
|
move_enemies,
|
||||||
|
click_enemies,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup(mut commands: Commands) {
|
||||||
|
commands.spawn(Camera2d);
|
||||||
|
|
||||||
|
// Дом
|
||||||
|
commands.spawn((
|
||||||
|
Sprite {
|
||||||
|
color: Color::srgb(0.2, 0.8, 0.2),
|
||||||
|
custom_size: Some(Vec2::new(20.0, 600.0)),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
Transform::from_xyz(HOME_X, 0.0, 0.0),
|
||||||
|
));
|
||||||
|
|
||||||
|
// Спавн
|
||||||
|
commands.spawn((
|
||||||
|
Sprite {
|
||||||
|
color: Color::srgb(0.8, 0.2, 0.2),
|
||||||
|
custom_size: Some(Vec2::new(20.0, 600.0)),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
Transform::from_xyz(SPAWN_X, 0.0, 0.0),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spawn_enemies(
|
||||||
|
mut commands: Commands,
|
||||||
|
asset_server: Res<AssetServer>,
|
||||||
|
time: Res<Time>,
|
||||||
|
) {
|
||||||
|
// Пока просто спавним врага каждые 2 секунды.
|
||||||
|
//
|
||||||
|
// Это временный вариант.
|
||||||
|
// Позже сделаем нормальный Timer как отдельный ресурс.
|
||||||
|
|
||||||
|
let seconds = time.elapsed_secs();
|
||||||
|
|
||||||
|
if (seconds % 2.0) < 0.02 {
|
||||||
|
let y = rand::random_range(-250.0..250.0);
|
||||||
|
|
||||||
|
let texture = asset_server.load("test.png");
|
||||||
|
|
||||||
|
commands.spawn((
|
||||||
|
Sprite {
|
||||||
|
image: texture,
|
||||||
|
custom_size: Some(Vec2::splat(ENEMY_SIZE)),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
Transform::from_xyz(SPAWN_X, y, 1.0),
|
||||||
|
Enemy,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn move_enemies(
|
||||||
|
mut commands: Commands,
|
||||||
|
mut enemies: Query<(Entity, &mut Transform), With<Enemy>>,
|
||||||
|
time: Res<Time>,
|
||||||
|
) {
|
||||||
|
for (entity, mut transform) in &mut enemies {
|
||||||
|
transform.translation.x -= ENEMY_SPEED * time.delta_secs();
|
||||||
|
|
||||||
|
// Враг дошёл до дома
|
||||||
|
if transform.translation.x <= HOME_X {
|
||||||
|
commands.entity(entity).despawn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn click_enemies(
|
||||||
|
mouse: Res<ButtonInput<MouseButton>>,
|
||||||
|
windows: Query<&Window, With<PrimaryWindow>>,
|
||||||
|
enemies: Query<(Entity, &Transform), With<Enemy>>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
if !mouse.just_pressed(MouseButton::Left) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let window = windows.single().unwrap();
|
||||||
|
|
||||||
|
let Some(cursor) = window.cursor_position() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Переводим координаты мыши из координат окна
|
||||||
|
// в координаты игрового мира.
|
||||||
|
let mouse_world = Vec2::new(
|
||||||
|
cursor.x - window.width() / 2.0,
|
||||||
|
window.height() / 2.0 - cursor.y,
|
||||||
|
);
|
||||||
|
|
||||||
|
for (entity, transform) in &enemies {
|
||||||
|
let enemy_position = transform.translation.truncate();
|
||||||
|
|
||||||
|
let distance = mouse_world.distance(enemy_position);
|
||||||
|
|
||||||
|
if distance < ENEMY_SIZE / 2.0 {
|
||||||
|
commands.entity(entity).despawn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
Generated
+7
@@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rust-training-config-reader"
|
||||||
|
version = "0.1.0"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "rust-training-config-reader"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
host=localhost
|
||||||
|
port=808
|
||||||
|
debug=true
|
||||||
|
workers=8
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
use std::fs;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
struct Config {
|
||||||
|
host: String,
|
||||||
|
port: u16,
|
||||||
|
debug: bool,
|
||||||
|
workers: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
fn init(text: &str) -> Config {
|
||||||
|
let mut new_conf = Config{host: String::new(),port: 0, debug: false, workers: 0};
|
||||||
|
let lines = text.lines();
|
||||||
|
for line in lines {
|
||||||
|
let (key, value) = line.split_once("=").map(|(x,y)| (x.trim(),y.trim())).unwrap();
|
||||||
|
match key {
|
||||||
|
"host" => new_conf.add_host(value),
|
||||||
|
"port" => new_conf.add_port(value),
|
||||||
|
"debug" => new_conf.add_debug(value),
|
||||||
|
"workers" => new_conf.add_workers(value),
|
||||||
|
_ => println!("nothing ready")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
new_conf
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_host(&mut self, host: &str){
|
||||||
|
self.host = host.to_string();
|
||||||
|
println!("host ready");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_port(&mut self, port: &str){
|
||||||
|
let port_ready:u16 = port.parse().expect("Not a u16");
|
||||||
|
self.port = port_ready;
|
||||||
|
println!("port ready");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn add_debug(&mut self, debug: &str){
|
||||||
|
let debug_ready: bool = debug.to_lowercase().parse().expect("Not a bool");
|
||||||
|
self.debug = debug_ready;
|
||||||
|
println!("debug ready");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_workers(&mut self, workers: &str){
|
||||||
|
let workers_ready:u16 = workers.parse().expect("Not a u16");
|
||||||
|
self.workers = workers_ready;
|
||||||
|
println!("workers ready");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_config(path: &str) -> Result<String, io::Error> {
|
||||||
|
fs::read_to_string(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let text = read_config("config.txt").unwrap();
|
||||||
|
let new_config = Config::init(&text);
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
Generated
+7
@@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rust-training-fold-custumers"
|
||||||
|
version = "0.1.0"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "rust-training-fold-custumers"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
use std::{collections::HashMap};
|
||||||
|
|
||||||
|
struct Order {
|
||||||
|
customer: String,
|
||||||
|
price: u32,
|
||||||
|
paid: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("Hello, world!");
|
||||||
|
|
||||||
|
let orders = vec![
|
||||||
|
Order { customer: "Alice".into(), price: 1200, paid: true },
|
||||||
|
Order { customer: "Bob".into(), price: 500, paid: false },
|
||||||
|
Order { customer: "Alice".into(), price: 800, paid: true },
|
||||||
|
Order { customer: "Charlie".into(), price: 2000, paid: true },
|
||||||
|
Order { customer: "Bob".into(), price: 1500, paid: true },
|
||||||
|
Order { customer: "Alice".into(), price: 300, paid: false },
|
||||||
|
];
|
||||||
|
|
||||||
|
let unique = orders.iter().fold(HashMap::new(), |mut acc, x| {
|
||||||
|
if x.paid {
|
||||||
|
*acc.entry(&x.customer).or_insert(0)+=x.price;
|
||||||
|
}
|
||||||
|
acc
|
||||||
|
});
|
||||||
|
|
||||||
|
let result = unique.iter().fold(String::new(), |mut acc, (x,y)| {
|
||||||
|
acc += &format!("{} {}\n", x, y);
|
||||||
|
acc
|
||||||
|
});
|
||||||
|
|
||||||
|
println!("{}",result);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
Generated
+7
@@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rust-training-static-analyser"
|
||||||
|
version = "0.1.0"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "rust-training-static-analyser"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::io::{self, Write};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut input: String = String::new();
|
||||||
|
|
||||||
|
io::stdin()
|
||||||
|
.read_line(&mut input)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let target: String = input.chars()
|
||||||
|
.filter(|c| c.is_alphanumeric() || c.is_whitespace())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let answer = count_words(&target);
|
||||||
|
|
||||||
|
for (word, count) in &answer {
|
||||||
|
println!("{} {}", word, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count_words(text: &str) -> HashMap<&str, usize> {
|
||||||
|
let mut result: HashMap<&str, usize> = HashMap::new();
|
||||||
|
|
||||||
|
for word in text.split_whitespace() {
|
||||||
|
*result.entry(word).or_insert(0) += 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
Generated
+7
@@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rust-training"
|
||||||
|
version = "0.1.0"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "rust-training"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
@@ -0,0 +1,300 @@
|
|||||||
|
use std::io::{self, Write};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
loop {
|
||||||
|
print!("Choose task number: ");
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
|
||||||
|
let mut task = String::new();
|
||||||
|
|
||||||
|
io::stdin()
|
||||||
|
.read_line(&mut task)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let task: i32 = match task.trim().parse() {
|
||||||
|
Ok(number) => number,
|
||||||
|
Err(_) => {
|
||||||
|
println!("Please enter a number!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if task <= 0 {
|
||||||
|
println!("Please enter positive number!");
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
println!("You chose task number: {task}");
|
||||||
|
match task {
|
||||||
|
1 => task1(),
|
||||||
|
2 => task2(),
|
||||||
|
3 => task3(),
|
||||||
|
4 => task4(),
|
||||||
|
5 => task5(),
|
||||||
|
6 => task6(),
|
||||||
|
7 => task7(),
|
||||||
|
8 => task8(),
|
||||||
|
9 => task9(),
|
||||||
|
10 => task10(),
|
||||||
|
_ => println!("Unknown task"),
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn task1(){
|
||||||
|
println!("Starting Task 1");
|
||||||
|
|
||||||
|
loop {
|
||||||
|
print!("Enter a number: ");
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
|
||||||
|
let mut task = String::new();
|
||||||
|
|
||||||
|
io::stdin()
|
||||||
|
.read_line(&mut task)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let task: i32 = match task.trim().parse() {
|
||||||
|
Ok(number) => number,
|
||||||
|
Err(_) => {
|
||||||
|
println!("Please enter a number!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if task <= 0 {
|
||||||
|
println!("It's negative");
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
if task == 0 {
|
||||||
|
println!("It's negative");
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
println!("It's positive");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn task2(){
|
||||||
|
println!("Starting Task 2") ;
|
||||||
|
print!("Enter a String: ");
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
let mut task = String::new();
|
||||||
|
|
||||||
|
io::stdin()
|
||||||
|
.read_line(&mut task)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let symbols: i32 = task.
|
||||||
|
trim_end()
|
||||||
|
.chars()
|
||||||
|
.count()
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
println!("It has {} symbols", symbols);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn task3(){
|
||||||
|
println!("Starting Task 3");
|
||||||
|
print!("Enter a String: ");
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
let mut task = String::new();
|
||||||
|
|
||||||
|
io::stdin()
|
||||||
|
.read_line(&mut task)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let last_symbol = task.trim_end().chars().last().unwrap();
|
||||||
|
|
||||||
|
println!("Last symbol is {}", last_symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn task4(){
|
||||||
|
println!("Starting Task 4");
|
||||||
|
print!("Enter first String: ");
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
let mut task1 = String::new();
|
||||||
|
|
||||||
|
io::stdin()
|
||||||
|
.read_line(&mut task1)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let first_symbol_1 = task1.trim_end().chars().next().unwrap();
|
||||||
|
|
||||||
|
//println!("first symbol of first string is {}", first_symbol_1);
|
||||||
|
|
||||||
|
print!("Enter second String: ");
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
let mut task2 = String::new();
|
||||||
|
|
||||||
|
io::stdin()
|
||||||
|
.read_line(&mut task2)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let first_symbol_2 = task2.trim_end().chars().next().unwrap();
|
||||||
|
|
||||||
|
if first_symbol_1 == first_symbol_2 {
|
||||||
|
println!("First symbols are equal")
|
||||||
|
} else {
|
||||||
|
println!("First symbols are not equal")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn task5(){
|
||||||
|
println!("This task is boring, to transform string into int, so I passed it")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn task6(){
|
||||||
|
println!("Starting Task 6");
|
||||||
|
|
||||||
|
loop {
|
||||||
|
print!("Enter a number: ");
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
|
||||||
|
let mut task = String::new();
|
||||||
|
|
||||||
|
io::stdin()
|
||||||
|
.read_line(&mut task)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let task: i32 = match task.trim().parse() {
|
||||||
|
Ok(number) => number,
|
||||||
|
Err(_) => {
|
||||||
|
println!("Please enter a number!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (task > 10) || (task<1) {
|
||||||
|
println!("It's not in range");
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
println!("It's in range");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn task7(){
|
||||||
|
println!("Starting Task 7");
|
||||||
|
|
||||||
|
loop {
|
||||||
|
print!("Enter a number: ");
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
|
||||||
|
let mut task = String::new();
|
||||||
|
|
||||||
|
io::stdin()
|
||||||
|
.read_line(&mut task)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut task: i32 = match task.trim().parse() {
|
||||||
|
Ok(number) => number,
|
||||||
|
Err(_) => {
|
||||||
|
println!("Please enter a number!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
task = task.abs()%10;
|
||||||
|
println!("Last digit is {task}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn task8(){
|
||||||
|
println!("Starting Task 8");
|
||||||
|
|
||||||
|
loop {
|
||||||
|
print!("Enter a number: ");
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
|
||||||
|
let mut task = String::new();
|
||||||
|
|
||||||
|
io::stdin()
|
||||||
|
.read_line(&mut task)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut task: i32 = match task.trim().parse() {
|
||||||
|
Ok(number) => number,
|
||||||
|
Err(_) => {
|
||||||
|
println!("Please enter a number!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
task = task.abs();
|
||||||
|
while task>=10 {
|
||||||
|
task = task/10;
|
||||||
|
}
|
||||||
|
println!("First digit is {task}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn task9(){
|
||||||
|
println!("Starting Task 9");
|
||||||
|
|
||||||
|
loop {
|
||||||
|
print!("Enter a number: ");
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
|
||||||
|
let mut task = String::new();
|
||||||
|
|
||||||
|
io::stdin()
|
||||||
|
.read_line(&mut task)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut task: i32 = match task.trim().parse() {
|
||||||
|
Ok(number) => number,
|
||||||
|
Err(_) => {
|
||||||
|
println!("Please enter a number!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
task = task.abs();
|
||||||
|
let last_digit: i32 = task%10;
|
||||||
|
//println!("Last digit is {last_digit}");
|
||||||
|
|
||||||
|
|
||||||
|
while task>=10 {
|
||||||
|
task = task/10;
|
||||||
|
}
|
||||||
|
let first_digit: i32= task;
|
||||||
|
//println!("First digit is {first_digit}");
|
||||||
|
|
||||||
|
println!("Sum of fist and last digits is {}", last_digit+first_digit);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn task10(){
|
||||||
|
println!("Starting Task 10");
|
||||||
|
|
||||||
|
loop {
|
||||||
|
print!("Enter a number: ");
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
|
||||||
|
let mut task = String::new();
|
||||||
|
let mut digits = 1;
|
||||||
|
io::stdin()
|
||||||
|
.read_line(&mut task)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut task: i32 = match task.trim().parse() {
|
||||||
|
Ok(number) => number,
|
||||||
|
Err(_) => {
|
||||||
|
println!("Please enter a number!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
while task>=10 {
|
||||||
|
task = task/10;
|
||||||
|
digits+=1;
|
||||||
|
}
|
||||||
|
//println!("First digit is {first_digit}");
|
||||||
|
|
||||||
|
println!("Number of digits equals {}", digits);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user