Back to the Future

Fun is still suspended though
This commit is contained in:
skippyall
2026-05-09 17:04:27 +02:00
parent 48a38b87c5
commit f8eb1578b2
35 changed files with 297 additions and 429 deletions
+1
View File
@@ -1,6 +1,7 @@
# User-specific stuff # User-specific stuff
.idea/ .idea/
urlaub/ urlaub/
.kotlin/
*.iml *.iml
*.ipr *.ipr
@@ -51,7 +51,7 @@ public abstract class InstructionBoundBlock extends Block implements EntityBlock
} }
world.getBlockEntity(pos, getBlockEntityType()).ifPresent(be -> { world.getBlockEntity(pos, getBlockEntityType()).ifPresent(be -> {
String name = MinionPersistentState.get(world.getServer()).getMinionData(be.getMinionUuid()).name(); String name = MinionPersistentState.get(world.getServer()).getMinionData(be.getMinionUuid()).getName();
player.sendSystemMessage(Component.translatable("minions.reference.instruction.tooltip", be.getInstructionName(), name)); player.sendSystemMessage(Component.translatable("minions.reference.instruction.tooltip", be.getInstructionName(), name));
}); });
return InteractionResult.SUCCESS; return InteractionResult.SUCCESS;
@@ -18,7 +18,7 @@ public class ListSubcommand {
public static int list(CommandContext<CommandSourceStack> context) { public static int list(CommandContext<CommandSourceStack> context) {
Collection<MinionData> minions = MinionPersistentState.get(context.getSource().getServer()).getMinionData().values(); Collection<MinionData> minions = MinionPersistentState.get(context.getSource().getServer()).getMinionData().values();
for (MinionData minion : minions) { for (MinionData minion : minions) {
context.getSource().sendSuccess(() -> Component.literal(minion.name() + "(" + minion.uuid() + "):" + minion.isSpawned()), false); context.getSource().sendSuccess(() -> Component.literal(minion.getName() + "(" + minion.getUuid() + "):" + minion.isSpawned()), false);
} }
return 0; return 0;
} }
@@ -41,7 +41,7 @@ public class MinionArgument {
@Override @Override
public CompletableFuture<Suggestions> getSuggestions(CommandContext<CommandSourceStack> context, SuggestionsBuilder builder) throws CommandSyntaxException { public CompletableFuture<Suggestions> getSuggestions(CommandContext<CommandSourceStack> context, SuggestionsBuilder builder) throws CommandSyntaxException {
for (MinionData data : MinionPersistentState.get(context.getSource().getServer()).getMinionDataList()) { for (MinionData data : MinionPersistentState.get(context.getSource().getServer()).getMinionDataList()) {
builder.suggest(data.name()); builder.suggest(data.getName());
} }
return builder.buildFuture(); return builder.buildFuture();
@@ -27,9 +27,10 @@ import java.util.UUID;
public interface GuiDisplay { public interface GuiDisplay {
Codec<GuiDisplay> CODEC = MinionRegistries.GUI_DISPLAY_TYPE.byNameCodec().dispatch(GuiDisplay::getCodec, codec -> codec.fieldOf("data")); Codec<GuiDisplay> CODEC = MinionRegistries.GUI_DISPLAY_TYPE.byNameCodec().dispatch(GuiDisplay::getCodec, codec -> codec.fieldOf("data"));
GuiDisplay DEFAULT_DISPLAY = new ItemBased(Items.BARRIER); GuiDisplay DEFAULT_DISPLAY = new ItemBased(Items.BARRIER);
TooltipDisplay TOOLTIP_DISPLAY = createTooltipDisplay();
private static TooltipDisplay createTooltipDisplay() { TooltipDisplay TOOLTIP_HIDE_ALL_COMPONENTS = createHideAllTooltip();
private static TooltipDisplay createHideAllTooltip() {
LinkedHashSet<DataComponentType<?>> set = new LinkedHashSet<>(); LinkedHashSet<DataComponentType<?>> set = new LinkedHashSet<>();
for(DataComponentType<?> type : BuiltInRegistries.DATA_COMPONENT_TYPE) { for(DataComponentType<?> type : BuiltInRegistries.DATA_COMPONENT_TYPE) {
if(type != DataComponents.LORE) { if(type != DataComponents.LORE) {
@@ -106,7 +107,7 @@ public interface GuiDisplay {
@Override @Override
public ItemStackTemplate createItemStackTemplate() { public ItemStackTemplate createItemStackTemplate() {
return new ItemStackTemplate(item, DataComponentPatch.builder() return new ItemStackTemplate(item, DataComponentPatch.builder()
.set(DataComponents.TOOLTIP_DISPLAY, TOOLTIP_DISPLAY) .set(DataComponents.TOOLTIP_DISPLAY, TOOLTIP_HIDE_ALL_COMPONENTS)
.set(DataComponents.RARITY, Rarity.COMMON) .set(DataComponents.RARITY, Rarity.COMMON)
.build()); .build());
} }
@@ -130,6 +131,7 @@ public interface GuiDisplay {
public ItemStackTemplate createItemStackTemplate() { public ItemStackTemplate createItemStackTemplate() {
return new ItemStackTemplate(Items.PLAYER_HEAD, DataComponentPatch.builder() return new ItemStackTemplate(Items.PLAYER_HEAD, DataComponentPatch.builder()
.set(DataComponents.PROFILE, ResolvableProfile.createUnresolved(uuid)) .set(DataComponents.PROFILE, ResolvableProfile.createUnresolved(uuid))
.set(DataComponents.TOOLTIP_DISPLAY, TOOLTIP_HIDE_ALL_COMPONENTS)
.build() .build()
); );
} }
@@ -10,6 +10,7 @@ import io.github.skippyall.minions.minion.MinionProfileUtils
import io.github.skippyall.minions.minion.skin.SkinProvider import io.github.skippyall.minions.minion.skin.SkinProvider
import io.github.skippyall.minions.registration.MinionRegistries import io.github.skippyall.minions.registration.MinionRegistries
import io.github.skippyall.minions.registration.SkinProviders import io.github.skippyall.minions.registration.SkinProviders
import kotlinx.coroutines.future.await
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import net.fabricmc.fabric.api.entity.FakePlayer import net.fabricmc.fabric.api.entity.FakePlayer
import net.minecraft.core.component.DataComponents import net.minecraft.core.component.DataComponents
@@ -20,8 +21,6 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items import net.minecraft.world.item.Items
import net.minecraft.world.item.component.ResolvableProfile import net.minecraft.world.item.component.ResolvableProfile
import java.util.Optional import java.util.Optional
import java.util.function.Consumer
import java.util.function.Function
class MinionLookGui( class MinionLookGui(
viewer: ServerPlayer, viewer: ServerPlayer,
@@ -82,20 +81,24 @@ class MinionLookGui(
gui.setSlot(16, builder) gui.setSlot(16, builder)
} }
private fun updateSkinProvider() {
gui.setSlot(
25, GuiElementBuilder()
.setItem(Items.GREEN_STAINED_GLASS_PANE)
.setComponent(DataComponents.CUSTOM_NAME, currentSkinProvider.getDisplayName())
.setCallback(Runnable { this.cycleSkinProvider() })
)
}
fun openSkinGui() { fun openSkinGui() {
currentSkinProvider.openSkinMenu(this) scope.launch {
.thenCompose(Function { profile: ResolvableProfile? -> val profile = currentSkinProvider.openSkinMenu(this@MinionLookGui).await()
profile!!.resolveProfile( val skin = profile.resolveProfile(viewer.level().server.services().profileResolver()).await()
viewer.level().server.services().profileResolver()
) data.skin = Optional.ofNullable(skin?.properties())
})
.thenAccept(Consumer { skin: GameProfile? -> updateSkin()
MinionItem.setData( }
viewer.level().server, this.data.withSkin(
Optional.of(skin!!.properties())
), minionItem
)
})
} }
private fun cycleSkinProvider() { private fun cycleSkinProvider() {
@@ -109,15 +112,6 @@ class MinionLookGui(
updateSkinProvider() updateSkinProvider()
} }
private fun updateSkinProvider() {
gui.setSlot(
25, GuiElementBuilder()
.setItem(Items.GREEN_STAINED_GLASS_PANE)
.setComponent(DataComponents.CUSTOM_NAME, currentSkinProvider.getDisplayName())
.setCallback(Runnable { this.cycleSkinProvider() })
)
}
fun openRenameGui() { fun openRenameGui() {
scope.launch { scope.launch {
val newName = TextInput.input( val newName = TextInput.input(
@@ -126,10 +120,11 @@ class MinionLookGui(
"Minion", "Minion",
) { name -> ) { name ->
MinionProfileUtils.checkMinionNameWithoutPrefix(viewer.level().server, name) MinionProfileUtils.checkMinionNameWithoutPrefix(viewer.level().server, name)
} }.await()
if(newName != null) { if(newName != null) {
this@MinionLookGui.data.withName(newName) data.name = newName
updateName()
} }
} }
} }
@@ -38,7 +38,7 @@ abstract class MinionsGui {
protected abstract fun open() protected abstract fun open()
protected fun reopen() { protected open fun reopen() {
open() open()
} }
@@ -4,26 +4,26 @@ 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.gui.MinionsGui import io.github.skippyall.minions.gui.MinionsGui
import io.github.skippyall.minions.gui.minion.SimpleMinionsGui import io.github.skippyall.minions.gui.minion.SimpleMinionsGui
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.future.asCompletableFuture
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.world.inventory.MenuType import net.minecraft.world.inventory.MenuType
import net.minecraft.world.item.Items import net.minecraft.world.item.Items
import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletableFuture
object BooleanInput { object BooleanInput {
@JvmStatic
@JvmOverloads
fun confirm( fun confirm(
parent: MinionsGui, parent: MinionsGui,
title: Component, title: Component,
falseText: Component = Component.translatable("minions.gui.abort"), falseText: Component = Component.translatable("minions.gui.abort"),
trueText: Component = Component.translatable("minions.gui.confirm") trueText: Component = Component.translatable("minions.gui.confirm")
): CompletableDeferred<Boolean> { ): CompletableFuture<Boolean> {
val deferred = CompletableDeferred<Boolean>() val future = CompletableFuture<Boolean>()
SimpleMinionsGui(parent) { onClose: Runnable, me: SimpleMinionsGui -> SimpleMinionsGui(parent) { onClose: Runnable, me: SimpleMinionsGui ->
val gui: SimpleGui = object : SimpleGui(MenuType.GENERIC_3x3, parent.viewer, false) { val gui: SimpleGui = object : SimpleGui(MenuType.GENERIC_3x3, parent.viewer, false) {
override fun onPlayerClose(success: Boolean) { override fun onPlayerClose(success: Boolean) {
deferred.complete(false) future.complete(false)
onClose.run() onClose.run()
} }
} }
@@ -33,7 +33,7 @@ object BooleanInput {
3, GuiElementBuilder(Items.REDSTONE_BLOCK) 3, GuiElementBuilder(Items.REDSTONE_BLOCK)
.setName(falseText) .setName(falseText)
.setCallback(Runnable { .setCallback(Runnable {
deferred.complete(false) future.complete(false)
me.goBack() me.goBack()
}) })
) )
@@ -42,7 +42,7 @@ object BooleanInput {
5, GuiElementBuilder(Items.EMERALD_BLOCK) 5, GuiElementBuilder(Items.EMERALD_BLOCK)
.setName(trueText) .setName(trueText)
.setCallback(Runnable { .setCallback(Runnable {
deferred.complete(true) future.complete(true)
me.goBack() me.goBack()
}) })
) )
@@ -50,22 +50,6 @@ object BooleanInput {
gui.open() gui.open()
gui gui
} }
return deferred return future
}
@JvmStatic
@JvmOverloads
fun confirmFuture(
parent: MinionsGui,
title: Component,
falseText: Component = Component.translatable("minions.gui.abort"),
trueText: Component = Component.translatable("minions.gui.confirm")
): CompletableFuture<Boolean> {
return confirm(
parent,
title,
falseText,
trueText
).asCompletableFuture()
} }
} }
@@ -8,7 +8,7 @@ import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
public interface Result<T, E> { public sealed interface Result<T, E> permits Result.Success, Result.Error {
static <T> Result<T, String> wrap(UnsafeOperation<T> toWrap) { static <T> Result<T, String> wrap(UnsafeOperation<T> toWrap) {
return wrapCustomError(toWrap, Exception::getMessage); return wrapCustomError(toWrap, Exception::getMessage);
} }
@@ -3,9 +3,6 @@ package io.github.skippyall.minions.gui.input
import eu.pb4.sgui.api.elements.GuiElementBuilder import eu.pb4.sgui.api.elements.GuiElementBuilder
import eu.pb4.sgui.api.gui.AnvilInputGui import eu.pb4.sgui.api.gui.AnvilInputGui
import io.github.skippyall.minions.gui.MinionsGui import io.github.skippyall.minions.gui.MinionsGui
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.future.asCompletableFuture
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.world.inventory.AnvilMenu import net.minecraft.world.inventory.AnvilMenu
@@ -29,10 +26,9 @@ class TextInput<T>(
private lateinit var gui: AnvilInputGui private lateinit var gui: AnvilInputGui
private var result: Result<T, Component>? = null private var result: Result<T, Component>? = null
val deferred = CompletableDeferred<T?>() val future = CompletableFuture<T?>()
init { init {
updateConfirmButton(defaultValue)
open() open()
} }
@@ -44,14 +40,15 @@ class TextInput<T>(
override fun onPlayerClose(success: Boolean) { override fun onPlayerClose(success: Boolean) {
onBackingClosed() onBackingClosed()
if (deferred.isActive) { if (!future.isDone) {
deferred.complete(null) future.complete(null)
} }
} }
} }
gui.setTitle(title) gui.setTitle(title)
gui.setDefaultInputValue(defaultValue) gui.setDefaultInputValue(defaultValue)
updateConfirmButton(defaultValue)
gui.open() gui.open()
} }
@@ -74,7 +71,8 @@ class TextInput<T>(
fun onConfirm() { fun onConfirm() {
result?.ifSuccess { success: T -> result?.ifSuccess { success: T ->
deferred.complete(success) future.complete(success)
goBack()
} }
} }
@@ -85,7 +83,7 @@ class TextInput<T>(
title: Component, title: Component,
defaultValue: String, defaultValue: String,
parser: suspend (String) -> Result<T, Component>, parser: suspend (String) -> Result<T, Component>,
): Deferred<T?> { ): CompletableFuture<T?> {
val input = TextInput( val input = TextInput(
parent = gui, parent = gui,
title = title, title = title,
@@ -93,22 +91,7 @@ class TextInput<T>(
parser = parser, parser = parser,
) )
return input.deferred return input.future
}
@JvmStatic
fun <T>inputFuture(
gui: MinionsGui,
title: Component,
defaultValue: String,
parser: (String) -> Result<T, Component>,
): CompletableFuture<T?> {
return input(
gui = gui,
title = title,
defaultValue = defaultValue,
parser = parser
).asCompletableFuture()
} }
@JvmStatic @JvmStatic
@@ -116,7 +99,7 @@ class TextInput<T>(
gui: MinionsGui, gui: MinionsGui,
title: Component, title: Component,
defaultValue: String, defaultValue: String,
): Deferred<String?> { ): CompletableFuture<String?> {
return input<String>( return input<String>(
gui = gui, gui = gui,
title = title, title = title,
@@ -125,25 +108,12 @@ class TextInput<T>(
) )
} }
@JvmStatic
fun inputStringFuture(
gui: MinionsGui,
title: Component,
defaultValue: String,
): CompletableFuture<String?> {
return inputString(
gui = gui,
title = title,
defaultValue = defaultValue,
).asCompletableFuture()
}
@JvmStatic @JvmStatic
fun inputLong( fun inputLong(
gui: MinionsGui, gui: MinionsGui,
title: Component, title: Component,
defaultValue: Long, defaultValue: Long,
): Deferred<Long?> { ): CompletableFuture<Long?> {
return input<Long>( return input<Long>(
gui = gui, gui = gui,
title = title, title = title,
@@ -157,25 +127,12 @@ class TextInput<T>(
) )
} }
@JvmStatic
fun inputLongFuture(
gui: MinionsGui,
title: Component,
defaultValue: Long,
): CompletableFuture<Long?> {
return inputLong(
gui = gui,
title = title,
defaultValue = defaultValue,
).asCompletableFuture()
}
@JvmStatic @JvmStatic
fun inputDouble( fun inputDouble(
gui: MinionsGui, gui: MinionsGui,
title: Component, title: Component,
defaultValue: Double, defaultValue: Double,
): Deferred<Double?> { ): CompletableFuture<Double?> {
return input<Double>( return input<Double>(
gui = gui, gui = gui,
title = title, title = title,
@@ -188,18 +145,5 @@ class TextInput<T>(
}, },
) )
} }
@JvmStatic
fun inputDoubleFuture(
gui: MinionsGui,
title: Component,
defaultValue: Double,
): CompletableFuture<Double?> {
return inputDouble(
gui = gui,
title = title,
defaultValue = defaultValue,
).asCompletableFuture()
}
} }
} }
@@ -7,7 +7,6 @@ import io.github.skippyall.minions.gui.MinionsGui;
import io.github.skippyall.minions.gui.PaginatedList; import io.github.skippyall.minions.gui.PaginatedList;
import io.github.skippyall.minions.gui.minion.GuiContext; import io.github.skippyall.minions.gui.minion.GuiContext;
import io.github.skippyall.minions.minion.MinionRuntime; import io.github.skippyall.minions.minion.MinionRuntime;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.program.instruction.ConfiguredInstruction; import io.github.skippyall.minions.program.instruction.ConfiguredInstruction;
import io.github.skippyall.minions.program.supplier.Parameter; import io.github.skippyall.minions.program.supplier.Parameter;
import io.github.skippyall.minions.program.supplier.ValueSupplier; import io.github.skippyall.minions.program.supplier.ValueSupplier;
@@ -60,7 +60,7 @@ public class ConfigureInstructionGui extends MinionsGui implements ConfiguredIns
gui.setSlot(7, new GuiElementBuilder(Items.LAVA_BUCKET) gui.setSlot(7, new GuiElementBuilder(Items.LAVA_BUCKET)
.setName(Component.translatable("minions.gui.instruction.configure.delete")) .setName(Component.translatable("minions.gui.instruction.configure.delete"))
.setCallback(() -> BooleanInput.confirmFuture(this, Component.translatable("minions.gui.instruction.configure.delete.confirm", name)) .setCallback(() -> BooleanInput.confirm(this, Component.translatable("minions.gui.instruction.configure.delete.confirm", name))
.thenAccept((confirmed) -> { .thenAccept((confirmed) -> {
if(confirmed) { if(confirmed) {
minion.getInstructionManager().removeInstruction(name); minion.getInstructionManager().removeInstruction(name);
@@ -28,7 +28,6 @@ public class ConverterGui extends MinionsGui {
public ConverterGui(MinionsGui parent, @Nullable ValueConverter<?,?> converter, ValueType<?> from, ValueType<?> to, ConverterList list, boolean isNew, int index) { public ConverterGui(MinionsGui parent, @Nullable ValueConverter<?,?> converter, ValueType<?> from, ValueType<?> to, ConverterList list, boolean isNew, int index) {
super(parent); super(parent);
open();
this.converter = converter; this.converter = converter;
if(converter != null) { if(converter != null) {
this.valueConverterType = converter.getType(); this.valueConverterType = converter.getType();
@@ -38,6 +37,8 @@ public class ConverterGui extends MinionsGui {
this.list = list; this.list = list;
this.isNew = isNew; this.isNew = isNew;
this.index = index; this.index = index;
open();
} }
@Override @Override
@@ -54,7 +54,7 @@ public class ConverterListGui extends MinionsGui {
gui.setSlot(23, new GuiElementBuilder(Items.ARROW) gui.setSlot(23, new GuiElementBuilder(Items.ARROW)
.setCallback(() -> { .setCallback(() -> {
if(page * 4 + 4 < converters.getConverters().size()) { if(page * 4 + 4 < converters.getConverters().size() + 1) {
page++; page++;
updateConverters(); updateConverters();
} }
@@ -67,6 +67,10 @@ public class ConverterListGui extends MinionsGui {
} }
public void updateConverters() { public void updateConverters() {
for(int slot = 9; slot < 18; slot++) {
gui.clearSlot(slot);
}
int lastConverter = Math.min(5, converters.getConverters().size() + 2 - page * 4); int lastConverter = Math.min(5, converters.getConverters().size() + 2 - page * 4);
for(int i = 0; i < lastConverter; i++) { for(int i = 0; i < lastConverter; i++) {
//Each page has 5 converters, but the last is displayed on the next page as well //Each page has 5 converters, but the last is displayed on the next page as well
@@ -73,7 +73,7 @@ public class InstructionGui {
} }
public static CompletableFuture<String> inputInstructionName(MinionsGui parent, GuiContext.Minion context, String defaultValue) { public static CompletableFuture<String> inputInstructionName(MinionsGui parent, GuiContext.Minion context, String defaultValue) {
return TextInput.inputFuture(parent, Component.translatable("minions.gui.instruction.enter_name"), defaultValue, name -> { return TextInput.input(parent, Component.translatable("minions.gui.instruction.enter_name"), defaultValue, (name, _) -> {
if (context.getMinion().getInstructionManager().hasInstruction(name)) { if (context.getMinion().getInstructionManager().hasInstruction(name)) {
return new Result.Error<>(Component.translatable("minions.gui.instruction.name_already_used")); return new Result.Error<>(Component.translatable("minions.gui.instruction.name_already_used"));
} }
@@ -1,43 +1,64 @@
package io.github.skippyall.minions.gui.minion; package io.github.skippyall.minions.gui.minion
import io.github.skippyall.minions.minion.MinionRuntime; import io.github.skippyall.minions.gui.minion.GuiContextImpl.*
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import io.github.skippyall.minions.minion.MinionRuntime
import io.github.skippyall.minions.program.instruction.ConfiguredInstruction; import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer
import io.github.skippyall.minions.program.supplier.Parameter; import io.github.skippyall.minions.program.instruction.ConfiguredInstruction
import net.minecraft.server.level.ServerPlayer; import io.github.skippyall.minions.program.supplier.Parameter
import net.minecraft.server.level.ServerPlayer
public interface GuiContext { interface GuiContext {
ServerPlayer getViewer(); val viewer: ServerPlayer
static GuiContext create(ServerPlayer viewer) { companion object {
return new GuiContextImpl(viewer); @JvmStatic
} fun create(viewer: ServerPlayer): GuiContext {
return GuiContextImpl(viewer)
interface Minion extends GuiContext {
MinionFakePlayer getMinion();
static GuiContext.Minion create(GuiContext context, MinionFakePlayer minion) {
return new GuiContextImpl.MinionImpl(context, minion);
} }
} }
interface Instruction extends Minion { interface Minion : GuiContext {
ConfiguredInstruction<MinionRuntime> getInstruction(); val minion: MinionFakePlayer
String getName(); companion object {
@JvmStatic
void setName(String name); fun create(context: GuiContext, minion: MinionFakePlayer): Minion {
return MinionImpl(
static GuiContext.Instruction create(GuiContext.Minion context, ConfiguredInstruction<MinionRuntime> instruction, String name) { if(context is MinionImpl) context.context else context,
return new GuiContextImpl.InstructionImpl(context, instruction, name); minion
)
}
} }
} }
interface ValueSupplier extends Instruction { interface Instruction : Minion {
Parameter<?> getParameter(); val instruction: ConfiguredInstruction<MinionRuntime>
static GuiContext.ValueSupplier create(GuiContext.Instruction context, Parameter<?> parameter) { var name: String
return new GuiContextImpl.ValueSupplierImpl(context, parameter);
companion object {
@JvmStatic
fun create(context: Minion, instruction: ConfiguredInstruction<MinionRuntime>, name: String): Instruction {
return InstructionImpl(
if(context is InstructionImpl) context.context else context,
instruction,
name
)
}
}
}
interface ValueSupplier : Instruction {
val parameter: Parameter<*>
companion object {
@JvmStatic
fun create(context: Instruction, parameter: Parameter<*>): ValueSupplier {
return ValueSupplierImpl(
if(context is ValueSupplierImpl) context.context else context,
parameter
)
}
} }
} }
} }
@@ -1,120 +1,26 @@
package io.github.skippyall.minions.gui.minion; package io.github.skippyall.minions.gui.minion
import io.github.skippyall.minions.minion.MinionRuntime; import io.github.skippyall.minions.minion.MinionRuntime
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer
import io.github.skippyall.minions.program.instruction.ConfiguredInstruction; import io.github.skippyall.minions.program.instruction.ConfiguredInstruction
import io.github.skippyall.minions.program.supplier.Parameter; import io.github.skippyall.minions.program.supplier.Parameter
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer
//If only this mod was kotlin //Thank you kotlin
public class GuiContextImpl implements GuiContext { class GuiContextImpl(override val viewer: ServerPlayer) : GuiContext {
private final ServerPlayer viewer; class MinionImpl(
val context: GuiContext,
override val minion: MinionFakePlayer
) : GuiContext by context, GuiContext.Minion
public GuiContextImpl(ServerPlayer viewer) { class InstructionImpl(
this.viewer = viewer; val context: GuiContext.Minion,
} override val instruction: ConfiguredInstruction<MinionRuntime>,
override var name: String
) : GuiContext.Minion by context, GuiContext.Instruction
@Override class ValueSupplierImpl(
public ServerPlayer getViewer() { val context: GuiContext.Instruction,
return viewer; override val parameter: Parameter<*>
} ) : GuiContext.Instruction by context, GuiContext.ValueSupplier
public static class MinionImpl extends DelegatingGuiContextImpl<GuiContext> implements GuiContext.Minion {
private final MinionFakePlayer minion;
public MinionImpl(GuiContext context, MinionFakePlayer minion) {
super(context instanceof DelegatingGuiContextImpl<?> impl ? impl.context : context);
this.minion = minion;
}
@Override
public MinionFakePlayer getMinion() {
return minion;
}
}
public static class InstructionImpl extends DelegatingMinionImpl<GuiContext.Minion> implements GuiContext.Instruction {
private final ConfiguredInstruction<MinionRuntime> instruction;
private String name;
public InstructionImpl(GuiContext.Minion context, ConfiguredInstruction<MinionRuntime> instruction, String name) {
super(context instanceof DelegatingMinionImpl<?> impl ? impl.context : context);
this.instruction = instruction;
this.name = name;
}
@Override
public ConfiguredInstruction<MinionRuntime> getInstruction() {
return instruction;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
}
public static class ValueSupplierImpl extends DelegatingInstructionImpl<GuiContext.Instruction> implements GuiContext.ValueSupplier {
private final Parameter<?> parameter;
public ValueSupplierImpl(GuiContext.Instruction context, Parameter<?> parameter) {
super(context instanceof DelegatingInstructionImpl<?> impl ? impl.context : context);
this.parameter = parameter;
}
@Override
public Parameter<?> getParameter() {
return parameter;
}
}
public static class DelegatingGuiContextImpl<C extends GuiContext> implements GuiContext {
protected final C context;
public DelegatingGuiContextImpl(C context) {
this.context = context;
}
@Override
public ServerPlayer getViewer() {
return context.getViewer();
}
}
public static class DelegatingMinionImpl<C extends GuiContext.Minion> extends DelegatingGuiContextImpl<C> implements GuiContext.Minion {
public DelegatingMinionImpl(C context) {
super(context);
}
@Override
public MinionFakePlayer getMinion() {
return context.getMinion();
}
}
public static class DelegatingInstructionImpl<C extends GuiContext.Instruction> extends DelegatingMinionImpl<C> implements GuiContext.Instruction {
public DelegatingInstructionImpl(C context) {
super(context);
}
@Override
public ConfiguredInstruction<MinionRuntime> getInstruction() {
return context.getInstruction();
}
@Override
public String getName() {
return context.getName();
}
@Override
public void setName(String name) {
context.setName(name);
}
}
} }
@@ -47,7 +47,7 @@ public abstract class BlockEntityMinionListener<E extends BlockEntity> implement
public static <T extends BlockEntityMinionListener<?>> T getListener(Level world, BlockPos pos, UUID minionUuid, Class<T> clazz) { public static <T extends BlockEntityMinionListener<?>> T getListener(Level world, BlockPos pos, UUID minionUuid, Class<T> clazz) {
if(minionUuid != null) { if(minionUuid != null) {
for (MinionListener listener : MinionPersistentState.get(world.getServer()).getMinionData(minionUuid).listeners()) { for (MinionListener listener : MinionPersistentState.get(world.getServer()).getMinionData(minionUuid).getListeners()) {
if (listener instanceof BlockEntityMinionListener<?> tl && tl.pos.equals(pos) && tl.worldKey.equals(world.dimension()) && clazz.isInstance(tl)) { if (listener instanceof BlockEntityMinionListener<?> tl && tl.pos.equals(pos) && tl.worldKey.equals(world.dimension()) && clazz.isInstance(tl)) {
return clazz.cast(tl); return clazz.cast(tl);
} }
@@ -95,13 +95,13 @@ public abstract class BlockEntityMinionListener<E extends BlockEntity> implement
} }
public void add(MinecraftServer server) { public void add(MinecraftServer server) {
MinionPersistentState.get(server).getMinionData(minionUuid).listeners().addListener(this); MinionPersistentState.get(server).getMinionData(minionUuid).getListeners().addListener(this);
MinionPersistentState.get(server).setDirty(); MinionPersistentState.get(server).setDirty();
this.minion = (MinionFakePlayer) server.getPlayerList().getPlayer(minionUuid); this.minion = (MinionFakePlayer) server.getPlayerList().getPlayer(minionUuid);
} }
public void remove(MinecraftServer server) { public void remove(MinecraftServer server) {
MinionPersistentState.get(server).getMinionData(minionUuid).listeners().removeListener(this); MinionPersistentState.get(server).getMinionData(minionUuid).getListeners().removeListener(this);
MinionPersistentState.get(server).setDirty(); MinionPersistentState.get(server).setDirty();
} }
@@ -1,37 +1,29 @@
package io.github.skippyall.minions.listener; package io.github.skippyall.minions.listener
import org.jetbrains.annotations.NotNull; import java.util.concurrent.CopyOnWriteArraySet
import java.util.Iterator; open class ListenerManager<T>(
import java.util.Set; protected val listeners: MutableSet<T> = CopyOnWriteArraySet(),
import java.util.concurrent.CopyOnWriteArraySet; val onChange: () -> Unit = {},
) : MutableIterable<T> by listeners {
public class ListenerManager<T> implements Iterable<T> { fun addListener(listener: T) {
protected final Set<T> listeners; listeners.add(listener)
onChange()
public ListenerManager() {
this(new CopyOnWriteArraySet<>());
} }
protected ListenerManager(Set<T> listeners) { fun removeListener(listener: T) {
this.listeners = listeners; listeners.remove(listener)
onChange()
} }
public void addListener(T listener) { override fun iterator(): MutableIterator<T> {
listeners.add(listener); val iterator = listeners.iterator()
return object : MutableIterator<T> by iterator {
override fun remove() {
iterator.remove()
onChange()
} }
public void removeListener(T listener) {
listeners.remove(listener);
} }
@Override
public @NotNull Iterator<T> iterator() {
return listeners.iterator();
}
@Override
public boolean equals(Object obj) {
return super.equals(obj);
} }
} }
@@ -1,46 +1,47 @@
package io.github.skippyall.minions.listener; package io.github.skippyall.minions.listener
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec
import com.mojang.serialization.MapCodec; import com.mojang.serialization.MapCodec
import net.minecraft.core.Registry; import io.github.skippyall.minions.listener.SerializableListenerManager.SerializableListener
import net.minecraft.resources.Identifier; import net.minecraft.core.Registry
import net.minecraft.resources.Identifier
import java.util.Optional
import java.util.concurrent.CopyOnWriteArraySet
import java.util.ArrayList; class SerializableListenerManager<T : SerializableListener>(
import java.util.List; listeners: MutableSet<T> = CopyOnWriteArraySet(),
import java.util.Optional; onChange: () -> Unit = {},
import java.util.Set; ) : ListenerManager<T>(listeners, onChange) {
import java.util.concurrent.CopyOnWriteArraySet;
public class SerializableListenerManager<T extends SerializableListenerManager.SerializableListener> extends ListenerManager<T> { interface SerializableListener {
public SerializableListenerManager() { val codecId: Optional<Identifier>
super(); get() = Optional.empty<Identifier>()
} }
protected SerializableListenerManager(Set<T> listeners) { companion object {
super(listeners); @JvmStatic
} @JvmOverloads
fun <T : SerializableListener> getCodec(
public static <T extends SerializableListener> Codec<SerializableListenerManager<T>> getCodec(Registry<Codec<? extends T>> registry) { registry: Registry<Codec<out T>>,
return registry.byNameCodec().<T>dispatch( onChange: () -> Unit = {},
listener -> listener.getCodecId().map(registry::getValue).orElse(MapCodec.unitCodec(null)), ): Codec<SerializableListenerManager<T>> {
codec -> codec.fieldOf("data") return registry.byNameCodec().dispatch(
{ listener -> listener.codecId.map(registry::getValue)
.orElseGet { MapCodec.unitCodec(null) }
},
{ codec -> codec.fieldOf("data") }
).listOf().xmap( ).listOf().xmap(
list -> new SerializableListenerManager<>(new CopyOnWriteArraySet<>(list)), { list -> SerializableListenerManager<T>(CopyOnWriteArraySet<T>(list), onChange) },
manager -> { { manager ->
List<T> serializableListeners = new ArrayList<>(); val serializableListeners: MutableList<T> = mutableListOf()
for(T listener : manager.listeners) { for (listener in manager.listeners) {
if(listener.getCodecId().isPresent()) { if (listener.codecId.isPresent) {
serializableListeners.add(listener); serializableListeners.add(listener)
} }
} }
return serializableListeners; return@xmap serializableListeners
} }
); )
}
public interface SerializableListener {
default Optional<Identifier> getCodecId() {
return Optional.empty();
} }
} }
} }
@@ -1,58 +1,82 @@
package io.github.skippyall.minions.minion; package io.github.skippyall.minions.minion
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.listener.SerializableListenerManager; import io.github.skippyall.minions.listener.SerializableListenerManager
import io.github.skippyall.minions.registration.MinionRegistries; import io.github.skippyall.minions.registration.MinionRegistries
import net.minecraft.core.UUIDUtil; import net.minecraft.core.UUIDUtil
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer
import net.minecraft.util.ExtraCodecs; import net.minecraft.util.ExtraCodecs
import java.util.Optional; import java.util.Optional
import java.util.UUID; import java.util.UUID
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
public record MinionData( class MinionData(
UUID uuid, initialUuid: UUID,
String name, initialName: String,
Optional<PropertyMap> skin, initialSkin: Optional<PropertyMap>,
boolean isSpawned, initialIsSpawned: Boolean,
SerializableListenerManager<MinionListener> listeners, val listeners: SerializableListenerManager<MinionListener>,
MinionConfig config initialConfig: MinionConfig,
var onDirty: Runnable = {},
) { ) {
public static final Codec<MinionData> CODEC = RecordCodecBuilder.create(instance -> var uuid by DirtyProperty(initialUuid, this::setDirty)
var name by DirtyProperty(initialName, this::setDirty)
var skin by DirtyProperty(initialSkin, this::setDirty)
var isSpawned by DirtyProperty(initialIsSpawned, this::setDirty)
var config by DirtyProperty(initialConfig, this::setDirty)
fun setDirty() {
this@MinionData.onDirty.run()
}
companion object {
@JvmField
val CODEC: Codec<MinionData> =
RecordCodecBuilder.create { instance ->
instance.group( instance.group(
UUIDUtil.AUTHLIB_CODEC.fieldOf("uuid").forGetter(MinionData::uuid), UUIDUtil.AUTHLIB_CODEC.fieldOf("uuid").forGetter(MinionData::uuid),
Codec.STRING.fieldOf("name").forGetter(MinionData::name), Codec.STRING.fieldOf("name").forGetter(MinionData::name),
ExtraCodecs.PROPERTY_MAP.optionalFieldOf("skin").forGetter(MinionData::skin), ExtraCodecs.PROPERTY_MAP.optionalFieldOf("skin").forGetter(MinionData::skin),
Codec.BOOL.optionalFieldOf("isSpawned", false).forGetter(MinionData::isSpawned), Codec.BOOL.optionalFieldOf("isSpawned", false).forGetter(MinionData::isSpawned),
SerializableListenerManager.getCodec(MinionRegistries.MINION_LISTENER_CODECS).optionalFieldOf("listeners").xmap( SerializableListenerManager.getCodec<MinionListener>(MinionRegistries.MINION_LISTENER_CODECS)
optional -> optional.orElseGet(SerializableListenerManager::new), .optionalFieldOf("listeners").xmap(
Optional::of { optional -> optional.orElseGet { SerializableListenerManager() } },
Optional<SerializableListenerManager<MinionListener>>::of
).forGetter(MinionData::listeners), ).forGetter(MinionData::listeners),
MinionConfig.CODEC.optionalFieldOf("config", new MinionConfig()).forGetter(MinionData::config) MinionConfig.CODEC.optionalFieldOf("config", MinionConfig())
).apply(instance, MinionData::new) .forGetter(MinionData::config)
); ).apply(
instance,
::MinionData
)
}
public static MinionData createDefault(MinecraftServer server) { @JvmStatic
return new MinionData( fun createDefault(server: MinecraftServer): MinionData {
return MinionData(
UUID.randomUUID(), UUID.randomUUID(),
MinionProfileUtils.newDefaultMinionName(server), MinionProfileUtils.newDefaultMinionName(server),
Optional.empty(), Optional.empty<PropertyMap>(),
false, false,
new SerializableListenerManager<>(), SerializableListenerManager(),
new MinionConfig() MinionConfig()
); ) {
MinionPersistentState.get(server).isDirty = true
}
}
} }
public MinionData withName(String name) { class DirtyProperty<V>(var value: V, val onDirty: () -> Unit) : ReadWriteProperty<Any?, V> {
return new MinionData(uuid, name, skin, isSpawned, listeners, config); override fun getValue(thisRef: Any?, property: KProperty<*>): V {
return value
} }
public MinionData withSkin(Optional<PropertyMap> skin) { override fun setValue(thisRef: Any?, property: KProperty<*>, value: V) {
return new MinionData(uuid, name, skin, isSpawned, listeners, config); this.value = value
onDirty()
} }
public MinionData withSpawned(boolean isSpawned) {
return new MinionData(uuid, name, skin, isSpawned, listeners, config);
} }
} }
@@ -79,7 +79,7 @@ public class MinionItem extends Item implements PolymerItem {
} }
public static void setData(MinecraftServer server, MinionData data, ItemStack item) { public static void setData(MinecraftServer server, MinionData data, ItemStack item) {
item.set(MinionComponentTypes.MINION_DATA, data.uuid()); item.set(MinionComponentTypes.MINION_DATA, data.getUuid());
MinionPersistentState.get(server).updateMinionData(data); MinionPersistentState.get(server).updateMinionData(data);
} }
@@ -31,7 +31,8 @@ public class MinionPersistentState extends SavedData {
public MinionPersistentState(List<MinionData> dataList) { public MinionPersistentState(List<MinionData> dataList) {
for (MinionData data : dataList) { for (MinionData data : dataList) {
minionData.put(data.uuid(), data); data.setOnDirty(this::setDirty);
minionData.put(data.getUuid(), data);
} }
} }
@@ -48,7 +49,8 @@ public class MinionPersistentState extends SavedData {
} }
public void updateMinionData(MinionData data) { public void updateMinionData(MinionData data) {
minionData.put(data.uuid(), data); minionData.put(data.getUuid(), data);
data.setOnDirty(this::setDirty);
setDirty(); setDirty();
} }
@@ -62,7 +64,7 @@ public class MinionPersistentState extends SavedData {
public Optional<MinionData> getMinionWithName(String name) { public Optional<MinionData> getMinionWithName(String name) {
return minionData.values().stream() return minionData.values().stream()
.filter(data -> data.name().equals(name)) .filter(data -> data.getName().equals(name))
.findFirst(); .findFirst();
} }
@@ -73,16 +73,16 @@ public class MinionFakePlayer extends ServerPlayer {
if(!data.isSpawned() || force) { if(!data.isSpawned() || force) {
MinecraftServer server = level.getServer(); MinecraftServer server = level.getServer();
PropertyMap skin = data.skin().orElse(null); PropertyMap skin = data.getSkin().orElse(null);
GameProfile profile = MinionProfileUtils.makeNewMinionProfile(data.uuid(), data.name(), skin); GameProfile profile = MinionProfileUtils.makeNewMinionProfile(data.getUuid(), data.getName(), skin);
server.schedule(server.wrapRunnable(() -> doSpawn(data, profile, server, level, pos, rot))); server.schedule(server.wrapRunnable(() -> doSpawn(data, profile, server, level, pos, rot)));
} }
} }
private static void doSpawn(MinionData data, GameProfile profile, MinecraftServer server, ServerLevel level, @Nullable Vec3 pos, @Nullable Vec2 rot) { private static void doSpawn(MinionData data, GameProfile profile, MinecraftServer server, ServerLevel level, @Nullable Vec3 pos, @Nullable Vec2 rot) {
MinionFakePlayer instance = new MinionFakePlayer(server, level, profile, ClientInformation.createDefault()); MinionFakePlayer instance = new MinionFakePlayer(server, level, profile, ClientInformation.createDefault());
MinionPersistentState.get(server).updateMinionData(data.withSpawned(true)); data.setSpawned(true);
if(pos != null && rot != null) { if(pos != null && rot != null) {
instance.fixStartingPosition = () -> instance.snapTo(pos.x, pos.y, pos.z, rot.x, rot.y); instance.fixStartingPosition = () -> instance.snapTo(pos.x, pos.y, pos.z, rot.x, rot.y);
@@ -158,7 +158,7 @@ public class MinionFakePlayer extends ServerPlayer {
} }
public SerializableListenerManager<MinionListener> listeners() { public SerializableListenerManager<MinionListener> listeners() {
return getData().listeners(); return getData().getListeners();
} }
public void addMinionListener(MinionListener listener) { public void addMinionListener(MinionListener listener) {
@@ -174,7 +174,7 @@ public class MinionFakePlayer extends ServerPlayer {
} }
public boolean canSpawnMobs() { public boolean canSpawnMobs() {
return moduleInventory.hasAbility(SpecialAbilities.MOB_SPAWNING) || getData().config().getOption(MinionConfigOptions.spawnAndDespawnMobs); return moduleInventory.hasAbility(SpecialAbilities.MOB_SPAWNING) || getData().getConfig().getOption(MinionConfigOptions.spawnAndDespawnMobs);
} }
public boolean canDespawnMobs() { public boolean canDespawnMobs() {
@@ -213,7 +213,7 @@ public class MinionFakePlayer extends ServerPlayer {
})); }));
} }
MinionPersistentState.get(getServer()).updateMinionData(getData().withSpawned(false)); getData().setSpawned(false);
} }
@Override @Override
@@ -10,7 +10,7 @@ import java.util.concurrent.CompletableFuture;
public class NameSkinProvider implements SkinProvider { public class NameSkinProvider implements SkinProvider {
@Override @Override
public CompletableFuture<ResolvableProfile> openSkinMenu(MinionsGui parent) { public CompletableFuture<ResolvableProfile> openSkinMenu(MinionsGui parent) {
return TextInput.inputStringFuture(parent, Component.translatable("minions.gui.look.skin.name.title"), "") return TextInput.inputString(parent, Component.translatable("minions.gui.look.skin.name.title"), "")
.thenApply(name -> name != null ? ResolvableProfile.createUnresolved(name) : null); .thenApply(name -> name != null ? ResolvableProfile.createUnresolved(name) : null);
} }
@@ -10,7 +10,7 @@ import java.util.concurrent.CompletableFuture;
public class UUIDSkinProvider implements SkinProvider { public class UUIDSkinProvider implements SkinProvider {
@Override @Override
public CompletableFuture<ResolvableProfile> openSkinMenu(MinionsGui parent) { public CompletableFuture<ResolvableProfile> openSkinMenu(MinionsGui parent) {
return TextInput.inputStringFuture(parent, Component.translatable("minions.gui.look.skin.uuid.title"), "") return TextInput.inputString(parent, Component.translatable("minions.gui.look.skin.uuid.title"), "")
.thenApply(name -> name != null ? ResolvableProfile.createUnresolved(name) : null); .thenApply(name -> name != null ? ResolvableProfile.createUnresolved(name) : null);
} }
@@ -13,7 +13,7 @@ import org.spongepowered.asm.mixin.injection.ModifyArg;
public class ClientboundPlayerInfoUpdatePacket$EntryMixin { public class ClientboundPlayerInfoUpdatePacket$EntryMixin {
@ModifyArg(method = "<init>(Lnet/minecraft/server/level/ServerPlayer;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket$Entry;<init>(Ljava/util/UUID;Lcom/mojang/authlib/GameProfile;ZILnet/minecraft/world/level/GameType;Lnet/minecraft/network/chat/Component;ZILnet/minecraft/network/chat/RemoteChatSession$Data;)V"), index = 2) @ModifyArg(method = "<init>(Lnet/minecraft/server/level/ServerPlayer;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket$Entry;<init>(Ljava/util/UUID;Lcom/mojang/authlib/GameProfile;ZILnet/minecraft/world/level/GameType;Lnet/minecraft/network/chat/Component;ZILnet/minecraft/network/chat/RemoteChatSession$Data;)V"), index = 2)
private static boolean removeMinionFromTabList(boolean original, @Local(argsOnly = true) ServerPlayer player) { private static boolean removeMinionFromTabList(boolean original, @Local(argsOnly = true) ServerPlayer player) {
if(player instanceof MinionFakePlayer minion && !minion.getData().config().getOption(MinionConfigOptions.showInTabList)) { if(player instanceof MinionFakePlayer minion && !minion.getData().getConfig().getOption(MinionConfigOptions.showInTabList)) {
return false; return false;
} }
@@ -24,7 +24,7 @@ public class MinecraftServerMixin {
public List<ServerPlayer> ignoreFakePlayers(List<ServerPlayer> original) { public List<ServerPlayer> ignoreFakePlayers(List<ServerPlayer> original) {
return original.stream() return original.stream()
.filter(player -> !(player instanceof MinionFakePlayer minion .filter(player -> !(player instanceof MinionFakePlayer minion
&& !minion.getData().config().getOption(MinionConfigOptions.showInServerList))) && !minion.getData().getConfig().getOption(MinionConfigOptions.showInServerList)))
.collect(Collectors.toCollection(ArrayList::new)); .collect(Collectors.toCollection(ArrayList::new));
} }
@@ -59,7 +59,7 @@ public class PlayerListMixin {
@WrapOperation(method = "placeNewPlayer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/players/PlayerList;broadcastSystemMessage(Lnet/minecraft/network/chat/Component;Z)V")) @WrapOperation(method = "placeNewPlayer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/players/PlayerList;broadcastSystemMessage(Lnet/minecraft/network/chat/Component;Z)V"))
public void noLoginMessage(PlayerList instance, Component message, boolean overlay, Operation<Void> original, @Local(argsOnly = true) ServerPlayer player) { public void noLoginMessage(PlayerList instance, Component message, boolean overlay, Operation<Void> original, @Local(argsOnly = true) ServerPlayer player) {
if(!(player instanceof MinionFakePlayer minion && !minion.getData().config().getOption(MinionConfigOptions.sendLoginMessage))) { if(!(player instanceof MinionFakePlayer minion && !minion.getData().getConfig().getOption(MinionConfigOptions.sendLoginMessage))) {
original.call(instance, message, overlay); original.call(instance, message, overlay);
} }
} }
@@ -67,7 +67,7 @@ public class PlayerListMixin {
@ModifyReceiver(method = "canPlayerLogin", at = @At(value = "INVOKE", target = "Ljava/util/List;size()I")) @ModifyReceiver(method = "canPlayerLogin", at = @At(value = "INVOKE", target = "Ljava/util/List;size()I"))
public List<ServerPlayer> noMinionCounting(List<ServerPlayer> instance) { public List<ServerPlayer> noMinionCounting(List<ServerPlayer> instance) {
return instance.stream() return instance.stream()
.filter(player -> !(player instanceof MinionFakePlayer minion && !minion.getData().config().getOption(MinionConfigOptions.countForPlayerLimit))) .filter(player -> !(player instanceof MinionFakePlayer minion && !minion.getData().getConfig().getOption(MinionConfigOptions.countForPlayerLimit)))
.collect(Collectors.toCollection(ArrayList::new)); .collect(Collectors.toCollection(ArrayList::new));
} }
} }
@@ -19,7 +19,7 @@ public class ServerGamePacketListenerImplMixin {
@WrapOperation(method = "removePlayerFromWorld", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/players/PlayerList;broadcastSystemMessage(Lnet/minecraft/network/chat/Component;Z)V")) @WrapOperation(method = "removePlayerFromWorld", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/players/PlayerList;broadcastSystemMessage(Lnet/minecraft/network/chat/Component;Z)V"))
public void noLogoutMessage(PlayerList instance, Component message, boolean overlay, Operation<Void> original) { public void noLogoutMessage(PlayerList instance, Component message, boolean overlay, Operation<Void> original) {
if(!(player instanceof MinionFakePlayer minion && !minion.getData().config().getOption(MinionConfigOptions.sendLogoutMessage))) { if(!(player instanceof MinionFakePlayer minion && !minion.getData().getConfig().getOption(MinionConfigOptions.sendLogoutMessage))) {
original.call(instance, message, overlay); original.call(instance, message, overlay);
} }
} }
@@ -13,7 +13,7 @@ import org.spongepowered.asm.mixin.injection.At;
public class SleepStatusMixin { public class SleepStatusMixin {
@WrapOperation(method = "update", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayer;isSpectator()Z")) @WrapOperation(method = "update", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayer;isSpectator()Z"))
public boolean excludeMinions(ServerPlayer instance, Operation<Boolean> original) { public boolean excludeMinions(ServerPlayer instance, Operation<Boolean> original) {
if (instance instanceof MinionFakePlayer minion && !minion.getData().config().getOption(MinionConfigOptions.countForSleeping)) { if (instance instanceof MinionFakePlayer minion && !minion.getData().getConfig().getOption(MinionConfigOptions.countForSleeping)) {
return true; return true;
} else { } else {
return original.call(instance); return original.call(instance);
@@ -78,8 +78,8 @@ public class ConfiguredInstruction<R extends InstructionRuntime<R>> {
public void run(R minion) { public void run(R minion) {
if(canRun() && !isRunning()) { if(canRun() && !isRunning()) {
ParameterValueList resolvedArguments = arguments.resolve(minion);
try { try {
ParameterValueList resolvedArguments = arguments.resolve(minion);
execution = instruction.createExecution(resolvedArguments, minion); execution = instruction.createExecution(resolvedArguments, minion);
execution.start(minion); execution.start(minion);
} catch (Exception e) { } catch (Exception e) {
@@ -37,11 +37,6 @@ public class ValueSupplierList<R extends InstructionRuntime<R>> {
return List.copyOf(arguments.values()); return List.copyOf(arguments.values());
} }
public <T> T getValue(Parameter<T> parameter, R runtime) {
ValueSupplierEntry<?,R> entry = getEntry(parameter);
return parameter.type().checkedCast(entry.getValue(runtime));
}
public ValueSupplier<?,R> getArgument(Parameter<?> parameter) { public ValueSupplier<?,R> getArgument(Parameter<?> parameter) {
if(arguments.containsKey(parameter)) { if(arguments.containsKey(parameter)) {
return arguments.get(parameter).supplier; return arguments.get(parameter).supplier;
@@ -153,20 +148,24 @@ public class ValueSupplierList<R extends InstructionRuntime<R>> {
this.supplier = supplier; this.supplier = supplier;
} }
private void addToList(ParameterValueList list, R runtime) { private @Nullable Component addToList(ParameterValueList list, R runtime) {
list.setValue(parameter, getValue(runtime)); Result<P, Component> result = getValue(supplier, runtime);
switch (result) {
case Result.Success<P, Component> success -> {
list.setValue(parameter, success.result());
return null;
}
case Result.Error<P, Component> error -> {
return error.message();
}
}
} }
public @Nullable P getValue(R runtime) { private <S> Result<P, Component> getValue(ValueSupplier<S, R> supplier, R runtime) {
return getValue(supplier, runtime);
}
//Ich liebe generische Typen (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)
private <S> @Nullable P getValue(ValueSupplier<S, R> supplier, R runtime) {
S value = supplier.resolve(runtime); S value = supplier.resolve(runtime);
Result<TypedValue<?>, Component> convertedResult = converters.convert(new TypedValue<>(value, supplier.getValueType())); Result<TypedValue<?>, Component> convertedResult = converters.convert(new TypedValue<>(value, supplier.getValueType()));
return convertedResult.flatMap(convertedValue -> Casts.castOrError(convertedValue, parameter.type())).getOrDefault(null); return convertedResult.flatMap(convertedValue -> Casts.castOrError(convertedValue, parameter.type()));
} }
public @Nullable Component check() { public @Nullable Component check() {
@@ -22,7 +22,7 @@ public class ValueTypes {
Codec.LONG, Codec.LONG,
0L, 0L,
o -> o instanceof Long l ? l : null, o -> o instanceof Long l ? l : null,
(parent, oldValue) -> TextInput.inputLongFuture( (parent, oldValue) -> TextInput.inputLong(
parent, parent,
Component.literal("Integer"), Component.literal("Integer"),
oldValue oldValue
@@ -37,10 +37,10 @@ public class ValueTypes {
Codec.DOUBLE, Codec.DOUBLE,
0D, 0D,
o -> o instanceof Double d ? d : null, o -> o instanceof Double d ? d : null,
(parent, oldValue) -> TextInput.inputDoubleFuture( (parent, oldValue) -> TextInput.inputDouble(
parent, parent,
Component.literal("Number"), Component.literal("Number"),
oldValue oldValue != null ? oldValue : 0D
), ),
value -> Component.literal(value.toString()) value -> Component.literal(value.toString())
) )
@@ -52,7 +52,7 @@ public class ValueTypes {
Codec.BOOL, Codec.BOOL,
false, false,
o -> o instanceof Boolean b ? b : null, o -> o instanceof Boolean b ? b : null,
(parent, value) -> BooleanInput.confirmFuture(parent, Component.literal(""), Component.translatable("value_type.minions.boolean.false"), Component.translatable("value_type.minions.boolean.true")), (parent, value) -> BooleanInput.confirm(parent, Component.literal(""), Component.translatable("value_type.minions.boolean.false"), Component.translatable("value_type.minions.boolean.true")),
value -> Component.literal(value.toString()) value -> Component.literal(value.toString())
) )
); );
@@ -63,7 +63,7 @@ public class ValueTypes {
Codec.STRING, Codec.STRING,
"", "",
o -> o instanceof String s ? s : null, o -> o instanceof String s ? s : null,
((parent, oldValue) -> TextInput.inputStringFuture( ((parent, oldValue) -> TextInput.inputString(
parent, parent,
Component.literal("Text"), Component.literal("Text"),
oldValue oldValue
@@ -1,11 +1,4 @@
{ {
"type": "minions:stack", "type": "minions:head",
"data": { "data": "459dbceed3ea4abc903cfdcae3065dd3"
"id": "minecraft:player_head",
"components": {
"minecraft:profile": {
"name": "CastCrafter"
}
}
}
} }