veloren_world/
index.rs

1use crate::{
2    Colors, Features,
3    layer::wildlife::{self, DensityFn, SpawnEntry},
4    site::{Site, economy::TradeInformation},
5};
6use common::{
7    assets::{AssetExt, AssetHandle},
8    store::Store,
9    trade::{SiteId, SitePrices},
10};
11use core::ops::Deref;
12use noise::{Fbm, MultiFractal, Perlin, SuperSimplex};
13use std::sync::Arc;
14
15const WORLD_COLORS_MANIFEST: &str = "world.style.colors";
16const WORLD_FEATURES_MANIFEST: &str = "world.features";
17
18pub struct Index {
19    pub seed: u32,
20    pub time: f32,
21    pub noise: Noise,
22    pub sites: Store<Site>,
23    pub trade: TradeInformation,
24    pub wildlife_spawns: Vec<(AssetHandle<SpawnEntry>, DensityFn)>,
25    colors: AssetHandle<Arc<Colors>>,
26    features: AssetHandle<Arc<Features>>,
27}
28
29/// An owned reference to indexed data.
30///
31/// The data are split out so that we can replace the colors without disturbing
32/// the rest of the index, while also keeping all the data within a single
33/// indirection.
34#[derive(Clone)]
35pub struct IndexOwned {
36    colors: Arc<Colors>,
37    features: Arc<Features>,
38    index: Arc<Index>,
39}
40
41impl Deref for IndexOwned {
42    type Target = Index;
43
44    fn deref(&self) -> &Self::Target { &self.index }
45}
46
47/// A shared reference to indexed data.
48///
49/// This is copyable and can be used from either style of index.
50#[derive(Clone, Copy)]
51pub struct IndexRef<'a> {
52    pub colors: &'a Colors,
53    pub features: &'a Features,
54    pub index: &'a Index,
55}
56
57impl Deref for IndexRef<'_> {
58    type Target = Index;
59
60    fn deref(&self) -> &Self::Target { self.index }
61}
62
63impl Index {
64    /// NOTE: Panics if the color manifest cannot be loaded.
65    pub fn new(seed: u32) -> Self {
66        let colors = Arc::<Colors>::load_expect(WORLD_COLORS_MANIFEST);
67        let features = Arc::<Features>::load_expect(WORLD_FEATURES_MANIFEST);
68        let wildlife_spawns = wildlife::spawn_manifest()
69            .into_iter()
70            .map(|(e, f)| (SpawnEntry::load_expect(e), f))
71            .collect();
72
73        Self {
74            seed,
75            time: 0.0,
76            noise: Noise::new(seed),
77            sites: Store::default(),
78            trade: Default::default(),
79            wildlife_spawns,
80            colors,
81            features,
82        }
83    }
84
85    pub fn colors(&self) -> impl Deref<Target = Arc<Colors>> + '_ { self.colors.read() }
86
87    pub fn features(&self) -> impl Deref<Target = Arc<Features>> + '_ { self.features.read() }
88
89    pub fn get_site_prices(&self, site_id: SiteId) -> Option<SitePrices> {
90        self.sites
91            .recreate_id(site_id)
92            .map(|i| self.sites.get(i))
93            .and_then(|s| s.economy.as_ref())
94            .map(|econ| econ.get_site_prices())
95    }
96}
97
98impl IndexOwned {
99    pub fn new(index: Index) -> Self {
100        let colors = index.colors.cloned();
101        let features = index.features.cloned();
102
103        Self {
104            index: Arc::new(index),
105            colors,
106            features,
107        }
108    }
109
110    /// NOTE: Callback is called only when colors actually have to be reloaded.
111    /// The server is responsible for making sure that all affected chunks are
112    /// reloaded; a naive approach will just regenerate every chunk on the
113    /// server, but it is possible that eventually we can find a better
114    /// solution.
115    ///
116    /// Ideally, this should be called about once per tick.
117    pub fn reload_if_changed<R>(&mut self, reload: impl FnOnce(&mut Self) -> R) -> Option<R> {
118        let reloaded = self.index.colors.reloaded_global() || self.index.features.reloaded_global();
119        reloaded.then(move || {
120            // Reload the fields from the asset handle, which is updated automatically
121            self.colors = self.index.colors.cloned();
122            self.features = self.index.features.cloned();
123            // Update wildlife spawns which is based on base_density in features
124            reload(self)
125        })
126    }
127
128    pub fn as_index_ref(&self) -> IndexRef {
129        IndexRef {
130            colors: &self.colors,
131            features: &self.features,
132            index: &self.index,
133        }
134    }
135}
136
137pub struct Noise {
138    pub cave_nz: SuperSimplex,
139    pub scatter_nz: SuperSimplex,
140    pub cave_fbm_nz: Fbm<Perlin>,
141}
142
143impl Noise {
144    fn new(seed: u32) -> Self {
145        Self {
146            cave_nz: SuperSimplex::new(seed + 0),
147            scatter_nz: SuperSimplex::new(seed + 1),
148            cave_fbm_nz: Fbm::new(seed + 2).set_octaves(5),
149        }
150    }
151}