steel_core/player/advancement/
visibility_evaluator.rs1use crate::player::advancement::PlayerAdvancement;
2use steel_registry::REGISTRY;
3use steel_registry::advancement::registry::{AdvancementNodeRef, AdvancementRef};
4
5static VISIBILITY_DEPTH: usize = 3;
6
7fn evaluate_visibility_rule(advancement: AdvancementRef, is_done: bool) -> VisibilityRule {
8 let display = advancement.display();
9 display.map_or(VisibilityRule::Hide, |display| {
10 if is_done {
11 VisibilityRule::Show
12 } else if display.hidden {
13 VisibilityRule::Hide
14 } else {
15 VisibilityRule::NoChange
16 }
17 })
18}
19
20fn evaluate_visibility_for_unfinished_node(ascendants: &[VisibilityRule]) -> bool {
22 for visibility in ascendants.iter().rev().take(VISIBILITY_DEPTH) {
23 match visibility {
24 VisibilityRule::Show => return true,
25 VisibilityRule::Hide => return false,
26 VisibilityRule::NoChange => {}
27 }
28 }
29 false
30}
31
32pub(super) fn evaluate_visibility_with_rules(
46 node: AdvancementNodeRef,
47 player_advancement: &mut PlayerAdvancement,
48 ascendants: &mut Vec<VisibilityRule>,
49 is_done_test: &mut impl FnMut(&mut PlayerAdvancement, AdvancementNodeRef) -> bool,
50 output: &mut impl FnMut(&mut PlayerAdvancement, AdvancementNodeRef, bool),
51) -> bool {
52 let tree = REGISTRY.advancements.nodes();
53 let is_self_done = is_done_test(player_advancement, node);
54 let descendant_visibility = evaluate_visibility_rule(node.value(), is_self_done);
55 let mut is_self_or_descendant_done = is_self_done;
56 ascendants.push(descendant_visibility);
57
58 for child in node.children() {
59 is_self_or_descendant_done |= evaluate_visibility_with_rules(
60 &tree[child],
61 player_advancement,
62 ascendants,
63 is_done_test,
64 output,
65 );
66 }
67
68 let visibility =
69 is_self_or_descendant_done || evaluate_visibility_for_unfinished_node(ascendants);
70 ascendants.pop();
71 output(player_advancement, node, visibility);
72 is_self_or_descendant_done
73}
74
75pub(crate) fn evaluate_visibility(
76 node: AdvancementNodeRef,
77 player_advancement: &mut PlayerAdvancement,
78 is_done: &mut impl FnMut(&mut PlayerAdvancement, AdvancementNodeRef) -> bool,
79 output: &mut impl FnMut(&mut PlayerAdvancement, AdvancementNodeRef, bool),
80) -> bool {
81 let root = REGISTRY.advancements.root(node);
82 let mut visibility_stack: Vec<VisibilityRule> = Vec::new();
83 evaluate_visibility_with_rules(
84 root,
85 player_advancement,
86 &mut visibility_stack,
87 is_done,
88 output,
89 )
90}
91
92#[derive(PartialEq, Eq, Copy, Clone)]
93pub(super) enum VisibilityRule {
94 Show,
95 Hide,
96 NoChange,
97}