From 09e0bcd7b2ebb7a0e7fed5a7a44e38ed6b0a65d7 Mon Sep 17 00:00:00 2001 From: Sollace Date: Sat, 27 Aug 2022 15:07:29 +0200 Subject: [PATCH] Rewrite races to use a registry --- .../com/minelittlepony/unicopia/Race.java | 83 ++++++------ .../com/minelittlepony/unicopia/Unicopia.java | 7 +- .../unicopia/WorldTribeManager.java | 4 +- .../advancement/CustomEventCriterion.java | 4 +- .../advancement/RaceChangeCriterion.java | 4 +- .../client/gui/LanSettingsScreen.java | 37 +++--- .../unicopia/client/gui/SettingsScreen.java | 24 ++-- .../unicopia/client/gui/TribeButton.java | 7 +- .../client/gui/TribeConfirmationScreen.java | 9 +- .../client/gui/TribeSelectionScreen.java | 2 +- .../unicopia/command/Commands.java | 10 +- .../unicopia/command/EnumArgumentType.java | 7 -- .../unicopia/command/RacelistCommand.java | 5 +- .../unicopia/command/SpeciesCommand.java | 16 +-- .../unicopia/entity/ItemImpl.java | 15 ++- .../entity/effect/RaceChangeStatusEffect.java | 36 +++--- .../unicopia/entity/effect/UPotions.java | 16 +-- .../unicopia/entity/player/Pony.java | 12 +- .../unicopia/item/toxin/Toxic.java | 6 +- .../network/MsgPlayerCapabilities.java | 4 +- .../network/MsgRequestSpeciesChange.java | 4 +- .../unicopia/network/MsgTribeSelect.java | 6 +- .../unicopia/util/Registries.java | 10 +- .../unicopia/util/RegistryIndexer.java | 54 ++++++++ .../resources/assets/unicopia/lang/en_us.json | 118 +++++++++--------- 25 files changed, 283 insertions(+), 217 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/util/RegistryIndexer.java diff --git a/src/main/java/com/minelittlepony/unicopia/Race.java b/src/main/java/com/minelittlepony/unicopia/Race.java index e1efa88e..da67542b 100644 --- a/src/main/java/com/minelittlepony/unicopia/Race.java +++ b/src/main/java/com/minelittlepony/unicopia/Race.java @@ -1,42 +1,55 @@ package com.minelittlepony.unicopia; -import java.util.Arrays; -import java.util.Collection; -import java.util.Map; import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; import org.jetbrains.annotations.Nullable; import com.google.common.base.Strings; -import com.minelittlepony.common.client.gui.sprite.TextureSprite; -import com.minelittlepony.common.client.gui.style.Style; import com.minelittlepony.unicopia.ability.magic.Affine; +import com.minelittlepony.unicopia.util.Registries; +import net.minecraft.command.argument.RegistryKeyArgumentType; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.text.Text; import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; +import net.minecraft.util.registry.RegistryKey; + +public final class Race implements Affine { + public static final String DEFAULT_ID = "unicopia:human"; + public static final Registry REGISTRY = Registries.createDefaulted(Unicopia.id("race"), DEFAULT_ID); + public static final RegistryKey> REGISTRY_KEY = REGISTRY.getKey(); + + public static Race register(String name, boolean magic, FlightType flight, boolean earth) { + return register(Unicopia.id(name), magic, flight, earth); + } + + public static Race register(Identifier id, boolean magic, FlightType flight, boolean earth) { + return Registry.register(REGISTRY, id, new Race(magic, flight, earth)); + } + + public static RegistryKeyArgumentType argument() { + return RegistryKeyArgumentType.registryKey(REGISTRY_KEY); + } -public enum Race implements Affine { /** * The default, unset race. * This is used if there are no other races. */ - HUMAN(false, FlightType.NONE, false), - EARTH(false, FlightType.NONE, true), - UNICORN(true, FlightType.NONE, false), - PEGASUS(false, FlightType.AVIAN, false), - BAT(false, FlightType.AVIAN, false), - ALICORN(true, FlightType.AVIAN, true), - CHANGELING(false, FlightType.INSECTOID, false); + public static final Race HUMAN = register("human", false, FlightType.NONE, false); + public static final Race EARTH = register("earth", false, FlightType.NONE, true); + public static final Race UNICORN = register("unicorn", true, FlightType.NONE, false); + public static final Race PEGASUS = register("pegasus", false, FlightType.AVIAN, false); + public static final Race BAT = register("bat", false, FlightType.AVIAN, false); + public static final Race ALICORN = register("alicorn", true, FlightType.AVIAN, true); + public static final Race CHANGELING = register("changeling", false, FlightType.INSECTOID, false); + + public static void bootstrap() {} private final boolean magic; private final FlightType flight; private final boolean earth; - private final static Map REGISTRY = Arrays.stream(values()).collect(Collectors.toMap(Enum::ordinal, Function.identity())); - Race(boolean magic, FlightType flight, boolean earth) { this.magic = magic; this.flight = flight; @@ -93,7 +106,8 @@ public enum Race implements Affine { } public String getTranslationKey() { - return String.format("unicopia.race.%s", name().toLowerCase()); + Identifier id = REGISTRY.getId(this); + return String.format("%s.race.%s", id.getNamespace(), id.getPath().toLowerCase()); } public boolean isPermitted(@Nullable PlayerEntity sender) { @@ -120,45 +134,26 @@ public enum Race implements Affine { return this; } - public Style createStyle() { - return new Style() - .setIcon(new TextureSprite() - .setPosition(2, 2) - .setSize(16, 16) - .setTexture(new Identifier("unicopia", "textures/gui/icons.png")) - .setTextureOffset((16 * ordinal()) % 256, (ordinal() / 256) * 16) - ) - .setTooltip(getTranslationKey(), 0, 10); - } - public boolean equals(String s) { - return name().equalsIgnoreCase(s) + return REGISTRY.getId(this).toString().equalsIgnoreCase(s) || getTranslationKey().equalsIgnoreCase(s); } public static Race fromName(String s, Race def) { if (!Strings.isNullOrEmpty(s)) { - for (Race i : values()) { - if (i.equals(s)) return i; + Identifier id = Identifier.tryParse(s); + if (id != null) { + if (id.getNamespace() == Identifier.DEFAULT_NAMESPACE) { + id = new Identifier(Unicopia.DEFAULT_NAMESPACE, id.getPath()); + } + return REGISTRY.getOrEmpty(id).orElse(def); } } - try { - return fromId(Integer.parseInt(s)); - } catch (NumberFormatException e) { } - return def; } - public static Collection all() { - return REGISTRY.values(); - } - public static Race fromName(String name) { return fromName(name, EARTH); } - - public static Race fromId(int id) { - return REGISTRY.getOrDefault(id, EARTH); - } } diff --git a/src/main/java/com/minelittlepony/unicopia/Unicopia.java b/src/main/java/com/minelittlepony/unicopia/Unicopia.java index 58cd8360..1a5d7628 100644 --- a/src/main/java/com/minelittlepony/unicopia/Unicopia.java +++ b/src/main/java/com/minelittlepony/unicopia/Unicopia.java @@ -4,6 +4,7 @@ import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; import net.fabricmc.fabric.api.resource.ResourceManagerHelper; import net.minecraft.resource.ResourceType; +import net.minecraft.util.Identifier; import java.util.Optional; @@ -23,7 +24,7 @@ import com.minelittlepony.unicopia.item.enchantment.UEnchantments; import com.minelittlepony.unicopia.network.Channel; public class Unicopia implements ModInitializer { - + public static final String DEFAULT_NAMESPACE = "unicopia"; public static final Logger LOGGER = LogManager.getLogger(); public static SidedAccess SIDE = Optional::empty; @@ -37,6 +38,10 @@ public class Unicopia implements ModInitializer { return CONFIG; } + public static Identifier id(String name) { + return new Identifier(DEFAULT_NAMESPACE, name); + } + public Unicopia() { getConfig(); } diff --git a/src/main/java/com/minelittlepony/unicopia/WorldTribeManager.java b/src/main/java/com/minelittlepony/unicopia/WorldTribeManager.java index 658af33b..961f4555 100644 --- a/src/main/java/com/minelittlepony/unicopia/WorldTribeManager.java +++ b/src/main/java/com/minelittlepony/unicopia/WorldTribeManager.java @@ -14,7 +14,7 @@ public class WorldTribeManager extends PersistentState { public WorldTribeManager() {} public WorldTribeManager(NbtCompound nbt) { - defaultRace = Race.fromName(nbt.getString("defaultRace")); + defaultRace = Race.fromName(nbt.getString("defaultRace"), Race.HUMAN); } public Race getDefaultRace() { @@ -27,7 +27,7 @@ public class WorldTribeManager extends PersistentState { @Override public NbtCompound writeNbt(NbtCompound tag) { - tag.putString("defaultRace", defaultRace.name()); + tag.putString("defaultRace", Race.REGISTRY.getId(defaultRace).toString()); return tag; } diff --git a/src/main/java/com/minelittlepony/unicopia/advancement/CustomEventCriterion.java b/src/main/java/com/minelittlepony/unicopia/advancement/CustomEventCriterion.java index afbb7e40..4312143a 100644 --- a/src/main/java/com/minelittlepony/unicopia/advancement/CustomEventCriterion.java +++ b/src/main/java/com/minelittlepony/unicopia/advancement/CustomEventCriterion.java @@ -36,7 +36,7 @@ public class CustomEventCriterion extends AbstractCriterion { - races.add(Race.fromName(el.getAsString())); + races.add(Race.fromName(el.getAsString(), Race.EARTH)); }); } @@ -93,7 +93,7 @@ public class CustomEventCriterion extends AbstractCriterion arr.add(r.name().toLowerCase())); + races.forEach(r -> arr.add(Race.REGISTRY.getId(r).toString())); json.add("race", arr); } if (flying != null) { diff --git a/src/main/java/com/minelittlepony/unicopia/advancement/RaceChangeCriterion.java b/src/main/java/com/minelittlepony/unicopia/advancement/RaceChangeCriterion.java index 2e862452..196ad69d 100644 --- a/src/main/java/com/minelittlepony/unicopia/advancement/RaceChangeCriterion.java +++ b/src/main/java/com/minelittlepony/unicopia/advancement/RaceChangeCriterion.java @@ -25,7 +25,7 @@ public class RaceChangeCriterion extends AbstractCriterion races = RegistryIndexer.of(Race.REGISTRY); return new Cycler(screen.width / 2 + 110, 60, 20, 20) { @Override protected void renderForground(MatrixStack matrices, MinecraftClient mc, int mouseX, int mouseY, int foreColor) { @@ -152,18 +168,11 @@ public class LanSettingsScreen extends GameGui { renderToolTip(matrices, screen, mouseX, mouseY); } } - }.setStyles( - Race.EARTH.createStyle(), - Race.UNICORN.createStyle(), - Race.PEGASUS.createStyle(), - Race.BAT.createStyle(), - Race.ALICORN.createStyle(), - Race.CHANGELING.createStyle() - ).onChange(i -> { - Unicopia.getConfig().preferredRace.set(Race.fromId(i + 1)); + }.setStyles(Race.REGISTRY.stream().map(LanSettingsScreen::createStyle).toArray(Style[]::new)).onChange(i -> { + Unicopia.getConfig().preferredRace.set(races.valueOf(i)); Unicopia.getConfig().save(); return i; - }).setValue(MathHelper.clamp(Unicopia.getConfig().preferredRace.get().ordinal() - 1, 0, 5)); + }).setValue(races.indexOf(Unicopia.getConfig().preferredRace.get())); } } diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/SettingsScreen.java b/src/main/java/com/minelittlepony/unicopia/client/gui/SettingsScreen.java index 5fbe0d50..3193780f 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/SettingsScreen.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/SettingsScreen.java @@ -4,15 +4,11 @@ import org.jetbrains.annotations.Nullable; import com.minelittlepony.common.client.gui.GameGui; import com.minelittlepony.common.client.gui.ScrollContainer; -import com.minelittlepony.common.client.gui.element.Button; -import com.minelittlepony.common.client.gui.element.EnumSlider; -import com.minelittlepony.common.client.gui.element.Label; -import com.minelittlepony.common.client.gui.element.Toggle; +import com.minelittlepony.common.client.gui.element.*; import com.minelittlepony.common.client.gui.style.Style; -import com.minelittlepony.unicopia.Config; -import com.minelittlepony.unicopia.Unicopia; -import com.minelittlepony.unicopia.WorldTribeManager; +import com.minelittlepony.unicopia.*; import com.minelittlepony.unicopia.client.minelittlepony.MineLPConnector; +import com.minelittlepony.unicopia.util.RegistryIndexer; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.MinecraftClient; @@ -73,9 +69,11 @@ public class SettingsScreen extends GameGui { mineLpStatus = content.addButton(new Label(LEFT, row += 10)).getStyle().setText(getMineLPStatus()); - content.addButton(new EnumSlider<>(LEFT, row += 25, config.preferredRace.get())) - .onChange(config.preferredRace::set) - .setTextFormat(v -> Text.translatable("unicopia.options.preferred_race", v.getValue().getDisplayName())); + RegistryIndexer races = RegistryIndexer.of(Race.REGISTRY); + + content.addButton(new Slider(LEFT, row += 25, 0, races.size(), races.indexOf(config.preferredRace.get()))) + .onChange(races.createSetter(config.preferredRace::set)) + .setTextFormat(v -> Text.translatable("unicopia.options.preferred_race", races.valueOf(v.getValue()).getDisplayName())); IntegratedServer server = client.getServer(); if (server != null) { @@ -84,9 +82,9 @@ public class SettingsScreen extends GameGui { WorldTribeManager tribes = WorldTribeManager.forWorld((ServerWorld)server.getPlayerManager().getPlayer(MinecraftClient.getInstance().player.getUuid()).world); - content.addButton(new EnumSlider<>(LEFT, row += 20, tribes.getDefaultRace())) - .onChange(tribes::setDefaultRace) - .setTextFormat(v -> Text.translatable("unicopia.options.world.default_race", v.getValue().getDisplayName())) + content.addButton(new Slider(LEFT, row += 20, 0, races.size(), races.indexOf(tribes.getDefaultRace()))) + .onChange(races.createSetter(tribes::setDefaultRace)) + .setTextFormat(v -> Text.translatable("unicopia.options.world.default_race", races.valueOf(v.getValue()).getDisplayName())) .setEnabled(client.isInSingleplayer()); } } diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/TribeButton.java b/src/main/java/com/minelittlepony/unicopia/client/gui/TribeButton.java index 505d38fb..3cd4d45f 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/TribeButton.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/TribeButton.java @@ -10,6 +10,7 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.GameRenderer; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.text.Text; +import net.minecraft.util.Identifier; import net.minecraft.util.math.MathHelper; public class TribeButton extends Button { @@ -23,6 +24,7 @@ public class TribeButton extends Button { this.race = race; int size = 32; int textureSize = 512; + int ordinal = Race.REGISTRY.getRawId(race); getStyle() .setIcon(new TextureSprite() @@ -30,7 +32,7 @@ public class TribeButton extends Button { .setSize(size, size) .setTextureSize(textureSize, textureSize) .setTexture(TribeSelectionScreen.ICONS) - .setTextureOffset((size * race.ordinal()) % textureSize, (race.ordinal() / textureSize) * size) + .setTextureOffset((size * ordinal) % textureSize, (ordinal / textureSize) * size) ) .setText(race.getTranslationKey()); } @@ -54,7 +56,8 @@ public class TribeButton extends Button { drawTexture(matrices, x - 4, y - 14, 76, 0, 78, 71); if (hovered && screenWidth > 0) { - drawCenteredText(matrices, getFont(), Text.translatable("gui.unicopia.tribe_selection.describe." + race.name().toLowerCase()), screenWidth / 2, y + height, 0xFFFFFFFF); + Identifier id = Race.REGISTRY.getId(race); + drawCenteredText(matrices, getFont(), Text.translatable("gui.unicopia.tribe_selection.describe." + id.getNamespace() + "." + id.getPath()), screenWidth / 2, y + height, 0xFFFFFFFF); } } diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/TribeConfirmationScreen.java b/src/main/java/com/minelittlepony/unicopia/client/gui/TribeConfirmationScreen.java index 7bf774ed..9697afe9 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/TribeConfirmationScreen.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/TribeConfirmationScreen.java @@ -11,8 +11,7 @@ import it.unimi.dsi.fastutil.booleans.BooleanConsumer; import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.text.Text; -import net.minecraft.util.Formatting; -import net.minecraft.util.Language; +import net.minecraft.util.*; public class TribeConfirmationScreen extends GameGui implements HidesHud { private final Race selection; @@ -53,8 +52,10 @@ public class TribeConfirmationScreen extends GameGui implements HidesHud { int maxWidth = 280; + Identifier id = Race.REGISTRY.getId(selection); + for (int i = 0; i < 5; i++) { - String key = String.format("gui.unicopia.tribe_selection.confirm.goods.%d.%s", i, selection.name().toLowerCase()); + String key = String.format("gui.unicopia.tribe_selection.confirm.goods.%d.%s.%s", i, id.getNamespace(), id.getPath()); if (Language.getInstance().hasTranslation(key)) { TextBlock block = addDrawable(new TextBlock(left, top, maxWidth)); block.getStyle().setText(Text.translatable(key)); @@ -67,7 +68,7 @@ public class TribeConfirmationScreen extends GameGui implements HidesHud { top += 15; for (int i = 0; i < 5; i++) { - String key = String.format("gui.unicopia.tribe_selection.confirm.bads.%d.%s", i, selection.name().toLowerCase()); + String key = String.format("gui.unicopia.tribe_selection.confirm.bads.%d.%s.%s", i, id.getNamespace(), id.getPath()); if (Language.getInstance().hasTranslation(key)) { TextBlock block = addDrawable(new TextBlock(left, top, maxWidth)); block.getStyle().setText(Text.translatable(key)); diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/TribeSelectionScreen.java b/src/main/java/com/minelittlepony/unicopia/client/gui/TribeSelectionScreen.java index a4436d9d..7a3a4b1b 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/TribeSelectionScreen.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/TribeSelectionScreen.java @@ -53,7 +53,7 @@ public class TribeSelectionScreen extends GameGui implements HidesHud { final int itemWidth = 70; - List options = Race.all().stream().filter(race -> !race.isDefault() && !race.isOp()).toList(); + List options = Race.REGISTRY.stream().filter(race -> !race.isDefault() && !race.isOp()).toList(); int totalWidth = options.size() * (itemWidth + 10) - 10; diff --git a/src/main/java/com/minelittlepony/unicopia/command/Commands.java b/src/main/java/com/minelittlepony/unicopia/command/Commands.java index 5417802d..9322fd5a 100644 --- a/src/main/java/com/minelittlepony/unicopia/command/Commands.java +++ b/src/main/java/com/minelittlepony/unicopia/command/Commands.java @@ -1,15 +1,21 @@ package com.minelittlepony.unicopia.command; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; + +import com.minelittlepony.unicopia.Unicopia; + import net.fabricmc.fabric.api.command.v2.ArgumentTypeRegistry; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.server.MinecraftServer; -import net.minecraft.util.Identifier; public class Commands { @SuppressWarnings({ "deprecation", "unchecked", "rawtypes" }) public static void bootstrap() { - ArgumentTypeRegistry.registerArgumentType(new Identifier("unicopia", "enumeration"), EnumArgumentType.class, new EnumArgumentType.Serializer()); + ArgumentTypeRegistry.registerArgumentType( + Unicopia.id("enumeration"), + EnumArgumentType.class, + new EnumArgumentType.Serializer() + ); CommandRegistrationCallback.EVENT.register((dispatcher, access, environment) -> { SpeciesCommand.register(dispatcher); RacelistCommand.register(dispatcher); diff --git a/src/main/java/com/minelittlepony/unicopia/command/EnumArgumentType.java b/src/main/java/com/minelittlepony/unicopia/command/EnumArgumentType.java index d3b104d4..eeee14ea 100644 --- a/src/main/java/com/minelittlepony/unicopia/command/EnumArgumentType.java +++ b/src/main/java/com/minelittlepony/unicopia/command/EnumArgumentType.java @@ -11,7 +11,6 @@ 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; @@ -29,12 +28,6 @@ import net.minecraft.network.PacketByteBuf; class EnumArgumentType> implements ArgumentType, Serializable { private static final long serialVersionUID = 3731493854867412243L; - private static final EnumArgumentType RACE = of(Race.class, Race::isUsable, Race.EARTH); - - public static EnumArgumentType race() { - return RACE; - } - public static > EnumArgumentType of(Class type, Predicate filter, T def) { return new EnumArgumentType<>(type, filter, def); } diff --git a/src/main/java/com/minelittlepony/unicopia/command/RacelistCommand.java b/src/main/java/com/minelittlepony/unicopia/command/RacelistCommand.java index 9307432c..a1aa1edb 100644 --- a/src/main/java/com/minelittlepony/unicopia/command/RacelistCommand.java +++ b/src/main/java/com/minelittlepony/unicopia/command/RacelistCommand.java @@ -7,6 +7,7 @@ import com.minelittlepony.unicopia.Unicopia; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import net.minecraft.command.argument.RegistryKeyArgumentType; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; @@ -18,7 +19,7 @@ class RacelistCommand { static void register(CommandDispatcher dispatcher) { LiteralArgumentBuilder builder = CommandManager.literal("racelist").requires(s -> s.hasPermissionLevel(4)); - EnumArgumentType raceArgument = EnumArgumentType.of(Race.class, Race::isUsable, Race.EARTH); + RegistryKeyArgumentType raceArgument = Race.argument(); builder.then(CommandManager.literal("allow") .then(CommandManager.argument("race", raceArgument) @@ -51,7 +52,7 @@ class RacelistCommand { translationKey += ".failed"; } - Text formattedName = Text.translatable(race.name().toLowerCase()).formatted(Formatting.GOLD); + Text formattedName = race.getDisplayName().copy().formatted(Formatting.GOLD); source.sendFeedback(Text.translatable(translationKey, formattedName).formatted(Formatting.GREEN), false); return 0; diff --git a/src/main/java/com/minelittlepony/unicopia/command/SpeciesCommand.java b/src/main/java/com/minelittlepony/unicopia/command/SpeciesCommand.java index 937112dd..84590154 100644 --- a/src/main/java/com/minelittlepony/unicopia/command/SpeciesCommand.java +++ b/src/main/java/com/minelittlepony/unicopia/command/SpeciesCommand.java @@ -6,6 +6,7 @@ import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import net.minecraft.command.argument.EntityArgumentType; +import net.minecraft.command.argument.RegistryKeyArgumentType; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; @@ -18,7 +19,7 @@ class SpeciesCommand { static void register(CommandDispatcher dispatcher) { LiteralArgumentBuilder builder = CommandManager.literal("race"); - EnumArgumentType raceArgument = EnumArgumentType.of(Race.class, Race::isUsable, Race.EARTH); + RegistryKeyArgumentType raceArgument = Race.argument(); builder.then(CommandManager.literal("get") .executes(context -> get(context.getSource(), context.getSource().getPlayer(), true)) @@ -52,15 +53,13 @@ class SpeciesCommand { pony.setSpecies(race); pony.setDirty(); - Text formattedName = Text.translatable(race.name().toLowerCase()); - if (!isSelf) { - source.sendFeedback(Text.translatable("commands.race.success.other", player.getName(), formattedName), true); + source.sendFeedback(Text.translatable("commands.race.success.other", player.getName(), race.getDisplayName()), true); } else { if (player.getEntityWorld().getGameRules().getBoolean(GameRules.SEND_COMMAND_FEEDBACK)) { player.sendMessage(Text.translatable("commands.race.success.self"), false); } - source.sendFeedback(Text.translatable("commands.race.success.otherself", player.getName(), formattedName), true); + source.sendFeedback(Text.translatable("commands.race.success.otherself", player.getName(), race.getDisplayName()), true); } } else if (player.getEntityWorld().getGameRules().getBoolean(GameRules.SEND_COMMAND_FEEDBACK)) { player.sendMessage(Text.translatable("commands.race.permission"), false); @@ -88,9 +87,10 @@ class SpeciesCommand { MutableText message = Text.literal(""); boolean first = true; - for (Race i : Race.values()) { + for (Race i : Race.REGISTRY) { if (!i.isDefault() && i.isPermitted(player)) { - message.append(Text.translatable((!first ? "\n" : "") + " - " + i.name().toLowerCase())); + message.append(Text.literal((!first ? "\n" : "") + " - ")); + message.append(i.getDisplayName()); first = false; } } @@ -101,7 +101,7 @@ class SpeciesCommand { } static int describe(PlayerEntity player, Race species) { - String name = species.name().toLowerCase(); + String name = species.getTranslationKey(); player.sendMessage(Text.translatable(String.format("commands.race.describe.%s.1", name)).styled(s -> s.withColor(Formatting.YELLOW)), false); player.sendMessage(Text.translatable(String.format("commands.race.describe.%s.2", name)), false); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/ItemImpl.java b/src/main/java/com/minelittlepony/unicopia/entity/ItemImpl.java index 54c7a258..3933c83a 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/ItemImpl.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/ItemImpl.java @@ -21,6 +21,7 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; import net.minecraft.particle.ParticleEffect; import net.minecraft.particle.ParticleTypes; import net.minecraft.util.ActionResult; @@ -28,7 +29,7 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.random.Random; public class ItemImpl implements Equine, Owned { - private static final TrackedData ITEM_RACE = DataTracker.registerData(ItemEntity.class, TrackedDataHandlerRegistry.INTEGER); + private static final TrackedData ITEM_RACE = DataTracker.registerData(ItemEntity.class, TrackedDataHandlerRegistry.STRING); static final TrackedData ITEM_GRAVITY = DataTracker.registerData(ItemEntity.class, TrackedDataHandlerRegistry.FLOAT); private final ItemEntity owner; @@ -41,7 +42,7 @@ public class ItemImpl implements Equine, Owned { this.owner = owner; this.physics = new ItemPhysics(owner); owner.getDataTracker().startTracking(ITEM_GRAVITY, 1F); - owner.getDataTracker().startTracking(ITEM_RACE, Race.HUMAN.ordinal()); + owner.getDataTracker().startTracking(ITEM_RACE, Race.REGISTRY.getId(Race.HUMAN).toString()); } @Override @@ -135,23 +136,25 @@ public class ItemImpl implements Equine, Owned { @Override public Race getSpecies() { - return Race.fromId(owner.getDataTracker().get(ITEM_RACE)); + return Race.fromName(owner.getDataTracker().get(ITEM_RACE), Race.HUMAN); } @Override public void setSpecies(Race race) { - owner.getDataTracker().set(ITEM_RACE, race.ordinal()); + owner.getDataTracker().set(ITEM_RACE, Race.REGISTRY.getId(race).toString()); } @Override public void toNBT(NbtCompound compound) { - compound.putString("owner_species", getSpecies().name()); + compound.putString("owner_race", Race.REGISTRY.getId(getSpecies()).toString()); physics.toNBT(compound); } @Override public void fromNBT(NbtCompound compound) { - setSpecies(Race.fromName(compound.getString("owner_species"))); + if (compound.contains("owner_race", NbtElement.STRING_TYPE)) { + setSpecies(Race.fromName(compound.getString("owner_race"), Race.HUMAN)); + } physics.fromNBT(compound); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/effect/RaceChangeStatusEffect.java b/src/main/java/com/minelittlepony/unicopia/entity/effect/RaceChangeStatusEffect.java index f61cc294..e2ebad21 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/effect/RaceChangeStatusEffect.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/effect/RaceChangeStatusEffect.java @@ -25,23 +25,29 @@ public class RaceChangeStatusEffect extends StatusEffect { public static final int STAGE_DURATION = 50; public static final int MAX_DURATION = Stage.VALUES.length * STAGE_DURATION + 1; - public static final RaceChangeStatusEffect CHANGE_RACE_EARTH = new RaceChangeStatusEffect(0x886F0F, Race.EARTH); - public static final RaceChangeStatusEffect CHANGE_RACE_UNICORN = new RaceChangeStatusEffect(0x88FFFF, Race.UNICORN); - public static final RaceChangeStatusEffect CHANGE_RACE_PEGASUS = new RaceChangeStatusEffect(0x00FFFF, Race.PEGASUS); - public static final RaceChangeStatusEffect CHANGE_RACE_BAT = new RaceChangeStatusEffect(0x0FFF00, Race.BAT); - public static final RaceChangeStatusEffect CHANGE_RACE_CHANGELING = new RaceChangeStatusEffect(0xFFFF00, Race.CHANGELING); + public static final StatusEffect CHANGE_RACE_EARTH = register(0x886F0F, Race.EARTH); + public static final StatusEffect CHANGE_RACE_UNICORN = register(0x88FFFF, Race.UNICORN); + public static final StatusEffect CHANGE_RACE_PEGASUS = register(0x00FFFF, Race.PEGASUS); + public static final StatusEffect CHANGE_RACE_BAT = register(0x0FFF00, Race.BAT); + public static final StatusEffect CHANGE_RACE_CHANGELING = register(0xFFFF00, Race.CHANGELING); - private final Race species; + private final Race race; - protected RaceChangeStatusEffect(int color, Race species) { + public static StatusEffect register(int color, Race race) { + Identifier id = Race.REGISTRY.getId(race); + return Registry.register(Registry.STATUS_EFFECT, + new Identifier(id.getNamespace(), "change_race_" + id.getPath().toLowerCase()), + new RaceChangeStatusEffect(color, race) + ); + } + + public RaceChangeStatusEffect(int color, Race race) { super(StatusEffectCategory.NEUTRAL, color); - this.species = species; - - Registry.register(Registry.STATUS_EFFECT, new Identifier("unicopia", "change_race_" + species.name().toLowerCase()), this); + this.race = race; } public Race getSpecies() { - return species; + return race; } @Override @@ -68,16 +74,16 @@ public class RaceChangeStatusEffect extends StatusEffect { int progression = ticks % (stage.ordinal() * STAGE_DURATION); - if (eq.getSpecies() == species || !species.isPermitted(entity instanceof PlayerEntity ? (PlayerEntity)entity : null)) { + if (eq.getSpecies() == race || !race.isPermitted(entity instanceof PlayerEntity ? (PlayerEntity)entity : null)) { if (progression == 0 && entity instanceof PlayerEntity && stage == Stage.CRAWLING) { - ((PlayerEntity)entity).sendMessage(Stage.INITIAL.getMessage(species), true); + ((PlayerEntity)entity).sendMessage(Stage.INITIAL.getMessage(race), true); } return; } if (progression == 0) { if (stage != Stage.DEATH && entity instanceof PlayerEntity) { - ((PlayerEntity)entity).sendMessage(stage.getMessage(species), true); + ((PlayerEntity)entity).sendMessage(stage.getMessage(race), true); } float hitAmount = entity.getHealth() / 2; @@ -101,7 +107,7 @@ public class RaceChangeStatusEffect extends StatusEffect { if (stage == Stage.DEATH) { - eq.setSpecies(species); + eq.setSpecies(race); if (eq instanceof Caster) { ((Caster)eq).getSpellSlot().clear(); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/effect/UPotions.java b/src/main/java/com/minelittlepony/unicopia/entity/effect/UPotions.java index 82639098..936bd952 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/effect/UPotions.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/effect/UPotions.java @@ -6,17 +6,11 @@ import net.minecraft.util.Identifier; import net.minecraft.util.registry.Registry; public interface UPotions { - Potion TRIBE_SWAP_EARTH_PONY = registerRacePotion(RaceChangeStatusEffect.CHANGE_RACE_EARTH); - Potion TRIBE_SWAP_UNICORN = registerRacePotion(RaceChangeStatusEffect.CHANGE_RACE_UNICORN); - Potion TRIBE_SWAP_PEGASUS = registerRacePotion(RaceChangeStatusEffect.CHANGE_RACE_PEGASUS); - Potion TRIBE_SWAP_BAT = registerRacePotion(RaceChangeStatusEffect.CHANGE_RACE_BAT); - Potion TRIBE_SWAP_CHANGELING = registerRacePotion(RaceChangeStatusEffect.CHANGE_RACE_CHANGELING); - - static Potion registerRacePotion(RaceChangeStatusEffect effect) { - String name = "tribe_swap_" + effect.getSpecies().name().toLowerCase(); - return register(name, new Potion("unicopia." + name, - new StatusEffectInstance(effect, RaceChangeStatusEffect.MAX_DURATION))); - } + Potion TRIBE_SWAP_EARTH_PONY = register("tribe_swap_earth", new Potion("unicopia.tribe_swap_earth", new StatusEffectInstance(RaceChangeStatusEffect.CHANGE_RACE_EARTH, RaceChangeStatusEffect.MAX_DURATION))); + Potion TRIBE_SWAP_UNICORN = register("tribe_swap_unicorn", new Potion("unicopia.tribe_swap_unicorn", new StatusEffectInstance(RaceChangeStatusEffect.CHANGE_RACE_UNICORN, RaceChangeStatusEffect.MAX_DURATION))); + Potion TRIBE_SWAP_PEGASUS = register("tribe_swap_pegasus", new Potion("unicopia.tribe_swap_pegasus", new StatusEffectInstance(RaceChangeStatusEffect.CHANGE_RACE_PEGASUS, RaceChangeStatusEffect.MAX_DURATION))); + Potion TRIBE_SWAP_BAT = register("tribe_swap_bat", new Potion("unicopia.tribe_swap_bat", new StatusEffectInstance(RaceChangeStatusEffect.CHANGE_RACE_BAT, RaceChangeStatusEffect.MAX_DURATION))); + Potion TRIBE_SWAP_CHANGELING = register("tribe_swap_changeling", new Potion("unicopia.tribe_swap_changeling", new StatusEffectInstance(RaceChangeStatusEffect.CHANGE_RACE_CHANGELING, RaceChangeStatusEffect.MAX_DURATION))); static Potion register(String name, Potion potion) { return Registry.register(Registry.POTION, new Identifier("unicopia", name), potion); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index 5ef59449..ac42708b 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -69,7 +69,7 @@ import net.minecraft.util.math.Direction; public class Pony extends Living implements Transmittable, Copieable, UpdateCallback { - private static final TrackedData RACE = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.INTEGER); + private static final TrackedData RACE = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.STRING); static final TrackedData ENERGY = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT); static final TrackedData EXHAUSTION = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT); @@ -121,7 +121,7 @@ public class Pony extends Living implements Transmittable, Copieab this.levels = new PlayerLevelStore(this); this.tickers = Lists.newArrayList(gravity, mana, attributes, charms); - player.getDataTracker().startTracking(RACE, Race.HUMAN.ordinal()); + player.getDataTracker().startTracking(RACE, Race.DEFAULT_ID); } public static void registerAttributes(DefaultAttributeContainer.Builder builder) { @@ -171,7 +171,7 @@ public class Pony extends Living implements Transmittable, Copieab return Race.HUMAN; } - return Race.fromId(getMaster().getDataTracker().get(RACE)); + return Race.fromName(getMaster().getDataTracker().get(RACE), Race.HUMAN); } @Override @@ -179,7 +179,7 @@ public class Pony extends Living implements Transmittable, Copieab race = race.validate(entity); speciesSet = true; ticksInSun = 0; - entity.getDataTracker().set(RACE, race.ordinal()); + entity.getDataTracker().set(RACE, Race.REGISTRY.getId(race).toString()); gravity.updateFlightState(); entity.sendAbilitiesUpdate(); @@ -522,7 +522,7 @@ public class Pony extends Living implements Transmittable, Copieab @Override public void toNBT(NbtCompound compound) { super.toNBT(compound); - compound.putString("playerSpecies", getSpecies().name()); + compound.putString("playerSpecies", Race.REGISTRY.getId(getSpecies()).toString()); compound.putFloat("magicExhaustion", magicExhaustion); @@ -546,7 +546,7 @@ public class Pony extends Living implements Transmittable, Copieab public void fromNBT(NbtCompound compound) { super.fromNBT(compound); speciesPersisted = true; - setSpecies(Race.fromName(compound.getString("playerSpecies"))); + setSpecies(Race.fromName(compound.getString("playerSpecies"), Race.HUMAN)); powers.fromNBT(compound.getCompound("powers")); gravity.fromNBT(compound.getCompound("gravity")); diff --git a/src/main/java/com/minelittlepony/unicopia/item/toxin/Toxic.java b/src/main/java/com/minelittlepony/unicopia/item/toxin/Toxic.java index f6c18ca2..56d34c95 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/toxin/Toxic.java +++ b/src/main/java/com/minelittlepony/unicopia/item/toxin/Toxic.java @@ -1,8 +1,6 @@ package com.minelittlepony.unicopia.item.toxin; -import java.util.EnumMap; -import java.util.Map; -import java.util.Optional; +import java.util.*; import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.UTags; @@ -74,7 +72,7 @@ public class Toxic { public static class Builder { private final Ailment def; - private final Map ailments = new EnumMap<>(Race.class); + private final Map ailments = new HashMap<>(); private UseAction action = UseAction.EAT; private Optional component = Optional.empty(); diff --git a/src/main/java/com/minelittlepony/unicopia/network/MsgPlayerCapabilities.java b/src/main/java/com/minelittlepony/unicopia/network/MsgPlayerCapabilities.java index e4ad02cc..ed344378 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/MsgPlayerCapabilities.java +++ b/src/main/java/com/minelittlepony/unicopia/network/MsgPlayerCapabilities.java @@ -32,7 +32,7 @@ public class MsgPlayerCapabilities implements Packet { MsgPlayerCapabilities(PacketByteBuf buffer) { playerId = buffer.readUuid(); - newRace = Race.values()[buffer.readInt()]; + newRace = buffer.readRegistryValue(Race.REGISTRY); try (InputStream in = new ByteBufInputStream(buffer)) { compoundTag = NbtIo.readCompressed(in); } catch (IOException e) { @@ -49,7 +49,7 @@ public class MsgPlayerCapabilities implements Packet { @Override public void toBuffer(PacketByteBuf buffer) { buffer.writeUuid(playerId); - buffer.writeInt(newRace.ordinal()); + buffer.writeRegistryValue(Race.REGISTRY, newRace); try (OutputStream out = new ByteBufOutputStream(buffer)) { NbtIo.writeCompressed(compoundTag, out); } catch (IOException e) { diff --git a/src/main/java/com/minelittlepony/unicopia/network/MsgRequestSpeciesChange.java b/src/main/java/com/minelittlepony/unicopia/network/MsgRequestSpeciesChange.java index d165ee31..db2da4a8 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/MsgRequestSpeciesChange.java +++ b/src/main/java/com/minelittlepony/unicopia/network/MsgRequestSpeciesChange.java @@ -21,7 +21,7 @@ public class MsgRequestSpeciesChange implements Packet { MsgRequestSpeciesChange(PacketByteBuf buffer) { force = buffer.readBoolean(); - newRace = Race.fromId(buffer.readInt()); + newRace = buffer.readRegistryValue(Race.REGISTRY); } public MsgRequestSpeciesChange(Race newRace) { @@ -36,7 +36,7 @@ public class MsgRequestSpeciesChange implements Packet { @Override public void toBuffer(PacketByteBuf buffer) { buffer.writeBoolean(force); - buffer.writeInt(newRace.ordinal()); + buffer.writeRegistryValue(Race.REGISTRY, newRace); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/network/MsgTribeSelect.java b/src/main/java/com/minelittlepony/unicopia/network/MsgTribeSelect.java index 505f0d5d..dc56d48f 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/MsgTribeSelect.java +++ b/src/main/java/com/minelittlepony/unicopia/network/MsgTribeSelect.java @@ -15,14 +15,14 @@ public class MsgTribeSelect implements Packet { private final Set availableRaces; public MsgTribeSelect(PlayerEntity player) { - availableRaces = Race.all().stream().filter(r -> r.isPermitted(player)).collect(Collectors.toSet()); + availableRaces = Race.REGISTRY.stream().filter(r -> r.isPermitted(player)).collect(Collectors.toSet()); } public MsgTribeSelect(PacketByteBuf buffer) { int len = buffer.readInt(); availableRaces = new HashSet<>(); while (len-- > 0) { - availableRaces.add(Race.fromId(buffer.readInt())); + availableRaces.add(buffer.readRegistryValue(Race.REGISTRY)); } } @@ -33,7 +33,7 @@ public class MsgTribeSelect implements Packet { @Override public void toBuffer(PacketByteBuf buffer) { buffer.writeInt(availableRaces.size()); - availableRaces.forEach(race -> buffer.writeInt(race.ordinal())); + availableRaces.forEach(race -> buffer.writeRegistryValue(Race.REGISTRY, race)); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/util/Registries.java b/src/main/java/com/minelittlepony/unicopia/util/Registries.java index f5f2ff31..223205a0 100644 --- a/src/main/java/com/minelittlepony/unicopia/util/Registries.java +++ b/src/main/java/com/minelittlepony/unicopia/util/Registries.java @@ -7,11 +7,7 @@ import com.mojang.serialization.Lifecycle; import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder; import net.minecraft.tag.TagKey; import net.minecraft.util.Identifier; -import net.minecraft.util.registry.Registry; -import net.minecraft.util.registry.RegistryEntry; -import net.minecraft.util.registry.RegistryEntryList; -import net.minecraft.util.registry.RegistryKey; -import net.minecraft.util.registry.SimpleRegistry; +import net.minecraft.util.registry.*; import net.minecraft.world.World; public interface Registries { @@ -19,6 +15,10 @@ public interface Registries { return FabricRegistryBuilder.from(new SimpleRegistry(RegistryKey.ofRegistry(id), Lifecycle.stable(), null)).buildAndRegister(); } + static Registry createDefaulted(Identifier id, String def) { + return FabricRegistryBuilder.from(new DefaultedRegistry(def, RegistryKey.ofRegistry(id), Lifecycle.stable(), null)).buildAndRegister(); + } + static RegistryEntryList entriesForTag(World world, TagKey key) { return world.getRegistryManager().get(key.registry()).getOrCreateEntryList(key); } diff --git a/src/main/java/com/minelittlepony/unicopia/util/RegistryIndexer.java b/src/main/java/com/minelittlepony/unicopia/util/RegistryIndexer.java new file mode 100644 index 00000000..e842dafd --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/util/RegistryIndexer.java @@ -0,0 +1,54 @@ +package com.minelittlepony.unicopia.util; + +import com.minelittlepony.common.client.gui.IField; + +import net.minecraft.util.registry.Registry; + +public class RegistryIndexer { + + public static RegistryIndexer of(Registry registry) { + return new RegistryIndexer<>(registry); + } + + private final Registry values; + + private RegistryIndexer(Registry registry) { + values = registry; + } + + public int size() { + return values.size(); + } + + public int indexOf(T value) { + return values.getRawId(value); + } + + public T valueOf(int index) { + return values.get(wrapIndex(index)); + } + + public T valueOf(float index) { + return valueOf((int)index); + } + + public T cycle(T value, int increment) { + return valueOf(indexOf(value) + increment); + } + + public IField.IChangeCallback createSetter(IField.IChangeCallback setter) { + return index -> { + int i = wrapIndex(index.intValue()); + setter.perform(valueOf(i)); + return (float)i; + }; + } + + private int wrapIndex(int index) { + int sz = size(); + while (index < 0) { + index += sz; + } + return index % sz; + } +} diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index 72ad489b..8a8c892c 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -243,58 +243,58 @@ "gui.unicopia.tribe_selection.options": "Available Tribes:", "gui.unicopia.tribe_selection.options.disabled": "Option Unavailable", - "gui.unicopia.tribe_selection.describe.earth": "Join the Earth Tribe", - "gui.unicopia.tribe_selection.describe.unicorn": "Join the Unicorn Tribe, master the arcane arts", - "gui.unicopia.tribe_selection.describe.pegasus": "Join the Pegasus Tribe, soar with the Wonderbolts", - "gui.unicopia.tribe_selection.describe.bat": "Join the Bat Tribe, become the darkest night", - "gui.unicopia.tribe_selection.describe.changeling": "Join the Changeling Hive, your Queen demands it", + "gui.unicopia.tribe_selection.describe.unicopia.earth": "Join the Earth Tribe", + "gui.unicopia.tribe_selection.describe.unicopia.unicorn": "Join the Unicorn Tribe, master the arcane arts", + "gui.unicopia.tribe_selection.describe.unicopia.pegasus": "Join the Pegasus Tribe, soar with the Wonderbolts", + "gui.unicopia.tribe_selection.describe.unicopia.bat": "Join the Bat Tribe, become the darkest night", + "gui.unicopia.tribe_selection.describe.unicopia.changeling": "Join the Changeling Hive, your Queen demands it", "gui.unicopia.tribe_selection.confirm": "You have selected %s", "gui.unicopia.tribe_selection.confirm.goods": "%s enjoy the following perks:", - "gui.unicopia.tribe_selection.confirm.goods.1.earth": " - Stronger knockback and resistance to magic", - "gui.unicopia.tribe_selection.confirm.goods.2.earth": " - Have extra weight makes them effective against magic and brute force", - "gui.unicopia.tribe_selection.confirm.goods.3.earth": " - A special connection to the earth that makes farming 10,000% more effective!", + "gui.unicopia.tribe_selection.confirm.goods.1.unicopia.earth": " - Stronger knockback and resistance to magic", + "gui.unicopia.tribe_selection.confirm.goods.2.unicopia.earth": " - Have extra weight makes them effective against magic and brute force", + "gui.unicopia.tribe_selection.confirm.goods.3.unicopia.earth": " - A special connection to the earth that makes farming 10,000% more effective!", - "gui.unicopia.tribe_selection.confirm.goods.1.unicorn": " - Able to teleport and cast powerful spells", - "gui.unicopia.tribe_selection.confirm.goods.2.unicorn": " - Research and craft magical artefacts that enhance their abilities", - "gui.unicopia.tribe_selection.confirm.goods.3.unicorn": " - Can use magic to detect or reveal nearby changelings", - "gui.unicopia.tribe_selection.confirm.goods.4.unicorn": " - Have pointy sticks on their heads", + "gui.unicopia.tribe_selection.confirm.goods.1.unicopia.unicorn": " - Able to teleport and cast powerful spells", + "gui.unicopia.tribe_selection.confirm.goods.2.unicopia.unicorn": " - Research and craft magical artefacts that enhance their abilities", + "gui.unicopia.tribe_selection.confirm.goods.3.unicopia.unicorn": " - Can use magic to detect or reveal nearby changelings", + "gui.unicopia.tribe_selection.confirm.goods.4.unicopia.unicorn": " - Have pointy sticks on their heads", - "gui.unicopia.tribe_selection.confirm.goods.1.pegasus": " - Flight and the ability to train to build endurace", - "gui.unicopia.tribe_selection.confirm.goods.2.pegasus": " - Use stored mana to perform a powerful rainboom", - "gui.unicopia.tribe_selection.confirm.goods.3.pegasus": " - Moves faster and takes less fall damage", - "gui.unicopia.tribe_selection.confirm.goods.4.pegasus": " - Can eat vegitables and certain types of fish", + "gui.unicopia.tribe_selection.confirm.goods.1.unicopia.pegasus": " - Flight and the ability to train to build endurace", + "gui.unicopia.tribe_selection.confirm.goods.2.unicopia.pegasus": " - Use stored mana to perform a powerful rainboom", + "gui.unicopia.tribe_selection.confirm.goods.3.unicopia.pegasus": " - Moves faster and takes less fall damage", + "gui.unicopia.tribe_selection.confirm.goods.4.unicopia.pegasus": " - Can eat vegitables and certain types of fish", - "gui.unicopia.tribe_selection.confirm.goods.1.bat": " - Flight and the ability to train to build endurance", - "gui.unicopia.tribe_selection.confirm.goods.2.bat": " - Sees better in the night", - "gui.unicopia.tribe_selection.confirm.goods.3.bat": " - Able to cling to the underside of blocks", - "gui.unicopia.tribe_selection.confirm.goods.4.bat": " - Has a terrifying, yet adorable, but still slightly annoying screech", + "gui.unicopia.tribe_selection.confirm.goods.1.unicopia.bat": " - Flight and the ability to train to build endurance", + "gui.unicopia.tribe_selection.confirm.goods.2.unicopia.bat": " - Sees better in the night", + "gui.unicopia.tribe_selection.confirm.goods.3.unicopia.bat": " - Able to cling to the underside of blocks", + "gui.unicopia.tribe_selection.confirm.goods.4.unicopia.bat": " - Has a terrifying, yet adorable, but still slightly annoying screech", - "gui.unicopia.tribe_selection.confirm.goods.1.changeling": " - Able to fly and hover in place", - "gui.unicopia.tribe_selection.confirm.goods.2.changeling": " - Shapeshift and morph into nearly anyone or anyling", - "gui.unicopia.tribe_selection.confirm.goods.3.changeling": " - Is carnivorous. Can eat anything that doesn't make them sick", + "gui.unicopia.tribe_selection.confirm.goods.1.unicopia.changeling": " - Able to fly and hover in place", + "gui.unicopia.tribe_selection.confirm.goods.2.unicopia.changeling": " - Shapeshift and morph into nearly anyone or anyling", + "gui.unicopia.tribe_selection.confirm.goods.3.unicopia.changeling": " - Is carnivorous. Can eat anything that doesn't make them sick", "gui.unicopia.tribe_selection.confirm.bads": "but they...", - "gui.unicopia.tribe_selection.confirm.bads.1.earth": " - Cannot fly", - "gui.unicopia.tribe_selection.confirm.bads.2.earth": " - Are weak to certain types of magic", - "gui.unicopia.tribe_selection.confirm.bads.3.earth": " - Can only eat plants and vegitables", + "gui.unicopia.tribe_selection.confirm.bads.1.unicopia.earth": " - Cannot fly", + "gui.unicopia.tribe_selection.confirm.bads.2.unicopia.earth": " - Are weak to certain types of magic", + "gui.unicopia.tribe_selection.confirm.bads.3.unicopia.earth": " - Can only eat plants and vegitables", - "gui.unicopia.tribe_selection.confirm.bads.1.unicorn": " - Cannot fly", - "gui.unicopia.tribe_selection.confirm.bads.2.unicorn": " - Are weak to brute force attacks", - "gui.unicopia.tribe_selection.confirm.bads.3.unicorn": " - Can only eat plants and vegitables", + "gui.unicopia.tribe_selection.confirm.bads.1.unicopia.unicorn": " - Cannot fly", + "gui.unicopia.tribe_selection.confirm.bads.2.unicopia.unicorn": " - Are weak to brute force attacks", + "gui.unicopia.tribe_selection.confirm.bads.3.unicopia.unicorn": " - Can only eat plants and vegitables", - "gui.unicopia.tribe_selection.confirm.bads.1.pegasus": " - Light weight makes them the weakest to brute force", - "gui.unicopia.tribe_selection.confirm.bads.2.pegasus": " - Must rest between flights to regain their strength", + "gui.unicopia.tribe_selection.confirm.bads.1.unicopia.pegasus": " - Light weight makes them the weakest to brute force", + "gui.unicopia.tribe_selection.confirm.bads.2.unicopia.pegasus": " - Must rest between flights to regain their strength", - "gui.unicopia.tribe_selection.confirm.bads.1.bat": " - Light weight makes them weak to brute force attacks.", - "gui.unicopia.tribe_selection.confirm.bads.2.bat": " - Must rest between flights to regain their strength", - "gui.unicopia.tribe_selection.confirm.bads.3.bat": " - Is sometimes scared of even themselves", - "gui.unicopia.tribe_selection.confirm.bads.4.bat": " - Is carnivorous. Can eat anything that doesn't make them sick", + "gui.unicopia.tribe_selection.confirm.bads.1.unicopia.bat": " - Light weight makes them weak to brute force attacks.", + "gui.unicopia.tribe_selection.confirm.bads.2.unicopia.bat": " - Must rest between flights to regain their strength", + "gui.unicopia.tribe_selection.confirm.bads.3.unicopia.bat": " - Is sometimes scared of even themselves", + "gui.unicopia.tribe_selection.confirm.bads.4.unicopia.bat": " - Is carnivorous. Can eat anything that doesn't make them sick", - "gui.unicopia.tribe_selection.confirm.bads.1.changeling": " - Are always starving", - "gui.unicopia.tribe_selection.confirm.bads.2.changeling": " - Require love, collected from ponies or other hostile mobs to subsidise their diet", - "gui.unicopia.tribe_selection.confirm.bads.3.changeling": " - Becomes sick from eating regular food and must eat love hasten a cure", + "gui.unicopia.tribe_selection.confirm.bads.1.unicopia.changeling": " - Are always starving", + "gui.unicopia.tribe_selection.confirm.bads.2.unicopia.changeling": " - Require love, collected from ponies or other hostile mobs to subsidise their diet", + "gui.unicopia.tribe_selection.confirm.bads.3.unicopia.changeling": " - Becomes sick from eating regular food and must eat love hasten a cure", "gui.unicopia.spellbook.page.inventory": "Inventory", "gui.unicopia.spellbook.page.discoveries": "Discoveries", @@ -338,33 +338,33 @@ "commands.race.tell.other.alt": "%s is an ", "commands.race.describe.title": "%s", - "commands.race.describe.human.1": "This is a default race with no abilities.", - "commands.race.describe.human.2": "If you have this, it means there are no other races available.", - "commands.race.describe.human.3": "It has no special abilities.", + "commands.race.describe.unicopia.human.1": "This is a default race with no abilities.", + "commands.race.describe.unicopia.human.2": "If you have this, it means there are no other races available.", + "commands.race.describe.unicopia.human.3": "It has no special abilities.", - "commands.race.describe.earth.1": "Earth Ponies can grow crops using mana and punch trees for apples (yeeeeeeehaaaaawwwwwwwwwww)", - "commands.race.describe.earth.2": "Their offensive ability is to kick down whilst jumping for a deafening ground smash.", - "commands.race.describe.earth.3": "They are strong but slow.", + "commands.race.describe.unicopia.earth.1": "Earth Ponies can grow crops using mana and punch trees for apples (yeeeeeeehaaaaawwwwwwwwwww)", + "commands.race.describe.unicopia.earth.2": "Their offensive ability is to kick down whilst jumping for a deafening ground smash.", + "commands.race.describe.unicopia.earth.3": "They are strong but slow.", - "commands.race.describe.unicorn.1": "Unicorns are the primary magic users. They can teleport and cast powerful spells.", - "commands.race.describe.unicorn.2": "Their defensive features a powerful shield powered by their mana.", - "commands.race.describe.unicorn.3": "They are prone to tiring quickly.", + "commands.race.describe.unicopia.unicorn.1": "Unicorns are the primary magic users. They can teleport and cast powerful spells.", + "commands.race.describe.unicopia.unicorn.2": "Their defensive features a powerful shield powered by their mana.", + "commands.race.describe.unicopia.unicorn.3": "They are prone to tiring quickly.", - "commands.race.describe.pegasus.1": "Pegasi are the masters of the skies.", - "commands.race.describe.pegasus.2": "They live mostly in the air and are the only species with the ability to mould and harness cloud materials for their homes.", - "commands.race.describe.pegasus.3": "They are fast and light but easy to knock down.", + "commands.race.describe.unicopia.pegasus.1": "Pegasi are the masters of the skies.", + "commands.race.describe.unicopia.pegasus.2": "They live mostly in the air and are the only species with the ability to mould and harness cloud materials for their homes.", + "commands.race.describe.unicopia.pegasus.3": "They are fast and light but easy to knock down.", - "commands.race.describe.alicorn.1": "Praise the sun!", - "commands.race.describe.alicorn.2": "Alicorns have all abilities of the other races.", - "commands.race.describe.alicorn.3": "Only available to CREATIVE mode players.", + "commands.race.describe.unicopia.alicorn.1": "Praise the sun!", + "commands.race.describe.unicopia.alicorn.2": "Alicorns have all abilities of the other races.", + "commands.race.describe.unicopia.alicorn.3": "Only available to CREATIVE mode players.", - "commands.race.describe.changeling.1": "Beware the changeling, for they can appear when least expected.", - "commands.race.describe.changeling.2": "Changelings can fly but but do not interact with clouds.", - "commands.race.describe.changeling.3": "They have to feed on mobs and other players to eat.", + "commands.race.describe.unicopia.changeling.1": "Beware the changeling, for they can appear when least expected.", + "commands.race.describe.unicopia.changeling.2": "Changelings can fly but but do not interact with clouds.", + "commands.race.describe.unicopia.changeling.3": "They have to feed on mobs and other players to eat.", - "commands.race.describe.bat.1": "I am the night! EEEEEEEEEEEEE!!!", - "commands.race.describe.bat.2": "Bat Ponies can fly but but do not interact with clouds.", - "commands.race.describe.bat.3": "They love mangoes. Give them one, and they will follow you forever.", + "commands.race.describe.unicopia.bat.1": "I am the night! EEEEEEEEEEEEE!!!", + "commands.race.describe.unicopia.bat.2": "Bat Ponies can fly but but do not interact with clouds.", + "commands.race.describe.unicopia.bat.3": "They love mangoes. Give them one, and they will follow you forever.", "commands.racelist.usage": "/racelist ", "commands.racelist.illegal": "The default race %s cannot be used with this command.",