From 7c35c284cd7d06419c52ee58b39a9e4e4c1b5376 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sun, 5 Jan 2025 23:50:43 +0700 Subject: [PATCH] Briefcase grill --- .../mc/otm/datagen/lang/English.kt | 9 +- .../mc/otm/datagen/lang/Russian.kt | 4 + .../mc/otm/datagen/loot/LootTablesData.kt | 1 + .../datagen/recipes/CraftingTableRecipes.kt | 29 +++ .../mc/otm/datagen/recipes/PainterRecipes.kt | 2 + .../dbotthepony/mc/otm/datagen/tags/Tags.kt | 1 + .../dbotthepony/mc/otm/block/MatteryBlock.kt | 35 ++- .../mc/otm/block/decorative/GrillBlock.kt | 106 +++++++++ .../block/entity/MatteryDeviceBlockEntity.kt | 23 +- .../entity/decorative/GrillBlockEntity.kt | 212 ++++++++++++++++++ .../mc/otm/client/render/WidgetLocation.kt | 1 + .../client/screen/decorative/GrillScreen.kt | 60 +++++ .../screen/widget/ProgressGaugePanel.kt | 93 +++++--- .../mc/otm/container/IMatteryContainer.kt | 21 ++ .../ru/dbotthepony/mc/otm/menu/Slots.kt | 6 + .../mc/otm/menu/decorative/GrillMenu.kt | 68 ++++++ .../otm/menu/widget/IProgressGaugeWidget.kt | 16 ++ .../mc/otm/menu/widget/ProgressGaugeWidget.kt | 6 +- .../mc/otm/registry/MBlockEntities.kt | 3 + .../ru/dbotthepony/mc/otm/registry/MBlocks.kt | 3 + .../mc/otm/registry/MCreativeTabs.kt | 2 + .../ru/dbotthepony/mc/otm/registry/MItems.kt | 2 + .../ru/dbotthepony/mc/otm/registry/MMenus.kt | 4 + .../ru/dbotthepony/mc/otm/registry/MNames.kt | 1 + .../textures/gui/widgets/fuel.png | Bin 0 -> 833 bytes .../textures/gui/widgets/fuel.xcf | Bin 0 -> 2254 bytes 26 files changed, 660 insertions(+), 48 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/block/decorative/GrillBlock.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/GrillBlockEntity.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/GrillScreen.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/GrillMenu.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/menu/widget/IProgressGaugeWidget.kt create mode 100644 src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/fuel.png create mode 100644 src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/fuel.xcf diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt index 45477de5c..2a286fb55 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt @@ -44,6 +44,8 @@ private fun decoratives(provider: MatteryLanguageProvider) { add(MBlocks.TRITANIUM_TRAPDOOR[color]!!, "description0", "High blast resistance door with redstone latch...") add(MBlocks.TRITANIUM_TRAPDOOR[color]!!, "description1", "...feeling safe now?") add(MBlocks.TRITANIUM_TRAPDOOR[color]!!, "description2", "This one is painted $name") + + add(MBlocks.GRILL[color]!!, "$name Briefcase Grill") } add(MRegistry.TRITANIUM_PRESSURE_PLATE.block, "Tritanium Pressure Plate") @@ -65,6 +67,8 @@ private fun decoratives(provider: MatteryLanguageProvider) { add(MItems.CARGO_CRATE_MINECARTS[null]!!, "Minecart with Cargo Crate") add(MEntityTypes.CARGO_CRATE_MINECARTS[null]!!, "Minecart with Cargo Crate") + add(MBlocks.GRILL[null]!!, "Briefcase Grill") + add(MRegistry.CARGO_CRATES.block, "Cargo Crate") add(MRegistry.COMPUTER_TERMINAL.block, "Computer Terminal") add(MRegistry.STAR_CHAIR.block, "Star Chair") @@ -372,7 +376,10 @@ private fun misc(provider: MatteryLanguageProvider) { gui("power.burn_time", "Burn time left: %s ticks") gui("progress_widget", "Progress: %s%%") - gui("progress_widget_stuck", "The machine can not work, check configuration") + gui("progress_widget_ticks", "Progress: %d / %d (%s%%)") + gui("fuel_widget", "Fuel: %s%%") + gui("fuel_widget_ticks", "Fuel: %d / %d (%s%%)") + gui("progress_stuck", "The machine can not work, check configuration") gui("total_raw", "Total:") gui("total", "Total: %s") diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt index f3eec2081..318c1db8a 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt @@ -56,6 +56,8 @@ private fun decoratives(provider: MatteryLanguageProvider) { add(MBlocks.TRITANIUM_TRAPDOOR[color]!!, "description0", HIGH_BLAST_RESISTANCE_DOOR) add(MBlocks.TRITANIUM_TRAPDOOR[color]!!, "description1", FEELING_SAFE_NOW) add(MBlocks.TRITANIUM_TRAPDOOR[color]!!, "description2", "Данный вариант выкрашен в $name") + + add(MBlocks.GRILL[color]!!, "$nameAdj мангал-дипломат") } add(MRegistry.TRITANIUM_PRESSURE_PLATE.block, "Тритановая нажимная пластина") @@ -65,6 +67,8 @@ private fun decoratives(provider: MatteryLanguageProvider) { misc("computer_terminal_tooltip", "Может быть использован как кнопка, с оговоркой что он посылает сигнал блоку сзади, а не под ним") misc("decorative", "Элемент декора") + add(MBlocks.GRILL[null]!!, "Мангал-дипломат") + add(MItems.CARGO_CRATE_MINECARTS[null]!!, "Вагонетка с грузовым ящиком") add(MEntityTypes.CARGO_CRATE_MINECARTS[null]!!, "Вагонетка с грузовым ящиком") diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/loot/LootTablesData.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/loot/LootTablesData.kt index e8d16867f..f57a5952c 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/loot/LootTablesData.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/loot/LootTablesData.kt @@ -181,6 +181,7 @@ fun addLootTables(lootTables: LootTables) { lootTables.tile(MBlocks.FLUID_TANK) lootTables.tile(MBlocks.PAINTER) lootTables.tile(MBlocks.MATTER_ENTANGLER) + lootTables.tile(MBlocks.GRILL.values) lootTables.tile(MBlocks.ENERGY_SERVO.values) lootTables.tile(MBlocks.ENERGY_COUNTER.values) diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/recipes/CraftingTableRecipes.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/recipes/CraftingTableRecipes.kt index 01c57d443..839579ea7 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/recipes/CraftingTableRecipes.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/recipes/CraftingTableRecipes.kt @@ -11,6 +11,7 @@ import net.minecraft.world.item.crafting.Ingredient import net.neoforged.neoforge.common.Tags import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity import ru.dbotthepony.mc.otm.config.CablesConfig +import ru.dbotthepony.mc.otm.core.ResourceLocation import ru.dbotthepony.mc.otm.registry.MBlocks import ru.dbotthepony.mc.otm.registry.MItemTags import ru.dbotthepony.mc.otm.registry.MItems @@ -493,4 +494,32 @@ fun addCraftingTableRecipes(consumer: RecipeOutput) { .row(Tags.Items.INGOTS_GOLD, Tags.Items.INGOTS_GOLD, Tags.Items.INGOTS_GOLD) .row(MItemTags.REINFORCED_TRITANIUM_PLATES, Items.BLUE_ICE, MItemTags.REINFORCED_TRITANIUM_PLATES) .build(consumer) + + val ironRod = ItemTags.create(ResourceLocation("c", "rods/iron")) + + for ((color, item) in MItems.GRILL) { + MatteryRecipe(item, category = RecipeCategory.DECORATIONS) + .rowB(color?.tag) + .row(Tags.Items.INGOTS_IRON, Tags.Items.INGOTS_IRON, Tags.Items.INGOTS_IRON) + .rowAC(MItemTags.TRITANIUM_INGOTS, MItemTags.TRITANIUM_INGOTS) + .build(consumer) + + MatteryRecipe(item, category = RecipeCategory.DECORATIONS) + .rowB(color?.tag) + .row(ironRod, ironRod, ironRod) + .rowAC(MItemTags.TRITANIUM_INGOTS, MItemTags.TRITANIUM_INGOTS) + .build(consumer, "grill_alt_a/${color?.name?.lowercase() ?: "default"}") + + MatteryRecipe(item, category = RecipeCategory.DECORATIONS) + .rowB(color?.tag) + .row(ironRod, ironRod, ironRod) + .rowB(MItemTags.TRITANIUM_PLATES) + .build(consumer, "grill_alt_b/${color?.name?.lowercase() ?: "default"}") + + MatteryRecipe(item, category = RecipeCategory.DECORATIONS) + .rowB(color?.tag) + .row(Tags.Items.INGOTS_IRON, Tags.Items.INGOTS_IRON, Tags.Items.INGOTS_IRON) + .rowB(MItemTags.TRITANIUM_PLATES) + .build(consumer, "grill_alt_c/${color?.name?.lowercase() ?: "default"}") + } } diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/recipes/PainterRecipes.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/recipes/PainterRecipes.kt index f60fed4c5..66aa99472 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/recipes/PainterRecipes.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/recipes/PainterRecipes.kt @@ -413,4 +413,6 @@ fun addPainterRecipes(consumer: RecipeOutput) { mapOf(color to 1) )) } + + generate(consumer, MItems.GRILL[null]!!, MItems.GRILL) } diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/tags/Tags.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/tags/Tags.kt index 9ba29f098..d8497f145 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/tags/Tags.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/tags/Tags.kt @@ -227,6 +227,7 @@ fun addTags(tagsProvider: TagsProvider) { tagsProvider.requiresPickaxe(MBlocks.TRITANIUM_TRAPDOOR.values, Tiers.IRON) tagsProvider.requiresPickaxe(MBlocks.PAINTER, Tiers.STONE) tagsProvider.requiresPickaxe(MBlocks.ENERGY_CABLES.values, Tiers.STONE) + tagsProvider.requiresPickaxe(MBlocks.GRILL.values, Tiers.STONE) tagsProvider.requiresPickaxe(listOf( *MBlocks.ANDROID_STATION.values.toTypedArray(), diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/MatteryBlock.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/MatteryBlock.kt index 399054a81..7a702d9f2 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/MatteryBlock.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/MatteryBlock.kt @@ -7,9 +7,13 @@ import net.minecraft.ChatFormatting import net.minecraft.Util import net.minecraft.core.BlockPos import net.minecraft.core.Direction +import net.minecraft.core.HolderLookup import net.minecraft.core.component.DataComponents import net.minecraft.core.particles.DustParticleOptions +import net.minecraft.nbt.CompoundTag +import net.minecraft.nbt.NbtOps import net.minecraft.network.chat.Component +import net.minecraft.network.chat.ComponentSerialization import net.minecraft.util.RandomSource import net.minecraft.world.Containers import net.minecraft.world.InteractionResult @@ -28,9 +32,11 @@ import net.minecraft.world.level.material.MapColor import net.minecraft.world.level.material.PushReaction import net.minecraft.world.phys.BlockHitResult import net.minecraft.world.phys.shapes.VoxelShape +import org.apache.logging.log4j.LogManager import ru.dbotthepony.mc.otm.block.entity.IRedstoneControlled import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity +import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity.Companion import ru.dbotthepony.mc.otm.block.entity.WorkerState import ru.dbotthepony.mc.otm.core.TooltipList import ru.dbotthepony.mc.otm.core.TranslatableComponent @@ -41,10 +47,14 @@ import ru.dbotthepony.mc.otm.core.math.BlockRotationFreedom import ru.dbotthepony.mc.otm.core.math.component1 import ru.dbotthepony.mc.otm.core.math.component2 import ru.dbotthepony.mc.otm.core.math.component3 +import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.once import java.util.concurrent.Callable import java.util.function.Function import java.util.function.Supplier +import kotlin.jvm.optionals.getOrNull + +private val LOGGER = LogManager.getLogger() fun Block.getShapeForEachState(properties: List>, fn: (BlockState) -> VoxelShape): Map { val builder = Object2ObjectArrayMap>() @@ -81,6 +91,29 @@ fun interface INeighbourChangeListener { ) } +interface IBlockWithCustomName { + var customDisplayName: Component? + + fun saveCustomDisplayName(nbt: CompoundTag, registry: HolderLookup.Provider) { + if (customDisplayName != null) + ComponentSerialization + .CODEC + .encodeStart(registry.createSerializationContext(NbtOps.INSTANCE), customDisplayName) + .resultOrPartial { LOGGER.error("Unable to serialize custom name: {}", it) } + .ifPresent { nbt["Name"] = it } + } + + fun loadCustomDisplayName(nbt: CompoundTag, registry: HolderLookup.Provider) { + if ("Name" in nbt) { + customDisplayName = ComponentSerialization + .CODEC + .decode(registry.createSerializationContext(NbtOps.INSTANCE), nbt["Name"]!!) + .resultOrPartial { LOGGER.error("Unable to deserialize custom name: {}", it) } + .getOrNull()?.first + } + } +} + open class MatteryBlock(properties: Properties = DEFAULT_PROPERTIES) : Block(properties), INeighbourChangeListener { val tooltips = TooltipList() @@ -94,7 +127,7 @@ open class MatteryBlock(properties: Properties = DEFAULT_PROPERTIES) : Block(pro if (this is EntityBlock && itemStack.has(DataComponents.CUSTOM_NAME) && !level.isClientSide) { val tile = level.getBlockEntity(blockPos) - if (tile is MatteryDeviceBlockEntity) { + if (tile is IBlockWithCustomName) { try { tile.customDisplayName = itemStack.get(DataComponents.CUSTOM_NAME) } catch(_: Exception) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/decorative/GrillBlock.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/decorative/GrillBlock.kt new file mode 100644 index 000000000..e11287d5f --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/decorative/GrillBlock.kt @@ -0,0 +1,106 @@ +package ru.dbotthepony.mc.otm.block.decorative + +import net.minecraft.core.BlockPos +import net.minecraft.core.particles.ParticleTypes +import net.minecraft.sounds.SoundEvents +import net.minecraft.sounds.SoundSource +import net.minecraft.util.RandomSource +import net.minecraft.util.StringRepresentable +import net.minecraft.world.item.DyeColor +import net.minecraft.world.level.Level +import net.minecraft.world.level.block.Block +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 net.minecraft.world.level.block.state.StateDefinition +import net.minecraft.world.level.block.state.properties.EnumProperty +import net.minecraft.world.level.material.MapColor +import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock +import ru.dbotthepony.mc.otm.block.entity.decorative.GrillBlockEntity +import ru.dbotthepony.mc.otm.core.get +import ru.dbotthepony.mc.otm.core.math.component1 +import ru.dbotthepony.mc.otm.core.math.component2 +import ru.dbotthepony.mc.otm.core.math.component3 +import kotlin.math.absoluteValue + +class GrillBlock(val color: DyeColor?) : RotatableMatteryBlock(Properties.of().mapColor(color?.mapColor ?: MapColor.METAL).destroyTime(0.75f).explosionResistance(10.0f)), EntityBlock { + override fun newBlockEntity(p_153215_: BlockPos, p_153216_: BlockState): BlockEntity { + return GrillBlockEntity(p_153215_, p_153216_) + } + + init { + tooltips.colored(color) + } + + override fun getTicker( + p_153212_: Level, + p_153213_: BlockState, + p_153214_: BlockEntityType + ): BlockEntityTicker? { + if (p_153212_.isClientSide) + return null + + return BlockEntityTicker { _, _, _, t -> if (t is GrillBlockEntity) t.tick() } + } + + enum class State : StringRepresentable { + IDLE, + FUELED, + GRILLING; + + private val str = name.lowercase() + + override fun getSerializedName(): String { + return str + } + } + + override fun createBlockStateDefinition(builder: StateDefinition.Builder) { + super.createBlockStateDefinition(builder) + builder.add(STATE_PROPERTY) + } + + override fun animateTick(blockState: BlockState, level: Level, blockPos: BlockPos, random: RandomSource) { + val state = blockState[STATE_PROPERTY] + + if (state === State.IDLE) + return + + val (x, y, z) = blockPos + + if (random.nextInt(15) == 0) { + val xd = x + 0.5 + random.nextGaussian() * 0.1 + val yd = y + 1.1 + val zd = z + 0.5 + random.nextGaussian() * 0.1 + + level.addParticle(ParticleTypes.LAVA, xd, yd, zd, random.nextDouble() * 0.5, 0.005, random.nextDouble() * 0.5) + } + + if (random.nextInt(6) == 0) { + level.playLocalSound( + x + 0.5, + y + 0.5, + z + 0.5, + SoundEvents.CAMPFIRE_CRACKLE, + SoundSource.BLOCKS, + 0.5f + random.nextFloat(), + random.nextFloat() * 0.7f + 0.6f, + false + ) + } + + if (state === State.GRILLING && random.nextInt(4) == 0) { + val xd = x + 0.5 + random.nextGaussian() * 0.25 + val yd = y + 1.1 + val zd = z + 0.5 + random.nextGaussian() * 0.25 + + level.addParticle(ParticleTypes.CAMPFIRE_COSY_SMOKE, xd, yd, zd, 0.0, random.nextGaussian().absoluteValue * 0.04 + 0.02, 0.0) + } + } + + companion object { + val STATE_PROPERTY: EnumProperty = EnumProperty.create("state", State::class.java) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryDeviceBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryDeviceBlockEntity.kt index 679f4e89b..71085dd64 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryDeviceBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryDeviceBlockEntity.kt @@ -22,6 +22,7 @@ import net.neoforged.neoforge.items.IItemHandler import org.apache.logging.log4j.LogManager import ru.dbotthepony.kommons.util.getValue import ru.dbotthepony.kommons.util.setValue +import ru.dbotthepony.mc.otm.block.IBlockWithCustomName import ru.dbotthepony.mc.otm.capability.FlowDirection import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage import ru.dbotthepony.mc.otm.capability.item.CombinedItemHandler @@ -44,9 +45,8 @@ import kotlin.jvm.optionals.getOrNull * Device block entity base, implementing [MenuProvider] and [IRedstoneControlled], and also tracks custom display name */ @Suppress("LiftReturnOrAssignment") -abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blockPos: BlockPos, blockState: BlockState) - : MatteryBlockEntity(blockEntityType, blockPos, blockState), MenuProvider, IRedstoneControlled { - var customDisplayName: Component? = null +abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blockPos: BlockPos, blockState: BlockState) : MatteryBlockEntity(blockEntityType, blockPos, blockState), MenuProvider, IRedstoneControlled, IBlockWithCustomName { + final override var customDisplayName: Component? = null override val redstoneControl: AbstractRedstoneControl = RedstoneControl { new, old -> markDirtyFast() @@ -72,25 +72,12 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo override fun saveShared(nbt: CompoundTag, registry: HolderLookup.Provider) { super.saveShared(nbt, registry) - - if (customDisplayName != null) - ComponentSerialization - .CODEC - .encodeStart(registry.createSerializationContext(NbtOps.INSTANCE), customDisplayName) - .resultOrPartial { LOGGER.error("Unable to serialize custom name: {}", it) } - .ifPresent { nbt["Name"] = it } + saveCustomDisplayName(nbt, registry) } override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) { super.loadAdditional(nbt, registry) - - if ("Name" in nbt) { - customDisplayName = ComponentSerialization - .CODEC - .decode(registry.createSerializationContext(NbtOps.INSTANCE), nbt["Name"]!!) - .resultOrPartial { LOGGER.error("Unable to deserialize custom name: {}", it) } - .getOrNull()?.first - } + loadCustomDisplayName(nbt, registry) } override fun setLevel(level: Level) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/GrillBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/GrillBlockEntity.kt new file mode 100644 index 000000000..585b65da5 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/GrillBlockEntity.kt @@ -0,0 +1,212 @@ +package ru.dbotthepony.mc.otm.block.entity.decorative + +import com.mojang.serialization.Codec +import it.unimi.dsi.fastutil.ints.IntArrayList +import net.minecraft.core.BlockPos +import net.minecraft.core.HolderLookup +import net.minecraft.nbt.CompoundTag +import net.minecraft.nbt.NbtOps +import net.minecraft.network.chat.Component +import net.minecraft.network.chat.ComponentSerialization +import net.minecraft.server.level.ServerLevel +import net.minecraft.world.Containers +import net.minecraft.world.MenuProvider +import net.minecraft.world.entity.item.ItemEntity +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.item.crafting.RecipeType +import net.minecraft.world.item.crafting.SingleRecipeInput +import net.minecraft.world.item.crafting.SmokingRecipe +import net.minecraft.world.level.block.Block +import net.minecraft.world.level.block.state.BlockState +import org.apache.logging.log4j.LogManager +import ru.dbotthepony.kommons.util.Delegate +import ru.dbotthepony.mc.otm.block.IBlockWithCustomName +import ru.dbotthepony.mc.otm.block.decorative.GrillBlock +import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity +import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity +import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity.Companion +import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.core.TextComponent +import ru.dbotthepony.mc.otm.core.get +import ru.dbotthepony.mc.otm.core.isNotEmpty +import ru.dbotthepony.mc.otm.core.math.component1 +import ru.dbotthepony.mc.otm.core.math.component2 +import ru.dbotthepony.mc.otm.core.math.component3 +import ru.dbotthepony.mc.otm.core.nbt.set +import ru.dbotthepony.mc.otm.core.set +import ru.dbotthepony.mc.otm.core.util.countingLazy +import ru.dbotthepony.mc.otm.data.minRange +import ru.dbotthepony.mc.otm.menu.decorative.GrillMenu +import ru.dbotthepony.mc.otm.registry.MBlockEntities +import ru.dbotthepony.mc.otm.registry.MBlocks +import kotlin.jvm.optionals.getOrNull + +class GrillBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBlockEntity(MBlockEntities.GRILL, blockPos, blockState), MenuProvider, IBlockWithCustomName { + val fuelSlot = object : MatteryContainer(this@GrillBlockEntity::markDirtyFast, 1) { + override fun getMaxStackSize(): Int { + return 4 + } + } + + val inputSlots = object : MatteryContainer(this@GrillBlockEntity::markDirtyFast, SLOTS) { + override fun getMaxStackSize(): Int { + return 1 + } + + private fun clearSlot(slot: Int) { + inputProgress[slot] = 0 + outputs[slot] = null + activeSlots.rem(slot) + } + + override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) { + super.setChanged(slot, new, old) + + if (new.isEmpty || new.count > 1) { + clearSlot(slot) + } else { + val level = level + + if (level == null) { + clearSlot(slot) + return + } + + val input = SingleRecipeInput(new) + val result = level.recipeManager + .byType(RecipeType.SMOKING) + .firstOrNull { it.value.matches(input, level) } + + if (result == null) { + clearSlot(slot) + } else { + if (outputs[slot] != result.value) + inputProgress[slot] = 0 + + outputs[slot] = result.value + activeSlots.add(slot) + } + } + } + } + + override var customDisplayName: Component? = null + + override fun createMenu(p_39954_: Int, p_39955_: Inventory, p_39956_: Player): AbstractContainerMenu { + return GrillMenu(p_39954_, p_39955_, this) + } + + override fun getDisplayName(): Component { + return customDisplayName ?: level?.getBlockState(blockPos)?.block?.name ?: TextComponent("null at $blockPos") + } + + private val outputs = arrayOfNulls(SLOTS) + private val activeSlots = IntArrayList() + private val inputProgress = IntArray(SLOTS) + + var fuelTicks = 0 + private set + var fuelTotalTicks = 0 + private set + + fun totalTicksRequired(slot: Int): Int { + return outputs[slot]?.cookingTime?.times(3) ?: 0 + } + + fun ticksPassed(slot: Int): Int { + return inputProgress[slot] + } + + override fun saveShared(nbt: CompoundTag, registry: HolderLookup.Provider) { + super.saveShared(nbt, registry) + saveCustomDisplayName(nbt, registry) + } + + override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) { + super.loadAdditional(nbt, registry) + loadCustomDisplayName(nbt, registry) + } + + init { + savetablesLevel.int(::fuelTicks) + savetablesLevel.int(::fuelTotalTicks) + savetables.stateful(::inputSlots) + savetables.stateful(::fuelSlot) + + // TODO: could have been done as list (and get more space efficient storage), but we use an array, oh well + for (i in inputProgress.indices) { + savetables.codec(Delegate.Of({ inputProgress[i] }, { inputProgress[i] = it }), progressCodec, "inputProgress${i}") + } + + // addDroppableContainer(inputSlots) + // addDroppableContainer(fuelSlot) + } + + private val state by countingLazy(blockStateChangesCounter) { + this.blockState[GrillBlock.STATE_PROPERTY] + } + + override fun tick() { + super.tick() + + if (fuelTicks <= 0 && activeSlots.isNotEmpty()) { + val fuel = fuelSlot[0].getBurnTime(null) * 8 + + if (fuel > 0) { + fuelTicks = fuel + fuelTotalTicks = fuel + val split = fuelSlot[0].split(1) + val remaining = split.craftingRemainingItem + + if (remaining.isEmpty) { + fuelSlot.setChanged(0) + } else if (fuelSlot[0].isNotEmpty) { + val level = level as ServerLevel + val (x, y, z) = blockPos.center + Containers.dropItemStack(level, x, y, z, remaining) + } else { + fuelSlot[0] = remaining + } + } + } + + if (fuelTicks > 0) { + if (activeSlots.isNotEmpty()) { + fuelTicks -= 5 + + for (slot in activeSlots.toIntArray()) { + val recipe = outputs[slot]!! + + if (recipe.cookingTime * 3 <= ++inputProgress[slot]) { + inputSlots[slot] = recipe.assemble(SingleRecipeInput(inputSlots[slot]), level!!.registryAccess()) + } + } + + if (state !== GrillBlock.State.GRILLING) { + level!!.setBlock(blockPos, blockState.set(GrillBlock.STATE_PROPERTY, GrillBlock.State.GRILLING), Block.UPDATE_ALL) + } + } else { + fuelTicks-- + + if (state !== GrillBlock.State.FUELED) { + level!!.setBlock(blockPos, blockState.set(GrillBlock.STATE_PROPERTY, GrillBlock.State.FUELED), Block.UPDATE_ALL) + } + } + } else { + fuelTotalTicks = 0 + + if (state !== GrillBlock.State.IDLE) { + level!!.setBlock(blockPos, blockState.set(GrillBlock.STATE_PROPERTY, GrillBlock.State.IDLE), Block.UPDATE_ALL) + } + } + } + + companion object { + const val SLOTS = 6 + + private val progressCodec = Codec.INT.minRange(0) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/WidgetLocation.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/WidgetLocation.kt index 6792c4b7c..688d59edc 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/WidgetLocation.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/WidgetLocation.kt @@ -18,6 +18,7 @@ object WidgetLocation { val CHECKBOX = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/checkbox.png"), 30f, 60f) val RADIO = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/radio.png"), 30f, 60f) val PROGRESS_ARROWS = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/progress_arrows.png"), 22f, 31f) + val FUEL = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/fuel.png"), 14f, 28f) val HORIZONTAL_GAUGES = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/horizontal_gauges.png"), 96f, 108f) val VERTICAL_GAUGES = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/vertical_gauges.png"), 90f, 48f) val REDSTONE_CONTROLS = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/redstone.png"), 54f, 18f) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/GrillScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/GrillScreen.kt new file mode 100644 index 000000000..881d6fbfa --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/GrillScreen.kt @@ -0,0 +1,60 @@ +package ru.dbotthepony.mc.otm.client.screen.decorative + +import mezz.jei.api.constants.RecipeTypes +import net.minecraft.network.chat.Component +import net.minecraft.world.entity.player.Inventory +import ru.dbotthepony.mc.otm.client.screen.MatteryScreen +import ru.dbotthepony.mc.otm.client.screen.panels.Dock +import ru.dbotthepony.mc.otm.client.screen.panels.DockProperty +import ru.dbotthepony.mc.otm.client.screen.panels.DockResizeMode +import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel +import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel +import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel +import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel +import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel +import ru.dbotthepony.mc.otm.menu.decorative.GrillMenu + +class GrillScreen(menu: GrillMenu, inventory: Inventory, title: Component) : MatteryScreen(menu, inventory, title) { + override fun makeMainFrame(): FramePanel> { + val frame = super.makeMainFrame()!! + + val topStrip = EditablePanel(this, frame, height = AbstractSlotPanel.SIZE) + topStrip.dock = Dock.TOP + topStrip.dockBottom = 4f + + val middleStrip = EditablePanel(this, frame, height = AbstractSlotPanel.SIZE) + middleStrip.dock = Dock.TOP + + for (slot in menu.inputSlots) + SlotPanel(this, topStrip, slot).also { it.dock = Dock.LEFT } + + for (slot in menu.progress) { + val panel = ProgressGaugePanel(this, middleStrip, slot) + panel.type = ProgressGaugePanel.Type.FUEL + panel.behaviorType = ProgressGaugePanel.Type.PROGRESS + panel.dock = Dock.LEFT + panel.dockResize = DockResizeMode.NONE + panel.dockMargin = DockProperty(left = 2f, right = 2f) + panel.setRecipeType { listOf(RecipeTypes.SMOKING) } + } + + ProgressGaugePanel(this, middleStrip, menu.fuel).also { + it.dock = Dock.LEFT + it.dockLeft = 2f + it.dockResize = DockResizeMode.NONE + it.flop = true + it.behaviorType = ProgressGaugePanel.Type.FUEL + it.setRecipeType { listOf(RecipeTypes.FUELING) } + } + + SlotPanel(this, middleStrip, menu.fuelSlot[0]).also { + it.dock = Dock.LEFT + it.dockLeft = 2f + it.dockResize = DockResizeMode.NONE + } + + frame.sizeToContents() + + return frame + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/ProgressGaugePanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/ProgressGaugePanel.kt index 64aaa21c4..5f197dbef 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/ProgressGaugePanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/ProgressGaugePanel.kt @@ -14,43 +14,74 @@ import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel import ru.dbotthepony.mc.otm.client.screen.panels.button.AbstractButtonPanel import ru.dbotthepony.mc.otm.compat.jei.JEIPlugin import ru.dbotthepony.mc.otm.compat.jei.isJeiLoaded +import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent -import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget +import ru.dbotthepony.mc.otm.menu.widget.IProgressGaugeWidget import java.util.function.Supplier import kotlin.math.roundToInt open class ProgressGaugePanel( screen: S, parent: EditablePanel<*>? = null, - val widget: ProgressGaugeWidget, + val widget: IProgressGaugeWidget, x: Float = 0f, y: Float = 0f -): AbstractButtonPanel(screen, parent, x, y, width = GAUGE_BACKGROUND.width, height = GAUGE_BACKGROUND.height) { +): AbstractButtonPanel(screen, parent, x, y) { init { scissor = true } var flop = false + var type = Type.PROGRESS + set(value) { + field = value + width = value.width + height = value.height + } + + var behaviorType: Type? = null + + init { + type = Type.PROGRESS + } + private var recipeTypeSupplier: Supplier>>? = null - protected open fun makeTooltip(): MutableList { - val tooltip: MutableList + enum class Type(val width: Float, val height: Float) { + PROGRESS(GAUGE_BACKGROUND.width, GAUGE_BACKGROUND.height), + FUEL(FUEL_BACKGROUND.width, FUEL_BACKGROUND.height); - if (widget.isStuck) { - tooltip = mutableListOf( + val localizedString = "otm.gui.${name.lowercase()}_widget" + } + + protected open fun makeTooltip(): MutableList { + val tooltip = ArrayList() + + if (widget is IProgressGaugeWidget.WithTicks) { + tooltip.add( TranslatableComponent( - "otm.gui.progress_widget", - String.format("%.2f", widget.percentage * 100f) - ), - TranslatableComponent("otm.gui.progress_widget_stuck").withStyle(ChatFormatting.DARK_RED) - ) - } else { - tooltip = mutableListOf( - TranslatableComponent( - "otm.gui.progress_widget", - String.format("%.2f", widget.percentage * 100f) + "${(behaviorType ?: type).localizedString}_ticks", + widget.workTicks, + widget.totalTicks, + String.format("%.2f", widget.progress * 100f) ) ) + } else { + tooltip.add( + TranslatableComponent( + (behaviorType ?: type).localizedString, + String.format("%.2f", widget.progress * 100f) + ) + ) + } + + if (widget.isStuck) { + tooltip.add(TranslatableComponent("otm.gui.progress_stuck").withStyle(ChatFormatting.DARK_RED)) + } + + if (tooltips.isNotEmpty()) { + tooltip.add(TextComponent("")) + tooltip.addAll(tooltips) } return tooltip @@ -61,14 +92,24 @@ open class ProgressGaugePanel( RenderSystem.setShaderColor(0.75f, 0.4f, 0.4f, 1f) } - if (flop) { - GAUGE_BACKGROUND.render(graphics, canvasHeight = height, canvasWidth = this.width, winding = UVWindingOrder.U1_V0_U0_V1) - val width = (this.width * widget.percentage).roundToInt().toFloat() - GAUGE_FOREGROUND.renderPartial(graphics, x = this.width - width, height = height, width = width, winding = UVWindingOrder.U1_V0_U0_V1) - } else { - GAUGE_BACKGROUND.render(graphics, canvasHeight = height, canvasWidth = this.width) - val width = (this.width * widget.percentage).roundToInt().toFloat() - GAUGE_FOREGROUND.renderPartial(graphics, height = height, width = width) + when (type) { + Type.PROGRESS -> { + if (flop) { + GAUGE_BACKGROUND.render(graphics, canvasHeight = height, canvasWidth = this.width, winding = UVWindingOrder.U1_V0_U0_V1) + val width = (this.width * widget.progress).roundToInt().toFloat() + GAUGE_FOREGROUND.renderPartial(graphics, x = this.width - width, height = height, width = width, winding = UVWindingOrder.U1_V0_U0_V1) + } else { + GAUGE_BACKGROUND.render(graphics, canvasHeight = height, canvasWidth = this.width) + val width = (this.width * widget.progress).roundToInt().toFloat() + GAUGE_FOREGROUND.renderPartial(graphics, height = height, width = width) + } + } + + Type.FUEL -> { + FUEL_BACKGROUND.render(graphics, canvasHeight = height, canvasWidth = this.width) + val height = (this.height * widget.progress).roundToInt().toFloat() + FUEL_FOREGROUND.renderPartial(graphics, height = height, y = this.height - height, topDown = false, width = width) + } } if (widget.isStuck && tickCount % 40 <= 20) { @@ -110,5 +151,7 @@ open class ProgressGaugePanel( companion object { val GAUGE_BACKGROUND = WidgetLocation.PROGRESS_ARROWS.sprite(y = 0f, width = 22f, height = 15f) val GAUGE_FOREGROUND = WidgetLocation.PROGRESS_ARROWS.sprite(y = 15f, width = 22f, height = 15f) + val FUEL_BACKGROUND = WidgetLocation.FUEL.sprite(y = 0f, width = 14f, height = 14f) + val FUEL_FOREGROUND = WidgetLocation.FUEL.sprite(y = 14f, width = 14f, height = 14f) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IMatteryContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IMatteryContainer.kt index 16d8b0ff2..d212c0be6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IMatteryContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IMatteryContainer.kt @@ -70,6 +70,9 @@ interface IMatteryContainer : IContainer, RecipeInput, Iterable { } } + /** + * Iterates either non-empty slots of container or all slots of container + */ fun slotIterator(nonEmpty: Boolean): Iterator { if (nonEmpty) { return (0 until containerSize).iterator().filter { this[it].isNotEmpty }.map { containerSlot(it) } @@ -230,4 +233,22 @@ interface IMatteryContainer : IContainer, RecipeInput, Iterable { return list } + + fun shrink(slot: Int, amount: Int): Boolean { + if (slot < 0 || slot > size()) + return false + + val item = this[slot] + if (item.isEmpty) + return false + + if (item.count <= amount) { + this[slot] = ItemStack.EMPTY + } else { + item.shrink(amount) + setChanged(slot) + } + + return true + } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt index 1205e3699..640b6156a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt @@ -139,6 +139,12 @@ open class BatterySlot(container: Container, index: Int, x: Int = 0, y: Int = 0) } } +open class ChemicalFuelSlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : MatterySlot(container, index, x, y) { + override fun mayPlace(itemStack: ItemStack): Boolean { + return super.mayPlace(itemStack) && itemStack.getBurnTime(null) > 0 + } +} + open class ChargeSlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : MatterySlot(container, index, x, y) { override fun mayPlace(itemStack: ItemStack): Boolean { return super.mayPlace(itemStack) && (itemStack.energy?.canReceive() ?: false) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/GrillMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/GrillMenu.kt new file mode 100644 index 000000000..a7d4fb74e --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/GrillMenu.kt @@ -0,0 +1,68 @@ +package ru.dbotthepony.mc.otm.menu.decorative + +import com.google.common.collect.ImmutableList +import net.minecraft.world.Container +import net.minecraft.world.SimpleContainer +import net.minecraft.world.entity.player.Inventory +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.crafting.RecipeType +import net.minecraft.world.item.crafting.SingleRecipeInput +import ru.dbotthepony.kommons.util.getValue +import ru.dbotthepony.mc.otm.block.entity.decorative.GrillBlockEntity +import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.core.immutableList +import ru.dbotthepony.mc.otm.menu.ChemicalFuelSlot +import ru.dbotthepony.mc.otm.menu.MatteryMenu +import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.OutputSlot +import ru.dbotthepony.mc.otm.menu.makeSlots +import ru.dbotthepony.mc.otm.menu.widget.IProgressGaugeWidget +import ru.dbotthepony.mc.otm.registry.MMenus +import java.util.function.Supplier + +class GrillMenu( + containerId: Int, + inventory: Inventory, + tile: GrillBlockEntity? = null +) : MatteryMenu(MMenus.GRILL, containerId, inventory, tile) { + val fuelSlot = makeSlots(tile?.fuelSlot ?: object : MatteryContainer(1) { + override fun getMaxStackSize(): Int { + return 4 + } + }, ::ChemicalFuelSlot) + + val inputSlots = makeSlots(tile?.inputSlots ?: object : MatteryContainer(GrillBlockEntity.SLOTS) { + override fun getMaxStackSize(): Int { + return 1 + } + }) { c, i -> + object : MatterySlot(c, i) { + override fun mayPlace(itemStack: ItemStack): Boolean { + val input = SingleRecipeInput(itemStack) + return super.mayPlace(itemStack) && player.level().recipeManager.byType(RecipeType.SMOKING).any { it.value.matches(input, player.level()) } + } + } + } + + val progress: ImmutableList = immutableList(GrillBlockEntity.SLOTS) { + object : IProgressGaugeWidget.WithTicks { + override val isStuck: Boolean + get() = totalTicks < workTicks + override val workTicks: Int by mSynchronizer.computedInt(Supplier { tile?.ticksPassed(it) ?: 0 }) + override val totalTicks: Int by mSynchronizer.computedInt(Supplier { tile?.totalTicksRequired(it) ?: 0 }) + } + } + + val fuel = object : IProgressGaugeWidget.WithTicks { + override val isStuck: Boolean + get() = false + override val workTicks: Int by mSynchronizer.computedInt(Supplier { tile?.fuelTicks ?: 0 }) + override val totalTicks: Int by mSynchronizer.computedInt(Supplier { tile?.fuelTotalTicks ?: 0 }) + } + + init { + addInventorySlots() + addStorageSlot(fuelSlot) + addStorageSlot(inputSlots) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/widget/IProgressGaugeWidget.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/widget/IProgressGaugeWidget.kt new file mode 100644 index 000000000..0e333efb1 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/widget/IProgressGaugeWidget.kt @@ -0,0 +1,16 @@ +package ru.dbotthepony.mc.otm.menu.widget + +import kotlin.math.min + +interface IProgressGaugeWidget { + val isStuck: Boolean + val progress: Float + + interface WithTicks : IProgressGaugeWidget { + val workTicks: Int + val totalTicks: Int + + override val progress: Float + get() = if (totalTicks <= 0 || workTicks <= 0) 0f else min(1f, workTicks.toFloat() / totalTicks.toFloat()) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/widget/ProgressGaugeWidget.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/widget/ProgressGaugeWidget.kt index af5cf09c1..f52f0839d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/widget/ProgressGaugeWidget.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/widget/ProgressGaugeWidget.kt @@ -9,14 +9,14 @@ import ru.dbotthepony.mc.otm.menu.MatteryMenu import java.util.function.BooleanSupplier @Suppress("unused") -class ProgressGaugeWidget(synchronizer: SynchableGroup) { +class ProgressGaugeWidget(synchronizer: SynchableGroup) : IProgressGaugeWidget { constructor(menu: MatteryMenu) : this(menu.mSynchronizer) var progressSupplier: FloatSupplier = FloatSupplier { 0f } var stuckSupplier: BooleanSupplier = BooleanSupplier { false } - val percentage by synchronizer.computedFloat(delegate = { progressSupplier.getAsFloat() }) - val isStuck by synchronizer.computedBoolean(delegate = BooleanSupplier { stuckSupplier.asBoolean }) + override val progress by synchronizer.computedFloat(delegate = { progressSupplier.getAsFloat() }) + override val isStuck by synchronizer.computedBoolean(delegate = BooleanSupplier { stuckSupplier.asBoolean }) constructor( menu: MatteryMenu, diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MBlockEntities.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MBlockEntities.kt index 2250b5604..69fd0631b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MBlockEntities.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MBlockEntities.kt @@ -15,6 +15,7 @@ import ru.dbotthepony.mc.otm.block.entity.cable.SimpleEnergyCableBlockEntity import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity import ru.dbotthepony.mc.otm.block.entity.decorative.DevChestBlockEntity import ru.dbotthepony.mc.otm.block.entity.decorative.FluidTankBlockEntity +import ru.dbotthepony.mc.otm.block.entity.decorative.GrillBlockEntity import ru.dbotthepony.mc.otm.block.entity.decorative.HoloSignBlockEntity import ru.dbotthepony.mc.otm.block.entity.decorative.InfiniteWaterSourceBlockEntity import ru.dbotthepony.mc.otm.block.entity.decorative.PainterBlockEntity @@ -106,6 +107,8 @@ object MBlockEntities { val STORAGE_EXPORTER by register(MNames.STORAGE_EXPORTER, ::StorageExporterBlockEntity, MBlocks::STORAGE_EXPORTER) val STORAGE_POWER_SUPPLIER by register(MNames.STORAGE_POWER_SUPPLIER, ::StoragePowerSupplierBlockEntity, MBlocks.STORAGE_POWER_SUPPLIER) + val GRILL by register(MNames.GRILL, ::GrillBlockEntity, MBlocks.GRILL) + val HOLO_SIGN: BlockEntityType by registry.register(MNames.HOLO_SIGN) { BlockEntityType.Builder.of(::HoloSignBlockEntity, MBlocks.HOLO_SIGN).build(null) } fun register(bus: IEventBus) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MBlocks.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MBlocks.kt index e3ea01009..bb4e4b231 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MBlocks.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MBlocks.kt @@ -35,6 +35,7 @@ import ru.dbotthepony.mc.otm.block.addSimpleDescription import ru.dbotthepony.mc.otm.block.decorative.DevChestBlock import ru.dbotthepony.mc.otm.block.decorative.EngineBlock import ru.dbotthepony.mc.otm.block.decorative.FluidTankBlock +import ru.dbotthepony.mc.otm.block.decorative.GrillBlock import ru.dbotthepony.mc.otm.block.decorative.HoloSignBlock import ru.dbotthepony.mc.otm.block.decorative.InfiniteWaterSourceBlock import ru.dbotthepony.mc.otm.block.decorative.LaboratoryLamp @@ -166,6 +167,8 @@ object MBlocks { val STORAGE_CABLE: Block by registry.register(MNames.STORAGE_CABLE, ::StorageCableBlock) val STORAGE_POWER_SUPPLIER = registry.coloredWithBase(MNames.STORAGE_POWER_SUPPLIER, ::StoragePowerSupplierBlock) + val GRILL = registry.coloredWithBase(MNames.GRILL, ::GrillBlock) + val BLACK_HOLE: Block by registry.register(MNames.BLACK_HOLE) { BlackHoleBlock() } val GRAVITATION_STABILIZER: Block by registry.register(MNames.GRAVITATION_STABILIZER) { BlockGravitationStabilizer() } val GRAVITATION_STABILIZER_LENS: Block by registry.register(MNames.GRAVITATION_STABILIZER_LENS) { BlockGravitationStabilizerLens() } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MCreativeTabs.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MCreativeTabs.kt index 58dc26ffc..5b6f57e45 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MCreativeTabs.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MCreativeTabs.kt @@ -147,6 +147,8 @@ private fun addMainCreativeTabItems(consumer: CreativeModeTab.Output) { accept(MRegistry.TRITANIUM_PRESSURE_PLATE.item) accept(MItems.TRITANIUM_ANVIL[0]) + accept(MItems.GRILL.values) + // accept(MItems.MATTER_DUST) accept(MItems.TRITANIUM_ORE) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MItems.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MItems.kt index ec2c208ae..dad58de9d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MItems.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MItems.kt @@ -121,6 +121,8 @@ object MItems { val STORAGE_CABLE: BlockItem by registry.register(MNames.STORAGE_CABLE) { BlockItem(MBlocks.STORAGE_CABLE, DEFAULT_PROPERTIES) } val STORAGE_POWER_SUPPLIER = register(MNames.STORAGE_POWER_SUPPLIER, MBlocks.STORAGE_POWER_SUPPLIER) + val GRILL = registry.coloredWithBase(MNames.GRILL) { BlockItem(MBlocks.GRILL[it]!!, DEFAULT_PROPERTIES) } + val GRAVITATION_STABILIZER: BlockItem by registry.register(MNames.GRAVITATION_STABILIZER) { BlockItem(MBlocks.GRAVITATION_STABILIZER, DEFAULT_PROPERTIES) } val PHANTOM_ATTRACTOR: DoubleHighBlockItem by registry.register(MNames.PHANTOM_ATTRACTOR) { DoubleHighBlockItem(MBlocks.PHANTOM_ATTRACTOR, DEFAULT_PROPERTIES) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MMenus.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MMenus.kt index 035d1ef39..a00498868 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MMenus.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MMenus.kt @@ -8,6 +8,7 @@ import net.neoforged.neoforge.client.event.RegisterMenuScreensEvent import ru.dbotthepony.mc.otm.block.entity.tech.AndroidChargerBlockEntity import ru.dbotthepony.mc.otm.client.screen.decorative.CargoCrateScreen import ru.dbotthepony.mc.otm.client.screen.decorative.FluidTankScreen +import ru.dbotthepony.mc.otm.client.screen.decorative.GrillScreen import ru.dbotthepony.mc.otm.client.screen.decorative.HoloSignScreen import ru.dbotthepony.mc.otm.client.screen.decorative.MinecartCargoCrateScreen import ru.dbotthepony.mc.otm.client.screen.decorative.PainterScreen @@ -42,6 +43,7 @@ import ru.dbotthepony.mc.otm.client.screen.tech.ItemHatchScreen import ru.dbotthepony.mc.otm.client.screen.tech.MatterHatchScreen import ru.dbotthepony.mc.otm.menu.decorative.CargoCrateMenu import ru.dbotthepony.mc.otm.menu.decorative.FluidTankMenu +import ru.dbotthepony.mc.otm.menu.decorative.GrillMenu import ru.dbotthepony.mc.otm.menu.decorative.HoloSignMenu import ru.dbotthepony.mc.otm.menu.decorative.MinecartCargoCrateMenu import ru.dbotthepony.mc.otm.menu.decorative.PainterMenu @@ -91,6 +93,7 @@ object MMenus { val MATTER_BOTTLER by registry.register(MNames.MATTER_BOTTLER) { MenuType(::MatterBottlerMenu, FeatureFlags.VANILLA_SET) } val DRIVE_VIEWER by registry.register(MNames.DRIVE_VIEWER) { MenuType(::DriveViewerMenu, FeatureFlags.VANILLA_SET) } val CARGO_CRATE by registry.register(MNames.CARGO_CRATE) { MenuType(::CargoCrateMenu, FeatureFlags.VANILLA_SET) } + val GRILL by registry.register(MNames.GRILL) { MenuType(::GrillMenu, FeatureFlags.VANILLA_SET) } val MINECART_CARGO_CRATE by registry.register(MNames.MINECART_CARGO_CRATE) { MenuType(::MinecartCargoCrateMenu, FeatureFlags.VANILLA_SET) } val DRIVE_RACK by registry.register(MNames.DRIVE_RACK) { MenuType(::DriveRackMenu, FeatureFlags.VANILLA_SET) } val ITEM_MONITOR by registry.register(MNames.ITEM_MONITOR) { MenuType(::ItemMonitorMenu, FeatureFlags.VANILLA_SET) } @@ -140,6 +143,7 @@ object MMenus { event.register(MATTER_BOTTLER, ::MatterBottlerScreen) event.register(DRIVE_VIEWER, ::DriveViewerScreen) event.register(CARGO_CRATE, ::CargoCrateScreen) + event.register(GRILL, ::GrillScreen) event.register(MINECART_CARGO_CRATE, ::MinecartCargoCrateScreen) event.register(DRIVE_RACK, ::DriveRackScreen) event.register(ITEM_MONITOR, ::ItemMonitorScreen) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MNames.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MNames.kt index a13d05887..890c37f48 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MNames.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MNames.kt @@ -58,6 +58,7 @@ object MNames { const val STORAGE_CABLE = "storage_cable" // нужен рецепт const val STORAGE_POWER_SUPPLIER = "storage_power_supplier" // нужен рецепт + const val GRILL = "grill" // нужен рецепт const val DEBUG_EXPLOSION_SMALL = "debug_explosion_small" const val DEBUG_SPHERE_POINTS = "debug_sphere_points" diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/fuel.png b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/fuel.png new file mode 100644 index 0000000000000000000000000000000000000000..e8389bfa6c6fd064b1c4cc9e4260a675c50ae707 GIT binary patch literal 833 zcmV-H1HSx;P)EX>4Tx04R}tkv&MmKpe$i(~3nZ4(%Y~5TrWUMMWG-6^me@v=v%)FuC*#nlvOS zE{=k0!NHHks)LKOt`4q(Aou~|?BJy6A|?JWDYS_3;J6>}?mh0_0YaNsHm-ExlVHwNh~3SG(^Z~po$tS#Aww>F_EGDgol5`@u$fpldB3w zjs?`ALUR1zfAG6ovot;BCWR6}--~U3j063$;!rY@@ zYnIJe{pA&iS*w57K{%IdlW1rl5p00000 LNkvXXu0mjfOY(AE literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/fuel.xcf b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/fuel.xcf new file mode 100644 index 0000000000000000000000000000000000000000..8ee1b4188d7eac501e023885954a9d66073d40f9 GIT binary patch literal 2254 zcmeHI%W4!s6s@kFJdDN%K2}1vMj=@YWWGQU1~>B)$z*11NHQT4C2qvH?M-muM~H|B zHi*P!Aqdj5%QuK%b|J61o>Ns#Di9D{xv+*)b?&KC)wiqr_VluqwRE%HO`py;8Vc<) zaGM0}HE<1xB6Qb*$%orY5okAnn#V0a(svX13S8}B>w31b(CgHD>)8?{#re0hgNjKae8yGw$RR2dud}H(X%s= z59&`=vyC)cZ9nb|xT4?f4mumD^#|P1vu5TTwCIrwYVQKEqSGKeJl^9>`D(Z|d|AFP zKa`)#kL6CeGtA3R>2M3-7myiy*5k192nD!9{@?|A95X{pu_VePQ^Rxw9s|^B&=~9dz%Ow=dbOPs zJCf`Ce-`c>>{%$0Np*~;k3mEShy$)wB(d73%_3HZj%zH5B*H5cW7H}JsMVk`)^gyN zI3K;*&WRn#HMX)PR+U-$hce^4r0ol()W1|~Oo{jKx3w1gd-B8B_aNrJgs-)+ALqf#QND#pg$v1C+45M|T6W9SSQTJ1j zFp=YtVr`V8Mfg43)iHf zu&Eb_V2b1o4F!|UVFZDmn?hOyC9m7etVF8_Ho#7FN^VWoAY4P{QvbzyyB#Dj6MS4o zrit8}$X%f$IcX~9t{nChb8jZ-k|qIzN_gxF5lq_&HZ@pd1g2&J0zEehb|pkV4o=5^C2>zGYId&%Z>Lb9)<;Q@PTzwRdg#Tx(SJtqrZLOes kC+nCsE%*k6oUy2JXw=8-C~Crbskt@W*R6Ga7gHmC1A&kp#sB~S literal 0 HcmV?d00001