veloren_world/site/economy/
map_types.rs

1use crate::{
2    assets::{self, AssetExt},
3    util::map_array::{GenericIndex, NotFound, enum_from_index, index_from_enum},
4};
5use common::{terrain::BiomeKind, trade::Good};
6use lazy_static::lazy_static;
7use serde::{Deserialize, Serialize};
8use std::{
9    convert::{TryFrom, TryInto},
10    fmt,
11    marker::PhantomData,
12    ops::{Index, IndexMut},
13};
14
15use Good::*;
16
17// the opaque index type into the "map" of Goods
18#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
19pub struct GoodIndex {
20    idx: usize,
21}
22
23impl GenericIndex<Good, 24> for GoodIndex {
24    // static list of all Goods traded
25    const VALUES: [Good; GoodIndex::LENGTH] = [
26        // controlled resources
27        Territory(BiomeKind::Grassland),
28        Territory(BiomeKind::Forest),
29        Territory(BiomeKind::Lake),
30        Territory(BiomeKind::Ocean),
31        Territory(BiomeKind::Mountain),
32        RoadSecurity,
33        Ingredients,
34        // produced goods
35        Flour,
36        Meat,
37        Wood,
38        Stone,
39        Food,
40        Tools,
41        Armor,
42        Potions,
43        Transportation,
44        Recipe,
45        // exchange currency
46        Coin,
47        // uncontrolled resources
48        Terrain(BiomeKind::Lake),
49        Terrain(BiomeKind::Mountain),
50        Terrain(BiomeKind::Grassland),
51        Terrain(BiomeKind::Forest),
52        Terrain(BiomeKind::Desert),
53        Terrain(BiomeKind::Ocean),
54    ];
55
56    fn from_usize(idx: usize) -> Self { Self { idx } }
57
58    fn into_usize(self) -> usize { self.idx }
59}
60
61impl TryFrom<Good> for GoodIndex {
62    type Error = NotFound;
63
64    fn try_from(e: Good) -> Result<Self, NotFound> { index_from_enum(e) }
65}
66
67impl From<GoodIndex> for Good {
68    fn from(gi: GoodIndex) -> Good { enum_from_index(gi) }
69}
70
71impl fmt::Debug for GoodIndex {
72    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { GoodIndex::VALUES[self.idx].fmt(f) }
73}
74
75// the "map" itself
76#[derive(Copy, Clone)]
77pub struct GoodMap<V> {
78    data: [V; GoodIndex::LENGTH],
79}
80
81impl<V: Default + Copy> Default for GoodMap<V> {
82    fn default() -> Self {
83        GoodMap {
84            data: [V::default(); GoodIndex::LENGTH],
85        }
86    }
87}
88
89impl<V: Default + Copy + PartialEq + fmt::Debug> fmt::Debug for GoodMap<V> {
90    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91        f.debug_map()
92            .entries(
93                self.iter()
94                    .filter(|i| *i.1 != V::default())
95                    .map(|i| (Good::from(i.0), i.1)),
96            )
97            .finish()
98    }
99}
100
101impl<V> Index<GoodIndex> for GoodMap<V> {
102    type Output = V;
103
104    fn index(&self, index: GoodIndex) -> &Self::Output { &self.data[index.idx] }
105}
106
107impl<V> IndexMut<GoodIndex> for GoodMap<V> {
108    fn index_mut(&mut self, index: GoodIndex) -> &mut Self::Output { &mut self.data[index.idx] }
109}
110
111impl<V> GoodMap<V> {
112    pub fn iter(&self) -> impl Iterator<Item = (GoodIndex, &V)> + '_ {
113        self.data
114            .iter()
115            .enumerate()
116            .map(|(idx, v)| (GoodIndex { idx }, v))
117    }
118
119    pub fn iter_mut(&mut self) -> impl Iterator<Item = (GoodIndex, &mut V)> + '_ {
120        self.data
121            .iter_mut()
122            .enumerate()
123            .map(|(idx, v)| (GoodIndex { idx }, v))
124    }
125}
126
127impl<V: Copy> GoodMap<V> {
128    pub fn from_default(default: V) -> Self {
129        GoodMap {
130            data: [default; GoodIndex::LENGTH],
131        }
132    }
133
134    pub fn from_iter(i: impl Iterator<Item = (GoodIndex, V)>, default: V) -> Self {
135        let mut result = Self::from_default(default);
136        for j in i {
137            result.data[j.0.idx] = j.1;
138        }
139        result
140    }
141
142    pub fn map<U: Default + Copy>(self, mut f: impl FnMut(GoodIndex, V) -> U) -> GoodMap<U> {
143        let mut result = GoodMap::<U>::from_default(U::default());
144        for j in self.data.iter().enumerate() {
145            result.data[j.0] = f(GoodIndex::from_usize(j.0), *j.1);
146        }
147        result
148    }
149
150    pub fn from_list<'a>(i: impl IntoIterator<Item = &'a (GoodIndex, V)>, default: V) -> Self
151    where
152        V: 'a,
153    {
154        let mut result = Self::from_default(default);
155        for j in i {
156            result.data[j.0.idx] = j.1;
157        }
158        result
159    }
160}
161
162#[derive(Debug, Serialize, Deserialize)]
163struct RawProfession {
164    pub name: String,
165    pub orders: Vec<(Good, f32)>,
166    pub products: Vec<(Good, f32)>,
167}
168
169#[derive(Debug)]
170pub struct Profession {
171    pub name: String,
172    pub orders: Vec<(GoodIndex, f32)>,
173    pub products: (GoodIndex, f32),
174}
175
176// reference to profession
177#[derive(Clone, Copy, Eq, Hash, PartialEq)]
178pub struct Labor(u8, PhantomData<Profession>);
179
180// the opaque index type into the "map" of Labors (as Labor already contains a
181// monotonous index we reuse it)
182pub type LaborIndex = Labor;
183
184impl LaborIndex {
185    fn from_usize(idx: usize) -> Self { Self(idx as u8, PhantomData) }
186
187    fn into_usize(self) -> usize { self.0 as usize }
188}
189
190// the "map" itself
191#[derive(Clone)]
192pub struct LaborMap<V> {
193    data: Vec<V>,
194}
195
196impl<V: Default + Clone> Default for LaborMap<V> {
197    fn default() -> Self {
198        LaborMap {
199            data: std::iter::repeat_n(V::default(), *LABOR_COUNT).collect(),
200        }
201    }
202}
203
204impl<V: Default + Copy + PartialEq + fmt::Debug> fmt::Debug for LaborMap<V> {
205    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206        f.debug_map()
207            .entries(
208                self.iter()
209                    .filter(|i| *i.1 != V::default())
210                    .map(|i| (i.0, i.1)),
211            )
212            .finish()
213    }
214}
215
216impl<V> Index<LaborIndex> for LaborMap<V> {
217    type Output = V;
218
219    fn index(&self, index: LaborIndex) -> &Self::Output { &self.data[index.into_usize()] }
220}
221
222impl<V> IndexMut<LaborIndex> for LaborMap<V> {
223    fn index_mut(&mut self, index: LaborIndex) -> &mut Self::Output {
224        &mut self.data[index.into_usize()]
225    }
226}
227
228impl<V> LaborMap<V> {
229    pub fn iter(&self) -> impl Iterator<Item = (LaborIndex, &V)> + '_ {
230        self.data
231            .iter()
232            .enumerate()
233            .map(|(idx, v)| (LaborIndex::from_usize(idx), v))
234    }
235
236    pub fn iter_mut(&mut self) -> impl Iterator<Item = (LaborIndex, &mut V)> + '_ {
237        self.data
238            .iter_mut()
239            .enumerate()
240            .map(|(idx, v)| (LaborIndex::from_usize(idx), v))
241    }
242}
243
244impl<V: Copy + Default> LaborMap<V> {
245    pub fn from_default(default: V) -> Self {
246        LaborMap {
247            data: std::iter::repeat_n(default, *LABOR_COUNT).collect(),
248        }
249    }
250}
251
252impl<V: Copy + Default> LaborMap<V> {
253    pub fn from_iter(i: impl Iterator<Item = (LaborIndex, V)>, default: V) -> Self {
254        let mut result = Self::from_default(default);
255        for j in i {
256            result.data[j.0.into_usize()] = j.1;
257        }
258        result
259    }
260
261    pub fn map<U: Default + Copy>(&self, f: impl Fn(LaborIndex, &V) -> U) -> LaborMap<U> {
262        LaborMap {
263            data: self.iter().map(|i| f(i.0, i.1)).collect(),
264        }
265    }
266}
267
268#[derive(Debug, Default)]
269pub struct AreaResources {
270    pub resource_sum: GoodMap<f32>,
271    pub resource_chunks: GoodMap<f32>,
272    pub chunks: u32,
273}
274
275#[derive(Debug, Default)]
276pub struct NaturalResources {
277    // resources per distance, we should increase labor cost for far resources
278    pub per_area: Vec<AreaResources>,
279
280    // computation simplifying cached values
281    pub chunks_per_resource: GoodMap<f32>,
282    pub average_yield_per_chunk: GoodMap<f32>,
283}
284
285#[derive(Debug, Deserialize)]
286pub struct RawProfessions(Vec<RawProfession>);
287
288impl assets::Asset for RawProfessions {
289    type Loader = assets::RonLoader;
290
291    const EXTENSION: &'static str = "ron";
292}
293
294pub fn default_professions() -> Vec<Profession> {
295    RawProfessions::load_expect("common.professions")
296        .read()
297        .0
298        .iter()
299        .map(|r| Profession {
300            name: r.name.clone(),
301            orders: r
302                .orders
303                .iter()
304                .map(|i| (i.0.try_into().unwrap_or_default(), i.1))
305                .collect(),
306            products: r
307                .products
308                .first()
309                .map(|p| (p.0.try_into().unwrap_or_default(), p.1))
310                .unwrap_or_default(),
311        })
312        .collect()
313}
314
315lazy_static! {
316    static ref LABOR: Vec<Profession> = default_professions();
317    // used to define resources needed by every person
318    static ref DUMMY_LABOR: Labor = Labor(
319        LABOR
320            .iter()
321            .position(|a| a.name == "_")
322            .unwrap_or(0) as u8,
323        PhantomData
324    );
325    // do not count the DUMMY_LABOR (has to be last entry)
326    static ref LABOR_COUNT: usize = LABOR.len()-1;
327}
328
329impl fmt::Debug for Labor {
330    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
331        if (self.0 as usize) < *LABOR_COUNT {
332            f.write_str(&LABOR[self.0 as usize].name)
333        } else {
334            f.write_str("?")
335        }
336    }
337}
338
339impl Default for Labor {
340    fn default() -> Self { *DUMMY_LABOR }
341}
342
343impl Labor {
344    pub fn list() -> impl Iterator<Item = Self> {
345        (0..LABOR.len())
346            .filter(|&i| i != (DUMMY_LABOR.0 as usize))
347            .map(|i| Self(i as u8, PhantomData))
348    }
349
350    pub fn list_full() -> impl Iterator<Item = Self> {
351        (0..LABOR.len()).map(|i| Self(i as u8, PhantomData))
352    }
353
354    pub fn is_everyone(&self) -> bool { self.0 == DUMMY_LABOR.0 }
355
356    pub fn orders_everyone() -> impl Iterator<Item = &'static (GoodIndex, f32)> {
357        LABOR
358            .get(DUMMY_LABOR.0 as usize)
359            .map_or([].iter(), |l| l.orders.iter())
360    }
361
362    pub fn orders(&self) -> impl Iterator<Item = &'static (GoodIndex, f32)> + use<> {
363        LABOR
364            .get(self.0 as usize)
365            .map_or([].iter(), |l| l.orders.iter())
366    }
367
368    pub fn products(&self) -> (GoodIndex, f32) {
369        LABOR
370            .get(self.0 as usize)
371            .map_or((GoodIndex::default(), 0.0), |l| l.products)
372    }
373}