Skip to content

1.18/dev #36

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

[1802.1.11]

### Fixed
* Backed out dynamic tab-completion functionality and use simple server-side suggestions instead
* FTB Ranks is a server-only mod again and no longer needs to be installed on the client since that's unnecessarily disruptive

[1802.1.10]

### Fixed
Expand Down
2 changes: 0 additions & 2 deletions common/src/main/java/dev/ftb/mods/ftbranks/FTBRanks.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,5 @@ public FTBRanks() {
CommandRegistrationEvent.EVENT.register(FTBRanksCommands::register);
// TODO: Register with LOWEST priority on forge
ChatEvent.SERVER.register(FTBRanksAPIImpl::serverChat);

ArgumentTypes.register("ftbranks:rank", RankArgumentType.class, new RankArgumentType.Serializer());
}
}
124 changes: 75 additions & 49 deletions common/src/main/java/dev/ftb/mods/ftbranks/FTBRanksCommands.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import dev.ftb.mods.ftblibrary.snbt.SNBT;
import dev.ftb.mods.ftbranks.api.FTBRanksAPI;
import dev.ftb.mods.ftbranks.api.PermissionValue;
Expand All @@ -18,24 +21,26 @@
import net.minecraft.ChatFormatting;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.commands.SharedSuggestionProvider;
import net.minecraft.commands.arguments.EntityArgument;
import net.minecraft.commands.arguments.GameProfileArgument;
import net.minecraft.nbt.StringTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.server.level.ServerPlayer;
import org.apache.commons.lang3.math.NumberUtils;

import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.CompletableFuture;

/**
* @author LatvianModder
*/
public class FTBRanksCommands {
public static final DynamicCommandExceptionType ERROR_UNKNOWN_RANK = new DynamicCommandExceptionType((object) -> new TextComponent("Unknown rank: " + object.toString()));

public static void register(CommandDispatcher<CommandSourceStack> dispatcher, Commands.CommandSelection selection) {
dispatcher.register(Commands.literal("ftbranks")
.requires(source -> source.getServer().isSingleplayer() || source.hasPermission(2))
Expand All @@ -54,21 +59,24 @@ public static void register(CommandDispatcher<CommandSourceStack> dispatcher, Co
)
)
.then(Commands.literal("delete")
.then(Commands.argument("rank", RankArgumentType.rank())
.executes(context -> deleteRank(context.getSource(), RankArgumentType.getRank(context, "rank")))
.then(Commands.argument("rank", StringArgumentType.word())
.suggests((context, builder) -> suggestRanks(builder))
.executes(context -> deleteRank(context.getSource(), StringArgumentType.getString(context, "rank")))
)
)
.then(Commands.literal("add")
.then(Commands.argument("players", GameProfileArgument.gameProfile())
.then(Commands.argument("rank", RankArgumentType.rank())
.executes(context -> addRank(context.getSource(), GameProfileArgument.getGameProfiles(context, "players"), RankArgumentType.getRank(context, "rank")))
.then(Commands.argument("rank", StringArgumentType.word())
.suggests((context, builder) -> suggestRanks(builder))
.executes(context -> addRank(context.getSource(), GameProfileArgument.getGameProfiles(context, "players"), StringArgumentType.getString(context, "rank")))
)
)
)
.then(Commands.literal("remove")
.then(Commands.argument("players", GameProfileArgument.gameProfile())
.then(Commands.argument("rank", RankArgumentType.rank())
.executes(context -> removeRank(context.getSource(), GameProfileArgument.getGameProfiles(context, "players"), RankArgumentType.getRank(context, "rank")))
.then(Commands.argument("rank", StringArgumentType.word())
.suggests((context, builder) -> suggestRanks(builder))
.executes(context -> removeRank(context.getSource(), GameProfileArgument.getGameProfiles(context, "players"), StringArgumentType.getString(context, "rank")))
)
)
)
Expand All @@ -78,51 +86,60 @@ public static void register(CommandDispatcher<CommandSourceStack> dispatcher, Co
)
)
.then(Commands.literal("list_players_with")
.then(Commands.argument("rank", RankArgumentType.rank())
.executes(context -> listPlayersWith(context.getSource(), RankArgumentType.getRank(context, "rank")))
.then(Commands.argument("rank", StringArgumentType.word())
.suggests((context, builder) -> suggestRanks(builder))
.executes(context -> listPlayersWith(context.getSource(), StringArgumentType.getString(context, "rank")))
)
)
.then(Commands.literal("node")
.then(Commands.literal("add")
.then(Commands.argument("rank", RankArgumentType.rank())
.then(Commands.argument("rank", StringArgumentType.word())
.suggests((context, builder) -> suggestRanks(builder))
.then(Commands.argument("node", StringArgumentType.word())
.then(Commands.argument("value", StringArgumentType.greedyString())
.executes(context -> setNode(context.getSource(), RankArgumentType.getRank(context, "rank"), StringArgumentType.getString(context, "node"), StringArgumentType.getString(context, "value")))
.executes(context -> setNode(context.getSource(), StringArgumentType.getString(context, "rank"), StringArgumentType.getString(context, "node"), StringArgumentType.getString(context, "value")))
)
)
)
)
.then(Commands.literal("remove")
.then(Commands.argument("rank", RankArgumentType.rank())
.then(Commands.argument("rank", StringArgumentType.word())
.suggests((context, builder) -> suggestRanks(builder))
.then(Commands.argument("node", StringArgumentType.word())
.executes(context -> setNode(context.getSource(), RankArgumentType.getRank(context, "rank"), StringArgumentType.getString(context, "node"), null))
.executes(context -> setNode(context.getSource(), StringArgumentType.getString(context, "rank"), StringArgumentType.getString(context, "node"), null))
)
)
)
)
.then(Commands.literal("condition")
.then(Commands.argument("rank", RankArgumentType.rank())
.then(Commands.argument("rank", StringArgumentType.word())
.suggests((context, builder) -> suggestRanks(builder))
.then(Commands.argument("value", StringArgumentType.greedyString())
.executes(context -> setCondition(context.getSource(), RankArgumentType.getRank(context, "rank"), StringArgumentType.getString(context, "value")))
.executes(context -> setCondition(context.getSource(), StringArgumentType.getString(context, "rank"), StringArgumentType.getString(context, "value")))
)
)
)
.then(Commands.literal("show_rank")
.then(Commands.argument("rank", RankArgumentType.rank())
.executes(context -> showRank(context.getSource(), RankArgumentType.getRank(context, "rank")))
.then(Commands.argument("rank", StringArgumentType.word())
.suggests((context, builder) -> suggestRanks(builder))
.executes(context -> showRank(context.getSource(), StringArgumentType.getString(context, "rank")))
)
)
);
}

private static CompletableFuture<Suggestions> suggestRanks(SuggestionsBuilder builder) {
return SharedSuggestionProvider.suggest(FTBRanksAPI.INSTANCE.getManager().getAllRanks().stream().map(Rank::getId), builder);
}

private static String normalizeRankName(String name) {
return name.toLowerCase().replace("+", "_plus").replaceAll("[^a-z0-9_]", "_").replaceAll("_{2,}", "_");
}

private static int reloadRanks(CommandSourceStack source) {
try {
FTBRanksAPIImpl.manager.reload();
source.sendSuccess(new TranslatableComponent("ftbranks.reload"), true);
source.sendSuccess(new TextComponent("Ranks reloaded from disk!"), true);

for (ServerPlayer p : source.getServer().getPlayerList().getPlayers()) {
source.getServer().getPlayerList().sendPlayerPermissionLevel(p);
Expand All @@ -143,12 +160,12 @@ private static int refreshReadme(CommandSourceStack source) {
ex.printStackTrace();
}

source.sendSuccess(new TranslatableComponent("ftbranks.refresh_readme"), false);
source.sendSuccess(new TextComponent("README file refreshed!"), false);
return 1;
}

private static int listAllRanks(CommandSourceStack source) {
source.sendSuccess(new TranslatableComponent("ftbranks.ranks"), false);
source.sendSuccess(new TextComponent("Ranks:"), false);

for (Rank rank : FTBRanksAPIImpl.manager.getAllRanks()) {
source.sendSuccess(new TextComponent("- " + rank.getName()).withStyle(rank.getCondition().isDefaultCondition() ? ChatFormatting.AQUA : ChatFormatting.YELLOW), false);
Expand All @@ -161,44 +178,47 @@ private static int createRank(CommandSourceStack source, String name) {
String id = normalizeRankName(name);

if (FTBRanksAPIImpl.manager.getRank(id).isPresent()) {
source.sendFailure(new TranslatableComponent("ftbranks.rank_taken", name));
source.sendFailure(new TextComponent("Rank '" + name + "' is already taken!"));
return 0;
}

FTBRanksAPIImpl.manager.createRank(id, name);
source.sendSuccess(new TranslatableComponent("ftbranks.rank_created", id), false);
source.sendSuccess(new TextComponent("Rank '" + id + "' created!"), false);
return 1;
}

private static int deleteRank(CommandSourceStack source, Rank rank) {
private static int deleteRank(CommandSourceStack source, String rankName) throws CommandSyntaxException {
Rank rank = getRank(rankName);
FTBRanksAPI.INSTANCE.getManager().deleteRank(rank.getId());
source.sendSuccess(new TranslatableComponent("ftbranks.rank_deleted", rank.getName()), false);
source.sendSuccess(new TextComponent("Rank '" + rank.getName() + "' deleted!"), false);

return 1;
}

private static int addRank(CommandSourceStack source, Collection<GameProfile> players, Rank rank) {
private static int addRank(CommandSourceStack source, Collection<GameProfile> players, String rankName) throws CommandSyntaxException {
Rank rank = getRank(rankName);
for (GameProfile profile : players) {
if (rank.add(profile)) {
source.sendSuccess(new TranslatableComponent("ftbranks.player_added", profile.getName(), rank.getName()), false);
source.sendSuccess(new TextComponent(String.format("Player %s added to rank '%s'!", profile.getName(), rank.getName())), false);
}
}

return 1;
}

private static int removeRank(CommandSourceStack source, Collection<GameProfile> players, Rank rank) {
private static int removeRank(CommandSourceStack source, Collection<GameProfile> players, String rankName) throws CommandSyntaxException {
Rank rank = getRank(rankName);
for (GameProfile profile : players) {
if (rank.remove(profile)) {
source.sendSuccess(new TranslatableComponent("ftbranks.player_removed", profile.getName(), rank.getName()), false);
source.sendSuccess(new TextComponent(String.format("Player %s removed from rank '%s'!", profile.getName(), rank.getName())), false);
}
}

return 1;
}

private static int listRanksOf(CommandSourceStack source, ServerPlayer player) {
source.sendSuccess(new TranslatableComponent("ftbranks.list_ranks_of", player.getGameProfile().getName()), false);
source.sendSuccess(new TextComponent(String.format("Ranks added to player '%s':", player.getGameProfile().getName())), false);

for (Rank rank : FTBRanksAPIImpl.manager.getAllRanks()) {
if (rank.isActive(player)) {
Expand All @@ -208,9 +228,10 @@ private static int listRanksOf(CommandSourceStack source, ServerPlayer player) {

return 1;
}
private static int listPlayersWith(CommandSourceStack source, String rankName) throws CommandSyntaxException {
Rank rank = getRank(rankName);

private static int listPlayersWith(CommandSourceStack source, Rank rank) {
source.sendSuccess(new TranslatableComponent("ftbranks.list_players_with", rank.getName()), false);
source.sendSuccess(new TextComponent(String.format("Players with rank '%s':", rank.getName())), false);

for (ServerPlayer player : source.getServer().getPlayerList().getPlayers()) {
if (rank.isActive(player)) {
Expand All @@ -221,13 +242,15 @@ private static int listPlayersWith(CommandSourceStack source, Rank rank) {
return 1;
}

private static int setNode(CommandSourceStack source, Rank rank, String node, String value) throws CommandSyntaxException {
private static int setNode(CommandSourceStack source, String rankName, String node, String value) throws CommandSyntaxException {
Rank rank = getRank(rankName);

try {
rank.setPermission(node, strToPermissionValue(value));
if (value != null) {
source.sendSuccess(new TranslatableComponent("ftbranks.node_added", node, rank.getPermission(node), rank), false);
source.sendSuccess(new TextComponent(String.format("Permission node '%s'='%s' added to rank '%s'", node, rank.getPermission(node), rank)), false);
} else {
source.sendSuccess(new TranslatableComponent("ftbranks.node_removed", node, rank), false);
source.sendSuccess(new TextComponent(String.format("Permission node '%s' removed from rank '%s'", node, rank)), false);
}
} catch (IllegalArgumentException e) {
throw new SimpleCommandExceptionType(new TextComponent(e.getMessage())).create();
Expand All @@ -236,7 +259,9 @@ private static int setNode(CommandSourceStack source, Rank rank, String node, St
return 1;
}

private static int setCondition(CommandSourceStack source, Rank rank, String value) throws CommandSyntaxException {
private static int setCondition(CommandSourceStack source, String rankName, String value) throws CommandSyntaxException {
Rank rank = getRank(rankName);

try {
RankCondition condition;
if (value.equals("default") || value.equals("\"\"")) {
Expand All @@ -247,37 +272,34 @@ private static int setCondition(CommandSourceStack source, Rank rank, String val
condition = FTBRanksAPI.INSTANCE.getManager().createCondition(rank, StringTag.valueOf(value));
}
rank.setCondition(condition);
source.sendSuccess(new TranslatableComponent("ftbranks.node_added", "condition", value, rank), false);
source.sendSuccess(new TextComponent(String.format("Condition '%s' added to rank '%s'", value, rank)), false);
} catch (Exception e) {
throw new SimpleCommandExceptionType(new TextComponent(e.getMessage())).create();
}

return 1;
}

private static int showRank(CommandSourceStack source, Rank rank) {
private static int showRank(CommandSourceStack source, String rankName) throws CommandSyntaxException {
Rank rank = getRank(rankName);

source.sendSuccess(new TextComponent("=".repeat(50)).withStyle(ChatFormatting.GREEN), false);

source.sendSuccess(new TranslatableComponent("ftbranks.show_rank.header", col(rank.getId(), ChatFormatting.WHITE), col(rank.getName(), ChatFormatting.WHITE), col(Integer.toString(rank.getPower()), ChatFormatting.WHITE)).withStyle(ChatFormatting.YELLOW), false);
source.sendSuccess(new TextComponent(String.format("Rank ID: %s, Rank Name: %s, Power: %d", rank.getId(), rank.getName(), rank.getPower())).withStyle(ChatFormatting.YELLOW), false);

String condStr = rank.getCondition().asString();
Component c = condStr.isEmpty() ?
new TranslatableComponent("ftbranks.show_rank.condition.default").withStyle(ChatFormatting.WHITE, ChatFormatting.ITALIC) :
col(condStr, ChatFormatting.WHITE);
source.sendSuccess(new TranslatableComponent("ftbranks.show_rank.condition", c).withStyle(ChatFormatting.YELLOW), false);
new TextComponent("(none: players must be added)").withStyle(ChatFormatting.WHITE, ChatFormatting.ITALIC) : new TextComponent(condStr);
source.sendSuccess(new TextComponent("Condition: ").append(c).withStyle(ChatFormatting.YELLOW), false);

source.sendSuccess(new TranslatableComponent("ftbranks.show_rank.nodes").withStyle(ChatFormatting.YELLOW), false);
source.sendSuccess(new TextComponent("Permission nodes:").withStyle(ChatFormatting.YELLOW), false);
rank.getPermissions().stream().sorted().forEach(node ->
source.sendSuccess(new TranslatableComponent("ftbranks.show_rank.node", col(node, ChatFormatting.AQUA), rank.getPermission(node)).withStyle(ChatFormatting.WHITE), false)
source.sendSuccess(new TextComponent(" - " + node + ": " + rank.getPermission(node)), false)
);

return 0;
}

private static MutableComponent col(String str, ChatFormatting color) {
return new TextComponent(str).withStyle(color);
}

private static PermissionValue strToPermissionValue(String str) {
if (str == null) {
return null;
Expand All @@ -291,4 +313,8 @@ private static PermissionValue strToPermissionValue(String str) {
return StringPermissionValue.of(str);
}
}
}

private static Rank getRank(String rankName) throws CommandSyntaxException {
return FTBRanksAPI.INSTANCE.getManager().getRank(rankName).orElseThrow(() -> ERROR_UNKNOWN_RANK.create(rankName));
}
}
Loading