2026-01-06 23:57:37 +07:00
|
|
|
use proto::{Avatar, AvatarPathData};
|
2024-03-29 16:49:57 +07:00
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
use std::collections::{BTreeMap, HashMap};
|
|
|
|
|
|
2025-03-11 17:27:05 +07:00
|
|
|
use crate::structs::{
|
|
|
|
|
// AllowedLanguages,
|
|
|
|
|
avatar::{AvatarJson, MultiPathAvatar},
|
|
|
|
|
battle::BattleConfig,
|
|
|
|
|
lightcone::Lightcone,
|
|
|
|
|
persistent::Persistent,
|
|
|
|
|
relic::Relic,
|
|
|
|
|
scene::{Position, Scene},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
|
|
|
pub struct FreesrData {
|
|
|
|
|
pub lightcones: Vec<Lightcone>,
|
|
|
|
|
pub relics: Vec<Relic>,
|
|
|
|
|
pub avatars: HashMap<u32, AvatarJson>,
|
|
|
|
|
#[serde(default)]
|
|
|
|
|
pub battle_config: BattleConfig,
|
2024-03-29 16:49:57 +07:00
|
|
|
|
2025-03-11 17:27:05 +07:00
|
|
|
// Non freesr-data.json fields
|
|
|
|
|
#[serde(skip_serializing, skip_deserializing)]
|
|
|
|
|
pub lineups: BTreeMap<u32, u32>,
|
|
|
|
|
#[serde(skip_serializing, skip_deserializing)]
|
|
|
|
|
pub position: Position,
|
|
|
|
|
#[serde(skip_serializing, skip_deserializing)]
|
|
|
|
|
pub scene: Scene,
|
|
|
|
|
#[serde(skip_serializing, skip_deserializing)]
|
|
|
|
|
pub main_character: MultiPathAvatar,
|
|
|
|
|
#[serde(skip_serializing, skip_deserializing)]
|
|
|
|
|
pub march_type: MultiPathAvatar,
|
2024-03-29 16:49:57 +07:00
|
|
|
}
|
|
|
|
|
|
2025-03-11 17:27:05 +07:00
|
|
|
impl FreesrData {
|
|
|
|
|
pub fn get_avatar_proto(&self, avatar_id: u32) -> Option<Avatar> {
|
|
|
|
|
let avatar = self.avatars.get(&avatar_id)?;
|
|
|
|
|
let lightcone = self.lightcones.iter().find(|l| l.equip_avatar == avatar_id);
|
2026-01-06 23:57:37 +07:00
|
|
|
Some(avatar.to_avatar_proto(lightcone))
|
2024-03-29 16:49:57 +07:00
|
|
|
}
|
|
|
|
|
|
2026-01-06 23:57:37 +07:00
|
|
|
pub fn get_avatar_path_data_proto(&self, avatar_id: u32) -> Option<AvatarPathData> {
|
2025-03-11 17:27:05 +07:00
|
|
|
let avatar = self.avatars.get(&avatar_id)?;
|
2024-03-29 23:32:32 +07:00
|
|
|
|
2026-01-06 23:57:37 +07:00
|
|
|
Some(
|
|
|
|
|
avatar.to_avatar_path_data_proto(
|
|
|
|
|
self.lightcones
|
|
|
|
|
.iter()
|
|
|
|
|
.find(|v| v.equip_avatar == avatar_id as u32),
|
|
|
|
|
self.relics
|
|
|
|
|
.iter()
|
|
|
|
|
.filter(|relic| relic.equip_avatar == avatar_id as u32)
|
|
|
|
|
.map(|relic| relic.into())
|
|
|
|
|
.collect(),
|
|
|
|
|
),
|
|
|
|
|
)
|
2024-03-29 16:49:57 +07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-27 19:41:36 +07:00
|
|
|
impl FreesrData {
|
2024-03-29 16:49:57 +07:00
|
|
|
pub async fn load() -> Self {
|
2025-03-11 17:27:05 +07:00
|
|
|
let mut freesr_data: FreesrData = tokio::fs::read_to_string("freesr-data.json")
|
2024-04-09 23:08:41 +07:00
|
|
|
.await
|
2024-05-09 22:14:27 +07:00
|
|
|
.map(|v| {
|
2024-06-27 19:41:36 +07:00
|
|
|
serde_json::from_str::<FreesrData>(&v)
|
2024-05-09 22:14:27 +07:00
|
|
|
.expect("freesr-data.json is broken, pls redownload")
|
|
|
|
|
})
|
|
|
|
|
.expect("failed to read freesr-data.json");
|
2024-04-09 23:08:41 +07:00
|
|
|
|
2025-03-11 17:27:05 +07:00
|
|
|
let persistent: Persistent = serde_json::from_str(
|
2024-04-09 23:08:41 +07:00
|
|
|
&tokio::fs::read_to_string("persistent")
|
|
|
|
|
.await
|
|
|
|
|
.unwrap_or_default(),
|
|
|
|
|
)
|
|
|
|
|
.unwrap_or_default();
|
2024-03-29 16:49:57 +07:00
|
|
|
|
2025-03-11 17:27:05 +07:00
|
|
|
freesr_data.lineups = persistent.lineups;
|
|
|
|
|
freesr_data.position = persistent.position;
|
|
|
|
|
freesr_data.scene = persistent.scene;
|
|
|
|
|
freesr_data.main_character = persistent.main_character;
|
|
|
|
|
freesr_data.march_type = persistent.march_type;
|
|
|
|
|
// freesr_data.game_language = persistent.game_language;
|
|
|
|
|
// freesr_data.voice_langauge = persistent.voice_language;
|
|
|
|
|
|
|
|
|
|
// remove unequipped lightcones
|
|
|
|
|
if freesr_data.lightcones.len() > 1500 {
|
|
|
|
|
freesr_data.lightcones.retain(|v| v.equip_avatar != 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// remove unequipped relics
|
|
|
|
|
if freesr_data.relics.len() > 2000 {
|
|
|
|
|
freesr_data.relics.retain(|v| v.equip_avatar != 0);
|
|
|
|
|
}
|
2024-03-29 16:49:57 +07:00
|
|
|
|
2025-03-11 17:27:05 +07:00
|
|
|
freesr_data.verify_lineup().await;
|
2024-03-29 18:36:02 +07:00
|
|
|
|
2025-03-11 17:27:05 +07:00
|
|
|
if freesr_data.march_type as u32 > 8000 {
|
|
|
|
|
freesr_data.march_type = MultiPathAvatar::MarchHunt;
|
2024-06-27 19:41:36 +07:00
|
|
|
}
|
|
|
|
|
|
2025-03-11 17:27:05 +07:00
|
|
|
freesr_data
|
2024-03-29 16:49:57 +07:00
|
|
|
}
|
|
|
|
|
|
2025-03-03 08:02:51 +07:00
|
|
|
pub async fn update(&mut self) {
|
|
|
|
|
*self = Self::load().await
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-29 18:36:02 +07:00
|
|
|
async fn verify_lineup(&mut self) {
|
2024-04-20 18:48:51 +07:00
|
|
|
if self.lineups.is_empty() {
|
2024-09-16 13:10:28 +07:00
|
|
|
self.lineups = BTreeMap::<u32, u32>::from([(0, 8001), (1, 0), (2, 0), (3, 0)])
|
2024-03-29 18:36:02 +07:00
|
|
|
} else if self.lineups.len() < 4 {
|
|
|
|
|
for i in self.lineups.len()..4 {
|
|
|
|
|
self.lineups.insert(i as u32, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-03 08:02:51 +07:00
|
|
|
self.save_persistent().await;
|
2024-03-29 16:49:57 +07:00
|
|
|
}
|
|
|
|
|
|
2025-03-03 08:02:51 +07:00
|
|
|
pub async fn save_persistent(&self) {
|
2024-04-09 23:08:41 +07:00
|
|
|
let _ = tokio::fs::write(
|
|
|
|
|
"persistent",
|
2024-06-27 19:41:36 +07:00
|
|
|
serde_json::to_string_pretty(&Persistent {
|
2024-04-09 23:08:41 +07:00
|
|
|
lineups: self.lineups.clone(),
|
|
|
|
|
main_character: self.main_character,
|
|
|
|
|
position: self.position.clone(),
|
|
|
|
|
scene: self.scene.clone(),
|
2024-06-27 19:41:36 +07:00
|
|
|
march_type: self.march_type,
|
2025-03-11 17:27:05 +07:00
|
|
|
// game_language: self.game_language,
|
|
|
|
|
// voice_language: self.voice_langauge,
|
2024-04-09 23:08:41 +07:00
|
|
|
})
|
2025-03-03 08:02:51 +07:00
|
|
|
.unwrap(),
|
2024-04-09 23:08:41 +07:00
|
|
|
)
|
|
|
|
|
.await;
|
2025-03-03 08:02:51 +07:00
|
|
|
tracing::info!("persistent saved");
|
2024-03-29 16:49:57 +07:00
|
|
|
}
|
2024-04-09 23:08:41 +07:00
|
|
|
}
|