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
//! The game's account actions: kick, ban and unban by account.
use crate::PlayerKey;
use crate::abi::AccountActionType;
use super::{World, WorldError};
/// What the game does to an account, as its account actions name it.
///
/// # Examples
///
/// See [`World::account_action`].
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum AccountAction {
/// Removes a player online from the game.
Kick,
/// Puts the account on the server's ban list, online or not, and
/// removes its player when online.
Ban,
/// Takes the account off the server's ban list.
UnBan,
}
impl AccountAction {
const fn abi(self) -> AccountActionType {
match self {
Self::Kick => AccountActionType::KICK,
Self::Ban => AccountActionType::BAN,
Self::UnBan => AccountActionType::UN_BAN,
}
}
}
impl World {
/// Asks the game to kick, ban or unban the account `key`, as its
/// administrators do; the mod decides who may ask. A ban of an account
/// not online goes straight onto the ban list, which a dedicated server
/// keeps in `bannedAccounts` of `enshrouded_server.json`; a hosted
/// game keeps it until it ends.
///
/// # Errors
///
/// [`WorldError::Refused`] for a kick or a ban of an administrator
/// online, whom the game never removes, or of a hosted game's host, a
/// kick of an account not online, a ban the game's list does not take
/// and account 0; [`WorldError::WrongThread`] off the server's game
/// thread or inside a step; [`WorldError::Missing`] while no server
/// runs or on a game build that lacks the action.
///
/// # Examples
///
/// ```
/// use enshwick::world::{AccountAction, World};
///
/// fn ban_for_cheating(world: &World, key: enshwick::PlayerKey) {
/// if let Err(why) = world.account_action(AccountAction::Ban, key) {
/// enshwick::warn!("no ban for {key:016x}: {why}");
/// }
/// }
/// ```
pub fn account_action(self, action: AccountAction, key: PlayerKey) -> Result<(), WorldError> {
WorldError::from_status((self.0.host.api().account_action)(
self.0.host.handle(),
action.abi(),
key,
))
}
/// Puts the account `key` on the loader's allowlist, or takes it off
/// when `listed` is false. With the server's `allowlist` setting on,
/// only listed accounts and administrators may join; the list keeps
/// its accounts with the setting off too, and a change applies from
/// the next join. Any thread.
///
/// # Errors
///
/// [`WorldError::Refused`] for account 0 or when the list's file is
/// not written; [`WorldError::Missing`] outside a dedicated server.
///
/// # Examples
///
/// ```
/// use enshwick::world::World;
///
/// fn let_in(world: &World, key: enshwick::PlayerKey) {
/// if let Err(why) = world.set_allowlisted(key, true) {
/// enshwick::warn!("{key:016x} not listed: {why}");
/// }
/// }
/// ```
pub fn set_allowlisted(self, key: PlayerKey, listed: bool) -> Result<(), WorldError> {
WorldError::from_status((self.0.host.api().allowlist_set)(
self.0.host.handle(),
key,
u8::from(listed),
))
}
/// Whether the loader's allowlist lists the account `key`, the
/// server's `allowlist` setting on or not. Any thread.
///
/// # Errors
///
/// [`WorldError::Refused`] for account 0; [`WorldError::Missing`]
/// outside a dedicated server.
///
/// # Examples
///
/// ```
/// use enshwick::world::World;
///
/// fn may_join(world: &World, key: enshwick::PlayerKey) -> bool {
/// world.allowlisted(key).unwrap_or(false)
/// }
/// ```
pub fn allowlisted(self, key: PlayerKey) -> Result<bool, WorldError> {
let mut listed = 0u8;
WorldError::from_status((self.0.host.api().allowlist_has)(
self.0.host.handle(),
key,
&raw mut listed,
))?;
Ok(listed == 1)
}
}