From 017b2ec59076591ecd7bed8adfdc33c77e99d7d7 Mon Sep 17 00:00:00 2001 From: skippyall <121978267+skippyall@users.noreply.github.com> Date: Sun, 25 Jan 2026 22:28:09 +0100 Subject: [PATCH] Listening in both directions --- .../minions/client/MinionsClient.java | 2 +- .../io/github/skippyall/minions/Minions.java | 15 ++- .../BlockEntityMinionInstructionListener.java | 55 ++++++++ .../block/BlockEntityMinionListener.java | 56 ++++++-- .../block/MinionTriggerMinionListener.java | 32 ----- .../MinionTriggerBlock.java | 25 ++-- .../MinionTriggerBlockEntity.java | 56 ++++---- .../MinionTriggerBlockItem.java | 2 +- .../MinionTriggerMinionListener.java | 126 ++++++++++++++++++ .../minions/command/ListSubcommand.java | 2 +- .../minions/command/MinionArgument.java | 9 +- .../minions/command/SpawnSubcommand.java | 2 +- .../minions/gui/ConfigureInstructionGui.java | 2 +- .../skippyall/minions/gui/GuiDisplay.java | 3 +- .../skippyall/minions/gui/InstructionGui.java | 4 +- .../skippyall/minions/gui/MinionLookGui.java | 12 +- .../skippyall/minions/minion/MinionData.java | 24 ++-- .../skippyall/minions/minion/MinionItem.java | 24 ++-- .../minions/minion/MinionListener.java | 8 +- .../minions/minion/MinionPersistentState.java | 6 +- .../minions/minion/MinionProfileUtils.java | 13 +- .../minions/minion/MinionRuntime.java | 4 +- .../minion/fakeplayer/MinionFakePlayer.java | 44 +++--- .../minions/minion/skin/SkinProviders.java | 2 +- .../minions/mixins/PlayerListMixin.java | 2 +- .../minions/module/MinionModule.java | 2 +- .../minions/module/SpecialAbilities.java | 2 +- .../program/consumer/ValueConsumer.java | 2 +- .../instruction/ConfiguredInstruction.java | 12 +- .../program/instruction/Instructions.java | 2 +- .../inventory/SwapItemExecution.java | 118 ++++++++++++++++ .../minions/program/supplier/Parameter.java | 2 +- .../program/supplier/ValueSupplier.java | 2 +- .../program/supplier/ValueSuppliers.java | 2 +- .../minions/program/value/ValueTypes.java | 2 +- .../minions/reference/Reference.java | 2 +- .../minions/reference/ReferenceItem.java | 2 +- .../{ => registration}/MinionBlocks.java | 7 +- .../{ => registration}/MinionCreativeTab.java | 3 +- .../{ => registration}/MinionItems.java | 8 +- .../registration/MinionRegistration.java | 13 ++ .../{ => registration}/MinionRegistries.java | 3 +- .../minions/util/ListenerManager.java | 45 +++++-- .../resources/data/minions/lang/en_us.json | 2 + 44 files changed, 550 insertions(+), 211 deletions(-) create mode 100644 src/main/java/io/github/skippyall/minions/block/BlockEntityMinionInstructionListener.java delete mode 100644 src/main/java/io/github/skippyall/minions/block/MinionTriggerMinionListener.java rename src/main/java/io/github/skippyall/minions/block/{ => miniontrigger}/MinionTriggerBlock.java (92%) rename src/main/java/io/github/skippyall/minions/block/{ => miniontrigger}/MinionTriggerBlockEntity.java (67%) rename src/main/java/io/github/skippyall/minions/block/{ => miniontrigger}/MinionTriggerBlockItem.java (93%) create mode 100644 src/main/java/io/github/skippyall/minions/block/miniontrigger/MinionTriggerMinionListener.java create mode 100644 src/main/java/io/github/skippyall/minions/program/instruction/execution/inventory/SwapItemExecution.java rename src/main/java/io/github/skippyall/minions/{ => registration}/MinionBlocks.java (86%) rename src/main/java/io/github/skippyall/minions/{ => registration}/MinionCreativeTab.java (92%) rename src/main/java/io/github/skippyall/minions/{ => registration}/MinionItems.java (94%) create mode 100644 src/main/java/io/github/skippyall/minions/registration/MinionRegistration.java rename src/main/java/io/github/skippyall/minions/{ => registration}/MinionRegistries.java (97%) diff --git a/src/client/java/io/github/skippyall/minions/client/MinionsClient.java b/src/client/java/io/github/skippyall/minions/client/MinionsClient.java index 721d8b3..a4b1dd1 100644 --- a/src/client/java/io/github/skippyall/minions/client/MinionsClient.java +++ b/src/client/java/io/github/skippyall/minions/client/MinionsClient.java @@ -1,7 +1,7 @@ package io.github.skippyall.minions.client; import eu.pb4.polymer.networking.api.client.PolymerClientNetworking; -import io.github.skippyall.minions.MinionBlocks; +import io.github.skippyall.minions.registration.MinionBlocks; import io.github.skippyall.minions.util.PolymerUtil; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.rendering.v1.BlockRenderLayerMap; diff --git a/src/main/java/io/github/skippyall/minions/Minions.java b/src/main/java/io/github/skippyall/minions/Minions.java index 2d78a73..27ce0fd 100644 --- a/src/main/java/io/github/skippyall/minions/Minions.java +++ b/src/main/java/io/github/skippyall/minions/Minions.java @@ -12,6 +12,11 @@ import io.github.skippyall.minions.program.instruction.Instructions; import io.github.skippyall.minions.program.supplier.ValueSuppliers; import io.github.skippyall.minions.program.value.ValueTypes; import io.github.skippyall.minions.reference.Reference; +import io.github.skippyall.minions.registration.MinionBlocks; +import io.github.skippyall.minions.registration.MinionCreativeTab; +import io.github.skippyall.minions.registration.MinionItems; +import io.github.skippyall.minions.registration.MinionRegistration; +import io.github.skippyall.minions.registration.MinionRegistries; import io.github.skippyall.minions.util.PolymerUtil; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; @@ -41,12 +46,12 @@ public class Minions implements ModInitializer { MinionBlocks.register(); MinionItems.register(); MinionCreativeTab.registerGroup(); + MinionRegistration.register(); PolymerUtil.register(); ServerLifecycleEvents.SERVER_STARTED.register(server -> { - MinionPersistentState.create(server); - MinionPersistentState.INSTANCE.getMinionData().forEach((uuid, data) -> { + MinionPersistentState.get(server).getMinionData().forEach((uuid, data) -> { if(data.isSpawned()) { MinionFakePlayer.spawnMinion(data, server.getOverworld(), null, null, true); } @@ -57,6 +62,12 @@ public class Minions implements ModInitializer { MinionsCommand.register(commandDispatcher); }); + /*ServerBlockEntityEvents.BLOCK_ENTITY_LOAD.register((blockEntity, world) -> { + if(blockEntity instanceof MinionTriggerBlockEntity) { + world.updateComparators(blockEntity.getPos(), MinionBlocks.MINION_TRIGGER_BLOCK); + } + });*/ + PolymerResourcePackUtils.addModAssets(Minions.MOD_ID); } } diff --git a/src/main/java/io/github/skippyall/minions/block/BlockEntityMinionInstructionListener.java b/src/main/java/io/github/skippyall/minions/block/BlockEntityMinionInstructionListener.java new file mode 100644 index 0000000..1d9be71 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/block/BlockEntityMinionInstructionListener.java @@ -0,0 +1,55 @@ +package io.github.skippyall.minions.block; + +import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; +import io.github.skippyall.minions.program.instruction.ConfiguredInstructionListener; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.registry.RegistryKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import java.util.Map; +import java.util.UUID; + +public abstract class BlockEntityMinionInstructionListener extends BlockEntityMinionListener { + protected BlockEntityMinionInstructionListener(RegistryKey worldKey, BlockPos pos, UUID minionUuid, BlockEntityType type) { + super(worldKey, pos, minionUuid, type); + } + + protected abstract Map getInstructionListeners(); + + @Override + public void onMinionSpawn(MinionFakePlayer minion) { + super.onMinionSpawn(minion); + registerInstructionListeners(); + } + + @Override + protected void add(MinecraftServer server) { + super.add(server); + if(minion != null) { + registerInstructionListeners(); + } + } + + @Override + public void remove(MinecraftServer server) { + super.remove(server); + if(minion != null) { + removeInstructionListeners(); + } + } + + public void registerInstructionListeners() { + for(Map.Entry listener : getInstructionListeners().entrySet()) { + minion.getInstructionManager().getInstruction(listener.getKey()).addListener(listener.getValue()); + } + } + + public void removeInstructionListeners() { + for(Map.Entry listener : getInstructionListeners().entrySet()) { + minion.getInstructionManager().getInstruction(listener.getKey()).removeListener(listener.getValue()); + } + } +} diff --git a/src/main/java/io/github/skippyall/minions/block/BlockEntityMinionListener.java b/src/main/java/io/github/skippyall/minions/block/BlockEntityMinionListener.java index d335ad6..010730d 100644 --- a/src/main/java/io/github/skippyall/minions/block/BlockEntityMinionListener.java +++ b/src/main/java/io/github/skippyall/minions/block/BlockEntityMinionListener.java @@ -1,36 +1,67 @@ package io.github.skippyall.minions.block; +import com.mojang.datafixers.util.Function3; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import io.github.skippyall.minions.minion.MinionListener; import io.github.skippyall.minions.minion.MinionPersistentState; +import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntityType; import net.minecraft.registry.RegistryKey; import net.minecraft.server.MinecraftServer; +import net.minecraft.util.Uuids; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; import java.util.Optional; import java.util.UUID; -import java.util.function.BiFunction; public abstract class BlockEntityMinionListener implements MinionListener { protected RegistryKey worldKey; protected BlockPos pos; + protected UUID minionUuid; protected BlockEntityType type; + protected @Nullable MinionFakePlayer minion; - public BlockEntityMinionListener(RegistryKey worldKey, BlockPos pos, BlockEntityType type) { + protected BlockEntityMinionListener(RegistryKey worldKey, BlockPos pos, UUID minionUuid, BlockEntityType type) { this.worldKey = worldKey; this.pos = pos; + this.minionUuid = minionUuid; this.type = type; } - public static > Codec getCodec(BiFunction, BlockPos, L> constructor) { + @Override + public void onMinionSpawn(MinionFakePlayer minion) { + MinionListener.super.onMinionSpawn(minion); + this.minion = minion; + removeIfBeRemoved(minion.getServer()); + } + + @Override + public void onMinionRemove(MinionFakePlayer minion) { + MinionListener.super.onMinionRemove(minion); + this.minion = null; + } + + public static > T getListener(World world, BlockPos pos, UUID minionUuid, Class clazz) { + if(minionUuid != null) { + for (MinionListener listener : MinionPersistentState.get(world.getServer()).getMinionData(minionUuid).listeners()) { + if (listener instanceof BlockEntityMinionListener tl && tl.pos.equals(pos) && tl.worldKey.equals(world.getRegistryKey()) && clazz.isInstance(tl)) { + return clazz.cast(tl); + } + } + } + return null; + } + + public static > Codec getCodec(Function3, BlockPos, UUID, L> constructor) { return RecordCodecBuilder.create(instance -> instance.group( World.CODEC.fieldOf("world").forGetter(listener -> listener.worldKey), - BlockPos.CODEC.fieldOf("pos").forGetter(listener -> listener.pos) + BlockPos.CODEC.fieldOf("pos").forGetter(listener -> listener.pos), + Uuids.CODEC.fieldOf("minionUuid").forGetter(listener -> listener.minionUuid) ).apply(instance, constructor)); } @@ -55,22 +86,23 @@ public abstract class BlockEntityMinionListener implement return Optional.empty(); } - public boolean removeIfBeRemoved(MinecraftServer server, UUID minion) { + public boolean removeIfBeRemoved(MinecraftServer server) { if(getBlockEntityState(server) == BlockEntityState.REMOVED) { - remove(minion); + remove(server); return true; } return false; } - public void add(UUID minion) { - MinionPersistentState.INSTANCE.getMinionData(minion).listeners().addListener(this); - MinionPersistentState.INSTANCE.markDirty(); + protected void add(MinecraftServer server) { + MinionPersistentState.get(server).getMinionData(minionUuid).listeners().addListener(this); + MinionPersistentState.get(server).markDirty(); + this.minion = (MinionFakePlayer) server.getPlayerManager().getPlayer(minionUuid); } - public void remove(UUID minion) { - MinionPersistentState.INSTANCE.getMinionData(minion).listeners().removeListener(this); - MinionPersistentState.INSTANCE.markDirty(); + public void remove(MinecraftServer server) { + MinionPersistentState.get(server).getMinionData(minionUuid).listeners().removeListener(this); + MinionPersistentState.get(server).markDirty(); } public enum BlockEntityState { diff --git a/src/main/java/io/github/skippyall/minions/block/MinionTriggerMinionListener.java b/src/main/java/io/github/skippyall/minions/block/MinionTriggerMinionListener.java deleted file mode 100644 index 1608056..0000000 --- a/src/main/java/io/github/skippyall/minions/block/MinionTriggerMinionListener.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.github.skippyall.minions.block; - -import io.github.skippyall.minions.MinionBlocks; -import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; -import io.github.skippyall.minions.program.instruction.ConfiguredInstructionListener; -import net.minecraft.registry.RegistryKey; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - -import java.util.UUID; - -public class MinionTriggerMinionListener extends BlockEntityMinionListener implements ConfiguredInstructionListener { - boolean registeredListener; - String instructionName; - - public MinionTriggerMinionListener(RegistryKey worldKey, BlockPos pos, String instructionName, boolean registeredListener) { - super(worldKey, pos, MinionBlocks.MINION_TRIGGER_BE_TYPE); - this.instructionName = instructionName; - this.registeredListener = registeredListener; - } - - @Override - public void onMinionSpawn(MinionFakePlayer minion) { - if(!registeredListener) { - minion.getInstructionManager().getInstruction(instructionName).addListener(this); - } - } - - @Override - public void onMinionRemove(MinionFakePlayer minion) { - } -} diff --git a/src/main/java/io/github/skippyall/minions/block/MinionTriggerBlock.java b/src/main/java/io/github/skippyall/minions/block/miniontrigger/MinionTriggerBlock.java similarity index 92% rename from src/main/java/io/github/skippyall/minions/block/MinionTriggerBlock.java rename to src/main/java/io/github/skippyall/minions/block/miniontrigger/MinionTriggerBlock.java index 8c4264d..1351c4f 100644 --- a/src/main/java/io/github/skippyall/minions/block/MinionTriggerBlock.java +++ b/src/main/java/io/github/skippyall/minions/block/miniontrigger/MinionTriggerBlock.java @@ -1,4 +1,4 @@ -package io.github.skippyall.minions.block; +package io.github.skippyall.minions.block.miniontrigger; import com.mojang.serialization.MapCodec; import eu.pb4.polymer.core.api.block.PolymerBlock; @@ -8,7 +8,7 @@ import eu.pb4.polymer.resourcepack.api.PolymerResourcePackUtils; import eu.pb4.polymer.virtualentity.api.BlockWithElementHolder; import eu.pb4.polymer.virtualentity.api.ElementHolder; import eu.pb4.polymer.virtualentity.api.elements.ItemDisplayElement; -import io.github.skippyall.minions.MinionBlocks; +import io.github.skippyall.minions.registration.MinionBlocks; import io.github.skippyall.minions.Minions; import io.github.skippyall.minions.minion.MinionPersistentState; import io.github.skippyall.minions.reference.InstructionReference; @@ -22,8 +22,6 @@ import net.minecraft.block.Blocks; import net.minecraft.block.ShapeContext; import net.minecraft.block.SideShapeType; import net.minecraft.block.entity.BlockEntity; -import net.minecraft.block.entity.BlockEntityTicker; -import net.minecraft.block.entity.BlockEntityType; import net.minecraft.component.DataComponentTypes; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; @@ -75,6 +73,12 @@ public class MinionTriggerBlock extends BlockWithEntity implements PolymerBlock, return state.isSideSolid(world, pos, Direction.UP, SideShapeType.RIGID); } + @Override + protected void onStateReplaced(BlockState state, ServerWorld world, BlockPos pos, boolean moved) { + super.onStateReplaced(state, world, pos, moved); + world.getBlockEntity(pos, MinionBlocks.MINION_TRIGGER_BE_TYPE).ifPresent(MinionTriggerBlockEntity::removeListener); + } + @Override protected void appendProperties(StateManager.Builder builder) { builder.add(POWERED); @@ -101,8 +105,7 @@ public class MinionTriggerBlock extends BlockWithEntity implements PolymerBlock, } world.getBlockEntity(pos, MinionBlocks.MINION_TRIGGER_BE_TYPE).ifPresent(be -> { - - String name = MinionPersistentState.INSTANCE.getMinionData(be.getMinionUuid()).name(); + String name = MinionPersistentState.get(world.getServer()).getMinionData(be.getMinionUuid()).name(); player.sendMessage(Text.translatable("minions.reference.instruction.tooltip", name, be.getInstructionName()), true); }); return ActionResult.SUCCESS; @@ -113,6 +116,7 @@ public class MinionTriggerBlock extends BlockWithEntity implements PolymerBlock, if(!canPlaceAt(state, world, pos)) { dropStacks(state, world, pos); world.removeBlock(pos, false); + return; } boolean newPower = world.isReceivingRedstonePower(pos); @@ -147,15 +151,6 @@ public class MinionTriggerBlock extends BlockWithEntity implements PolymerBlock, return PolymerUtil.isOnClient(context) ? state : Blocks.COMPARATOR.getDefaultState().with(AbstractRedstoneGateBlock.POWERED, state.get(POWERED)); } - @Override - public @Nullable BlockEntityTicker getTicker(World world, BlockState state, BlockEntityType type) { - if(type == MinionBlocks.MINION_TRIGGER_BE_TYPE) { - return MinionTriggerBlockEntity::tick; - } else { - return null; - } - } - @Override public @Nullable ElementHolder createElementHolder(ServerWorld world, BlockPos pos, BlockState initialBlockState) { ElementHolder holder = new ElementHolder() { diff --git a/src/main/java/io/github/skippyall/minions/block/MinionTriggerBlockEntity.java b/src/main/java/io/github/skippyall/minions/block/miniontrigger/MinionTriggerBlockEntity.java similarity index 67% rename from src/main/java/io/github/skippyall/minions/block/MinionTriggerBlockEntity.java rename to src/main/java/io/github/skippyall/minions/block/miniontrigger/MinionTriggerBlockEntity.java index ae283a6..5dd7dc7 100644 --- a/src/main/java/io/github/skippyall/minions/block/MinionTriggerBlockEntity.java +++ b/src/main/java/io/github/skippyall/minions/block/miniontrigger/MinionTriggerBlockEntity.java @@ -1,7 +1,7 @@ -package io.github.skippyall.minions.block; +package io.github.skippyall.minions.block.miniontrigger; -import io.github.skippyall.minions.MinionBlocks; -import io.github.skippyall.minions.minion.MinionPersistentState; +import io.github.skippyall.minions.block.BlockEntityMinionListener; +import io.github.skippyall.minions.registration.MinionBlocks; import io.github.skippyall.minions.minion.MinionRuntime; import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import io.github.skippyall.minions.program.instruction.ConfiguredInstruction; @@ -11,7 +11,6 @@ import net.minecraft.storage.ReadView; import net.minecraft.storage.WriteView; import net.minecraft.util.Uuids; import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; import java.util.Optional; import java.util.UUID; @@ -20,38 +19,34 @@ public class MinionTriggerBlockEntity extends BlockEntity { private UUID minionUuid; private String instructionName = ""; - private boolean first = true; - private boolean runningCache = false; - public MinionTriggerBlockEntity(BlockPos pos, BlockState state) { super(MinionBlocks.MINION_TRIGGER_BE_TYPE, pos, state); } - public void setInstruction(UUID minionUuid, String instructionName) { - this.minionUuid = minionUuid; - this.instructionName = instructionName; - markDirty(); + public void removeListener() { + MinionTriggerMinionListener.removeListener(world, pos, minionUuid, instructionName); } - public static void tick(World world, BlockPos pos, BlockState state, BlockEntity blockEntity) { - if(!(blockEntity instanceof MinionTriggerBlockEntity triggerBlockEntity)) { - return; - } - if(triggerBlockEntity.first) { - triggerBlockEntity.first = false; - world.updateComparators(pos, MinionBlocks.MINION_TRIGGER_BLOCK); - triggerBlockEntity.runningCache = triggerBlockEntity.getInstruction().map(ConfiguredInstruction::isRunning).orElse(false); - } else { - boolean isRunning = triggerBlockEntity.getInstruction().map(ConfiguredInstruction::isRunning).orElse(false); - if (isRunning != triggerBlockEntity.runningCache) { - world.updateComparators(pos, MinionBlocks.MINION_TRIGGER_BLOCK); - triggerBlockEntity.runningCache = isRunning; - } - } + public void addListener() { + MinionTriggerMinionListener.addListener(world, pos, minionUuid, instructionName); + } + + public void setInstruction(UUID minionUuid, String instructionName) { + removeListener(); + this.minionUuid = minionUuid; + this.instructionName = instructionName; + addListener(); + markDirty(); } public void updatePower() { boolean powered = getCachedState().get(MinionTriggerBlock.POWERED); + + MinionTriggerMinionListener listener = getListener(); + if(listener != null) { + listener.incomingPowerCache = powered; + } + getMinion().ifPresent(minion -> { getInstruction().ifPresent(instruction -> { if(powered) { @@ -61,12 +56,11 @@ public class MinionTriggerBlockEntity extends BlockEntity { } }); }); - } public int getComparatorOutput() { - Optional> instruction = getInstruction(); - if(instruction.isPresent() && instruction.get().isRunning()) { + MinionTriggerMinionListener listener = getListener(); + if(listener != null && listener.runningCache) { return 15; } return 0; @@ -95,6 +89,10 @@ public class MinionTriggerBlockEntity extends BlockEntity { return getMinion().flatMap(this::getInstruction); } + public MinionTriggerMinionListener getListener() { + return BlockEntityMinionListener.getListener(world, pos, minionUuid, MinionTriggerMinionListener.class); + } + @Override protected void readData(ReadView view) { minionUuid = view.read("minionUuid", Uuids.CODEC).orElse(null); diff --git a/src/main/java/io/github/skippyall/minions/block/MinionTriggerBlockItem.java b/src/main/java/io/github/skippyall/minions/block/miniontrigger/MinionTriggerBlockItem.java similarity index 93% rename from src/main/java/io/github/skippyall/minions/block/MinionTriggerBlockItem.java rename to src/main/java/io/github/skippyall/minions/block/miniontrigger/MinionTriggerBlockItem.java index 55392b6..1be8d57 100644 --- a/src/main/java/io/github/skippyall/minions/block/MinionTriggerBlockItem.java +++ b/src/main/java/io/github/skippyall/minions/block/miniontrigger/MinionTriggerBlockItem.java @@ -1,4 +1,4 @@ -package io.github.skippyall.minions.block; +package io.github.skippyall.minions.block.miniontrigger; import eu.pb4.polymer.core.api.item.PolymerBlockItem; import eu.pb4.polymer.resourcepack.api.PolymerResourcePackUtils; diff --git a/src/main/java/io/github/skippyall/minions/block/miniontrigger/MinionTriggerMinionListener.java b/src/main/java/io/github/skippyall/minions/block/miniontrigger/MinionTriggerMinionListener.java new file mode 100644 index 0000000..546be5d --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/block/miniontrigger/MinionTriggerMinionListener.java @@ -0,0 +1,126 @@ +package io.github.skippyall.minions.block.miniontrigger; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import io.github.skippyall.minions.Minions; +import io.github.skippyall.minions.block.BlockEntityMinionInstructionListener; +import io.github.skippyall.minions.minion.MinionRuntime; +import io.github.skippyall.minions.registration.MinionBlocks; +import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; +import io.github.skippyall.minions.program.instruction.ConfiguredInstruction; +import io.github.skippyall.minions.program.instruction.ConfiguredInstructionListener; +import net.minecraft.registry.RegistryKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.Identifier; +import net.minecraft.util.Uuids; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; + +public class MinionTriggerMinionListener extends BlockEntityMinionInstructionListener { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> + instance.group( + World.CODEC.fieldOf("world").forGetter(listener -> listener.worldKey), + BlockPos.CODEC.fieldOf("pos").forGetter(listener -> listener.pos), + Uuids.CODEC.fieldOf("minionUuid").forGetter(listener -> listener.minionUuid), + Codec.STRING.fieldOf("instructionName").forGetter(listener -> listener.instructionName) + ).apply(instance, MinionTriggerMinionListener::new)); + + String instructionName; + final TriggerInstructionListener listener = new TriggerInstructionListener(); + + boolean runningCache; + boolean incomingPowerCache; + + private MinionTriggerMinionListener(RegistryKey worldKey, BlockPos pos, UUID minionUuid, String instructionName) { + super(worldKey, pos, minionUuid, MinionBlocks.MINION_TRIGGER_BE_TYPE); + this.instructionName = Objects.requireNonNull(instructionName); + } + + public static void addListener(World world, BlockPos pos, UUID minion, String instructionName) { + MinionTriggerMinionListener listener = new MinionTriggerMinionListener(world.getRegistryKey(), pos, minion, instructionName); + listener.add(world.getServer()); + } + + public static void removeListener(World world, BlockPos pos, UUID minion, String instructionName) { + MinionTriggerMinionListener old = getListener(world, pos, minion, MinionTriggerMinionListener.class); + if(old != null) { + old.remove(world.getServer()); + } + } + + @Override + protected Map getInstructionListeners() { + return Map.of(instructionName, listener); + } + + @Override + public void onMinionSpawn(MinionFakePlayer minion) { + super.onMinionSpawn(minion); + runningCache = minion.getInstructionManager().getInstruction(instructionName).isRunning(); + updateComparatorsIfLoaded(minion.getServer()); + + ConfiguredInstruction instruction = minion.getInstructionManager().getInstruction(instructionName); + if(instruction.isRunning() && !incomingPowerCache) { + instruction.stop(minion.getInstructionManager()); + } else if (!instruction.isRunning() && incomingPowerCache) { + instruction.run(minion.getInstructionManager()); + } + } + + @Override + public void onMinionRemove(MinionFakePlayer minion) { + super.onMinionRemove(minion); + runningCache = false; + updateComparatorsIfLoaded(minion.getServer()); + } + + @Override + public void onInstructionRename(MinionFakePlayer minion, ConfiguredInstruction instruction, String oldName, String newName) { + super.onInstructionRename(minion, instruction, oldName, newName); + if(instructionName.equals(oldName)) { + instructionName = newName; + } + } + + @Override + protected void add(MinecraftServer server) { + super.add(server); + runningCache = minion.getInstructionManager().getInstruction(instructionName).isRunning(); + updateComparatorsIfLoaded(server); + } + + @Override + public Optional getCodecId() { + return Optional.of(Identifier.of(Minions.MOD_ID, "minion_trigger")); + } + + public void updateComparatorsIfLoaded(MinecraftServer server) { + World world = server.getWorld(worldKey); + if(world.isPosLoaded(pos)) { + world.updateComparators(pos, MinionBlocks.MINION_TRIGGER_BLOCK); + } + } + + public boolean isRunning() { + return runningCache; + } + + public class TriggerInstructionListener implements ConfiguredInstructionListener { + @Override + public void onRun(ConfiguredInstruction instruction) { + runningCache = true; + updateComparatorsIfLoaded(minion.getServer()); + } + + @Override + public void onStop(ConfiguredInstruction instruction) { + runningCache = false; + updateComparatorsIfLoaded(minion.getServer()); + } + } +} diff --git a/src/main/java/io/github/skippyall/minions/command/ListSubcommand.java b/src/main/java/io/github/skippyall/minions/command/ListSubcommand.java index 6e84db2..4377cc5 100644 --- a/src/main/java/io/github/skippyall/minions/command/ListSubcommand.java +++ b/src/main/java/io/github/skippyall/minions/command/ListSubcommand.java @@ -16,7 +16,7 @@ public class ListSubcommand { .executes(ListSubcommand::list); public static int list(CommandContext context) { - Collection minions = MinionPersistentState.INSTANCE.getMinionData().values(); + Collection minions = MinionPersistentState.get(context.getSource().getServer()).getMinionData().values(); for (MinionData minion : minions) { context.getSource().sendFeedback(() -> Text.literal(minion.name() + "(" + minion.uuid() + "):" + minion.isSpawned()), false); } diff --git a/src/main/java/io/github/skippyall/minions/command/MinionArgument.java b/src/main/java/io/github/skippyall/minions/command/MinionArgument.java index b4d2c68..33cc5cc 100644 --- a/src/main/java/io/github/skippyall/minions/command/MinionArgument.java +++ b/src/main/java/io/github/skippyall/minions/command/MinionArgument.java @@ -9,6 +9,7 @@ import com.mojang.brigadier.suggestion.SuggestionsBuilder; import io.github.skippyall.minions.minion.MinionData; import io.github.skippyall.minions.minion.MinionPersistentState; import io.github.skippyall.minions.minion.MinionProfileUtils; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.text.Text; @@ -21,13 +22,13 @@ public class MinionArgument { public static final MinionSuggestionProvider SUGGESTION_PROVIDER = new MinionSuggestionProvider(); - public static MinionData parse(String argument) throws CommandSyntaxException { + public static MinionData parse(MinecraftServer server, String argument) throws CommandSyntaxException { Optional data = Optional.empty(); if(argument.startsWith(MinionProfileUtils.PREFIX)) { - data = MinionPersistentState.INSTANCE.getMinionWithName(argument); + data = MinionPersistentState.get(server).getMinionWithName(argument); } else { try { - data = Optional.ofNullable(MinionPersistentState.INSTANCE.getMinionData(UUID.fromString(argument))); + data = Optional.ofNullable(MinionPersistentState.get(server).getMinionData(UUID.fromString(argument))); } catch (IllegalArgumentException ignored) {} } @@ -40,7 +41,7 @@ public class MinionArgument { public static class MinionSuggestionProvider implements SuggestionProvider { @Override public CompletableFuture getSuggestions(CommandContext context, SuggestionsBuilder builder) throws CommandSyntaxException { - for (MinionData data : MinionPersistentState.INSTANCE.getMinionDataList()) { + for (MinionData data : MinionPersistentState.get(context.getSource().getServer()).getMinionDataList()) { builder.suggest(data.name()); } diff --git a/src/main/java/io/github/skippyall/minions/command/SpawnSubcommand.java b/src/main/java/io/github/skippyall/minions/command/SpawnSubcommand.java index 4b7a42a..32c76f9 100644 --- a/src/main/java/io/github/skippyall/minions/command/SpawnSubcommand.java +++ b/src/main/java/io/github/skippyall/minions/command/SpawnSubcommand.java @@ -48,7 +48,7 @@ public class SpawnSubcommand { ); public static int spawnCommand(ServerCommandSource source, String minion, PosArgument pos, boolean force) throws CommandSyntaxException { - MinionData data = MinionArgument.parse(minion); + MinionData data = MinionArgument.parse(source.getServer(), minion); MinionFakePlayer.spawnMinion(data, source.getWorld(), pos != null ? pos.getPos(source) : null, pos != null ? pos.getRotation(source) : null, force); return 0; } diff --git a/src/main/java/io/github/skippyall/minions/gui/ConfigureInstructionGui.java b/src/main/java/io/github/skippyall/minions/gui/ConfigureInstructionGui.java index bc71991..1f54e10 100644 --- a/src/main/java/io/github/skippyall/minions/gui/ConfigureInstructionGui.java +++ b/src/main/java/io/github/skippyall/minions/gui/ConfigureInstructionGui.java @@ -70,7 +70,7 @@ public class ConfigureInstructionGui extends InstructionBoundSimpleGui { } @Override - public void onInstructionRename(MinionFakePlayer minion, ConfiguredInstruction instruction, String newName) { + public void onInstructionRename(MinionFakePlayer minion, ConfiguredInstruction instruction, String oldName, String newName) { this.setTitle(Text.literal(newName)); name = newName; } diff --git a/src/main/java/io/github/skippyall/minions/gui/GuiDisplay.java b/src/main/java/io/github/skippyall/minions/gui/GuiDisplay.java index a0b3ca6..0622d83 100644 --- a/src/main/java/io/github/skippyall/minions/gui/GuiDisplay.java +++ b/src/main/java/io/github/skippyall/minions/gui/GuiDisplay.java @@ -2,7 +2,7 @@ package io.github.skippyall.minions.gui; import com.mojang.authlib.properties.PropertyMap; import com.mojang.serialization.Codec; -import io.github.skippyall.minions.MinionRegistries; +import io.github.skippyall.minions.registration.MinionRegistries; import io.github.skippyall.minions.Minions; import io.github.skippyall.minions.util.TranslationUtil; import it.unimi.dsi.fastutil.objects.ReferenceSortedSets; @@ -15,7 +15,6 @@ import net.minecraft.item.Items; import net.minecraft.registry.DynamicRegistryManager; import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; -import net.minecraft.registry.RegistryKeys; import net.minecraft.text.Text; import net.minecraft.util.Identifier; import net.minecraft.util.Rarity; diff --git a/src/main/java/io/github/skippyall/minions/gui/InstructionGui.java b/src/main/java/io/github/skippyall/minions/gui/InstructionGui.java index 8d024e2..0ec7ec2 100644 --- a/src/main/java/io/github/skippyall/minions/gui/InstructionGui.java +++ b/src/main/java/io/github/skippyall/minions/gui/InstructionGui.java @@ -2,7 +2,7 @@ package io.github.skippyall.minions.gui; import eu.pb4.sgui.api.elements.GuiElementBuilder; import eu.pb4.sgui.api.gui.SimpleGui; -import io.github.skippyall.minions.MinionRegistries; +import io.github.skippyall.minions.registration.MinionRegistries; import io.github.skippyall.minions.gui.input.Result; import io.github.skippyall.minions.gui.input.TextInput; import io.github.skippyall.minions.minion.MinionRuntime; @@ -164,6 +164,7 @@ public class InstructionGui { if (!future.isDone()) { future.cancel(false); } + super.onClose(); } }; gui.setTitle(Text.translatable("minions.gui.instruction.select_instruction")); @@ -193,6 +194,7 @@ public class InstructionGui { if (!future.isDone()) { future.cancel(false); } + super.onClose(); } }; gui.setTitle(Text.translatable("minions.gui.instruction.select_instruction")); diff --git a/src/main/java/io/github/skippyall/minions/gui/MinionLookGui.java b/src/main/java/io/github/skippyall/minions/gui/MinionLookGui.java index d2c58b9..ce0355e 100644 --- a/src/main/java/io/github/skippyall/minions/gui/MinionLookGui.java +++ b/src/main/java/io/github/skippyall/minions/gui/MinionLookGui.java @@ -2,7 +2,7 @@ package io.github.skippyall.minions.gui; import eu.pb4.sgui.api.elements.GuiElementBuilder; import eu.pb4.sgui.api.gui.SimpleGui; -import io.github.skippyall.minions.MinionRegistries; +import io.github.skippyall.minions.registration.MinionRegistries; import io.github.skippyall.minions.gui.input.TextInput; import io.github.skippyall.minions.minion.MinionData; import io.github.skippyall.minions.minion.MinionItem; @@ -49,9 +49,9 @@ public class MinionLookGui extends SimpleGui { GuiElementBuilder builder = new GuiElementBuilder() .setItem(Items.PLAYER_HEAD) .setCallback(() -> currentSkinProvider.openSkinMenu(player).thenAccept(skin -> { - MinionItem.setData(getData().withSkin(skin), minionItem); + MinionItem.setData(player.getServer(), getData().withSkin(skin), minionItem); })); - if(MinionItem.getData(minionItem) != null && MinionItem.getData(minionItem).skin().isPresent()) { + if(MinionItem.getData(player.getServer(), minionItem) != null && MinionItem.getData(player.getServer(), minionItem).skin().isPresent()) { builder.setComponent(DataComponentTypes.PROFILE, new ProfileComponent(Optional.empty(), Optional.empty(), getData().skin().get())); } setSlot(16, builder); @@ -77,7 +77,7 @@ public class MinionLookGui extends SimpleGui { } private MinionData getData() { - return MinionItem.getDataOrDefault(minionItem); + return MinionItem.getDataOrDefault(player.getServer(), minionItem); } public static void open(ServerPlayerEntity player, ItemStack minionItem) { @@ -87,9 +87,9 @@ public class MinionLookGui extends SimpleGui { } public void openRenameGui(ServerPlayerEntity player, ItemStack minionItem) { - TextInput.inputSync(player, Text.translatable("minions.gui.look.rename.title"), "Minion", MinionProfileUtils::checkMinionNameWithoutPrefix) + TextInput.inputSync(player, Text.translatable("minions.gui.look.rename.title"), "Minion", name -> MinionProfileUtils.checkMinionNameWithoutPrefix(player.getServer(), name)) .thenAccept(name -> { - MinionItem.setData(getData().withName(MinionProfileUtils.PREFIX + name), minionItem); + MinionItem.setData(player.getServer(), getData().withName(MinionProfileUtils.PREFIX + name), minionItem); open(); }); } diff --git a/src/main/java/io/github/skippyall/minions/minion/MinionData.java b/src/main/java/io/github/skippyall/minions/minion/MinionData.java index ddcda1f..c1482d6 100644 --- a/src/main/java/io/github/skippyall/minions/minion/MinionData.java +++ b/src/main/java/io/github/skippyall/minions/minion/MinionData.java @@ -1,22 +1,19 @@ package io.github.skippyall.minions.minion; import com.mojang.authlib.properties.PropertyMap; -import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import eu.pb4.polymer.core.api.other.PolymerComponent; -import io.github.skippyall.minions.MinionRegistries; +import io.github.skippyall.minions.registration.MinionRegistries; import io.github.skippyall.minions.Minions; import io.github.skippyall.minions.util.SerializableListenerManager; import net.minecraft.component.ComponentType; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtOps; import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; +import net.minecraft.server.MinecraftServer; import net.minecraft.util.Identifier; import net.minecraft.util.Uuids; import net.minecraft.util.dynamic.Codecs; -import org.jetbrains.annotations.Nullable; import java.util.Optional; import java.util.UUID; @@ -28,14 +25,17 @@ public record MinionData(UUID uuid, String name, Optional skin, boo Codec.STRING.fieldOf("name").forGetter(MinionData::name), Codecs.GAME_PROFILE_PROPERTY_MAP.optionalFieldOf("skin").forGetter(MinionData::skin), Codec.BOOL.optionalFieldOf("isSpawned", false).forGetter(MinionData::isSpawned), - SerializableListenerManager.getCodec(MinionRegistries.MINION_LISTENER_CODECS).optionalFieldOf("listeners", new SerializableListenerManager<>(MinionRegistries.MINION_LISTENER_CODECS)).forGetter(MinionData::listeners) + SerializableListenerManager.getCodec(MinionRegistries.MINION_LISTENER_CODECS).optionalFieldOf("listeners").xmap( + optional -> optional.orElseGet(() -> new SerializableListenerManager<>(MinionRegistries.MINION_LISTENER_CODECS)), + Optional::of + ).forGetter(MinionData::listeners) ).apply(instance, MinionData::new) ); public static final ComponentType COMPONENT = Registry.register(Registries.DATA_COMPONENT_TYPE, Identifier.of(Minions.MOD_ID, "minion_data"), ComponentType.builder().codec(Uuids.CODEC).build()); - public static MinionData createDefault() { - return new MinionData(UUID.randomUUID(), MinionProfileUtils.newDefaultMinionName(), Optional.empty(), false, new SerializableListenerManager<>(MinionRegistries.MINION_LISTENER_CODECS)); + public static MinionData createDefault(MinecraftServer server) { + return new MinionData(UUID.randomUUID(), MinionProfileUtils.newDefaultMinionName(server), Optional.empty(), false, new SerializableListenerManager<>(MinionRegistries.MINION_LISTENER_CODECS)); } public MinionData withName(String name) { @@ -50,14 +50,6 @@ public record MinionData(UUID uuid, String name, Optional skin, boo return new MinionData(uuid, name, skin, isSpawned, listeners); } - public NbtCompound writeNbt() { - return (NbtCompound) MinionData.CODEC.encode(this, NbtOps.INSTANCE, null).result().orElse(new NbtCompound()); - } - - public static MinionData readNbt(NbtCompound nbt) { - return MinionData.CODEC.decode(NbtOps.INSTANCE, nbt).resultOrPartial().map(Pair::getFirst).orElseGet(MinionData::createDefault); - } - public static void register() { PolymerComponent.registerDataComponent(COMPONENT); } diff --git a/src/main/java/io/github/skippyall/minions/minion/MinionItem.java b/src/main/java/io/github/skippyall/minions/minion/MinionItem.java index ee5938e..56ebd68 100644 --- a/src/main/java/io/github/skippyall/minions/minion/MinionItem.java +++ b/src/main/java/io/github/skippyall/minions/minion/MinionItem.java @@ -12,6 +12,7 @@ import net.minecraft.item.ItemStack; import net.minecraft.item.ItemUsageContext; import net.minecraft.item.Items; import net.minecraft.item.tooltip.TooltipType; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.text.Text; @@ -23,7 +24,6 @@ import net.minecraft.world.World; import org.jetbrains.annotations.Nullable; import xyz.nucleoid.packettweaker.PacketContext; -import java.util.List; import java.util.function.Consumer; public class MinionItem extends Item implements PolymerItem { @@ -49,8 +49,8 @@ public class MinionItem extends Item implements PolymerItem { } @Override - public void appendTooltip(ItemStack stack, TooltipContext context, TooltipDisplayComponent component, Consumer tooltip, TooltipType type) { - MinionData data = getData(stack); + public void appendTooltip(ItemStack stack, TooltipContext context, TooltipDisplayComponent component, Consumer tooltip, TooltipType type) { + MinionData data = null /*getData(stack)*/; if(data != null) { tooltip.accept(Text.translatable("minions.minion_item.tooltip", data.name())); } @@ -70,31 +70,31 @@ public class MinionItem extends Item implements PolymerItem { @Override public ActionResult useOnBlock(ItemUsageContext context) { if(!context.getWorld().isClient) { - MinionData data = getDataOrDefault(context.getStack()); + MinionData data = getDataOrDefault(context.getWorld().getServer(), context.getStack()); MinionFakePlayer.spawnMinion(data, (ServerWorld) context.getWorld(), context.getBlockPos().toCenterPos().add(0,0.5,0), new Vec2f(0, 0)); } context.getStack().decrement(1); return ActionResult.SUCCESS; } - public static void setData(MinionData data, ItemStack item) { + public static void setData(MinecraftServer server, MinionData data, ItemStack item) { item.set(MinionData.COMPONENT, data.uuid()); - MinionPersistentState.INSTANCE.updateMinionData(data); + MinionPersistentState.get(server).updateMinionData(data); } @Nullable - public static MinionData getData(ItemStack item) { + public static MinionData getData(MinecraftServer server, ItemStack item) { if(item.contains(MinionData.COMPONENT)) { - return MinionPersistentState.INSTANCE.getMinionData(item.get(MinionData.COMPONENT)); + return MinionPersistentState.get(server).getMinionData(item.get(MinionData.COMPONENT)); } return null; } - public static MinionData getDataOrDefault(ItemStack item) { - MinionData data = getData(item); + public static MinionData getDataOrDefault(MinecraftServer server, ItemStack item) { + MinionData data = getData(server, item); if(data == null) { - data = MinionData.createDefault(); - setData(data, item); + data = MinionData.createDefault(server); + setData(server, data, item); } return data; } diff --git a/src/main/java/io/github/skippyall/minions/minion/MinionListener.java b/src/main/java/io/github/skippyall/minions/minion/MinionListener.java index 5f811e9..b18a285 100644 --- a/src/main/java/io/github/skippyall/minions/minion/MinionListener.java +++ b/src/main/java/io/github/skippyall/minions/minion/MinionListener.java @@ -12,7 +12,7 @@ public interface MinionListener extends SerializableListenerManager.Serializable default void onInstructionsUpdate(MinionFakePlayer minion) {} - default void onInstructionRename(MinionFakePlayer minion, ConfiguredInstruction instruction, String newName) {} + default void onInstructionRename(MinionFakePlayer minion, ConfiguredInstruction instruction, String oldName, String newName) {} interface Delegating extends MinionListener { @Nullable MinionListener getBacking(); @@ -34,14 +34,14 @@ public interface MinionListener extends SerializableListenerManager.Serializable @Override default void onInstructionsUpdate(MinionFakePlayer minion) { if(getBacking() != null) { - getBacking().onMinionSpawn(minion); + getBacking().onInstructionsUpdate(minion); } } @Override - default void onInstructionRename(MinionFakePlayer minion, ConfiguredInstruction instruction, String newName) { + default void onInstructionRename(MinionFakePlayer minion, ConfiguredInstruction instruction, String oldName, String newName) { if(getBacking() != null) { - getBacking().onInstructionRename(minion, instruction, newName); + getBacking().onInstructionRename(minion, instruction, oldName, newName); } } } diff --git a/src/main/java/io/github/skippyall/minions/minion/MinionPersistentState.java b/src/main/java/io/github/skippyall/minions/minion/MinionPersistentState.java index 0ee429e..f3b99b4 100644 --- a/src/main/java/io/github/skippyall/minions/minion/MinionPersistentState.java +++ b/src/main/java/io/github/skippyall/minions/minion/MinionPersistentState.java @@ -17,8 +17,6 @@ public class MinionPersistentState extends PersistentState { public static PersistentStateType TYPE = new PersistentStateType<>("minion", MinionPersistentState::new, MinionPersistentState.CODEC, null); - public static MinionPersistentState INSTANCE; - private final Map minionData = new HashMap<>(); public MinionPersistentState() { @@ -62,7 +60,7 @@ public class MinionPersistentState extends PersistentState { .findFirst(); } - public static void create(MinecraftServer server) { - INSTANCE = server.getWorld(World.OVERWORLD).getPersistentStateManager().getOrCreate(TYPE); + public static MinionPersistentState get(MinecraftServer server) { + return server.getWorld(World.OVERWORLD).getPersistentStateManager().getOrCreate(TYPE); } } diff --git a/src/main/java/io/github/skippyall/minions/minion/MinionProfileUtils.java b/src/main/java/io/github/skippyall/minions/minion/MinionProfileUtils.java index 7bc56a0..9542a99 100644 --- a/src/main/java/io/github/skippyall/minions/minion/MinionProfileUtils.java +++ b/src/main/java/io/github/skippyall/minions/minion/MinionProfileUtils.java @@ -4,6 +4,7 @@ import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.PropertyMap; import com.mojang.brigadier.StringReader; import io.github.skippyall.minions.gui.input.Result; +import net.minecraft.server.MinecraftServer; import net.minecraft.text.Text; import net.minecraft.util.StringHelper; @@ -27,7 +28,7 @@ public class MinionProfileUtils { return newProfile; } - public static Result checkMinionNameWithoutPrefix(String name) { + public static Result checkMinionNameWithoutPrefix(MinecraftServer server, String name) { for(char c : name.toCharArray()) { if(!StringReader.isAllowedInUnquotedString(c)) { return new Result.Error<>(Text.translatable("minions.generic.name.invalid_char")); @@ -42,22 +43,22 @@ public class MinionProfileUtils { return new Result.Error<>(Text.translatable("minions.generic.name.invalid")); } - if(MinionPersistentState.INSTANCE.isMinionNameTaken(PREFIX + name)) { + if(MinionPersistentState.get(server).isMinionNameTaken(PREFIX + name)) { return new Result.Error<>(Text.translatable("minions.generic.name.taken")); } return new Result.Success<>(name); } - public static String newDefaultMinionName() { + public static String newDefaultMinionName(MinecraftServer server) { int i = 0; - while (MinionPersistentState.INSTANCE.isMinionNameTaken("+Minion" + i)) { + while (MinionPersistentState.get(server).isMinionNameTaken("+Minion" + i)) { i++; } return "+Minion" + i; } - public static boolean isMinion(UUID uuid) { - return MinionPersistentState.INSTANCE.isMinion(uuid); + public static boolean isMinion(MinecraftServer server, UUID uuid) { + return MinionPersistentState.get(server).isMinion(uuid); } } diff --git a/src/main/java/io/github/skippyall/minions/minion/MinionRuntime.java b/src/main/java/io/github/skippyall/minions/minion/MinionRuntime.java index de3061f..80971eb 100644 --- a/src/main/java/io/github/skippyall/minions/minion/MinionRuntime.java +++ b/src/main/java/io/github/skippyall/minions/minion/MinionRuntime.java @@ -1,6 +1,6 @@ package io.github.skippyall.minions.minion; -import io.github.skippyall.minions.MinionRegistries; +import io.github.skippyall.minions.registration.MinionRegistries; import io.github.skippyall.minions.Minions; import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import io.github.skippyall.minions.program.InstructionRuntime; @@ -83,7 +83,7 @@ public class MinionRuntime implements InstructionRuntime { minion.forEachMinionListener(minionListener -> { - minionListener.onInstructionRename(minion , instruction, newName); + minionListener.onInstructionRename(minion, instruction, oldName, newName); minionListener.onInstructionsUpdate(minion); }); } diff --git a/src/main/java/io/github/skippyall/minions/minion/fakeplayer/MinionFakePlayer.java b/src/main/java/io/github/skippyall/minions/minion/fakeplayer/MinionFakePlayer.java index e133c2a..59225e6 100644 --- a/src/main/java/io/github/skippyall/minions/minion/fakeplayer/MinionFakePlayer.java +++ b/src/main/java/io/github/skippyall/minions/minion/fakeplayer/MinionFakePlayer.java @@ -3,8 +3,7 @@ package io.github.skippyall.minions.minion.fakeplayer; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.PropertyMap; -import io.github.skippyall.minions.MinionItems; -import io.github.skippyall.minions.MinionRegistries; +import io.github.skippyall.minions.registration.MinionItems; import io.github.skippyall.minions.minion.MinionListener; import io.github.skippyall.minions.minion.MinionData; import io.github.skippyall.minions.gui.MinionGui; @@ -12,7 +11,6 @@ import io.github.skippyall.minions.minion.MinionRuntime; import io.github.skippyall.minions.minion.MinionItem; import io.github.skippyall.minions.minion.MinionPersistentState; import io.github.skippyall.minions.minion.MinionProfileUtils; -import io.github.skippyall.minions.module.MobSpawningAbility; import io.github.skippyall.minions.module.ModuleInventory; import io.github.skippyall.minions.module.SpecialAbilities; import io.github.skippyall.minions.util.SerializableListenerManager; @@ -57,12 +55,9 @@ public class MinionFakePlayer extends ServerPlayerEntity { private EntityPlayerActionPack actionPack; - private final SerializableListenerManager minionListeners = new SerializableListenerManager<>(MinionRegistries.MINION_LISTENER_CODECS); private final ModuleInventory moduleInventory = new ModuleInventory(this); private final MinionRuntime instructionManager = new MinionRuntime(this); - private final MinionData data; - public static void spawnMinion(MinionData data, ServerWorld level, @Nullable Vec3d pos, @Nullable Vec2f rot) { spawnMinion(data, level, pos, rot, false); } @@ -79,8 +74,8 @@ public class MinionFakePlayer extends ServerPlayerEntity { } private static void doSpawn(MinionData data, GameProfile profile, MinecraftServer server, ServerWorld level, @Nullable Vec3d pos, @Nullable Vec2f rot) { - MinionFakePlayer instance = new MinionFakePlayer(server, level, profile, SyncedClientOptions.createDefault(), data); - MinionPersistentState.INSTANCE.updateMinionData(data.withSpawned(true)); + MinionFakePlayer instance = new MinionFakePlayer(server, level, profile, SyncedClientOptions.createDefault()); + MinionPersistentState.get(server).updateMinionData(data.withSpawned(true)); if(pos != null && rot != null) { instance.fixStartingPosition = () -> instance.refreshPositionAndAngles(pos.x, pos.y, pos.z, rot.x, rot.y); @@ -101,18 +96,17 @@ public class MinionFakePlayer extends ServerPlayerEntity { instance.dataTracker.set(PLAYER_MODEL_PARTS, (byte) 0x7f); // show all model layers (incl. capes) instance.getAbilities().flying = false; - instance.minionListeners.forEachListener(listener -> listener.onMinionSpawn(instance)); + instance.listeners().forEach(listener -> listener.onMinionSpawn(instance)); } - public static MinionFakePlayer respawnFake(MinecraftServer server, ServerWorld level, GameProfile profile, SyncedClientOptions cli, MinionData data) + public static MinionFakePlayer respawnFake(MinecraftServer server, ServerWorld level, GameProfile profile, SyncedClientOptions cli) { - return new MinionFakePlayer(server, level, profile, cli, data); + return new MinionFakePlayer(server, level, profile, cli); } - private MinionFakePlayer(MinecraftServer server, ServerWorld worldIn, GameProfile profile, SyncedClientOptions cli, MinionData data) + private MinionFakePlayer(MinecraftServer server, ServerWorld worldIn, GameProfile profile, SyncedClientOptions cli) { super(server, worldIn, profile, cli); - this.data = data; actionPack = new EntityPlayerActionPack(this); } @@ -129,19 +123,23 @@ public class MinionFakePlayer extends ServerPlayerEntity { } public MinionData getData() { - return data; + return MinionPersistentState.get(getServer()).getMinionData(getUuid()); + } + + public SerializableListenerManager listeners() { + return getData().listeners(); } public void addMinionListener(MinionListener listener) { - minionListeners.addListener(listener); + listeners().addListener(listener); } public void removeMinionListener(MinionListener listener) { - minionListeners.removeListener(listener); + listeners().removeListener(listener); } public void forEachMinionListener(Consumer listenerConsumer) { - minionListeners.forEachListener(listenerConsumer); + listeners().forEach(listenerConsumer); } public boolean canSpawnMobs() { @@ -173,7 +171,7 @@ public class MinionFakePlayer extends ServerPlayerEntity { public void kill(Text reason) { - minionListeners.forEachListener(listener -> listener.onMinionRemove(this)); + listeners().forEach(listener -> listener.onMinionRemove(this)); shakeOff(); @@ -185,7 +183,7 @@ public class MinionFakePlayer extends ServerPlayerEntity { })); } - MinionPersistentState.INSTANCE.updateMinionData(data.withSpawned(false)); + MinionPersistentState.get(getServer()).updateMinionData(getData().withSpawned(false)); } @Override @@ -266,15 +264,15 @@ public class MinionFakePlayer extends ServerPlayerEntity { @Override public void drop(ServerWorld world, DamageSource damageSource) { super.drop(world, damageSource); - ItemEntity entity = dropStack(world, toItemStack()); + ItemEntity entity = dropStack(world, toItemStack(getServer())); if (entity != null) { entity.setNeverDespawn(); } } - private ItemStack toItemStack() { + private ItemStack toItemStack(MinecraftServer server) { ItemStack stack = new ItemStack(MinionItems.MINION_ITEM); - MinionItem.setData(data, stack); + MinionItem.setData(server, getData(), stack); return stack; } @@ -283,7 +281,6 @@ public class MinionFakePlayer extends ServerPlayerEntity { super.writeCustomData(view); moduleInventory.writeData(view.get("modules")); instructionManager.save(view.get("instructionManager")); - minionListeners.save(view); } @Override @@ -291,6 +288,5 @@ public class MinionFakePlayer extends ServerPlayerEntity { super.readCustomData(view); moduleInventory.readData(view.getReadView("modules")); instructionManager.load(view.getReadView("instructionManager")); - minionListeners.load(view); } } \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/minion/skin/SkinProviders.java b/src/main/java/io/github/skippyall/minions/minion/skin/SkinProviders.java index 7749c46..c36a69d 100644 --- a/src/main/java/io/github/skippyall/minions/minion/skin/SkinProviders.java +++ b/src/main/java/io/github/skippyall/minions/minion/skin/SkinProviders.java @@ -1,6 +1,6 @@ package io.github.skippyall.minions.minion.skin; -import io.github.skippyall.minions.MinionRegistries; +import io.github.skippyall.minions.registration.MinionRegistries; import io.github.skippyall.minions.Minions; import net.minecraft.registry.Registry; import net.minecraft.util.Identifier; diff --git a/src/main/java/io/github/skippyall/minions/mixins/PlayerListMixin.java b/src/main/java/io/github/skippyall/minions/mixins/PlayerListMixin.java index 8557760..8f4fc7f 100644 --- a/src/main/java/io/github/skippyall/minions/mixins/PlayerListMixin.java +++ b/src/main/java/io/github/skippyall/minions/mixins/PlayerListMixin.java @@ -54,7 +54,7 @@ public class PlayerListMixin { @WrapOperation(method = "respawnPlayer", at = @At(value = "NEW", target = "(Lnet/minecraft/server/MinecraftServer;Lnet/minecraft/server/world/ServerWorld;Lcom/mojang/authlib/GameProfile;Lnet/minecraft/network/packet/c2s/common/SyncedClientOptions;)Lnet/minecraft/server/network/ServerPlayerEntity;")) public ServerPlayerEntity makePlayerForRespawn(MinecraftServer minecraftServer, ServerWorld serverLevel, GameProfile gameProfile, SyncedClientOptions clientInformation, Operation original, ServerPlayerEntity serverPlayer, boolean bl) { if (serverPlayer instanceof MinionFakePlayer minion) { - return MinionFakePlayer.respawnFake(minecraftServer, serverLevel, gameProfile, clientInformation, minion.getData()); + return MinionFakePlayer.respawnFake(minecraftServer, serverLevel, gameProfile, clientInformation); } return original.call(minecraftServer, serverLevel, gameProfile, clientInformation); } diff --git a/src/main/java/io/github/skippyall/minions/module/MinionModule.java b/src/main/java/io/github/skippyall/minions/module/MinionModule.java index 93c9f05..c846991 100644 --- a/src/main/java/io/github/skippyall/minions/module/MinionModule.java +++ b/src/main/java/io/github/skippyall/minions/module/MinionModule.java @@ -3,7 +3,7 @@ package io.github.skippyall.minions.module; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import eu.pb4.polymer.core.api.other.PolymerComponent; -import io.github.skippyall.minions.MinionRegistries; +import io.github.skippyall.minions.registration.MinionRegistries; import io.github.skippyall.minions.Minions; import io.github.skippyall.minions.minion.MinionRuntime; import io.github.skippyall.minions.program.instruction.InstructionType; diff --git a/src/main/java/io/github/skippyall/minions/module/SpecialAbilities.java b/src/main/java/io/github/skippyall/minions/module/SpecialAbilities.java index c84d26d..9deed87 100644 --- a/src/main/java/io/github/skippyall/minions/module/SpecialAbilities.java +++ b/src/main/java/io/github/skippyall/minions/module/SpecialAbilities.java @@ -1,6 +1,6 @@ package io.github.skippyall.minions.module; -import io.github.skippyall.minions.MinionRegistries; +import io.github.skippyall.minions.registration.MinionRegistries; import io.github.skippyall.minions.Minions; import net.minecraft.registry.Registry; import net.minecraft.util.Identifier; diff --git a/src/main/java/io/github/skippyall/minions/program/consumer/ValueConsumer.java b/src/main/java/io/github/skippyall/minions/program/consumer/ValueConsumer.java index cdccb72..09da40b 100644 --- a/src/main/java/io/github/skippyall/minions/program/consumer/ValueConsumer.java +++ b/src/main/java/io/github/skippyall/minions/program/consumer/ValueConsumer.java @@ -1,7 +1,7 @@ package io.github.skippyall.minions.program.consumer; import com.mojang.serialization.Codec; -import io.github.skippyall.minions.MinionRegistries; +import io.github.skippyall.minions.registration.MinionRegistries; import io.github.skippyall.minions.program.InstructionRuntime; import io.github.skippyall.minions.program.value.ValueType; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/io/github/skippyall/minions/program/instruction/ConfiguredInstruction.java b/src/main/java/io/github/skippyall/minions/program/instruction/ConfiguredInstruction.java index 8cbe38e..84ff787 100644 --- a/src/main/java/io/github/skippyall/minions/program/instruction/ConfiguredInstruction.java +++ b/src/main/java/io/github/skippyall/minions/program/instruction/ConfiguredInstruction.java @@ -1,6 +1,6 @@ package io.github.skippyall.minions.program.instruction; -import io.github.skippyall.minions.MinionRegistries; +import io.github.skippyall.minions.registration.MinionRegistries; import io.github.skippyall.minions.Minions; import io.github.skippyall.minions.program.InstructionRuntime; import io.github.skippyall.minions.program.supplier.Parameter; @@ -66,7 +66,7 @@ public class ConfiguredInstruction> { Minions.LOGGER.error("An error occurred while executing configured Instruction", e); } - listeners.forEachListener(listener -> listener.onRun(this)); + listeners.forEach(listener -> listener.onRun(this)); } } @@ -87,20 +87,20 @@ public class ConfiguredInstruction> { if(execution != null) { execution.stop(minion, valueConsumers); execution = null; - listeners.forEachListener(listener -> listener.onStop(this)); + listeners.forEach(listener -> listener.onStop(this)); } } private void onSupplierChange(Parameter parameter) { - listeners.forEachListener(listener -> listener.onSupplierChange(this, parameter)); + listeners.forEach(listener -> listener.onSupplierChange(this, parameter)); } private void onConsumerChange(Parameter parameter) { - listeners.forEachListener(listener -> listener.onConsumerChange(this, parameter)); + listeners.forEach(listener -> listener.onConsumerChange(this, parameter)); } public void onInstructionRemove() { - listeners.forEachListener(listener -> listener.onInstructionRemove(this)); + listeners.forEach(listener -> listener.onInstructionRemove(this)); } public void addListener(ConfiguredInstructionListener listener) { diff --git a/src/main/java/io/github/skippyall/minions/program/instruction/Instructions.java b/src/main/java/io/github/skippyall/minions/program/instruction/Instructions.java index 115dc61..8c8685b 100644 --- a/src/main/java/io/github/skippyall/minions/program/instruction/Instructions.java +++ b/src/main/java/io/github/skippyall/minions/program/instruction/Instructions.java @@ -1,6 +1,6 @@ package io.github.skippyall.minions.program.instruction; -import io.github.skippyall.minions.MinionRegistries; +import io.github.skippyall.minions.registration.MinionRegistries; import io.github.skippyall.minions.Minions; import io.github.skippyall.minions.minion.MinionRuntime; import io.github.skippyall.minions.minion.fakeplayer.EntityPlayerActionPack; diff --git a/src/main/java/io/github/skippyall/minions/program/instruction/execution/inventory/SwapItemExecution.java b/src/main/java/io/github/skippyall/minions/program/instruction/execution/inventory/SwapItemExecution.java new file mode 100644 index 0000000..e41b289 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/program/instruction/execution/inventory/SwapItemExecution.java @@ -0,0 +1,118 @@ +package io.github.skippyall.minions.program.instruction.execution.inventory; + +import io.github.skippyall.minions.minion.MinionRuntime; +import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; +import io.github.skippyall.minions.program.consumer.ValueConsumerList; +import io.github.skippyall.minions.program.instruction.InstructionExecution; +import io.github.skippyall.minions.program.supplier.ValueSupplierList; +import net.minecraft.component.EnchantmentEffectComponentTypes; +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.slot.Slot; +import net.minecraft.screen.slot.SlotActionType; +import net.minecraft.storage.ReadView; +import net.minecraft.storage.WriteView; + +public class SwapItemExecution implements InstructionExecution { + private int fromSlot; + private boolean fromScreen; + private int toSlot; + private boolean toScreen; + + @Override + public void start(MinionRuntime runtime) { + MinionFakePlayer minion = runtime.getMinion(); + + if((fromScreen || toScreen) && minion.currentScreenHandler == null) { + return; + } + if(!(checkBounds(minion, fromSlot, fromScreen) && checkBounds(minion, toSlot, toScreen))) { + return; + } + + ItemStack fromStack = getStack(minion, fromSlot, fromScreen); + ItemStack toStack = getStack(minion, toSlot, toScreen); + + if(!(canExchange(minion, fromSlot, fromScreen, toStack) && canExchange(minion, toSlot, toScreen, fromStack))) { + return; + } + + + } + + private boolean checkBounds(MinionFakePlayer minion, int slot, boolean screen) { + if(screen) { + return slot >= 0 && slot < minion.currentScreenHandler.slots.size(); + } else { + return slot >= 0 && slot <= PlayerInventory.OFF_HAND_SLOT; + } + } + + private ItemStack getStack(MinionFakePlayer minion, int slot, boolean screen) { + if(screen) { + return minion.currentScreenHandler.getSlot(slot).getStack(); + } else { + return minion.getInventory().getStack(slot); + } + } + + private boolean canExchange(MinionFakePlayer minion, int slotIndex, boolean screen, ItemStack newStack) { + if(screen) { + Slot slot = minion.currentScreenHandler.getSlot(slotIndex); + if(!slot.getStack().isEmpty() && !slot.canTakeItems(minion)) { + return false; + } + if(!newStack.isEmpty() && !slot.canInsert(newStack)) { + return false; + } + } else { + if(slotIndex >= PlayerInventory.MAIN_SIZE && slotIndex < PlayerInventory.OFF_HAND_SLOT) { + if(!minion.canEquip(newStack, PlayerInventory.EQUIPMENT_SLOTS.get(slotIndex))) { + return false; + } + if(EnchantmentHelper.hasAnyEnchantmentsWith(minion.getInventory().getStack(slotIndex), EnchantmentEffectComponentTypes.PREVENT_ARMOR_CHANGE)) { + return false; + } + } + } + return true; + } + + private void simulateClick(MinionFakePlayer minion, int slotIndex, boolean screen) { + if(screen) { + minion.currentScreenHandler.onSlotClick(slotIndex, 0, SlotActionType.SWAP, minion); + } else { + } + } + + @Override + public void tick(MinionRuntime runtime) { + InstructionExecution.super.tick(runtime); + } + + @Override + public boolean isDone(MinionRuntime runtime) { + return false; + } + + @Override + public void stop(MinionRuntime runtime, ValueConsumerList valueConsumers) { + InstructionExecution.super.stop(runtime, valueConsumers); + } + + @Override + public void readArguments(ValueSupplierList arguments, MinionRuntime runtime) { + + } + + @Override + public void save(WriteView view, MinionRuntime runtime) { + + } + + @Override + public void load(ReadView view, MinionRuntime runtime) { + + } +} diff --git a/src/main/java/io/github/skippyall/minions/program/supplier/Parameter.java b/src/main/java/io/github/skippyall/minions/program/supplier/Parameter.java index 20abec5..7226dab 100644 --- a/src/main/java/io/github/skippyall/minions/program/supplier/Parameter.java +++ b/src/main/java/io/github/skippyall/minions/program/supplier/Parameter.java @@ -2,7 +2,7 @@ package io.github.skippyall.minions.program.supplier; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; -import io.github.skippyall.minions.MinionRegistries; +import io.github.skippyall.minions.registration.MinionRegistries; import io.github.skippyall.minions.program.value.ValueType; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/io/github/skippyall/minions/program/supplier/ValueSupplier.java b/src/main/java/io/github/skippyall/minions/program/supplier/ValueSupplier.java index ad6eb5b..4d7a77a 100644 --- a/src/main/java/io/github/skippyall/minions/program/supplier/ValueSupplier.java +++ b/src/main/java/io/github/skippyall/minions/program/supplier/ValueSupplier.java @@ -1,7 +1,7 @@ package io.github.skippyall.minions.program.supplier; import com.mojang.serialization.Codec; -import io.github.skippyall.minions.MinionRegistries; +import io.github.skippyall.minions.registration.MinionRegistries; import io.github.skippyall.minions.program.InstructionRuntime; import io.github.skippyall.minions.program.value.ValueType; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/io/github/skippyall/minions/program/supplier/ValueSuppliers.java b/src/main/java/io/github/skippyall/minions/program/supplier/ValueSuppliers.java index cdb7883..5ca0eb2 100644 --- a/src/main/java/io/github/skippyall/minions/program/supplier/ValueSuppliers.java +++ b/src/main/java/io/github/skippyall/minions/program/supplier/ValueSuppliers.java @@ -1,6 +1,6 @@ package io.github.skippyall.minions.program.supplier; -import io.github.skippyall.minions.MinionRegistries; +import io.github.skippyall.minions.registration.MinionRegistries; import io.github.skippyall.minions.Minions; import io.github.skippyall.minions.minion.MinionRuntime; import net.minecraft.registry.Registry; diff --git a/src/main/java/io/github/skippyall/minions/program/value/ValueTypes.java b/src/main/java/io/github/skippyall/minions/program/value/ValueTypes.java index 2c04d1d..6d3dbf9 100644 --- a/src/main/java/io/github/skippyall/minions/program/value/ValueTypes.java +++ b/src/main/java/io/github/skippyall/minions/program/value/ValueTypes.java @@ -1,7 +1,7 @@ package io.github.skippyall.minions.program.value; import com.mojang.serialization.Codec; -import io.github.skippyall.minions.MinionRegistries; +import io.github.skippyall.minions.registration.MinionRegistries; import io.github.skippyall.minions.Minions; import io.github.skippyall.minions.gui.input.ChoiceInput; import io.github.skippyall.minions.gui.input.TextInput; diff --git a/src/main/java/io/github/skippyall/minions/reference/Reference.java b/src/main/java/io/github/skippyall/minions/reference/Reference.java index 0b01d58..4230c1c 100644 --- a/src/main/java/io/github/skippyall/minions/reference/Reference.java +++ b/src/main/java/io/github/skippyall/minions/reference/Reference.java @@ -3,7 +3,7 @@ package io.github.skippyall.minions.reference; import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; import eu.pb4.polymer.core.api.other.PolymerComponent; -import io.github.skippyall.minions.MinionRegistries; +import io.github.skippyall.minions.registration.MinionRegistries; import io.github.skippyall.minions.Minions; import net.fabricmc.fabric.api.item.v1.ComponentTooltipAppenderRegistry; import net.minecraft.component.ComponentType; diff --git a/src/main/java/io/github/skippyall/minions/reference/ReferenceItem.java b/src/main/java/io/github/skippyall/minions/reference/ReferenceItem.java index 212c125..8c784c8 100644 --- a/src/main/java/io/github/skippyall/minions/reference/ReferenceItem.java +++ b/src/main/java/io/github/skippyall/minions/reference/ReferenceItem.java @@ -1,7 +1,7 @@ package io.github.skippyall.minions.reference; import eu.pb4.polymer.core.api.item.PolymerItem; -import io.github.skippyall.minions.MinionItems; +import io.github.skippyall.minions.registration.MinionItems; import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import net.minecraft.component.DataComponentTypes; import net.minecraft.item.Item; diff --git a/src/main/java/io/github/skippyall/minions/MinionBlocks.java b/src/main/java/io/github/skippyall/minions/registration/MinionBlocks.java similarity index 86% rename from src/main/java/io/github/skippyall/minions/MinionBlocks.java rename to src/main/java/io/github/skippyall/minions/registration/MinionBlocks.java index 5e98c02..72e8cb1 100644 --- a/src/main/java/io/github/skippyall/minions/MinionBlocks.java +++ b/src/main/java/io/github/skippyall/minions/registration/MinionBlocks.java @@ -1,8 +1,9 @@ -package io.github.skippyall.minions; +package io.github.skippyall.minions.registration; import eu.pb4.polymer.core.api.block.PolymerBlockUtils; -import io.github.skippyall.minions.block.MinionTriggerBlock; -import io.github.skippyall.minions.block.MinionTriggerBlockEntity; +import io.github.skippyall.minions.Minions; +import io.github.skippyall.minions.block.miniontrigger.MinionTriggerBlock; +import io.github.skippyall.minions.block.miniontrigger.MinionTriggerBlockEntity; import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; import net.minecraft.block.AbstractBlock; import net.minecraft.block.entity.BlockEntityType; diff --git a/src/main/java/io/github/skippyall/minions/MinionCreativeTab.java b/src/main/java/io/github/skippyall/minions/registration/MinionCreativeTab.java similarity index 92% rename from src/main/java/io/github/skippyall/minions/MinionCreativeTab.java rename to src/main/java/io/github/skippyall/minions/registration/MinionCreativeTab.java index 0c019ed..917160a 100644 --- a/src/main/java/io/github/skippyall/minions/MinionCreativeTab.java +++ b/src/main/java/io/github/skippyall/minions/registration/MinionCreativeTab.java @@ -1,6 +1,7 @@ -package io.github.skippyall.minions; +package io.github.skippyall.minions.registration; import eu.pb4.polymer.core.api.item.PolymerItemGroupUtils; +import io.github.skippyall.minions.Minions; import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup; import net.minecraft.item.Item; import net.minecraft.item.ItemGroup; diff --git a/src/main/java/io/github/skippyall/minions/MinionItems.java b/src/main/java/io/github/skippyall/minions/registration/MinionItems.java similarity index 94% rename from src/main/java/io/github/skippyall/minions/MinionItems.java rename to src/main/java/io/github/skippyall/minions/registration/MinionItems.java index da2fd4b..8ddebd9 100644 --- a/src/main/java/io/github/skippyall/minions/MinionItems.java +++ b/src/main/java/io/github/skippyall/minions/registration/MinionItems.java @@ -1,12 +1,11 @@ -package io.github.skippyall.minions; +package io.github.skippyall.minions.registration; import eu.pb4.polymer.core.api.item.PolymerBlockItem; import eu.pb4.polymer.core.api.item.SimplePolymerItem; -import io.github.skippyall.minions.block.MinionTriggerBlockItem; +import io.github.skippyall.minions.block.miniontrigger.MinionTriggerBlockItem; import io.github.skippyall.minions.minion.MinionItem; import io.github.skippyall.minions.minion.MinionRuntime; import io.github.skippyall.minions.module.MinionModule; -import io.github.skippyall.minions.module.MobSpawningAbility; import io.github.skippyall.minions.module.SpecialAbilities; import io.github.skippyall.minions.module.SpecialAbility; import io.github.skippyall.minions.program.instruction.InstructionType; @@ -75,7 +74,8 @@ public class MinionItems { public static final PolymerBlockItem MINION_TRIGGER_ITEM = registerItem( MinionBlocks.MINION_TRIGGER_ID, - settings -> new MinionTriggerBlockItem(MinionBlocks.MINION_TRIGGER_BLOCK, settings, Items.COMPARATOR) + settings -> new MinionTriggerBlockItem(MinionBlocks.MINION_TRIGGER_BLOCK, settings, Items.COMPARATOR), + new Item.Settings().useBlockPrefixedTranslationKey() ); public static final ReferenceItem REFERENCE_ITEM = registerItem(Identifier.of(MOD_ID, "reference"), ReferenceItem::new); diff --git a/src/main/java/io/github/skippyall/minions/registration/MinionRegistration.java b/src/main/java/io/github/skippyall/minions/registration/MinionRegistration.java new file mode 100644 index 0000000..e4bc3ef --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/registration/MinionRegistration.java @@ -0,0 +1,13 @@ +package io.github.skippyall.minions.registration; + +import io.github.skippyall.minions.Minions; +import io.github.skippyall.minions.block.miniontrigger.MinionTriggerMinionListener; +import net.minecraft.registry.Registry; +import net.minecraft.util.Identifier; + +public class MinionRegistration { + + public static void register() { + Registry.register(MinionRegistries.MINION_LISTENER_CODECS, Identifier.of(Minions.MOD_ID, "minion_trigger"), MinionTriggerMinionListener.CODEC); + } +} diff --git a/src/main/java/io/github/skippyall/minions/MinionRegistries.java b/src/main/java/io/github/skippyall/minions/registration/MinionRegistries.java similarity index 97% rename from src/main/java/io/github/skippyall/minions/MinionRegistries.java rename to src/main/java/io/github/skippyall/minions/registration/MinionRegistries.java index bc260d2..9b0c17c 100644 --- a/src/main/java/io/github/skippyall/minions/MinionRegistries.java +++ b/src/main/java/io/github/skippyall/minions/registration/MinionRegistries.java @@ -1,7 +1,8 @@ -package io.github.skippyall.minions; +package io.github.skippyall.minions.registration; import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; +import io.github.skippyall.minions.Minions; import io.github.skippyall.minions.docs.ReferenceEntry; import io.github.skippyall.minions.gui.GuiDisplay; import io.github.skippyall.minions.minion.MinionListener; diff --git a/src/main/java/io/github/skippyall/minions/util/ListenerManager.java b/src/main/java/io/github/skippyall/minions/util/ListenerManager.java index 5401fdf..131602f 100644 --- a/src/main/java/io/github/skippyall/minions/util/ListenerManager.java +++ b/src/main/java/io/github/skippyall/minions/util/ListenerManager.java @@ -1,10 +1,12 @@ package io.github.skippyall.minions.util; +import org.jetbrains.annotations.NotNull; + +import java.util.Iterator; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; -import java.util.function.Consumer; -public class ListenerManager { +public class ListenerManager implements Iterable { protected final List listeners; public ListenerManager() { @@ -15,17 +17,44 @@ public class ListenerManager { this.listeners = listeners; } - public void forEachListener(Consumer listenerConsumer) { - for(T listener : listeners) { - listenerConsumer.accept(listener); - } - } - public void addListener(T listener) { listeners.add(listener); } public void removeListener(T listener) { listeners.remove(listener); + onRemove(listener); + } + + protected void onRemove(T listener) {} + + @Override + public @NotNull Iterator iterator() { + return new Iterator<>() { + final Iterator backing = listeners.iterator(); + T last; + + @Override + public boolean hasNext() { + return backing.hasNext(); + } + + @Override + public T next() { + last = backing.next(); + return last; + } + + @Override + public void remove() { + backing.remove(); + onRemove(last); + } + }; + } + + @Override + public boolean equals(Object obj) { + return super.equals(obj); } } diff --git a/src/main/resources/data/minions/lang/en_us.json b/src/main/resources/data/minions/lang/en_us.json index 91046a1..ff13896 100644 --- a/src/main/resources/data/minions/lang/en_us.json +++ b/src/main/resources/data/minions/lang/en_us.json @@ -81,6 +81,8 @@ "item.minions.advanced_upgrade_base": "Advanced Upgrade Base", "item.minions.reference": "Reference", + "block.minions.minion_trigger": "Minion Trigger", + "minions.minion_item.tooltip": "Name: %s", "minions.generic.name.invalid_char": "Name contains invalid character", "minions.generic.name.too_long": "Name is too long",