Merge pull request #5575 from horizon-rust/fix/commands-take-nicknames

🤖 Agent: players can /msg, /tell and /w a player by their nickname (shown as ~name); server guests included. SMP proof and pr_ready --quick passed on this head (comment above).
This commit is contained in:
Ludovic Marie authored and GitHub committed 2026-11-01 01:32:29 +01:00
commit 74698584ed
2 files changed
+41 -4

No files matched your search

@@ -61,7 +61,11 @@ impl Game<'_> {
.unwrap_or(Target::Player)
}
/// `PlayerList.getPlayerByName`: names are not case sensitive.
/// `PlayerList.getPlayerByName`: names are not case sensitive. Horizon:
/// on a server where a mod gave players nicknames
/// (`native_set_nickname`), a name no player has finds the player going
/// by it, without its `~` or with it (quoted), so `/msg` and `/tell`
/// reach a player by the name chat shows. No nickname, no change.
pub(super) fn player_named(&self, name: &str) -> Option<Target> {
if self.player.is_some() && name.eq_ignore_ascii_case(self.acting_player_name()) {
return Some(Target::Player);
@@ -69,6 +73,21 @@ impl Game<'_> {
self.command_players()
.find(|g| g.name.eq_ignore_ascii_case(name))
.map(|g| Target::Guest(g.conn))
.or_else(|| self.player_nicknamed(name))
}
/// The player whose nickname is `name` (any case, a leading `~` either
/// side ignored).
fn player_nicknamed(&self, name: &str) -> Option<Target> {
let bare = |s: &str| s.strip_prefix('~').unwrap_or(s).to_ascii_lowercase();
let wanted = bare(name);
let hub = &self.lan.as_ref()?.hub;
let uuid = hub
.nicknames
.iter()
.find(|(_, nick)| bare(nick) == wanted)?
.0;
self.target_by_uuid(*uuid)
}
/// `EntitySelector.findEntities` with a UUID: the player with it, else
+21 -3
View File
@@ -186,9 +186,27 @@ impl Game<'_> {
let targets: Vec<usize> = match (raw, &selector.player_name, selector.uuid) {
(Some("@s"), ..) => vec![i],
(Some("@a"), ..) => (0..guests.len()).filter(placed).collect(),
(_, Some(name), _) => (0..guests.len())
.filter(|&k| placed(&k) && guests[k].name.eq_ignore_ascii_case(name))
.collect(),
(_, Some(name), _) => {
let named: Vec<usize> = (0..guests.len())
.filter(|&k| placed(&k) && guests[k].name.eq_ignore_ascii_case(name))
.collect();
if named.is_empty() {
// No player has that name: the one going by it as a nickname (`~` optional).
let bare = |s: &str| s.strip_prefix('~').unwrap_or(s).to_ascii_lowercase();
let wanted = bare(name);
let nicknamed = |k: &usize| {
host.hub
.nicknames
.get(&guests[*k].uuid)
.is_some_and(|nick| bare(nick) == wanted)
};
(0..guests.len())
.filter(|k| placed(k) && nicknamed(k))
.collect()
} else {
named
}
}
(_, None, Some(uuid)) => (0..guests.len())
.filter(|&k| placed(&k) && guests[k].uuid == uuid)
.collect(),