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}