From 10c71a91a907fc130d66efb71f0644c0dfe7c15b Mon Sep 17 00:00:00 2001 From: Brian Date: Sat, 29 May 2021 13:05:01 -0400 Subject: [PATCH] Add ability for a "random" add or remove command Partial address for #51 --- .../allomancy/datagen/Languages.java | 18 ++- .../powers/command/AllomancyPowerCommand.java | 144 +++++++++++------- .../powers/data/DefaultAllomancyData.java | 9 +- .../assets/allomancy/lang/en_us.json | 2 + 4 files changed, 105 insertions(+), 68 deletions(-) diff --git a/src/main/java/com/legobmw99/allomancy/datagen/Languages.java b/src/main/java/com/legobmw99/allomancy/datagen/Languages.java index 276b57dd..0954881f 100644 --- a/src/main/java/com/legobmw99/allomancy/datagen/Languages.java +++ b/src/main/java/com/legobmw99/allomancy/datagen/Languages.java @@ -19,6 +19,14 @@ public Languages(DataGenerator gen, String modid, String locale) { super(gen, modid, locale); } + private static String getDisplayName(Metal mt) { + return toTitleCase(mt.getName()); + } + + private static String toTitleCase(String in) { + return in.substring(0, 1).toUpperCase() + in.substring(1); + } + @Override protected void addTranslations() { add("itemGroup.allomancy", "Allomancy"); @@ -88,6 +96,8 @@ protected void addTranslations() { add("commands.allomancy.addpower", "%s added Allomantic power %s"); add("commands.allomancy.removepower", "%s removed Allomantic power %s"); add("commands.allomancy.unrecognized", "Unrecognized Allomancy power: '%s'"); + add("commands.allomancy.err_add", "Unable to add power %s, already had"); + add("commands.allomancy.err_remove", "Unable to remove power %s, did not have"); for (DyeColor color : DyeColor.values()) { for (Metal mt : Metal.values()) { @@ -102,16 +112,8 @@ public String getName() { return "Allomancy Language"; } - private static String getDisplayName(Metal mt) { - return toTitleCase(mt.getName()); - } - private String getDisplayName(DyeColor color) { String[] trans = color.getName().split("_"); return Arrays.stream(trans).map(Languages::toTitleCase).collect(Collectors.joining(" ")); } - - private static String toTitleCase(String in) { - return in.substring(0, 1).toUpperCase() + in.substring(1); - } } diff --git a/src/main/java/com/legobmw99/allomancy/modules/powers/command/AllomancyPowerCommand.java b/src/main/java/com/legobmw99/allomancy/modules/powers/command/AllomancyPowerCommand.java index 0c0e0830..8112b885 100644 --- a/src/main/java/com/legobmw99/allomancy/modules/powers/command/AllomancyPowerCommand.java +++ b/src/main/java/com/legobmw99/allomancy/modules/powers/command/AllomancyPowerCommand.java @@ -1,32 +1,42 @@ package com.legobmw99.allomancy.modules.powers.command; +import com.legobmw99.allomancy.api.IAllomancyData; import com.legobmw99.allomancy.modules.powers.data.AllomancyCapability; -import com.legobmw99.allomancy.modules.powers.network.AllomancyDataPacket; import com.legobmw99.allomancy.network.Network; import com.legobmw99.allomancy.util.Metal; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; import com.mojang.brigadier.tree.LiteralCommandNode; import net.minecraft.command.CommandSource; import net.minecraft.command.Commands; import net.minecraft.command.arguments.EntityArgument; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.util.text.TranslationTextComponent; +import net.minecraftforge.common.util.NonNullConsumer; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.function.Function; import java.util.function.Predicate; public class AllomancyPowerCommand { - protected static final String[] names = new String[Metal.values().length + 1]; + protected static final String[] names = new String[Metal.values().length + 2]; + private static final DynamicCommandExceptionType ERROR_CANT_ADD = new DynamicCommandExceptionType(s -> new TranslationTextComponent("commands.allomancy.err_add", s)); + private static final DynamicCommandExceptionType ERROR_CANT_REMOVE = new DynamicCommandExceptionType(s -> new TranslationTextComponent("commands.allomancy.err_remove", s)); static { int i = 0; for (Metal mt : Metal.values()) { names[i++] = mt.getName(); } + names[i++] = "random"; names[i] = "all"; + } private static Predicate permissions(int level) { @@ -39,24 +49,28 @@ public static void register(CommandDispatcher dispatcher) { root.then(Commands .literal("get") .requires(permissions(0)) - .executes(ctx -> getPowers(ctx, false)) - .then(Commands.argument("targets", EntityArgument.players()).executes(ctx -> getPowers(ctx, true)))); + .executes(ctx -> handleMultiPlayer(ctx, false, AllomancyPowerCommand::getPowers)) + .then(Commands.argument("targets", EntityArgument.players()).executes(ctx -> handleMultiPlayer(ctx, true, AllomancyPowerCommand::getPowers)))); root.then(Commands .literal("add") .requires(permissions(2)) .then(Commands .argument("type", AllomancyPowerType.INSTANCE) - .executes(ctx -> addPower(ctx, false)) - .then(Commands.argument("targets", EntityArgument.players()).executes(ctx -> addPower(ctx, true))))); + .executes(ctx -> handleMultiPlayer(ctx, false, AllomancyPowerCommand::addPower)) + .then(Commands + .argument("targets", EntityArgument.players()) + .executes(ctx -> handleMultiPlayer(ctx, true, AllomancyPowerCommand::addPower))))); root.then(Commands .literal("remove") .requires(permissions(2)) .then(Commands .argument("type", AllomancyPowerType.INSTANCE) - .executes(ctx -> removePower(ctx, false)) - .then(Commands.argument("targets", EntityArgument.players()).executes(ctx -> removePower(ctx, true))))); + .executes(ctx -> handleMultiPlayer(ctx, false, AllomancyPowerCommand::removePower)) + .then(Commands + .argument("targets", EntityArgument.players()) + .executes(ctx -> handleMultiPlayer(ctx, true, AllomancyPowerCommand::removePower))))); LiteralCommandNode command = dispatcher.register(root); @@ -65,18 +79,28 @@ public static void register(CommandDispatcher dispatcher) { } - private static int getPowers(CommandContext ctx, boolean hasPlayer) throws CommandSyntaxException { + /** + * Abstraction to handle possibly multiple players + * + * @param ctx Command context + * @param hasPlayer If true, command had player(s) in the "targets" argument + * @param toApply Function to apply to all players or sender + * @return The number of players successfully applied to + * @throws CommandSyntaxException + */ + private static int handleMultiPlayer(CommandContext ctx, + boolean hasPlayer, + CheckedBiCon, ServerPlayerEntity> toApply) throws CommandSyntaxException { int i = 0; if (hasPlayer) { for (ServerPlayerEntity p : EntityArgument.getPlayers(ctx, "targets")) { - getPowers(ctx, p); + toApply.accept(ctx, p); i++; } } else { - getPowers(ctx, ctx.getSource().getPlayerOrException()); + toApply.accept(ctx, ctx.getSource().getPlayerOrException()); i = 1; } - return i; } @@ -102,63 +126,67 @@ private static void getPowers(CommandContext ctx, ServerPlayerEnt ctx.getSource().sendSuccess(new TranslationTextComponent("commands.allomancy.getpowers", player.getDisplayName(), powers.toString()), true); } - private static int addPower(CommandContext ctx, boolean hasPlayer) throws CommandSyntaxException { - int i = 0; - if (hasPlayer) { - for (ServerPlayerEntity p : EntityArgument.getPlayers(ctx, "targets")) { - addPower(ctx, p); - i++; - } - } else { - addPower(ctx, ctx.getSource().getPlayerOrException()); - i = 1; - } - return i; + private static void addPower(CommandContext ctx, ServerPlayerEntity player) throws CommandSyntaxException { + handlePowerChange(ctx, player, IAllomancyData::setMistborn, data -> (mt -> !data.hasPower(mt)), mt -> (data -> data.addPower(mt)), ERROR_CANT_ADD::create, + "commands.allomancy.addpower"); } - private static void addPower(CommandContext ctx, ServerPlayerEntity player) { - String type = ctx.getArgument("type", String.class); - player.getCapability(AllomancyCapability.PLAYER_CAP).ifPresent(data -> { - if (type.equalsIgnoreCase("all")) { - data.setMistborn(); - } else { - Metal mt = Metal.valueOf(type.toUpperCase()); - data.addPower(mt); - } - - Network.sendTo(new AllomancyDataPacket(data, player), player); - }); - ctx.getSource().sendSuccess(new TranslationTextComponent("commands.allomancy.addpower", player.getDisplayName(), type), true); + private static void removePower(CommandContext ctx, ServerPlayerEntity player) throws CommandSyntaxException { + handlePowerChange(ctx, player, IAllomancyData::setUninvested, (data) -> data::hasPower, (mt) -> (data -> data.revokePower(mt)), ERROR_CANT_REMOVE::create, + "commands.allomancy.removepower"); } - private static int removePower(CommandContext ctx, boolean hasPlayer) throws CommandSyntaxException { - int i = 0; - if (hasPlayer) { - for (ServerPlayerEntity p : EntityArgument.getPlayers(ctx, "targets")) { - removePower(ctx, p); - i++; - } - } else { - removePower(ctx, ctx.getSource().getPlayerOrException()); - i = 1; - } - return i; - } + /** + * Function abstraction for both add and remove + * + * @param ctx The command context + * @param player The player + * @param all Function to call with 'all' type, either setMistborn or setUninvested + * @param filterFunction Either data -> data.hasMetal or its inverse + * @param single Either metal -> data.addPower or its inverse + * @param exception Function to create an exception + * @param success String used when successful + * @throws CommandSyntaxException + */ + private static void handlePowerChange(CommandContext ctx, + ServerPlayerEntity player, + NonNullConsumer all, + Function> filterFunction, + Function> single, + Function exception, + String success) throws CommandSyntaxException { - private static void removePower(CommandContext ctx, ServerPlayerEntity player) { String type = ctx.getArgument("type", String.class); - player.getCapability(AllomancyCapability.PLAYER_CAP).ifPresent(data -> { - if (type.equalsIgnoreCase("all")) { - data.setUninvested(); + + if (type.equalsIgnoreCase("all")) { + player.getCapability(AllomancyCapability.PLAYER_CAP).ifPresent(all); + } else { + Predicate filter = player.getCapability(AllomancyCapability.PLAYER_CAP).map(filterFunction::apply).orElse((m) -> false); + + if (type.equalsIgnoreCase("random")) { + List metalList = Arrays.asList(Metal.values()); + Collections.shuffle(metalList); + Metal mt = metalList.stream().filter(filter).findFirst().orElseThrow(() -> exception.apply(type)); + player.getCapability(AllomancyCapability.PLAYER_CAP).ifPresent(single.apply(mt)); } else { Metal mt = Metal.valueOf(type.toUpperCase()); - data.revokePower(mt); + if (filter.test(mt)) { + player.getCapability(AllomancyCapability.PLAYER_CAP).ifPresent(single.apply(mt)); + } else { + throw exception.apply(type); + } } - Network.sendTo(new AllomancyDataPacket(data, player), player); - }); + } + Network.sync(player); + + ctx.getSource().sendSuccess(new TranslationTextComponent(success, player.getDisplayName(), type), true); - ctx.getSource().sendSuccess(new TranslationTextComponent("commands.allomancy.removepower", player.getDisplayName(), type), true); } + @FunctionalInterface + private interface CheckedBiCon { + void accept(T t, U u) throws CommandSyntaxException; + } + } diff --git a/src/main/java/com/legobmw99/allomancy/modules/powers/data/DefaultAllomancyData.java b/src/main/java/com/legobmw99/allomancy/modules/powers/data/DefaultAllomancyData.java index b17ed6b7..acd94659 100644 --- a/src/main/java/com/legobmw99/allomancy/modules/powers/data/DefaultAllomancyData.java +++ b/src/main/java/com/legobmw99/allomancy/modules/powers/data/DefaultAllomancyData.java @@ -49,26 +49,31 @@ public DefaultAllomancyData() { public void tickBurning(ServerPlayerEntity player) { + boolean sync = false; for (Metal metal : Metal.values()) { if (this.isBurning(metal)) { if (!this.hasPower(metal)) { // put out any metals that the player shouldn't be able to burn this.setBurning(metal, false); - Network.sync(this, player); + sync = true; } else { this.setBurnTime(metal, this.getBurnTime(metal) - 1); if (this.getBurnTime(metal) <= 0) { if (this.getAmount(metal) <= 0) { this.setBurning(metal, false); + sync = true; } else { this.setAmount(metal, this.getAmount(metal) - 1); } this.setBurnTime(metal, MAX_BURN_TIME[metal.getIndex()]); - Network.sync(this, player); } } } } + if (sync) { + Network.sync(this, player); + } + } diff --git a/src/main/resources/assets/allomancy/lang/en_us.json b/src/main/resources/assets/allomancy/lang/en_us.json index d4551a21..c60bb548 100644 --- a/src/main/resources/assets/allomancy/lang/en_us.json +++ b/src/main/resources/assets/allomancy/lang/en_us.json @@ -285,6 +285,8 @@ "block.minecraft.banner.allomancy_zinc.white": "White Zinc Symbol", "block.minecraft.banner.allomancy_zinc.yellow": "Yellow Zinc Symbol", "commands.allomancy.addpower": "%s added Allomantic power %s", + "commands.allomancy.err_add": "Unable to add power %s, already had", + "commands.allomancy.err_remove": "Unable to remove power %s, did not have", "commands.allomancy.getpowers": "%s currently has Allomantic powers: %s", "commands.allomancy.removepower": "%s removed Allomantic power %s", "commands.allomancy.unrecognized": "Unrecognized Allomancy power: '%s'",