1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
use crate::data::player::ACCOUNT_HASH_SALT;
use hex::encode;
use sha1::{Digest, Sha1};
use std::fmt::{Display, Formatter};
use std::hash::{Hash, Hasher};
use bincode::{Decode, Encode};
use serde::{Deserialize, Serialize};
use nogamepads::string_utils::process_id_text;
/// Player information
/// Describes a player's specific details, which are frequently exchanged between the controller and game pad_client.
#[derive(Default, Clone, Encode, Decode, Serialize, Deserialize, Debug)]
pub struct Player {
/// Account information
pub account: Account,
/// Custom information (Optional)
pub customize: Option<Customize>
}
/// Account information
/// Essential data for verifying player uniqueness, including the player's hash value and account ID.
#[derive(Default, Clone, Encode, Decode, Serialize, Deserialize, Eq, Hash, PartialEq, Debug)]
pub struct Account {
/// Player name stored in data, allowing only lowercase letters and underscores
pub id: String,
/// Player hash value proving player uniqueness
pub player_hash: String
}
/// Custom information
/// Describes personalized player details displayed in-game, such as name, color, or other customizations.
#[derive(Default, Clone, Encode, Decode, Serialize, Deserialize, PartialEq, Debug)]
pub struct Customize {
/// Player name displayed in the game
pub nickname: String,
/// HSV Color - Hue (Range: 0 - 360)
pub color_hue: i32,
/// HSV Color - Saturation (Range: 0 - 1)
pub color_saturation: f64,
/// HSV Color - Value (Range: 0 - 1)
pub color_value: f64
}
impl Player {
/// Create new player information using a username and password
pub fn register(id: String, password: String) -> Player {
let mut player = Player {
customize: None,
account: Account::default()
};
let processed_id = process_id_text(id);
player.account.id = processed_id.clone();
player.account.player_hash = Self::gen_hash(processed_id, password);
player
}
pub fn check(&self, password: String) -> bool {
let hash = Self::gen_hash(self.account.id.clone(), password);
hash == self.account.player_hash
}
fn gen_hash(processed_id: String, password: String) -> String {
let combined = format!("{}{}{}", processed_id, password, ACCOUNT_HASH_SALT);
let mut hasher = Sha1::new();
hasher.update(combined);
let result = hasher.finalize();
encode(&result[..])
}
}
// Customize implements
impl Player {
/// Set player nickname
pub fn nickname(&mut self, name: &String) -> &mut Player {
self.change(|custom| {
custom.nickname = name.clone();
custom
})
}
/// Set the hue of the player's color
pub fn hue(&mut self, mut hue: i32) -> &mut Player {
hue = hue.clamp(0, 360);
self.change(|custom| {
custom.color_hue = hue.clone();
custom
})
}
/// Set the player's HSV values
pub fn hsv(&mut self, mut hue: i32, mut saturation: f64, mut value: f64) -> &mut Player {
hue = hue.clamp(0, 360);
saturation = saturation.clamp(0.0, 1.0);
value = value.clamp(0.0, 1.0);
self.change(|custom| {
custom.color_hue = hue.clone();
custom.color_saturation = saturation.clone();
custom.color_value = value.clone();
custom
})
}
fn init(&mut self) {
if self.customize.is_none() {
self.customize = Some(Customize::default());
}
}
fn change<F>(&mut self, f: F) -> &mut Player
where F: FnOnce(&mut Customize) -> &mut Customize {
self.init();
let mut customize = self.customize.clone().unwrap();
f(&mut customize);
self.customize = Some(customize);
self
}
}
impl PartialEq for Player {
fn eq(&self, other: &Self) -> bool {
self.account == other.account
}
}
impl Hash for Player {
fn hash<H: Hasher>(&self, state: &mut H) {
self.account.hash(state);
}
}
impl Display for Player {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(self.account.id.as_str())
}
}
impl From<Account> for Player {
fn from(account: Account) -> Self {
Player {
account,
customize: None
}
}
}
impl Display for Account {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(self.id.as_str())
}
}
|