Redo everything

This commit is contained in:
skippyall
2025-09-12 00:59:57 +02:00
parent e27b1698e4
commit b6f7bfc57b
84 changed files with 980 additions and 1188 deletions
@@ -2,7 +2,6 @@ package io.github.skippyall.minions;
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.module.Modules;
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;
@@ -39,6 +38,5 @@ public class MinionItems {
} }
public static void register() { public static void register() {
Modules.register();
} }
} }
@@ -0,0 +1,22 @@
package io.github.skippyall.minions;
import com.mojang.serialization.Lifecycle;
import io.github.skippyall.minions.minion.skin.SkinProvider;
import io.github.skippyall.minions.new_program.argument.GenericArgumentType;
import io.github.skippyall.minions.new_program.instruction.InstructionType;
import io.github.skippyall.minions.new_program.value.ValueType;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.SimpleRegistry;
import net.minecraft.util.Identifier;
public class MinionRegistries {
public static final Registry<ValueType<?>> VALUE_TYPES = registry("value_type");
public static final Registry<GenericArgumentType> GENERIC_ARGUMENT_TYPE_REGISTRY = registry("generic_argument_type");
public static final Registry<InstructionType<?>> INSTRUCTION_TYPES = registry("instruction_type");
public static final Registry<SkinProvider> SKIN_PROVIDERS = registry("skin_providers");
private static <T> Registry<T> registry(String id) {
return new SimpleRegistry<>(RegistryKey.ofRegistry(Identifier.of(Minions.MOD_ID, id)), Lifecycle.stable());
}
}
@@ -5,12 +5,19 @@ import io.github.skippyall.minions.command.MinionsCommand;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.minion.MinionData; import io.github.skippyall.minions.minion.MinionData;
import io.github.skippyall.minions.minion.MinionPersistentState; import io.github.skippyall.minions.minion.MinionPersistentState;
import io.github.skippyall.minions.minion.skin.SkinProviders;
import io.github.skippyall.minions.mixins.PlayerListEntryS2CPacket$EntryMixin; import io.github.skippyall.minions.mixins.PlayerListEntryS2CPacket$EntryMixin;
import io.github.skippyall.minions.new_module.MinionModule;
import io.github.skippyall.minions.new_module.ModuleLoader;
import io.github.skippyall.minions.new_program.instruction.Instructions;
import io.github.skippyall.minions.new_program.value.ValueTypes;
import net.fabricmc.api.ModInitializer; import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.resource.ResourceType;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -21,10 +28,12 @@ public class Minions implements ModInitializer {
@Override @Override
public void onInitialize() { public void onInitialize() {
Instructions.register();
MinionData.register(); MinionData.register();
PolymerEntityUtils.registerType(); MinionModule.register();
ServerLifecycleEvents.SERVER_STARTED.register(server -> { ServerLifecycleEvents.SERVER_STARTED.register(server -> {
LOGGER.error("Initializing Minion data");
MinionPersistentState.create(server); MinionPersistentState.create(server);
MinionPersistentState.INSTANCE.getMinionData().forEach((uuid, data) -> { MinionPersistentState.INSTANCE.getMinionData().forEach((uuid, data) -> {
if(data.isSpawned()) { if(data.isSpawned()) {
@@ -32,14 +41,16 @@ public class Minions implements ModInitializer {
} }
}); });
}); });
PlayerEntity
ClientPlayNetworkHandler
CommandRegistrationCallback.EVENT.register((commandDispatcher, commandRegistryAccess, registrationEnvironment) -> { CommandRegistrationCallback.EVENT.register((commandDispatcher, commandRegistryAccess, registrationEnvironment) -> {
MinionsCommand.register(commandDispatcher); MinionsCommand.register(commandDispatcher);
}); });
ValueTypes.register();
SkinProviders.register();
MinionItems.register(); MinionItems.register();
MinionCreativeTab.registerGroup(); MinionCreativeTab.registerGroup();
ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener(new ModuleLoader());
} }
} }
@@ -1,20 +1,8 @@
package io.github.skippyall.minions.gui; 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.module.command.Command;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.module.ModuleItem;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import java.util.Collection;
import java.util.List;
public class CommandsGui { public class CommandsGui {
public static void openServerModuleCommandGui(ServerPlayerEntity player, MinionFakePlayer minion) { /*public static void openServerModuleCommandGui(ServerPlayerEntity player, MinionFakePlayer minion) {
Collection<ModuleItem> modules = minion.getModuleInventory().getModuleItems(); Collection<ModuleItem> modules = minion.getModuleInventory().getModules();
SimpleGui gui = new SimpleGui(ScreenHandlerType.GENERIC_9X3, player, false); SimpleGui gui = new SimpleGui(ScreenHandlerType.GENERIC_9X3, player, false);
@@ -48,5 +36,5 @@ public class CommandsGui {
} }
commandGui.open(); commandGui.open();
} }*/
} }
@@ -0,0 +1,5 @@
package io.github.skippyall.minions.gui;
public interface Displayable {
GuiDisplay getDisplay();
}
@@ -0,0 +1,36 @@
package io.github.skippyall.minions.gui;
import eu.pb4.sgui.api.elements.GuiElementBuilder;
import io.github.skippyall.minions.util.ModelIdUtil;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.LoreComponent;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
public interface GuiDisplay {
default GuiElementBuilder createElement() {
return new GuiElementBuilder(createItemStack());
}
ItemStack createItemStack();
record ModelBased(Identifier model, String translationKeyBase, boolean withLore) implements GuiDisplay {
public ModelBased(Item model, String translationKeyBase, boolean withLore) {
this(ModelIdUtil.getItemModelId(model), translationKeyBase, withLore);
}
@Override
public ItemStack createItemStack() {
ItemStack stack = new ItemStack(Items.BARRIER);
stack.set(DataComponentTypes.ITEM_MODEL, model);
stack.set(DataComponentTypes.ITEM_NAME, Text.translatable(translationKeyBase + ".name"));
if(withLore) {
stack.set(DataComponentTypes.LORE, LoreComponent.DEFAULT.with(Text.translatable(translationKeyBase + ".description")));
}
return stack;
}
}
}
@@ -22,7 +22,7 @@ public class MinionGui {
.setItem(Items.COMMAND_BLOCK) .setItem(Items.COMMAND_BLOCK)
.setName(Text.translatable("minions.gui.main.commands")) .setName(Text.translatable("minions.gui.main.commands"))
.setCallback((i, clickType, slotActionType) -> { .setCallback((i, clickType, slotActionType) -> {
openCommandsGui(player, minion); InstructionGui.openInstructionMainMenu(minion, player);
}) })
); );
gui.setSlot(3, new GuiElementBuilder() gui.setSlot(3, new GuiElementBuilder()
@@ -50,7 +50,7 @@ public class MinionGui {
} }
public static void openCommandsGui(ServerPlayerEntity player, MinionFakePlayer minion) { public static void openCommandsGui(ServerPlayerEntity player, MinionFakePlayer minion) {
CommandsGui.openServerModuleCommandGui(player, minion); //CommandsGui.openServerModuleCommandGui(player, minion);
} }
public static void openProgrammingInventory(ServerPlayerEntity player, MinionFakePlayer minion) { public static void openProgrammingInventory(ServerPlayerEntity player, MinionFakePlayer minion) {
@@ -2,6 +2,7 @@ package io.github.skippyall.minions.gui;
import eu.pb4.sgui.api.elements.GuiElementBuilder; import eu.pb4.sgui.api.elements.GuiElementBuilder;
import eu.pb4.sgui.api.gui.SimpleGui; import eu.pb4.sgui.api.gui.SimpleGui;
import io.github.skippyall.minions.MinionRegistries;
import io.github.skippyall.minions.input.TextInput; import io.github.skippyall.minions.input.TextInput;
import io.github.skippyall.minions.minion.MinionData; import io.github.skippyall.minions.minion.MinionData;
import io.github.skippyall.minions.minion.MinionItem; import io.github.skippyall.minions.minion.MinionItem;
@@ -57,13 +58,13 @@ public class MinionLookGui extends SimpleGui {
} }
private void cycleSkinProvider() { private void cycleSkinProvider() {
int currentId = SkinProviders.SKIN_PROVIDERS.getRawId(currentSkinProvider); int currentId = MinionRegistries.SKIN_PROVIDERS.getRawId(currentSkinProvider);
currentId++; currentId++;
if(SkinProviders.SKIN_PROVIDERS.size() == currentId) { if(MinionRegistries.SKIN_PROVIDERS.size() == currentId) {
currentId = 0; currentId = 0;
} }
currentSkinProvider = SkinProviders.SKIN_PROVIDERS.get(currentId); currentSkinProvider = MinionRegistries.SKIN_PROVIDERS.get(currentId);
updateSkinProvider(); updateSkinProvider();
} }
@@ -1,9 +1,8 @@
package io.github.skippyall.minions.gui; package io.github.skippyall.minions.gui;
import io.github.skippyall.minions.module.command.Command;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.module.ModuleItem; import io.github.skippyall.minions.new_module.MinionModule;
import io.github.skippyall.minions.program.block.CodeBlock; import io.github.skippyall.minions.new_program.instruction.InstructionType;
import net.minecraft.inventory.Inventories; import net.minecraft.inventory.Inventories;
import net.minecraft.inventory.SimpleInventory; import net.minecraft.inventory.SimpleInventory;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
@@ -20,7 +19,7 @@ import java.util.List;
import java.util.Set; import java.util.Set;
public class ModuleInventory extends SimpleInventory { public class ModuleInventory extends SimpleInventory {
private final Set<ModuleItem> modules = new HashSet<>(); private final Set<MinionModule> modules = new HashSet<>();
public ModuleInventory() { public ModuleInventory() {
super(27); super(27);
} }
@@ -36,7 +35,7 @@ public class ModuleInventory extends SimpleInventory {
@Override @Override
public boolean isValid(int slot, ItemStack stack) { public boolean isValid(int slot, ItemStack stack) {
return (stack.getCount() <= getMaxCountPerStack()) && stack.getItem() instanceof ModuleItem; return (stack.getCount() <= getMaxCountPerStack()) && stack.contains(MinionModule.COMPONENT_TYPE);
} }
@Override @Override
@@ -48,8 +47,9 @@ public class ModuleInventory extends SimpleInventory {
public void updateModules() { public void updateModules() {
modules.clear(); modules.clear();
for (ItemStack heldStack : heldStacks) { for (ItemStack heldStack : heldStacks) {
if(heldStack.getItem() instanceof ModuleItem moduleItem) { MinionModule module = heldStack.get(MinionModule.COMPONENT_TYPE);
modules.add(moduleItem); if(module != null) {
modules.add(module);
} }
} }
} }
@@ -63,31 +63,19 @@ public class ModuleInventory extends SimpleInventory {
Inventories.writeData(view, heldStacks); Inventories.writeData(view, heldStacks);
} }
public boolean hasModule(ModuleItem module) { public boolean hasModule(MinionModule module) {
return modules.contains(module); return modules.contains(module);
} }
public Collection<ModuleItem> getModuleItems() { public Collection<MinionModule> getModules() {
return modules; return modules;
} }
public List<Command> getAllCommands() { public List<InstructionType<?>> getAllInstructions() {
ArrayList<Command> commands = new ArrayList<>(); ArrayList<InstructionType<?>> instructionTypes = new ArrayList<>();
for(ItemStack stack : heldStacks) { for(MinionModule module : modules) {
if(stack.getItem() instanceof ModuleItem module) { instructionTypes.addAll(module.instructions());
commands.addAll(module.getCommands());
} }
} return instructionTypes;
return commands;
}
public List<CodeBlock<?,?>> getAllCodeBlocks() {
ArrayList<CodeBlock<?,?>> commands = new ArrayList<>();
for(ItemStack stack : heldStacks) {
if(stack.getItem() instanceof ModuleItem module) {
commands.addAll(module.getCodeBlocks());
}
}
return commands;
} }
} }
@@ -0,0 +1,37 @@
package io.github.skippyall.minions.input;
import eu.pb4.sgui.api.gui.SimpleGui;
import io.github.skippyall.minions.gui.Displayable;
import io.github.skippyall.minions.gui.GuiDisplay;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.server.network.ServerPlayerEntity;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiFunction;
import java.util.function.Function;
public class ChoiceInput {
public static <T> BiFunction<ServerPlayerEntity, T, CompletableFuture<T>> createDialogOpener(Function<T, GuiDisplay> displayFunction, T[] values) {
return (player, object) -> {
CompletableFuture<T> future = new CompletableFuture<>();
SimpleGui gui = new SimpleGui(ScreenHandlerType.GENERIC_9X3, player, false) {
@Override
public void onClose() {
future.cancel(false);
}
};
for(T value : values) {
gui.addSlot(displayFunction.apply(value).createElement()
.setCallback(() -> future.complete(value))
);
}
gui.open();
return future;
};
}
public static <T extends Displayable> BiFunction<ServerPlayerEntity, T, CompletableFuture<T>> createDialogOpener(T[] values) {
return createDialogOpener(Displayable::getDisplay, values);
}
}
@@ -22,6 +22,7 @@ public class TextInput<T> extends AnvilInputGui {
private final Function<String, CompletableFuture<Result<T, Text>>> parser; private final Function<String, CompletableFuture<Result<T, Text>>> parser;
private final CompletableFuture<T> future; private final CompletableFuture<T> future;
private Result<T, Text> result; private Result<T, Text> result;
private boolean isConfirm;
public TextInput(ServerPlayerEntity player, Text title, String defaultValue, Function<String, CompletableFuture<Result<T, Text>>> parser, CompletableFuture<T> future) { public TextInput(ServerPlayerEntity player, Text title, String defaultValue, Function<String, CompletableFuture<Result<T, Text>>> parser, CompletableFuture<T> future) {
super(player, false); super(player, false);
@@ -74,7 +75,7 @@ public class TextInput<T> extends AnvilInputGui {
@Override @Override
public void onClose() { public void onClose() {
if(!future.isDone()) { if(!future.isDone() && !isConfirm) {
future.cancel(false); future.cancel(false);
} }
} }
@@ -82,8 +83,9 @@ public class TextInput<T> extends AnvilInputGui {
public void onConfirm() { public void onConfirm() {
if(result != null) { if(result != null) {
result.ifSuccess(success -> { result.ifSuccess(success -> {
future.complete(success); isConfirm = true;
close(); close();
future.complete(success);
}); });
} }
} }
@@ -0,0 +1,75 @@
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.new_program.instruction.ConfiguredInstruction;
import io.github.skippyall.minions.new_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 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);
}
}
}
}
@@ -6,16 +6,15 @@ 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.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;
import io.github.skippyall.minions.gui.ModuleInventory; import io.github.skippyall.minions.gui.ModuleInventory;
import io.github.skippyall.minions.program.runtime.MinionRuntime;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.ItemEntity; import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.MovementType;
import net.minecraft.entity.attribute.EntityAttributes; import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.player.HungerManager; import net.minecraft.entity.player.HungerManager;
@@ -56,7 +55,7 @@ public class MinionFakePlayer extends ServerPlayerEntity {
private float moveSideways; private float moveSideways;
private final ModuleInventory moduleInventory = new ModuleInventory(); private final ModuleInventory moduleInventory = new ModuleInventory();
private final MinionRuntime runtime = new MinionRuntime(this); private final MinionInstructionManager instructionManager = new MinionInstructionManager(this);
private final MinionData data; private final MinionData data;
@@ -115,14 +114,26 @@ public class MinionFakePlayer extends ServerPlayerEntity {
return moduleInventory; return moduleInventory;
} }
public MinionRuntime getRuntime() {
return runtime;
}
public EntityPlayerActionPack getMinionActionPack() { public EntityPlayerActionPack getMinionActionPack() {
return actionPack; return actionPack;
} }
public MinionInstructionManager getInstructionManager() {
return instructionManager;
}
public MinionData getData() {
return data;
}
public boolean canSpawnMobs() {
return true;
}
public boolean canDespawnMobs() {
return true;
}
@Override @Override
public ActionResult interact(PlayerEntity player, Hand hand) { public ActionResult interact(PlayerEntity player, Hand hand) {
if(player instanceof ServerPlayerEntity spe) { if(player instanceof ServerPlayerEntity spe) {
@@ -176,13 +187,13 @@ public class MinionFakePlayer extends ServerPlayerEntity {
{ {
super.tick(); super.tick();
this.playerTick(); this.playerTick();
instructionManager.tick();
} }
catch (NullPointerException ignored) catch (NullPointerException ignored)
{ {
// happens with that paper port thingy - not sure what that would fix, but hey // happens with that paper port thingy - not sure what that would fix, but hey
// the game not gonna crash violently. // the game not gonna crash violently.
} }
runtime.tick();
} }
@@ -238,7 +249,7 @@ public class MinionFakePlayer extends ServerPlayerEntity {
return networkHandler.player; return networkHandler.player;
} }
public void moveForward(float forward) { /*public void moveForward(float forward) {
this.moveForward += forward; this.moveForward += forward;
EntityPlayerActionPack actionPack = getMinionActionPack(); EntityPlayerActionPack actionPack = getMinionActionPack();
if (moveForward != 0) { if (moveForward != 0) {
@@ -274,7 +285,7 @@ public class MinionFakePlayer extends ServerPlayerEntity {
moveSideways = newSideways; moveSideways = newSideways;
} }
super.move(movementType, newMovement); super.move(movementType, newMovement);
} }*/
@Override @Override
public void drop(ServerWorld world, DamageSource damageSource) { public void drop(ServerWorld world, DamageSource damageSource) {
@@ -291,19 +302,17 @@ public class MinionFakePlayer extends ServerPlayerEntity {
return stack; return stack;
} }
public MinionData getData() {
return data;
}
@Override @Override
public void writeCustomData(WriteView view) { public void writeCustomData(WriteView view) {
super.writeCustomData(view); super.writeCustomData(view);
moduleInventory.writeData(view.get("modules")); moduleInventory.writeData(view.get("modules"));
instructionManager.save(view.get("instructionManager"));
} }
@Override @Override
public void readCustomData(ReadView view) { public void readCustomData(ReadView view) {
super.readCustomData(view); super.readCustomData(view);
moduleInventory.readData(view.getReadView("modules")); moduleInventory.readData(view.getReadView("modules"));
instructionManager.load(view.getReadView("instructionManager"));
} }
} }
@@ -1,22 +1,17 @@
package io.github.skippyall.minions.minion.skin; package io.github.skippyall.minions.minion.skin;
import com.mojang.serialization.Lifecycle; import io.github.skippyall.minions.MinionRegistries;
import io.github.skippyall.minions.Minions; import io.github.skippyall.minions.Minions;
import net.minecraft.registry.Registry; import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.SimpleRegistry;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
public class SkinProviders { public class SkinProviders {
public static final Registry<SkinProvider> SKIN_PROVIDERS = new SimpleRegistry<>(RegistryKey.ofRegistry(Identifier.of(Minions.MOD_ID, "skin_providers")), Lifecycle.stable());
public static NameSkinProvider NAME = register(new NameSkinProvider(), "name"); public static NameSkinProvider NAME = register(new NameSkinProvider(), "name");
public static UUIDSkinProvider UUID = register(new UUIDSkinProvider(), "uuid"); public static UUIDSkinProvider UUID = register(new UUIDSkinProvider(), "uuid");
public static Base64SkinProvider BASE64 = register(new Base64SkinProvider(), "base64"); public static Base64SkinProvider BASE64 = register(new Base64SkinProvider(), "base64");
public static <T extends SkinProvider> T register(T skinProvider, String path) { public static <T extends SkinProvider> T register(T skinProvider, String path) {
return Registry.register(SKIN_PROVIDERS, Identifier.of(Minions.MOD_ID, path), skinProvider); return Registry.register(MinionRegistries.SKIN_PROVIDERS, Identifier.of(Minions.MOD_ID, path), skinProvider);
} }
public static void register() { public static void register() {
@@ -4,7 +4,6 @@ import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.mixinhelper.EntityViewMixinHelper; import io.github.skippyall.minions.mixinhelper.EntityViewMixinHelper;
import io.github.skippyall.minions.module.MobSpawningModule;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.mob.MobEntity; import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
@@ -18,7 +17,7 @@ public abstract class MobEntityMixin {
public PlayerEntity checkMobDespawningMinion(World instance, Entity entity, double maxDistance, Operation<PlayerEntity> original) { public PlayerEntity checkMobDespawningMinion(World instance, Entity entity, double maxDistance, Operation<PlayerEntity> original) {
EntityViewMixinHelper.ADDITIONAL_PREDICATE.set(entity2 -> { EntityViewMixinHelper.ADDITIONAL_PREDICATE.set(entity2 -> {
if(entity2 instanceof MinionFakePlayer minion) { if(entity2 instanceof MinionFakePlayer minion) {
return MobSpawningModule.canMinionDespawnMobs(minion); return minion.canDespawnMobs();
} else { } else {
return true; return true;
} }
@@ -1,7 +1,6 @@
package io.github.skippyall.minions.mixins; package io.github.skippyall.minions.mixins;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.module.MobSpawningModule;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.predicate.entity.EntityPredicates; import net.minecraft.predicate.entity.EntityPredicates;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
@@ -18,7 +17,7 @@ public class SpawnHelperMixin {
return instance.getClosestPlayer(x, y, z, maxDistance, EntityPredicates.EXCEPT_SPECTATOR.and(entity -> { return instance.getClosestPlayer(x, y, z, maxDistance, EntityPredicates.EXCEPT_SPECTATOR.and(entity -> {
if(entity instanceof ServerPlayerEntity player) { if(entity instanceof ServerPlayerEntity player) {
if(player instanceof MinionFakePlayer minion) { if(player instanceof MinionFakePlayer minion) {
return MobSpawningModule.canMinionSpawnMobs(minion); return minion.canSpawnMobs();
} }
return true; return true;
} }
@@ -3,7 +3,6 @@ package io.github.skippyall.minions.mixins.antimobcap;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.mixinhelper.ChunkLevelManager$DistanceFromNearestPlayerTrackerAccessor; import io.github.skippyall.minions.mixinhelper.ChunkLevelManager$DistanceFromNearestPlayerTrackerAccessor;
import io.github.skippyall.minions.mixinhelper.ChunkLevelManagerAccessor; import io.github.skippyall.minions.mixinhelper.ChunkLevelManagerAccessor;
import io.github.skippyall.minions.module.MobSpawningModule;
import it.unimi.dsi.fastutil.longs.Long2ByteMap; import it.unimi.dsi.fastutil.longs.Long2ByteMap;
import it.unimi.dsi.fastutil.objects.ObjectSet; import it.unimi.dsi.fastutil.objects.ObjectSet;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
@@ -47,7 +46,7 @@ public abstract class ChunkLevelManager$DistanceFromNearestPlayerTrackerMixin ex
if(players != null) { if(players != null) {
contains = players.stream().anyMatch(player -> { contains = players.stream().anyMatch(player -> {
if (player instanceof MinionFakePlayer minion) { if (player instanceof MinionFakePlayer minion) {
return MobSpawningModule.canMinionSpawnMobs(minion); return minion.canSpawnMobs();
} }
return true; return true;
}); });
@@ -1,34 +0,0 @@
package io.github.skippyall.minions.module;
import io.github.skippyall.minions.Minions;
import io.github.skippyall.minions.module.action.ActionModules;
import io.github.skippyall.minions.minion.fakeplayer.EntityPlayerActionPack;
import io.github.skippyall.minions.module.instruction.InstructionDisplay;
import net.minecraft.item.Items;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import java.util.List;
import static io.github.skippyall.minions.module.Modules.register;
public class AttackModule {
public static final InstructionDisplay ATTACK_COMMAND = new InstructionDisplay(
Text.translatable("minions.command.attack.name"),
Text.translatable("minions.command.attack.description"),
Items.DIAMOND_PICKAXE,
ActionModules.detailSelectionExecutor(EntityPlayerActionPack.ActionType.ATTACK, Text.translatable("minions.command.attack.name"))
);
public static final SimpleModuleItem ATTACK_MODULE = register(
Identifier.of(Minions.MOD_ID, "attack_module"),
List.of(),
List.of(ATTACK_COMMAND),
Items.DIAMOND_PICKAXE
);
public static void registerMe() {
}
}
@@ -1,22 +0,0 @@
package io.github.skippyall.minions.module;
import io.github.skippyall.minions.Minions;
import io.github.skippyall.minions.module.command.SimpleCommand;
import net.minecraft.item.Items;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import java.util.ArrayList;
import java.util.Arrays;
import static io.github.skippyall.minions.module.Modules.register;
public class ChatModule {
public static final SimpleModuleItem CHAT_MODULE = register(Identifier.of(Minions.MOD_ID, "chat_module"),
new ArrayList<>(), Arrays.asList(
new SimpleCommand(Text.of("Message"), Text.of("Send Message in Public Chat"), Items.PAPER, (player, minion) -> minion.getServer().getPlayerManager().broadcast(Text.of("message"), true)),
new SimpleCommand(Text.of("Prvt-Message"), Text.of("Send Message to one Person"), Items.TRIAL_KEY, (player, minion) -> {})
), Items.PAPER);
public static void registerMe() {}
}
@@ -1,34 +0,0 @@
package io.github.skippyall.minions.module;
import io.github.skippyall.minions.Minions;
import io.github.skippyall.minions.module.action.ActionModules;
import io.github.skippyall.minions.module.command.SimpleCommand;
import io.github.skippyall.minions.minion.fakeplayer.EntityPlayerActionPack;
import net.minecraft.item.Items;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import java.util.List;
import static io.github.skippyall.minions.module.Modules.register;
public class InteractModule {
public static final SimpleCommand INTERACT_COMMAND = new SimpleCommand(
Text.translatable("minions.command.interact.name"),
Text.translatable("minions.command.interact.description"),
Items.LEVER,
ActionModules.detailSelectionExecutor(EntityPlayerActionPack.ActionType.USE, Text.translatable("minions.command.interact.name"))
);
public static final SimpleModuleItem INTERACT_MODULE = register(
Identifier.of(Minions.MOD_ID, "interact_module"),
List.of(),
List.of(INTERACT_COMMAND),
Items.LEVER
);
public static void registerMe() {
}
}
@@ -1,30 +0,0 @@
package io.github.skippyall.minions.module;
import io.github.skippyall.minions.Minions;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import net.minecraft.item.Items;
import net.minecraft.util.Identifier;
import java.util.List;
import static io.github.skippyall.minions.module.Modules.register;
public class MobSpawningModule {
public static final SimpleModuleItem MOB_SPAWNING_MODULE =
register(
Identifier.of(Minions.MOD_ID, "mob_spawning_module"),
List.of(),
List.of(),
Items.SPAWNER
);
public static boolean canMinionSpawnMobs(MinionFakePlayer minion) {
return minion.getModuleInventory().hasModule(MOB_SPAWNING_MODULE);
}
public static boolean canMinionDespawnMobs(MinionFakePlayer minion) {
return minion.getModuleInventory().hasModule(MOB_SPAWNING_MODULE);
}
public static void registerMe() {}
}
@@ -1,10 +0,0 @@
package io.github.skippyall.minions.module;
import io.github.skippyall.minions.module.instruction.InstructionDisplay;
import net.minecraft.item.ItemConvertible;
import java.util.List;
public interface ModuleItem extends ItemConvertible {
List<InstructionDisplay> getInstructions();
}
@@ -1,30 +0,0 @@
package io.github.skippyall.minions.module;
import io.github.skippyall.minions.MinionItems;
import io.github.skippyall.minions.module.command.Command;
import io.github.skippyall.minions.module.instruction.InstructionDisplay;
import io.github.skippyall.minions.new_program.instruction.Instruction;
import io.github.skippyall.minions.program.block.CodeBlock;
import net.minecraft.item.Item;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.util.Identifier;
import java.util.List;
public class Modules {
public static void register() {
ChatModule.registerMe();
MountModule.registerMe();
MoveModule.registerMe();
MobSpawningModule.registerMe();
InteractModule.registerMe();
AttackModule.registerMe();
}
public static SimpleModuleItem register(Identifier id, List<InstructionDisplay> instructions, Item vanillaItem) {
return MinionItems.registerItem(id, settings -> new SimpleModuleItem(instructions, settings, vanillaItem));
}
}
@@ -1,41 +0,0 @@
package io.github.skippyall.minions.module;
import io.github.skippyall.minions.Minions;
import io.github.skippyall.minions.module.command.SimpleCommand;
import net.minecraft.item.Items;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import java.util.List;
import static io.github.skippyall.minions.module.Modules.register;
public class MountModule {
public static final SimpleCommand MOUNT_COMMAND = new SimpleCommand(
Text.of("Mount"),
Text.of("Mount the minion to the nearest mountable Entity"),
Items.MINECART,
(player, minion) -> minion.getMinionActionPack().mount(true)
);
public static final SimpleCommand DISMOUNT_COMMAND = new SimpleCommand(
Text.of("Dismount"),
Text.of("Dismount the minion"),
Items.BARRIER,
(player, minion) -> minion.getMinionActionPack().dismount()
);
public static final SimpleModuleItem MOUNT_MODULE =
register(Identifier.of(Minions.MOD_ID, "mount_module"),
List.of(),
List.of(
MOUNT_COMMAND,
DISMOUNT_COMMAND
),
Items.MINECART
);
public static void registerMe() {
}
}
@@ -1,76 +0,0 @@
package io.github.skippyall.minions.module;
import io.github.skippyall.minions.Minions;
import io.github.skippyall.minions.module.command.SimpleCommand;
import io.github.skippyall.minions.input.TextInput;
import net.minecraft.item.Items;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import java.util.List;
import static io.github.skippyall.minions.module.Modules.register;
public class MoveModule {
public static final SimpleCommand WALK_COMMAND =
new SimpleCommand(
Text.literal("Walk"),
Text.literal("Walk a specific amount of blocks forward"),
Items.IRON_BOOTS,
(player, minion) -> TextInput.inputFloat(player, Text.literal("Amount of Blocks"), "1")
.thenAccept(minion::moveForward)
);
public static final SimpleCommand TURN_RIGHT_COMMAND =
new SimpleCommand(
Text.literal("Turn Right"),
Text.literal("Turn a specific amount of degrees right"),
Items.COMPASS,
(player, minion) -> TextInput.inputFloat(player, Text.literal("Degrees"), "90")
.thenAccept(degrees -> minion.getMinionActionPack().turn(degrees, 0))
);
public static final SimpleCommand TURN_LEFT_COMMAND =
new SimpleCommand(
Text.literal("Turn Left"),
Text.literal("Turn a specific amount of degrees left"),
Items.COMPASS,
(player, minion) -> TextInput.inputFloat(player, Text.literal("Degrees"), "90")
.thenAccept(degrees -> minion.getMinionActionPack().turn(-degrees, 0))
);
public static final SimpleCommand TURN_UP_COMMAND =
new SimpleCommand(
Text.literal("Turn Up"),
Text.literal("Turn a specific amount of degrees up"),
Items.COMPASS,
(player, minion) -> TextInput.inputFloat(player, Text.literal("Degrees"), "90")
.thenAccept(degrees -> minion.getMinionActionPack().turn(0, -degrees))
);
public static final SimpleCommand TURN_DOWN_COMMAND =
new SimpleCommand(
Text.literal("Turn Down"),
Text.literal("Turn a specific amount of degrees down"),
Items.COMPASS,
(player, minion) -> TextInput.inputFloat(player, Text.literal("Degrees"), "90")
.thenAccept(degrees -> minion.getMinionActionPack().turn(0, degrees))
);
public static final SimpleModuleItem MOVE_MODULE =
register(Identifier.of(Minions.MOD_ID, "move_module"),
List.of(),
List.of(
WALK_COMMAND,
TURN_RIGHT_COMMAND,
TURN_LEFT_COMMAND,
TURN_UP_COMMAND,
TURN_DOWN_COMMAND
),
Items.IRON_BOOTS
);
public static void registerMe() {}
}
@@ -1,24 +0,0 @@
package io.github.skippyall.minions.module;
import eu.pb4.polymer.core.api.item.SimplePolymerItem;
import io.github.skippyall.minions.module.command.Command;
import io.github.skippyall.minions.module.instruction.InstructionDisplay;
import io.github.skippyall.minions.new_program.instruction.Instruction;
import io.github.skippyall.minions.program.block.CodeBlock;
import net.minecraft.item.Item;
import java.util.List;
public class SimpleModuleItem extends SimplePolymerItem implements ModuleItem {
private final List<InstructionDisplay> instructions;
public SimpleModuleItem(List<InstructionDisplay> instructions, Settings settings, Item vanillaItem) {
super(settings.maxCount(1), vanillaItem);
this.instructions = instructions;
}
@Override
public List<InstructionDisplay> getInstructions() {
return instructions;
}
}
@@ -1,68 +0,0 @@
package io.github.skippyall.minions.module.action;
import eu.pb4.sgui.api.elements.GuiElementBuilder;
import eu.pb4.sgui.api.gui.SimpleGui;
import io.github.skippyall.minions.input.TextInput;
import io.github.skippyall.minions.minion.fakeplayer.EntityPlayerActionPack;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.new_program.instruction.Instruction;
import net.minecraft.item.Items;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import java.util.List;
public class ActionModules {
public static void executeOnce(EntityPlayerActionPack.ActionType actionType, ServerPlayerEntity player, MinionFakePlayer minion) {
minion.getMinionActionPack().start(actionType, EntityPlayerActionPack.Action.once());
}
public static void executeContinuous(EntityPlayerActionPack.ActionType actionType, ServerPlayerEntity player, MinionFakePlayer minion) {
minion.getMinionActionPack().start(actionType, EntityPlayerActionPack.Action.continuous());
}
public static void executeInterval(EntityPlayerActionPack.ActionType actionType, ServerPlayerEntity player, MinionFakePlayer minion) {
TextInput.inputFloat(player, Text.translatable("minions.command.action.interval.enter"), "3.5").thenAccept(interval -> {
int ticks = Math.round(interval * 20);
minion.getMinionActionPack().start(actionType, EntityPlayerActionPack.Action.interval(ticks));
});
}
public static void executeStop(EntityPlayerActionPack.ActionType actionType, ServerPlayerEntity player, MinionFakePlayer minion) {
minion.getMinionActionPack().stop(actionType);
}
public static List<Instruction> actionInstruction(EntityPlayerActionPack.ActionType actionType, Text actionName) {
return List.of(
)
return (player, minion) -> {
SimpleGui gui = new SimpleGui(ScreenHandlerType.GENERIC_3X3, player, false);
gui.setTitle(Text.translatable("minions.command.action.details", actionName));
gui.setSlot(1, new GuiElementBuilder()
.setItem(Items.COMMAND_BLOCK)
.setName(Text.translatable("minions.command.action.once", actionName))
.setCallback(() -> executeOnce(actionType, player, minion))
);
gui.setSlot(3, new GuiElementBuilder()
.setItem(Items.REPEATING_COMMAND_BLOCK)
.setName(Text.translatable("minions.command.action.continuous", actionName))
.setCallback(() -> executeContinuous(actionType, player, minion))
);
gui.setSlot(5, new GuiElementBuilder()
.setItem(Items.CHAIN_COMMAND_BLOCK)
.setName(Text.translatable("minions.command.action.interval", actionName))
.setCallback(() -> executeInterval(actionType, player, minion))
);
gui.setSlot(4, new GuiElementBuilder()
.setItem(Items.BARRIER)
.setName(Text.translatable("minions.command.action.stop", actionName))
.setCallback(() -> executeStop(actionType, player, minion))
);
gui.open();
};
}
}
@@ -1,10 +0,0 @@
package io.github.skippyall.minions.module.command;
import net.minecraft.item.Item;
import net.minecraft.text.Text;
public interface Command extends CommandExecutor {
Text getName();
Text getDescription();
Item getItemRepresentation();
}
@@ -1,8 +0,0 @@
package io.github.skippyall.minions.module.command;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import net.minecraft.server.network.ServerPlayerEntity;
public interface CommandExecutor {
void execute(ServerPlayerEntity player, MinionFakePlayer minion);
}
@@ -1,40 +0,0 @@
package io.github.skippyall.minions.module.command;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import net.minecraft.item.Item;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
public class SimpleCommand implements Command {
private final Text name;
private final Text description;
private final Item itemRepresentation;
private final CommandExecutor executor;
public SimpleCommand(Text name, Text description, Item itemRepresentation, CommandExecutor executor) {
this.name = name;
this.description = description;
this.itemRepresentation = itemRepresentation;
this.executor = executor;
}
@Override
public Text getName() {
return name;
}
@Override
public Text getDescription() {
return description;
}
@Override
public Item getItemRepresentation() {
return itemRepresentation;
}
@Override
public void execute(ServerPlayerEntity player, MinionFakePlayer minion) {
executor.execute(player, minion);
}
}
@@ -1,9 +0,0 @@
package io.github.skippyall.minions.module.instruction;
import io.github.skippyall.minions.new_program.instruction.Instruction;
import net.minecraft.item.Item;
import net.minecraft.text.Text;
public record InstructionDisplay(Text name, Text description, Item itemRepresentation, Instruction instruction) {
}
@@ -0,0 +1,38 @@
package io.github.skippyall.minions.new_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.Minions;
import io.github.skippyall.minions.new_program.instruction.InstructionType;
import net.minecraft.component.ComponentType;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.util.Identifier;
import java.util.List;
public record MinionModule(List<InstructionType<?>> instructions) {
public static final Codec<MinionModule> CODEC = RecordCodecBuilder.create(instance ->
instance.group(
MinionRegistries.INSTRUCTION_TYPES.getCodec().listOf().fieldOf("instructions").forGetter(MinionModule::instructions)
).apply(instance, MinionModule::new)
);
public static final Codec<MinionModule> DATAPACK_CODEC = Codec.withAlternative(Identifier.CODEC.xmap(ModuleLoader.MODULES::get, ModuleLoader.ID_BY_MODULE::get), CODEC);
public static final ComponentType<MinionModule> COMPONENT_TYPE = ComponentType.<MinionModule>builder().codec(DATAPACK_CODEC).build();
public static final MinionModule EMPTY = new MinionModule(List.of());
public MinionModule(List<InstructionType<?>> instructions) {
this.instructions = List.copyOf(instructions);
}
public static void register() {
Registry.register(Registries.DATA_COMPONENT_TYPE, Identifier.of(Minions.MOD_ID, "minion_module"), COMPONENT_TYPE);
PolymerComponent.registerDataComponent(COMPONENT_TYPE);
}
}
@@ -0,0 +1,30 @@
package io.github.skippyall.minions.new_module;
import com.mojang.serialization.JsonOps;
import io.github.skippyall.minions.Minions;
import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener;
import net.minecraft.resource.JsonDataLoader;
import net.minecraft.resource.ResourceFinder;
import net.minecraft.resource.ResourceManager;
import net.minecraft.util.Identifier;
import java.util.HashMap;
import java.util.Map;
public class ModuleLoader implements SimpleSynchronousResourceReloadListener {
public static final HashMap<MinionModule, Identifier> ID_BY_MODULE = new HashMap<>();
public static final Map<Identifier, MinionModule> MODULES = new HashMap<>();
@Override
public Identifier getFabricId() {
return Identifier.of(Minions.MOD_ID, "module");
}
@Override
public void reload(ResourceManager manager) {
MODULES.clear();
ID_BY_MODULE.clear();
JsonDataLoader.load(manager, ResourceFinder.json("minion_module"), JsonOps.INSTANCE, MinionModule.CODEC, MODULES);
MODULES.forEach((id, module) -> ID_BY_MODULE.put(module, id));
}
}
@@ -1,32 +0,0 @@
package io.github.skippyall.minions.new_program;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.new_program.argument.Argument;
import io.github.skippyall.minions.new_program.value.ValueType;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
public class ParameterList {
Map<String, Argument<?>> parameters = new HashMap<>();
public <T> @Nullable T getValue(String name, ValueType<T> valueType, MinionFakePlayer minion) {
Argument<T> argument = getArgument(name, valueType);
return argument != null ? argument.resolve(minion) : null;
}
public <T> @Nullable Argument<T> getArgument(String name, ValueType<T> valueType) {
Argument<?> argument = parameters.get(name);
if(argument != null && argument.getType() == valueType) {
//noinspection unchecked
return (Argument<T>) argument;
} else {
return null;
}
}
public void setArgument(String name, Argument<?> argument) {
parameters.put(name, argument);
}
}
@@ -1,9 +1,34 @@
package io.github.skippyall.minions.new_program.argument; package io.github.skippyall.minions.new_program.argument;
import io.github.skippyall.minions.gui.GuiDisplay;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.new_program.value.ValueType; import io.github.skippyall.minions.new_program.value.ValueType;
import org.jetbrains.annotations.Nullable;
public interface Argument<T> { /**
* 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
* @param <S> The <code>SpecificArgumentType</code>
*/
public interface Argument<T, S extends SpecificArgumentType<T, ? extends Argument<T, S>>> {
T resolve(MinionFakePlayer minion); T resolve(MinionFakePlayer minion);
ValueType<T> getType();
default ValueType<T> getValueType() {
return getType().getValueType();
}
GuiDisplay getDisplay();
S getType();
default <U, A extends Argument<U, ? extends SpecificArgumentType<U,A>>> @Nullable A cast(ValueType<U> type) {
if(getValueType() == type) {
//noinspection unchecked
return (A) this;
} else {
return null;
}
}
} }
@@ -0,0 +1,50 @@
package io.github.skippyall.minions.new_program.argument;
import com.mojang.serialization.Codec;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class ArgumentList {
public static final Codec<ArgumentList> CODEC = Codec.unboundedMap(Codec.STRING, Arguments.ARGUMENT_CODEC)
.xmap(ArgumentList::new, list -> list.arguments);
private final Map<String, Argument<?, ?>> arguments;
public ArgumentList() {
arguments = new HashMap<>();
}
public ArgumentList(Map<String, Argument<?,?>> arguments) {
this.arguments = new HashMap<>(arguments);
}
public <T> T getValue(Parameter<T> parameter, MinionFakePlayer minion) {
Argument<T,?> argument = getArgument(parameter);
return argument != null ? argument.resolve(minion) : null;
}
public <T, A extends Argument<T, ? extends SpecificArgumentType<T,A>>> A getArgument(Parameter<T> parameter) {
Argument<?, ?> argument = arguments.get(parameter.name());
return argument == null ? null : argument.cast(parameter.type());
}
public <T> void setArgument(Parameter<T> parameter, Argument<T,?> 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;
}
}
@@ -1,6 +1,8 @@
package io.github.skippyall.minions.new_program.argument; package io.github.skippyall.minions.new_program.argument;
import com.mojang.serialization.Codec;
import com.mojang.serialization.Lifecycle; import com.mojang.serialization.Lifecycle;
import io.github.skippyall.minions.MinionRegistries;
import io.github.skippyall.minions.Minions; import io.github.skippyall.minions.Minions;
import io.github.skippyall.minions.new_program.value.ValueType; import io.github.skippyall.minions.new_program.value.ValueType;
import net.minecraft.registry.Registry; import net.minecraft.registry.Registry;
@@ -9,20 +11,30 @@ import net.minecraft.registry.SimpleRegistry;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
public class Arguments { public class Arguments {
public static final Registry<GenericArgumentType> GENERIC_ARGUMENT_TYPE_REGISTRY = new SimpleRegistry<>(RegistryKey.ofRegistry(Identifier.of("minions", "generic_argument_type")), Lifecycle.stable()); public static final Codec<SpecificArgumentType<?,?>> SPECIFIC_ARGUMENT_TYPE_CODEC = MinionRegistries.GENERIC_ARGUMENT_TYPE_REGISTRY.getCodec().dispatch(
"type",
SpecificArgumentType::getGenericArgumentType,
generic ->
MinionRegistries.VALUE_TYPES.getCodec().xmap(
generic::createTypeSpecific,
SpecificArgumentType::getValueType
).fieldOf("valueType")
);
public static final Codec<Argument<?,?>> ARGUMENT_CODEC = SPECIFIC_ARGUMENT_TYPE_CODEC.dispatch(Argument::getType, specific -> specific.getArgumentCodec().fieldOf("data"));
public static final GenericArgumentType VALUE_ARGUMENT = register(Identifier.of(Minions.MOD_ID, "value"), ValueArgumentType::new); public static final GenericArgumentType VALUE_ARGUMENT = register(Identifier.of(Minions.MOD_ID, "value"), ValueArgumentType::new);
public static <V> SpecificArgumentType<V, ?> getArgumentType(Identifier id, ValueType<V> valueType) { /*public static <V> SpecificArgumentType<V, ? extends Argument<V, ?>> getArgumentType(Identifier id, ValueType<V> valueType) {
GenericArgumentType generic = GENERIC_ARGUMENT_TYPE_REGISTRY.get(id); GenericArgumentType generic = MinionRegistries.GENERIC_ARGUMENT_TYPE_REGISTRY.get(id);
if(generic != null) { if(generic != null) {
return generic.createTypeSpecific(valueType); return generic.createTypeSpecific(valueType);
} }
return null; return null;
} }*/
public static GenericArgumentType register(Identifier id, GenericArgumentType argumentType) { public static GenericArgumentType register(Identifier id, GenericArgumentType argumentType) {
return Registry.register(GENERIC_ARGUMENT_TYPE_REGISTRY, id, argumentType); return Registry.register(MinionRegistries.GENERIC_ARGUMENT_TYPE_REGISTRY, id, argumentType);
} }
} }
@@ -3,5 +3,5 @@ package io.github.skippyall.minions.new_program.argument;
import io.github.skippyall.minions.new_program.value.ValueType; import io.github.skippyall.minions.new_program.value.ValueType;
public interface GenericArgumentType { public interface GenericArgumentType {
<V> SpecificArgumentType<V, ? extends Argument<V>> createTypeSpecific(ValueType<V> valueType); <V> SpecificArgumentType<V, ? extends Argument<V,?>> createTypeSpecific(ValueType<V> valueType);
} }
@@ -0,0 +1,24 @@
package io.github.skippyall.minions.new_program.argument;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import io.github.skippyall.minions.MinionRegistries;
import io.github.skippyall.minions.new_program.value.ValueType;
import org.jetbrains.annotations.Nullable;
public record Parameter<T>(String name, ValueType<T> type) {
public static final Codec<Parameter<?>> CODEC = RecordCodecBuilder.create(instance ->
instance.group(
Codec.STRING.fieldOf("name").forGetter(Parameter::name),
MinionRegistries.VALUE_TYPES.getCodec().fieldOf("type").forGetter(Parameter::type)
).apply(instance, Parameter::new));
public <U> @Nullable Parameter<U> cast(ValueType<U> type) {
if(this.type == type) {
//noinspection unchecked
return (Parameter<U>) this;
} else {
return null;
}
}
}
@@ -3,19 +3,28 @@ package io.github.skippyall.minions.new_program.argument;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import io.github.skippyall.minions.new_program.value.ValueType; import io.github.skippyall.minions.new_program.value.ValueType;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import org.jetbrains.annotations.Nullable;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public abstract class SpecificArgumentType<V, A extends Argument<V>> { /**
* <code>SpecificArgumentType</code>s create <code>Argument</code>s of the specified <code>ValueType</code>.
* They are also responsible for the serialization and user input of arguments.
* @param <V> The value type of the <code>Argument</code>s to create
* @param <A> The type of the <code>Argument</code>s themselves
*/
public abstract class SpecificArgumentType<V, A extends Argument<V, ? extends SpecificArgumentType<V, A>>> {
protected final ValueType<V> valueType; protected final ValueType<V> valueType;
public SpecificArgumentType(ValueType<V> valueType) { public SpecificArgumentType(ValueType<V> valueType) {
this.valueType = valueType; this.valueType = valueType;
} }
public abstract GenericArgumentType getGenericArgumentType();
public abstract Codec<A> getArgumentCodec(); public abstract Codec<A> getArgumentCodec();
public abstract CompletableFuture<A> openArgumentDialog(ServerPlayerEntity player, A previousArgument); public abstract CompletableFuture<A> openArgumentDialog(ServerPlayerEntity player, @Nullable A previousArgument);
public ValueType<V> getValueType() { public ValueType<V> getValueType() {
return valueType; return valueType;
@@ -1,14 +1,18 @@
package io.github.skippyall.minions.new_program.argument; package io.github.skippyall.minions.new_program.argument;
import io.github.skippyall.minions.gui.GuiDisplay;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.new_program.value.ValueType; import io.github.skippyall.minions.new_program.value.ValueType;
public class ValueArgument<T> implements Argument<T> { /**
private final ValueType<T> valueType; * An argument that always resolves to a fixed value
*/
public class ValueArgument<T> implements Argument<T, ValueArgumentType<T>> {
private final ValueArgumentType<T> type;
private final T value; private final T value;
public ValueArgument(ValueType<T> valueType, T value) { public ValueArgument(ValueArgumentType<T> valueType, T value) {
this.valueType = valueType; this.type = valueType;
this.value = value; this.value = value;
} }
@@ -22,7 +26,12 @@ public class ValueArgument<T> implements Argument<T> {
} }
@Override @Override
public ValueType<T> getType() { public GuiDisplay getDisplay() {
return valueType; return getValueType().display();
}
@Override
public ValueArgumentType<T> getType() {
return type;
} }
} }
@@ -3,6 +3,7 @@ package io.github.skippyall.minions.new_program.argument;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import io.github.skippyall.minions.new_program.value.ValueType; import io.github.skippyall.minions.new_program.value.ValueType;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import org.jetbrains.annotations.Nullable;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@@ -12,12 +13,20 @@ public class ValueArgumentType<V> extends SpecificArgumentType<V, ValueArgument<
} }
@Override @Override
public Codec<ValueArgument<V>> getArgumentCodec() { public GenericArgumentType getGenericArgumentType() {
return valueType.getCodec().xmap(value -> new ValueArgument<>(valueType, value), ValueArgument::getValue); return Arguments.VALUE_ARGUMENT;
} }
@Override @Override
public CompletableFuture<ValueArgument<V>> openArgumentDialog(ServerPlayerEntity player, ValueArgument<V> previousArgument) { public Codec<ValueArgument<V>> getArgumentCodec() {
return valueType.openValueDialog(player, previousArgument.getValue()).thenApply(value -> new ValueArgument<>(valueType, value)); return valueType.codec().xmap(value -> new ValueArgument<>(this, value), ValueArgument::getValue);
}
@Override
public CompletableFuture<ValueArgument<V>> openArgumentDialog(ServerPlayerEntity player, @Nullable ValueArgument<V> previousArgument) {
return valueType.openValueDialog(
player,
previousArgument != null ? previousArgument.getValue() : valueType.defaultValue()
).thenApply(value -> new ValueArgument<>(this, value));
} }
} }
@@ -1,15 +0,0 @@
package io.github.skippyall.minions.new_program.instruction;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.new_program.ParameterList;
import io.github.skippyall.minions.program.variables.Type;
import java.util.List;
public interface Instruction {
List<Type<?>> getParameterTypes();
Type<?> getReturnType();
InstructionRun run(MinionFakePlayer minion, ParameterList params);
}
@@ -0,0 +1,66 @@
package io.github.skippyall.minions.new_program.instruction;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.new_program.argument.ArgumentList;
import net.minecraft.storage.ReadView;
import net.minecraft.storage.WriteView;
/**
* Responsible for executing instructions.
* When an instruction is executed:
* <li>A new instance is created using the factory</li>
* <li>{@link InstructionExecution#readArguments(ArgumentList, MinionFakePlayer) readFromParameters} is called</li>
* <li>{@link InstructionExecution#start(MinionFakePlayer) start} is called</li>
* @param <R>
*/
public interface InstructionExecution<R> {
/**
* Starts the execution.
* @param minion
*/
default void start(MinionFakePlayer minion) {}
/**
* Continues the execution of this instruction.
* Called every tick while executing the instruction.
* @param minion
*/
default void tick(MinionFakePlayer minion) {}
/**
* Called every tick to determine if the execution of this instruction should be stopped.
* Shouldn't
* @param minion The minion executing the instruction
* @return <code>true</code> if the instruction is done, <code>false</code> otherwise.
*/
boolean isDone(MinionFakePlayer minion);
/**
* Stops this execution. This is guaranteed to be called if {@link InstructionExecution#isDone(MinionFakePlayer) isDone}
* returns true after ticking the execution, but it may also be called before that.
* In this case, the return value is ignored unless this is a
* {@link io.github.skippyall.minions.new_program.instruction.execution.ContinuousInstructionExecution ContinuousInstructionExecution}.</br>
* This should undo changes to the minion unless they are supposed to be permanent.
*
* @param minion The minion that was executing this instruction.
* @return The return value of the instruction
*/
R stop(MinionFakePlayer minion);
/**
* Initializes the execution with its arguments.
* @param arguments The arguments to initialize the execution
* @param minion The minion should be used to resolve the arguments
*/
void readArguments(ArgumentList arguments, MinionFakePlayer minion);
/**
* Saves the execution, e.g. when the server is closed.
*/
void save(WriteView view, MinionFakePlayer minion);
/**
* Loads the execution, e.g. when the server is started.
*/
void load(ReadView view, MinionFakePlayer minion);
}
@@ -1,9 +0,0 @@
package io.github.skippyall.minions.new_program.instruction;
public interface InstructionRun {
default void tick() {}
default boolean isDone() {
return true;
}
}
@@ -0,0 +1,58 @@
package io.github.skippyall.minions.new_program.instruction;
import io.github.skippyall.minions.gui.GuiDisplay;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.new_program.argument.Parameter;
import io.github.skippyall.minions.new_program.argument.ArgumentList;
import io.github.skippyall.minions.new_program.value.ValueType;
import net.minecraft.storage.ReadView;
import java.util.Collection;
import java.util.List;
import java.util.function.Supplier;
public final class InstructionType<R> {
private final GuiDisplay display;
private final Collection<Parameter<?>> parameters;
private final ValueType<R> returnType;
private final Supplier<InstructionExecution<R>> executionFactory;
private InstructionType(GuiDisplay display, Supplier<InstructionExecution<R>> executionFactory, ValueType<R> returnType, Collection<Parameter<?>> parameters) {
this.display = display;
this.parameters = parameters;
this.returnType = returnType;
this.executionFactory = executionFactory;
}
public static <R> InstructionType<R> create(GuiDisplay display, Supplier<InstructionExecution<R>> executionFactory, ValueType<R> returnType, Collection<Parameter<?>> parameters) {
return new InstructionType<>(display, executionFactory, returnType, List.copyOf(parameters));
}
public static <R> InstructionType<R> create(GuiDisplay display, Supplier<InstructionExecution<R>> executionFactory, ValueType<R> returnType, Parameter<?>... parameters) {
return new InstructionType<>(display, executionFactory, returnType, List.of(parameters));
}
public Collection<Parameter<?>> getParameters() {
return parameters;
}
public ValueType<R> getReturnType() {
return returnType;
}
public GuiDisplay getDisplay() {
return display;
}
public InstructionExecution<R> createExecution(ArgumentList parameters, MinionFakePlayer minion) {
InstructionExecution<R> execution = executionFactory.get();
execution.readArguments(parameters, minion);
return execution;
}
public InstructionExecution<R> loadExecution(ReadView view, MinionFakePlayer minion) {
InstructionExecution<R> execution = executionFactory.get();
execution.load(view, minion);
return execution;
}
}
@@ -0,0 +1,43 @@
package io.github.skippyall.minions.new_program.instruction;
import io.github.skippyall.minions.MinionRegistries;
import io.github.skippyall.minions.Minions;
import io.github.skippyall.minions.gui.GuiDisplay;
import io.github.skippyall.minions.new_program.instruction.execution.WalkExecution;
import io.github.skippyall.minions.new_program.argument.Parameter;
import io.github.skippyall.minions.new_program.value.ValueType;
import io.github.skippyall.minions.new_program.value.ValueTypes;
import io.github.skippyall.minions.util.ModelIdUtil;
import net.minecraft.item.Items;
import net.minecraft.registry.Registry;
import net.minecraft.util.Identifier;
import java.util.function.Function;
import java.util.function.Supplier;
public class Instructions {
public static final InstructionType<Void> WALK = register(
"walk",
base -> new GuiDisplay.ModelBased(ModelIdUtil.getItemModelId(Items.IRON_BOOTS), base, true),
WalkExecution::new,
ValueTypes.VOID,
WalkExecution.blocksToMoveParam
);
public static final InstructionType<Void> ATTACK = register(
"attack",
base -> new GuiDisplay.ModelBased(ModelIdUtil.getItemModelId(Items.IRON_PICKAXE), base, true),
WalkExecution::new,
ValueTypes.VOID,
WalkExecution.blocksToMoveParam
);
private static <R> InstructionType<R> register(String id, Function<String, GuiDisplay> displayFunction, Supplier<InstructionExecution<R>> factory, ValueType<R> returnType, Parameter<?>... parameters) {
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));
}
public static void register() {
}
}
@@ -0,0 +1,35 @@
package io.github.skippyall.minions.new_program.instruction.execution;
import io.github.skippyall.minions.minion.fakeplayer.EntityPlayerActionPack;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.new_program.argument.ArgumentList;
import net.minecraft.storage.ReadView;
import net.minecraft.storage.WriteView;
public class ActionExecution implements ContinuousInstructionExecution<Void> {
private final EntityPlayerActionPack.ActionType action;
public ActionExecution(EntityPlayerActionPack.ActionType action) {
this.action = action;
}
@Override
public void start(MinionFakePlayer minion) {
minion.getMinionActionPack().start(action, EntityPlayerActionPack.Action.continuous());
}
@Override
public Void stop(MinionFakePlayer minion) {
minion.getMinionActionPack().stop(action);
return null;
}
@Override
public void readArguments(ArgumentList parameters, MinionFakePlayer minion) {}
@Override
public void save(WriteView view, MinionFakePlayer minion) {}
@Override
public void load(ReadView view, MinionFakePlayer minion) {}
}
@@ -0,0 +1,11 @@
package io.github.skippyall.minions.new_program.instruction.execution;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.new_program.instruction.InstructionExecution;
public interface ContinuousInstructionExecution<R> extends InstructionExecution<R> {
@Override
default boolean isDone(MinionFakePlayer minion) {
return false;
}
}
@@ -0,0 +1,43 @@
package io.github.skippyall.minions.new_program.instruction.execution;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.new_program.instruction.InstructionExecution;
import net.minecraft.storage.ReadView;
import net.minecraft.storage.WriteView;
/**
* An <code>InstructionExecution</code> that takes a predefined time to execute.
* 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.
*/
public abstract class TimedInstructionExecution<T> implements InstructionExecution<T> {
int timer;
public int getTimer() {
return timer;
}
protected void setTimer(int timer) {
this.timer = timer;
}
@Override
public void tick(MinionFakePlayer minion) {
timer--;
}
@Override
public boolean isDone(MinionFakePlayer minion) {
return timer > 0;
}
@Override
public void save(WriteView view, MinionFakePlayer minion) {
view.putInt("timer", timer);
}
@Override
public void load(ReadView view, MinionFakePlayer minion) {
timer = view.getInt("timer", 0);
}
}
@@ -0,0 +1,67 @@
package io.github.skippyall.minions.new_program.instruction.execution;
import com.mojang.serialization.Codec;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.new_program.argument.ArgumentList;
import io.github.skippyall.minions.new_program.instruction.InstructionExecution;
import net.minecraft.storage.ReadView;
import net.minecraft.storage.WriteView;
import net.minecraft.util.StringIdentifiable;
public class TurnExecution implements InstructionExecution<Void> {
@Override
public void start(MinionFakePlayer minion) {
InstructionExecution.super.start(minion);
}
@Override
public boolean isDone(MinionFakePlayer minion) {
return false;
}
@Override
public Void stop(MinionFakePlayer minion) {
return null;
}
@Override
public void readArguments(ArgumentList arguments, MinionFakePlayer minion) {
}
@Override
public void save(WriteView view, MinionFakePlayer minion) {
}
@Override
public void load(ReadView view, MinionFakePlayer minion) {
}
public enum TurnDirection implements StringIdentifiable {
LEFT("left", -1, 0),
UP("up", 0, -1),
RIGHT("right", 1, 0),
DOWN("down", 0, 1);
public static final Codec<TurnDirection> CODEC = StringIdentifiable.createCodec(TurnDirection::values);
public final String name;
public final int xFactor;
public final int yFactor;
TurnDirection(String name, int xFactor, int yFactor) {
this.xFactor = xFactor;
this.yFactor = yFactor;
this.name = name;
}
@Override
public String asString() {
return name;
}
}
}
@@ -0,0 +1,53 @@
package io.github.skippyall.minions.new_program.instruction.execution;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.new_program.instruction.InstructionExecution;
import io.github.skippyall.minions.new_program.argument.Parameter;
import io.github.skippyall.minions.new_program.argument.ArgumentList;
import io.github.skippyall.minions.new_program.value.ValueTypes;
import net.minecraft.entity.MovementType;
import net.minecraft.storage.ReadView;
import net.minecraft.storage.WriteView;
public class WalkExecution implements InstructionExecution<Void> {
public static final Parameter<Float> blocksToMoveParam = new Parameter<>("blocksToMove", ValueTypes.FLOAT);
private final float ACCURACY = 1F / 32F;
private float totalBlocksToMove;
private float blocksMoved;
@Override
public void tick(MinionFakePlayer minion) {
float speed = Math.min(minion.getMovementSpeed(), totalBlocksToMove - blocksMoved);
minion.move(MovementType.SELF, minion.getHorizontalFacing().getDoubleVector().normalize().multiply(speed));
blocksMoved += speed;
}
@Override
public boolean isDone(MinionFakePlayer minion) {
return totalBlocksToMove - blocksMoved < ACCURACY;
}
@Override
public Void stop(MinionFakePlayer minion) {
return null;
}
@Override
public void readArguments(ArgumentList parameters, MinionFakePlayer minion) {
totalBlocksToMove = parameters.getValue(blocksToMoveParam, minion);
blocksMoved = 0;
}
@Override
public void save(WriteView view, MinionFakePlayer minion) {
view.putFloat("totalBlocksToMove", totalBlocksToMove);
view.putFloat("blocksMoved", blocksMoved);
}
@Override
public void load(ReadView view, MinionFakePlayer minion) {
totalBlocksToMove = view.getFloat("totalBlocksToMove", 0F);
blocksMoved = view.getFloat("blocksMoved", 0F);
}
}
@@ -1,20 +0,0 @@
package io.github.skippyall.minions.new_program.value;
import com.mojang.serialization.Codec;
import io.github.skippyall.minions.input.TextInput;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import java.util.concurrent.CompletableFuture;
public class FloatValueType implements ValueType<Float> {
@Override
public Codec<Float> getCodec() {
return Codec.FLOAT;
}
@Override
public CompletableFuture<Float> openValueDialog(ServerPlayerEntity player, Float previousValue) {
return TextInput.inputFloat(player, Text.literal("Please enter a decimal number."), previousValue.toString());
}
}
@@ -1,20 +0,0 @@
package io.github.skippyall.minions.new_program.value;
import com.mojang.serialization.Codec;
import io.github.skippyall.minions.input.TextInput;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import java.util.concurrent.CompletableFuture;
public class IntegerValueType implements ValueType<Integer> {
@Override
public Codec<Integer> getCodec() {
return Codec.INT;
}
@Override
public CompletableFuture<Integer> openValueDialog(ServerPlayerEntity player, Integer previousValue) {
return TextInput.inputInt(player, Text.literal("Please enter an integer number."), previousValue.toString());
}
}
@@ -1,12 +1,14 @@
package io.github.skippyall.minions.new_program.value; package io.github.skippyall.minions.new_program.value;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import io.github.skippyall.minions.gui.GuiDisplay;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.function.BiFunction;
public interface ValueType<T> { public record ValueType<T>(Codec<T> codec, GuiDisplay display, T defaultValue, BiFunction<ServerPlayerEntity, T, CompletableFuture<T>> valueDialogOpener) {
Codec<T> getCodec(); public CompletableFuture<T> openValueDialog(ServerPlayerEntity player, T previousValue) {
return valueDialogOpener.apply(player, previousValue);
CompletableFuture<T> openValueDialog(ServerPlayerEntity player, T previousValue); }
} }
@@ -0,0 +1,78 @@
package io.github.skippyall.minions.new_program.value;
import com.mojang.serialization.Codec;
import io.github.skippyall.minions.MinionRegistries;
import io.github.skippyall.minions.Minions;
import io.github.skippyall.minions.gui.GuiDisplay;
import io.github.skippyall.minions.input.TextInput;
import net.minecraft.item.Items;
import net.minecraft.registry.Registry;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiFunction;
import java.util.function.Function;
public class ValueTypes {
public static ValueType<Integer> INTEGER = registerSimple(
"integer",
Codec.INT,
key -> new GuiDisplay.ModelBased(Items.NETHERITE_SCRAP, key, true),
0,
(player, oldValue) -> TextInput.inputInt(
player,
Text.literal("Integer"),
String.valueOf(oldValue)
)
);
public static ValueType<Float> FLOAT = registerSimple(
"float",
Codec.FLOAT,
key -> new GuiDisplay.ModelBased(Items.BAMBOO_RAFT, key, true),
0F,
(player, oldValue) -> TextInput.inputFloat(
player,
Text.literal("Number"),
String.valueOf(oldValue)
)
);
public static ValueType<String> STRING = registerSimple(
"string",
Codec.STRING,
key -> new GuiDisplay.ModelBased(Items.STRING, key, true),
"",
((player, oldValue) -> TextInput.inputString(
player,
Text.literal("Text"),
oldValue)
)
);
public static ValueType<Void> VOID = registerSimple(
"void",
Codec.unit(null),
key -> new GuiDisplay.ModelBased(Items.BARRIER, key, false),
null,
(player, oldValue) -> CompletableFuture.completedFuture(null)
);
private static <T> ValueType<T> registerSimple(String id, Codec<T> codec, Function<String, GuiDisplay> displayFunction, T defaultValue, BiFunction<ServerPlayerEntity, T, CompletableFuture<T>> valueDialogOpener) {
Identifier identifier = Identifier.of(Minions.MOD_ID, id);
return Registry.register(
MinionRegistries.VALUE_TYPES,
identifier,
new ValueType<>(
codec,
displayFunction.apply(identifier.toTranslationKey("value_type")),
defaultValue,
valueDialogOpener
)
);
}
public static void register() {}
}
@@ -1,9 +0,0 @@
package io.github.skippyall.minions.program.argument;
import io.github.skippyall.minions.program.runtime.ProgramRuntime;
import io.github.skippyall.minions.program.variables.Type;
public interface Arg<T> {
T resolve(ProgramRuntime runtime);
Type<T> getType();
}
@@ -1,16 +0,0 @@
package io.github.skippyall.minions.program.argument;
import io.github.skippyall.minions.program.runtime.ProgramRuntime;
import io.github.skippyall.minions.program.tuple.Tuple;
import io.github.skippyall.minions.program.tuple.Tuple0;
public class ArgUtils {
public static Tuple resolveArgs(Tuple args, ProgramRuntime runtime) {
Tuple tuple = new Tuple0();
for(Object object : args) {
Arg<?> arg =(Arg<?>) object;
tuple = tuple.add(arg.getType().cast(arg.resolve(runtime)));
}
return tuple;
}
}
@@ -1,34 +0,0 @@
package io.github.skippyall.minions.program.block;
import io.github.skippyall.minions.program.argument.Arg;
import io.github.skippyall.minions.program.runtime.ProgramRuntime;
import io.github.skippyall.minions.program.statement.Statement;
import io.github.skippyall.minions.program.tuple.Tuple;
import io.github.skippyall.minions.program.variables.Type;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
public abstract class CodeBlock<R, A extends Tuple> {
private String name;
private final List<Type<?>> arguments;
private final Type<?> returnType;
public CodeBlock(String name, List<Type<?>> arguments, Type<?> returnType) {
this.arguments = arguments;
this.returnType = returnType;
}
protected abstract R execute(ProgramRuntime runtime, A args, Statement<R,A>.Run run);
public boolean fits(Arg<?> arg, int slot) {
return arguments.get(slot) == arg.getType();
}
public void start(ProgramRuntime runtime, A args, Statement<R,A>.Run run) {
ForkJoinPool.commonPool().execute(() -> {
R result = execute(runtime, args, run);
run.afterRun(result);
});
}
}
@@ -1,5 +0,0 @@
package io.github.skippyall.minions.program.block;
public class CodeBlocks {
public static final GoBlock GO = new GoBlock();
}
@@ -1,15 +0,0 @@
package io.github.skippyall.minions.program.block;
import io.github.skippyall.minions.program.variables.Type;
import java.util.List;
public abstract class CodeContainingCodeBlock extends CodeBlock{
public CodeContainingCodeBlock(String name, List<Type> arguments, Type returnType) {
super(name, arguments, returnType);
}
protected void executeBlocks() {
}
}
@@ -1,27 +0,0 @@
package io.github.skippyall.minions.program.block;
import io.github.skippyall.minions.minion.fakeplayer.EntityPlayerActionPack;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.program.runtime.MinionRuntime;
import io.github.skippyall.minions.program.runtime.ProgramRuntime;
import io.github.skippyall.minions.program.statement.Statement;
import io.github.skippyall.minions.program.tuple.Tuple2;
import io.github.skippyall.minions.program.variables.Types;
import java.util.List;
public class GoBlock extends CodeBlock<Void, Tuple2<Float, Float>> {
public GoBlock() {
super("move", List.of(Types.FLOAT, Types.FLOAT), Types.VOID);
}
public Void execute(ProgramRuntime runtime, Tuple2<Float, Float> args, Statement<Void, Tuple2<Float, Float>>.Run run) {
if(runtime instanceof MinionRuntime minionRuntime) {
MinionFakePlayer minion = minionRuntime.getMinion();
EntityPlayerActionPack action = ((ServerPlayerInterface) minion).minions$getActionPack();
minion.moveForward(args.v0());
minion.moveSideways(args.v1());
}
return null;
}
}
@@ -1,26 +0,0 @@
package io.github.skippyall.minions.program.block;
import io.github.skippyall.minions.minion.fakeplayer.EntityPlayerActionPack;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.program.runtime.MinionRuntime;
import io.github.skippyall.minions.program.runtime.ProgramRuntime;
import io.github.skippyall.minions.program.statement.Statement;
import io.github.skippyall.minions.program.tuple.Tuple0;
import io.github.skippyall.minions.program.variables.Types;
import java.util.List;
public class UseBlock extends CodeBlock<Void, Tuple0>{
public UseBlock(String name) {
super("use", List.of(), Types.VOID);
}
@Override
public Void execute(ProgramRuntime runtime, Tuple0 args, Statement<Void,Tuple0>.Run run) {
if(runtime instanceof MinionRuntime minionRuntime) {
MinionFakePlayer minion = minionRuntime.getMinion();
minion.getMinionActionPack().start(EntityPlayerActionPack.ActionType.USE, EntityPlayerActionPack.Action.once());
}
return null;
}
}
@@ -1,15 +0,0 @@
package io.github.skippyall.minions.program.runtime;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
public class MinionRuntime extends ProgramRuntime {
private final MinionFakePlayer minion;
public MinionRuntime(MinionFakePlayer minion) {
this.minion = minion;
}
public MinionFakePlayer getMinion() {
return minion;
}
}
@@ -1,42 +0,0 @@
package io.github.skippyall.minions.program.runtime;
import io.github.skippyall.minions.program.statement.StatementList;
import java.util.HashMap;
import java.util.Map;
public abstract class ProgramRuntime {
private final Map<String, Object> variables = new HashMap<>();
private StatementList statements;
private StatementList.Run run;
public ProgramRuntime() {
this(new StatementList());
}
public ProgramRuntime(StatementList statements) {
this.statements = statements;
}
public void start() {
run = statements.start(this);
}
public void tick() {
if(run != null) {
run.tick();
}
}
public StatementList getStatementList() {
return statements;
}
public Object getVariable(String name) {
return variables.get(name);
}
public void setVariable(String name, Object value) {
variables.put(name, value);
}
}
@@ -1,73 +0,0 @@
package io.github.skippyall.minions.program.statement;
import io.github.skippyall.minions.program.argument.ArgUtils;
import io.github.skippyall.minions.program.block.CodeBlock;
import io.github.skippyall.minions.program.runtime.ProgramRuntime;
import io.github.skippyall.minions.program.tuple.Tuple;
import io.github.skippyall.minions.program.variables.ValueStorage;
public record Statement<R,A extends Tuple>(CodeBlock<R,A> codeBlock, A args, ValueStorage<R> valueStorage) {
@SuppressWarnings("unchecked")
public Run start(ProgramRuntime runtime) {
Run run = new Run(runtime);
codeBlock.start(runtime, (A) ArgUtils.resolveArgs(args, runtime), run);
return run;
}
public class Run {
private boolean running = false;
private boolean waiting = false;
private boolean afterRun = false;
private R cachedResult;
private int ticksRunning = 0;
private int ticksLeft = 0;
private final ProgramRuntime runtime;
Run(ProgramRuntime runtime) {
this.runtime = runtime;
}
public boolean isDone() {
return !running;
}
public void tick() {
if(running) {
ticksRunning ++;
ticksLeft --;
if(ticksLeft == 0 && waiting && afterRun) {
complete(cachedResult);
}
}
}
public void afterRun(R result) {
afterRun = true;
if(ticksLeft == 0) {
complete(result);
}
}
private void complete(R result) {
if(valueStorage != null) {
valueStorage.storeValue(result, runtime);
}
running = false;
waiting = false;
cachedResult = null;
ticksRunning = 0;
ticksLeft = 0;
}
public void completeAfter(int ticks, R value) {
waiting = true;
ticksLeft = ticks;
cachedResult = value;
}
public int getTicksRunning() {
return ticksRunning;
}
}
}
@@ -1,50 +0,0 @@
package io.github.skippyall.minions.program.statement;
import io.github.skippyall.minions.program.runtime.ProgramRuntime;
import java.util.Iterator;
import java.util.List;
public class StatementList {
private final List<Statement<?,?>> statements;
public StatementList() {
this.statements = List.of();
}
public StatementList(List<Statement<?,?>> statements) {
this.statements = List.copyOf(statements);
}
public Run start(ProgramRuntime runtime) {
return new Run(runtime);
}
public class Run {
final ProgramRuntime runtime;
final Iterator<Statement<?,?>> iterator;
Statement<?,?>.Run run;
public Run(ProgramRuntime runtime) {
this.runtime = runtime;
iterator = statements.iterator();
startNext();
}
private boolean startNext() {
if(iterator.hasNext()) {
run = iterator.next().start(runtime);
return true;
} else {
return false;
}
}
public void tick() {
run.tick();
if(run.isDone()){
startNext();
}
}
}
}
@@ -1,29 +0,0 @@
package io.github.skippyall.minions.program.tuple;
import org.jetbrains.annotations.NotNull;
import java.util.Iterator;
import java.util.List;
public interface Tuple extends Iterable<Object>{
<T> Tuple add(T value);
Tuple removeLast();
List<Object> getValueList();
int size();
@NotNull
@Override
default Iterator<Object> iterator() {
return getValueList().iterator();
}
static Tuple ofList(List<?> list) {
return switch (list.size()) {
case 0 -> new Tuple0();
case 1 -> new Tuple1<Object>(list.get(0));
case 2 -> new Tuple2<Object, Object>(list.get(0), list.get(1));
case 3 -> new Tuple3<Object, Object, Object>(list.get(0), list.get(1), list.get(2));
default -> throw new UnsupportedOperationException();
};
}
}
@@ -1,25 +0,0 @@
package io.github.skippyall.minions.program.tuple;
import java.util.List;
public record Tuple0() implements Tuple{
@Override
public <T> Tuple add(T value) {
return new Tuple1<>(value);
}
@Override
public Tuple removeLast() {
throw new UnsupportedOperationException("Cannot remove element from length 0 tuple.");
}
@Override
public List<Object> getValueList() {
return List.of();
}
@Override
public int size() {
return 0;
}
}
@@ -1,25 +0,0 @@
package io.github.skippyall.minions.program.tuple;
import java.util.List;
public record Tuple1<T0>(T0 v0) implements Tuple{
@Override
public <T> Tuple add(T value) {
return new Tuple2<>(v0, value);
}
@Override
public Tuple removeLast() {
return new Tuple0();
}
@Override
public List<Object> getValueList() {
return List.of(v0);
}
@Override
public int size() {
return 1;
}
}
@@ -1,25 +0,0 @@
package io.github.skippyall.minions.program.tuple;
import java.util.List;
public record Tuple2<T0, T1>(T0 v0, T1 v1) implements Tuple {
@Override
public <T> Tuple add(T value) {
return new Tuple3<>(v0, v1, value);
}
@Override
public Tuple removeLast() {
return new Tuple1<>(v0);
}
@Override
public List<Object> getValueList() {
return List.of(v0, v1);
}
@Override
public int size() {
return 2;
}
}
@@ -1,25 +0,0 @@
package io.github.skippyall.minions.program.tuple;
import java.util.List;
public record Tuple3<T0, T1, T2>(T0 v0, T1 v1, T2 v2) implements Tuple {
@Override
public <T> Tuple add(T value) {
return new Tuple4<>(v0, v1, v2, value);
}
@Override
public Tuple removeLast() {
return new Tuple2<>(v0, v1);
}
@Override
public List<Object> getValueList() {
return List.of(v0, v1, v2);
}
@Override
public int size() {
return 3;
}
}
@@ -1,25 +0,0 @@
package io.github.skippyall.minions.program.tuple;
import java.util.List;
public record Tuple4<T0, T1, T2, T3, T4>(T0 v0, T1 v1, T2 v2, T3 v3) implements Tuple {
@Override
public <T> Tuple add(T value) {
return new Tuple5<>(v0, v1, v2, v3, value);
}
@Override
public Tuple removeLast() {
return new Tuple3<>(v0, v1, v2);
}
@Override
public List<Object> getValueList() {
return List.of(v0, v1, v2, v3);
}
@Override
public int size() {
return 4;
}
}
@@ -1,25 +0,0 @@
package io.github.skippyall.minions.program.tuple;
import java.util.List;
public record Tuple5<T0, T1, T2, T3, T4>(T0 v0, T1 v1, T2 v2, T3 v3, T4 v4) implements Tuple {
@Override
public <T> Tuple add(T value) {
throw new UnsupportedOperationException("Cannot add element to length 5 tuple.");
}
@Override
public Tuple removeLast() {
return new Tuple4<>(v0, v1, v2, v3);
}
@Override
public List<Object> getValueList() {
return List.of(v0, v1, v2, v3, v4);
}
@Override
public int size() {
return 5;
}
}
@@ -1,4 +0,0 @@
package io.github.skippyall.minions.program.variables;
public class FloatType extends Type<Float>{
}
@@ -1,4 +0,0 @@
package io.github.skippyall.minions.program.variables;
public class IntegerType extends Type<Integer>{
}
@@ -1,8 +0,0 @@
package io.github.skippyall.minions.program.variables;
public abstract class Type<T> {
@SuppressWarnings("unchecked")
public T cast(Object object) throws ClassCastException {
return (T) object;
}
}
@@ -1,7 +0,0 @@
package io.github.skippyall.minions.program.variables;
public class Types {
public static final IntegerType INTEGER = new IntegerType();
public static final FloatType FLOAT = new FloatType();
public static final Type<Void> VOID = new Type<>() {};
}
@@ -1,7 +0,0 @@
package io.github.skippyall.minions.program.variables;
import io.github.skippyall.minions.program.runtime.ProgramRuntime;
public interface ValueStorage<T> {
void storeValue(T value, ProgramRuntime runtime);
}
@@ -1,29 +0,0 @@
package io.github.skippyall.minions.program.variables;
import io.github.skippyall.minions.program.argument.Arg;
import io.github.skippyall.minions.program.runtime.ProgramRuntime;
public class Variable<T> implements Arg<T>, ValueStorage<T> {
private final Type<T> type;
private final String name;
public Variable(Type<T> type, String name) {
this.type = type;
this.name = name;
}
@Override
public T resolve(ProgramRuntime runtime) {
return type.cast(runtime.getVariable(name));
}
@Override
public Type<T> getType() {
return type;
}
@Override
public void storeValue(T value, ProgramRuntime runtime) {
runtime.setVariable(name, value);
}
}
@@ -0,0 +1,12 @@
package io.github.skippyall.minions.util;
import net.minecraft.item.Item;
import net.minecraft.registry.Registries;
import net.minecraft.util.Identifier;
public class ModelIdUtil {
public static Identifier getItemModelId(Item item) {
Identifier identifier = Registries.ITEM.getId(item);
return identifier.withPrefixedPath("item/");
}
}
@@ -0,0 +1,26 @@
package io.github.skippyall.minions.util;
import net.minecraft.registry.Registry;
import net.minecraft.util.Identifier;
public class TranslationUtil {
public static <T> String getTranslationKey(T object, Registry<T> registry, String defaultKey) {
return getTranslationKey(object, registry, registry.getKey().getValue().getPath(), defaultKey);
}
public static <T> String getTranslationKey(T object, Registry<T> registry, String prefix, String defaultKey) {
if(object == null) {
return defaultKey;
}
Identifier id = registry.getId(object);
if(id == null) {
return defaultKey;
}
return id.toTranslationKey(prefix);
}
public static <T> String getTranslationKey(T object, Registry<T> registry) {
return getTranslationKey(object, registry, "minions.generic.unknown");
}
}
@@ -15,6 +15,8 @@
"minions.gui.look.skin.base64": "Base64", "minions.gui.look.skin.base64": "Base64",
"minions.gui.look.skin.base64.title": "Enter a skin in base64 encoding", "minions.gui.look.skin.base64.title": "Enter a skin in base64 encoding",
"minions.gui.look.rename.title": "Enter a name", "minions.gui.look.rename.title": "Enter a name",
"minions.gui.instruction.no_instruction_set": "No instruction set",
"minions.gui.instruction.enter_name": "Enter a name",
"minions.command.input.int.fail": "Not an integer", "minions.command.input.int.fail": "Not an integer",
"minions.command.input.float.fail": "Not a number", "minions.command.input.float.fail": "Not a number",
@@ -29,6 +31,8 @@
"minions.command.attack.name": "Attack", "minions.command.attack.name": "Attack",
"minions.command.attack.description": "Attack and mine blocks", "minions.command.attack.description": "Attack and mine blocks",
"minions.command.minion.not_present": "This minion does not exist",
"item.minions.attack_module": "Attack Module", "item.minions.attack_module": "Attack Module",
"item.minions.interact_module": "Interact Module", "item.minions.interact_module": "Interact Module",
"item.minions.mob_spawning_module": "Mob Spawning Module", "item.minions.mob_spawning_module": "Mob Spawning Module",
@@ -44,5 +48,6 @@
"minions.generic.name.invalid": "Name is invalid", "minions.generic.name.invalid": "Name is invalid",
"minions.generic.name.taken": "This name is already used", "minions.generic.name.taken": "This name is already used",
"minions.generic.mod_name": "Minions", "minions.generic.mod_name": "Minions",
"minions.command.minion.not_present": "This minion does not exist" "minions.generic.unknown": "Unknown",
"minions.gui.instruction.no_argument_set": "No argument set"
} }
@@ -0,0 +1,5 @@
{
"instructions": [
"minions:walk"
]
}