Skin Improvements

This commit is contained in:
skippyall
2025-04-24 22:09:38 +02:00
parent c7ff6de42b
commit 1931848068
33 changed files with 235 additions and 323 deletions
+4
View File
@@ -10,6 +10,10 @@ base {
archivesName = project.archives_base_name archivesName = project.archives_base_name
} }
loom {
accessWidenerPath = file("src/main/resources/minions.accesswidener")
}
repositories { repositories {
// Add repositories to retrieve artifacts from in here. // Add repositories to retrieve artifacts from in here.
// You should only use this when depending on other mods because // You should only use this when depending on other mods because
+1 -1
View File
@@ -4,7 +4,7 @@ org.gradle.jvmargs=-Xmx1G
# Fabric Properties # Fabric Properties
# check these on https://modmuss50.me/fabric.html # check these on https://modmuss50.me/fabric.html
minecraft_version=1.21.3 minecraft_version=1.21.3
loader_version=0.16.7 loader_version=0.16.13
yarn_mappings=1.21.3+build.2 yarn_mappings=1.21.3+build.2
# Mod Properties # Mod Properties
@@ -2,7 +2,7 @@ package io.github.skippyall.minions.gui;
import eu.pb4.sgui.api.elements.GuiElementBuilder; import eu.pb4.sgui.api.elements.GuiElementBuilder;
import eu.pb4.sgui.api.gui.SimpleGui; import eu.pb4.sgui.api.gui.SimpleGui;
import io.github.skippyall.minions.command.Command; import io.github.skippyall.minions.module.command.Command;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.module.ModuleItem; import io.github.skippyall.minions.module.ModuleItem;
import net.minecraft.screen.ScreenHandlerType; import net.minecraft.screen.ScreenHandlerType;
@@ -6,8 +6,8 @@ import io.github.skippyall.minions.input.TextInput;
import io.github.skippyall.minions.minion.MinionData; import io.github.skippyall.minions.minion.MinionData;
import io.github.skippyall.minions.minion.MinionItem; import io.github.skippyall.minions.minion.MinionItem;
import io.github.skippyall.minions.minion.MinionProfileUtils; import io.github.skippyall.minions.minion.MinionProfileUtils;
import net.minecraft.block.PlayerSkullBlock; import io.github.skippyall.minions.minion.skin.SkinProvider;
import net.minecraft.block.entity.SkullBlockEntity; import io.github.skippyall.minions.minion.skin.SkinProviders;
import net.minecraft.component.DataComponentTypes; import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.ProfileComponent; import net.minecraft.component.type.ProfileComponent;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
@@ -20,10 +20,18 @@ import java.util.Optional;
public class MinionLookGui extends SimpleGui { public class MinionLookGui extends SimpleGui {
private ItemStack minionItem; private ItemStack minionItem;
private SkinProvider currentSkinProvider;
public MinionLookGui(ServerPlayerEntity player, ItemStack minionItem) { public MinionLookGui(ServerPlayerEntity player, ItemStack minionItem) {
super(ScreenHandlerType.GENERIC_9X3, player, false); super(ScreenHandlerType.GENERIC_9X3, player, false);
this.minionItem = minionItem; this.minionItem = minionItem;
this.currentSkinProvider = SkinProviders.NAME;
}
public void update() {
updateName();
updateSkin();
updateSkinProvider();
} }
private void updateName() { private void updateName() {
@@ -37,45 +45,50 @@ public class MinionLookGui extends SimpleGui {
} }
private void updateSkin() { private void updateSkin() {
setSlot(16, new GuiElementBuilder() GuiElementBuilder builder = new GuiElementBuilder()
.setItem(Items.PLAYER_HEAD) .setItem(Items.PLAYER_HEAD)
); .setCallback(() -> currentSkinProvider.openSkinMenu(player).thenAccept(skin -> {
MinionItem.setData(getData().withSkin(skin), minionItem);
getData().getSkin(player.server).thenAccept(skin -> { }));
setSlot(16, new GuiElementBuilder() if(MinionItem.getData(minionItem) != null && MinionItem.getData(minionItem).skin().isPresent()) {
.setItem(Items.PLAYER_HEAD) builder.setComponent(DataComponentTypes.PROFILE, new ProfileComponent(Optional.empty(), Optional.empty(), getData().skin().get()));
.setComponent(DataComponentTypes.PROFILE, new ProfileComponent(Optional.empty(), Optional.empty(), skin)) }
.setCallback(this::cycleSkinProvider) setSlot(16, builder);
);
});
} }
private void cycleSkinProvider() { private void cycleSkinProvider() {
int currentId = SkinProviders.SKIN_PROVIDERS.getRawId(currentSkinProvider);
currentId++;
if(SkinProviders.SKIN_PROVIDERS.size() == currentId) {
currentId = 0;
}
currentSkinProvider = SkinProviders.SKIN_PROVIDERS.get(currentId);
updateSkinProvider();
} }
private void updateSkinProvider() { private void updateSkinProvider() {
setSlot(25, new GuiElementBuilder() setSlot(25, new GuiElementBuilder()
.setItem(Items.GREEN_STAINED_GLASS_PANE) .setItem(Items.GREEN_STAINED_GLASS_PANE)
.setComponent(DataComponentTypes.CUSTOM_NAME, Text.literal()) .setComponent(DataComponentTypes.CUSTOM_NAME, currentSkinProvider.getDisplayName())
.setCallback(this::cycleSkinProvider)
); );
updateSkin();
} }
private MinionData getData() { private MinionData getData() {
return MinionItem.getData(minionItem); return MinionItem.getDataOrDefault(minionItem);
} }
public static void open(ServerPlayerEntity player, ItemStack minionItem) { public static void open(ServerPlayerEntity player, ItemStack minionItem) {
MinionLookGui gui = new MinionLookGui(player, minionItem); MinionLookGui gui = new MinionLookGui(player, minionItem);
gui.update();
gui.open(); gui.open();
} }
public void openRenameGui(ServerPlayerEntity player, ItemStack minionItem) { public void openRenameGui(ServerPlayerEntity player, ItemStack minionItem) {
TextInput.input(player, Text.translatable("minions.gui.look.rename.title"), "Minion", MinionProfileUtils::checkMinionName) TextInput.inputSync(player, Text.translatable("minions.gui.look.rename.title"), "Minion", MinionProfileUtils::checkMinionNameWithoutPrefix)
.thenAccept(name -> { .thenAccept(name -> {
MinionItem.setData(MinionItem.getDataOrDefault(minionItem).withName(name), minionItem); MinionItem.setData(getData().withName(MinionProfileUtils.PREFIX + name), minionItem);
open(); open();
}); });
} }
@@ -1,6 +1,6 @@
package io.github.skippyall.minions.gui; package io.github.skippyall.minions.gui;
import io.github.skippyall.minions.command.Command; import io.github.skippyall.minions.module.command.Command;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.module.ModuleItem; import io.github.skippyall.minions.module.ModuleItem;
import io.github.skippyall.minions.program.block.CodeBlock; import io.github.skippyall.minions.program.block.CodeBlock;
@@ -9,6 +9,7 @@ import net.minecraft.text.Text;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate;
public class TextInput<T> extends AnvilInputGui { public class TextInput<T> extends AnvilInputGui {
private final GuiElementBuilder valid = new GuiElementBuilder() private final GuiElementBuilder valid = new GuiElementBuilder()
@@ -18,11 +19,11 @@ public class TextInput<T> extends AnvilInputGui {
private final GuiElementBuilder invalid = new GuiElementBuilder() private final GuiElementBuilder invalid = new GuiElementBuilder()
.setItem(Items.REDSTONE_BLOCK); .setItem(Items.REDSTONE_BLOCK);
private final Function<String, Result<T, Text>> parser; private final Function<String, CompletableFuture<Result<T, Text>>> parser;
private final CompletableFuture<T> future; private final CompletableFuture<T> future;
private Result<T, Text> result; private Result<T, Text> result;
public TextInput(ServerPlayerEntity player, Text title, String defaultValue, Function<String, Result<T, Text>> parser, CompletableFuture<T> future) { public TextInput(ServerPlayerEntity player, Text title, String defaultValue, Function<String, CompletableFuture<Result<T, Text>>> parser, CompletableFuture<T> future) {
super(player, false); super(player, false);
setTitle(title); setTitle(title);
setDefaultInputValue(defaultValue); setDefaultInputValue(defaultValue);
@@ -32,18 +33,26 @@ public class TextInput<T> extends AnvilInputGui {
updateConfirmButton(defaultValue); updateConfirmButton(defaultValue);
} }
public static <T> CompletableFuture<T> input(ServerPlayerEntity player, Text title, String defaultValue, Function<String, Result<T, Text>> parser) { public static <T> CompletableFuture<T> inputSync(ServerPlayerEntity player, Text title, String defaultValue, Function<String, Result<T, Text>> parser) {
return input(player, title, defaultValue, (String string) -> CompletableFuture.completedFuture(parser.apply(string)));
}
public static <T> CompletableFuture<T> input(ServerPlayerEntity player, Text title, String defaultValue, Function<String, CompletableFuture<Result<T, Text>>> parser) {
CompletableFuture<T> future = new CompletableFuture<>(); CompletableFuture<T> future = new CompletableFuture<>();
new TextInput<>(player, title, defaultValue, parser, future).open(); new TextInput<>(player, title, defaultValue, parser, future).open();
return future; return future;
} }
public static CompletableFuture<String> inputString(ServerPlayerEntity player, Text title, String defaultValue) {
return inputSync(player, title, defaultValue, Result.Success::new);
}
public static CompletableFuture<Integer> inputInt(ServerPlayerEntity player, Text title, String defaultValue) { public static CompletableFuture<Integer> inputInt(ServerPlayerEntity player, Text title, String defaultValue) {
return input(player, title, defaultValue, string -> Result.wrapCustomError(() -> Integer.valueOf(string), Text.translatable("minions.command.input.int.fail"))); return inputSync(player, title, defaultValue, string -> Result.wrapCustomError(() -> Integer.valueOf(string), Text.translatable("minions.command.input.int.fail")));
} }
public static CompletableFuture<Float> inputFloat(ServerPlayerEntity player, Text title, String defaultValue) { public static CompletableFuture<Float> inputFloat(ServerPlayerEntity player, Text title, String defaultValue) {
return input(player, title, defaultValue, string -> Result.wrapCustomError(() -> Float.valueOf(string), Text.translatable("minions.command.input.float.fail"))); return inputSync(player, title, defaultValue, string -> Result.wrapCustomError(() -> Float.valueOf(string), Text.translatable("minions.command.input.float.fail")));
} }
@Override @Override
@@ -52,13 +61,15 @@ public class TextInput<T> extends AnvilInputGui {
} }
public void updateConfirmButton(String input) { public void updateConfirmButton(String input) {
result = parser.apply(input); parser.apply(input).thenAccept(result -> {
this.result = result;
if(result.isSuccess()) { if(result.isSuccess()) {
setSlot(AnvilScreenHandler.OUTPUT_ID, valid); setSlot(AnvilScreenHandler.OUTPUT_ID, valid);
} else { } else {
Text text = result.getErrorOrThrow(); Text text = result.getErrorOrThrow();
setSlot(AnvilScreenHandler.OUTPUT_ID, invalid.setName(text)); setSlot(AnvilScreenHandler.OUTPUT_ID, invalid.setName(text));
} }
});
} }
@Override @Override
@@ -69,9 +80,11 @@ public class TextInput<T> extends AnvilInputGui {
} }
public void onConfirm() { public void onConfirm() {
if(result != null) {
result.ifSuccess(success -> { result.ifSuccess(success -> {
future.complete(success); future.complete(success);
close(); close();
}); });
} }
}
} }
@@ -6,27 +6,25 @@ import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder; import com.mojang.serialization.codecs.RecordCodecBuilder;
import eu.pb4.polymer.core.api.other.PolymerComponent; import eu.pb4.polymer.core.api.other.PolymerComponent;
import io.github.skippyall.minions.Minions; import io.github.skippyall.minions.Minions;
import io.github.skippyall.minions.minion.skin.SkinProvider;
import io.github.skippyall.minions.minion.skin.SkinProviders;
import net.minecraft.component.ComponentType; import net.minecraft.component.ComponentType;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NbtOps;
import net.minecraft.registry.Registries; import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry; import net.minecraft.registry.Registry;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.Uuids; import net.minecraft.util.Uuids;
import net.minecraft.util.dynamic.Codecs;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public record MinionData(UUID uuid, String name, @Nullable SkinProvider skin, boolean isSpawned) { public record MinionData(UUID uuid, String name, Optional<PropertyMap> skin, boolean isSpawned) {
public static final Codec<MinionData> CODEC = RecordCodecBuilder.create(instance -> public static final Codec<MinionData> CODEC = RecordCodecBuilder.create(instance ->
instance.group( instance.group(
Uuids.CODEC.fieldOf("uuid").forGetter(MinionData::uuid), Uuids.CODEC.fieldOf("uuid").forGetter(MinionData::uuid),
Codec.STRING.fieldOf("name").forGetter(MinionData::name), Codec.STRING.fieldOf("name").forGetter(MinionData::name),
SkinProviders.CODEC.optionalFieldOf("skin", null).forGetter(MinionData::skin), Codecs.GAME_PROFILE_PROPERTY_MAP.optionalFieldOf("skin").forGetter(MinionData::skin),
Codec.BOOL.optionalFieldOf("isSpawned", false).forGetter(MinionData::isSpawned) Codec.BOOL.optionalFieldOf("isSpawned", false).forGetter(MinionData::isSpawned)
).apply(instance, MinionData::new) ).apply(instance, MinionData::new)
); );
@@ -34,7 +32,7 @@ public record MinionData(UUID uuid, String name, @Nullable SkinProvider skin, bo
public static final ComponentType<UUID> COMPONENT = Registry.register(Registries.DATA_COMPONENT_TYPE, Identifier.of(Minions.MOD_ID, "minion_data"), ComponentType.<UUID>builder().codec(Uuids.CODEC).build()); public static final ComponentType<UUID> COMPONENT = Registry.register(Registries.DATA_COMPONENT_TYPE, Identifier.of(Minions.MOD_ID, "minion_data"), ComponentType.<UUID>builder().codec(Uuids.CODEC).build());
public static MinionData createDefault() { public static MinionData createDefault() {
return new MinionData(UUID.randomUUID(), "Minion", null, false); return new MinionData(UUID.randomUUID(), MinionProfileUtils.newDefaultMinionName(), Optional.empty(), false);
} }
public MinionData withUuid(UUID uuid) { public MinionData withUuid(UUID uuid) {
@@ -45,17 +43,10 @@ public record MinionData(UUID uuid, String name, @Nullable SkinProvider skin, bo
return new MinionData(uuid, name, skin, isSpawned); return new MinionData(uuid, name, skin, isSpawned);
} }
public MinionData withSkin(@Nullable SkinProvider skin) { public MinionData withSkin(Optional<PropertyMap> skin) {
return new MinionData(uuid, name, skin, isSpawned); return new MinionData(uuid, name, skin, isSpawned);
} }
public CompletableFuture<@Nullable PropertyMap> getSkin(MinecraftServer server) {
if(skin != null) {
return skin.getSkin(server);
}
return CompletableFuture.completedFuture(null);
}
public MinionData withSpawned(boolean isSpawned) { public MinionData withSpawned(boolean isSpawned) {
return new MinionData(uuid, name, skin, isSpawned); return new MinionData(uuid, name, skin, isSpawned);
} }
@@ -2,18 +2,23 @@ package io.github.skippyall.minions.minion;
import eu.pb4.polymer.core.api.item.PolymerItem; import eu.pb4.polymer.core.api.item.PolymerItem;
import eu.pb4.polymer.core.api.item.PolymerItemUtils; import eu.pb4.polymer.core.api.item.PolymerItemUtils;
import io.github.skippyall.minions.gui.MinionLookGui;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import net.minecraft.component.DataComponentTypes; import net.minecraft.component.DataComponentTypes;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUsageContext; import net.minecraft.item.ItemUsageContext;
import net.minecraft.item.Items; import net.minecraft.item.Items;
import net.minecraft.item.tooltip.TooltipType; import net.minecraft.item.tooltip.TooltipType;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.math.Vec2f; import net.minecraft.util.math.Vec2f;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import xyz.nucleoid.packettweaker.PacketContext; import xyz.nucleoid.packettweaker.PacketContext;
@@ -49,6 +54,17 @@ public class MinionItem extends Item implements PolymerItem {
} }
} }
@Override
public ActionResult use(World world, PlayerEntity user, Hand hand) {
if(user instanceof ServerPlayerEntity serverPlayer) {
ItemStack stack = user.getStackInHand(hand);
MinionLookGui.open(serverPlayer, stack);
return ActionResult.SUCCESS;
}
return ActionResult.SUCCESS_SERVER;
}
@Override @Override
public ActionResult useOnBlock(ItemUsageContext context) { public ActionResult useOnBlock(ItemUsageContext context) {
if(!context.getWorld().isClient) { if(!context.getWorld().isClient) {
@@ -61,6 +77,7 @@ public class MinionItem extends Item implements PolymerItem {
public static void setData(MinionData data, ItemStack item) { public static void setData(MinionData data, ItemStack item) {
item.set(MinionData.COMPONENT, data.uuid()); item.set(MinionData.COMPONENT, data.uuid());
MinionPersistentState.INSTANCE.updateMinionData(data);
} }
@Nullable @Nullable
@@ -75,6 +92,7 @@ public class MinionItem extends Item implements PolymerItem {
MinionData data = getData(item); MinionData data = getData(item);
if(data == null) { if(data == null) {
data = MinionData.createDefault(); data = MinionData.createDefault();
setData(data, item);
} }
return data; return data;
} }
@@ -18,7 +18,6 @@ public class MinionPersistentState extends PersistentState {
public static MinionPersistentState INSTANCE; public static MinionPersistentState INSTANCE;
private final Map<UUID, MinionData> minionData = new HashMap<>(); private final Map<UUID, MinionData> minionData = new HashMap<>();
//private final List<UUID> minionUuids = new ArrayList<>();
@Override @Override
public NbtCompound writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) { public NbtCompound writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) {
@@ -28,13 +27,6 @@ public class MinionPersistentState extends PersistentState {
} }
nbt.put("minions", list); nbt.put("minions", list);
/*NbtList uuids = new NbtList();
for(UUID uuid : minionUuids) {
NbtCompound compound = new NbtCompound();
compound.putUuid("uuid", uuid);
uuids.add(compound);
}
nbt.put("uuids", uuids);*/
return nbt; return nbt;
} }
@@ -43,39 +35,13 @@ public class MinionPersistentState extends PersistentState {
MinionPersistentState instance = new MinionPersistentState(); MinionPersistentState instance = new MinionPersistentState();
for(NbtElement element : list) { for(NbtElement element : list) {
if(element instanceof NbtCompound compound1) { if(element instanceof NbtCompound compound1) {
MinionData data = MinionData.readNbt((NbtCompound) element); MinionData data = MinionData.readNbt(compound1);
instance.minionData.put(data.uuid(), data); instance.minionData.put(data.uuid(), data);
} }
} }
/*NbtList uuids = compound.getList("uuids", NbtElement.COMPOUND_TYPE);
for(NbtElement element : uuids) {
instance.minionUuids.add(((NbtCompound) element).getUuid("uuid"));
}*/
return instance; return instance;
} }
/*public void addMinionUUID(UUID uuid) {
if(!minionUuids.contains(uuid)) {
minionUuids.add(uuid);
}
}*/
public void addMinion(MinionData data) {
System.out.println("add Minion " + data.name());
minionData.put(data.uuid(), data);
markDirty();
}
public void removeMinion(MinionData minionData) {
removeMinion(minionData.uuid());
}
public void removeMinion(UUID minionUUID) {
minionData.remove(minionUUID);
markDirty();
}
public MinionData getMinionData(UUID uuid) { public MinionData getMinionData(UUID uuid) {
return minionData.get(uuid); return minionData.get(uuid);
} }
@@ -86,12 +52,17 @@ public class MinionPersistentState extends PersistentState {
public void updateMinionData(MinionData data) { public void updateMinionData(MinionData data) {
minionData.put(data.uuid(), data); minionData.put(data.uuid(), data);
markDirty();
} }
public boolean isMinion(UUID uuid) { public boolean isMinion(UUID uuid) {
return minionData.containsKey(uuid); return minionData.containsKey(uuid);
} }
public boolean isMinionNameTaken(String name) {
return minionData.values().stream().anyMatch(data -> data.name().equals(name));
}
public static void create(MinecraftServer server) { public static void create(MinecraftServer server) {
INSTANCE = server.getWorld(World.OVERWORLD).getPersistentStateManager().getOrCreate(TYPE, "minion"); INSTANCE = server.getWorld(World.OVERWORLD).getPersistentStateManager().getOrCreate(TYPE, "minion");
} }
@@ -4,7 +4,9 @@ import com.mojang.authlib.GameProfile;
import com.mojang.authlib.ProfileLookupCallback; import com.mojang.authlib.ProfileLookupCallback;
import com.mojang.authlib.properties.PropertyMap; import com.mojang.authlib.properties.PropertyMap;
import com.mojang.authlib.yggdrasil.ProfileResult; import com.mojang.authlib.yggdrasil.ProfileResult;
import com.mojang.brigadier.StringReader;
import io.github.skippyall.minions.input.Result; import io.github.skippyall.minions.input.Result;
import net.minecraft.block.entity.SkullBlockEntity;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.StringHelper; import net.minecraft.util.StringHelper;
@@ -17,54 +19,7 @@ import java.util.concurrent.ForkJoinPool;
import static io.github.skippyall.minions.Minions.LOGGER; import static io.github.skippyall.minions.Minions.LOGGER;
public class MinionProfileUtils { public class MinionProfileUtils {
public static final String PREFIX = "#"; public static final String PREFIX = "+";
public static CompletableFuture<@Nullable GameProfile> lookupSkinOwnerProfile(MinecraftServer server, String username) {
CompletableFuture<GameProfile> future = new CompletableFuture<>();
ForkJoinPool.commonPool().execute(() -> {
try {
server.getGameProfileRepo().findProfilesByNames(new String[]{username}, new ProfileLookupCallback() {
@Override
public void onProfileLookupSucceeded(GameProfile found) {
LOGGER.info("SkinProfile: {}", found);
try {
getSkinOwnerProfile(server, found.getId()).thenAccept(future::complete);
} catch (Throwable ex) {
LOGGER.warn("Exception during Game Profile creation", ex);
}
}
@Override
public void onProfileLookupFailed(String profileName, Exception exception) {
LOGGER.warn("Lookup Error: ", exception);
future.complete(null);
}
});
} catch (Throwable e) {
LOGGER.warn("Failed to get UUID for username " + username, e);
future.complete(null);
}
});
return future;
}
public static CompletableFuture<@Nullable GameProfile> getSkinOwnerProfile(MinecraftServer server, @Nullable UUID uuid) {
CompletableFuture<GameProfile> future = new CompletableFuture<>();
future.completeAsync(() -> {
GameProfile profile = null;
if(uuid != null) {
ProfileResult result = server.getSessionService().fetchProfile(uuid, true);
if (result != null) {
profile = result.profile();
LOGGER.info("Full SkinProfile: {}", profile);
}
}
return profile;
});
return future;
}
public static GameProfile makeNewMinionProfile(UUID uuidMinion, String username, PropertyMap skin) { public static GameProfile makeNewMinionProfile(UUID uuidMinion, String username, PropertyMap skin) {
if(uuidMinion == null) { if(uuidMinion == null) {
@@ -79,16 +34,34 @@ public class MinionProfileUtils {
return newProfile; return newProfile;
} }
public static Result<String, Text> checkMinionName(String name) { public static Result<String, Text> checkMinionNameWithoutPrefix(String name) {
if(StringHelper.isValidPlayerName(PREFIX + name)) { for(char c : name.toCharArray()) {
return new Result.Success<>(name); if(!StringReader.isAllowedInUnquotedString(c)) {
} else { return new Result.Error<>(Text.translatable("minions.generic.name.invalid_char"));
return new Result.Error<>(Text.translatable("minions.generic.minion_name_too_long"));
} }
} }
public static boolean isValidMinionName(String name) { if((PREFIX + name).length() > 16) {
return checkMinionName(name).isSuccess(); return new Result.Error<>(Text.translatable("minions.generic.name.too_long"));
}
if(!StringHelper.isValidPlayerName(PREFIX + name)) {
return new Result.Error<>(Text.translatable("minions.generic.name.invalid"));
}
if(MinionPersistentState.INSTANCE.isMinionNameTaken(PREFIX + name)) {
return new Result.Error<>(Text.translatable("minions.generic.name.taken"));
}
return new Result.Success<>(name);
}
public static String newDefaultMinionName() {
int i = 0;
while (MinionPersistentState.INSTANCE.isMinionNameTaken("+Minion" + i)) {
i++;
}
return "+Minion" + i;
} }
public static boolean isMinion(UUID uuid) { public static boolean isMinion(UUID uuid) {
@@ -58,22 +58,22 @@ public class MinionFakePlayer extends ServerPlayerEntity {
private final ModuleInventory moduleInventory = new ModuleInventory(); private final ModuleInventory moduleInventory = new ModuleInventory();
private final MinionRuntime runtime = new MinionRuntime(this); private final MinionRuntime runtime = new MinionRuntime(this);
private MinionData data; private final MinionData data;
public static void spawnMinion(MinionData data, ServerWorld level, @Nullable Vec3d pos, @Nullable Vec2f rot) { public static void spawnMinion(MinionData data, ServerWorld level, @Nullable Vec3d pos, @Nullable Vec2f rot) {
MinecraftServer server = level.getServer(); MinecraftServer server = level.getServer();
CompletableFuture<PropertyMap> future = data.getSkin(server); PropertyMap skin = data.skin().orElse(null);
future.thenAccept((skin) -> {
GameProfile profile = MinionProfileUtils.makeNewMinionProfile(data.uuid(), data.name(), skin); GameProfile profile = MinionProfileUtils.makeNewMinionProfile(data.uuid(), data.name(), skin);
MinionsTickExecutor.addExecuteOnNextTick(() -> doSpawn(data, profile, server, level, pos, rot)); doSpawn(data, profile, server, level, pos, rot);
});
} }
private static void doSpawn(MinionData data, GameProfile profile, MinecraftServer server, ServerWorld level, @Nullable Vec3d pos, @Nullable Vec2f rot) { private static void doSpawn(MinionData data, GameProfile profile, MinecraftServer server, ServerWorld level, @Nullable Vec3d pos, @Nullable Vec2f rot) {
MinionFakePlayer instance = new MinionFakePlayer(server, level, profile, SyncedClientOptions.createDefault()); MinionFakePlayer instance = new MinionFakePlayer(server, level, profile, SyncedClientOptions.createDefault(), data);
MinionPersistentState.INSTANCE.updateMinionData(data.withSpawned(true));
if(pos != null && rot != null) { if(pos != null && rot != null) {
instance.fixStartingPosition = () -> instance.refreshPositionAndAngles(pos.x, pos.y, pos.z, rot.x, rot.y); instance.fixStartingPosition = () -> instance.refreshPositionAndAngles(pos.x, pos.y, pos.z, rot.x, rot.y);
@@ -95,14 +95,15 @@ public class MinionFakePlayer extends ServerPlayerEntity {
instance.getAbilities().flying = false; instance.getAbilities().flying = false;
} }
public static MinionFakePlayer respawnFake(MinecraftServer server, ServerWorld level, GameProfile profile, SyncedClientOptions cli) public static MinionFakePlayer respawnFake(MinecraftServer server, ServerWorld level, GameProfile profile, SyncedClientOptions cli, MinionData data)
{ {
return new MinionFakePlayer(server, level, profile, cli); return new MinionFakePlayer(server, level, profile, cli, data);
} }
private MinionFakePlayer(MinecraftServer server, ServerWorld worldIn, GameProfile profile, SyncedClientOptions cli) private MinionFakePlayer(MinecraftServer server, ServerWorld worldIn, GameProfile profile, SyncedClientOptions cli, MinionData data)
{ {
super(server, worldIn, profile, cli); super(server, worldIn, profile, cli);
this.data = data;
} }
public boolean isProgrammable() { public boolean isProgrammable() {
@@ -162,9 +163,7 @@ public class MinionFakePlayer extends ServerPlayerEntity {
})); }));
} }
data.withSpawned(false); MinionPersistentState.INSTANCE.updateMinionData(data.withSpawned(false));
MinionPersistentState.INSTANCE.updateMinionData(data);
} }
@Override @Override
@@ -291,6 +290,10 @@ public class MinionFakePlayer extends ServerPlayerEntity {
return stack; return stack;
} }
public MinionData getData() {
return data;
}
@Override @Override
public void writeCustomDataToNbt(NbtCompound nbt) { public void writeCustomDataToNbt(NbtCompound nbt) {
super.writeCustomDataToNbt(nbt); super.writeCustomDataToNbt(nbt);
@@ -0,0 +1,27 @@
package io.github.skippyall.minions.minion.skin;
import com.mojang.authlib.properties.Property;
import com.mojang.authlib.properties.PropertyMap;
import io.github.skippyall.minions.input.TextInput;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
public class Base64SkinProvider implements SkinProvider {
@Override
public CompletableFuture<Optional<PropertyMap>> openSkinMenu(ServerPlayerEntity player) {
return TextInput.inputString(player, Text.translatable("minions.gui.look.skin.base64.title"), "")
.thenApply(base64String -> {
PropertyMap map = new PropertyMap();
map.put("textures", new Property("textures", base64String));
return Optional.of(map);
});
}
@Override
public Text getDisplayName() {
return Text.translatable("minions.gui.look.skin.base64");
}
}
@@ -1,41 +0,0 @@
package io.github.skippyall.minions.minion.skin;
import com.mojang.authlib.properties.PropertyMap;
import net.minecraft.server.MinecraftServer;
import org.jetbrains.annotations.Nullable;
import java.util.concurrent.CompletableFuture;
public abstract class CachedSkinProvider implements SkinProvider {
private @Nullable PropertyMap cache = null;
protected CachedSkinProvider(@Nullable PropertyMap cache) {
this.cache = cache;
}
public abstract CompletableFuture<@Nullable PropertyMap> fetchSkin(MinecraftServer server);
public @Nullable PropertyMap getCache() {
return cache;
}
public CompletableFuture<@Nullable PropertyMap> updateCache(MinecraftServer server) {
CompletableFuture<PropertyMap> future = fetchSkin(server);
future.thenAccept(result -> {
this.cache = result;
});
return future;
}
@Override
public CompletableFuture<@Nullable PropertyMap> getSkin(MinecraftServer server) {
CompletableFuture<PropertyMap> future = new CompletableFuture<>();
if(cache == null) {
fetchSkin(server).thenAccept(skin -> {
cache = skin;
future.complete(skin);
});
}
return CompletableFuture.completedFuture(cache);
}
}
@@ -1,33 +0,0 @@
package io.github.skippyall.minions.minion.skin;
import com.mojang.authlib.properties.PropertyMap;
import com.mojang.serialization.Codec;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.dynamic.Codecs;
import org.jetbrains.annotations.Nullable;
import java.util.concurrent.CompletableFuture;
public class DirectSkinProvider implements SkinProvider {
private final PropertyMap propertyMap;
public static final Codec<DirectSkinProvider> CODEC = Codecs.GAME_PROFILE_PROPERTY_MAP.xmap(DirectSkinProvider::new, DirectSkinProvider::getPropertyMap);
public DirectSkinProvider(PropertyMap propertyMap) {
this.propertyMap = propertyMap;
}
public PropertyMap getPropertyMap() {
return propertyMap;
}
@Override
public CompletableFuture<@Nullable PropertyMap> getSkin(MinecraftServer server) {
return CompletableFuture.completedFuture(propertyMap);
}
@Override
public Codec<? extends SkinProvider> getCodec() {
return null;
}
}
@@ -1,43 +1,25 @@
package io.github.skippyall.minions.minion.skin; package io.github.skippyall.minions.minion.skin;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.PropertyMap; import com.mojang.authlib.properties.PropertyMap;
import com.mojang.serialization.Codec; import io.github.skippyall.minions.input.TextInput;
import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.block.entity.SkullBlockEntity;
import io.github.skippyall.minions.minion.MinionProfileUtils; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.MinecraftServer; import net.minecraft.text.Text;
import net.minecraft.util.dynamic.Codecs;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public class NameSkinProvider extends CachedSkinProvider { public class NameSkinProvider implements SkinProvider {
public static final Codec<NameSkinProvider> CODEC = RecordCodecBuilder.create(instance -> instance.group( @Override
Codec.STRING.fieldOf("name").forGetter(NameSkinProvider::getName), public CompletableFuture<Optional<PropertyMap>> openSkinMenu(ServerPlayerEntity player) {
Codecs.GAME_PROFILE_PROPERTY_MAP.optionalFieldOf("cache", null).forGetter(NameSkinProvider::getCache) return TextInput.inputString(player, Text.translatable("minions.gui.look.skin.name.title"), "")
).apply(instance, NameSkinProvider::new)); .thenCompose(SkullBlockEntity::fetchProfileByName)
.thenApply(gameProfile -> gameProfile.map(GameProfile::getProperties));
private final String name;
public NameSkinProvider(String name, @Nullable PropertyMap cache) {
super(cache);
this.name = name;
}
public NameSkinProvider(String name) {
this(name, null);
}
public String getName() {
return name;
} }
@Override @Override
public CompletableFuture<PropertyMap> fetchSkin(MinecraftServer server) { public Text getDisplayName() {
return MinionProfileUtils.lookupSkinOwnerProfile(server, name).thenApply(gameProfile -> gameProfile != null ? gameProfile.getProperties() : null); return Text.translatable("minions.gui.look.skin.name");
}
@Override
public Codec<? extends SkinProvider> getCodec() {
return null;
} }
} }
@@ -1,14 +1,14 @@
package io.github.skippyall.minions.minion.skin; package io.github.skippyall.minions.minion.skin;
import com.mojang.authlib.properties.PropertyMap; import com.mojang.authlib.properties.PropertyMap;
import com.mojang.serialization.Codec; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.MinecraftServer; import net.minecraft.text.Text;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public interface SkinProvider { public interface SkinProvider {
CompletableFuture<@Nullable PropertyMap> getSkin(MinecraftServer server); CompletableFuture<Optional<PropertyMap>> openSkinMenu(ServerPlayerEntity player);
Codec<? extends SkinProvider> getCodec(); Text getDisplayName();
} }
@@ -1,6 +1,5 @@
package io.github.skippyall.minions.minion.skin; package io.github.skippyall.minions.minion.skin;
import com.mojang.serialization.Codec;
import com.mojang.serialization.Lifecycle; import com.mojang.serialization.Lifecycle;
import io.github.skippyall.minions.Minions; import io.github.skippyall.minions.Minions;
import net.minecraft.registry.Registry; import net.minecraft.registry.Registry;
@@ -9,18 +8,18 @@ import net.minecraft.registry.SimpleRegistry;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
public class SkinProviders { public class SkinProviders {
public static final Registry<Codec<? extends SkinProvider>> REGISTRY = new SimpleRegistry<>(RegistryKey.ofRegistry(Identifier.of(Minions.MOD_ID, "skin_providers")), Lifecycle.stable()); public static final Registry<SkinProvider> SKIN_PROVIDERS = new SimpleRegistry<>(RegistryKey.ofRegistry(Identifier.of(Minions.MOD_ID, "skin_providers")), Lifecycle.stable());
public static final Codec<SkinProvider> CODEC = REGISTRY.getCodec().dispatchStable(SkinProvider::getCodec, codec -> codec.fieldOf("data")); public static NameSkinProvider NAME = register(new NameSkinProvider(), "name");
public static UUIDSkinProvider UUID = register(new UUIDSkinProvider(), "uuid");
public static Base64SkinProvider BASE64 = register(new Base64SkinProvider(), "base64");
public static <T extends Codec<? extends SkinProvider>> T register(T skinProvider, Identifier id) {
Registry.register(REGISTRY, id, skinProvider); public static <T extends SkinProvider> T register(T skinProvider, String path) {
return skinProvider; return Registry.register(SKIN_PROVIDERS, Identifier.of(Minions.MOD_ID, path), skinProvider);
} }
public static void register() { public static void register() {
register(UUIDSkinProvider.CODEC, Identifier.of(Minions.MOD_ID, "uuid"));
register(NameSkinProvider.CODEC, Identifier.of(Minions.MOD_ID, "name"));
register(DirectSkinProvider.CODEC, Identifier.of(Minions.MOD_ID, "direct"));
} }
} }
@@ -1,51 +1,32 @@
package io.github.skippyall.minions.minion.skin; package io.github.skippyall.minions.minion.skin;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.PropertyMap; import com.mojang.authlib.properties.PropertyMap;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder; import com.mojang.serialization.codecs.RecordCodecBuilder;
import io.github.skippyall.minions.input.TextInput;
import io.github.skippyall.minions.minion.MinionProfileUtils; import io.github.skippyall.minions.minion.MinionProfileUtils;
import net.minecraft.block.entity.SkullBlockEntity;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.Uuids; import net.minecraft.util.Uuids;
import net.minecraft.util.dynamic.Codecs; import net.minecraft.util.dynamic.Codecs;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public class UUIDSkinProvider extends CachedSkinProvider { public class UUIDSkinProvider implements SkinProvider {
public static final Codec<UUIDSkinProvider> CODEC = RecordCodecBuilder.create(instance -> @Override
instance.group( public CompletableFuture<Optional<PropertyMap>> openSkinMenu(ServerPlayerEntity player) {
Codecs.GAME_PROFILE_PROPERTY_MAP.optionalFieldOf("cache", null).forGetter(CachedSkinProvider::getCache), return TextInput.inputString(player, Text.translatable("minions.gui.look.skin.uuid.title"), "")
Uuids.CODEC.fieldOf("uuid").forGetter(UUIDSkinProvider::getUuid) .thenCompose(uuidString -> SkullBlockEntity.fetchProfileByUuid(UUID.fromString(uuidString)))
).apply(instance, UUIDSkinProvider::new)); .thenApply(gameProfile -> gameProfile.map(GameProfile::getProperties));
private final UUID uuid;
public UUIDSkinProvider(UUID uuid) {
this(null, uuid);
}
public UUIDSkinProvider(PropertyMap cache, UUID uuid) {
super(cache);
this.uuid = uuid;
}
public UUID getUuid() {
return uuid;
} }
@Override @Override
public CompletableFuture<PropertyMap> fetchSkin(MinecraftServer server) { public Text getDisplayName() {
return MinionProfileUtils.getSkinOwnerProfile(server, uuid).thenApply(gameProfile -> { return Text.translatable("minions.gui.look.skin.uuid");
if (gameProfile != null) {
return gameProfile.getProperties();
} else {
return null;
}
});
}
@Override
public Codec<? extends SkinProvider> getCodec() {
return CODEC;
} }
} }
@@ -11,7 +11,7 @@ import org.spongepowered.asm.mixin.injection.ModifyArg;
import java.util.function.Predicate; import java.util.function.Predicate;
@Mixin(EntityView.class) @Mixin(EntityView.class)
public class EntityViewMixin { public interface EntityViewMixin {
@ModifyArg(method = "getClosestPlayer(DDDDZ)Lnet/minecraft/entity/player/PlayerEntity;", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/EntityView;getClosestPlayer(DDDDLjava/util/function/Predicate;)Lnet/minecraft/entity/player/PlayerEntity;")) @ModifyArg(method = "getClosestPlayer(DDDDZ)Lnet/minecraft/entity/player/PlayerEntity;", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/EntityView;getClosestPlayer(DDDDLjava/util/function/Predicate;)Lnet/minecraft/entity/player/PlayerEntity;"))
private @Nullable Predicate<Entity> addMinionPredicate(@Nullable Predicate<Entity> targetPredicate) { private @Nullable Predicate<Entity> addMinionPredicate(@Nullable Predicate<Entity> targetPredicate) {
Predicate<Entity> predicate = EntityViewMixinHelper.ADDITIONAL_PREDICATE.get(); Predicate<Entity> predicate = EntityViewMixinHelper.ADDITIONAL_PREDICATE.get();
@@ -52,7 +52,7 @@ public class PlayerListMixin {
@WrapOperation(method = "respawnPlayer", at = @At(value = "NEW", target = "(Lnet/minecraft/server/MinecraftServer;Lnet/minecraft/server/world/ServerWorld;Lcom/mojang/authlib/GameProfile;Lnet/minecraft/network/packet/c2s/common/SyncedClientOptions;)Lnet/minecraft/server/network/ServerPlayerEntity;")) @WrapOperation(method = "respawnPlayer", at = @At(value = "NEW", target = "(Lnet/minecraft/server/MinecraftServer;Lnet/minecraft/server/world/ServerWorld;Lcom/mojang/authlib/GameProfile;Lnet/minecraft/network/packet/c2s/common/SyncedClientOptions;)Lnet/minecraft/server/network/ServerPlayerEntity;"))
public ServerPlayerEntity makePlayerForRespawn(MinecraftServer minecraftServer, ServerWorld serverLevel, GameProfile gameProfile, SyncedClientOptions clientInformation, Operation<ServerPlayerEntity> original, ServerPlayerEntity serverPlayer, boolean bl) { public ServerPlayerEntity makePlayerForRespawn(MinecraftServer minecraftServer, ServerWorld serverLevel, GameProfile gameProfile, SyncedClientOptions clientInformation, Operation<ServerPlayerEntity> original, ServerPlayerEntity serverPlayer, boolean bl) {
if (serverPlayer instanceof MinionFakePlayer minion) { if (serverPlayer instanceof MinionFakePlayer minion) {
return MinionFakePlayer.respawnFake(minecraftServer, serverLevel, gameProfile, clientInformation); return MinionFakePlayer.respawnFake(minecraftServer, serverLevel, gameProfile, clientInformation, minion.getData());
} }
return original.call(minecraftServer, serverLevel, gameProfile, clientInformation); return original.call(minecraftServer, serverLevel, gameProfile, clientInformation);
} }
@@ -2,7 +2,7 @@ package io.github.skippyall.minions.module;
import eu.pb4.sgui.api.elements.GuiElementBuilder; import eu.pb4.sgui.api.elements.GuiElementBuilder;
import eu.pb4.sgui.api.gui.SimpleGui; import eu.pb4.sgui.api.gui.SimpleGui;
import io.github.skippyall.minions.command.CommandExecutor; import io.github.skippyall.minions.module.command.CommandExecutor;
import io.github.skippyall.minions.input.TextInput; import io.github.skippyall.minions.input.TextInput;
import io.github.skippyall.minions.minion.fakeplayer.EntityPlayerActionPack; import io.github.skippyall.minions.minion.fakeplayer.EntityPlayerActionPack;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
@@ -1,7 +1,7 @@
package io.github.skippyall.minions.module; package io.github.skippyall.minions.module;
import io.github.skippyall.minions.Minions; import io.github.skippyall.minions.Minions;
import io.github.skippyall.minions.command.SimpleCommand; import io.github.skippyall.minions.module.command.SimpleCommand;
import io.github.skippyall.minions.minion.fakeplayer.EntityPlayerActionPack; import io.github.skippyall.minions.minion.fakeplayer.EntityPlayerActionPack;
import net.minecraft.item.Items; import net.minecraft.item.Items;
import net.minecraft.text.Text; import net.minecraft.text.Text;
@@ -1,7 +1,7 @@
package io.github.skippyall.minions.module; package io.github.skippyall.minions.module;
import io.github.skippyall.minions.Minions; import io.github.skippyall.minions.Minions;
import io.github.skippyall.minions.command.SimpleCommand; import io.github.skippyall.minions.module.command.SimpleCommand;
import net.minecraft.item.Items; import net.minecraft.item.Items;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
@@ -1,7 +1,7 @@
package io.github.skippyall.minions.module; package io.github.skippyall.minions.module;
import io.github.skippyall.minions.Minions; import io.github.skippyall.minions.Minions;
import io.github.skippyall.minions.command.SimpleCommand; import io.github.skippyall.minions.module.command.SimpleCommand;
import io.github.skippyall.minions.minion.fakeplayer.EntityPlayerActionPack; import io.github.skippyall.minions.minion.fakeplayer.EntityPlayerActionPack;
import net.minecraft.item.Items; import net.minecraft.item.Items;
import net.minecraft.text.Text; import net.minecraft.text.Text;
@@ -1,6 +1,6 @@
package io.github.skippyall.minions.module; package io.github.skippyall.minions.module;
import io.github.skippyall.minions.command.Command; import io.github.skippyall.minions.module.command.Command;
import io.github.skippyall.minions.program.block.CodeBlock; import io.github.skippyall.minions.program.block.CodeBlock;
import net.minecraft.item.ItemConvertible; import net.minecraft.item.ItemConvertible;
@@ -1,6 +1,6 @@
package io.github.skippyall.minions.module; package io.github.skippyall.minions.module;
import io.github.skippyall.minions.command.Command; import io.github.skippyall.minions.module.command.Command;
import io.github.skippyall.minions.program.block.CodeBlock; import io.github.skippyall.minions.program.block.CodeBlock;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.registry.Registries; import net.minecraft.registry.Registries;
@@ -1,7 +1,7 @@
package io.github.skippyall.minions.module; package io.github.skippyall.minions.module;
import io.github.skippyall.minions.Minions; import io.github.skippyall.minions.Minions;
import io.github.skippyall.minions.command.SimpleCommand; import io.github.skippyall.minions.module.command.SimpleCommand;
import net.minecraft.item.Items; import net.minecraft.item.Items;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
@@ -1,7 +1,7 @@
package io.github.skippyall.minions.module; package io.github.skippyall.minions.module;
import io.github.skippyall.minions.Minions; import io.github.skippyall.minions.Minions;
import io.github.skippyall.minions.command.SimpleCommand; import io.github.skippyall.minions.module.command.SimpleCommand;
import io.github.skippyall.minions.input.TextInput; import io.github.skippyall.minions.input.TextInput;
import net.minecraft.item.Items; import net.minecraft.item.Items;
import net.minecraft.text.Text; import net.minecraft.text.Text;
@@ -1,7 +1,7 @@
package io.github.skippyall.minions.module; package io.github.skippyall.minions.module;
import eu.pb4.polymer.core.api.item.SimplePolymerItem; import eu.pb4.polymer.core.api.item.SimplePolymerItem;
import io.github.skippyall.minions.command.Command; import io.github.skippyall.minions.module.command.Command;
import io.github.skippyall.minions.program.block.CodeBlock; import io.github.skippyall.minions.program.block.CodeBlock;
import net.minecraft.item.Item; import net.minecraft.item.Item;
@@ -1,4 +1,4 @@
package io.github.skippyall.minions.command; package io.github.skippyall.minions.module.command;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.text.Text; import net.minecraft.text.Text;
@@ -1,4 +1,4 @@
package io.github.skippyall.minions.command; package io.github.skippyall.minions.module.command;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
@@ -1,4 +1,4 @@
package io.github.skippyall.minions.command; package io.github.skippyall.minions.module.command;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import net.minecraft.item.Item; import net.minecraft.item.Item;
@@ -8,6 +8,13 @@
"minions.gui.commands.title": "%s's Commands", "minions.gui.commands.title": "%s's Commands",
"minions.gui.modules.title": "%s's Modules", "minions.gui.modules.title": "%s's Modules",
"minions.gui.ok": "OK", "minions.gui.ok": "OK",
"minions.gui.look.skin.name": "Name",
"minions.gui.look.skin.name.title": "Enter a player name",
"minions.gui.look.skin.uuid": "UUID",
"minions.gui.look.skin.uuid.title": "Enter a player UUID",
"minions.gui.look.skin.base64": "Base64",
"minions.gui.look.skin.base64.title": "Enter a skin in base64 encoding",
"minions.gui.look.rename.title": "Enter a name",
"minions.command.input.int.fail": "Not an integer", "minions.command.input.int.fail": "Not an integer",
"minions.command.input.float.fail": "Not a number", "minions.command.input.float.fail": "Not a number",
@@ -31,5 +38,9 @@
"item.minions.basic_upgrade_base": "Basic Upgrade Base", "item.minions.basic_upgrade_base": "Basic Upgrade Base",
"item.minions.advanced_upgrade_base": "Advanced Upgrade Base", "item.minions.advanced_upgrade_base": "Advanced Upgrade Base",
"minions.minion_item.tooltip": "Name: %s" "minions.minion_item.tooltip": "Name: %s",
"minions.generic.name.invalid_char": "Name contains invalid character",
"minions.generic.name.too_long": "Name is too long",
"minions.generic.name.invalid": "Name is invalid",
"minions.generic.name.taken": "This name is already used"
} }