Skin Improvements
This commit is contained in:
@@ -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
@@ -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
-1
@@ -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
-1
@@ -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
-1
@@ -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"
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user