Added /trait

This commit is contained in:
Sollace 2021-12-28 18:22:08 +02:00
parent 3cec6de107
commit de6f9a92d4
6 changed files with 232 additions and 49 deletions

View file

@ -3,19 +3,19 @@ package com.minelittlepony.unicopia.command;
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.command.argument.ArgumentTypes;
import net.minecraft.command.argument.serialize.ConstantArgumentSerializer;
import net.minecraft.server.MinecraftServer;
public class Commands {
@SuppressWarnings({ "deprecation", "unchecked", "rawtypes" })
public static void bootstrap() {
ArgumentTypes.register("unicopia:race", RaceArgument.class, new ConstantArgumentSerializer<>(RaceArgument::new));
ArgumentTypes.register("unicopia:enumeration", EnumArgumentType.class, new EnumArgumentType.Serializer());
CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> {
SpeciesCommand.register(dispatcher);
RacelistCommand.register(dispatcher);
GravityCommand.register(dispatcher);
DisguiseCommand.register(dispatcher);
TraitCommand.register(dispatcher);
});
@SuppressWarnings("deprecation")
Object game = FabricLoader.getInstance().getGameInstance();
if (game instanceof MinecraftServer) {
((MinecraftServer)game).setFlightEnabled(true);

View file

@ -0,0 +1,126 @@
package com.minelittlepony.unicopia.command;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
import com.google.common.base.Strings;
import com.google.gson.JsonObject;
import com.minelittlepony.unicopia.Race;
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.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.ByteBufOutputStream;
import net.minecraft.command.argument.serialize.ArgumentSerializer;
import net.minecraft.network.PacketByteBuf;
class EnumArgumentType<T extends Enum<T>> implements ArgumentType<T>, Serializable {
private static final long serialVersionUID = 3731493854867412243L;
private static final EnumArgumentType<Race> RACE = of(Race.class, Race::isUsable, Race.EARTH);
public static EnumArgumentType<Race> race() {
return RACE;
}
public static <T extends Enum<T>> EnumArgumentType<T> of(Class<T> type, Predicate<T> filter, T def) {
return new EnumArgumentType<>(type, filter, def);
}
public static <T extends Enum<T>> EnumArgumentType<T> of(Class<T> type, T def) {
return new EnumArgumentType<>(type, s -> true, def);
}
public static <T extends Enum<T>> EnumArgumentType<T> of(Class<T> type) {
return new EnumArgumentType<>(type, s -> true, null);
}
private final T def;
private final T[] values;
private final List<String> suggestions;
private EnumArgumentType(Class<T> type, Predicate<T> filter, T def) {
this.def = def;
values = type.getEnumConstants();
suggestions = Arrays.stream(values).filter(filter).map(T::name).toList();
}
private EnumArgumentType(List<String> suggestions, T[] values, T def) {
this.suggestions = suggestions;
this.values = values;
this.def = def;
}
@Override
public T parse(StringReader reader) throws CommandSyntaxException {
return fromName(reader.readUnquotedString());
}
@Override
public <S> CompletableFuture<Suggestions> listSuggestions(final CommandContext<S> context, final SuggestionsBuilder builder) {
suggestions.stream()
.filter(i -> i.toLowerCase().startsWith(builder.getRemaining().toLowerCase()))
.forEach(builder::suggest);
return builder.buildFuture();
}
@SuppressWarnings("unlikely-arg-type")
private T fromName(String s) {
if (!Strings.isNullOrEmpty(s)) {
for (T i : values) {
if (i.equals(s) || i.name().equalsIgnoreCase(s)) {
return i;
}
}
}
try {
int ordinal = Integer.parseInt(s);
if (ordinal >= 0 && ordinal < values.length) {
return values[ordinal];
}
} catch (NumberFormatException e) { }
return def;
}
@Override
public Collection<String> getExamples() {
return suggestions;
}
public static class Serializer<T extends Enum<T>> implements ArgumentSerializer<EnumArgumentType<T>> {
@Override
public void toPacket(EnumArgumentType<T> type, PacketByteBuf buf) {
try (ObjectOutputStream stream = new ObjectOutputStream(new ByteBufOutputStream(buf))) {
stream.writeObject(type);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@SuppressWarnings("unchecked")
@Override
public EnumArgumentType<T> fromPacket(PacketByteBuf buf) {
try (ObjectInputStream stream = new ObjectInputStream(new ByteBufInputStream(buf))) {
return (EnumArgumentType<T>)stream.readObject();
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
@Override
public void toJson(EnumArgumentType<T> type, JsonObject json) { }
}
}

View file

@ -1,42 +0,0 @@
package com.minelittlepony.unicopia.command;
import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import com.minelittlepony.unicopia.Race;
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.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
class RaceArgument implements ArgumentType<Race> {
static final Collection<String> EXAMPLES = Arrays.stream(Race.values())
.filter(Race::isUsable)
.map(Race::name)
.collect(Collectors.toList());
@Override
public Race parse(StringReader reader) throws CommandSyntaxException {
return Race.fromName(reader.readUnquotedString(), Race.EARTH);
}
@Override
public <S> CompletableFuture<Suggestions> listSuggestions(final CommandContext<S> context, final SuggestionsBuilder builder) {
Arrays.stream(Race.values())
.filter(Race::isUsable)
.map(i -> i.name().toLowerCase())
.filter(i -> i.startsWith(builder.getRemaining().toLowerCase()))
.forEach(i -> builder.suggest(i.toLowerCase()));
return builder.buildFuture();
}
@Override
public Collection<String> getExamples() {
return EXAMPLES;
}
}

View file

@ -19,8 +19,10 @@ class RacelistCommand {
static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
LiteralArgumentBuilder<ServerCommandSource> builder = CommandManager.literal("racelist").requires(s -> s.hasPermissionLevel(4));
EnumArgumentType<Race> raceArgument = EnumArgumentType.of(Race.class, Race::isUsable, Race.EARTH);
builder.then(CommandManager.literal("allow")
.then(CommandManager.argument("race", new RaceArgument())
.then(CommandManager.argument("race", raceArgument)
.executes(context -> toggle(context.getSource(), context.getSource().getPlayer(), context.getArgument("race", Race.class), "allowed", race -> {
boolean result = Unicopia.getConfig().speciesWhiteList.get().add(race);
@ -30,7 +32,7 @@ class RacelistCommand {
}))
));
builder.then(CommandManager.literal("disallow")
.then(CommandManager.argument("race", new RaceArgument())
.then(CommandManager.argument("race", raceArgument)
.executes(context -> toggle(context.getSource(), context.getSource().getPlayer(), context.getArgument("race", Race.class), "disallowed", race -> {
boolean result = Unicopia.getConfig().speciesWhiteList.get().remove(race);

View file

@ -20,6 +20,8 @@ class SpeciesCommand {
static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
LiteralArgumentBuilder<ServerCommandSource> builder = CommandManager.literal("race");
EnumArgumentType<Race> raceArgument = EnumArgumentType.of(Race.class, Race::isUsable, Race.EARTH);
builder.then(CommandManager.literal("get")
.executes(context -> get(context.getSource(), context.getSource().getPlayer(), true))
.then(CommandManager.argument("target", EntityArgumentType.player())
@ -27,14 +29,14 @@ class SpeciesCommand {
));
builder.then(CommandManager.literal("set")
.then(CommandManager.argument("race", new RaceArgument())
.then(CommandManager.argument("race", raceArgument)
.executes(context -> set(context.getSource(), context.getSource().getPlayer(), context.getArgument("race", Race.class), true))
.then(CommandManager.argument("target", EntityArgumentType.player())
.executes(context -> set(context.getSource(), EntityArgumentType.getPlayer(context, "target"), context.getArgument("race", Race.class), false))
)));
builder.then(CommandManager.literal("describe")
.then(CommandManager.argument("race", new RaceArgument())
.then(CommandManager.argument("race", raceArgument)
.executes(context -> describe(context.getSource().getPlayer(), context.getArgument("race", Race.class))
)));

View file

@ -0,0 +1,95 @@
package com.minelittlepony.unicopia.command;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.FloatArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.LiteralText;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Hand;
class TraitCommand {
static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
LiteralArgumentBuilder<ServerCommandSource> builder = CommandManager
.literal("trait")
.requires(s -> s.hasPermissionLevel(4));
builder.then(CommandManager.literal("add")
.then(CommandManager.argument("trait", EnumArgumentType.of(Trait.class))
.then(CommandManager.argument("value", FloatArgumentType.floatArg()).executes(source -> add(
source.getSource(),
source.getSource().getPlayer(),
source.getArgument("trait", Trait.class),
FloatArgumentType.getFloat(source, "value")
)))
));
builder.then(CommandManager.literal("remove")
.then(CommandManager.argument("trait", EnumArgumentType.of(Trait.class)).executes(source -> remove(
source.getSource(),
source.getSource().getPlayer(),
source.getArgument("trait", Trait.class)
))
));
dispatcher.register(builder);
}
static int add(ServerCommandSource source, PlayerEntity player, Trait trait, float amount) throws CommandSyntaxException {
if (trait == null) {
source.sendError(new LiteralText("Invalid trait"));
return 0;
}
ItemStack stack = player.getMainHandStack();
if (stack.isEmpty()) {
source.sendError(new LiteralText("That trait cannot be added to the current item"));
return 0;
}
player.setStackInHand(Hand.MAIN_HAND, SpellTraits.union(SpellTraits.of(stack), new SpellTraits.Builder().with(trait, amount).build()).applyTo(stack));
return 0;
}
static int remove(ServerCommandSource source, PlayerEntity player, Trait trait) throws CommandSyntaxException {
if (trait == null) {
source.sendError(new LiteralText("Invalid trait"));
return 0;
}
ItemStack stack = player.getMainHandStack();
SpellTraits existing = SpellTraits.of(stack);
if (existing.get(trait) == 0) {
return 0;
}
player.setStackInHand(Hand.MAIN_HAND, existing.map((t, v) -> t == trait ? 0 : v).applyTo(stack));
return 0;
}
static int get(ServerCommandSource source, PlayerEntity player, Trait trait, float amount) throws CommandSyntaxException {
String translationKey = "commands.gravity.get";
Pony iplayer = Pony.of(player);
float gravity = iplayer.getPhysics().getGravityModifier();
if (source.getPlayer() == player) {
player.sendMessage(new TranslatableText(translationKey, gravity), false);
} else {
source.sendFeedback(new TranslatableText(translationKey + ".other", player.getName(), gravity), true);
}
return 0;
}
}