From 8bd6852d103dd1030f1f324e4044aa990d7f82f1 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sun, 30 Jan 2022 13:02:03 +0700 Subject: [PATCH] Matter Recycler, Matter Dust and some fixes --- .../ru/dbotthepony/mc/otm/datagen/DataGen.kt | 1 + .../java/ru/dbotthepony/mc/otm/Registry.java | 19 ++ .../block/entity/worker/WorkTickContext.java | 3 +- .../otm/capability/matter/IMatterHandler.java | 2 +- .../mc/otm/block/BlockMatterRecycler.kt | 28 +++ .../entity/BlockEntityMatterDecomposer.kt | 111 +++++++++-- .../block/entity/BlockEntityMatterRecycler.kt | 182 ++++++++++++++++++ .../entity/worker/BlockEntityMatteryWorker.kt | 52 ++--- .../client/screen/ScreenMatterDecomposer.kt | 3 +- .../otm/client/screen/ScreenMatterRecycler.kt | 26 +++ .../otm/client/screen/ScreenMatterScanner.kt | 1 - .../mc/otm/container/MatteryContainer.kt | 10 + .../mc/otm/core/ImpreciseFraction.kt | 28 ++- .../dbotthepony/mc/otm/item/ItemMatterDust.kt | 75 ++++++++ .../mc/otm/matter/MatterRegistry.kt | 49 ++++- .../mc/otm/menu/MenuMatterDecomposer.kt | 20 +- .../mc/otm/menu/MenuMatterRecycler.kt | 47 +++++ .../overdrive_that_matters/lang/en_us.json | 6 + .../tags/blocks/mineable/pickaxe.json | 1 + .../tags/blocks/needs_iron_tool.json | 1 + 20 files changed, 598 insertions(+), 67 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/block/BlockMatterRecycler.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterRecycler.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ScreenMatterRecycler.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/item/ItemMatterDust.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/menu/MenuMatterRecycler.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 c0f55d033..d2bfae73a 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/DataGen.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/DataGen.kt @@ -350,6 +350,7 @@ object DataGen { tile(Blocks.MATTER_DECOMPOSER, TileNbtCopy("container"), TileNbtCopy("matter"), *workerTags) tile(Blocks.MATTER_REPLICATOR, TileNbtCopy("container"), TileNbtCopy("matter"), *workerTags) + tile(Blocks.MATTER_RECYCLER, TileNbtCopy("container"), TileNbtCopy("matter"), *workerTags) tile(Blocks.MATTER_SCANNER, TileNbtCopy("container"), *workerTags) tile(Blocks.PLATE_PRESS, TileNbtCopy("container"), *workerTags) diff --git a/src/main/java/ru/dbotthepony/mc/otm/Registry.java b/src/main/java/ru/dbotthepony/mc/otm/Registry.java index 650c55e54..a3e0b32dc 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/Registry.java +++ b/src/main/java/ru/dbotthepony/mc/otm/Registry.java @@ -252,6 +252,7 @@ public class Registry { 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 MATTER_RECYCLER = loc("matter_recycler"); // нужен рецепт public static final ResourceLocation DEBUG_EXPLOSION_SMALL = loc("debug_explosion_small"); public static final ResourceLocation DEBUG_SPHERE_POINTS = loc("debug_sphere_points"); @@ -272,6 +273,7 @@ public class Registry { // items public static final ResourceLocation GRAVITATIONAL_DISRUPTOR = loc("gravitational_disruptor"); + public static final ResourceLocation MATTER_DUST = loc("matter_dust"); public static final ResourceLocation PILL_ANDROID = loc("pill_android"); public static final ResourceLocation PILL_HUMANE = loc("pill_humane"); @@ -415,6 +417,7 @@ public class Registry { 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 BlockMatterRecycler MATTER_RECYCLER = new BlockMatterRecycler(); public static final BlockExplosionDebugger DEBUG_EXPLOSION_SMALL = new BlockExplosionDebugger(); public static final BlockSphereDebugger DEBUG_SPHERE_POINTS = new BlockSphereDebugger(); @@ -500,6 +503,7 @@ public class Registry { ENERGY_COUNTER.setRegistryName(Names.ENERGY_COUNTER); CHEMICAL_GENERATOR.setRegistryName(Names.CHEMICAL_GENERATOR); PLATE_PRESS.setRegistryName(Names.PLATE_PRESS); + MATTER_RECYCLER.setRegistryName(Names.MATTER_RECYCLER); GRAVITATION_STABILIZER.setRegistryName(Names.GRAVITATION_STABILIZER); GRAVITATION_STABILIZER_LENS.setRegistryName(Names.GRAVITATION_STABILIZER_LENS); @@ -541,6 +545,7 @@ public class Registry { event.getRegistry().register(PLATE_PRESS); event.getRegistry().register(GRAVITATION_STABILIZER); event.getRegistry().register(GRAVITATION_STABILIZER_LENS); + event.getRegistry().register(MATTER_RECYCLER); event.getRegistry().register(DEBUG_EXPLOSION_SMALL); event.getRegistry().register(DEBUG_SPHERE_POINTS); @@ -590,6 +595,7 @@ public class Registry { 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 MATTER_RECYCLER = new BlockItem(Blocks.MATTER_RECYCLER, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB)); public static final BlockItem GRAVITATION_STABILIZER = new BlockItem(Blocks.GRAVITATION_STABILIZER, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB)) { @Override public void appendHoverText(@Nonnull ItemStack p_40572_, @Nullable Level p_40573_, @Nonnull List p_40574_, @Nonnull TooltipFlag p_40575_) { @@ -605,6 +611,8 @@ public class Registry { 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)); + public static final ItemMatterDust MATTER_DUST = new ItemMatterDust(); + public static final Item TRITANIUM_ORE_CLUMP = new Item(new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB)); public static final Item TRITANIUM_INGOT = new Item(new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB)); @@ -763,6 +771,8 @@ public class Registry { CHEMICAL_GENERATOR.setRegistryName(Names.CHEMICAL_GENERATOR); PLATE_PRESS.setRegistryName(Names.PLATE_PRESS); GRAVITATION_STABILIZER.setRegistryName(Names.GRAVITATION_STABILIZER); + MATTER_RECYCLER.setRegistryName(Names.MATTER_RECYCLER); + MATTER_DUST.setRegistryName(Names.MATTER_DUST); DEBUG_EXPLOSION_SMALL.setRegistryName(Names.DEBUG_EXPLOSION_SMALL); DEBUG_SPHERE_POINTS.setRegistryName(Names.DEBUG_SPHERE_POINTS); @@ -855,6 +865,8 @@ public class Registry { event.getRegistry().register(CHEMICAL_GENERATOR); event.getRegistry().register(PLATE_PRESS); event.getRegistry().register(GRAVITATION_STABILIZER); + event.getRegistry().register(MATTER_DUST); + event.getRegistry().register(MATTER_RECYCLER); event.getRegistry().register(DEBUG_EXPLOSION_SMALL); event.getRegistry().register(DEBUG_SPHERE_POINTS); @@ -958,6 +970,7 @@ public class Registry { 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 GRAVITATION_STABILIZER = BlockEntityType.Builder.of(BlockEntityGravitationStabilizer::new, Blocks.GRAVITATION_STABILIZER).build(null); + public static final BlockEntityType MATTER_RECYCLER = BlockEntityType.Builder.of(BlockEntityMatterRecycler::new, Blocks.MATTER_RECYCLER).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); @@ -982,6 +995,7 @@ public class Registry { CHEMICAL_GENERATOR.setRegistryName(Names.CHEMICAL_GENERATOR); PLATE_PRESS.setRegistryName(Names.PLATE_PRESS); GRAVITATION_STABILIZER.setRegistryName(Names.GRAVITATION_STABILIZER); + MATTER_RECYCLER.setRegistryName(Names.MATTER_RECYCLER); DEBUG_EXPLOSION_SMALL.setRegistryName(Names.DEBUG_EXPLOSION_SMALL); DEBUG_SPHERE_POINTS.setRegistryName(Names.DEBUG_SPHERE_POINTS); @@ -1009,6 +1023,7 @@ public class Registry { event.getRegistry().register(CHEMICAL_GENERATOR); event.getRegistry().register(PLATE_PRESS); event.getRegistry().register(GRAVITATION_STABILIZER); + event.getRegistry().register(MATTER_RECYCLER); event.getRegistry().register(DEBUG_EXPLOSION_SMALL); event.getRegistry().register(DEBUG_SPHERE_POINTS); @@ -1285,6 +1300,7 @@ public class Registry { public static final MenuType ENERGY_COUNTER = new MenuType<>(MenuEnergyCounter::new); public static final MenuType CHEMICAL_GENERATOR = new MenuType<>(MenuChemicalGenerator::new); public static final MenuType PLATE_PRESS = new MenuType<>(MenuPlatePress::new); + public static final MenuType MATTER_RECYCLER = new MenuType<>(MenuMatterRecycler::new); static { ANDROID_STATION.setRegistryName(Names.ANDROID_STATION); @@ -1303,6 +1319,7 @@ public class Registry { ENERGY_COUNTER.setRegistryName(Names.ENERGY_COUNTER); CHEMICAL_GENERATOR.setRegistryName(Names.CHEMICAL_GENERATOR); PLATE_PRESS.setRegistryName(Names.PLATE_PRESS); + MATTER_RECYCLER.setRegistryName(Names.MATTER_RECYCLER); } @SubscribeEvent @@ -1324,6 +1341,7 @@ public class Registry { event.getRegistry().register(ENERGY_COUNTER); event.getRegistry().register(CHEMICAL_GENERATOR); event.getRegistry().register(PLATE_PRESS); + event.getRegistry().register(MATTER_RECYCLER); // OverdriveThatMatters.LOGGER.info("Registered menus"); } @@ -1347,6 +1365,7 @@ public class Registry { MenuScreens.register(ENERGY_COUNTER, ScreenEnergyCounter::new); MenuScreens.register(CHEMICAL_GENERATOR, ScreenChemicalGenerator::new); MenuScreens.register(PLATE_PRESS, ScreenPlatePress::new); + MenuScreens.register(MATTER_RECYCLER, ScreenMatterRecycler::new); // OverdriveThatMatters.LOGGER.info("Registered screens"); } diff --git a/src/main/java/ru/dbotthepony/mc/otm/block/entity/worker/WorkTickContext.java b/src/main/java/ru/dbotthepony/mc/otm/block/entity/worker/WorkTickContext.java index 30524cc95..481d862e9 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/block/entity/worker/WorkTickContext.java +++ b/src/main/java/ru/dbotthepony/mc/otm/block/entity/worker/WorkTickContext.java @@ -1,13 +1,12 @@ package ru.dbotthepony.mc.otm.block.entity.worker; import net.minecraft.MethodsReturnNonnullByDefault; -import ru.dbotthepony.mc.otm.core.Fraction; import ru.dbotthepony.mc.otm.core.ImpreciseFraction; import javax.annotation.ParametersAreNonnullByDefault; @MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault -public record WorkTickContext(MachineJob job, ImpreciseFraction requiredPower, ImpreciseFraction extractedPower, ImpreciseFraction workSpeed) { +public record WorkTickContext(MachineJob job, ImpreciseFraction requiredPower, ImpreciseFraction extractedPower, double ticksAdvanced) { } diff --git a/src/main/java/ru/dbotthepony/mc/otm/capability/matter/IMatterHandler.java b/src/main/java/ru/dbotthepony/mc/otm/capability/matter/IMatterHandler.java index 359f8ed32..619a3b53b 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/capability/matter/IMatterHandler.java +++ b/src/main/java/ru/dbotthepony/mc/otm/capability/matter/IMatterHandler.java @@ -26,6 +26,6 @@ public interface IMatterHandler { MatterDirection getDirection(); default ImpreciseFraction getMissingMatter() { - return getMaxStoredMatter().minus(getStoredMatter()); + return getMaxStoredMatter().minus(getStoredMatter()).moreThanZero(); } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/BlockMatterRecycler.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/BlockMatterRecycler.kt new file mode 100644 index 000000000..b8b25a0c0 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/BlockMatterRecycler.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.BlockEntityMatterRecycler + +class BlockMatterRecycler : BlockMatteryRotatable(), EntityBlock { + override fun newBlockEntity(p_153215_: BlockPos, p_153216_: BlockState): BlockEntity { + return BlockEntityMatterRecycler(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.MATTER_RECYCLER) + return null + + return BlockEntityTicker { _, _, _, tile -> if (tile is BlockEntityMatterRecycler) tile.tick() } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterDecomposer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterDecomposer.kt index 08e74df42..d8188cdfb 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterDecomposer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterDecomposer.kt @@ -43,9 +43,9 @@ class BlockEntityMatterDecomposer(pos: BlockPos, state: BlockState) energy = MatteryMachineEnergyStorage( this, MatteryMachineEnergyStorage.MachineType.WORKER, - ImpreciseFraction(400000), - ImpreciseFraction(2000), - ImpreciseFraction(2000) + ENERGY_STORAGE, + MAX_IO, + MAX_IO ) } @@ -64,12 +64,12 @@ class BlockEntityMatterDecomposer(pos: BlockPos, state: BlockState) // вход, выход @JvmField - val itemContainer = MatteryContainer(this::setChangedLight, 2) + val container = MatteryContainer(this::setChangedLight, 3) private val itemHandler = LazyOptional.of { - itemContainer.handler( - { slot: Int, stack: ItemStack -> slot == 0 && canDecompose(stack) }, - { slot: Int, amount: Int, stack: ItemStack -> slot == 1 }) + container.handler( + { slot: Int, stack: ItemStack -> slot == INPUT_SLOT && canDecompose(stack) }, + { slot: Int, _: Int, _: ItemStack -> slot != INPUT_SLOT }) } override fun getDefaultDisplayName(): Component { @@ -82,7 +82,7 @@ class BlockEntityMatterDecomposer(pos: BlockPos, state: BlockState) override fun saveAdditional(nbt: CompoundTag) { super.saveAdditional(nbt) - nbt["container"] = itemContainer.serializeNBT() + nbt["container"] = container.serializeNBT() nbt["matter"] = matter.serializeNBT() } @@ -93,7 +93,7 @@ class BlockEntityMatterDecomposer(pos: BlockPos, state: BlockState) matter.deserializeNBT(it) } - itemContainer.deserializeNBT(nbt["container"]) + container.deserializeNBT(nbt["container"]) } override fun reviveCaps() { @@ -119,12 +119,74 @@ class BlockEntityMatterDecomposer(pos: BlockPos, state: BlockState) } override fun onJobFinish(job: MachineJob): MachineJobStatus { - matter.receiveMatterInner(getMatterValue(job.stack()).value, false) + var matterValue = ImpreciseFraction.deserializeNBT(job.data["value"]) + + if (job.data.getBoolean("to_dust")) { + val item = Registry.Items.MATTER_DUST + + while (matterValue > ImpreciseFraction.ZERO) { + val stack = container[OUTPUT_DUST_MAIN] + + // первый слот пустой + if (stack.isEmpty) { + container[OUTPUT_DUST_MAIN] = ItemStack(item, 1).also { + matterValue -= item.addMatterValue(it, matterValue, false) + } + // первый слот не пустой, но мы можем влить туда материю + } else if (!item.isFull(stack) && stack.count == 1) { + matterValue -= item.addMatterValue(stack, matterValue, false) + container.setChanged(OUTPUT_DUST_MAIN) + // первый слот не пустой и мы не можем влить туда материю + } else { + val stack2 = container[OUTPUT_DUST_STACKING] + + // второй слот пустой + if (stack2.isEmpty) { + container[OUTPUT_DUST_STACKING] = ItemStack(item, 1).also { + matterValue -= item.addMatterValue(it, matterValue, false) + } + // второй слот не пустой, но мы можем влить туда материю + } else if (!item.isFull(stack2)) { + if (stack2.count != 1) { + job.data["value"] = matterValue.serializeNBT() + return MachineJobStatus(false, 20) + } + + matterValue -= item.addMatterValue(stack2, matterValue, false) + container.setChanged(OUTPUT_DUST_STACKING) + } + + // можем ли мы стакнуть материю из второго слота в первый? + if (!stack2.isEmpty && item.isFull(stack2)) { + if (ItemStack.isSameItemSameTags(stack, stack2) && container.getMaxStackSizeWithItem(OUTPUT_DUST_MAIN) >= stack.count + 1) { + stack.count++ + stack2.count-- + + container.setChanged(OUTPUT_DUST_MAIN) + container.setChanged(OUTPUT_DUST_STACKING) + } else { + job.data["value"] = matterValue.serializeNBT() + return MachineJobStatus(false, 20) + } + } + } + } + + return MachineJobStatus() + } + + matterValue -= matter.receiveMatterInner(matterValue, false) + + if (matterValue.isPositive) { + job.data["value"] = matterValue.serializeNBT() + return MachineJobStatus(false, 20) + } + return MachineJobStatus() } override fun computeNextJob(): MachineJob? { - val stack = itemContainer.getItem(0) + val stack = container[INPUT_SLOT] if (!stack.isEmpty) { val copy = stack.copy() @@ -133,9 +195,13 @@ class BlockEntityMatterDecomposer(pos: BlockPos, state: BlockState) if (canDecompose(copy)) { val matter = getMatterValue(copy) - if (!matter.isZero && this.matter.canReceiveAll(matter.value)) { - stack.shrink(1) - return MachineJob(copy, matter.complexity * baselineComplexityDecomposeTicks, BASE_CONSUMPTION) + if (!matter.isZero) { + stack.count-- + + return MachineJob(copy, matter.complexity * baselineComplexityDecomposeTicks, BASE_CONSUMPTION, CompoundTag().also { + it["to_dust"] = (level?.random?.nextDouble() ?: 1.0) <= 1.0 + it["value"] = matter.value.serializeNBT() + }) } } } @@ -160,13 +226,13 @@ class BlockEntityMatterDecomposer(pos: BlockPos, state: BlockState) } fun tick() { - batteryChargeLoop(); - workerLoop(); + batteryChargeLoop() + workerLoop() - val grid = node.graph as MatterNetworkGraph? + val grid = node.graph as MatterNetworkGraph? ?: return - if (!matter.storedMatter.isZero && grid != null) { - val diff = matter.extractMatterInner(matter.getStoredMatter(), true) + if (!matter.storedMatter.isZero) { + val diff = matter.extractMatterInner(matter.storedMatter, true) val diff2 = grid.receiveMatter(diff, true) matter.extractMatterInner(diff2, false) @@ -175,8 +241,15 @@ class BlockEntityMatterDecomposer(pos: BlockPos, state: BlockState) } companion object { + const val INPUT_SLOT = 0 + const val OUTPUT_DUST_MAIN = 1 + const val OUTPUT_DUST_STACKING = 2 + private val CAPACITY = ImpreciseFraction("20") private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.matter_decomposer") private val BASE_CONSUMPTION = ImpreciseFraction(240) + + private val ENERGY_STORAGE = ImpreciseFraction(400_000) + private val MAX_IO = ImpreciseFraction(2_000) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterRecycler.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterRecycler.kt new file mode 100644 index 000000000..aa23abe78 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BlockEntityMatterRecycler.kt @@ -0,0 +1,182 @@ +package ru.dbotthepony.mc.otm.block.entity + +import net.minecraft.core.BlockPos +import net.minecraft.core.Direction +import net.minecraft.nbt.CompoundTag +import net.minecraft.network.chat.TranslatableComponent +import net.minecraft.server.level.ServerLevel +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.Level +import net.minecraft.world.level.block.state.BlockState +import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.common.util.LazyOptional +import net.minecraftforge.items.CapabilityItemHandler +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.block.entity.worker.WorkTickContext +import ru.dbotthepony.mc.otm.capability.MatteryCapability +import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage +import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler +import ru.dbotthepony.mc.otm.capability.matter.MatterHandlerCapability +import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.container.MatteryContainerFilter +import ru.dbotthepony.mc.otm.core.ImpreciseFraction +import ru.dbotthepony.mc.otm.graph.Graph6Node +import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode +import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph +import ru.dbotthepony.mc.otm.ifHas +import ru.dbotthepony.mc.otm.item.ItemMatterDust +import ru.dbotthepony.mc.otm.menu.MenuMatterRecycler +import ru.dbotthepony.mc.otm.set + +class BlockEntityMatterRecycler(blockPos: BlockPos, blockState: BlockState) + : BlockEntityMatteryWorker(Registry.BlockEntities.MATTER_RECYCLER, blockPos, blockState), IMatterGraphNode { + val matter = MatterHandlerCapability(this::setChangedLight, IMatterHandler.MatterDirection.EXTRACT, STORAGE) + val container = MatteryContainer(this::setChangedLight, 1) + private val node = Graph6Node(this) + private var resolverNode = LazyOptional.of { this } + private var valid = true + + override fun getAsMatterNode(): Graph6Node { + return node + } + + override fun getMatterHandler(): IMatterHandler { + return matter + } + + init { + energy = MatteryMachineEnergyStorage(this, MatteryMachineEnergyStorage.MachineType.WORKER, MAX_POWER) + } + + private val itemHandler = container.handler(object : MatteryContainerFilter { + override fun canInsert(slot: Int, stack: ItemStack): Boolean { + return stack.item is ItemMatterDust + } + + override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { + return false + } + }) + + override fun invalidateCaps() { + super.invalidateCaps() + matter.invalidate() + itemHandler.invalidate() + resolverNode.invalidate() + } + + override fun reviveCaps() { + super.reviveCaps() + matter.revive() + itemHandler.revive() + resolverNode = LazyOptional.of { this } + } + + override fun setRemoved() { + super.setRemoved() + node.destroy(::MatterNetworkGraph) + } + + override fun setLevel(p_155231_: Level) { + super.setLevel(p_155231_) + + if (p_155231_ is ServerLevel) + MatterNetworkGraph.discoverFull(this, node) + } + + override fun saveAdditional(nbt: CompoundTag) { + super.saveAdditional(nbt) + nbt["matter"] = matter.serializeNBT() + nbt["container"] = container.serializeNBT() + } + + override fun load(nbt: CompoundTag) { + super.load(nbt) + nbt.ifHas("matter", CompoundTag::class.java, matter::deserializeNBT) + container.deserializeNBT(nbt["container"]) + } + + override fun getCapability(cap: Capability, side: Direction?): LazyOptional { + if (!valid) + return super.getCapability(cap, side) + + if (cap === CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { + return itemHandler.get().cast() + } else if (cap === MatteryCapability.MATTER) { + return matter.get().cast() + } else if (cap === MatteryCapability.MATTER_NODE) { + return resolverNode.cast() + } + + return super.getCapability(cap, side) + } + + override fun getDefaultDisplayName() = NAME + + override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { + return MenuMatterRecycler(containerID, inventory, this) + } + + override fun onJobFinish(job: MachineJob): MachineJobStatus { + // вся логика в onWorkTick + return MachineJobStatus() + } + + override fun computeNextJob(): MachineJob? { + if (matter.missingMatter.isZero) + return null + + val stack = container[0] + + if (stack.isEmpty || stack.item !is ItemMatterDust) { + return null + } + + val copy = stack.copy() + copy.count = 1 + + val dustMatter = (stack.item as ItemMatterDust).getMatterValue(copy) ?: return null + stack.shrink(1) + return MachineJob(copy, dustMatter.value.toDouble() * MATTER_TICKS, POWER_CONSUMPTION) + } + + override fun onWorkTick(context: WorkTickContext): MachineJobStatus { + if ((level?.random?.nextDouble() ?: 1.0) <= 0.4) + return MachineJobStatus() + + val receive = if (context.ticksAdvanced == 1.0) MATTER_PER_TICK else MATTER_PER_TICK * context.ticksAdvanced + val received = matter.receiveMatterInner(receive, true) + + if (receive != received) + return MachineJobStatus(false, 20) + + matter.receiveMatterInner(receive, false) + return MachineJobStatus() + } + + fun tick() { + basicTicker() + + val graph = node.graph as MatterNetworkGraph? ?: return + val received = graph.receiveMatter(matter.storedMatter, false) + + if (!received.isZero) { + matter.extractMatterInner(received, false) + } + } + + companion object { + private val NAME = TranslatableComponent("block.overdrive_that_matters.matter_recycler") + private val STORAGE = ImpreciseFraction(40) + private val POWER_CONSUMPTION = ImpreciseFraction(80) + private val MAX_POWER = ImpreciseFraction(80_000) + private const val MATTER_TICKS = 200.0 + private val MATTER_PER_TICK = ImpreciseFraction(1.0 / MATTER_TICKS) + } +} 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 a22bb60da..f3729d24c 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 @@ -7,7 +7,6 @@ import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatteryPowered import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.DoubleTag import net.minecraft.world.level.block.Block -import ru.dbotthepony.mc.otm.core.Fraction import ru.dbotthepony.mc.otm.core.ImpreciseFraction import ru.dbotthepony.mc.otm.ifHas import ru.dbotthepony.mc.otm.set @@ -154,10 +153,24 @@ abstract class BlockEntityMatteryWorker(p_155228_: BlockEntityType<*>, p_155229_ if (workTicks < currentJob.ticks) { if (!currentJob.power.isZero) { - val extractedPower = energy.extractEnergyInner(currentJob.power, true) - val workSpeed = extractedPower.div(currentJob.power) + // сколько осталось тиков работать + val ticksLeft = currentJob.ticks - workTicks + val requiredPower: ImpreciseFraction - val status = onWorkTick(WorkTickContext(currentJob, currentJob.power, extractedPower, workSpeed)) + // запрос энергии на то количество, сколько действительно осталось работать + if (ticksLeft > 1.0) { + requiredPower = currentJob.power + } else { + requiredPower = currentJob.power * ticksLeft + } + + val extractedPower = energy.extractEnergyInner(requiredPower, true) + + // сколько тиков мы "проработали" + // может быть меньше, чем единица, если недостаточно питания или мы завершаем работу, + // для которой осталось дробное количество тиков + val ticksAdvanced = (extractedPower / requiredPower).toDouble().coerceAtMost(ticksLeft) + val status = onWorkTick(WorkTickContext(currentJob, requiredPower, extractedPower, ticksAdvanced)) if (!status.valid()) { throttleTicks += status.throttle @@ -167,32 +180,27 @@ abstract class BlockEntityMatteryWorker(p_155228_: BlockEntityType<*>, p_155229_ workingTicksAnim++ errorTicksAnim = 0 - val updatedWorkTicks = workSpeed.toDouble() + workTicks + val updatedWorkTicks = workTicks + ticksAdvanced - if (updatedWorkTicks > currentJob.ticks) { + if (updatedWorkTicks >= currentJob.ticks) { workTicks = currentJob.ticks + energy.extractEnergyInner(extractedPower * (1.0 - (updatedWorkTicks - currentJob.ticks)), false) - energy.extractEnergyInner( - extractedPower.times(1.0 - (updatedWorkTicks - currentJob.ticks())), - false - ) + val finish = onJobFinish(currentJob) + + if (finish.valid) { + this.currentJob = null + workTicks = 0.0 + } else { + throttleTicks += finish.throttle + } } else { workTicks = updatedWorkTicks energy.extractEnergyInner(extractedPower, false) - - if (workTicks >= currentJob.ticks) { - val finish = onJobFinish(currentJob) - - if (finish.valid) { - this.currentJob = null - workTicks = 0.0 - } else { - throttleTicks += finish.throttle - } - } } } else { - val status = onWorkTick(WorkTickContext(currentJob, ImpreciseFraction.ZERO, ImpreciseFraction.ZERO, ImpreciseFraction.ONE)) + val ticksLeft = (currentJob.ticks - workTicks).coerceAtMost(1.0) + val status = onWorkTick(WorkTickContext(currentJob, ImpreciseFraction.ZERO, ImpreciseFraction.ZERO, ticksLeft)) if (!status.valid) { throttleTicks += status.throttle() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ScreenMatterDecomposer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ScreenMatterDecomposer.kt index 3c7459a35..7b927c8e1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ScreenMatterDecomposer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ScreenMatterDecomposer.kt @@ -22,7 +22,8 @@ class ScreenMatterDecomposer(p_97741_: MenuMatterDecomposer, p_97742_: Inventory SlotPanel(this, frame, menu.input, 56f, PROGRESS_SLOT_TOP) ProgressGaugePanel(this, frame, menu.progressWidget, 78f, PROGRESS_ARROW_TOP) - SlotPanel(this, frame, menu.output, 104f, PROGRESS_SLOT_TOP) + SlotPanel(this, frame, menu.outputMain, 104f, PROGRESS_SLOT_TOP) + SlotPanel(this, frame, menu.outputStacking, 122f, PROGRESS_SLOT_TOP) return frame } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ScreenMatterRecycler.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ScreenMatterRecycler.kt new file mode 100644 index 000000000..4703d210b --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ScreenMatterRecycler.kt @@ -0,0 +1,26 @@ +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.MatterGaugePanel +import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel +import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel +import ru.dbotthepony.mc.otm.menu.MenuMatterRecycler + +class ScreenMatterRecycler(menu: MenuMatterRecycler, inventory: Inventory, title: Component) : MatteryScreen(menu, inventory, title) { + override fun makeMainFrame(): FramePanel { + val frame = super.makeMainFrame()!! + + val m = PowerGaugePanel(this, frame, menu.powerWidget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) + MatterGaugePanel(this, frame, menu.matter, LEFT_MARGIN + m.width, GAUGE_TOP_WITH_SLOT) + + SlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE) + + ProgressGaugePanel(this, frame, menu.progress, 63f, PROGRESS_ARROW_TOP).flop = true + SlotPanel(this, frame, menu.input, 93f, PROGRESS_SLOT_TOP) + + return frame + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ScreenMatterScanner.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ScreenMatterScanner.kt index 8e0344e31..96582c69e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ScreenMatterScanner.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ScreenMatterScanner.kt @@ -14,7 +14,6 @@ class ScreenMatterScanner(p_97741_: MenuMatterScanner, p_97742_: Inventory, p_97 override fun makeMainFrame(): FramePanel { val frame = super.makeMainFrame()!! - val m = PowerGaugePanel(this, frame, menu.powerWidget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) PatternGaugePanel(this, frame, menu.patterns, LEFT_MARGIN + m.width, GAUGE_TOP_WITH_SLOT) 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 14ee5345d..314d4f164 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt @@ -156,6 +156,16 @@ open class MatteryContainer(val watcher: Runnable, private val size: Int) : Cont open fun getMaxStackSize(slot: Int) = maxStackSize + open fun getMaxStackSizeWithItem(slot: Int): Int { + val item = this[slot] + + if (!item.isEmpty) { + return Math.min(getMaxStackSize(slot), item.maxStackSize) + } + + return getMaxStackSize(slot) + } + @JvmOverloads fun addItem(stack: ItemStack, start: Int = 0, end: Int = size - 1, simulate: Boolean = false): ItemStack { if (stack.isEmpty || start < 0 || end >= size || start > end) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/ImpreciseFraction.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/ImpreciseFraction.kt index 3e90ac153..29e950b24 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/ImpreciseFraction.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/ImpreciseFraction.kt @@ -155,6 +155,11 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do operator fun minus(other: ImpreciseFraction) = ImpreciseFraction(whole - other.whole, decimal - other.decimal) operator fun times(other: ImpreciseFraction): ImpreciseFraction { + if (other == ONE) + return this + else if (other == MINUS_ONE) + return -this + val a = whole val c = other.whole @@ -226,6 +231,11 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do } operator fun div(other: ImpreciseFraction): ImpreciseFraction { + if (other == ONE) + return this + else if (other == MINUS_ONE) + return -this + if (isZero && other.isZero) return this @@ -269,7 +279,7 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do operator fun div(other: Long): ImpreciseFraction = div(ImpreciseFraction(other)) operator fun unaryMinus(): ImpreciseFraction { - return ImpreciseFraction(-whole, decimal) + return ImpreciseFraction(-whole, -decimal) } override fun equals(other: Any?): Boolean { @@ -285,7 +295,7 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do fun equalsStrict(other: Any?): Boolean { if (isNaN) - return false + return other is ImpreciseFraction && other.isNaN // ибо hashCode() так требует if (other is ImpreciseFraction) { return other.whole == whole && other.decimal == decimal @@ -298,7 +308,7 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do if (isNaN) return Double.NaN.hashCode() - return 31 * decimal.hashCode() + whole.hashCode() + return 31 * (decimal - decimal % EPSILON).hashCode() + whole.hashCode() } fun toString(decimals: Int): String { @@ -346,7 +356,10 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do return sign } - return if (decimal > 0.0) 1 else if (decimal < 0.0) -1 else 0 + if (cmpDouble(decimal, 0.0)) + return 0 + + return if (decimal > 0.0) 1 else -1 } override fun compareTo(other: ImpreciseFraction): Int { @@ -409,6 +422,8 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do } val isZero get() = cmpDouble(decimal, 0.0) && isZero(whole) + val isPositive get() = this > ZERO + val isNegative get() = this < ZERO fun moreThanZero(): ImpreciseFraction { if (signum() >= 0) @@ -537,6 +552,11 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do return ZERO } + @JvmStatic + fun deserializeNBT(input: ByteArrayTag): ImpreciseFraction { + return fromByteArray(input.asByteArray) + } + @JvmStatic fun read(buff: FriendlyByteBuf): ImpreciseFraction { val len = unsignedInt(buff.readByte()) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/ItemMatterDust.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/ItemMatterDust.kt new file mode 100644 index 000000000..dffd50c9d --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/ItemMatterDust.kt @@ -0,0 +1,75 @@ +package ru.dbotthepony.mc.otm.item + +import net.minecraft.ChatFormatting +import net.minecraft.network.chat.Component +import net.minecraft.network.chat.TranslatableComponent +import net.minecraft.world.item.Item +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.TooltipFlag +import net.minecraft.world.level.Level +import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.core.ImpreciseFraction +import ru.dbotthepony.mc.otm.matter.IMatterItem +import ru.dbotthepony.mc.otm.matter.MatterTuple +import ru.dbotthepony.mc.otm.set + +class ItemMatterDust : Item(Properties().tab(OverdriveThatMatters.CREATIVE_TAB).stacksTo(64)), IMatterItem { + private fun matter(stack: ItemStack): ImpreciseFraction { + return stack.tag?.get("matter")?.let { return@let ImpreciseFraction.deserializeNBT(it) } ?: return ImpreciseFraction.ZERO + } + + private fun matter(stack: ItemStack, matter: ImpreciseFraction) { + stack.orCreateTag["matter"] = matter.serializeNBT() + } + + override fun getMatterValue(stack: ItemStack): MatterTuple? { + val value = stack.tag?.get("matter") ?: return null + return MatterTuple(ImpreciseFraction.deserializeNBT(value), 0.0) + } + + override fun canDecompose(stack: ItemStack) = false + + override fun appendHoverText( + p_41421_: ItemStack, + p_41422_: Level?, + p_41423_: MutableList, + p_41424_: TooltipFlag + ) { + super.appendHoverText(p_41421_, p_41422_, p_41423_, p_41424_) + val matter = this.getMatterValue(p_41421_) + + if (matter == null) { + p_41423_.add(DESC) + } + + p_41423_.add(DESC2) + } + + fun addMatterValue(stack: ItemStack, matter: ImpreciseFraction, simulate: Boolean): ImpreciseFraction { + if (stack.count != 1) + return ImpreciseFraction.ZERO + + val matterThis = matter(stack) + + if (matterThis >= MAX_MATTER_IN_ITEM) + return ImpreciseFraction.ZERO + + val newMatter = (matterThis + matter).min(MAX_MATTER_IN_ITEM) + val diff = newMatter - matterThis + + if (!simulate) + matter(stack, newMatter) + + return diff + } + + fun isFull(stack: ItemStack): Boolean { + return matter(stack) >= MAX_MATTER_IN_ITEM + } + + companion object { + private val DESC = TranslatableComponent("item.overdrive_that_matters.matter_dust.desc").withStyle(ChatFormatting.DARK_GRAY) + private val DESC2 = TranslatableComponent("item.overdrive_that_matters.matter_dust.desc2").withStyle(ChatFormatting.GRAY) + val MAX_MATTER_IN_ITEM = ImpreciseFraction(4) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterRegistry.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterRegistry.kt index 3a9d1e2b8..6852137f0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterRegistry.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterRegistry.kt @@ -33,6 +33,12 @@ interface MatterTuplePredicate { fun accept(item: Item): MatterTuple? } +interface IMatterItem { + fun getMatterValue(stack: ItemStack): MatterTuple? + fun hasMatterValue(stack: ItemStack) = getMatterValue(stack) != null + fun canDecompose(stack: ItemStack): Boolean +} + private val rootEntries = HashMap() private val derivedEntries = HashMap() @@ -123,26 +129,48 @@ val derivedEntriesAccess = object : MutableMap by derivedEntr } fun getMatterValue(item: Item): MatterTuple { + if (item is IMatterItem) + return item.getMatterValue(ItemStack.EMPTY) ?: MatterTuple.ZERO + return rootEntries[item] ?: derivedEntries[item] ?: MatterTuple.ZERO } fun getMatterValueNullable(item: Item): MatterTuple? { + if (item is IMatterItem) + return item.getMatterValue(ItemStack.EMPTY) + return rootEntries[item] ?: derivedEntries[item] } fun hasMatterValue(item: Item): Boolean { + if (item is IMatterItem) + return item.hasMatterValue(ItemStack.EMPTY) + return !getMatterValue(item).isZero } fun hasMatterValue(stack: ItemStack): Boolean { + val item = stack.item + + if (item is IMatterItem) + return item.hasMatterValue(stack) + return !getMatterValue(stack).isZero } fun canDecompose(item: Item): Boolean { + if (item is IMatterItem) + return item.canDecompose(ItemStack.EMPTY) + return hasMatterValue(item) } fun canDecompose(stack: ItemStack): Boolean { + val item = stack.item + + if (item is IMatterItem) + return item.canDecompose(stack) + return canDecompose(stack.item) && (stack.getCapability(MatteryCapability.MATTER).orNull()?.storedMatter ?: ImpreciseFraction.ZERO).isZero && (stack.getCapability(MatteryCapability.DRIVE).orNull()?.storedCount ?: ImpreciseFraction.ZERO).isZero @@ -157,10 +185,10 @@ private fun getMatterValue(stack: ItemStack, level: Int): MatterTuple { var matter = getMatterValue(stack.item) - if (matter.isZero) - return matter + if (stack.item is IMatterItem) + matter = (stack.item as IMatterItem).getMatterValue(stack) ?: MatterTuple.ZERO - if (stack.isDamageableItem) { + if (!matter.isZero && stack.isDamageableItem) { val severity = stack.damageValue.toDouble() / stack.maxDamage.toDouble() matter = MatterTuple(matter.value * severity, matter.complexity * (1.0 - severity / 2)) } @@ -225,11 +253,15 @@ fun tooltipEvent(event: ItemTooltipEvent) { val matter = getMatterValue(event.itemStack) if (!matter.isZero) { - event.toolTip.add( - TranslatableComponent("otm.gui.matter.format_and_complexity", - FormattingHelper.formatMatterValue(matter.value), - "%.3f".format(matter.complexity) - ).withStyle(ChatFormatting.AQUA)) + if (matter.complexity >= 1.0E-3) { + event.toolTip.add( + TranslatableComponent("otm.gui.matter.format_and_complexity", + FormattingHelper.formatMatterValue(matter.value), + "%.3f".format(matter.complexity) + ).withStyle(ChatFormatting.AQUA)) + } else { + event.toolTip.add(FormattingHelper.formatMatterValue(matter.value).withStyle(ChatFormatting.AQUA)) + } } } } @@ -260,6 +292,7 @@ data class MatterTuple(val value: ImpreciseFraction, val complexity: Double): Co } val isZero get() = value.isZero + val isZeroComplexity get() = complexity <= 0.0 companion object { @JvmField val ZERO = MatterTuple(ImpreciseFraction.ZERO, 0.0) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MenuMatterDecomposer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MenuMatterDecomposer.kt index 414d7b2bb..3283862cb 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MenuMatterDecomposer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MenuMatterDecomposer.kt @@ -18,25 +18,27 @@ class MenuMatterDecomposer @JvmOverloads constructor( tile: BlockEntityMatterDecomposer? = null ) : MenuMatteryPowered(Registry.Menus.MATTER_DECOMPOSER, containerID, inventory, tile) { val input: MatterySlot - val output: MachineOutputSlot + val outputMain: MachineOutputSlot + val outputStacking: MachineOutputSlot val progressWidget: ProgressGaugeWidget val matterWidget: LevelGaugeWidget init { - val container = tile?.itemContainer ?: SimpleContainer(2) + val container = tile?.container ?: SimpleContainer(3) // Вход - input = object : MatterySlot(container, 0, 61, 36) { - override fun mayPlace(p_40231_: ItemStack): Boolean { - return canDecompose(p_40231_) - } + input = object : MatterySlot(container, 0) { + override fun mayPlace(p_40231_: ItemStack) = canDecompose(p_40231_) } addSlot(input) // Выход - output = MachineOutputSlot(container, 1, 61 + 18 + 10 + 3 + 22, 36) - addSlot(output) + outputMain = MachineOutputSlot(container, 1) + outputStacking = MachineOutputSlot(container, 2) + + addSlot(outputMain) + addSlot(outputStacking) matterWidget = LevelGaugeWidget(this, tile?.getCapability(MatteryCapability.MATTER)?.orNull()) @@ -54,6 +56,6 @@ class MenuMatterDecomposer @JvmOverloads constructor( } override fun getWorkingSlotEnd(): Int { - return 2 + return 3 } } \ No newline at end of file diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MenuMatterRecycler.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MenuMatterRecycler.kt new file mode 100644 index 000000000..d8d31174e --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MenuMatterRecycler.kt @@ -0,0 +1,47 @@ +package ru.dbotthepony.mc.otm.menu + +import net.minecraft.world.SimpleContainer +import net.minecraft.world.entity.player.Inventory +import net.minecraft.world.item.ItemStack +import ru.dbotthepony.mc.otm.Registry +import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterRecycler +import ru.dbotthepony.mc.otm.item.ItemMatterDust +import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget +import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget + +class MenuMatterRecycler @JvmOverloads constructor( + containerID: Int, + inventory: Inventory, + tile: BlockEntityMatterRecycler? = null +) : MenuMatteryPowered(Registry.Menus.MATTER_RECYCLER, containerID, inventory, tile) { + val input: MatterySlot + val progress: ProgressGaugeWidget + val matter = LevelGaugeWidget(this, tile?.matter) + + init { + val container = tile?.container ?: SimpleContainer(1) + + input = object : MatterySlot(container, 0) { + override fun mayPlace(p_40231_: ItemStack): Boolean { + return p_40231_.item is ItemMatterDust && (p_40231_.item as ItemMatterDust).getMatterValue(p_40231_) != null + } + } + + if (tile == null) { + progress = ProgressGaugeWidget(this) + } else { + progress = ProgressGaugeWidget(this, tile::workProgress, tile::isUnableToProcess) + } + + addSlot(input) + addInventorySlots() + } + + override fun getWorkingSlotStart(): Int { + return 0 + } + + override fun getWorkingSlotEnd(): Int { + return 2 + } +} 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 fa140917e..a0bcfc300 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 @@ -198,6 +198,8 @@ "block.overdrive_that_matters.gravitation_stabilizer.desc3": "Keep in mind the effect of multiple stabilizers produce exponentially increasing result", "block.overdrive_that_matters.gravitation_stabilizer.desc4": "Too weak gravitation field will cause singularity to melt and evaporate away very fast", + "block.overdrive_that_matters.matter_recycler": "Matter Recycler", + "otm.container.matter_panel.number_input": "Input replication task count", "otm.container.matter_panel.increase_by": "+%s", @@ -230,6 +232,10 @@ "item.overdrive_that_matters.pill_oblivion": "Android Factory Reset Pill", "item.overdrive_that_matters.pill_heal": "Medical Pill", + "item.overdrive_that_matters.matter_dust": "Matter Dust", + "item.overdrive_that_matters.matter_dust.desc": "This item is product of failed decomposition or replication attempt", + "item.overdrive_that_matters.matter_dust.desc2": "Throw into matter recycler to get some of it's value back!", + "item.overdrive_that_matters.portable_condensation_drive": "Portable Condensation Drive", "item.overdrive_that_matters.portable_dense_condensation_drive": "Portable Dense Condensation Drive", diff --git a/src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json b/src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json index 1f276efee..2b3bc3bc4 100644 --- a/src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json +++ b/src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json @@ -12,6 +12,7 @@ "overdrive_that_matters:matter_replicator", "overdrive_that_matters:matter_bottler", "overdrive_that_matters:drive_viewer", + "overdrive_that_matters:matter_recycler", "overdrive_that_matters:tritanium_block", "overdrive_that_matters:tritanium_striped_block", diff --git a/src/main/resources/data/minecraft/tags/blocks/needs_iron_tool.json b/src/main/resources/data/minecraft/tags/blocks/needs_iron_tool.json index 5e660d6f7..3254611d2 100644 --- a/src/main/resources/data/minecraft/tags/blocks/needs_iron_tool.json +++ b/src/main/resources/data/minecraft/tags/blocks/needs_iron_tool.json @@ -12,6 +12,7 @@ "overdrive_that_matters:matter_replicator", "overdrive_that_matters:matter_bottler", "overdrive_that_matters:drive_viewer", + "overdrive_that_matters:matter_recycler", "overdrive_that_matters:tritanium_block", "overdrive_that_matters:tritanium_striped_block",