From c016b8850d64b664bd1df7b5dadaa8c4ac4fcd6b Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 14 Jan 2022 17:19:09 +0700 Subject: [PATCH] Plate Press initial datagen for recipes fix addItem ranges in MatteryContainer --- .../ru/dbotthepony/mc/otm/datagen/DataGen.kt | 14 +++ .../ru/dbotthepony/mc/otm/datagen/Ext.kt | 3 - .../mc/otm/datagen/items/DummyItemTag.kt | 11 ++ .../otm/datagen/models/MatteryModelBuilder.kt | 2 +- .../datagen/recipes/MatteryRecipeProvider.kt | 43 +++++++ .../recipes/PlatePressFinishedRecipe.kt | 78 +++++++++++++ .../mc/otm/OverdriveThatMatters.java | 1 + .../java/ru/dbotthepony/mc/otm/Registry.java | 54 +++++++++ .../otm/block/entity/worker/MachineJob.java | 11 +- src/main/kotlin/ru/dbotthepony/mc/otm/Ext.kt | 10 ++ .../mc/otm/block/BlockPlatePress.kt | 28 +++++ .../otm/block/entity/BlockEntityPlatePress.kt | 79 +++++++++++++ .../entity/worker/BlockEntityMatteryWorker.kt | 6 +- .../capability/MatteryMachineEnergyStorage.kt | 4 +- .../mc/otm/client/screen/PlatePressScreen.kt | 25 ++++ .../mc/otm/container/MatteryContainer.kt | 14 +-- .../dbotthepony/mc/otm/menu/PlatePressMenu.kt | 29 +++++ .../ru/dbotthepony/mc/otm/recipes/Helpers.kt | 57 ++++++++++ .../mc/otm/recipes/PlatePressRecipe.kt | 107 ++++++++++++++++++ .../overdrive_that_matters/lang/en_us.json | 1 + 20 files changed, 555 insertions(+), 22 deletions(-) create mode 100644 src/data/kotlin/ru/dbotthepony/mc/otm/datagen/items/DummyItemTag.kt create mode 100644 src/data/kotlin/ru/dbotthepony/mc/otm/datagen/recipes/MatteryRecipeProvider.kt create mode 100644 src/data/kotlin/ru/dbotthepony/mc/otm/datagen/recipes/PlatePressFinishedRecipe.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/block/BlockPlatePress.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BlockEntityPlatePress.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/PlatePressScreen.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/menu/PlatePressMenu.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/recipes/Helpers.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/recipes/PlatePressRecipe.kt diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/DataGen.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/DataGen.kt index 9115502a5..25546049c 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/DataGen.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/DataGen.kt @@ -2,6 +2,9 @@ package ru.dbotthepony.mc.otm.datagen import net.minecraft.core.Direction import net.minecraft.resources.ResourceLocation +import net.minecraft.tags.Tag +import net.minecraft.world.item.Item +import net.minecraft.world.item.crafting.Ingredient import net.minecraft.world.level.block.Block import net.minecraftforge.eventbus.api.SubscribeEvent import net.minecraftforge.fml.common.Mod @@ -15,10 +18,13 @@ import ru.dbotthepony.mc.otm.block.BlockMatteryRotatable import ru.dbotthepony.mc.otm.block.BlockPatternStorage import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState import ru.dbotthepony.mc.otm.datagen.blocks.* +import ru.dbotthepony.mc.otm.datagen.items.DummyItemTag import ru.dbotthepony.mc.otm.datagen.items.MatteryItemModelProvider import ru.dbotthepony.mc.otm.datagen.loot.MatteryLootTableProvider import ru.dbotthepony.mc.otm.datagen.loot.TileNbtCopy import ru.dbotthepony.mc.otm.datagen.models.BlockMatteryModelProvider +import ru.dbotthepony.mc.otm.datagen.recipes.MatteryRecipeProvider +import ru.dbotthepony.mc.otm.recipes.PlatePressRecipe @Mod.EventBusSubscriber(modid = DataGen.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) object DataGen { @@ -28,6 +34,7 @@ object DataGen { private lateinit var itemModelProvider: MatteryItemModelProvider private lateinit var blockStateProvider: MatteryBlockStateProvider private lateinit var lootTableProvider: MatteryLootTableProvider + private lateinit var recipeProvider: MatteryRecipeProvider private fun decorativeCubeAll(vararg blocks: Block) { blockModelProvider.decorativeCubeAll(*blocks) @@ -52,11 +59,13 @@ object DataGen { blockStateProvider = MatteryBlockStateProvider(event) itemModelProvider = MatteryItemModelProvider(event) lootTableProvider = MatteryLootTableProvider(event.generator) + recipeProvider = MatteryRecipeProvider(event.generator) event.generator.addProvider(blockModelProvider) event.generator.addProvider(itemModelProvider) event.generator.addProvider(blockStateProvider) event.generator.addProvider(blockStateProvider) + event.generator.addProvider(recipeProvider) decorativeCubeAll(*Blocks.CRATES) decorativeCubeAll(Blocks.CARBON_FIBRE_BLOCK) @@ -279,5 +288,10 @@ object DataGen { tile(Blocks.MATTER_CAPACITOR_BANK, TileNbtCopy("matter_container")) tile(Blocks.MATTER_BOTTLER, TileNbtCopy("energy_cap"), TileNbtCopy("battery_container"), TileNbtCopy("work_slots"), TileNbtCopy("work_flow"), TileNbtCopy("matter_capability")) } + + with(recipeProvider) { + plate("iron") + plate("tritanium") + } } } diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/Ext.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/Ext.kt index 942f980bb..ac9181495 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/Ext.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/Ext.kt @@ -25,6 +25,3 @@ fun > BlockState.getValueNullable(prop: Property): T? { return null } - -operator fun JsonObject.set(s: String, value: JsonArray) = add(s, value) - diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/items/DummyItemTag.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/items/DummyItemTag.kt new file mode 100644 index 000000000..6577b60b9 --- /dev/null +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/items/DummyItemTag.kt @@ -0,0 +1,11 @@ +package ru.dbotthepony.mc.otm.datagen.items + +import net.minecraft.resources.ResourceLocation +import net.minecraft.tags.Tag +import net.minecraft.world.item.Item + +class DummyItemTag(private val name: ResourceLocation) : Tag.Named { + override fun contains(p_13287_: Item) = false + override fun getValues() = emptyList() + override fun getName() = name +} diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/models/MatteryModelBuilder.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/models/MatteryModelBuilder.kt index 35faea5b6..f61057840 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/models/MatteryModelBuilder.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/models/MatteryModelBuilder.kt @@ -9,7 +9,7 @@ import net.minecraft.core.Direction import net.minecraft.resources.ResourceLocation import net.minecraftforge.client.model.generators.ModelBuilder import net.minecraftforge.common.data.ExistingFileHelper -import ru.dbotthepony.mc.otm.datagen.set +import ru.dbotthepony.mc.otm.set data class TextureSize(val width: Float, val height: Float) { constructor(arr: JsonArray) : this(arr[0].asFloat, arr[1].asFloat) diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/recipes/MatteryRecipeProvider.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/recipes/MatteryRecipeProvider.kt new file mode 100644 index 000000000..5e4394097 --- /dev/null +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/recipes/MatteryRecipeProvider.kt @@ -0,0 +1,43 @@ +package ru.dbotthepony.mc.otm.datagen.recipes + +import net.minecraft.data.DataGenerator +import net.minecraft.data.recipes.FinishedRecipe +import net.minecraft.data.recipes.RecipeProvider +import net.minecraft.resources.ResourceLocation +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.crafting.Ingredient +import ru.dbotthepony.mc.otm.datagen.DataGen +import ru.dbotthepony.mc.otm.recipes.PlatePressRecipe +import java.util.function.Consumer + +private typealias RecipeLambda = (MatteryRecipeProvider, Consumer) -> Unit + +class MatteryRecipeProvider(generatorIn: DataGenerator) : RecipeProvider(generatorIn) { + private val lambdas = ArrayList() + + fun lambda(lambda: RecipeLambda) = lambdas.add(lambda) + + override fun buildCraftingRecipes(callback: Consumer) { + for (lambda in lambdas) { + lambda(this, callback) + } + } + + fun plate(id: String, count: Int = 1, workTicks: Int = 200) { + lambda { it, callback -> + callback.accept(PlatePressShallowFinishedRecipe( + ResourceLocation(DataGen.MOD_ID, "plate_$id"), + ResourceLocation("forge", "ingots/$id"), + ResourceLocation("forge", "plates/$id"), + count, + workTicks + )) + } + } + + fun plate(id: String, ingredient: Ingredient, result: Ingredient, count: Int = 1, workTicks: Int = 200) { + lambda { it, callback -> + callback.accept(PlatePressFinishedRecipe(PlatePressRecipe(ResourceLocation(DataGen.MOD_ID, "plate_$id"), ingredient, result, count, workTicks))) + } + } +} diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/recipes/PlatePressFinishedRecipe.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/recipes/PlatePressFinishedRecipe.kt new file mode 100644 index 000000000..44f505f7b --- /dev/null +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/recipes/PlatePressFinishedRecipe.kt @@ -0,0 +1,78 @@ +package ru.dbotthepony.mc.otm.datagen.recipes + +import com.google.gson.JsonObject +import com.google.gson.JsonPrimitive +import net.minecraft.data.recipes.FinishedRecipe +import net.minecraft.resources.ResourceLocation +import net.minecraft.world.item.crafting.RecipeSerializer +import ru.dbotthepony.mc.otm.recipes.PlatePressRecipe +import ru.dbotthepony.mc.otm.recipes.PlatePressRecipeFactory +import ru.dbotthepony.mc.otm.set + +class PlatePressFinishedRecipe(private val recipe: PlatePressRecipe) : FinishedRecipe { + override fun serializeRecipeData(it: JsonObject) { + it["input"] = recipe.input.toJson() + + it["result"] = recipe.output.toJson().also { + if (it is JsonObject && recipe.count != 1) + it["count"] = JsonPrimitive(recipe.count) + } + + it["work_time"] = JsonPrimitive(recipe.workTime) + } + + override fun getId(): ResourceLocation { + return recipe.id + } + + override fun getType(): RecipeSerializer<*> { + return PlatePressRecipeFactory + } + + override fun serializeAdvancement(): JsonObject? { + return null + } + + override fun getAdvancementId(): ResourceLocation? { + return null + } +} + +class PlatePressShallowFinishedRecipe( + private val id: ResourceLocation, + private val input: ResourceLocation, + private val output: ResourceLocation, + private val count: Int = 1, + private val workTime: Int = 200 +) : FinishedRecipe { + override fun serializeRecipeData(it: JsonObject) { + it["input"] = JsonObject().also { + it["tag"] = JsonPrimitive(input.toString()) + } + + it["result"] = JsonObject().also { + it["tag"] = JsonPrimitive(output.toString()) + + if (count != 1) + it["count"] = JsonPrimitive(count) + } + + it["work_time"] = JsonPrimitive(workTime) + } + + override fun getId(): ResourceLocation { + return id + } + + override fun getType(): RecipeSerializer<*> { + return PlatePressRecipeFactory + } + + override fun serializeAdvancement(): JsonObject? { + return null + } + + override fun getAdvancementId(): ResourceLocation? { + return null + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java b/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java index 353078a31..a9f508b83 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java +++ b/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java @@ -142,6 +142,7 @@ public class OverdriveThatMatters { FMLJavaModLoadingContext.get().getModEventBus().register(Registry.AndroidFeatures.class); FMLJavaModLoadingContext.get().getModEventBus().register(Registry.AndroidResearch.class); FMLJavaModLoadingContext.get().getModEventBus().register(Registry.Stats.class); + FMLJavaModLoadingContext.get().getModEventBus().register(Registry.Recipes.class); MinecraftForge.EVENT_BUS.register(DrivePool.INSTANCE); MinecraftForge.EVENT_BUS.register(ItemPortableCondensationDrive.Companion); diff --git a/src/main/java/ru/dbotthepony/mc/otm/Registry.java b/src/main/java/ru/dbotthepony/mc/otm/Registry.java index cee607575..cda514dcd 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/Registry.java +++ b/src/main/java/ru/dbotthepony/mc/otm/Registry.java @@ -8,11 +8,15 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.stats.StatFormatter; import net.minecraft.tags.BlockTags; import net.minecraft.util.valueproviders.UniformInt; +import net.minecraft.world.Container; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.food.FoodProperties; import net.minecraft.world.inventory.MenuType; import net.minecraft.world.item.*; import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.RecipeSerializer; +import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.OreBlock; import net.minecraft.world.level.block.SoundType; @@ -46,6 +50,8 @@ import ru.dbotthepony.mc.otm.core.Fraction; import ru.dbotthepony.mc.otm.item.*; import ru.dbotthepony.mc.otm.menu.*; import ru.dbotthepony.mc.otm.client.screen.*; +import ru.dbotthepony.mc.otm.recipes.PlatePressRecipe; +import ru.dbotthepony.mc.otm.recipes.PlatePressRecipeFactory; public class Registry { public static final DamageSource DAMAGE_BECOME_ANDROID = new DamageSource("otm_become_android"); @@ -121,6 +127,7 @@ public class Registry { public static final ResourceLocation ITEM_MONITOR = loc("item_monitor"); // нужен рецепт (после улучшений) public static final ResourceLocation ENERGY_COUNTER = loc("energy_counter"); // нужен рецепт public static final ResourceLocation CHEMICAL_GENERATOR = loc("chemical_generator"); // нужен рецепт + public static final ResourceLocation PLATE_PRESS = loc("plate_press"); // нужен рецепт public static final ResourceLocation DEBUG_EXPLOSION_SMALL = loc("debug_explosion_small"); @@ -271,6 +278,7 @@ public class Registry { public static final BlockItemMonitor ITEM_MONITOR = new BlockItemMonitor(); public static final BlockEnergyCounter ENERGY_COUNTER = new BlockEnergyCounter(); public static final BlockChemicalGenerator CHEMICAL_GENERATOR = new BlockChemicalGenerator(); + public static final BlockPlatePress PLATE_PRESS = new BlockPlatePress(); public static final BlockExplosionDebugger DEBUG_EXPLOSION_SMALL = new BlockExplosionDebugger(); public static final BlockSphereDebugger DEBUG_SPHERE_POINTS = new BlockSphereDebugger(); @@ -353,6 +361,7 @@ public class Registry { ITEM_MONITOR.setRegistryName(Names.ITEM_MONITOR); ENERGY_COUNTER.setRegistryName(Names.ENERGY_COUNTER); CHEMICAL_GENERATOR.setRegistryName(Names.CHEMICAL_GENERATOR); + PLATE_PRESS.setRegistryName(Names.PLATE_PRESS); DEBUG_EXPLOSION_SMALL.setRegistryName(Names.DEBUG_EXPLOSION_SMALL); DEBUG_SPHERE_POINTS.setRegistryName(Names.DEBUG_SPHERE_POINTS); @@ -388,6 +397,7 @@ public class Registry { event.getRegistry().register(ITEM_MONITOR); event.getRegistry().register(ENERGY_COUNTER); event.getRegistry().register(CHEMICAL_GENERATOR); + event.getRegistry().register(PLATE_PRESS); event.getRegistry().register(DEBUG_EXPLOSION_SMALL); event.getRegistry().register(DEBUG_SPHERE_POINTS); @@ -420,6 +430,7 @@ public class Registry { public static final BlockItem ITEM_MONITOR = new BlockItem(Blocks.ITEM_MONITOR, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB)); public static final BlockItem ENERGY_COUNTER = new BlockItem(Blocks.ENERGY_COUNTER, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB)); public static final BlockItem CHEMICAL_GENERATOR = new BlockItem(Blocks.CHEMICAL_GENERATOR, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB)); + public static final BlockItem PLATE_PRESS = new BlockItem(Blocks.PLATE_PRESS, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB)); public static final BlockItem DEBUG_EXPLOSION_SMALL = new BlockItem(Blocks.DEBUG_EXPLOSION_SMALL, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB)); public static final BlockItem DEBUG_SPHERE_POINTS = new BlockItem(Blocks.DEBUG_SPHERE_POINTS, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB)); @@ -555,6 +566,7 @@ public class Registry { ITEM_MONITOR.setRegistryName(Names.ITEM_MONITOR); ENERGY_COUNTER.setRegistryName(Names.ENERGY_COUNTER); CHEMICAL_GENERATOR.setRegistryName(Names.CHEMICAL_GENERATOR); + PLATE_PRESS.setRegistryName(Names.PLATE_PRESS); DEBUG_EXPLOSION_SMALL.setRegistryName(Names.DEBUG_EXPLOSION_SMALL); DEBUG_SPHERE_POINTS.setRegistryName(Names.DEBUG_SPHERE_POINTS); @@ -635,6 +647,7 @@ public class Registry { event.getRegistry().register(ITEM_MONITOR); event.getRegistry().register(ENERGY_COUNTER); event.getRegistry().register(CHEMICAL_GENERATOR); + event.getRegistry().register(PLATE_PRESS); event.getRegistry().register(DEBUG_EXPLOSION_SMALL); event.getRegistry().register(DEBUG_SPHERE_POINTS); @@ -721,6 +734,7 @@ public class Registry { public static final BlockEntityType ITEM_MONITOR = BlockEntityType.Builder.of(BlockEntityItemMonitor::new, Blocks.ITEM_MONITOR).build(null); public static final BlockEntityType ENERGY_COUNTER = BlockEntityType.Builder.of(BlockEntityEnergyCounter::new, Blocks.ENERGY_COUNTER).build(null); public static final BlockEntityType CHEMICAL_GENERATOR = BlockEntityType.Builder.of(BlockEntityChemicalGenerator::new, Blocks.CHEMICAL_GENERATOR).build(null); + public static final BlockEntityType PLATE_PRESS = BlockEntityType.Builder.of(BlockEntityPlatePress::new, Blocks.PLATE_PRESS).build(null); public static final BlockEntityType DEBUG_EXPLOSION_SMALL = BlockEntityType.Builder.of(BlockEntityExplosionDebugger::new, Blocks.DEBUG_EXPLOSION_SMALL).build(null); public static final BlockEntityType DEBUG_SPHERE_POINTS = BlockEntityType.Builder.of(BlockEntitySphereDebugger::new, Blocks.DEBUG_SPHERE_POINTS).build(null); @@ -743,6 +757,7 @@ public class Registry { ITEM_MONITOR.setRegistryName(Names.ITEM_MONITOR); ENERGY_COUNTER.setRegistryName(Names.ENERGY_COUNTER); CHEMICAL_GENERATOR.setRegistryName(Names.CHEMICAL_GENERATOR); + PLATE_PRESS.setRegistryName(Names.PLATE_PRESS); DEBUG_EXPLOSION_SMALL.setRegistryName(Names.DEBUG_EXPLOSION_SMALL); DEBUG_SPHERE_POINTS.setRegistryName(Names.DEBUG_SPHERE_POINTS); @@ -768,6 +783,8 @@ public class Registry { event.getRegistry().register(ITEM_MONITOR); event.getRegistry().register(ENERGY_COUNTER); event.getRegistry().register(CHEMICAL_GENERATOR); + event.getRegistry().register(PLATE_PRESS); + event.getRegistry().register(DEBUG_EXPLOSION_SMALL); event.getRegistry().register(DEBUG_SPHERE_POINTS); @@ -1040,6 +1057,7 @@ public class Registry { public static final MenuType ITEM_MONITOR = new MenuType<>(ItemMonitorMenu::new); public static final MenuType ENERGY_COUNTER = new MenuType<>(EnergyCounterMenu::new); public static final MenuType CHEMICAL_GENERATOR = new MenuType<>(ChemicalGeneratorMenu::new); + public static final MenuType PLATE_PRESS = new MenuType<>(PlatePressMenu::new); static { ANDROID_STATION.setRegistryName(Names.ANDROID_STATION); @@ -1057,6 +1075,7 @@ public class Registry { ITEM_MONITOR.setRegistryName(Names.ITEM_MONITOR); ENERGY_COUNTER.setRegistryName(Names.ENERGY_COUNTER); CHEMICAL_GENERATOR.setRegistryName(Names.CHEMICAL_GENERATOR); + PLATE_PRESS.setRegistryName(Names.PLATE_PRESS); } @SubscribeEvent @@ -1077,6 +1096,7 @@ public class Registry { event.getRegistry().register(ITEM_MONITOR); event.getRegistry().register(ENERGY_COUNTER); event.getRegistry().register(CHEMICAL_GENERATOR); + event.getRegistry().register(PLATE_PRESS); // OverdriveThatMatters.LOGGER.info("Registered menus"); } @@ -1099,6 +1119,7 @@ public class Registry { MenuScreens.register(ITEM_MONITOR, ItemMonitorScreen::new); MenuScreens.register(ENERGY_COUNTER, EnergyCounterScreen::new); MenuScreens.register(CHEMICAL_GENERATOR, ChemicalGeneratorScreen::new); + MenuScreens.register(PLATE_PRESS, PlatePressScreen::new); // OverdriveThatMatters.LOGGER.info("Registered screens"); } @@ -1117,4 +1138,37 @@ public class Registry { net.minecraft.stats.Stats.CUSTOM.get(Names.POWER_CONSUMED, StatFormatter.DIVIDE_BY_TEN); } } + + public static class Recipes { + public static class MatteryRecipeType> implements RecipeType { + public final ResourceLocation name; + + private MatteryRecipeType(ResourceLocation name) { + this.name = name; + } + + private void register() { + net.minecraft.core.Registry.register(net.minecraft.core.Registry.RECIPE_TYPE, name, this); + } + + @Override + public String toString() { + return name.toString(); + } + } + + public static final MatteryRecipeType PLATE_PRESS = new MatteryRecipeType<>(Names.PLATE_PRESS); + + @SubscribeEvent + @SuppressWarnings("unused") + public static void register(final FMLCommonSetupEvent event) { + PLATE_PRESS.register(); + } + + @SubscribeEvent + @SuppressWarnings("unused") + public static void register(final RegistryEvent.Register> event) { + event.getRegistry().register(PlatePressRecipeFactory.INSTANCE); + } + } } diff --git a/src/main/java/ru/dbotthepony/mc/otm/block/entity/worker/MachineJob.java b/src/main/java/ru/dbotthepony/mc/otm/block/entity/worker/MachineJob.java index 1822c5afc..67be2b48a 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/block/entity/worker/MachineJob.java +++ b/src/main/java/ru/dbotthepony/mc/otm/block/entity/worker/MachineJob.java @@ -12,14 +12,13 @@ import javax.annotation.ParametersAreNonnullByDefault; @MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault -public record MachineJob(ItemStack stack, double ticks, Fraction power, - CompoundTag data) { - public MachineJob(ItemStack stack, double ticks_processing_time, Fraction power_consumption_multiplier) { - this(stack, ticks_processing_time, power_consumption_multiplier, new CompoundTag()); +public record MachineJob(ItemStack stack, double ticks, Fraction power, CompoundTag data) { + public MachineJob(ItemStack stack, double ticks, Fraction power) { + this(stack, ticks, power, new CompoundTag()); } - public MachineJob(ItemStack stack, double ticks_processing_time) { - this(stack, ticks_processing_time, Fraction.ZERO); + public MachineJob(ItemStack stack, double ticks) { + this(stack, ticks, Fraction.ZERO); } public CompoundTag serializeNBT() { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/Ext.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/Ext.kt index db18c82c4..2f81423a0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/Ext.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/Ext.kt @@ -1,11 +1,16 @@ package ru.dbotthepony.mc.otm +import com.google.gson.JsonArray +import com.google.gson.JsonElement +import com.google.gson.JsonObject import net.minecraft.core.BlockPos import net.minecraft.core.Direction import net.minecraft.core.Vec3i import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.ListTag import net.minecraft.nbt.Tag +import net.minecraft.world.Container +import net.minecraft.world.item.ItemStack import net.minecraft.world.phys.Vec3 import java.util.function.Consumer @@ -25,6 +30,11 @@ operator fun CompoundTag.set(s: String, value: Boolean) = putBoolean(s, value) operator fun CompoundTag.set(s: String, value: ByteArray) = putByteArray(s, value) operator fun CompoundTag.set(s: String, value: LongArray) = putLongArray(s, value) +operator fun Container.set(index: Int, value: ItemStack) = setItem(index, value) +operator fun Container.get(index: Int): ItemStack = getItem(index) + +operator fun JsonObject.set(s: String, value: JsonElement) = add(s, value) + inline fun CompoundTag.ifHas(s: String, consumer: (Tag) -> Unit) { val tag = get(s) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/BlockPlatePress.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/BlockPlatePress.kt new file mode 100644 index 000000000..a1ab1f49c --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/BlockPlatePress.kt @@ -0,0 +1,28 @@ +package ru.dbotthepony.mc.otm.block + +import net.minecraft.core.BlockPos +import net.minecraft.world.level.Level +import net.minecraft.world.level.block.EntityBlock +import net.minecraft.world.level.block.entity.BlockEntity +import net.minecraft.world.level.block.entity.BlockEntityTicker +import net.minecraft.world.level.block.entity.BlockEntityType +import net.minecraft.world.level.block.state.BlockState +import ru.dbotthepony.mc.otm.Registry +import ru.dbotthepony.mc.otm.block.entity.BlockEntityPlatePress + +class BlockPlatePress(properties: Properties = DEFAULT_PROPERTIES) : BlockMatteryRotatable(properties), EntityBlock { + override fun newBlockEntity(p_153215_: BlockPos, p_153216_: BlockState): BlockEntity { + return BlockEntityPlatePress(p_153215_, p_153216_) + } + + override fun getTicker( + p_153212_: Level, + p_153213_: BlockState, + p_153214_: BlockEntityType + ): BlockEntityTicker? { + if (p_153212_.isClientSide || p_153214_ !== Registry.BlockEntities.PLATE_PRESS) + return null + + return BlockEntityTicker { _, _, _, tile -> if (tile is BlockEntityPlatePress) tile.basicTicker() } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BlockEntityPlatePress.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BlockEntityPlatePress.kt new file mode 100644 index 000000000..83f96438f --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BlockEntityPlatePress.kt @@ -0,0 +1,79 @@ +package ru.dbotthepony.mc.otm.block.entity + +import net.minecraft.core.BlockPos +import net.minecraft.nbt.CompoundTag +import net.minecraft.network.chat.TranslatableComponent +import net.minecraft.world.entity.player.Inventory +import net.minecraft.world.entity.player.Player +import net.minecraft.world.inventory.AbstractContainerMenu +import net.minecraft.world.item.ItemStack +import net.minecraft.world.level.block.state.BlockState +import ru.dbotthepony.mc.otm.Registry +import ru.dbotthepony.mc.otm.block.entity.worker.BlockEntityMatteryWorker +import ru.dbotthepony.mc.otm.block.entity.worker.MachineJob +import ru.dbotthepony.mc.otm.block.entity.worker.MachineJobStatus +import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage +import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.container.MatteryContainerFilter +import ru.dbotthepony.mc.otm.core.Fraction +import ru.dbotthepony.mc.otm.menu.PlatePressMenu +import ru.dbotthepony.mc.otm.set + +class BlockEntityPlatePress(p_155229_: BlockPos, p_155230_: BlockState) : BlockEntityMatteryWorker(Registry.BlockEntities.PLATE_PRESS, p_155229_, p_155230_) { + val container = MatteryContainer(this::setChangedLight, 2) + + val handler = container.handler(object : MatteryContainerFilter { + override fun canInsert(slot: Int, stack: ItemStack): Boolean { + return slot != SLOT_OUTPUT + } + + override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { + return slot != SLOT_INPUT + } + }) + + init { + energy = MatteryMachineEnergyStorage(this::setChangedLight, MatteryMachineEnergyStorage.MachineType.WORKER) + } + + override fun getDefaultDisplayName() = NAME + + override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { + return PlatePressMenu(containerID, inventory, this) + } + + override fun onJobFinish(job: MachineJob): MachineJobStatus { + val resultTag = job.data["result"] as? CompoundTag ?: return MachineJobStatus() + val result = ItemStack.of(resultTag) + + if (result.isEmpty) + return MachineJobStatus() + + if (!container.fullyAddItem(result, start = SLOT_OUTPUT, end = SLOT_OUTPUT)) { + return MachineJobStatus(false, 20) + } + + return MachineJobStatus() + } + + override fun computeNextJob(): MachineJob? { + val level = level ?: return null + val recipe = level.recipeManager.getRecipeFor(Registry.Recipes.PLATE_PRESS, container, level).orElse(null) ?: return null + + val copy = container[SLOT_INPUT].copy() + container[SLOT_INPUT].shrink(1) + container.setChanged(SLOT_INPUT) + copy.count = 1 + + return MachineJob(copy, recipe.workTime.toDouble(), BASELINE_CONSUMPTION, CompoundTag().also { + it["result"] = recipe.resultItem.serializeNBT() + }) + } + + companion object { + private val BASELINE_CONSUMPTION = Fraction(15) + private val NAME = TranslatableComponent("block.overdrive_that_matters.plate_press") + const val SLOT_INPUT = 0 + const val SLOT_OUTPUT = 1 + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/worker/BlockEntityMatteryWorker.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/worker/BlockEntityMatteryWorker.kt index 1715fcd90..dbe2d9990 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/worker/BlockEntityMatteryWorker.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/worker/BlockEntityMatteryWorker.kt @@ -33,10 +33,10 @@ abstract class BlockEntityMatteryWorker(p_155228_: BlockEntityType<*>, p_155229_ val isUnableToProcess: Boolean get() = throttleTicks > 0 - val workProgress: Double + val workProgress: Float get() { - val currentJob = currentJob ?: return 0.0 - return (workTicks / currentJob.ticks()).coerceAtMost(1.0) + val currentJob = currentJob ?: return 0.0f + return (workTicks / currentJob.ticks).coerceAtMost(1.0).toFloat() } override fun saveAdditional(nbt: CompoundTag) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryMachineEnergyStorage.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryMachineEnergyStorage.kt index 88eb850d9..3b689efec 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryMachineEnergyStorage.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryMachineEnergyStorage.kt @@ -21,7 +21,7 @@ open class MatteryMachineEnergyStorage @JvmOverloads constructor( type: MachineType, maxBatteryLevel: Fraction = DEFAULT_MAX_CAPACITY, maxInput: Fraction = DEFAULT_MAX_RECEIVE, - maxOutput: Fraction = maxInput) : this({listener.setChanged()}, type, maxBatteryLevel, maxInput, maxOutput) + maxOutput: Fraction = DEFAULT_MAX_EXTRACT) : this({listener.setChanged()}, type, maxBatteryLevel, maxInput, maxOutput) enum class MachineType { WORKER, GENERATOR, CAPACITOR @@ -97,7 +97,7 @@ open class MatteryMachineEnergyStorage @JvmOverloads constructor( companion object { val DEFAULT_MAX_RECEIVE = Fraction(200) - val DEFAULT_MAX_EXTRACT = Fraction(200) + val DEFAULT_MAX_EXTRACT = DEFAULT_MAX_RECEIVE val DEFAULT_MAX_CAPACITY = Fraction(60000) } } \ No newline at end of file diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/PlatePressScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/PlatePressScreen.kt new file mode 100644 index 000000000..cf3fb4d4c --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/PlatePressScreen.kt @@ -0,0 +1,25 @@ +package ru.dbotthepony.mc.otm.client.screen + +import net.minecraft.network.chat.Component +import net.minecraft.world.entity.player.Inventory +import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel +import ru.dbotthepony.mc.otm.client.screen.panels.SlotPanel +import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel +import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel +import ru.dbotthepony.mc.otm.menu.PlatePressMenu + +class PlatePressScreen(menu: PlatePressMenu, inventory: Inventory, title: Component) : + MatteryScreen(menu, inventory, title) { + override fun makeMainFrame(): FramePanel { + val frame = super.makeMainFrame()!! + + PowerGaugePanel(this, frame, menu.powerWidget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) + SlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE) + + SlotPanel(this, frame, menu.inputSlot, 56f, PROGRESS_SLOT_TOP) + ProgressGaugePanel(this, frame, menu.progressGauge, 78f, PROGRESS_ARROW_TOP) + SlotPanel(this, frame, menu.outputSlot, 104f, PROGRESS_SLOT_TOP) + + return frame + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt index 94a2d51e5..51540105e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt @@ -157,14 +157,14 @@ open class MatteryContainer(val watcher: Runnable, private val size: Int) : Cont open fun getMaxStackSize(slot: Int) = maxStackSize @JvmOverloads - fun addItem(stack: ItemStack, start: Int = 0, end: Int = size, simulate: Boolean = false): ItemStack { - if (stack.isEmpty || start < 0 || end > size || start >= end) - return ItemStack.EMPTY + fun addItem(stack: ItemStack, start: Int = 0, end: Int = size - 1, simulate: Boolean = false): ItemStack { + if (stack.isEmpty || start < 0 || end >= size || start > end) + return stack val copy = stack.copy() // двигаем в одинаковые слоты - for (slot in start until end) { + for (slot in start .. end) { if (ItemStack.isSameItemSameTags(slots[slot], copy)) { val slotStack = slots[slot] val slotLimit = Math.min(getMaxStackSize(slot), slotStack.maxStackSize) @@ -190,7 +190,7 @@ open class MatteryContainer(val watcher: Runnable, private val size: Int) : Cont } // двигаем в пустые слоты - for (slot in start until end) { + for (slot in start .. end) { if (slots[slot].isEmpty) { val diff = Math.min(copy.count, Math.min(getMaxStackSize(slot), copy.maxStackSize)) @@ -212,11 +212,11 @@ open class MatteryContainer(val watcher: Runnable, private val size: Int) : Cont } fun addItem(stack: ItemStack, simulate: Boolean): ItemStack { - return addItem(stack, 0, size, simulate) + return addItem(stack, 0, size - 1, simulate) } @JvmOverloads - fun fullyAddItem(stack: ItemStack, start: Int = 0, end: Int = size): Boolean { + fun fullyAddItem(stack: ItemStack, start: Int = 0, end: Int = size - 1): Boolean { if (!addItem(stack, start, end, true).isEmpty) return false diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/PlatePressMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/PlatePressMenu.kt new file mode 100644 index 000000000..23e03f6de --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/PlatePressMenu.kt @@ -0,0 +1,29 @@ +package ru.dbotthepony.mc.otm.menu + +import net.minecraft.world.SimpleContainer +import net.minecraft.world.entity.player.Inventory +import ru.dbotthepony.mc.otm.Registry +import ru.dbotthepony.mc.otm.block.entity.BlockEntityPlatePress +import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget + +class PlatePressMenu @JvmOverloads constructor( + containerID: Int, + inventory: Inventory, + tile: BlockEntityPlatePress? = null +) : PoweredMatteryMenu(Registry.Menus.PLATE_PRESS, containerID, inventory, tile) { + val container = tile?.container ?: SimpleContainer(2) + + val inputSlot = MatterySlot(container, BlockEntityPlatePress.SLOT_INPUT) + val outputSlot = MachineOutputSlot(container, BlockEntityPlatePress.SLOT_OUTPUT) + + val progressGauge = if (tile != null) ProgressGaugeWidget(this, tile::workProgress, tile::isUnableToProcess) else ProgressGaugeWidget(this) + + init { + addSlot(inputSlot) + addSlot(outputSlot) + addInventorySlots() + } + + override fun getWorkingSlotStart() = 0 + override fun getWorkingSlotEnd() = 2 +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/recipes/Helpers.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/recipes/Helpers.kt new file mode 100644 index 000000000..0bba35061 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/recipes/Helpers.kt @@ -0,0 +1,57 @@ +package ru.dbotthepony.mc.otm.recipes + +import com.google.gson.JsonElement +import com.google.gson.JsonObject +import com.google.gson.JsonPrimitive +import net.minecraft.data.structures.SnbtToNbt +import net.minecraft.resources.ResourceLocation +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items +import net.minecraftforge.registries.ForgeRegistries +import ru.dbotthepony.mc.otm.set + +fun stackFromJson(obj: JsonElement, field: String = ""): ItemStack { + if (obj is JsonPrimitive) { + check(obj.isString) { "Field $field is supposed to be an Item, but it is malformed (not a string and not an object)" } + val item = ForgeRegistries.ITEMS.getValue(ResourceLocation(obj.asString)) ?: return ItemStack.EMPTY + + if (item === Items.AIR) { + return ItemStack.EMPTY + } + + return ItemStack(item, 1) + } + + if (obj is JsonObject) { + val name = obj["name"] as? JsonPrimitive ?: throw IllegalStateException("Invalid name of $field") + check(name.isString) { "Invalid name of $field (supposed to be a string)" } + val item = ForgeRegistries.ITEMS.getValue(ResourceLocation(name.asString)) ?: return ItemStack.EMPTY + + val count = (obj["count"] as? JsonPrimitive)?.let { + try { + return@let it.asInt + } catch(err: Throwable) { + throw IllegalStateException("Invalid format of count of $field (supposed to be a number)", err) + } + } ?: 1 + + check(count > 0) { "Field count of $field does not make any sense" } + + return ItemStack(item, count) + } + + throw IllegalStateException("Invalid or missing $field") +} + +fun stackToJson(stack: ItemStack, field: String = ""): JsonElement { + check(stack.count > 0) { "ItemStack $field is empty" } + + if (stack.count == 1) { + return JsonPrimitive(stack.item.registryName!!.toString()) + } + + return JsonObject().also { + it["name"] = JsonPrimitive(stack.item.registryName!!.toString()) + it["count"] = JsonPrimitive(stack.count) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/recipes/PlatePressRecipe.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/recipes/PlatePressRecipe.kt new file mode 100644 index 000000000..262c0f3d9 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/recipes/PlatePressRecipe.kt @@ -0,0 +1,107 @@ +package ru.dbotthepony.mc.otm.recipes + +import com.google.gson.JsonObject +import com.google.gson.JsonPrimitive +import net.minecraft.network.FriendlyByteBuf +import net.minecraft.resources.ResourceLocation +import net.minecraft.world.Container +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.crafting.Ingredient +import net.minecraft.world.item.crafting.Recipe +import net.minecraft.world.item.crafting.RecipeSerializer +import net.minecraft.world.item.crafting.RecipeType +import net.minecraft.world.level.Level +import net.minecraftforge.registries.ForgeRegistryEntry +import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.Registry +import ru.dbotthepony.mc.otm.block.entity.BlockEntityPlatePress +import ru.dbotthepony.mc.otm.get + +class PlatePressRecipe( + private val id: ResourceLocation, + val input: Ingredient, + val output: Ingredient, + val count: Int, + val workTime: Int = 200 +) : Recipe { + override fun matches(container: Container, p_44003_: Level): Boolean { + if (output.isEmpty || input.isEmpty) + return false + + return input.test(container[BlockEntityPlatePress.SLOT_INPUT]) + } + + private var outputStack: ItemStack? = null + + override fun assemble(p_44001_: Container): ItemStack = resultItem.copy() + override fun canCraftInDimensions(p_43999_: Int, p_44000_: Int) = true + override fun getResultItem(): ItemStack { + if (outputStack == null) { + if (output.isEmpty) { + outputStack = ItemStack.EMPTY + } else { + val items = output.items + var bestMatch = items[0] + + // прежде всего выдавать предметы из OTM + for (item in items) { + if (item.item.registryName?.namespace == OverdriveThatMatters.MOD_ID) { + bestMatch = item + break + } + } + + outputStack = bestMatch.copy() + outputStack!!.count = this.count + } + } + + return outputStack!! + } + + override fun getId() = id + + override fun getSerializer(): RecipeSerializer<*> { + return PlatePressRecipeFactory + } + + override fun getType(): RecipeType = Registry.Recipes.PLATE_PRESS +} + +object PlatePressRecipeFactory : ForgeRegistryEntry>(), RecipeSerializer { + init { + registryName = Registry.Names.PLATE_PRESS + } + + override fun fromJson(loc: ResourceLocation, obj: JsonObject): PlatePressRecipe { + val input = try { + Ingredient.fromJson(obj["input"] ?: throw IllegalStateException("Recipe $loc has no input field defined")) + } catch (err: Throwable) { + throw IllegalStateException("Input of $loc is malformed", err) + } + + val result = try { + Ingredient.fromJson(obj["result"] ?: throw IllegalStateException("Recipe $loc has no result field defined")) + } catch (err: Throwable) { + throw IllegalStateException("Result of $loc is malformed", err) + } + + val workTime = (obj["work_time"] as? JsonPrimitive)?.let { return@let try {it.asInt} catch(err: Throwable) {throw IllegalStateException("Invalid work_time")} } ?: 200 + + check(workTime >= 0) { "work_time of $loc does not make any sense" } + + val count = ((obj["result"] as JsonObject)["count"] as? JsonPrimitive)?.let { return@let try {it.asInt} catch(err: Throwable) {throw IllegalStateException("Invalid result.count")} } ?: 1 + + return PlatePressRecipe(loc, input, result, count, workTime) + } + + override fun fromNetwork(loc: ResourceLocation, buff: FriendlyByteBuf): PlatePressRecipe { + return PlatePressRecipe(loc, Ingredient.fromNetwork(buff), Ingredient.fromNetwork(buff), buff.readInt()) + } + + override fun toNetwork(buff: FriendlyByteBuf, recipe: PlatePressRecipe) { + recipe.input.toNetwork(buff) + recipe.output.toNetwork(buff) + buff.writeInt(recipe.workTime) + } +} diff --git a/src/main/resources/assets/overdrive_that_matters/lang/en_us.json b/src/main/resources/assets/overdrive_that_matters/lang/en_us.json index 152c70191..d3b2a8fe3 100644 --- a/src/main/resources/assets/overdrive_that_matters/lang/en_us.json +++ b/src/main/resources/assets/overdrive_that_matters/lang/en_us.json @@ -165,6 +165,7 @@ "block.overdrive_that_matters.chemical_generator": "Chemical Generator", "block.overdrive_that_matters.drive_rack": "Condensation Drive Rack", "block.overdrive_that_matters.item_monitor": "Item Monitor", + "block.overdrive_that_matters.plate_press": "Plate Press", "otm.container.matter_panel.number_input": "Input replication task count",