scroll.server/crates/game-service/src/home.rs
WiseDev ad5a1613e3 move players and accounts into postgres
json stores are gone, they nulled out every data ref on load and wrote the null straight back on save.
shop json and the purchase commands ended up in here too.
2026-08-23 08:40:13 +03:00

142 lines
5.1 KiB
Rust

use logic::model::{
LogicChest, LogicClientAvatar, LogicClientHome, LogicCommodityStore, LogicDataSlot, LogicSpell,
LogicSpellCollection, LogicSpellDeck, LogicTimer,
};
use titan::LogicLong;
use logic::data::RESOURCE_GOLD;
use logic::{table, LogicDataRef};
use crate::catalog::GOLD_RESOURCE_FALLBACK_INSTANCE;
use crate::store::{OwnedCard, PlayerProfile, StoredChest};
pub const COMMODITY_RESOURCES: usize = 0;
fn spell_of(owned: &OwnedCard) -> LogicSpell {
LogicSpell {
data: owned.card.clone(),
level_index: owned.level_index,
create_time: 0,
count: owned.count,
new_count: 0,
recent_use_count: 0,
new_upgrade_available: false,
show_new_icon: false,
}
}
fn chest_of(stored: &StoredChest) -> LogicChest {
LogicChest {
data: stored.chest.clone(),
unlocked: stored.unlocked,
claimed: stored.claimed,
is_new: false,
unlock_timer: (stored.remaining_ticks > 0).then_some(LogicTimer {
remaining_ticks: stored.remaining_ticks,
total_ticks: stored.total_ticks,
end_timestamp: stored.end_timestamp,
}),
chest_id: stored.chest_id,
source: stored.source,
slot_index: stored.slot_index,
}
}
fn chest_slots(profile: &PlayerProfile) -> Vec<Option<LogicChest>> {
let mut slots = vec![None; profile.chest_slot_count];
for stored in &profile.chests {
let Ok(index) = usize::try_from(stored.slot_index) else {
continue;
};
if index < slots.len() {
slots[index] = Some(chest_of(stored));
}
}
slots
}
pub fn build_home(profile: &PlayerProfile) -> LogicClientHome {
let deck = LogicSpellDeck::from_cards(profile.deck.iter().map(spell_of));
let collection =
LogicSpellCollection::from_spells(profile.collection.iter().map(spell_of).collect());
let mut home = LogicClientHome {
home_id: LogicLong::new(profile.account.high, profile.account.low),
chest_id_counter: profile.chest_id_counter,
free_chest_collect_count: profile.free_chest_collect_count,
donation_capacity_limit_timer: LogicTimer::idle(),
donated_capacity: 0,
decks: vec![deck],
spell_collection: collection,
selected_deck_index: 0,
chest_slots: chest_slots(profile),
free_chest_timer: LogicTimer::idle(),
donation_cooldown_timer: LogicTimer::idle(),
free_chest: None,
purchased_chest: None,
crowns_towards_crown_chest: profile.crowns_towards_crown_chest,
star_chest_timer_pending: false,
star_chest_timer: LogicTimer::idle(),
crown_chest: None,
request_spells_cooldown_timer: LogicTimer::idle(),
finished_tutorials: [0; 8],
opened_pages: 0,
last_shown_level_up: profile.exp_level,
arena: profile.arena.clone(),
shop_seed: -1,
shop_weekday_index: -1,
shop_weekday_index_seen: -1,
shop_timer: LogicTimer::idle(),
shop_spells: Vec::new(),
share_replay_cooldown_timer: LogicTimer::idle(),
send_team_mail_cooldown_timer: LogicTimer::idle(),
free_chest_diamond_index: 0,
crown_chest_diamond_index: 0,
card_usage_stats_battle_count: profile.battle_count,
royal_tv_replay_version_major: 0,
royal_tv_replay_version_build: 0,
royal_tv_replay_version_content: 0,
seen_replay_ids: Vec::new(),
card_request_message: None,
requested_cards: Vec::new(),
};
if profile.tutorials_finished {
home.finish_all_tutorials();
}
home
}
fn gold_resource(profile: &PlayerProfile) -> LogicDataRef {
if !profile.gold_resource.is_none() {
return profile.gold_resource.clone();
}
let by_name = LogicDataRef::by_name(table::RESOURCES, RESOURCE_GOLD);
if !by_name.is_none() {
return by_name;
}
LogicDataRef::of(table::RESOURCES, GOLD_RESOURCE_FALLBACK_INSTANCE)
}
pub fn build_avatar(profile: &PlayerProfile) -> LogicClientAvatar {
let account = LogicLong::new(profile.account.high, profile.account.low);
let mut commodities = LogicCommodityStore::default();
commodities.set(
COMMODITY_RESOURCES,
vec![LogicDataSlot::new(gold_resource(profile), profile.gold)],
);
LogicClientAvatar {
avatar_id: account,
account_id: account,
home_id: account,
name: profile.name.clone(),
name_set_by_user: profile.name_set_by_user,
name_change_state: -1,
arena: profile.arena.clone(),
score: profile.trophies,
legacy_flag: false,
commodities,
diamonds: profile.diamonds,
free_diamonds: profile.free_diamonds,
exp_points: profile.exp_points,
exp_level: profile.exp_level,
cumulative_purchased_diamonds: 0,
alliance: None,
battle_count: profile.battle_count,
win_count: profile.win_count,
lose_count: profile.lose_count,
win_loose_streak: 0,
npc_win_count: profile.npc_win_count,
npc_lose_count: profile.npc_lose_count,
arena_before_last_npc_match: profile.arena.instance_id().unwrap_or(0) != 0,
}
}