Skip to content

Commit 67012b6

Browse files
committed
feat: nicknames_must_be_unique
1 parent bb6e42b commit 67012b6

7 files changed

Lines changed: 44 additions & 10 deletions

File tree

docs/Config-Documentation.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ The config file can be found at `config/EssentialCommands.properties`
6666
| nickname_prefix | {"text":"~","color":"red"} | MinecraftText |
6767
| nicknames_as_command_arg | Never | NicknameCommandArgMode |
6868
| nicknames_in_player_list | true | boolean |
69+
| nicknames_must_be_unique | false | boolean |
6970
| ops_bypass_teleport_rules | true | boolean |
7071
| persist_back_location | false | boolean |
7172
| print_teleport_coordinates | true | boolean |

docs/Feature-Guide.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ Customize player display names.
216216
- `Never` - Nicknames are not resolved in any command argument
217217
- `EssentialCommandsOnly` - Nicknames resolve and suggest only in Essential Commands
218218
- `Everywhere` - Nicknames resolve and suggest in all commands (e.g. `/tp`, `/give`)
219+
- `nicknames_must_be_unique` - Block nicknames that duplicate another player's nickname or match an existing username (case-insensitive) - Default: `false`
219220

220221
## Utility Commands
221222

src/main/java/com/fibermc/essentialcommands/commands/NicknameSetCommand.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ public static int exec(CommandContext<CommandSourceStack> context, Component raw
7474
ecText.accent(String.valueOf(nicknameText.getString().length())),
7575
ecText.accent(String.valueOf(CONFIG.NICKNAME_MAX_LENGTH))
7676
);
77+
case -3 -> ecText.getText(
78+
"cmd.nickname.set.error.taken", TextFormatType.Error,
79+
ecText.accent(nicknameText.getString())
80+
);
7781
default -> ecText.getText("generic.error.unknown", TextFormatType.Error);
7882
};
7983
senderFeedbackReceiver.sendCommandError("cmd.nickname.set.error", nicknameText, failReason);

src/main/java/com/fibermc/essentialcommands/config/EssentialCommandsConfig.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,7 @@
66
import java.util.List;
77
import java.util.Set;
88
import java.util.stream.Collectors;
9-
import net.minecraft.ChatFormatting;
10-
import net.minecraft.network.chat.Component;
11-
import net.minecraft.network.chat.Style;
12-
import net.minecraft.resources.Identifier;
13-
import net.minecraft.resources.ResourceKey;
14-
import net.minecraft.world.level.Level;
9+
1510
import com.fibermc.essentialcommands.ECPerms;
1611
import com.fibermc.essentialcommands.EssentialCommands;
1712
import com.fibermc.essentialcommands.ManagerLocator;
@@ -20,6 +15,14 @@
2015
import com.fibermc.essentialcommands.types.RespawnCondition;
2116
import com.fibermc.essentialcommands.types.RtpCenter;
2217
import org.jetbrains.annotations.NotNull;
18+
19+
import net.minecraft.ChatFormatting;
20+
import net.minecraft.network.chat.Component;
21+
import net.minecraft.network.chat.Style;
22+
import net.minecraft.resources.Identifier;
23+
import net.minecraft.resources.ResourceKey;
24+
import net.minecraft.world.level.Level;
25+
2326
import dev.jpcode.eccore.config.Config;
2427
import dev.jpcode.eccore.config.ConfigOption;
2528
import dev.jpcode.eccore.config.ConfigUtil;
@@ -87,6 +90,7 @@ public final class EssentialCommandsConfig extends Config<EssentialCommandsConfi
8790
@ConfigOption public final Option<Boolean> NICKNAMES_IN_PLAYER_LIST = new Option<>("nicknames_in_player_list", true, Boolean::parseBoolean);
8891
@ConfigOption public final Option<Integer> NICKNAME_MAX_LENGTH = new Option<>("nickname_max_length", 32, ConfigUtil::parseInt);
8992
@ConfigOption public final Option<NicknameCommandArgMode> NICKNAMES_AS_COMMAND_ARG = new Option<>("nicknames_as_command_arg", NicknameCommandArgMode.Never, NicknameCommandArgMode::valueOf);
93+
@ConfigOption public final Option<Boolean> NICKNAMES_MUST_BE_UNIQUE = new Option<>("nicknames_must_be_unique", false, Boolean::parseBoolean);
9094
@ConfigOption public final Option<Boolean> NICKNAME_ABOVE_HEAD = new Option<>("nickname_above_head", false, Boolean::parseBoolean);
9195
@ConfigOption public final Option<RtpCenter> RTP_CENTER = new Option<>("rtp_center", RtpCenter.spawn(), RtpCenter::parse, RtpCenter::serialize);
9296
@ConfigOption public final Option<Integer> RTP_RADIUS = new Option<>("rtp_radius", 1000, ConfigUtil::parseInt);

src/main/java/com/fibermc/essentialcommands/config/EssentialCommandsConfigSnapshot.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22

33
import java.util.List;
44
import java.util.Set;
5+
6+
import com.fibermc.essentialcommands.types.NicknameCommandArgMode;
7+
import com.fibermc.essentialcommands.types.RespawnCondition;
8+
import com.fibermc.essentialcommands.types.RtpCenter;
9+
510
import net.minecraft.network.chat.Component;
611
import net.minecraft.network.chat.Style;
712
import net.minecraft.resources.ResourceKey;
813
import net.minecraft.world.level.Level;
9-
import com.fibermc.essentialcommands.types.NicknameCommandArgMode;
10-
import com.fibermc.essentialcommands.types.RespawnCondition;
11-
import com.fibermc.essentialcommands.types.RtpCenter;
14+
1215
import dev.jpcode.eccore.config.expression.Expression;
1316
import dev.jpcode.eccore.util.TimeUtil;
1417

@@ -66,6 +69,7 @@ public final class EssentialCommandsConfigSnapshot {
6669
public final boolean NICKNAMES_IN_PLAYER_LIST;
6770
public final int NICKNAME_MAX_LENGTH;
6871
public final NicknameCommandArgMode NICKNAMES_AS_COMMAND_ARG;
72+
public final boolean NICKNAMES_MUST_BE_UNIQUE;
6973
public final boolean NICKNAME_ABOVE_HEAD;
7074
public final RtpCenter RTP_CENTER;
7175
public final int RTP_RADIUS;
@@ -146,6 +150,7 @@ private EssentialCommandsConfigSnapshot(EssentialCommandsConfig config) {
146150
this.NICKNAMES_IN_PLAYER_LIST = config.NICKNAMES_IN_PLAYER_LIST.getValue();
147151
this.NICKNAME_MAX_LENGTH = config.NICKNAME_MAX_LENGTH.getValue();
148152
this.NICKNAMES_AS_COMMAND_ARG = config.NICKNAMES_AS_COMMAND_ARG.getValue();
153+
this.NICKNAMES_MUST_BE_UNIQUE = config.NICKNAMES_MUST_BE_UNIQUE.getValue();
149154
this.NICKNAME_ABOVE_HEAD = config.NICKNAME_ABOVE_HEAD.getValue();
150155
this.RTP_CENTER = config.RTP_CENTER.getValue();
151156
this.RTP_RADIUS = config.RTP_RADIUS.getValue();

src/main/java/com/fibermc/essentialcommands/playerdata/PlayerData.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -547,9 +547,27 @@ public int setNickname(Component nickname) {
547547
);
548548
}
549549

550+
String candidateNormalized = normalizeNickname(nickname.getString());
551+
552+
if (CONFIG.NICKNAMES_MUST_BE_UNIQUE) {
553+
List<PlayerData> existing = PlayerDataManager.getInstance().getByNickname(candidateNormalized);
554+
boolean takenByOther = existing.stream().anyMatch(pd -> pd != this);
555+
if (takenByOther) {
556+
return -3;
557+
}
558+
559+
var nameCache = this.player.level().getServer().services().nameToIdCache();
560+
boolean matchesOtherUsername = nameCache.get(candidateNormalized)
561+
.filter(profile -> !profile.id().equals(this.player.getUUID()))
562+
.isPresent();
563+
if (matchesOtherUsername) {
564+
return -3;
565+
}
566+
}
567+
550568
// Set nickname
551569
this.nickname = nickname;
552-
this.normalizedNickname = normalizeNickname(nickname.getString());
570+
this.normalizedNickname = candidateNormalized;
553571
}
554572

555573
reloadFullNickname();

src/main/resources/data/essential_commands/lang/en_us.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"cmd.nickname.set.error": "Nickname could not be set to '%1$s'. Reason: %2$s",
2525
"cmd.nickname.set.error.perms": "Player has insufficient permissions for specified nickname.",
2626
"cmd.nickname.set.error.length": "Length of supplied nickname (%1$s) exceeded max nickname length (%2$s)",
27+
"cmd.nickname.set.error.taken": "The nickname ('%1$s') is already in use or conflicts with an existing username.",
2728
"cmd.rtp.error.pre": "Could not execute command '/rtp'. Reason: ",
2829
"cmd.rtp.error.world_not_enabled": "RTP is not enabled in the world '%1$s'",
2930
"cmd.rtp.error.cooldown": "Command is on cooldown. (%1$s seconds remaining.)",

0 commit comments

Comments
 (0)