Skip to content

Commit

Permalink
fix: rework some commands to not use QuestObjectArgument
Browse files Browse the repository at this point in the history
Just use a simple string argument type for quest object IDs

QuestObjectArgument depends on the server quest file being loaded,
  which breaks using ftbquests commands in MC functions; these are
  parsed much sooner than the quest file can be loaded.

FTBTeam/FTB-Mods-Issues#1422
  • Loading branch information
desht committed Feb 4, 2025
1 parent bad5182 commit 20eb0cb
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.mojang.brigadier.arguments.BoolArgumentType;
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 dev.architectury.registry.registries.RegistrarManager;
import dev.ftb.mods.ftblibrary.config.Tristate;
Expand Down Expand Up @@ -41,12 +42,15 @@

import java.util.*;

/**
* @author LatvianModder
*/
public class FTBQuestsCommands {

private static final SimpleCommandExceptionType NO_INVENTORY = new SimpleCommandExceptionType(Component.translatable("commands.ftbquests.command.error.no_inventory"));
public static final SimpleCommandExceptionType NO_FILE = new SimpleCommandExceptionType(
Component.translatable("commands.ftbquests.command.error.no_file"));
public static final DynamicCommandExceptionType NO_OBJECT = new DynamicCommandExceptionType(
(object) -> Component.translatable("commands.ftbquests.command.error.no_object", object));
public static final DynamicCommandExceptionType INVALID_ID = new DynamicCommandExceptionType(
(id) -> Component.translatable("commands.ftbquests.command.error.invalid_id", id));
private static final SimpleCommandExceptionType NO_INVENTORY = new SimpleCommandExceptionType(
Component.translatable("commands.ftbquests.command.error.no_inventory"));

public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
//noinspection ConstantValue
Expand Down Expand Up @@ -78,43 +82,33 @@ public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
.requires(FTBQuestsCommands::hasEditorPermission)
.then(Commands.argument("players", EntityArgument.players())
.then(Commands.literal("reset")
.then(Commands.argument("quest_object", QuestObjectArgument.questObject())
.then(Commands.argument("quest_object", StringArgumentType.string())
.executes(ctx -> {
Collection<ServerPlayer> players = EntityArgument.getPlayers(ctx, "players");
QuestObjectBase questObject = ctx.getArgument("quest_object", QuestObjectBase.class);
return changeProgress(ctx.getSource(), players, true, questObject);
return changeProgress(ctx.getSource(), players, true, StringArgumentType.getString(ctx, "quest_object"));
})
)
)
.then(Commands.literal("complete")
.then(Commands.argument("quest_object", QuestObjectArgument.questObject())
.then(Commands.argument("quest_object", StringArgumentType.string())
.executes(ctx -> {
Collection<ServerPlayer> players = EntityArgument.getPlayers(ctx, "players");
QuestObjectBase questObject = ctx.getArgument("quest_object", QuestObjectBase.class);
return changeProgress(ctx.getSource(), players, false, questObject);
return changeProgress(ctx.getSource(), players, false, StringArgumentType.getString(ctx, "quest_object"));
})
)
)
)
)
.then(Commands.literal("export_reward_table_to_chest")
.requires(FTBQuestsCommands::hasEditorPermission)
.then(Commands.argument("reward_table", QuestObjectArgument.questObject())
.executes(ctx -> {
QuestObjectBase table = ctx.getArgument("reward_table", QuestObjectBase.class);
if (!(table instanceof RewardTable)) {
throw QuestObjectArgument.NO_OBJECT.create(table.getCodeString());
}
return exportRewards(ctx.getSource(), (RewardTable) table, null);
})
.then(Commands.argument("reward_table", StringArgumentType.string())
.executes(ctx ->
exportRewards(ctx.getSource(), StringArgumentType.getString(ctx, "reward_table"), null)
)
.then(Commands.argument("pos", BlockPosArgument.blockPos())
.executes(ctx -> {
QuestObjectBase table = ctx.getArgument("reward_table", QuestObjectBase.class);
BlockPos pos = BlockPosArgument.getSpawnablePos(ctx, "pos");
if (!(table instanceof RewardTable)) {
throw QuestObjectArgument.NO_OBJECT.create(table.getCodeString());
}
return exportRewards(ctx.getSource(), (RewardTable) table, pos);
return exportRewards(ctx.getSource(), StringArgumentType.getString(ctx, "reward_table"), pos);
})
)
)
Expand Down Expand Up @@ -154,8 +148,8 @@ public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
)
.then(Commands.literal("open_book")
.executes(c -> openQuest(c.getSource().getPlayerOrException(), null))
.then(Commands.argument("quest_object", QuestObjectArgument.questObject(qob -> qob instanceof QuestObject))
.executes(c -> openQuest(c.getSource().getPlayerOrException(), c.getArgument("quest_object", QuestObjectBase.class))))
.then(Commands.argument("quest_object", StringArgumentType.string())
.executes(c -> openQuest(c.getSource().getPlayerOrException(), StringArgumentType.getString(c, "quest_object"))))
)
.then(Commands.literal("clear_item_display_cache")
.requires(FTBQuestsCommands::hasEditorPermission)
Expand All @@ -170,19 +164,31 @@ private static boolean hasEditorPermission(CommandSourceStack stack) {
|| stack.isPlayer() && PermissionsHelper.hasEditorPermission(stack.getPlayer(), false);
}

private static int openQuest(ServerPlayer player, QuestObjectBase qob) {
if (qob == null) {
// just open the book to wherever it last was
new OpenQuestBookMessage(0L).sendTo(player);
} else if (qob instanceof QuestObject quest) {
if (canSeeQuestObject(player, quest)) {
new OpenQuestBookMessage(quest.id).sendTo(player);
private static QuestObjectBase getQuestObjectForString(String idStr) throws CommandSyntaxException {
ServerQuestFile file = ServerQuestFile.INSTANCE;
if (file == null) {
throw NO_FILE.create();
}

if (idStr.startsWith("#")) {
String val = idStr.substring(1);
for (QuestObjectBase qob : file.getAllObjects()) {
if (qob.hasTag(val)) {
return qob;
}
}
throw NO_OBJECT.create(idStr);
} else {
long id = QuestObjectBase.parseHexId(idStr).orElseThrow(() -> INVALID_ID.create(idStr));
QuestObjectBase qob = file.getBase(id);
if (qob == null) {
throw NO_OBJECT.create(idStr);
}
return qob;
}
return 1;
}

private static boolean canSeeQuestObject(ServerPlayer player, QuestObject qo) {
private static boolean playerCanSeeQuestObject(ServerPlayer player, QuestObject qo) {
if (qo instanceof Chapter) {
return true;
}
Expand All @@ -198,34 +204,47 @@ private static boolean canSeeQuestObject(ServerPlayer player, QuestObject qo) {
return quest != null && (data.getCanEdit(player) || !quest.hideDetailsUntilStartable() || data.canStartTasks(quest));
}

private static int exportRewards(CommandSourceStack source, RewardTable table, BlockPos pos) throws CommandSyntaxException {
private static int openQuest(ServerPlayer player, String qobId) throws CommandSyntaxException {
if (qobId == null) {
new OpenQuestBookMessage(0L).sendTo(player);
return Command.SINGLE_SUCCESS;
} else {
if (getQuestObjectForString(qobId) instanceof Quest quest && playerCanSeeQuestObject(player, quest)) {
new OpenQuestBookMessage(quest.id).sendTo(player);
return Command.SINGLE_SUCCESS;
}
}
return 0;
}

private static int exportRewards(CommandSourceStack source, String idStr, @Nullable BlockPos pos) throws CommandSyntaxException {
ServerPlayer player = source.getPlayerOrException();
ServerLevel level = source.getLevel();

if (pos == null) {
pos = BlockPos.containing(player.pick(10, 1F, false).getLocation());
if (!(getQuestObjectForString(idStr) instanceof RewardTable table)) {
throw NO_OBJECT.create(idStr);
}

BlockEntity be = level.getBlockEntity(pos);
if (!(be instanceof BaseContainerBlockEntity container)) {
pos = Objects.requireNonNullElse(pos, BlockPos.containing(player.pick(10, 1F, false).getLocation()));
if (!(level.getBlockEntity(pos) instanceof BaseContainerBlockEntity container)) {
throw NO_INVENTORY.create();
}

container.clearContent();

int s = 0;
int slot = 0;
for (WeightedReward wr : table.getWeightedRewards()) {
if (s >= container.getContainerSize()) {
if (slot >= container.getContainerSize()) {
source.sendFailure(Component.translatable("commands.ftbquests.command.feedback.table_too_many_items", table.getTitle()));
return 0;
} else if (wr.getReward() instanceof ItemReward itemReward) {
container.setItem(s++, itemReward.getItem());
container.setItem(slot++, itemReward.getItem());
}
}

source.sendSuccess(() -> Component.translatable("commands.ftbquests.command.feedback.table_imported", table.getTitle(), table.getWeightedRewards().size()), false);

return 1;
return Command.SINGLE_SUCCESS;
}

private static int importRewards(CommandSourceStack source, String name, BlockPos pos) throws CommandSyntaxException {
Expand Down Expand Up @@ -259,7 +278,7 @@ private static int importRewards(CommandSourceStack source, String name, BlockPo

source.sendSuccess(() -> Component.translatable("commands.ftbquests.command.feedback.table_imported", name, table.getWeightedRewards().size()), false);

return 1;
return Command.SINGLE_SUCCESS;
}

private static int editingMode(CommandSourceStack source, ServerPlayer player, @Nullable Boolean canEdit) {
Expand All @@ -270,14 +289,7 @@ private static int editingMode(CommandSourceStack source, ServerPlayer player, @
}

data.setCanEdit(player, canEdit);

if (canEdit) {
source.sendSuccess(() -> Component.translatable("commands.ftbquests.editing_mode.enabled", player.getDisplayName()), true);
} else {
source.sendSuccess(() -> Component.translatable("commands.ftbquests.editing_mode.disabled", player.getDisplayName()), true);
}

return 1;
return Command.SINGLE_SUCCESS;
}

private static int locked(CommandSourceStack source, ServerPlayer player, @Nullable Boolean locked) {
Expand All @@ -289,16 +301,11 @@ private static int locked(CommandSourceStack source, ServerPlayer player, @Nulla

data.setLocked(locked);

if (locked) {
source.sendSuccess(() -> Component.translatable("commands.ftbquests.locked.enabled", player.getDisplayName()), true);
} else {
source.sendSuccess(() -> Component.translatable("commands.ftbquests.locked.disabled", player.getDisplayName()), true);
}

return 1;
return Command.SINGLE_SUCCESS;
}

private static int changeProgress(CommandSourceStack source, Collection<ServerPlayer> players, boolean reset, QuestObjectBase questObject) {
private static int changeProgress(CommandSourceStack source, Collection<ServerPlayer> players, boolean reset, String idStr) throws CommandSyntaxException {
QuestObjectBase questObject = getQuestObjectForString(idStr);
for (ServerPlayer player : players) {
ProgressChange progressChange = new ProgressChange(ServerQuestFile.INSTANCE, questObject, player.getUUID()).setReset(reset);
questObject.forceProgress(ServerQuestFile.INSTANCE.getOrCreateTeamData(player), progressChange);
Expand All @@ -313,7 +320,7 @@ private static int deleteEmptyRewardTables(CommandSourceStack source) {

source.sendSuccess(() -> Component.translatable("commands.ftbquests.command.delete_empty_reward_tables.text", removed), false);

return 1;
return Command.SINGLE_SUCCESS;
}

private static int generateAllItemChapter(CommandSourceStack source) {
Expand All @@ -337,7 +344,7 @@ private static int generateAllItemChapter(CommandSourceStack source) {
.filter(stack -> !stack.isEmpty() && RegistrarManager.getId(stack.getItem(), Registries.ITEM) != null)
.sorted(Comparator.comparing(a -> RegistrarManager.getId(a.getItem(), Registries.ITEM)))
.toList();
FTBQuests.LOGGER.info("Found " + allItems.size() + " items in total, chapter ID: " + chapter);
FTBQuests.LOGGER.info("Found {} items in total, chapter ID: {}", allItems.size(), chapter);

if (list.isEmpty()) {
return 0;
Expand Down Expand Up @@ -380,7 +387,7 @@ private static int generateAllItemChapter(CommandSourceStack source) {
ServerQuestFile.INSTANCE.markDirty();
ServerQuestFile.INSTANCE.saveNow();
source.sendSuccess(() -> Component.literal("Done!"), false);
return 1;
return Command.SINGLE_SUCCESS;
}

private static final Set<UUID> warnedPlayers = new HashSet<>();
Expand All @@ -391,7 +398,7 @@ private static int doReload(CommandSourceStack source) {

if (sender != null && !instance.getOrCreateTeamData(sender).getCanEdit(sender)) {
source.sendFailure(Component.translatable("commands.ftbquests.command.error.not_editing"));
return 1;
return 0;
}

instance.load();
Expand All @@ -406,7 +413,7 @@ private static int doReload(CommandSourceStack source) {
warnedPlayers.add(id);
}

return 1;
return Command.SINGLE_SUCCESS;
}

private static int toggleRewardBlocking(CommandSourceStack source, ServerPlayer player, Boolean doBlocking) {
Expand All @@ -415,17 +422,15 @@ private static int toggleRewardBlocking(CommandSourceStack source, ServerPlayer
if (doBlocking == null) {
doBlocking = !data.areRewardsBlocked();
}

data.setRewardsBlocked(doBlocking);

source.sendSuccess(() -> Component.translatable("commands.ftbquests.command.feedback.rewards_blocked", data, data.areRewardsBlocked()), false);

return 1;
return Command.SINGLE_SUCCESS;
}

private static int clearDisplayCache(CommandSourceStack source) {
ClearDisplayCacheMessage.clearForAll(source.getServer());
source.sendSuccess(() -> Component.translatable("commands.ftbquests.command.feedback.clear_display_cache"), false);
return 1;
return Command.SINGLE_SUCCESS;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,32 @@
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.context.CommandContext;
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.ftbquests.client.ClientQuestFile;
import dev.ftb.mods.ftbquests.quest.BaseQuestFile;
import dev.ftb.mods.ftbquests.quest.QuestObjectBase;
import dev.ftb.mods.ftbquests.quest.ServerQuestFile;
import net.minecraft.commands.SharedSuggestionProvider;
import net.minecraft.network.chat.Component;
import org.jetbrains.annotations.Nullable;

import java.util.Collection;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;

/**
* Avoid using this in commands, since it breaks MC functions; functions are parsed by the server very early on,
* long before the server quest file can possibly be loaded.
* Will be removed sometime after 1.21.1
*/
@Deprecated(forRemoval = true)
public class QuestObjectArgument implements ArgumentType<QuestObjectBase> {

private static final List<String> examples = ImmutableList.of(
"1CF239D256879E6F",
"#importantquests"
);

public static final SimpleCommandExceptionType NO_FILE = new SimpleCommandExceptionType(
Component.translatable("commands.ftbquests.command.error.no_file"));

public static final DynamicCommandExceptionType NO_OBJECT = new DynamicCommandExceptionType(
(object) -> Component.translatable("commands.ftbquests.command.error.no_object", object));

public static final DynamicCommandExceptionType INVALID_ID = new DynamicCommandExceptionType(
(id) -> Component.translatable("commands.ftbquests.command.error.invalid_id", id));

private final Predicate<QuestObjectBase> filter;

public QuestObjectArgument() {
Expand All @@ -60,21 +53,21 @@ public QuestObjectBase parse(StringReader reader) throws CommandSyntaxException
return object;
}
}
throw NO_OBJECT.createWithContext(reader, id);
throw FTBQuestsCommands.NO_OBJECT.createWithContext(reader, id);
} else {
try {
long num = file.getID(id);
QuestObjectBase object = file.getBase(num);
if (object == null || !filter.test(object)) {
throw NO_OBJECT.createWithContext(reader, id);
throw FTBQuestsCommands.NO_OBJECT.createWithContext(reader, id);
}
return object;
} catch (NumberFormatException e) {
throw INVALID_ID.createWithContext(reader, id);
throw FTBQuestsCommands.INVALID_ID.createWithContext(reader, id);
}
}
}
throw NO_FILE.create();
throw FTBQuestsCommands.NO_FILE.create();
}

@Override
Expand Down

0 comments on commit 20eb0cb

Please sign in to comment.