-
Notifications
You must be signed in to change notification settings - Fork 65
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add dialogue commands for testing and reviewing dialogue (#590)
Two new commands: - `/review_dialogue <entity_type> <dialogue_category>` spawns entities of the given type for every dialogue in the given category (going by the starting node of all randomly selectable dialogue) - `/set_dialogue <entity> <dialogue_id>` sets the dialogue node for the given entity Both of these commands sets the dialogue such that it is kept on reset.
- Loading branch information
Showing
11 changed files
with
285 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
49 changes: 49 additions & 0 deletions
49
src/main/java/com/mraof/minestuck/command/MSSuggestionProviders.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package com.mraof.minestuck.command; | ||
|
||
import com.mojang.brigadier.suggestion.SuggestionProvider; | ||
import com.mraof.minestuck.Minestuck; | ||
import com.mraof.minestuck.entity.MSEntityTypes; | ||
import com.mraof.minestuck.entity.dialogue.DialogueNodes; | ||
import net.minecraft.Util; | ||
import net.minecraft.commands.CommandSourceStack; | ||
import net.minecraft.commands.SharedSuggestionProvider; | ||
import net.minecraft.commands.synchronization.SuggestionProviders; | ||
import net.minecraft.network.chat.Component; | ||
import net.minecraft.resources.ResourceLocation; | ||
import net.minecraft.world.entity.EntityType; | ||
|
||
import javax.annotation.Nullable; | ||
import java.util.List; | ||
import java.util.Objects; | ||
|
||
public final class MSSuggestionProviders | ||
{ | ||
public final SuggestionProvider<CommandSourceStack> DIALOGUE_ENTITY_TYPE = SuggestionProviders.register(Minestuck.id("dialogue_entity_type"), (context, builder) -> { | ||
//todo need a better way of identifying valid entity types | ||
Iterable<EntityType<?>> dialogueEntities = List.of(MSEntityTypes.SALAMANDER.get(), MSEntityTypes.TURTLE.get(), MSEntityTypes.NAKAGATOR.get(), MSEntityTypes.IGUANA.get()); | ||
return SharedSuggestionProvider.suggestResource(dialogueEntities, builder, EntityType::getKey, | ||
type -> Component.translatable(Util.makeDescriptionId("entity", EntityType.getKey(type)))); | ||
}); | ||
// this suggestion provider is not registered because dialogue nodes are not available at client-side | ||
public static final SuggestionProvider<CommandSourceStack> ALL_DIALOGUE_NODES = (context, builder) -> SharedSuggestionProvider.suggestResource(DialogueNodes.getInstance().allIds(), builder); | ||
|
||
private MSSuggestionProviders() | ||
{ | ||
} | ||
|
||
@Nullable | ||
private static MSSuggestionProviders instance; | ||
|
||
public static MSSuggestionProviders instance() | ||
{ | ||
return Objects.requireNonNull(instance, "Tried to get instance before suggestions had been set up."); | ||
} | ||
|
||
/** | ||
* To be called during main thread setup as {@link net.minecraft.commands.synchronization.SuggestionProviders#register(ResourceLocation, SuggestionProvider)} does not appear to be thread-safe. | ||
*/ | ||
public static void register() | ||
{ | ||
instance = new MSSuggestionProviders(); | ||
} | ||
} |
105 changes: 105 additions & 0 deletions
105
src/main/java/com/mraof/minestuck/command/ReviewDialogueCommand.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package com.mraof.minestuck.command; | ||
|
||
import com.mojang.brigadier.CommandDispatcher; | ||
import com.mojang.brigadier.exceptions.CommandSyntaxException; | ||
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; | ||
import com.mraof.minestuck.command.argument.DialogueCategoryArgument; | ||
import com.mraof.minestuck.entity.dialogue.Dialogue; | ||
import com.mraof.minestuck.entity.dialogue.DialogueEntity; | ||
import com.mraof.minestuck.entity.dialogue.RandomlySelectableDialogue; | ||
import net.minecraft.commands.CommandBuildContext; | ||
import net.minecraft.commands.CommandSourceStack; | ||
import net.minecraft.commands.Commands; | ||
import net.minecraft.commands.arguments.ResourceArgument; | ||
import net.minecraft.core.BlockPos; | ||
import net.minecraft.core.Direction; | ||
import net.minecraft.core.registries.Registries; | ||
import net.minecraft.network.chat.Component; | ||
import net.minecraft.server.level.ServerLevel; | ||
import net.minecraft.world.entity.Entity; | ||
import net.minecraft.world.entity.EntityType; | ||
import net.minecraft.world.entity.Mob; | ||
import net.minecraft.world.entity.MobSpawnType; | ||
import net.minecraft.world.item.DyeColor; | ||
import net.minecraft.world.level.block.Block; | ||
import net.minecraft.world.level.block.Blocks; | ||
import net.minecraft.world.level.block.WallSignBlock; | ||
import net.minecraft.world.level.block.entity.SignBlockEntity; | ||
import net.minecraft.world.level.block.entity.SignText; | ||
|
||
import java.util.Collection; | ||
|
||
public final class ReviewDialogueCommand | ||
{ | ||
public static final String INVALID_TYPE_KEY = "commands.minestuck.review_dialouge.invalid_type"; | ||
public static final String SUCCESS_KEY = "commands.minestuck.review_dialouge.success"; | ||
private static final SimpleCommandExceptionType ERROR_FAILED = new SimpleCommandExceptionType(Component.translatable("commands.summon.failed")); | ||
private static final SimpleCommandExceptionType INVALID_TYPE = new SimpleCommandExceptionType(Component.translatable(INVALID_TYPE_KEY)); | ||
|
||
public static void register(CommandDispatcher<CommandSourceStack> dispatcher, CommandBuildContext buildContext) | ||
{ | ||
dispatcher.register(Commands.literal("review_dialogue").requires(source -> source.hasPermission(Commands.LEVEL_GAMEMASTERS)) | ||
.then(Commands.argument("entity", ResourceArgument.resource(buildContext, Registries.ENTITY_TYPE)) | ||
.suggests(MSSuggestionProviders.instance().DIALOGUE_ENTITY_TYPE) | ||
.then(Commands.argument("category", new DialogueCategoryArgument()) | ||
.executes(context -> spawnDialogueEntities(context.getSource(), | ||
ResourceArgument.getSummonableEntityType(context, "entity").value(), | ||
DialogueCategoryArgument.getCategory(context, "category")))))); | ||
} | ||
|
||
private static int spawnDialogueEntities(CommandSourceStack source, EntityType<?> entityType, RandomlySelectableDialogue.DialogueCategory category) throws CommandSyntaxException | ||
{ | ||
Collection<Dialogue.SelectableDialogue> dialogueCollection = RandomlySelectableDialogue.instance(category).getAll(); | ||
|
||
ServerLevel level = source.getLevel(); | ||
BlockPos pos = BlockPos.containing(source.getPosition()); | ||
|
||
for(Dialogue.SelectableDialogue dialogue : dialogueCollection) | ||
{ | ||
pos = pos.east(2); | ||
level.removeBlock(pos, false); | ||
level.setBlock(pos.below(), Blocks.BRICKS.defaultBlockState(), Block.UPDATE_ALL); | ||
|
||
DialogueEntity dialogueEntity = spawnEntity(entityType, level, pos); | ||
|
||
dialogueEntity.getDialogueComponent().setDialogue(dialogue.dialogueId(), true); | ||
|
||
placeSign(dialogue, pos, level); | ||
} | ||
|
||
source.sendSuccess(() -> Component.translatable(SUCCESS_KEY, dialogueCollection.size()), true); | ||
|
||
return dialogueCollection.size(); | ||
} | ||
|
||
private static DialogueEntity spawnEntity(EntityType<?> entityType, ServerLevel level, BlockPos pos) throws CommandSyntaxException | ||
{ | ||
Entity entity = entityType.spawn(level, pos, MobSpawnType.COMMAND); | ||
if(entity == null) | ||
throw ERROR_FAILED.create(); | ||
|
||
entity.setNoGravity(true); | ||
if(entity instanceof Mob mob) | ||
mob.setNoAi(true); | ||
|
||
if(entity instanceof DialogueEntity dialogueEntity) | ||
return dialogueEntity; | ||
else | ||
throw INVALID_TYPE.create(); | ||
} | ||
|
||
private static void placeSign(Dialogue.SelectableDialogue dialogue, BlockPos pos, ServerLevel level) | ||
{ | ||
BlockPos signPos = pos.north().below(); | ||
level.setBlock(signPos, Blocks.OAK_WALL_SIGN.defaultBlockState().setValue(WallSignBlock.FACING, Direction.NORTH), Block.UPDATE_ALL); | ||
if(level.getBlockEntity(signPos) instanceof SignBlockEntity sign) | ||
{ | ||
SignText signText = new SignText().setHasGlowingText(true).setColor(DyeColor.WHITE) | ||
.setMessage(0, Component.literal(dialogue.dialogueId().getNamespace())); | ||
String[] lines = dialogue.dialogueId().getPath().split("/", 3); | ||
for(int i = 0; i < lines.length; i++) | ||
signText = signText.setMessage(i + 1, Component.literal(lines[i])); | ||
sign.setText(signText, true); | ||
} | ||
} | ||
} |
46 changes: 46 additions & 0 deletions
46
src/main/java/com/mraof/minestuck/command/SetDialogueCommand.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package com.mraof.minestuck.command; | ||
|
||
import com.mojang.brigadier.CommandDispatcher; | ||
import com.mojang.brigadier.exceptions.CommandSyntaxException; | ||
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; | ||
import com.mraof.minestuck.entity.dialogue.DialogueEntity; | ||
import com.mraof.minestuck.entity.dialogue.DialogueNodes; | ||
import net.minecraft.commands.CommandSourceStack; | ||
import net.minecraft.commands.Commands; | ||
import net.minecraft.commands.arguments.EntityArgument; | ||
import net.minecraft.commands.arguments.ResourceLocationArgument; | ||
import net.minecraft.network.chat.Component; | ||
import net.minecraft.resources.ResourceLocation; | ||
import net.minecraft.world.entity.Entity; | ||
|
||
public final class SetDialogueCommand | ||
{ | ||
public static final String INVALID_ENTITY_KEY = "commands.minestuck.set_dialouge.invalid_entity"; | ||
public static final String INVALID_ID_KEY = "commands.minestuck.set_dialouge.invalid_id"; | ||
public static final String SUCCESS_KEY = "commands.minestuck.set_dialouge.success"; | ||
private static final DynamicCommandExceptionType INVALID_ENTITY = new DynamicCommandExceptionType(entity -> Component.translatable(INVALID_ENTITY_KEY, entity)); | ||
private static final DynamicCommandExceptionType INVALID_ID = new DynamicCommandExceptionType(id -> Component.translatable(INVALID_ID_KEY, id)); | ||
|
||
public static void register(CommandDispatcher<CommandSourceStack> dispatcher) | ||
{ | ||
dispatcher.register(Commands.literal("set_dialogue").requires(source -> source.hasPermission(Commands.LEVEL_GAMEMASTERS)) | ||
.then(Commands.argument("entity", EntityArgument.entity()) | ||
.then(Commands.argument("dialogue", ResourceLocationArgument.id()) | ||
.suggests(MSSuggestionProviders.ALL_DIALOGUE_NODES) | ||
.executes(context -> setDialogue(context.getSource(), | ||
EntityArgument.getEntity(context, "entity"), ResourceLocationArgument.getId(context, "dialogue")))))); | ||
} | ||
|
||
private static int setDialogue(CommandSourceStack source, Entity entity, ResourceLocation id) throws CommandSyntaxException | ||
{ | ||
if(!(entity instanceof DialogueEntity dialogueEntity)) | ||
throw INVALID_ENTITY.create(entity.getDisplayName()); | ||
|
||
if(DialogueNodes.getInstance().getDialogue(id) == null) | ||
throw INVALID_ID.create(id); | ||
|
||
dialogueEntity.getDialogueComponent().setDialogue(id, true); | ||
source.sendSuccess(() -> Component.translatable(SUCCESS_KEY, entity.getDisplayName(), id), true); | ||
return 1; | ||
} | ||
} |
57 changes: 57 additions & 0 deletions
57
src/main/java/com/mraof/minestuck/command/argument/DialogueCategoryArgument.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package com.mraof.minestuck.command.argument; | ||
|
||
import com.mojang.brigadier.StringReader; | ||
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.suggestion.Suggestions; | ||
import com.mojang.brigadier.suggestion.SuggestionsBuilder; | ||
import com.mraof.minestuck.entity.dialogue.RandomlySelectableDialogue.DialogueCategory; | ||
import net.minecraft.commands.CommandSourceStack; | ||
import net.minecraft.commands.SharedSuggestionProvider; | ||
import net.minecraft.network.chat.Component; | ||
|
||
import java.util.Collection; | ||
import java.util.Optional; | ||
import java.util.concurrent.CompletableFuture; | ||
import java.util.stream.Stream; | ||
|
||
public final class DialogueCategoryArgument implements ArgumentType<DialogueCategory> | ||
{ | ||
public static final String INVALID = "argument.dialogue_category.invalid"; | ||
public static final DynamicCommandExceptionType INVALID_TYPE = new DynamicCommandExceptionType(o -> Component.translatable(INVALID, o)); | ||
|
||
public static final Collection<String> CATEGORY_STRINGS = Stream.of(DialogueCategory.values()).map(DialogueCategory::folderName).toList(); | ||
|
||
@Override | ||
public DialogueCategory parse(StringReader reader) throws CommandSyntaxException | ||
{ | ||
int start = reader.getCursor(); | ||
String name = reader.readUnquotedString(); | ||
Optional<DialogueCategory> categoryOptional = Stream.of(DialogueCategory.values()).filter(category -> category.name().equalsIgnoreCase(name)).findAny(); | ||
if(categoryOptional.isEmpty()) | ||
{ | ||
reader.setCursor(start); | ||
throw INVALID_TYPE.createWithContext(reader, name); | ||
} | ||
return categoryOptional.get(); | ||
} | ||
|
||
@Override | ||
public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) | ||
{ | ||
return SharedSuggestionProvider.suggest(CATEGORY_STRINGS, builder); | ||
} | ||
|
||
@Override | ||
public Collection<String> getExamples() | ||
{ | ||
return CATEGORY_STRINGS; | ||
} | ||
|
||
public static DialogueCategory getCategory(CommandContext<CommandSourceStack> context, String id) | ||
{ | ||
return context.getArgument(id, DialogueCategory.class); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters