2 Commits

Author SHA1 Message Date
skippyall f8eb1578b2 Back to the Future
Fun is still suspended though
2026-05-09 17:04:27 +02:00
skippyall 48a38b87c5 Rename .java to .kt 2026-05-09 17:04:27 +02:00
40 changed files with 352 additions and 484 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 +0,0 @@
package io.github.skippyall.minions.gui.minion;
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.supplier.Parameter;
import net.minecraft.server.level.ServerPlayer;
public interface GuiContext {
ServerPlayer getViewer();
static GuiContext create(ServerPlayer viewer) {
return new 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 {
ConfiguredInstruction<MinionRuntime> getInstruction();
String getName();
void setName(String name);
static GuiContext.Instruction create(GuiContext.Minion context, ConfiguredInstruction<MinionRuntime> instruction, String name) {
return new GuiContextImpl.InstructionImpl(context, instruction, name);
}
}
interface ValueSupplier extends Instruction {
Parameter<?> getParameter();
static GuiContext.ValueSupplier create(GuiContext.Instruction context, Parameter<?> parameter) {
return new GuiContextImpl.ValueSupplierImpl(context, parameter);
}
}
}
@@ -0,0 +1,64 @@
package io.github.skippyall.minions.gui.minion
import io.github.skippyall.minions.gui.minion.GuiContextImpl.*
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.supplier.Parameter
import net.minecraft.server.level.ServerPlayer
interface GuiContext {
val viewer: ServerPlayer
companion object {
@JvmStatic
fun create(viewer: ServerPlayer): GuiContext {
return GuiContextImpl(viewer)
}
}
interface Minion : GuiContext {
val minion: MinionFakePlayer
companion object {
@JvmStatic
fun create(context: GuiContext, minion: MinionFakePlayer): Minion {
return MinionImpl(
if(context is MinionImpl) context.context else context,
minion
)
}
}
}
interface Instruction : Minion {
val instruction: ConfiguredInstruction<MinionRuntime>
var name: String
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 +0,0 @@
package io.github.skippyall.minions.gui.minion;
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.supplier.Parameter;
import net.minecraft.server.level.ServerPlayer;
//If only this mod was kotlin
public class GuiContextImpl implements GuiContext {
private final ServerPlayer viewer;
public GuiContextImpl(ServerPlayer viewer) {
this.viewer = viewer;
}
@Override
public ServerPlayer getViewer() {
return viewer;
}
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);
}
}
}
@@ -0,0 +1,26 @@
package io.github.skippyall.minions.gui.minion
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.supplier.Parameter
import net.minecraft.server.level.ServerPlayer
//Thank you kotlin
class GuiContextImpl(override val viewer: ServerPlayer) : GuiContext {
class MinionImpl(
val context: GuiContext,
override val minion: MinionFakePlayer
) : GuiContext by context, GuiContext.Minion
class InstructionImpl(
val context: GuiContext.Minion,
override val instruction: ConfiguredInstruction<MinionRuntime>,
override var name: String
) : GuiContext.Minion by context, GuiContext.Instruction
class ValueSupplierImpl(
val context: GuiContext.Instruction,
override val parameter: Parameter<*>
) : GuiContext.Instruction by context, GuiContext.ValueSupplier
}
@@ -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 +0,0 @@
package io.github.skippyall.minions.listener;
import org.jetbrains.annotations.NotNull;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
public class ListenerManager<T> implements Iterable<T> {
protected final Set<T> listeners;
public ListenerManager() {
this(new CopyOnWriteArraySet<>());
}
protected ListenerManager(Set<T> listeners) {
this.listeners = listeners;
}
public void addListener(T listener) {
listeners.add(listener);
}
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);
}
}
@@ -0,0 +1,29 @@
package io.github.skippyall.minions.listener
import java.util.concurrent.CopyOnWriteArraySet
open class ListenerManager<T>(
protected val listeners: MutableSet<T> = CopyOnWriteArraySet(),
val onChange: () -> Unit = {},
) : MutableIterable<T> by listeners {
fun addListener(listener: T) {
listeners.add(listener)
onChange()
}
fun removeListener(listener: T) {
listeners.remove(listener)
onChange()
}
override fun iterator(): MutableIterator<T> {
val iterator = listeners.iterator()
return object : MutableIterator<T> by iterator {
override fun remove() {
iterator.remove()
onChange()
}
}
}
}
@@ -1,46 +0,0 @@
package io.github.skippyall.minions.listener;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.Registry;
import net.minecraft.resources.Identifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
public class SerializableListenerManager<T extends SerializableListenerManager.SerializableListener> extends ListenerManager<T> {
public SerializableListenerManager() {
super();
}
protected SerializableListenerManager(Set<T> listeners) {
super(listeners);
}
public static <T extends SerializableListener> Codec<SerializableListenerManager<T>> getCodec(Registry<Codec<? extends T>> registry) {
return registry.byNameCodec().<T>dispatch(
listener -> listener.getCodecId().map(registry::getValue).orElse(MapCodec.unitCodec(null)),
codec -> codec.fieldOf("data")
).listOf().xmap(
list -> new SerializableListenerManager<>(new CopyOnWriteArraySet<>(list)),
manager -> {
List<T> serializableListeners = new ArrayList<>();
for(T listener : manager.listeners) {
if(listener.getCodecId().isPresent()) {
serializableListeners.add(listener);
}
}
return serializableListeners;
}
);
}
public interface SerializableListener {
default Optional<Identifier> getCodecId() {
return Optional.empty();
}
}
}
@@ -0,0 +1,47 @@
package io.github.skippyall.minions.listener
import com.mojang.serialization.Codec
import com.mojang.serialization.MapCodec
import io.github.skippyall.minions.listener.SerializableListenerManager.SerializableListener
import net.minecraft.core.Registry
import net.minecraft.resources.Identifier
import java.util.Optional
import java.util.concurrent.CopyOnWriteArraySet
class SerializableListenerManager<T : SerializableListener>(
listeners: MutableSet<T> = CopyOnWriteArraySet(),
onChange: () -> Unit = {},
) : ListenerManager<T>(listeners, onChange) {
interface SerializableListener {
val codecId: Optional<Identifier>
get() = Optional.empty<Identifier>()
}
companion object {
@JvmStatic
@JvmOverloads
fun <T : SerializableListener> getCodec(
registry: Registry<Codec<out T>>,
onChange: () -> Unit = {},
): Codec<SerializableListenerManager<T>> {
return registry.byNameCodec().dispatch(
{ listener -> listener.codecId.map(registry::getValue)
.orElseGet { MapCodec.unitCodec(null) }
},
{ codec -> codec.fieldOf("data") }
).listOf().xmap(
{ list -> SerializableListenerManager<T>(CopyOnWriteArraySet<T>(list), onChange) },
{ manager ->
val serializableListeners: MutableList<T> = mutableListOf()
for (listener in manager.listeners) {
if (listener.codecId.isPresent) {
serializableListeners.add(listener)
}
}
return@xmap serializableListeners
}
)
}
}
}
@@ -1,58 +0,0 @@
package io.github.skippyall.minions.minion;
import com.mojang.authlib.properties.PropertyMap;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import io.github.skippyall.minions.listener.SerializableListenerManager;
import io.github.skippyall.minions.registration.MinionRegistries;
import net.minecraft.core.UUIDUtil;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.ExtraCodecs;
import java.util.Optional;
import java.util.UUID;
public record MinionData(
UUID uuid,
String name,
Optional<PropertyMap> skin,
boolean isSpawned,
SerializableListenerManager<MinionListener> listeners,
MinionConfig config
) {
public static final Codec<MinionData> CODEC = RecordCodecBuilder.create(instance ->
instance.group(
UUIDUtil.AUTHLIB_CODEC.fieldOf("uuid").forGetter(MinionData::uuid),
Codec.STRING.fieldOf("name").forGetter(MinionData::name),
ExtraCodecs.PROPERTY_MAP.optionalFieldOf("skin").forGetter(MinionData::skin),
Codec.BOOL.optionalFieldOf("isSpawned", false).forGetter(MinionData::isSpawned),
SerializableListenerManager.getCodec(MinionRegistries.MINION_LISTENER_CODECS).optionalFieldOf("listeners").xmap(
optional -> optional.orElseGet(SerializableListenerManager::new),
Optional::of
).forGetter(MinionData::listeners),
MinionConfig.CODEC.optionalFieldOf("config", new MinionConfig()).forGetter(MinionData::config)
).apply(instance, MinionData::new)
);
public static MinionData createDefault(MinecraftServer server) {
return new MinionData(
UUID.randomUUID(),
MinionProfileUtils.newDefaultMinionName(server),
Optional.empty(),
false,
new SerializableListenerManager<>(),
new MinionConfig()
);
}
public MinionData withName(String name) {
return new MinionData(uuid, name, skin, isSpawned, listeners, config);
}
public MinionData withSkin(Optional<PropertyMap> skin) {
return new MinionData(uuid, name, skin, isSpawned, listeners, config);
}
public MinionData withSpawned(boolean isSpawned) {
return new MinionData(uuid, name, skin, isSpawned, listeners, config);
}
}
@@ -0,0 +1,82 @@
package io.github.skippyall.minions.minion
import com.mojang.authlib.properties.PropertyMap
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import io.github.skippyall.minions.listener.SerializableListenerManager
import io.github.skippyall.minions.registration.MinionRegistries
import net.minecraft.core.UUIDUtil
import net.minecraft.server.MinecraftServer
import net.minecraft.util.ExtraCodecs
import java.util.Optional
import java.util.UUID
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class MinionData(
initialUuid: UUID,
initialName: String,
initialSkin: Optional<PropertyMap>,
initialIsSpawned: Boolean,
val listeners: SerializableListenerManager<MinionListener>,
initialConfig: MinionConfig,
var onDirty: Runnable = {},
) {
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(
UUIDUtil.AUTHLIB_CODEC.fieldOf("uuid").forGetter(MinionData::uuid),
Codec.STRING.fieldOf("name").forGetter(MinionData::name),
ExtraCodecs.PROPERTY_MAP.optionalFieldOf("skin").forGetter(MinionData::skin),
Codec.BOOL.optionalFieldOf("isSpawned", false).forGetter(MinionData::isSpawned),
SerializableListenerManager.getCodec<MinionListener>(MinionRegistries.MINION_LISTENER_CODECS)
.optionalFieldOf("listeners").xmap(
{ optional -> optional.orElseGet { SerializableListenerManager() } },
Optional<SerializableListenerManager<MinionListener>>::of
).forGetter(MinionData::listeners),
MinionConfig.CODEC.optionalFieldOf("config", MinionConfig())
.forGetter(MinionData::config)
).apply(
instance,
::MinionData
)
}
@JvmStatic
fun createDefault(server: MinecraftServer): MinionData {
return MinionData(
UUID.randomUUID(),
MinionProfileUtils.newDefaultMinionName(server),
Optional.empty<PropertyMap>(),
false,
SerializableListenerManager(),
MinionConfig()
) {
MinionPersistentState.get(server).isDirty = true
}
}
}
class DirtyProperty<V>(var value: V, val onDirty: () -> Unit) : ReadWriteProperty<Any?, V> {
override fun getValue(thisRef: Any?, property: KProperty<*>): V {
return value
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: V) {
this.value = value
onDirty()
}
}
}
@@ -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"
}
}
}
} }