diff --git a/src/generated/resources/data/advancedperipherals/computercraft/turtle_upgrade/pattern_turtle.json b/src/generated/resources/data/advancedperipherals/computercraft/turtle_upgrade/pattern_turtle.json new file mode 100644 index 000000000..21b79a957 --- /dev/null +++ b/src/generated/resources/data/advancedperipherals/computercraft/turtle_upgrade/pattern_turtle.json @@ -0,0 +1,4 @@ +{ + "type": "advancedperipherals:pattern_turtle", + "item": "refinedstorage:pattern_grid" +} \ No newline at end of file diff --git a/src/main/java/de/srendi/advancedperipherals/client/ClientRegistry.java b/src/main/java/de/srendi/advancedperipherals/client/ClientRegistry.java index ece61b712..ecdffb6ba 100644 --- a/src/main/java/de/srendi/advancedperipherals/client/ClientRegistry.java +++ b/src/main/java/de/srendi/advancedperipherals/client/ClientRegistry.java @@ -24,6 +24,7 @@ public static void menuRegister(RegisterMenuScreensEvent event) { public static void onUpgradeModeller(RegisterTurtleModellersEvent event) { event.register(CCRegistration.CHUNKY_TURTLE.get(), TurtleUpgradeModeller.flatItem()); event.register(CCRegistration.COMPASS_TURTLE.get(), TurtleUpgradeModeller.flatItem()); + event.register(CCRegistration.PATTERN_TURTLE.get(), TurtleUpgradeModeller.sided(AdvancedPeripherals.getRL("block/turtle_pattern_left"), AdvancedPeripherals.getRL("block/turtle_pattern_right"))); event.register(CCRegistration.CHAT_BOX_TURTLE.get(), TurtleUpgradeModeller.sided(AdvancedPeripherals.getRL("block/turtle_chatty_left"), AdvancedPeripherals.getRL("block/turtle_chatty_right"))); event.register(CCRegistration.ENVIRONMENT_TURTLE.get(), TurtleUpgradeModeller.sided(AdvancedPeripherals.getRL("block/turtle_environment_left"), AdvancedPeripherals.getRL("block/turtle_environment_right"))); event.register(CCRegistration.GEO_SCANNER_TURTLE.get(), TurtleUpgradeModeller.sided(AdvancedPeripherals.getRL("block/turtle_geoscanner_left"), AdvancedPeripherals.getRL("block/turtle_geoscanner_right"))); diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/PatternGridPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/PatternGridPeripheral.java new file mode 100644 index 000000000..23f399d85 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/PatternGridPeripheral.java @@ -0,0 +1,305 @@ +package de.srendi.advancedperipherals.common.addons.computercraft.peripheral; + +import com.refinedmods.refinedstorage.api.autocrafting.Pattern; +import com.refinedmods.refinedstorage.api.resource.ResourceAmount; +import com.refinedmods.refinedstorage.api.resource.ResourceKey; +import com.refinedmods.refinedstorage.common.api.autocrafting.PatternProviderItem; +import com.refinedmods.refinedstorage.common.autocrafting.CraftingPatternState; +import com.refinedmods.refinedstorage.common.autocrafting.PatternState; +import com.refinedmods.refinedstorage.common.autocrafting.ProcessingPatternState; +import com.refinedmods.refinedstorage.common.autocrafting.patterngrid.PatternType; +import com.refinedmods.refinedstorage.common.content.DataComponents; +import com.refinedmods.refinedstorage.common.content.Items; +import com.refinedmods.refinedstorage.common.support.resource.FluidResource; +import com.refinedmods.refinedstorage.common.support.resource.ItemResource; + +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.api.lua.LuaTable; +import dan200.computercraft.api.lua.MethodResult; +import dan200.computercraft.api.lua.ObjectLuaTable; +import dan200.computercraft.api.turtle.ITurtleAccess; +import dan200.computercraft.api.turtle.TurtleSide; +import de.srendi.advancedperipherals.common.addons.APAddon; +import de.srendi.advancedperipherals.common.addons.computercraft.owner.TurtlePeripheralOwner; +import de.srendi.advancedperipherals.common.addons.refinedstorage.RSApi; +import de.srendi.advancedperipherals.common.configuration.APConfig; +import de.srendi.advancedperipherals.lib.peripherals.BasePeripheral; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.Container; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.CraftingInput; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.Fluids; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +public class PatternGridPeripheral extends BasePeripheral { + + public static final String PERIPHERAL_TYPE = "pattern_grid"; + + protected PatternGridPeripheral(TurtlePeripheralOwner owner) { + super(PERIPHERAL_TYPE, owner); + } + + public PatternGridPeripheral(ITurtleAccess turtle, TurtleSide side) { + this(new TurtlePeripheralOwner(turtle, side)); + } + + @Override + public boolean isEnabled() { + return APAddon.REFINEDSTORAGE.isLoaded() && APConfig.PERIPHERALS_CONFIG.enablePatternGridTurtle.get(); + } + + /** + * Returns information about a pattern, in the style of the RS Bridge ".getPattern()" method. + * + * @param target the pattern item to examine + * @return a Map containing the properties as returned by the RSApi + * @throws IllegalArgumentException if the item isn't a pattern + * @throws IllegalStateException if the pattern is blank + */ + public Map getDetailsForItem(ItemStack target) throws IllegalArgumentException, IllegalStateException { + if (!target.is(Items.INSTANCE.getPattern())) { + throw new IllegalArgumentException("Not a pattern"); + } + + Optional pattern = Optional.empty(); + if (target.getItem() instanceof PatternProviderItem patternProvider) { + pattern = patternProvider.getPattern(target, this.getLevel()); + } + + if (pattern.isEmpty()) { + throw new IllegalStateException("Pattern is blank"); + } + + return RSApi.parsePattern(pattern.get(), null); + } + + @LuaFunction(mainThread = true) + public MethodResult getDetails(Optional slot) { + try { + ITurtleAccess turtle = this.getPeripheralOwner().getTurtle(); + // Note: the hack at the end of the line here converts between CC slot numbering (from 1) to Java slot numbering (from 0). + // It's broken out like this so we can call getDetailsForItem from the builder functions later, and not have to care + // what Lua thinks about array indexing. + ItemStack target = turtle.getInventory().getItem(slot.orElse(turtle.getSelectedSlot() + 1) - 1); + return MethodResult.of(getDetailsForItem(target)); + } catch (IllegalStateException | IllegalArgumentException e) { + return MethodResult.of(false, e.getMessage()); + } + } + + // ----------------------------------------------------------------------------------------------------------------- + + /** + * Ensures that a slot contains patterns. + * + * @param slot the slot number to look in + * @return how many patterns are in the slot + * @throws IllegalStateException if the slot doesn't contain any patterns + */ + private int verifyPatternsInSlot(int slot) throws IllegalStateException { + Container turtleInventory = this.getPeripheralOwner().getTurtle().getInventory(); + ItemStack selected = turtleInventory.getItem(slot); + if (selected.is(Items.INSTANCE.getPattern()) && selected.getCount() > 0) { + return selected.getCount(); + } else { + // TODO: do I even care to do this here + throw new IllegalStateException("No pattern available"); + } + } + + /** + * Finds a free slot in which to insert the result of a pattern build. + * + * @param source the slot containing our source pattern + * @return which slot to store the built pattern in + * @throws IllegalStateException if there are no free slots in the turtle + */ + private int getFreeSlotAfterBuild(int source) throws IllegalStateException { + // We assume that we'll consume one of whatever is in the source slot. + Container turtleInventory = this.getPeripheralOwner().getTurtle().getInventory(); + + if (turtleInventory.getItem(source).getCount() <= 1) { + // We're using the last of something, so feel free to take its place. + return source; + } else { + // Otherwise... are there any free slots? + for (int i = 0; i < turtleInventory.getContainerSize(); i++) { + if (turtleInventory.getItem(i).getCount() == 0) { + return i; + } + } + // Turtle's full, keep movin' + throw new IllegalStateException("No room in destination"); + } + } + + /** + * Attempts to match a String resource name to an ItemResource or FluidResource. + * + * @param name the resource name + * @return a ResourceKey representing the resource + * @throws IllegalArgumentException if the name doesn't match a resource + */ + private ResourceKey parseResourceName(String name) throws IllegalArgumentException { + ResourceLocation location = ResourceLocation.parse(name); + // Try as item first + Item item = BuiltInRegistries.ITEM.get(location); + // The parser seems to be greedy... sometimes it'll map an invalid Item to air. Make sure it behaves. + if (!item.equals(net.minecraft.world.item.Items.AIR)) { + return new ItemResource(item); + } + // Try as fluid + Fluid fluid = BuiltInRegistries.FLUID.get(location); + if (!fluid.equals(Fluids.EMPTY)) { + return new FluidResource(fluid); + } + throw new IllegalArgumentException("Couldn't find item or fluid: " + name); + } + + // ----------------------------------------------------------------------------------------------------------------- + + // Build a crafting pattern from a table of slots. + @LuaFunction(mainThread = true) + public MethodResult buildCrafting(Map recipeInput, Optional fuzzy) { + ITurtleAccess turtle = this.getPeripheralOwner().getTurtle(); + + try { + verifyPatternsInSlot(turtle.getSelectedSlot()); + int destinationSlot = getFreeSlotAfterBuild(turtle.getSelectedSlot()); + + ItemStack patternStack = new ItemStack(Items.INSTANCE.getPattern()); + PatternState patternState = new PatternState(UUID.randomUUID(), PatternType.CRAFTING); + patternStack.set(DataComponents.INSTANCE.getPatternState(), patternState); + + List ingredients = new ArrayList<>(Collections.nCopies(9, ItemStack.EMPTY)); + + for (Object o : recipeInput.keySet()) { + // Note: I'm assuming that Lua returns all numbers as doubles. + // Only care about slots 1 through 9 in the input; we'll just ignore everything else. + if (o instanceof Double) { + int slot = ((Double) o).intValue() - 1; + if (slot >= 0 && slot < 9) { + if (recipeInput.get(o) instanceof String) { + ingredients.set(slot, ((ItemResource) parseResourceName((String) recipeInput.get(o))).toItemStack()); + } else { + return MethodResult.of(false, "Couldn't parse item in slot " + slot); + } + } + } + } + + CraftingInput craftingInput = CraftingInput.of(3, 3, ingredients); + CraftingInput.Positioned positioned = new CraftingInput.Positioned(craftingInput, 0, 0); + CraftingPatternState craftingState = new CraftingPatternState(fuzzy.orElse(false), positioned); + patternStack.set(DataComponents.INSTANCE.getCraftingPatternState(), craftingState); + + // Kismet: a bad recipe will be caught automatically, since it'll stay a blank pattern + Map result; + try { + result = getDetailsForItem(patternStack); + } catch (IllegalStateException e) { + throw new IllegalStateException("Bad recipe"); + } + + turtle.getInventory().removeItem(turtle.getSelectedSlot(), 1); + turtle.getInventory().setItem(destinationSlot, patternStack); + + return MethodResult.of(true, result); + } catch (IllegalStateException | IllegalArgumentException e) { + // I like exceptions but the other peripherals in this mod don't use them. So just return errors as strings. + return MethodResult.of(false, e.getMessage()); + } + } + + // ----------------------------------------------------------------------------------------------------------------- + + // Build a processing pattern from a list of ingredients. + @LuaFunction(mainThread = true) + public MethodResult buildProcessing(Map recipeArg) { + ITurtleAccess turtle = this.getPeripheralOwner().getTurtle(); + LuaTable recipeTable = new ObjectLuaTable(recipeArg); + + try { + verifyPatternsInSlot(turtle.getSelectedSlot()); + int destinationSlot = getFreeSlotAfterBuild(turtle.getSelectedSlot()); + + ItemStack patternStack = new ItemStack(Items.INSTANCE.getPattern()); + PatternState patternState = new PatternState(UUID.randomUUID(), PatternType.PROCESSING); + patternStack.set(DataComponents.INSTANCE.getPatternState(), patternState); + + List> ingredients = new ArrayList<>(); + List> results = new ArrayList<>(); + + /* Attempt to parse our recipe. We should be passed in a table that looks like this: + * + * { + * inputs = { + * [1] = { name = "", count = }, + * [2] = { name = "", alts = { [1] = "", ... }, count = }, + * ... + * }, + * outputs = { + * [1] = { name = "", count = }, + * ... + * } + * } + * + */ + + // Lua sends in all numbers as doubles. We don't really care about the index. + LuaTable inputsTable = new ObjectLuaTable(recipeTable.getTable("inputs")); + + for (LuaTable thisInput : inputsTable.values().stream().map(Map.class::cast).map(ObjectLuaTable::new).toList()) { + int thisCount = thisInput.getInt("count"); + ResourceKey thisItem = parseResourceName(thisInput.getString("name")); + + List theseAlts = new ArrayList<>(); + + if (thisInput.containsKey("alts")) { + theseAlts = thisInput.getTable("alts").values().stream() + .map(String.class::cast).map(ResourceLocation::parse).toList(); + } + + ingredients.add(Optional.of( + new ProcessingPatternState.ProcessingIngredient(new ResourceAmount(thisItem, thisCount), theseAlts))); + } + + LuaTable outputsTable = new ObjectLuaTable(recipeTable.getTable("outputs")); + + for (LuaTable thisOutput : outputsTable.values().stream().map(Map.class::cast).map(ObjectLuaTable::new).toList()) { + int thisCount = thisOutput.getInt("count"); + ResourceKey thisItem = parseResourceName(thisOutput.getString("name")); + + results.add(Optional.of(new ResourceAmount(thisItem, thisCount))); + } + + ProcessingPatternState processingState = new ProcessingPatternState(ingredients, results); + patternStack.set(DataComponents.INSTANCE.getProcessingPatternState(), processingState); + + Map result; + try { + result = getDetailsForItem(patternStack); + } catch (IllegalStateException e) { + throw new IllegalStateException("Bad recipe"); + } + + turtle.getInventory().removeItem(turtle.getSelectedSlot(), 1); + turtle.getInventory().setItem(destinationSlot, patternStack); + + return MethodResult.of(true, result); + } catch (IllegalStateException | IllegalArgumentException | LuaException e) { + // I like exceptions but the other peripherals in this mod don't use them. So just return errors as strings. + return MethodResult.of(false, e.getMessage()); + } + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/turtles/TurtlePatternGridUpgrade.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/turtles/TurtlePatternGridUpgrade.java new file mode 100644 index 000000000..2953db57a --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/turtles/TurtlePatternGridUpgrade.java @@ -0,0 +1,40 @@ +package de.srendi.advancedperipherals.common.addons.computercraft.turtles; + +import dan200.computercraft.api.turtle.ITurtleAccess; +import dan200.computercraft.api.turtle.ITurtleUpgrade; +import dan200.computercraft.api.turtle.TurtleSide; +import dan200.computercraft.api.upgrades.UpgradeType; +import de.srendi.advancedperipherals.AdvancedPeripherals; +import de.srendi.advancedperipherals.common.addons.computercraft.peripheral.PatternGridPeripheral; +import de.srendi.advancedperipherals.common.setup.CCRegistration; +import de.srendi.advancedperipherals.lib.turtle.PeripheralTurtleUpgrade; +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.NotNull; + +public class TurtlePatternGridUpgrade extends PeripheralTurtleUpgrade { + + public TurtlePatternGridUpgrade(ItemStack stack) { + super(CCRegistration.ID.PATTERN_TURTLE, stack); + } + + @Override + public ModelResourceLocation getLeftModel() { + return new ModelResourceLocation(AdvancedPeripherals.getRL("turtle_pattern_upgrade_left"), "inventory"); + } + + @Override + public ModelResourceLocation getRightModel() { + return new ModelResourceLocation(AdvancedPeripherals.getRL("turtle_pattern_upgrade_right"), "inventory"); + } + + @Override + protected PatternGridPeripheral buildPeripheral(@NotNull ITurtleAccess turtle, @NotNull TurtleSide side) { + return new PatternGridPeripheral(turtle, side); + } + + @Override + public UpgradeType getType() { + return CCRegistration.PATTERN_TURTLE.get(); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/refinedstorage/RSApi.java b/src/main/java/de/srendi/advancedperipherals/common/addons/refinedstorage/RSApi.java index 59307eb42..685e1a910 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/refinedstorage/RSApi.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/refinedstorage/RSApi.java @@ -606,7 +606,7 @@ public static boolean isSameResource(ResourceKey resource, ResourceKey toCompare return false; } - public static Object parseDiskDrive(StorageNetworkNode diskDrive, InWorldNetworkNodeContainer nodeContainer) { + public static Map parseDiskDrive(StorageNetworkNode diskDrive, InWorldNetworkNodeContainer nodeContainer) { Map properties = new HashMap<>(); StorageConfiguration storageConfiguration = diskDrive.getStorageConfiguration(); @@ -631,7 +631,7 @@ public static Object parseDiskDrive(StorageNetworkNode diskDrive, InWorldNetwork return properties; } - public static Object parseStorageDisk(StateTrackedStorage disk) { + public static Map parseStorageDisk(StateTrackedStorage disk) { Map properties = new HashMap<>(); properties.put("used", disk.getStored()); @@ -654,7 +654,7 @@ public static Object parseStorageDisk(StateTrackedStorage disk) { return properties; } - public static Object parseCraftingTask(@Nullable RSCraftJob task, TaskStatus status, @Nullable AutocraftingNetworkComponent autocraftingComponent) { + public static Map parseCraftingTask(@Nullable RSCraftJob task, TaskStatus status, @Nullable AutocraftingNetworkComponent autocraftingComponent) { Map properties = new HashMap<>(); properties.put("bridge_id", task == null ? -1 : task.getId()); @@ -669,7 +669,7 @@ public static Object parseCraftingTask(@Nullable RSCraftJob task, TaskStatus sta return properties; } - public static Object parsePattern(Pattern pattern, @Nullable AutocraftingNetworkComponent autocraftingComponent) { + public static Map parsePattern(Pattern pattern, @Nullable AutocraftingNetworkComponent autocraftingComponent) { if (pattern == null) return null; diff --git a/src/main/java/de/srendi/advancedperipherals/common/configuration/PeripheralsConfig.java b/src/main/java/de/srendi/advancedperipherals/common/configuration/PeripheralsConfig.java index 62a061140..2af8386e8 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/configuration/PeripheralsConfig.java +++ b/src/main/java/de/srendi/advancedperipherals/common/configuration/PeripheralsConfig.java @@ -58,6 +58,9 @@ public class PeripheralsConfig implements IAPConfig { public final ModConfigSpec.BooleanValue enableRSBridge; public final ModConfigSpec.IntValue rsConsumption; + // Pattern Grid turtle + public final ModConfigSpec.BooleanValue enablePatternGridTurtle; + // Environment Detector public final ModConfigSpec.BooleanValue enableEnvironmentDetector; @@ -162,6 +165,9 @@ public PeripheralsConfig() { enableRSBridge = builder.comment("Enable the Rs Bridge or not.").define("enableRsBridge", true); rsConsumption = builder.comment("Power consumption per tick.").defineInRange("rsPowerConsumption", 10, 0, Integer.MAX_VALUE); + pop("Pattern_Grid_Turtle", builder); + enablePatternGridTurtle = builder.comment("Enable the RS Pattern Grid turtle or not.").define("enablePatternGridTurtle", true); + pop("Environment_Detector", builder); enableEnvironmentDetector = builder.comment("Enable the Environment Detector or not.").define("enableEnvironmentDetector", true); diff --git a/src/main/java/de/srendi/advancedperipherals/common/data/EnUsLanguageProvider.java b/src/main/java/de/srendi/advancedperipherals/common/data/EnUsLanguageProvider.java index edc89370b..4d0980de9 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/data/EnUsLanguageProvider.java +++ b/src/main/java/de/srendi/advancedperipherals/common/data/EnUsLanguageProvider.java @@ -72,6 +72,7 @@ private void addTurtles() { addTurtle(CCRegistration.ID.ENVIRONMENT_TURTLE, "Environment"); addTurtle(CCRegistration.ID.PLAYER_TURTLE, "Player Detector"); addTurtle(CCRegistration.ID.GEOSCANNER_TURTLE, "Geo"); + addTurtle(CCRegistration.ID.PATTERN_TURTLE, "Pattern Grid"); addTurtle(CCRegistration.ID.COMPASS_TURTLE, "Compass"); addTurtle(CCRegistration.ID.WEAK_AUTOMATA, "Weak automata"); addTurtle(CCRegistration.ID.HUSBANDRY_AUTOMATA, "Husbandry automata"); diff --git a/src/main/java/de/srendi/advancedperipherals/common/setup/CCRegistration.java b/src/main/java/de/srendi/advancedperipherals/common/setup/CCRegistration.java index c05b0402a..9194b6046 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/setup/CCRegistration.java +++ b/src/main/java/de/srendi/advancedperipherals/common/setup/CCRegistration.java @@ -17,6 +17,7 @@ import de.srendi.advancedperipherals.common.addons.computercraft.turtles.TurtleCompassUpgrade; import de.srendi.advancedperipherals.common.addons.computercraft.turtles.TurtleEnvironmentDetectorUpgrade; import de.srendi.advancedperipherals.common.addons.computercraft.turtles.TurtleGeoScannerUpgrade; +import de.srendi.advancedperipherals.common.addons.computercraft.turtles.TurtlePatternGridUpgrade; import de.srendi.advancedperipherals.common.addons.computercraft.turtles.TurtlePlayerDetectorUpgrade; import de.srendi.advancedperipherals.common.addons.computercraft.turtles.metaphysics.EndAutomata; import de.srendi.advancedperipherals.common.addons.computercraft.turtles.metaphysics.HusbandryAutomata; @@ -35,6 +36,7 @@ public class CCRegistration { public static final DeferredHolder, UpgradeType> CHUNKY_TURTLE = Registration.TURTLE_SERIALIZER.register(ID.CHUNKY_TURTLE.getPath(), () -> UpgradeType.simpleWithCustomItem(TurtleChunkyUpgrade::new)); public static final DeferredHolder, UpgradeType> GEO_SCANNER_TURTLE = Registration.TURTLE_SERIALIZER.register(ID.GEOSCANNER_TURTLE.getPath(), () -> UpgradeType.simpleWithCustomItem(TurtleGeoScannerUpgrade::new)); public static final DeferredHolder, UpgradeType> COMPASS_TURTLE = Registration.TURTLE_SERIALIZER.register(ID.COMPASS_TURTLE.getPath(), () -> UpgradeType.simpleWithCustomItem(TurtleCompassUpgrade::new)); + public static final DeferredHolder, UpgradeType> PATTERN_TURTLE = Registration.TURTLE_SERIALIZER.register(ID.PATTERN_TURTLE.getPath(), () -> UpgradeType.simpleWithCustomItem(TurtlePatternGridUpgrade::new)); public static final DeferredHolder, UpgradeType> WEAK_TURTLE = Registration.TURTLE_SERIALIZER.register(ID.WEAK_AUTOMATA.getPath(), () -> UpgradeType.simpleWithCustomItem(WeakAutomata::new)); public static final DeferredHolder, UpgradeType> END_TURTLE = Registration.TURTLE_SERIALIZER.register(ID.END_AUTOMATA.getPath(), () -> UpgradeType.simpleWithCustomItem(EndAutomata::new)); public static final DeferredHolder, UpgradeType> HUSBANDRY_TURTLE = Registration.TURTLE_SERIALIZER.register(ID.HUSBANDRY_AUTOMATA.getPath(), () -> UpgradeType.simpleWithCustomItem(HusbandryAutomata::new)); @@ -61,6 +63,7 @@ public static class ID { public static final ResourceLocation CHUNKY_TURTLE = AdvancedPeripherals.getRL("chunky_turtle"); public static final ResourceLocation GEOSCANNER_TURTLE = AdvancedPeripherals.getRL("geoscanner_turtle"); public static final ResourceLocation COMPASS_TURTLE = AdvancedPeripherals.getRL("compass_turtle"); + public static final ResourceLocation PATTERN_TURTLE = AdvancedPeripherals.getRL("pattern_turtle"); public static final ResourceLocation WEAK_AUTOMATA = AdvancedPeripherals.getRL("weak_automata"); public static final ResourceLocation END_AUTOMATA = AdvancedPeripherals.getRL("end_automata"); public static final ResourceLocation HUSBANDRY_AUTOMATA = AdvancedPeripherals.getRL("husbandry_automata"); diff --git a/src/main/resources/assets/advancedperipherals/models/block/turtle_pattern_left.json b/src/main/resources/assets/advancedperipherals/models/block/turtle_pattern_left.json new file mode 100644 index 000000000..fc87a80e1 --- /dev/null +++ b/src/main/resources/assets/advancedperipherals/models/block/turtle_pattern_left.json @@ -0,0 +1,4 @@ +{ + "parent": "computercraft:block/turtle_upgrade_base_left", + "textures": {"texture": "advancedperipherals:block/pattern_grid_small"} +} \ No newline at end of file diff --git a/src/main/resources/assets/advancedperipherals/models/block/turtle_pattern_right.json b/src/main/resources/assets/advancedperipherals/models/block/turtle_pattern_right.json new file mode 100644 index 000000000..107c410d3 --- /dev/null +++ b/src/main/resources/assets/advancedperipherals/models/block/turtle_pattern_right.json @@ -0,0 +1,4 @@ +{ + "parent": "computercraft:block/turtle_upgrade_base_right", + "textures": {"texture": "advancedperipherals:block/pattern_grid_small"} +} \ No newline at end of file diff --git a/src/main/resources/assets/advancedperipherals/models/item/turtle_pattern_upgrade_left.json b/src/main/resources/assets/advancedperipherals/models/item/turtle_pattern_upgrade_left.json new file mode 100644 index 000000000..62f95a889 --- /dev/null +++ b/src/main/resources/assets/advancedperipherals/models/item/turtle_pattern_upgrade_left.json @@ -0,0 +1,6 @@ +{ + "parent": "advancedperipherals:block/turtle_upgrade_base_left", + "textures": { + "texture": "advancedperipherals:block/pattern_grid_small" + } +} diff --git a/src/main/resources/assets/advancedperipherals/models/item/turtle_pattern_upgrade_right.json b/src/main/resources/assets/advancedperipherals/models/item/turtle_pattern_upgrade_right.json new file mode 100644 index 000000000..6ec2d358a --- /dev/null +++ b/src/main/resources/assets/advancedperipherals/models/item/turtle_pattern_upgrade_right.json @@ -0,0 +1,6 @@ +{ + "parent": "advancedperipherals:block/turtle_upgrade_base_right", + "textures": { + "texture": "advancedperipherals:block/pattern_grid_small" + } +} diff --git a/src/main/resources/assets/advancedperipherals/textures/block/pattern_grid.png b/src/main/resources/assets/advancedperipherals/textures/block/pattern_grid.png new file mode 100644 index 000000000..02e9e85d1 Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/pattern_grid.png differ diff --git a/src/main/resources/assets/advancedperipherals/textures/block/pattern_grid_small.png b/src/main/resources/assets/advancedperipherals/textures/block/pattern_grid_small.png new file mode 100644 index 000000000..a0018153b Binary files /dev/null and b/src/main/resources/assets/advancedperipherals/textures/block/pattern_grid_small.png differ