Add /racelist show and /racelist rest

This commit is contained in:
Sollace 2024-02-12 19:36:43 +00:00
parent db53f4906e
commit e97adc8841
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
13 changed files with 144 additions and 27 deletions

View file

@ -19,6 +19,7 @@ import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
import net.minecraft.command.argument.RegistryKeyArgumentType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import net.minecraft.registry.Registry;
@ -135,18 +136,19 @@ public record Race (Supplier<Composite> compositeSupplier, Availability availabi
public boolean isPermitted(@Nullable PlayerEntity sender) {
Set<String> whitelist = Unicopia.getConfig().speciesWhiteList.get();
return isUnset()
return this == HUMAN
|| isUnset()
|| whitelist.isEmpty()
|| whitelist.contains(getId().toString());
}
public Race validate(PlayerEntity sender) {
if (!isPermitted(sender)) {
if (this == EARTH) {
return HUMAN;
Race alternative = this == EARTH ? HUMAN : EARTH.validate(sender);
if (alternative != this && sender instanceof ServerPlayerEntity spe) {
spe.sendMessageToClient(Text.translatable("respawn.reason.illegal_race", getDisplayName()), false);
}
return EARTH.validate(sender);
return alternative;
}
return this;

View file

@ -1,12 +1,14 @@
package com.minelittlepony.unicopia.client;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import net.minecraft.client.MinecraftClient;
import net.minecraft.text.*;
public interface FlowingText {
public interface TextHelper {
static Stream<Text> wrap(Text text, int maxWidth) {
return MinecraftClient.getInstance().textRenderer.getTextHandler().wrapLines(text, maxWidth, Style.EMPTY).stream().map(line -> {
MutableText compiled = Text.literal("");
@ -17,4 +19,11 @@ public interface FlowingText {
return compiled;
});
}
static Text join(Text delimiter, Iterable<? extends MutableText> elements) {
MutableText initial = Text.empty();
return StreamSupport.stream(elements.spliterator(), false).collect(Collectors.reducing(initial, (a, b) -> {
return a == initial ? b : a.append(delimiter).append(b);
}));
}
}

View file

@ -9,7 +9,7 @@ import com.minelittlepony.common.client.gui.GameGui;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
import com.minelittlepony.unicopia.ability.magic.spell.*;
import com.minelittlepony.unicopia.client.FlowingText;
import com.minelittlepony.unicopia.client.TextHelper;
import com.minelittlepony.unicopia.client.render.model.SphereModel;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.UItems;
@ -195,7 +195,7 @@ public class DismissSpellScreen extends GameGui {
tooltip.add(ScreenTexts.EMPTY);
tooltip.add(Text.translatable("gui.unicopia.dispell_screen.affinity", actualSpell.getAffinity().name()).formatted(actualSpell.getAffinity().getColor()));
tooltip.add(ScreenTexts.EMPTY);
tooltip.addAll(FlowingText.wrap(Text.translatable(actualSpell.getType().getTranslationKey() + ".lore").formatted(actualSpell.getAffinity().getColor()), 180).toList());
tooltip.addAll(TextHelper.wrap(Text.translatable(actualSpell.getType().getTranslationKey() + ".lore").formatted(actualSpell.getAffinity().getColor()), 180).toList());
if (spell instanceof TimedSpell timed) {
tooltip.add(ScreenTexts.EMPTY);
tooltip.add(Text.translatable("gui.unicopia.dispell_screen.time_left", StringHelper.formatTicks(timed.getTimer().getTicksRemaining())));

View file

@ -14,7 +14,7 @@ import com.minelittlepony.unicopia.Debug;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
import com.minelittlepony.unicopia.client.FlowingText;
import com.minelittlepony.unicopia.client.TextHelper;
import com.minelittlepony.unicopia.client.gui.*;
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterList.*;
import com.minelittlepony.unicopia.compat.trinkets.TrinketSlotBackSprites;
@ -219,7 +219,7 @@ public class SpellbookScreen extends HandledScreen<SpellbookScreenHandler> imple
List<Text> tooltip = new ArrayList<>();
tooltip.add(spell.type().getName());
tooltip.addAll(FlowingText.wrap(Text.translatable(spell.type().getTranslationKey() + ".lore").formatted(spell.type().getAffinity().getColor()), 180).toList());
tooltip.addAll(TextHelper.wrap(Text.translatable(spell.type().getTranslationKey() + ".lore").formatted(spell.type().getAffinity().getColor()), 180).toList());
context.drawTooltip(textRenderer, tooltip, x, y);

View file

@ -9,7 +9,7 @@ import com.minelittlepony.common.client.gui.element.Label;
import com.minelittlepony.common.client.gui.sprite.TextureSprite;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.magic.spell.trait.*;
import com.minelittlepony.unicopia.client.FlowingText;
import com.minelittlepony.unicopia.client.TextHelper;
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterList.Chapter;
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookScreen.ImageButton;
import com.minelittlepony.unicopia.container.SpellbookState;
@ -191,7 +191,7 @@ public class SpellbookTraitDexPageContent implements SpellbookChapterList.Conten
.setTextureSize(16, 16)
.setSize(16, 16)
.setTexture(trait.getSprite()));
getStyle().setTooltip(Tooltip.of(FlowingText.wrap(trait.getTooltip(), 200).toList()));
getStyle().setTooltip(Tooltip.of(TextHelper.wrap(trait.getTooltip(), 200).toList()));
onClick(sender -> Pony.of(MinecraftClient.getInstance().player).getDiscoveries().markRead(trait));
}

View file

@ -1,13 +1,16 @@
package com.minelittlepony.unicopia.command;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Function;
import com.minelittlepony.unicopia.*;
import com.minelittlepony.unicopia.client.TextHelper;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
@ -15,8 +18,41 @@ class RacelistCommand {
static LiteralArgumentBuilder<ServerCommandSource> create() {
return CommandManager.literal("racelist").requires(s -> s.hasPermissionLevel(3))
.then(CommandManager.literal("show")
.executes(context -> {
context.getSource().sendFeedback(() -> {
Set<String> whitelist = Unicopia.getConfig().speciesWhiteList.get();
if (whitelist.isEmpty()) {
return Text.translatable("commands.racelist.inactive");
}
Set<MutableText> allowed = new HashSet<>();
Set<MutableText> unallowed = new HashSet<>();
Race.REGISTRY.forEach(race -> {
(race.isPermitted(null) ? allowed : unallowed).add(Text.translatable("commands.racelist.get.list_item",
race.getDisplayName(),
Text.literal(race.getId().toString()).formatted(Formatting.GRAY)
));
});
return Text.translatable("commands.racelist.get.allowed", allowed.size()).formatted(Formatting.YELLOW)
.append("\n").append(TextHelper.join(Text.literal("\n"), allowed))
.append("\n")
.append(Text.translatable("commands.racelist.get.not_allowed", unallowed.size()).formatted(Formatting.YELLOW))
.append("\n").append(TextHelper.join(Text.literal("\n"), unallowed));
}, false);
return 0;
})
)
.then(CommandManager.literal("reset")
.executes(context -> {
Unicopia.getConfig().speciesWhiteList.get().clear();
Unicopia.getConfig().save();
context.getSource().sendFeedback(() -> Text.translatable("commands.racelist.clear.success").formatted(Formatting.GREEN), false);
return 0;
})
)
.then(CommandManager.literal("allow")
.then(CommandManager.argument("race", Race.argument())
.then(CommandManager.argument("race", Race.argument()).suggests(UCommandSuggestion.ALL_RACE_SUGGESTIONS)
.executes(context -> toggle(context.getSource(), context.getSource().getPlayer(), Race.fromArgument(context, "race"), "allowed", race -> {
if (race.isUnset()) {
@ -31,7 +67,7 @@ class RacelistCommand {
}))
))
.then(CommandManager.literal("disallow")
.then(CommandManager.argument("race", Race.argument())
.then(CommandManager.argument("race", Race.argument()).suggests(UCommandSuggestion.ALL_RACE_SUGGESTIONS)
.executes(context -> toggle(context.getSource(), context.getSource().getPlayer(), Race.fromArgument(context, "race"), "disallowed", race -> {
boolean result = Unicopia.getConfig().speciesWhiteList.get().remove(race.getId().toString());

View file

@ -6,7 +6,6 @@ import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.network.Channel;
import com.minelittlepony.unicopia.network.MsgTribeSelect;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import net.minecraft.command.argument.EntityArgumentType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.command.CommandManager;
@ -38,13 +37,13 @@ class SpeciesCommand {
.executes(context -> get(context.getSource(), EntityArgumentType.getPlayer(context, "target"), false))
))
.then(CommandManager.literal("set")
.then(CommandManager.argument("race", Race.argument())
.then(CommandManager.argument("race", Race.argument()).suggests(UCommandSuggestion.ALL_RACE_SUGGESTIONS)
.executes(context -> set(context.getSource(), context.getSource().getPlayer(), Race.fromArgument(context, "race"), true))
.then(CommandManager.argument("target", EntityArgumentType.player())
.executes(context -> set(context.getSource(), EntityArgumentType.getPlayer(context, "target"), Race.fromArgument(context, "race"), false)))
))
.then(CommandManager.literal("describe")
.then(CommandManager.argument("race", Race.argument())
.then(CommandManager.argument("race", Race.argument()).suggests(UCommandSuggestion.ALL_RACE_SUGGESTIONS)
.executes(context -> describe(context.getSource().getPlayer(), Race.fromArgument(context, "race")))
))
.then(CommandManager.literal("list")
@ -60,7 +59,7 @@ class SpeciesCommand {
pony.setDirty();
if (race.isUnset()) {
Channel.SERVER_SELECT_TRIBE.sendToPlayer(new MsgTribeSelect(Race.allPermitted(player), "gui.unicopia.tribe_selection.respawn"), (ServerPlayerEntity)player);
Channel.SERVER_SELECT_TRIBE.sendToPlayer(new MsgTribeSelect(Race.allPermitted(player), "gui.unicopia.tribe_selection.welcome"), (ServerPlayerEntity)player);
}
if (player == source.getPlayer()) {

View file

@ -0,0 +1,62 @@
package com.minelittlepony.unicopia.command;
import java.util.Locale;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.Race;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import net.minecraft.command.CommandSource;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.util.Identifier;
public class UCommandSuggestion {
public static final SuggestionProvider<ServerCommandSource> ALL_RACE_SUGGESTIONS = suggestFromRegistry(Race.REGISTRY_KEY);
public static final SuggestionProvider<ServerCommandSource> ALLOWED_RACE_SUGGESTIONS = suggestFromRegistry(Race.REGISTRY_KEY, (context, race) -> race.isPermitted(context.getSource().getPlayer()));
public static <T> SuggestionProvider<ServerCommandSource> suggestFromRegistry(RegistryKey<? extends Registry<T>> registryKey, @Nullable BiPredicate<CommandContext<ServerCommandSource>, T> filter) {
return (context, builder) -> {
Registry<T> registry = context.getSource().getRegistryManager().get(registryKey);
return suggestIdentifiers(
filter == null ? registry : registry.stream().filter(v -> filter.test(context, v))::iterator,
registry::getId,
builder, registryKey.getValue().getNamespace());
};
}
public static <T> SuggestionProvider<ServerCommandSource> suggestFromRegistry(RegistryKey<? extends Registry<T>> registryKey) {
return suggestFromRegistry(registryKey, null);
}
public static <T> CompletableFuture<Suggestions> suggestIdentifiers(Iterable<T> candidates, Function<T, Identifier> idFunc, SuggestionsBuilder builder, String defaultNamespace) {
forEachMatching(candidates, builder.getRemaining().toLowerCase(Locale.ROOT), idFunc, id -> builder.suggest(idFunc.apply(id).toString()), defaultNamespace);
return builder.buildFuture();
}
public static <T> void forEachMatching(Iterable<T> candidates, String input, Function<T, Identifier> idFunc, Consumer<T> consumer, String defaultNamespace) {
final boolean hasNamespaceDelimiter = input.indexOf(58) > -1;
for (T object : candidates) {
final Identifier id = idFunc.apply(object);
if (hasNamespaceDelimiter) {
if (CommandSource.shouldSuggest(input, id.toString())) {
consumer.accept(object);
}
} else {
if (CommandSource.shouldSuggest(input, id.getNamespace())
|| (id.getNamespace().equals(defaultNamespace) && CommandSource.shouldSuggest(input, id.getPath()))
) {
consumer.accept(object);
}
}
}
}
}

View file

@ -14,7 +14,7 @@ class WorldTribeCommand {
return CommandManager.literal("worldtribe").requires(s -> s.hasPermissionLevel(3))
.then(CommandManager.literal("get").executes(context -> get(context.getSource())))
.then(CommandManager.literal("set")
.then(CommandManager.argument("race", Race.argument())
.then(CommandManager.argument("race", Race.argument()).suggests(UCommandSuggestion.ALLOWED_RACE_SUGGESTIONS)
.executes(context -> set(context.getSource(), Race.fromArgument(context, "race")))));
}

View file

@ -231,7 +231,7 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
public void setSpecies(Race race) {
race = race.validate(entity);
Race current = getSpecies();
entity.getDataTracker().set(RACE, Race.REGISTRY.getId(race.validate(entity)).toString());
entity.getDataTracker().set(RACE, race.getId().toString());
if (race != current) {
clearSuppressedRace();
}
@ -244,7 +244,7 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
}
public void setSuppressedRace(Race race) {
entity.getDataTracker().set(SUPPRESSED_RACE, Race.REGISTRY.getId(race.validate(entity)).toString());
entity.getDataTracker().set(SUPPRESSED_RACE, race.validate(entity).getId().toString());
}
public void clearSuppressedRace() {

View file

@ -10,7 +10,7 @@ import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.client.FlowingText;
import com.minelittlepony.unicopia.client.TextHelper;
import com.minelittlepony.unicopia.entity.player.PlayerCharmTracker;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.group.MultiItem;
@ -90,7 +90,7 @@ public class GemstoneItem extends Item implements MultiItem, EnchantableItem {
line = line.formatted(Formatting.OBFUSCATED);
}
lines.addAll(FlowingText.wrap(line, 180).toList());
lines.addAll(TextHelper.wrap(line, 180).toList());
}
}

View file

@ -36,7 +36,11 @@ public record MsgRequestSpeciesChange (
Pony player = Pony.of(sender);
if (force || player.getSpecies().isUnset()) {
player.setSpecies(newRace.isPermitted(sender) ? newRace : UnicopiaWorldProperties.forWorld((ServerWorld)player.asWorld()).getDefaultRace());
boolean permitted = newRace.isPermitted(sender);
player.setSpecies(permitted ? newRace : UnicopiaWorldProperties.forWorld((ServerWorld)player.asWorld()).getDefaultRace());
if (!permitted) {
sender.sendMessageToClient(Text.translatable("respawn.reason.illegal_race", newRace.getDisplayName()), false);
}
if (force) {
if (sender.getWorld().getGameRules().getBoolean(UGameRules.ANNOUNCE_TRIBE_JOINS)) {

View file

@ -699,6 +699,7 @@
"gui.unicopia.page_num": "%d of %d",
"respawn.reason.joined_new_tribe": "%1$s was reborn as a %2$s",
"respawn.reason.illegal_race": "The %s race is not permitted by your server's configuration.",
"gui.unicopia.tribe_selection.respawn": "You have died.",
"gui.unicopia.tribe_selection.respawn.journey": "But the end is not all, for at the end of every end is another beginning.",
@ -1327,7 +1328,12 @@
"commands.racelist.illegal": "The default race %s cannot be used with this command.",
"commands.racelist.allowed": "Added %1$s to the whitelist.",
"commands.racelist.allowed.failed": "%1$s is already whitelisted.",
"commands.racelist.get.allowed": "Allowed (%s):",
"commands.racelist.get.not_allowed": "Not Allowed (%s):",
"commands.racelist.get.list_item": "- %s (%s)",
"commands.racelist.clear.success": "Disabled Whitelist",
"commands.racelist.allowed.failed": "%1$s is already allowed.",
"commands.racelist.inactive": "The allowlist is not active. Add races with /unicopia racelist allow <race> to configure it.",
"commands.racelist.disallowed": "Removed %1$s from the whitelist.",
"commands.racelist.disallowed.failed": "%1$s is not on the whitelist.",
@ -1335,7 +1341,6 @@
"commands.worldtribe.success.get": "Default race for all new players is currently set to: %s",
"commands.worldtribe.success.set": "Set default race for new players is now set to: %s",
"commands.disguise.usage": "/disguise <player> <entity> [nbt]",
"commands.disguise.notfound": "The entity id '%s' does not exist.",
"commands.disguise.removed": "Your disguise has been removed.",
"commands.disguise.removed.self": "Removed own disguise.",