Runtime & MinionTriggerBlock start

This commit is contained in:
skippyall
2025-11-06 22:48:20 +01:00
parent cc1320d5c6
commit b413592abf
40 changed files with 726 additions and 473 deletions
@@ -1,7 +1,12 @@
package io.github.skippyall.minions; package io.github.skippyall.minions;
import eu.pb4.polymer.core.api.item.PolymerBlockItem;
import eu.pb4.polymer.core.api.item.SimplePolymerItem; import eu.pb4.polymer.core.api.item.SimplePolymerItem;
import io.github.skippyall.minions.minion.MinionItem; 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.program.instruction.InstructionType;
import io.github.skippyall.minions.program.instruction.Instructions;
import net.minecraft.component.DataComponentTypes; import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.DamageResistantComponent; import net.minecraft.component.type.DamageResistantComponent;
import net.minecraft.entity.damage.DamageType; import net.minecraft.entity.damage.DamageType;
@@ -14,16 +19,59 @@ import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.tag.TagKey; import net.minecraft.registry.tag.TagKey;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import java.util.List;
import java.util.function.Function; import java.util.function.Function;
import static io.github.skippyall.minions.Minions.MOD_ID; import static io.github.skippyall.minions.Minions.MOD_ID;
public class MinionItems { public class MinionItems {
public static final TagKey<DamageType> MINION_ITEM_RESISTS = TagKey.of(RegistryKeys.DAMAGE_TYPE, Identifier.of(MOD_ID, "minion_item_resists")); public static final TagKey<DamageType> MINION_ITEM_RESISTS = TagKey.of(RegistryKeys.DAMAGE_TYPE, Identifier.of(MOD_ID, "minion_item_resists"));
public static final MinionItem MINION_ITEM = registerItem(Identifier.of(MOD_ID, "minion"), settings -> new MinionItem(settings.component(DataComponentTypes.DAMAGE_RESISTANT, new DamageResistantComponent(MINION_ITEM_RESISTS)))); public static final MinionItem MINION_ITEM = registerItem(
public static final SimplePolymerItem BASIC_UPGRADE_BASE = registerItem(Identifier.of(MOD_ID, "basic_upgrade_base"), settings -> new SimplePolymerItem(settings, Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE)); Identifier.of(MOD_ID, "minion"),
public static final SimplePolymerItem ADVANCED_UPGRADE_BASE = registerItem(Identifier.of(MOD_ID, "advanced_upgrade_base"), settings -> new SimplePolymerItem(settings, Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE)); settings -> new MinionItem(settings.component(DataComponentTypes.DAMAGE_RESISTANT, new DamageResistantComponent(MINION_ITEM_RESISTS)))
);
public static final SimplePolymerItem BASIC_UPGRADE_BASE = registerItem(
Identifier.of(MOD_ID, "basic_upgrade_base"),
settings -> new SimplePolymerItem(settings, Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE)
);
public static final SimplePolymerItem ADVANCED_UPGRADE_BASE = registerItem(
Identifier.of(MOD_ID, "advanced_upgrade_base"),
settings -> new SimplePolymerItem(settings, Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE)
);
public static final SimplePolymerItem MOVE_MODULE = registerModule(
Identifier.of(MOD_ID, "move_module"),
Items.IRON_BOOTS,
List.of(Instructions.WALK, Instructions.TURN)
);
public static final SimplePolymerItem ATTACK_MODULE = registerModule(
Identifier.of(MOD_ID, "attack_module"),
Items.IRON_PICKAXE,
List.of(Instructions.ATTACK)
);
public static final SimplePolymerItem INTERACT_MODULE = registerModule(
Identifier.of(MOD_ID, "interact_module"),
Items.LEVER,
List.of(Instructions.USE)
);
public static final SimplePolymerItem MOB_SPAWNING_MODULE = registerModule(
Identifier.of(MOD_ID, "mob_spawning_module"),
Items.SPAWNER,
List.of(),
List.of("mobSpawning")
);
public static final PolymerBlockItem MINION_TRIGGER_ITEM =
registerItem(
MinionRegistration.MINION_TRIGGER_ID,
settings -> new PolymerBlockItem(MinionRegistration.MINION_TRIGGER_BLOCK, settings, Items.GOLD_BLOCK)
);
public static <T extends Item> T registerItem(Identifier identifier, Function<Item.Settings, T> constructor, Item.Settings settings) { public static <T extends Item> T registerItem(Identifier identifier, Function<Item.Settings, T> constructor, Item.Settings settings) {
T item = constructor.apply(settings.registryKey(RegistryKey.of(RegistryKeys.ITEM, identifier))); T item = constructor.apply(settings.registryKey(RegistryKey.of(RegistryKeys.ITEM, identifier)));
@@ -37,6 +85,23 @@ public class MinionItems {
return registerItem(identifier, constructor, new Item.Settings()); return registerItem(identifier, constructor, new Item.Settings());
} }
public static SimplePolymerItem registerModule(Identifier identifier, Item vanillaItem, List<InstructionType<MinionRuntime>> instructionTypes, List<String> specialEffects) {
return registerItem(
identifier,
settings -> new SimplePolymerItem(settings, vanillaItem),
new Item.Settings().component(MinionModule.COMPONENT_TYPE, new MinionModule(instructionTypes, specialEffects))
);
}
public static SimplePolymerItem registerModule(Identifier identifier, Item vanillaItem, List<InstructionType<MinionRuntime>> instructionTypes) {
return registerModule(
identifier,
vanillaItem,
instructionTypes,
List.of()
);
}
public static void register() { public static void register() {
} }
} }
@@ -0,0 +1,39 @@
package io.github.skippyall.minions;
import eu.pb4.polymer.core.api.block.PolymerBlockUtils;
import io.github.skippyall.minions.block.MinionTriggerBlock;
import io.github.skippyall.minions.block.MinionTriggerBlockEntity;
import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.sound.BlockSoundGroup;
import net.minecraft.util.Identifier;
public class MinionRegistration {
public static final Identifier MINION_TRIGGER_ID = Identifier.of(Minions.MOD_ID, "minion_trigger");
public static final MinionTriggerBlock MINION_TRIGGER_BLOCK = Registry.register(
Registries.BLOCK,
MINION_TRIGGER_ID,
new MinionTriggerBlock(AbstractBlock.Settings.create()
.registryKey(RegistryKey.of(RegistryKeys.BLOCK, MINION_TRIGGER_ID))
.hardness(5)
.strength(5.0F, 6.0F)
.sounds(BlockSoundGroup.IRON)
.requiresTool()
)
);
public static final BlockEntityType<MinionTriggerBlockEntity> MINION_TRIGGER_BE_TYPE =
Registry.register(
Registries.BLOCK_ENTITY_TYPE,
MINION_TRIGGER_ID,
FabricBlockEntityTypeBuilder.create(MinionTriggerBlockEntity::new, MINION_TRIGGER_BLOCK).build()
);
public static void register() {
PolymerBlockUtils.registerBlockEntity(MINION_TRIGGER_BE_TYPE);
}
}
@@ -3,8 +3,9 @@ package io.github.skippyall.minions;
import com.mojang.serialization.Lifecycle; import com.mojang.serialization.Lifecycle;
import io.github.skippyall.minions.minion.MinionRuntime; import io.github.skippyall.minions.minion.MinionRuntime;
import io.github.skippyall.minions.minion.skin.SkinProvider; import io.github.skippyall.minions.minion.skin.SkinProvider;
import io.github.skippyall.minions.program.argument.ArgumentType; import io.github.skippyall.minions.program.supplier.ValueSupplierType;
import io.github.skippyall.minions.program.instruction.InstructionType; import io.github.skippyall.minions.program.instruction.InstructionType;
import io.github.skippyall.minions.program.consumer.ValueConsumerType;
import io.github.skippyall.minions.program.value.ValueType; import io.github.skippyall.minions.program.value.ValueType;
import net.minecraft.registry.Registry; import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey; import net.minecraft.registry.RegistryKey;
@@ -13,7 +14,8 @@ import net.minecraft.util.Identifier;
public class MinionRegistries { public class MinionRegistries {
public static final Registry<ValueType<?>> VALUE_TYPES = registry("value_type"); public static final Registry<ValueType<?>> VALUE_TYPES = registry("value_type");
public static final Registry<ArgumentType<MinionRuntime>> ARGUMENT_TYPE_REGISTRY = registry("argument_type"); public static final Registry<ValueSupplierType<MinionRuntime>> ARGUMENT_TYPES = registry("argument_type");
public static final Registry<ValueConsumerType<MinionRuntime>> VALUE_CONSUMER_TYPES = registry("value_consumer_type");
public static final Registry<InstructionType<MinionRuntime>> INSTRUCTION_TYPES = registry("instruction_type"); public static final Registry<InstructionType<MinionRuntime>> INSTRUCTION_TYPES = registry("instruction_type");
public static final Registry<SkinProvider> SKIN_PROVIDERS = registry("skin_providers"); public static final Registry<SkinProvider> SKIN_PROVIDERS = registry("skin_providers");
@@ -41,6 +41,8 @@ public class Minions implements ModInitializer {
ValueTypes.register(); ValueTypes.register();
SkinProviders.register(); SkinProviders.register();
MinionRegistration.register();
MinionItems.register(); MinionItems.register();
MinionCreativeTab.registerGroup(); MinionCreativeTab.registerGroup();
} }
@@ -0,0 +1,67 @@
package io.github.skippyall.minions.block;
import com.mojang.serialization.MapCodec;
import eu.pb4.polymer.core.api.block.PolymerBlock;
import io.github.skippyall.minions.MinionRegistration;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.BlockWithEntity;
import net.minecraft.block.Blocks;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.state.StateManager;
import net.minecraft.state.property.BooleanProperty;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.block.WireOrientation;
import org.jetbrains.annotations.Nullable;
import xyz.nucleoid.packettweaker.PacketContext;
public class MinionTriggerBlock extends BlockWithEntity implements PolymerBlock {
public static final MapCodec<MinionTriggerBlock> CODEC = createCodec(MinionTriggerBlock::new);
public static final BooleanProperty POWERED = BooleanProperty.of("powered");
public MinionTriggerBlock(Settings settings) {
super(settings);
setDefaultState(getDefaultState().with(POWERED, false));
}
@Override
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
builder.add(POWERED);
}
@Override
protected void neighborUpdate(BlockState state, World world, BlockPos pos, Block sourceBlock, @Nullable WireOrientation wireOrientation, boolean notify) {
boolean newPower = world.isReceivingRedstonePower(pos);
if(state.get(POWERED) != newPower) {
world.setBlockState(pos, state.with(POWERED, newPower));
world.getBlockEntity(pos, MinionRegistration.MINION_TRIGGER_BE_TYPE).ifPresent(MinionTriggerBlockEntity::updatePower);
}
}
@Override
protected boolean hasComparatorOutput(BlockState state) {
return true;
}
@Override
protected int getComparatorOutput(BlockState state, World world, BlockPos pos) {
return world.getBlockEntity(pos, MinionRegistration.MINION_TRIGGER_BE_TYPE).map(MinionTriggerBlockEntity::getComparatorOutput).orElse(0);
}
@Override
protected MapCodec<? extends BlockWithEntity> getCodec() {
return CODEC;
}
@Override
public @Nullable BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
return new MinionTriggerBlockEntity(pos, state);
}
@Override
public BlockState getPolymerBlockState(BlockState state, PacketContext context) {
return state.get(POWERED) ? Blocks.REDSTONE_BLOCK.getDefaultState() : Blocks.GOLD_BLOCK.getDefaultState();
}
}
@@ -0,0 +1,84 @@
package io.github.skippyall.minions.block;
import io.github.skippyall.minions.MinionRegistration;
import io.github.skippyall.minions.minion.MinionRuntime;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.program.instruction.ConfiguredInstruction;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.storage.ReadView;
import net.minecraft.storage.WriteView;
import net.minecraft.util.Uuids;
import net.minecraft.util.math.BlockPos;
import java.util.UUID;
public class MinionTriggerBlockEntity extends BlockEntity {
private UUID minionUuid;
private String instructionName = "";
public MinionTriggerBlockEntity(BlockPos pos, BlockState state) {
super(MinionRegistration.MINION_TRIGGER_BE_TYPE, pos, state);
}
public void updatePower() {
boolean powered = getCachedState().get(MinionTriggerBlock.POWERED);
ConfiguredInstruction<MinionRuntime> instruction = getInstruction();
if(instruction != null) {
if(powered) {
instruction.run(getMinion().getInstructionManager());
} else {
instruction.stop(getMinion().getInstructionManager());
}
}
}
public int getComparatorOutput() {
ConfiguredInstruction<MinionRuntime> instruction = getInstruction();
if(instruction != null && instruction.isRunning()) {
return 15;
}
return 0;
}
public MinionFakePlayer getMinion() {
if(minionUuid != null && world != null && world.getPlayerByUuid(minionUuid) instanceof MinionFakePlayer minion) {
return minion;
}
return null;
}
public ConfiguredInstruction<MinionRuntime> getInstruction() {
MinionFakePlayer minion = getMinion();
if(minion == null) {
return null;
}
return minion.getInstructionManager().getInstruction(instructionName);
}
@Override
public void onBlockReplaced(BlockPos pos, BlockState oldState) {
super.onBlockReplaced(pos, oldState);
}
@Override
public void markRemoved() {
super.markRemoved();
}
@Override
protected void readData(ReadView view) {
minionUuid = view.read("minionUuid", Uuids.CODEC).orElse(null);
instructionName = view.getString("instructionName", "");
}
@Override
protected void writeData(WriteView view) {
if(minionUuid != null) {
view.put("minionUuid", Uuids.CODEC, minionUuid);
}
view.putString("instructionName", instructionName);
}
}
@@ -7,13 +7,11 @@ import io.github.skippyall.minions.input.TextInput;
import io.github.skippyall.minions.minion.MinionRuntime; import io.github.skippyall.minions.minion.MinionRuntime;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.module.MinionModule; import io.github.skippyall.minions.module.MinionModule;
import io.github.skippyall.minions.program.argument.Argument; import io.github.skippyall.minions.program.supplier.ValueSupplier;
import io.github.skippyall.minions.program.argument.GenericArgumentType; import io.github.skippyall.minions.program.supplier.ValueSupplierType;
import io.github.skippyall.minions.program.argument.SpecificArgumentType;
import io.github.skippyall.minions.program.dingenskirchen.SpecificDingenskirchenType;
import io.github.skippyall.minions.program.instruction.ConfiguredInstruction; import io.github.skippyall.minions.program.instruction.ConfiguredInstruction;
import io.github.skippyall.minions.program.instruction.InstructionType; import io.github.skippyall.minions.program.instruction.InstructionType;
import io.github.skippyall.minions.program.argument.Parameter; import io.github.skippyall.minions.program.supplier.Parameter;
import io.github.skippyall.minions.util.TranslationUtil; import io.github.skippyall.minions.util.TranslationUtil;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.Items; import net.minecraft.item.Items;
@@ -45,7 +43,7 @@ public class InstructionGui {
public static void instructionList(MinionFakePlayer minion, ServerPlayerEntity player) { public static void instructionList(MinionFakePlayer minion, ServerPlayerEntity player) {
SimpleGui gui = new SimpleGui(ScreenHandlerType.GENERIC_9X3, player, false); SimpleGui gui = new SimpleGui(ScreenHandlerType.GENERIC_9X3, player, false);
for(String instructionName : minion.getInstructionManager().getInstructionNames()) { for(String instructionName : minion.getInstructionManager().getInstructionNames()) {
ConfiguredInstruction<?> instruction = minion.getInstructionManager().getInstruction(instructionName); ConfiguredInstruction<MinionRuntime> instruction = minion.getInstructionManager().getInstruction(instructionName);
gui.addSlot(instruction.getInstruction().getDisplay().createElement() gui.addSlot(instruction.getInstruction().getDisplay().createElement()
.setName(Text.literal(instructionName)) .setName(Text.literal(instructionName))
.setLore(List.of()) .setLore(List.of())
@@ -58,7 +56,7 @@ public class InstructionGui {
public static void createNewInstruction(MinionFakePlayer minion, ServerPlayerEntity player) { public static void createNewInstruction(MinionFakePlayer minion, ServerPlayerEntity player) {
selectInstructionModuleMenu(minion, player).thenAccept(instructionType -> selectInstructionModuleMenu(minion, player).thenAccept(instructionType ->
TextInput.inputString(player, Text.translatable("minions.gui.instruction.enter_name"), "Instruction").thenAccept(name -> { TextInput.inputString(player, Text.translatable("minions.gui.instruction.enter_name"), "Instruction").thenAccept(name -> {
ConfiguredInstruction<?> configuredInstruction = minion.getInstructionManager().createInstruction(name, instructionType); ConfiguredInstruction<MinionRuntime> configuredInstruction = minion.getInstructionManager().createInstruction(name, instructionType);
configureInstructionMenu(name, configuredInstruction, minion, player); configureInstructionMenu(name, configuredInstruction, minion, player);
}) })
); );
@@ -73,7 +71,7 @@ public class InstructionGui {
return stillExists; return stillExists;
} }
public static void configureInstructionMenu(String name, ConfiguredInstruction<?> instruction, MinionFakePlayer minion, ServerPlayerEntity player) { public static void configureInstructionMenu(String name, ConfiguredInstruction<MinionRuntime> instruction, MinionFakePlayer minion, ServerPlayerEntity player) {
if(!checkInstructionExists(name, instruction, minion, player)) { if(!checkInstructionExists(name, instruction, minion, player)) {
return; return;
} }
@@ -94,12 +92,12 @@ public class InstructionGui {
gui.open(); gui.open();
} }
private static void updateRunSlot(ConfiguredInstruction<?> instruction, MinionFakePlayer minion, SimpleGui gui) { private static void updateRunSlot(ConfiguredInstruction<MinionRuntime> instruction, MinionFakePlayer minion, SimpleGui gui) {
if(!instruction.isRunning()) { if(!instruction.isRunning()) {
gui.setSlot(26, new GuiElementBuilder(Items.ARROW) gui.setSlot(26, new GuiElementBuilder(Items.ARROW)
.setName(Text.literal("Run")) .setName(Text.literal("Run"))
.setCallback(() -> { .setCallback(() -> {
instruction.run(minion); instruction.run(minion.getInstructionManager());
updateRunSlot(instruction, minion, gui); updateRunSlot(instruction, minion, gui);
}) })
); );
@@ -107,14 +105,14 @@ public class InstructionGui {
gui.setSlot(26, new GuiElementBuilder(Items.BARRIER) gui.setSlot(26, new GuiElementBuilder(Items.BARRIER)
.setName(Text.literal("Stop")) .setName(Text.literal("Stop"))
.setCallback(() -> { .setCallback(() -> {
instruction.stop(minion); instruction.stop(minion.getInstructionManager());
updateRunSlot(instruction, minion, gui); updateRunSlot(instruction, minion, gui);
}) })
); );
} }
} }
public static <T, A extends Argument<T, ? extends SpecificDingenskirchenType<T, A, MinionRuntime>, MinionRuntime>> void configureArgumentMenu(String name, ConfiguredInstruction<?> instruction, Parameter<T> parameter, MinionFakePlayer minion, ServerPlayerEntity player) { public static <T, A extends ValueSupplier<T, MinionRuntime>> void configureArgumentMenu(String name, ConfiguredInstruction<MinionRuntime> instruction, Parameter<T> parameter, MinionFakePlayer minion, ServerPlayerEntity player) {
if(!checkInstructionExists(name, instruction, minion, player)) { if(!checkInstructionExists(name, instruction, minion, player)) {
return; return;
} }
@@ -123,9 +121,9 @@ public class InstructionGui {
SimpleGui gui = new SimpleGui(ScreenHandlerType.GENERIC_3X3, player, false); SimpleGui gui = new SimpleGui(ScreenHandlerType.GENERIC_3X3, player, false);
gui.setSlot(3, new GuiElementBuilder(Items.STICK) gui.setSlot(3, new GuiElementBuilder(Items.STICK)
.setName(Text.literal("Type: " + (argument == null ? "Unset" : MinionRegistries.GENERIC_ARGUMENT_TYPE_REGISTRY.getId(argument.getType().getGenericArgumentType()).getPath()))) .setName(Text.literal("Type: " + (argument == null ? "Unset" : MinionRegistries.ARGUMENT_TYPES.getId(argument.getType()).getPath())))
.setCallback(() -> selectArgumentType(player) .setCallback(() -> selectArgumentType(player)
.thenApply(type -> type.<T>createTypeSpecific(parameter.type()).openArgumentDialog(player, null) .thenApply(type -> type.openConfiguration(player, parameter.type(), null)
.thenAccept(newArgument -> { .thenAccept(newArgument -> {
instruction.getArguments().setArgument(parameter, newArgument); instruction.getArguments().setArgument(parameter, newArgument);
configureArgumentMenu(name, instruction, parameter, minion, player); configureArgumentMenu(name, instruction, parameter, minion, player);
@@ -137,7 +135,7 @@ public class InstructionGui {
if(argument != null) { if(argument != null) {
gui.setSlot(5, new GuiElementBuilder(Items.STRUCTURE_VOID) gui.setSlot(5, new GuiElementBuilder(Items.STRUCTURE_VOID)
.setName(Text.literal("Configure")) .setName(Text.literal("Configure"))
.setCallback(() -> argument.getType().openArgumentDialog(player, argument) .setCallback(() -> argument.getType().openConfiguration(player, argument.getValueType(), argument)
.thenAccept(newArgument -> instruction.getArguments().setArgument(parameter, newArgument)) .thenAccept(newArgument -> instruction.getArguments().setArgument(parameter, newArgument))
) )
); );
@@ -145,12 +143,12 @@ public class InstructionGui {
gui.open(); gui.open();
} }
public static CompletableFuture<GenericArgumentType> selectArgumentType(ServerPlayerEntity player) { public static CompletableFuture<ValueSupplierType<MinionRuntime>> selectArgumentType(ServerPlayerEntity player) {
CompletableFuture<GenericArgumentType> future = new CompletableFuture<>(); CompletableFuture<ValueSupplierType<MinionRuntime>> future = new CompletableFuture<>();
SimpleGui gui = new SimpleGui(ScreenHandlerType.GENERIC_9X3, player, false); SimpleGui gui = new SimpleGui(ScreenHandlerType.GENERIC_9X3, player, false);
for(GenericArgumentType type : MinionRegistries.GENERIC_ARGUMENT_TYPE_REGISTRY) { for(ValueSupplierType<MinionRuntime> type : MinionRegistries.ARGUMENT_TYPES) {
gui.addSlot(new GuiElementBuilder() gui.addSlot(new GuiElementBuilder()
.setName(Text.translatable(TranslationUtil.getTranslationKey(type, MinionRegistries.GENERIC_ARGUMENT_TYPE_REGISTRY))) .setName(Text.translatable(TranslationUtil.getTranslationKey(type, MinionRegistries.ARGUMENT_TYPES)))
.setCallback(() -> future.complete(type)) .setCallback(() -> future.complete(type))
); );
} }
@@ -158,13 +156,13 @@ public class InstructionGui {
return future; return future;
} }
public static CompletableFuture<InstructionType<?>> selectInstructionModuleMenu(MinionFakePlayer minion, ServerPlayerEntity player) { public static CompletableFuture<InstructionType<MinionRuntime>> selectInstructionModuleMenu(MinionFakePlayer minion, ServerPlayerEntity player) {
if(minion.getModuleInventory().getModules().isEmpty()) { if(minion.getModuleInventory().getModules().isEmpty()) {
player.sendMessage(Text.literal("This minion has no modules")); player.sendMessage(Text.literal("This minion has no modules"));
return CompletableFuture.failedFuture(new NoSuchElementException("No modules")); return CompletableFuture.failedFuture(new NoSuchElementException("No modules"));
} }
CompletableFuture<InstructionType<?>> future = new CompletableFuture<>(); CompletableFuture<InstructionType<MinionRuntime>> future = new CompletableFuture<>();
SimpleGui gui = new SimpleGui(ScreenHandlerType.GENERIC_9X3, player, false) { SimpleGui gui = new SimpleGui(ScreenHandlerType.GENERIC_9X3, player, false) {
@Override @Override
@@ -190,11 +188,11 @@ public class InstructionGui {
return future; return future;
} }
public static CompletableFuture<InstructionType<?>> selectInstructionMenu(MinionModule module, MinionFakePlayer minion, ServerPlayerEntity player) { public static CompletableFuture<InstructionType<MinionRuntime>> selectInstructionMenu(MinionModule module, MinionFakePlayer minion, ServerPlayerEntity player) {
CompletableFuture<InstructionType<?>> future = new CompletableFuture<>(); CompletableFuture<InstructionType<MinionRuntime>> future = new CompletableFuture<>();
SimpleGui gui = new SimpleGui(ScreenHandlerType.GENERIC_9X3, player, false); SimpleGui gui = new SimpleGui(ScreenHandlerType.GENERIC_9X3, player, false);
for(InstructionType<?> instructionType : module.instructions()) { for(InstructionType<MinionRuntime> instructionType : module.instructions()) {
gui.addSlot(createInstructionElement(instructionType) gui.addSlot(createInstructionElement(instructionType)
.setCallback(() -> future.complete(instructionType)) .setCallback(() -> future.complete(instructionType))
); );
@@ -215,10 +213,10 @@ public class InstructionGui {
return instructionBuilder; return instructionBuilder;
} }
public static GuiElementBuilder createArgumentElement(Argument<?,?> argument) { public static GuiElementBuilder createArgumentElement(ValueSupplier<?,?> valueSupplier) {
GuiElementBuilder argumentBuilder; GuiElementBuilder argumentBuilder;
if(argument != null) { if(valueSupplier != null) {
argumentBuilder = argument.getDisplay().createElement(); argumentBuilder = valueSupplier.getDisplay().createElement();
} else { } else {
argumentBuilder = new GuiElementBuilder(Items.RED_WOOL) argumentBuilder = new GuiElementBuilder(Items.RED_WOOL)
.setName(Text.translatable("minions.gui.instruction.no_argument_set")); .setName(Text.translatable("minions.gui.instruction.no_argument_set"));
@@ -1,79 +0,0 @@
package io.github.skippyall.minions.minion;
import io.github.skippyall.minions.Minions;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.program.instruction.ConfiguredInstruction;
import io.github.skippyall.minions.program.instruction.InstructionType;
import net.minecraft.storage.ReadView;
import net.minecraft.storage.WriteView;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
public class MinionInstructionManager {
private final MinionFakePlayer minion;
private final Map<String, ConfiguredInstruction<?>> configuredInstructions = new HashMap<>();
public MinionInstructionManager(MinionFakePlayer minion) {
this.minion = minion;
}
public void tick() {
for (ConfiguredInstruction<?> instruction : configuredInstructions.values()) {
instruction.tick(minion);
}
}
public Set<String> getInstructionNames() {
return configuredInstructions.keySet();
}
public <T> ConfiguredInstruction<T> createInstruction(String name, InstructionType<T> instructionType) {
ConfiguredInstruction<T> instruction = new ConfiguredInstruction<>(instructionType, name);
configuredInstructions.put(name, instruction);
return instruction;
}
public void removeInstruction(String name) {
ConfiguredInstruction<?> instruction = getInstruction(name);
instruction.stop(minion);
configuredInstructions.remove(name);
}
public ConfiguredInstruction<?> getInstruction(String name) {
return configuredInstructions.get(name);
}
public boolean hasInstruction(String name) {
return configuredInstructions.containsKey(name);
}
public void save(WriteView view) {
WriteView.ListView list = view.getList("configuredInstructions");
for (Map.Entry<String, ConfiguredInstruction<?>> instruction : configuredInstructions.entrySet()) {
WriteView inner = list.add();
inner.putString("name", instruction.getKey());
instruction.getValue().save(inner, minion);
}
}
public void load(ReadView view) {
ReadView.ListReadView list = view.getListReadView("configuredInstructions");
for (ReadView inner : list) {
Optional<String> name = inner.getOptionalString("name");
if(name.isEmpty()) {
Minions.LOGGER.error("Tried deserializing configured instruction without a name of minion \"{}\":", minion.getGameProfile().getName());
continue;
}
try {
ConfiguredInstruction<?> instruction = ConfiguredInstruction.load(inner, minion, name.get());
configuredInstructions.put(name.get(), instruction);
} catch (Exception e) {
Minions.LOGGER.error("Could not deserialize configured instruction \"{}\" of minion \"{}\":", name.get(), minion.getGameProfile().getName(), e);
}
}
}
}
@@ -1,14 +1,103 @@
package io.github.skippyall.minions.minion; package io.github.skippyall.minions.minion;
import io.github.skippyall.minions.MinionRegistries; import io.github.skippyall.minions.MinionRegistries;
import io.github.skippyall.minions.Minions;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.program.InstructionRuntime; import io.github.skippyall.minions.program.InstructionRuntime;
import io.github.skippyall.minions.program.argument.GenericArgumentType; import io.github.skippyall.minions.program.supplier.ValueSupplierType;
import io.github.skippyall.minions.program.instruction.ConfiguredInstruction;
import io.github.skippyall.minions.program.instruction.InstructionType;
import io.github.skippyall.minions.program.consumer.ValueConsumerType;
import net.minecraft.registry.Registry; import net.minecraft.registry.Registry;
import net.minecraft.storage.ReadView;
import net.minecraft.storage.WriteView;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
public class MinionRuntime implements InstructionRuntime<MinionRuntime> { public class MinionRuntime implements InstructionRuntime<MinionRuntime> {
private final MinionFakePlayer minion;
private final Map<String, ConfiguredInstruction<MinionRuntime>> configuredInstructions = new HashMap<>();
public MinionRuntime(MinionFakePlayer minion) {
this.minion = minion;
}
public MinionFakePlayer getMinion() {
return minion;
}
public void tick() {
for (ConfiguredInstruction<MinionRuntime> instruction : configuredInstructions.values()) {
instruction.tick(this);
}
}
public Set<String> getInstructionNames() {
return configuredInstructions.keySet();
}
public ConfiguredInstruction<MinionRuntime> createInstruction(String name, InstructionType<MinionRuntime> instructionType) {
ConfiguredInstruction<MinionRuntime> instruction = new ConfiguredInstruction<>(instructionType, name);
configuredInstructions.put(name, instruction);
return instruction;
}
public void removeInstruction(String name) {
ConfiguredInstruction<MinionRuntime> instruction = getInstruction(name);
instruction.stop(this);
configuredInstructions.remove(name);
}
public ConfiguredInstruction<MinionRuntime> getInstruction(String name) {
return configuredInstructions.get(name);
}
public boolean hasInstruction(String name) {
return configuredInstructions.containsKey(name);
}
public void save(WriteView view) {
WriteView.ListView list = view.getList("configuredInstructions");
for (Map.Entry<String, ConfiguredInstruction<MinionRuntime>> instruction : configuredInstructions.entrySet()) {
WriteView inner = list.add();
inner.putString("name", instruction.getKey());
instruction.getValue().save(inner, this);
}
}
public void load(ReadView view) {
ReadView.ListReadView list = view.getListReadView("configuredInstructions");
for (ReadView inner : list) {
Optional<String> name = inner.getOptionalString("name");
if(name.isEmpty()) {
Minions.LOGGER.error("Tried deserializing configured instruction without a name of minion \"{}\":", minion.getGameProfile().getName());
continue;
}
try {
ConfiguredInstruction<MinionRuntime> instruction = ConfiguredInstruction.load(inner, this, name.get());
configuredInstructions.put(name.get(), instruction);
} catch (Exception e) {
Minions.LOGGER.error("Could not deserialize configured instruction \"{}\" of minion \"{}\":", name.get(), minion.getGameProfile().getName(), e);
}
}
}
@Override @Override
public Registry<GenericArgumentType<MinionRuntime>> getGenericArgumentTypeRegistry() { public Registry<ValueSupplierType<MinionRuntime>> getArgumentTypeRegistry() {
return MinionRegistries.GENERIC_ARGUMENT_TYPE_REGISTRY; return MinionRegistries.ARGUMENT_TYPES;
}
@Override
public Registry<InstructionType<MinionRuntime>> getInstructionTypeRegistry() {
return MinionRegistries.INSTRUCTION_TYPES;
}
@Override
public Registry<ValueConsumerType<MinionRuntime>> getValueConsumerTypeRegistry() {
return MinionRegistries.VALUE_CONSUMER_TYPES;
} }
} }
@@ -6,7 +6,7 @@ import com.mojang.authlib.properties.PropertyMap;
import io.github.skippyall.minions.MinionItems; import io.github.skippyall.minions.MinionItems;
import io.github.skippyall.minions.minion.MinionData; import io.github.skippyall.minions.minion.MinionData;
import io.github.skippyall.minions.gui.MinionGui; import io.github.skippyall.minions.gui.MinionGui;
import io.github.skippyall.minions.minion.MinionInstructionManager; import io.github.skippyall.minions.minion.MinionRuntime;
import io.github.skippyall.minions.minion.MinionItem; import io.github.skippyall.minions.minion.MinionItem;
import io.github.skippyall.minions.minion.MinionPersistentState; import io.github.skippyall.minions.minion.MinionPersistentState;
import io.github.skippyall.minions.minion.MinionProfileUtils; import io.github.skippyall.minions.minion.MinionProfileUtils;
@@ -51,11 +51,8 @@ public class MinionFakePlayer extends ServerPlayerEntity {
private EntityPlayerActionPack actionPack; private EntityPlayerActionPack actionPack;
private float moveForward;
private float moveSideways;
private final ModuleInventory moduleInventory = new ModuleInventory(); private final ModuleInventory moduleInventory = new ModuleInventory();
private final MinionInstructionManager instructionManager = new MinionInstructionManager(this); private final MinionRuntime instructionManager = new MinionRuntime(this);
private final MinionData data; private final MinionData data;
@@ -118,7 +115,7 @@ public class MinionFakePlayer extends ServerPlayerEntity {
return actionPack; return actionPack;
} }
public MinionInstructionManager getInstructionManager() { public MinionRuntime getInstructionManager() {
return instructionManager; return instructionManager;
} }
@@ -127,11 +124,11 @@ public class MinionFakePlayer extends ServerPlayerEntity {
} }
public boolean canSpawnMobs() { public boolean canSpawnMobs() {
return true; return moduleInventory.hasAbility("mobSpawning");
} }
public boolean canDespawnMobs() { public boolean canDespawnMobs() {
return true; return moduleInventory.hasAbility("mobSpawning");
} }
@Override @Override
@@ -249,44 +246,6 @@ public class MinionFakePlayer extends ServerPlayerEntity {
return networkHandler.player; return networkHandler.player;
} }
/*public void moveForward(float forward) {
this.moveForward += forward;
EntityPlayerActionPack actionPack = getMinionActionPack();
if (moveForward != 0) {
actionPack.setForward(moveForward > 0 ? 1 : -1);
}
}
public void moveSideways(float sideways) {
this.moveSideways += sideways;
EntityPlayerActionPack actionPack = getMinionActionPack();
if (moveSideways != 0) {
actionPack.setStrafing(moveSideways > 0 ? 1 : -1);
}
}
@Override
public void move(MovementType movementType, Vec3d movement) {
float newForward = (float) (moveForward - movement.z);
float newSideways = (float) (moveSideways - movement.x);
Vec3d newMovement = movement;
if ((newForward < 0 && moveForward > 0) || (newForward > 0 && moveForward < 0)) {
newMovement = new Vec3d(newMovement.x, newMovement.y, moveForward);
moveForward = 0;
getMinionActionPack().setForward(0);
}else {
moveForward = newForward;
}
if ((newSideways < 0 && moveSideways > 0) || (newSideways > 0 && moveSideways < 0)) {
newMovement = new Vec3d(newMovement.x, newMovement.y, moveSideways);
moveSideways = 0;
getMinionActionPack().setStrafing(0);
}else {
moveSideways = newSideways;
}
super.move(movementType, newMovement);
}*/
@Override @Override
public void drop(ServerWorld world, DamageSource damageSource) { public void drop(ServerWorld world, DamageSource damageSource) {
super.drop(world, damageSource); super.drop(world, damageSource);
@@ -8,7 +8,6 @@ import com.llamalad7.mixinextras.sugar.Local;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.minion.fakeplayer.NetHandlerPlayServerFake; import io.github.skippyall.minions.minion.fakeplayer.NetHandlerPlayServerFake;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.network.ClientConnection; import net.minecraft.network.ClientConnection;
import net.minecraft.network.packet.c2s.common.SyncedClientOptions; import net.minecraft.network.packet.c2s.common.SyncedClientOptions;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
@@ -5,6 +5,7 @@ import com.mojang.serialization.codecs.RecordCodecBuilder;
import eu.pb4.polymer.core.api.other.PolymerComponent; import eu.pb4.polymer.core.api.other.PolymerComponent;
import io.github.skippyall.minions.MinionRegistries; import io.github.skippyall.minions.MinionRegistries;
import io.github.skippyall.minions.Minions; import io.github.skippyall.minions.Minions;
import io.github.skippyall.minions.minion.MinionRuntime;
import io.github.skippyall.minions.program.instruction.InstructionType; import io.github.skippyall.minions.program.instruction.InstructionType;
import net.minecraft.component.ComponentType; import net.minecraft.component.ComponentType;
import net.minecraft.registry.Registries; import net.minecraft.registry.Registries;
@@ -13,10 +14,11 @@ import net.minecraft.util.Identifier;
import java.util.List; import java.util.List;
public record MinionModule(List<InstructionType<?>> instructions) { public record MinionModule(List<InstructionType<MinionRuntime>> instructions, List<String> specialBehaviour) {
public static final Codec<MinionModule> CODEC = RecordCodecBuilder.create(instance -> public static final Codec<MinionModule> CODEC = RecordCodecBuilder.create(instance ->
instance.group( instance.group(
MinionRegistries.INSTRUCTION_TYPES.getCodec().listOf().fieldOf("instructions").forGetter(MinionModule::instructions) MinionRegistries.INSTRUCTION_TYPES.getCodec().listOf().fieldOf("instructions").forGetter(MinionModule::instructions),
Codec.STRING.listOf().fieldOf("specialBehaviour").forGetter(MinionModule::specialBehaviour)
).apply(instance, MinionModule::new) ).apply(instance, MinionModule::new)
); );
@@ -24,8 +26,13 @@ public record MinionModule(List<InstructionType<?>> instructions) {
public static final MinionModule EMPTY = new MinionModule(List.of()); public static final MinionModule EMPTY = new MinionModule(List.of());
public MinionModule(List<InstructionType<?>> instructions) { public MinionModule(List<InstructionType<MinionRuntime>> instructions) {
this(instructions, List.of());
}
public MinionModule(List<InstructionType<MinionRuntime>> instructions, List<String> specialBehaviour) {
this.instructions = List.copyOf(instructions); this.instructions = List.copyOf(instructions);
this.specialBehaviour = List.copyOf(specialBehaviour);
} }
public static void register() { public static void register() {
@@ -19,6 +19,8 @@ import java.util.Set;
public class ModuleInventory extends SimpleInventory { public class ModuleInventory extends SimpleInventory {
private final Set<MinionModule> modules = new HashSet<>(); private final Set<MinionModule> modules = new HashSet<>();
private final Set<String> specialAbilities = new HashSet<>();
public ModuleInventory() { public ModuleInventory() {
super(27); super(27);
} }
@@ -45,10 +47,12 @@ public class ModuleInventory extends SimpleInventory {
public void updateModules() { public void updateModules() {
modules.clear(); modules.clear();
specialAbilities.clear();
for (ItemStack heldStack : heldStacks) { for (ItemStack heldStack : heldStacks) {
MinionModule module = heldStack.get(MinionModule.COMPONENT_TYPE); MinionModule module = heldStack.get(MinionModule.COMPONENT_TYPE);
if(module != null) { if(module != null) {
modules.add(module); modules.add(module);
specialAbilities.addAll(module.specialBehaviour());
} }
} }
} }
@@ -62,14 +66,14 @@ public class ModuleInventory extends SimpleInventory {
Inventories.writeData(view, heldStacks); Inventories.writeData(view, heldStacks);
} }
public boolean hasModule(MinionModule module) {
return modules.contains(module);
}
public Collection<MinionModule> getModules() { public Collection<MinionModule> getModules() {
return modules; return modules;
} }
public boolean hasAbility(String ability) {
return specialAbilities.contains(ability);
}
public List<InstructionType<?>> getAllInstructions() { public List<InstructionType<?>> getAllInstructions() {
ArrayList<InstructionType<?>> instructionTypes = new ArrayList<>(); ArrayList<InstructionType<?>> instructionTypes = new ArrayList<>();
for(MinionModule module : modules) { for(MinionModule module : modules) {
@@ -11,6 +11,7 @@ import net.minecraft.screen.slot.Slot;
public class ModuleInventoryScreenHandler extends ScreenHandler { public class ModuleInventoryScreenHandler extends ScreenHandler {
private final int rows = 3; private final int rows = 3;
private final ModuleInventory inventory; private final ModuleInventory inventory;
public ModuleInventoryScreenHandler(int syncId, ModuleInventory inventory) { public ModuleInventoryScreenHandler(int syncId, ModuleInventory inventory) {
super(ScreenHandlerType.GENERIC_9X3, syncId); super(ScreenHandlerType.GENERIC_9X3, syncId);
this.inventory = inventory; this.inventory = inventory;
@@ -18,14 +19,13 @@ public class ModuleInventoryScreenHandler extends ScreenHandler {
public ModuleInventoryScreenHandler(int syncId, PlayerInventory playerInventory, ModuleInventory inventory) { public ModuleInventoryScreenHandler(int syncId, PlayerInventory playerInventory, ModuleInventory inventory) {
super(ScreenHandlerType.GENERIC_9X3, syncId); super(ScreenHandlerType.GENERIC_9X3, syncId);
int k;
int j;
GenericContainerScreenHandler.checkSize(inventory, 3 * 9); GenericContainerScreenHandler.checkSize(inventory, 3 * 9);
this.inventory = inventory; this.inventory = inventory;
inventory.onOpen(playerInventory.player); inventory.onOpen(playerInventory.player);
int i = (rows - 4) * 18;
for (j = 0; j < rows; ++j) { for (int j = 0; j < rows; ++j) {
for (k = 0; k < 9; ++k) { for (int k = 0; k < 9; ++k) {
this.addSlot(new Slot(inventory, k + j * 9, 8 + k * 18, 18 + j * 18) { this.addSlot(new Slot(inventory, k + j * 9, 8 + k * 18, 18 + j * 18) {
@Override @Override
public boolean canInsert(ItemStack stack) { public boolean canInsert(ItemStack stack) {
@@ -34,14 +34,8 @@ public class ModuleInventoryScreenHandler extends ScreenHandler {
}); });
} }
} }
for (j = 0; j < 3; ++j) {
for (k = 0; k < 9; ++k) { addPlayerSlots(playerInventory, 8, 85);
this.addSlot(new Slot(playerInventory, k + j * 9 + 9, 8 + k * 18, 103 + j * 18 + i));
}
}
for (j = 0; j < 9; ++j) {
this.addSlot(new Slot(playerInventory, j, 8 + j * 18, 161 + i));
}
} }
@Override @Override
@@ -1,30 +1,43 @@
package io.github.skippyall.minions.program; package io.github.skippyall.minions.program;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import io.github.skippyall.minions.program.argument.Argument; import io.github.skippyall.minions.program.supplier.ValueSupplier;
import io.github.skippyall.minions.program.argument.ArgumentList; import io.github.skippyall.minions.program.supplier.ValueSupplierList;
import io.github.skippyall.minions.program.argument.ArgumentType; import io.github.skippyall.minions.program.supplier.ValueSupplierType;
import io.github.skippyall.minions.program.argument.Arguments;
import io.github.skippyall.minions.program.instruction.InstructionType; import io.github.skippyall.minions.program.instruction.InstructionType;
import io.github.skippyall.minions.program.returnvalue.ValueConsumerType; import io.github.skippyall.minions.program.consumer.ValueConsumer;
import io.github.skippyall.minions.program.consumer.ValueConsumerList;
import io.github.skippyall.minions.program.consumer.ValueConsumerType;
import net.minecraft.registry.Registry; import net.minecraft.registry.Registry;
public interface InstructionRuntime<R extends InstructionRuntime<R>> { public interface InstructionRuntime<R extends InstructionRuntime<R>> {
Registry<ArgumentType<R>> getArgumentTypeRegistry(); Registry<ValueSupplierType<R>> getArgumentTypeRegistry();
Registry<InstructionType<R>> getInstructionTypeRegistry(); Registry<InstructionType<R>> getInstructionTypeRegistry();
Registry<ValueConsumerType<R>> getValueConsumerRegistry(); Registry<ValueConsumerType<R>> getValueConsumerTypeRegistry();
default Codec<ArgumentType<R>> getArgumentTypeCodec() { default Codec<ValueSupplierType<R>> getArgumentTypeCodec() {
return getArgumentTypeRegistry().getCodec(); return getArgumentTypeRegistry().getCodec();
} }
default Codec<Argument<?,R>> getArgumentCodec() { default Codec<ValueSupplier<?,R>> getArgumentCodec() {
return Arguments.createArgumentCodec(getArgumentTypeCodec()); return ValueSupplier.createArgumentCodec(getArgumentTypeCodec());
} }
default Codec<ArgumentList<R>> getArgumentListCodec() { default Codec<ValueSupplierList<R>> getArgumentListCodec() {
return ArgumentList.getCodec(getArgumentTypeCodec()); return ValueSupplierList.getCodec(getArgumentCodec());
}
default Codec<ValueConsumerType<R>> getValueConsumerTypeCodec() {
return getValueConsumerTypeRegistry().getCodec();
}
default Codec<ValueConsumer<?,R>> getValueConsumerCodec() {
return ValueConsumer.createValueConsumerCodec(getValueConsumerTypeCodec());
}
default Codec<ValueConsumerList<R>> getValueConsumerListCodec() {
return ValueConsumerList.getCodec(getValueConsumerCodec());
} }
} }
@@ -1,31 +0,0 @@
package io.github.skippyall.minions.program.argument;
import io.github.skippyall.minions.gui.GuiDisplay;
import io.github.skippyall.minions.program.InstructionRuntime;
import io.github.skippyall.minions.program.value.ValueType;
import org.jetbrains.annotations.Nullable;
/**
* An <code>Argument</code> can be supplied to an instruction with a matching parameter.
* Its value is resolved at runtime and can vary between executions.
* <code>Argument</code>s are created exclusively by <code>SpecificArgumentType</code>s.
* @param <T> The type of the <code>Argument</code>'s value
*/
public interface Argument<T, R extends InstructionRuntime<R>> {
T resolve(R minion);
GuiDisplay getDisplay();
ValueType<T> getValueType();
ArgumentType<R> getType();
default <U,A extends Argument<U,R>> @Nullable A cast(ValueType<U> type) {
if(getValueType() == type) {
//noinspection unchecked
return (A) this;
} else {
return null;
}
}
}
@@ -1,52 +0,0 @@
package io.github.skippyall.minions.program.argument;
import com.mojang.serialization.Codec;
import io.github.skippyall.minions.program.InstructionRuntime;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class ArgumentList<R extends InstructionRuntime<R>> {
private final Map<String, Argument<?, R>> arguments;
public ArgumentList() {
arguments = new HashMap<>();
}
public ArgumentList(Map<String, Argument<?,R>> arguments) {
this.arguments = new HashMap<>(arguments);
}
public <T> T getValue(Parameter<T> parameter, R runtime) {
Argument<T,R> argument = getArgument(parameter);
return argument != null ? argument.resolve(runtime) : null;
}
public <T, A extends Argument<T,R>> A getArgument(Parameter<T> parameter) {
Argument<?,R> argument = arguments.get(parameter.name());
return argument == null ? null : argument.cast(parameter.type());
}
public <T> void setArgument(Parameter<T> parameter, Argument<T,R> argument) {
arguments.put(parameter.name(), argument);
}
public boolean hasArgumentFor(Parameter<?> parameter) {
return getArgument(parameter) != null;
}
public boolean hasArgumentForAll(Collection<Parameter<?>> checkParameters) {
for(Parameter<?> parameter : checkParameters) {
if(!hasArgumentFor(parameter)) {
return false;
}
}
return true;
}
public static <R extends InstructionRuntime<R>> Codec<ArgumentList<R>> getCodec(Codec<ArgumentType<R>> genericCodec) {
return Codec.unboundedMap(Codec.STRING, Arguments.createArgumentCodec(genericCodec))
.xmap(ArgumentList::new, list -> list.arguments);
}
}
@@ -1,15 +0,0 @@
package io.github.skippyall.minions.program.argument;
import com.mojang.serialization.Codec;
import io.github.skippyall.minions.program.InstructionRuntime;
import io.github.skippyall.minions.program.value.ValueType;
import net.minecraft.server.network.ServerPlayerEntity;
import org.jetbrains.annotations.Nullable;
import java.util.concurrent.CompletableFuture;
public abstract class ArgumentType<R extends InstructionRuntime<R>> {
public abstract <T> Codec<? extends Argument<T,R>> getCodec(ValueType<T> type);
public abstract <T> CompletableFuture<? extends Argument<T,R>> openConfiguration(ServerPlayerEntity player, ValueType<T> valueType, @Nullable Argument<T,R> previous);
}
@@ -1,19 +0,0 @@
package io.github.skippyall.minions.program.argument;
import com.mojang.serialization.Codec;
import io.github.skippyall.minions.MinionRegistries;
import io.github.skippyall.minions.program.InstructionRuntime;
public class Arguments {
public static <R extends InstructionRuntime<R>> Codec<Argument<?,R>> createArgumentCodec(Codec<ArgumentType<R>> codec) {
return codec.dispatch(
"type",
Argument::getType,
type ->
MinionRegistries.VALUE_TYPES.getCodec().<Argument<?,R>>dispatch(
Argument::getValueType,
valueType -> type.getCodec(valueType).fieldOf("valueType")
).fieldOf("valueType")
);
}
}
@@ -0,0 +1,45 @@
package io.github.skippyall.minions.program.consumer;
import com.mojang.serialization.Codec;
import io.github.skippyall.minions.MinionRegistries;
import io.github.skippyall.minions.gui.GuiDisplay;
import io.github.skippyall.minions.program.InstructionRuntime;
import io.github.skippyall.minions.program.value.ValueType;
import org.jetbrains.annotations.Nullable;
/**
* An <code>ValueSupplier</code> can be supplied to an instruction with a matching parameter.
* Its value is resolved at runtime and can vary between executions.
* <code>ValueSupplier</code>s are created exclusively by <code>SpecificArgumentType</code>s.
* @param <T> The type of the <code>ValueSupplier</code>'s value
*/
public interface ValueConsumer<T,R extends InstructionRuntime<R>> {
void consume(T value, R runtime);
GuiDisplay getDisplay();
ValueType<T> getValueType();
ValueConsumerType<R> getType();
default <U,A extends ValueConsumer<U,R>> @Nullable A cast(ValueType<U> type) {
if(getValueType() == type) {
//noinspection unchecked
return (A) this;
} else {
return null;
}
}
static <R extends InstructionRuntime<R>> Codec<ValueConsumer<?,R>> createValueConsumerCodec(Codec<ValueConsumerType<R>> codec) {
return codec.dispatch(
"type",
ValueConsumer::getType,
type ->
MinionRegistries.VALUE_TYPES.getCodec().<ValueConsumer<?,R>>dispatch(
ValueConsumer::getValueType,
valueType -> type.getCodec(valueType).fieldOf("valueType")
).fieldOf("valueType")
);
}
}
@@ -1,8 +1,8 @@
package io.github.skippyall.minions.program.returnvalue; package io.github.skippyall.minions.program.consumer;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import io.github.skippyall.minions.program.InstructionRuntime; import io.github.skippyall.minions.program.InstructionRuntime;
import io.github.skippyall.minions.program.argument.Parameter; import io.github.skippyall.minions.program.supplier.Parameter;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@@ -27,8 +27,15 @@ public class ValueConsumerList<R extends InstructionRuntime<R>> {
valueConsumers.put(parameter.name(), consumer); valueConsumers.put(parameter.name(), consumer);
} }
public static <R extends InstructionRuntime<R>> Codec<ValueConsumerList<R>> getCodec(Codec<ValueConsumerType<R>> genericCodec) { public <T> void setValue(Parameter<T> parameter, T value, R runtime) {
return Codec.unboundedMap(Codec.STRING, ValueConsumers.createValueConsumersCodec(genericCodec)) ValueConsumer<T,R> consumer = getValueConsumer(parameter).cast(parameter.type());
if (consumer != null) {
consumer.consume(value, runtime);
}
}
public static <R extends InstructionRuntime<R>> Codec<ValueConsumerList<R>> getCodec(Codec<ValueConsumer<?,R>> valueConsumerCodec) {
return Codec.unboundedMap(Codec.STRING, valueConsumerCodec)
.xmap(ValueConsumerList::new, list -> list.valueConsumers); .xmap(ValueConsumerList::new, list -> list.valueConsumers);
} }
} }
@@ -1,8 +1,7 @@
package io.github.skippyall.minions.program.returnvalue; package io.github.skippyall.minions.program.consumer;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import io.github.skippyall.minions.program.InstructionRuntime; import io.github.skippyall.minions.program.InstructionRuntime;
import io.github.skippyall.minions.program.argument.Argument;
import io.github.skippyall.minions.program.value.ValueType; import io.github.skippyall.minions.program.value.ValueType;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -2,33 +2,36 @@ package io.github.skippyall.minions.program.instruction;
import io.github.skippyall.minions.Minions; import io.github.skippyall.minions.Minions;
import io.github.skippyall.minions.program.InstructionRuntime; import io.github.skippyall.minions.program.InstructionRuntime;
import io.github.skippyall.minions.program.argument.ArgumentList; import io.github.skippyall.minions.program.supplier.ValueSupplierList;
import io.github.skippyall.minions.program.consumer.ValueConsumerList;
import net.minecraft.storage.ReadView; import net.minecraft.storage.ReadView;
import net.minecraft.storage.WriteView; import net.minecraft.storage.WriteView;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
public class ConfiguredInstruction<R extends InstructionRuntime<R>> { public class ConfiguredInstruction<R extends InstructionRuntime<R>> {
private final InstructionType<R> instruction; private final InstructionType<R> instruction;
private final ArgumentList<R> arguments; private final ValueSupplierList<R> arguments;
private final ValueConsumerList<R> valueConsumers;
private @Nullable InstructionExecution<R> execution; private @Nullable InstructionExecution<R> execution;
private final String name; private final String name;
private ConfiguredInstruction(InstructionType<R> instruction, ArgumentList<R> arguments, @Nullable InstructionExecution<R> execution, String name) { private ConfiguredInstruction(InstructionType<R> instruction, ValueSupplierList<R> arguments, ValueConsumerList<R> valueConsumers, @Nullable InstructionExecution<R> execution, String name) {
this.instruction = instruction; this.instruction = instruction;
this.arguments = arguments; this.arguments = arguments;
this.valueConsumers = valueConsumers;
this.execution = execution; this.execution = execution;
this.name = name; this.name = name;
} }
public ConfiguredInstruction(InstructionType<R> instruction, String name) { public ConfiguredInstruction(InstructionType<R> instruction, String name) {
this(instruction, new ArgumentList<>(), null, name); this(instruction, new ValueSupplierList<>(), new ValueConsumerList<>(), null, name);
} }
public InstructionType<R> getInstruction() { public InstructionType<R> getInstruction() {
return instruction; return instruction;
} }
public ArgumentList<R> getArguments() { public ValueSupplierList<R> getArguments() {
return arguments; return arguments;
} }
@@ -75,7 +78,7 @@ public class ConfiguredInstruction<R extends InstructionRuntime<R>> {
public void stop(R minion) { public void stop(R minion) {
if(isRunning()) { if(isRunning()) {
execution.stop(minion); execution.stop(minion, valueConsumers);
execution = null; execution = null;
} }
} }
@@ -83,6 +86,7 @@ public class ConfiguredInstruction<R extends InstructionRuntime<R>> {
public void save(WriteView view, R minion) { public void save(WriteView view, R minion) {
view.put("instruction", minion.getInstructionTypeRegistry().getCodec(), instruction); view.put("instruction", minion.getInstructionTypeRegistry().getCodec(), instruction);
view.put("arguments", minion.getArgumentListCodec(), arguments); view.put("arguments", minion.getArgumentListCodec(), arguments);
view.put("valueConsumers", minion.getValueConsumerListCodec(), valueConsumers);
view.putBoolean("running", isRunning()); view.putBoolean("running", isRunning());
if(isRunning()) { if(isRunning()) {
execution.save(view.get("execution"), minion); execution.save(view.get("execution"), minion);
@@ -92,7 +96,8 @@ public class ConfiguredInstruction<R extends InstructionRuntime<R>> {
public static <R extends InstructionRuntime<R>> ConfiguredInstruction<R> load(ReadView view, R minion, String name) { public static <R extends InstructionRuntime<R>> ConfiguredInstruction<R> load(ReadView view, R minion, String name) {
InstructionType<R> instructionType = view.read("instruction", minion.getInstructionTypeRegistry().getCodec()).orElseThrow(); InstructionType<R> instructionType = view.read("instruction", minion.getInstructionTypeRegistry().getCodec()).orElseThrow();
ArgumentList<R> arguments = view.read("arguments", minion.getArgumentListCodec()).orElseThrow(); ValueSupplierList<R> arguments = view.read("arguments", minion.getArgumentListCodec()).orElseGet(ValueSupplierList::new);
ValueConsumerList<R> valueConsumers = view.read("valueConsumers", minion.getValueConsumerListCodec()).orElseGet(ValueConsumerList::new);
boolean running = view.getBoolean("running", false); boolean running = view.getBoolean("running", false);
@@ -100,12 +105,12 @@ public class ConfiguredInstruction<R extends InstructionRuntime<R>> {
ReadView executionView = view.getReadView("execution"); ReadView executionView = view.getReadView("execution");
try { try {
InstructionExecution<R> execution = instructionType.loadExecution(executionView, minion); InstructionExecution<R> execution = instructionType.loadExecution(executionView, minion);
return new ConfiguredInstruction<>(instructionType, arguments, execution, name); return new ConfiguredInstruction<>(instructionType, arguments, valueConsumers, execution, name);
} catch (Exception e) { } catch (Exception e) {
Minions.LOGGER.error("Error while loading execution", e);
} }
} }
return new ConfiguredInstruction<>(instructionType, arguments, null, name); return new ConfiguredInstruction<>(instructionType, arguments, valueConsumers, null, name);
} }
} }
@@ -1,7 +1,8 @@
package io.github.skippyall.minions.program.instruction; package io.github.skippyall.minions.program.instruction;
import io.github.skippyall.minions.program.InstructionRuntime; import io.github.skippyall.minions.program.InstructionRuntime;
import io.github.skippyall.minions.program.argument.ArgumentList; import io.github.skippyall.minions.program.supplier.ValueSupplierList;
import io.github.skippyall.minions.program.consumer.ValueConsumerList;
import net.minecraft.storage.ReadView; import net.minecraft.storage.ReadView;
import net.minecraft.storage.WriteView; import net.minecraft.storage.WriteView;
@@ -9,7 +10,7 @@ import net.minecraft.storage.WriteView;
* Responsible for executing instructions. * Responsible for executing instructions.
* When an instruction is executed: * When an instruction is executed:
* <li>A new instance is created using the factory</li> * <li>A new instance is created using the factory</li>
* <li>{@link InstructionExecution#readArguments(ArgumentList, R) readFromParameters} is called</li> * <li>{@link InstructionExecution#readArguments(ValueSupplierList, R) readFromParameters} is called</li>
* <li>{@link InstructionExecution#start(R) start} is called</li> * <li>{@link InstructionExecution#start(R) start} is called</li>
*/ */
public interface InstructionExecution<R extends InstructionRuntime<R>> { public interface InstructionExecution<R extends InstructionRuntime<R>> {
@@ -32,19 +33,18 @@ public interface InstructionExecution<R extends InstructionRuntime<R>> {
/** /**
* Stops this execution. Is called when isDone returns true, but it may also be called before that. * Stops this execution. Is called when isDone returns true, but it may also be called before that.
* In this case, the return value is ignored.
* This should undo changes to the minion unless they are supposed to be permanent. * This should undo changes to the minion unless they are supposed to be permanent.
* *
* @param runtime The runtime that was executing this instruction. * @param runtime The runtime that was executing this instruction.
*/ */
void stop(R runtime); void stop(R runtime, ValueConsumerList<R> valueConsumers);
/** /**
* Initializes the execution with its arguments. * Initializes the execution with its parameters. The parameters must be defined by the InstructionType
* @param arguments The arguments to initialize the execution * @param arguments The arguments to initialize the execution
* @param runtime The runtime should be used to resolve the arguments * @param runtime The runtime should be used to resolve the arguments
*/ */
void readArguments(ArgumentList<R> arguments, R runtime); void readArguments(ValueSupplierList<R> arguments, R runtime);
/** /**
* Saves the execution, e.g. when the server is closed. * Saves the execution, e.g. when the server is closed.
@@ -2,9 +2,8 @@ package io.github.skippyall.minions.program.instruction;
import io.github.skippyall.minions.gui.GuiDisplay; import io.github.skippyall.minions.gui.GuiDisplay;
import io.github.skippyall.minions.program.InstructionRuntime; import io.github.skippyall.minions.program.InstructionRuntime;
import io.github.skippyall.minions.program.argument.Parameter; import io.github.skippyall.minions.program.supplier.Parameter;
import io.github.skippyall.minions.program.argument.ArgumentList; import io.github.skippyall.minions.program.supplier.ValueSupplierList;
import io.github.skippyall.minions.program.value.ValueType;
import net.minecraft.storage.ReadView; import net.minecraft.storage.ReadView;
import java.util.Collection; import java.util.Collection;
@@ -14,31 +13,29 @@ import java.util.function.Supplier;
public class InstructionType<R extends InstructionRuntime<R>> { public class InstructionType<R extends InstructionRuntime<R>> {
private final GuiDisplay display; private final GuiDisplay display;
private final Collection<Parameter<?>> parameters; private final Collection<Parameter<?>> parameters;
private final Collection<Parameter<?>> returnParameters;
private final Supplier<InstructionExecution<R>> executionFactory; private final Supplier<InstructionExecution<R>> executionFactory;
private InstructionType(GuiDisplay display, Supplier<InstructionExecution<R>> executionFactory, Collection<Parameter<?>> parameters) { public InstructionType(GuiDisplay display, Supplier<InstructionExecution<R>> executionFactory, Collection<Parameter<?>> parameters, Collection<Parameter<?>> returnParameters) {
this.display = display; this.display = display;
this.parameters = parameters; this.parameters = List.copyOf(parameters);
this.returnParameters = List.copyOf(returnParameters);
this.executionFactory = executionFactory; this.executionFactory = executionFactory;
} }
public static <R extends InstructionRuntime<R>> InstructionType<R> create(GuiDisplay display, Supplier<InstructionExecution<R>> executionFactory, Collection<Parameter<?>> parameters) {
return new InstructionType<>(display, executionFactory, List.copyOf(parameters));
}
public static <Return,R extends InstructionRuntime<R>> InstructionType<R> create(GuiDisplay display, Supplier<InstructionExecution<R>> executionFactory, ValueType<Return> returnType, Parameter<?>... parameters) {
return new InstructionType<>(display, executionFactory, List.of(parameters));
}
public Collection<Parameter<?>> getParameters() { public Collection<Parameter<?>> getParameters() {
return parameters; return parameters;
} }
public Collection<Parameter<?>> getReturnParameters() {
return returnParameters;
}
public GuiDisplay getDisplay() { public GuiDisplay getDisplay() {
return display; return display;
} }
public InstructionExecution<R> createExecution(ArgumentList<R> parameters, R minion) { public InstructionExecution<R> createExecution(ValueSupplierList<R> parameters, R minion) {
InstructionExecution<R> execution = executionFactory.get(); InstructionExecution<R> execution = executionFactory.get();
execution.readArguments(parameters, minion); execution.readArguments(parameters, minion);
return execution; return execution;
@@ -3,47 +3,60 @@ package io.github.skippyall.minions.program.instruction;
import io.github.skippyall.minions.MinionRegistries; import io.github.skippyall.minions.MinionRegistries;
import io.github.skippyall.minions.Minions; import io.github.skippyall.minions.Minions;
import io.github.skippyall.minions.gui.GuiDisplay; import io.github.skippyall.minions.gui.GuiDisplay;
import io.github.skippyall.minions.minion.MinionRuntime;
import io.github.skippyall.minions.minion.fakeplayer.EntityPlayerActionPack; import io.github.skippyall.minions.minion.fakeplayer.EntityPlayerActionPack;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.program.instruction.execution.ActionExecution; import io.github.skippyall.minions.program.instruction.execution.ActionExecution;
import io.github.skippyall.minions.program.instruction.execution.TurnExecution;
import io.github.skippyall.minions.program.instruction.execution.WalkExecution; import io.github.skippyall.minions.program.instruction.execution.WalkExecution;
import io.github.skippyall.minions.program.argument.Parameter; import io.github.skippyall.minions.program.supplier.Parameter;
import io.github.skippyall.minions.program.value.ValueType;
import io.github.skippyall.minions.program.value.ValueTypes;
import io.github.skippyall.minions.util.ModelIdUtil; import io.github.skippyall.minions.util.ModelIdUtil;
import net.minecraft.item.Items; import net.minecraft.item.Items;
import net.minecraft.registry.Registry; import net.minecraft.registry.Registry;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import java.util.Collection;
import java.util.List;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
public class Instructions { public class Instructions {
public static final InstructionType<Void, MinionFakePlayer> WALK = register( public static final InstructionType<MinionRuntime> WALK = register(
"walk", "walk",
base -> new GuiDisplay.ModelBased(ModelIdUtil.getItemModelId(Items.IRON_BOOTS), base, true), base -> new GuiDisplay.ModelBased(ModelIdUtil.getItemModelId(Items.IRON_BOOTS), base, true),
WalkExecution::new, WalkExecution::new,
ValueTypes.VOID, List.of(WalkExecution.blocksToMoveParam)
WalkExecution.blocksToMoveParam
); );
public static final InstructionType<Void, MinionFakePlayer> ATTACK = register( public static final InstructionType<MinionRuntime> TURN = register(
"turn",
base -> new GuiDisplay.ModelBased(Items.STRUCTURE_VOID, base, true),
TurnExecution::new,
List.of(TurnExecution.ANGLE, TurnExecution.DIRECTION)
);
public static final InstructionType<MinionRuntime> ATTACK = register(
"attack", "attack",
base -> new GuiDisplay.ModelBased(ModelIdUtil.getItemModelId(Items.IRON_BOOTS), base, true), base -> new GuiDisplay.ModelBased(ModelIdUtil.getItemModelId(Items.IRON_BOOTS), base, true),
() -> new ActionExecution(EntityPlayerActionPack.ActionType.ATTACK), () -> new ActionExecution(EntityPlayerActionPack.ActionType.ATTACK)
ValueTypes.VOID
); );
public static final InstructionType<Void, MinionFakePlayer> USE = register( public static final InstructionType<MinionRuntime> USE = register(
"use", "use",
base -> new GuiDisplay.ModelBased(ModelIdUtil.getItemModelId(Items.LEVER), base, true), base -> new GuiDisplay.ModelBased(ModelIdUtil.getItemModelId(Items.LEVER), base, true),
() -> new ActionExecution(EntityPlayerActionPack.ActionType.USE), () -> new ActionExecution(EntityPlayerActionPack.ActionType.USE)
ValueTypes.VOID
); );
private static <R> InstructionType<R, MinionFakePlayer> register(String id, Function<String, GuiDisplay> displayFunction, Supplier<InstructionExecution<R,MinionFakePlayer>> factory, ValueType<R> returnType, Parameter<?>... parameters) { private static InstructionType<MinionRuntime> register(String id, Function<String, GuiDisplay> displayFunction, Supplier<InstructionExecution<MinionRuntime>> factory, Collection<Parameter<?>> parameters, Collection<Parameter<?>> returnParameters) {
Identifier identifier = Identifier.of(Minions.MOD_ID, id); Identifier identifier = Identifier.of(Minions.MOD_ID, id);
return Registry.register(MinionRegistries.INSTRUCTION_TYPES, identifier, InstructionType.create(displayFunction.apply(identifier.toTranslationKey("instruction_type")), factory, returnType, parameters)); return Registry.register(MinionRegistries.INSTRUCTION_TYPES, identifier, new InstructionType<>(displayFunction.apply(identifier.toTranslationKey("instruction_type")), factory, parameters, returnParameters));
}
private static InstructionType<MinionRuntime> register(String id, Function<String, GuiDisplay> displayFunction, Supplier<InstructionExecution<MinionRuntime>> factory, Collection<Parameter<?>> parameters) {
return register(id, displayFunction, factory, parameters, List.of());
}
private static InstructionType<MinionRuntime> register(String id, Function<String, GuiDisplay> displayFunction, Supplier<InstructionExecution<MinionRuntime>> factory) {
return register(id, displayFunction, factory, List.of(), List.of());
} }
public static void register() { public static void register() {
@@ -1,12 +1,13 @@
package io.github.skippyall.minions.program.instruction.execution; package io.github.skippyall.minions.program.instruction.execution;
import io.github.skippyall.minions.minion.MinionRuntime;
import io.github.skippyall.minions.minion.fakeplayer.EntityPlayerActionPack; import io.github.skippyall.minions.minion.fakeplayer.EntityPlayerActionPack;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import io.github.skippyall.minions.program.consumer.ValueConsumerList;
import io.github.skippyall.minions.program.argument.ArgumentList; import io.github.skippyall.minions.program.supplier.ValueSupplierList;
import net.minecraft.storage.ReadView; import net.minecraft.storage.ReadView;
import net.minecraft.storage.WriteView; import net.minecraft.storage.WriteView;
public class ActionExecution implements ContinuousInstructionExecution { public class ActionExecution implements ContinuousInstructionExecution<MinionRuntime> {
private final EntityPlayerActionPack.ActionType action; private final EntityPlayerActionPack.ActionType action;
public ActionExecution(EntityPlayerActionPack.ActionType action) { public ActionExecution(EntityPlayerActionPack.ActionType action) {
@@ -14,24 +15,23 @@ public class ActionExecution implements ContinuousInstructionExecution {
} }
@Override @Override
public void start(MinionFakePlayer minion) { public void start(MinionRuntime minion) {
minion.getMinionActionPack().start(action, EntityPlayerActionPack.Action.continuous()); minion.getMinion().getMinionActionPack().start(action, EntityPlayerActionPack.Action.continuous());
} }
@Override @Override
public Void stop(MinionFakePlayer minion) { public void stop(MinionRuntime minion, ValueConsumerList<MinionRuntime> valueConsumers) {
minion.getMinionActionPack().stop(action); minion.getMinion().getMinionActionPack().stop(action);
return null;
} }
@Override @Override
public void readArguments(ArgumentList parameters, MinionFakePlayer minion) {} public void readArguments(ValueSupplierList<MinionRuntime> parameters, MinionRuntime minion) {}
@Override @Override
public void save(WriteView view, MinionFakePlayer minion) {} public void save(WriteView view, MinionRuntime minion) {}
@Override @Override
public void load(ReadView view, MinionFakePlayer minion) { public void load(ReadView view, MinionRuntime minion) {
minion.getMinionActionPack().start(action, EntityPlayerActionPack.Action.continuous()); minion.getMinion().getMinionActionPack().start(action, EntityPlayerActionPack.Action.continuous());
} }
} }
@@ -1,11 +1,11 @@
package io.github.skippyall.minions.program.instruction.execution; package io.github.skippyall.minions.program.instruction.execution;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import io.github.skippyall.minions.program.InstructionRuntime;
import io.github.skippyall.minions.program.instruction.InstructionExecution; import io.github.skippyall.minions.program.instruction.InstructionExecution;
public interface ContinuousInstructionExecution extends InstructionExecution<Void,MinionFakePlayer> { public interface ContinuousInstructionExecution<R extends InstructionRuntime<R>> extends InstructionExecution<R> {
@Override @Override
default boolean isDone(MinionFakePlayer minion) { default boolean isDone(R minion) {
return false; return false;
} }
} }
@@ -1,6 +1,6 @@
package io.github.skippyall.minions.program.instruction.execution; package io.github.skippyall.minions.program.instruction.execution;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import io.github.skippyall.minions.program.InstructionRuntime;
import io.github.skippyall.minions.program.instruction.InstructionExecution; import io.github.skippyall.minions.program.instruction.InstructionExecution;
import net.minecraft.storage.ReadView; import net.minecraft.storage.ReadView;
import net.minecraft.storage.WriteView; import net.minecraft.storage.WriteView;
@@ -10,7 +10,7 @@ import net.minecraft.storage.WriteView;
* The timer must be set with <code>setTimer</code> when reading from parameters. * The timer must be set with <code>setTimer</code> when reading from parameters.
* Saving and loading of the timer is automatic if the super method is called by the subclass. * Saving and loading of the timer is automatic if the super method is called by the subclass.
*/ */
public abstract class TimedInstructionExecution<T> implements InstructionExecution<T,MinionFakePlayer> { public abstract class TimedInstructionExecution<R extends InstructionRuntime<R>> implements InstructionExecution<R> {
int timer; int timer;
public int getTimer() { public int getTimer() {
@@ -22,22 +22,22 @@ public abstract class TimedInstructionExecution<T> implements InstructionExecuti
} }
@Override @Override
public void tick(MinionFakePlayer minion) { public void tick(R minion) {
timer--; timer--;
} }
@Override @Override
public boolean isDone(MinionFakePlayer minion) { public boolean isDone(R minion) {
return timer > 0; return timer > 0;
} }
@Override @Override
public void save(WriteView view, MinionFakePlayer minion) { public void save(WriteView view, R minion) {
view.putInt("timer", timer); view.putInt("timer", timer);
} }
@Override @Override
public void load(ReadView view, MinionFakePlayer minion) { public void load(ReadView view, R minion) {
timer = view.getInt("timer", 0); timer = view.getInt("timer", 0);
} }
} }
@@ -3,9 +3,10 @@ package io.github.skippyall.minions.program.instruction.execution;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import io.github.skippyall.minions.gui.Displayable; import io.github.skippyall.minions.gui.Displayable;
import io.github.skippyall.minions.gui.GuiDisplay; import io.github.skippyall.minions.gui.GuiDisplay;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import io.github.skippyall.minions.minion.MinionRuntime;
import io.github.skippyall.minions.program.argument.ArgumentList; import io.github.skippyall.minions.program.consumer.ValueConsumerList;
import io.github.skippyall.minions.program.argument.Parameter; import io.github.skippyall.minions.program.supplier.ValueSupplierList;
import io.github.skippyall.minions.program.supplier.Parameter;
import io.github.skippyall.minions.program.instruction.InstructionExecution; import io.github.skippyall.minions.program.instruction.InstructionExecution;
import io.github.skippyall.minions.program.value.ValueTypes; import io.github.skippyall.minions.program.value.ValueTypes;
import net.minecraft.storage.ReadView; import net.minecraft.storage.ReadView;
@@ -14,7 +15,7 @@ import net.minecraft.util.StringIdentifiable;
import java.util.UUID; import java.util.UUID;
public class TurnExecution implements InstructionExecution<Void,MinionFakePlayer> { public class TurnExecution implements InstructionExecution<MinionRuntime> {
public static final Parameter<Float> ANGLE = new Parameter<>("maxAngle", ValueTypes.FLOAT); public static final Parameter<Float> ANGLE = new Parameter<>("maxAngle", ValueTypes.FLOAT);
public static final Parameter<TurnDirection> DIRECTION = new Parameter<>("direction", ValueTypes.TURN_DIRECTION); public static final Parameter<TurnDirection> DIRECTION = new Parameter<>("direction", ValueTypes.TURN_DIRECTION);
@@ -25,37 +26,36 @@ public class TurnExecution implements InstructionExecution<Void,MinionFakePlayer
private TurnDirection direction; private TurnDirection direction;
@Override @Override
public void tick(MinionFakePlayer minion) { public void tick(MinionRuntime minion) {
float toRotate = Math.min(anglePerTick, maxAngle - rotatedAngle); float toRotate = Math.min(anglePerTick, maxAngle - rotatedAngle);
minion.getMinionActionPack().turn(direction.xFactor * toRotate, direction.yFactor * toRotate); minion.getMinion().getMinionActionPack().turn(direction.xFactor * toRotate, direction.yFactor * toRotate);
rotatedAngle += toRotate; rotatedAngle += toRotate;
} }
@Override @Override
public boolean isDone(MinionFakePlayer minion) { public boolean isDone(MinionRuntime minion) {
return Math.abs(maxAngle - rotatedAngle) < 0.001F; return Math.abs(maxAngle - rotatedAngle) < 0.001F;
} }
@Override @Override
public Void stop(MinionFakePlayer minion) { public void stop(MinionRuntime minion, ValueConsumerList<MinionRuntime> valueConsumers) {
return null;
} }
@Override @Override
public void readArguments(ArgumentList<MinionFakePlayer> arguments, MinionFakePlayer minion) { public void readArguments(ValueSupplierList<MinionRuntime> arguments, MinionRuntime minion) {
maxAngle = arguments.getValue(ANGLE, minion); maxAngle = arguments.getValue(ANGLE, minion);
direction = arguments.getValue(DIRECTION, minion); direction = arguments.getValue(DIRECTION, minion);
} }
@Override @Override
public void save(WriteView view, MinionFakePlayer minion) { public void save(WriteView view, MinionRuntime minion) {
view.putFloat("maxAngle", maxAngle); view.putFloat("maxAngle", maxAngle);
view.put("direction", TurnDirection.CODEC, direction); view.put("direction", TurnDirection.CODEC, direction);
} }
@Override @Override
public void load(ReadView view, MinionFakePlayer minion) { public void load(ReadView view, MinionRuntime minion) {
maxAngle = view.getFloat("maxAngle", 0); maxAngle = view.getFloat("maxAngle", 0);
direction = view.read("direction", TurnDirection.CODEC).orElseThrow(); direction = view.read("direction", TurnDirection.CODEC).orElseThrow();
} }
@@ -1,52 +1,53 @@
package io.github.skippyall.minions.program.instruction.execution; package io.github.skippyall.minions.program.instruction.execution;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import io.github.skippyall.minions.minion.MinionRuntime;
import io.github.skippyall.minions.program.consumer.ValueConsumerList;
import io.github.skippyall.minions.program.instruction.InstructionExecution; import io.github.skippyall.minions.program.instruction.InstructionExecution;
import io.github.skippyall.minions.program.argument.Parameter; import io.github.skippyall.minions.program.supplier.Parameter;
import io.github.skippyall.minions.program.argument.ArgumentList; import io.github.skippyall.minions.program.supplier.ValueSupplierList;
import io.github.skippyall.minions.program.value.ValueTypes; import io.github.skippyall.minions.program.value.ValueTypes;
import net.minecraft.entity.MovementType; import net.minecraft.entity.MovementType;
import net.minecraft.storage.ReadView; import net.minecraft.storage.ReadView;
import net.minecraft.storage.WriteView; import net.minecraft.storage.WriteView;
public class WalkExecution implements InstructionExecution<Void,MinionFakePlayer> { public class WalkExecution implements InstructionExecution<MinionRuntime> {
public static final Parameter<Float> blocksToMoveParam = new Parameter<>("blocksToMove", ValueTypes.FLOAT); public static final Parameter<Float> blocksToMoveParam = new Parameter<>("blocksToMove", ValueTypes.FLOAT);
private final float ACCURACY = 1F / 32F; private static final float ACCURACY = 1F / 32F;
private float totalBlocksToMove; private float totalBlocksToMove;
private float blocksMoved; private float blocksMoved;
@Override @Override
public void tick(MinionFakePlayer minion) { public void tick(MinionRuntime minion) {
float speed = Math.min(minion.getMovementSpeed(), totalBlocksToMove - blocksMoved); float speed = Math.min(minion.getMinion().getMovementSpeed(), totalBlocksToMove - blocksMoved);
minion.move(MovementType.SELF, minion.getHorizontalFacing().getDoubleVector().normalize().multiply(speed)); minion.getMinion().move(MovementType.SELF, minion.getMinion().getHorizontalFacing().getDoubleVector().normalize().multiply(speed));
blocksMoved += speed; blocksMoved += speed;
} }
@Override @Override
public boolean isDone(MinionFakePlayer minion) { public boolean isDone(MinionRuntime minion) {
return totalBlocksToMove - blocksMoved < ACCURACY; return totalBlocksToMove - blocksMoved < ACCURACY;
} }
@Override @Override
public Void stop(MinionFakePlayer minion) { public void stop(MinionRuntime minion, ValueConsumerList<MinionRuntime> valueConsumers) {
return null;
} }
@Override @Override
public void readArguments(ArgumentList<MinionFakePlayer> parameters, MinionFakePlayer minion) { public void readArguments(ValueSupplierList<MinionRuntime> parameters, MinionRuntime minion) {
totalBlocksToMove = parameters.getValue(blocksToMoveParam, minion); totalBlocksToMove = parameters.getValue(blocksToMoveParam, minion);
blocksMoved = 0; blocksMoved = 0;
} }
@Override @Override
public void save(WriteView view, MinionFakePlayer minion) { public void save(WriteView view, MinionRuntime minion) {
view.putFloat("totalBlocksToMove", totalBlocksToMove); view.putFloat("totalBlocksToMove", totalBlocksToMove);
view.putFloat("blocksMoved", blocksMoved); view.putFloat("blocksMoved", blocksMoved);
} }
@Override @Override
public void load(ReadView view, MinionFakePlayer minion) { public void load(ReadView view, MinionRuntime minion) {
totalBlocksToMove = view.getFloat("totalBlocksToMove", 0F); totalBlocksToMove = view.getFloat("totalBlocksToMove", 0F);
blocksMoved = view.getFloat("blocksMoved", 0F); blocksMoved = view.getFloat("blocksMoved", 0F);
} }
@@ -1,32 +0,0 @@
package io.github.skippyall.minions.program.returnvalue;
import io.github.skippyall.minions.gui.GuiDisplay;
import io.github.skippyall.minions.program.InstructionRuntime;
import io.github.skippyall.minions.program.argument.ArgumentType;
import io.github.skippyall.minions.program.value.ValueType;
import org.jetbrains.annotations.Nullable;
/**
* An <code>Argument</code> can be supplied to an instruction with a matching parameter.
* Its value is resolved at runtime and can vary between executions.
* <code>Argument</code>s are created exclusively by <code>SpecificArgumentType</code>s.
* @param <T> The type of the <code>Argument</code>'s value
*/
public interface ValueConsumer<T,R extends InstructionRuntime<R>> {
void consume(T value, R runtime);
GuiDisplay getDisplay();
ValueType<T> getValueType();
ValueConsumerType<R> getType();
default <U,A extends ValueConsumer<U,R>> @Nullable A cast(ValueType<U> type) {
if(getValueType() == type) {
//noinspection unchecked
return (A) this;
} else {
return null;
}
}
}
@@ -1,24 +0,0 @@
package io.github.skippyall.minions.program.returnvalue;
import com.mojang.serialization.Codec;
import io.github.skippyall.minions.MinionRegistries;
import io.github.skippyall.minions.Minions;
import io.github.skippyall.minions.minion.MinionRuntime;
import io.github.skippyall.minions.program.InstructionRuntime;
import io.github.skippyall.minions.program.argument.Argument;
import net.minecraft.registry.Registry;
import net.minecraft.util.Identifier;
public class ValueConsumers {
public static <R extends InstructionRuntime<R>> Codec<ValueConsumer<?,R>> createValueConsumersCodec(Codec<ValueConsumerType<R>> codec) {
return codec.dispatch(
"type",
ValueConsumer::getType,
type ->
MinionRegistries.VALUE_TYPES.getCodec().<ValueConsumer<?,R>>dispatch(
ValueConsumer::getValueType,
valueType -> type.getCodec(valueType).fieldOf("valueType")
).fieldOf("valueType")
);
}
}
@@ -1,4 +1,4 @@
package io.github.skippyall.minions.program.argument; package io.github.skippyall.minions.program.supplier;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder; import com.mojang.serialization.codecs.RecordCodecBuilder;
@@ -1,14 +1,13 @@
package io.github.skippyall.minions.program.argument; package io.github.skippyall.minions.program.supplier;
import io.github.skippyall.minions.gui.GuiDisplay; import io.github.skippyall.minions.gui.GuiDisplay;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.program.InstructionRuntime; import io.github.skippyall.minions.program.InstructionRuntime;
import io.github.skippyall.minions.program.value.ValueType; import io.github.skippyall.minions.program.value.ValueType;
/** /**
* An argument that always resolves to a fixed value * An supplier that always resolves to a fixed value
*/ */
public class ValueArgument<T, R extends InstructionRuntime<R>> implements Argument<T, R> { public class ValueArgument<T, R extends InstructionRuntime<R>> implements ValueSupplier<T, R> {
private final ValueArgumentType<R> type; private final ValueArgumentType<R> type;
private final ValueType<T> valueType; private final ValueType<T> valueType;
private final T value; private final T value;
@@ -1,4 +1,4 @@
package io.github.skippyall.minions.program.argument; package io.github.skippyall.minions.program.supplier;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import io.github.skippyall.minions.program.InstructionRuntime; import io.github.skippyall.minions.program.InstructionRuntime;
@@ -8,17 +8,17 @@ import org.jetbrains.annotations.Nullable;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public class ValueArgumentType<R extends InstructionRuntime<R>> extends ArgumentType<R> { public class ValueArgumentType<R extends InstructionRuntime<R>> extends ValueSupplierType<R> {
@Override @Override
public <T> Codec<ValueArgument<T,R>> getCodec(ValueType<T> valueType) { public <T> Codec<ValueArgument<T,R>> getCodec(ValueType<T> valueType) {
return valueType.codec().xmap(value -> new ValueArgument<>(this, valueType, value), ValueArgument::getValue); return valueType.codec().xmap(value -> new ValueArgument<>(this, valueType, value), ValueArgument::getValue);
} }
@Override @Override
public <V> CompletableFuture<ValueArgument<V,R>> openConfiguration(ServerPlayerEntity player, ValueType<V> valueType, @Nullable Argument<V,R> previousArgument) { public <V> CompletableFuture<ValueArgument<V,R>> openConfiguration(ServerPlayerEntity player, ValueType<V> valueType, @Nullable ValueSupplier<V,R> previousValueSupplier) {
return valueType.openValueDialog( return valueType.openValueDialog(
player, player,
previousArgument instanceof ValueArgument<V,R> val ? val.getValue() : valueType.defaultValue() previousValueSupplier instanceof ValueArgument<V,R> val ? val.getValue() : valueType.defaultValue()
).thenApply(value -> new ValueArgument<>(this, valueType, value)); ).thenApply(value -> new ValueArgument<>(this, valueType, value));
} }
} }
@@ -0,0 +1,45 @@
package io.github.skippyall.minions.program.supplier;
import com.mojang.serialization.Codec;
import io.github.skippyall.minions.MinionRegistries;
import io.github.skippyall.minions.gui.GuiDisplay;
import io.github.skippyall.minions.program.InstructionRuntime;
import io.github.skippyall.minions.program.value.ValueType;
import org.jetbrains.annotations.Nullable;
/**
* An <code>ValueSupplier</code> can be supplied to an instruction with a matching parameter.
* Its value is resolved at runtime and can vary between executions.
* <code>ValueSupplier</code>s are created exclusively by <code>SpecificArgumentType</code>s.
* @param <T> The type of the <code>ValueSupplier</code>'s value
*/
public interface ValueSupplier<T, R extends InstructionRuntime<R>> {
T resolve(R minion);
GuiDisplay getDisplay();
ValueType<T> getValueType();
ValueSupplierType<R> getType();
default <U,A extends ValueSupplier<U,R>> @Nullable A cast(ValueType<U> type) {
if(getValueType() == type) {
//noinspection unchecked
return (A) this;
} else {
return null;
}
}
static <R extends InstructionRuntime<R>> Codec<ValueSupplier<?,R>> createArgumentCodec(Codec<ValueSupplierType<R>> codec) {
return codec.dispatch(
"type",
ValueSupplier::getType,
type ->
MinionRegistries.VALUE_TYPES.getCodec().<ValueSupplier<?,R>>dispatch(
ValueSupplier::getValueType,
valueType -> type.getCodec(valueType).fieldOf("valueType")
).fieldOf("valueType")
);
}
}
@@ -0,0 +1,52 @@
package io.github.skippyall.minions.program.supplier;
import com.mojang.serialization.Codec;
import io.github.skippyall.minions.program.InstructionRuntime;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class ValueSupplierList<R extends InstructionRuntime<R>> {
private final Map<String, ValueSupplier<?, R>> arguments;
public ValueSupplierList() {
arguments = new HashMap<>();
}
public ValueSupplierList(Map<String, ValueSupplier<?,R>> arguments) {
this.arguments = new HashMap<>(arguments);
}
public <T> T getValue(Parameter<T> parameter, R runtime) {
ValueSupplier<T,R> valueSupplier = getArgument(parameter);
return valueSupplier != null ? valueSupplier.resolve(runtime) : null;
}
public <T, A extends ValueSupplier<T,R>> A getArgument(Parameter<T> parameter) {
ValueSupplier<?,R> valueSupplier = arguments.get(parameter.name());
return valueSupplier == null ? null : valueSupplier.cast(parameter.type());
}
public <T> void setArgument(Parameter<T> parameter, ValueSupplier<T,R> valueSupplier) {
arguments.put(parameter.name(), valueSupplier);
}
public boolean hasArgumentFor(Parameter<?> parameter) {
return getArgument(parameter) != null;
}
public boolean hasArgumentForAll(Collection<Parameter<?>> checkParameters) {
for(Parameter<?> parameter : checkParameters) {
if(!hasArgumentFor(parameter)) {
return false;
}
}
return true;
}
public static <R extends InstructionRuntime<R>> Codec<ValueSupplierList<R>> getCodec(Codec<ValueSupplier<?,R>> argumentCodec) {
return Codec.unboundedMap(Codec.STRING, argumentCodec)
.xmap(ValueSupplierList::new, list -> list.arguments);
}
}
@@ -0,0 +1,15 @@
package io.github.skippyall.minions.program.supplier;
import com.mojang.serialization.Codec;
import io.github.skippyall.minions.program.InstructionRuntime;
import io.github.skippyall.minions.program.value.ValueType;
import net.minecraft.server.network.ServerPlayerEntity;
import org.jetbrains.annotations.Nullable;
import java.util.concurrent.CompletableFuture;
public abstract class ValueSupplierType<R extends InstructionRuntime<R>> {
public abstract <T> Codec<? extends ValueSupplier<T,R>> getCodec(ValueType<T> type);
public abstract <T> CompletableFuture<? extends ValueSupplier<T,R>> openConfiguration(ServerPlayerEntity player, ValueType<T> valueType, @Nullable ValueSupplier<T,R> previous);
}
@@ -0,0 +1,5 @@
{
"values": [
"minions:minion_trigger"
]
}