Skip to main content

rkg_utils/header/location/
mod.rs

1use std::fmt::Display;
2
3use crate::header::location::constants::{Country, LocationFinder, Subregion, Version};
4
5pub mod constants;
6
7/// Represents a player's geographic location as recorded in the ghost file header,
8/// consisting of a country, subregion, and regions version.
9pub struct Location {
10    /// The country component of the location.
11    country: Country,
12    /// The subregion component of the location.
13    subregion: Subregion,
14    /// The region version associated with this location entry.
15    version: Version,
16}
17
18impl Location {
19    /// Returns the country component of this location.
20    pub fn country(&self) -> Country {
21        self.country
22    }
23
24    /// Returns the subregion component of this location.
25    pub fn subregion(&self) -> Subregion {
26        self.subregion
27    }
28
29    /// Returns the region version associated with this location.
30    pub fn version(&self) -> Version {
31        self.version
32    }
33
34    /// Looks up a [`Location`] by country ID, subregion ID, and optional region version.
35    ///
36    /// If `version` is `None`, the lookup may return an adjusted match (i.e. the
37    /// closest valid location). Both exact and adjusted matches are returned as `Some`.
38    ///
39    /// Returns `None` if no matching location can be found.
40    ///
41    /// # Arguments
42    ///
43    /// * `country_id` - The numeric country identifier.
44    /// * `subregion_id` - The numeric subregion identifier.
45    /// * `version` - An optional region version to constrain the lookup.
46    pub fn find(country_id: u8, subregion_id: u8, version: Option<Version>) -> Option<Location> {
47        match LocationFinder::find(country_id, subregion_id, version) {
48            LocationFinder::None => None,
49            LocationFinder::Exact(v) | LocationFinder::Adjusted(v) => Some(v),
50        }
51    }
52
53    /// Looks up a [`Location`] by country ID, subregion ID, and exact version.
54    ///
55    /// Unlike [`Location::find`], this only returns `Some` when the lookup produces
56    /// an exact match. Adjusted matches and missing entries both return `None`.
57    ///
58    /// # Arguments
59    ///
60    /// * `country_id` - The numeric country identifier.
61    /// * `subregion_id` - The numeric subregion identifier.
62    /// * `version` - The region version that must match exactly.
63    pub fn find_exact(country_id: u8, subregion_id: u8, version: Version) -> Option<Location> {
64        match LocationFinder::find(country_id, subregion_id, Some(version)) {
65            LocationFinder::None | LocationFinder::Adjusted(_) => None,
66            LocationFinder::Exact(v) => Some(v),
67        }
68    }
69
70    /// Returns a new [`Location`] with the same country and subregion but a different version.
71    ///
72    /// Returns `None` if no exact location entry exists for this country/subregion
73    /// combination under the requested version.
74    ///
75    /// # Arguments
76    ///
77    /// * `version` - The new region version to look up for this location's country ID and subregion ID.
78    pub fn change_version(&self, version: Version) -> Option<Self> {
79        Self::find_exact(self.country.into(), self.subregion.into(), version)
80    }
81}
82
83impl Default for Location {
84    fn default() -> Self {
85        Location {
86            country: Country::NotSet,
87            subregion: Subregion::NotSet,
88            version: Version::Vanilla,
89        }
90    }
91}
92
93impl Display for Version {
94    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95        write!(
96            f,
97            "{}",
98            match self {
99                Version::Vanilla => "Vanilla",
100                Version::ER10 => "Extended Regions 1.0",
101                Version::ER11 => "Extended Regions 1.1",
102                Version::ER12 => "Extended Regions 1.2",
103                Version::ER13 => "Extended Regions 1.3",
104            }
105        )
106    }
107}