Compare commits
2 Commits
057c97fae9
...
7c35c284cd
Author | SHA1 | Date | |
---|---|---|---|
7c35c284cd | |||
a09795ad74 |
@ -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")
|
||||
|
@ -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]!!, "Вагонетка с грузовым ящиком")
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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"}")
|
||||
}
|
||||
}
|
||||
|
@ -413,4 +413,6 @@ fun addPainterRecipes(consumer: RecipeOutput) {
|
||||
mapOf(color to 1)
|
||||
))
|
||||
}
|
||||
|
||||
generate(consumer, MItems.GRILL[null]!!, MItems.GRILL)
|
||||
}
|
||||
|
@ -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<Block>(
|
||||
*MBlocks.ANDROID_STATION.values.toTypedArray(),
|
||||
|
@ -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<Property<*>>, fn: (BlockState) -> VoxelShape): Map<BlockState, VoxelShape> {
|
||||
val builder = Object2ObjectArrayMap<BlockState, Supplier<VoxelShape>>()
|
||||
@ -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) {
|
||||
|
@ -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 <T : BlockEntity?> getTicker(
|
||||
p_153212_: Level,
|
||||
p_153213_: BlockState,
|
||||
p_153214_: BlockEntityType<T>
|
||||
): BlockEntityTicker<T>? {
|
||||
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<Block, BlockState>) {
|
||||
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<State> = EnumProperty.create("state", State::class.java)
|
||||
}
|
||||
}
|
@ -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) {
|
||||
|
@ -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<SmokingRecipe>(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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -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<GrillMenu>(menu, inventory, title) {
|
||||
override fun makeMainFrame(): FramePanel<MatteryScreen<*>> {
|
||||
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
|
||||
}
|
||||
}
|
@ -34,6 +34,7 @@ import java.util.concurrent.CopyOnWriteArrayList
|
||||
import java.util.function.Predicate
|
||||
import java.util.random.RandomGenerator
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.math.max
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
data class ScreenPos(val x: Float, val y: Float)
|
||||
@ -1385,24 +1386,66 @@ open class EditablePanel<out S : Screen>(
|
||||
|
||||
/**
|
||||
* Attempts to tightly fit dimensions to all children
|
||||
*
|
||||
* Performs layout if required
|
||||
*/
|
||||
open fun sizeToContents(performLayout: Boolean = true) {
|
||||
if (layoutInvalidated && performLayout) {
|
||||
performLayout()
|
||||
open fun sizeToContents() {
|
||||
if (visibleChildrenInternal.isEmpty() || visibleChildrenInternal.any { it.dock == Dock.FILL }) {
|
||||
// nothing to size against OR there is "fill" children
|
||||
return
|
||||
}
|
||||
|
||||
var width = 1f
|
||||
var height = 1f
|
||||
visibleChildrenInternal.forEach { it.sizeToContents() }
|
||||
|
||||
var accumulatedWidth = 0f
|
||||
var accumulatedHeight = 0f
|
||||
|
||||
var height = 0f
|
||||
var width = 0f
|
||||
var previousDock = 0
|
||||
|
||||
for (child in visibleChildrenInternal) {
|
||||
width = width.coerceAtLeast(child.x + child.width)
|
||||
height = height.coerceAtLeast(child.y + child.height)
|
||||
when (child.dock) {
|
||||
Dock.NONE, Dock.FILL -> {} // do nothing
|
||||
|
||||
Dock.LEFT, Dock.RIGHT -> {
|
||||
if (previousDock != 1) {
|
||||
previousDock = 1
|
||||
width += accumulatedWidth
|
||||
height = max(height, accumulatedHeight)
|
||||
accumulatedWidth = 0f
|
||||
accumulatedHeight = 0f
|
||||
}
|
||||
|
||||
accumulatedWidth += child.dockLeft + child.dockRight + child.width
|
||||
accumulatedHeight = max(accumulatedHeight, child.dockTop + child.dockBottom + child.height)
|
||||
}
|
||||
|
||||
Dock.TOP, Dock.BOTTOM -> {
|
||||
if (previousDock != 2) {
|
||||
previousDock = 2
|
||||
height += accumulatedHeight
|
||||
width = max(width, accumulatedWidth)
|
||||
accumulatedWidth = 0f
|
||||
accumulatedHeight = 0f
|
||||
}
|
||||
|
||||
accumulatedHeight += child.dockTop + child.dockBottom + child.height
|
||||
accumulatedWidth = max(accumulatedWidth, child.dockLeft + child.dockRight + child.width)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.width = width
|
||||
this.height = height
|
||||
if (previousDock == 1) {
|
||||
height += accumulatedHeight
|
||||
width = max(width, accumulatedWidth)
|
||||
} else if (previousDock == 2) {
|
||||
width += accumulatedWidth
|
||||
height = max(height, accumulatedHeight)
|
||||
}
|
||||
|
||||
this.width = width + dockPadding.left + dockPadding.right
|
||||
this.height = height + dockPadding.top + dockPadding.bottom
|
||||
|
||||
performLayout()
|
||||
}
|
||||
|
||||
protected open fun visibilityChanges(new: Boolean, old: Boolean) {
|
||||
|
@ -60,9 +60,7 @@ open class Label<out S : Screen>(
|
||||
}
|
||||
}
|
||||
|
||||
override fun sizeToContents(performLayout: Boolean) {
|
||||
super.sizeToContents(performLayout)
|
||||
|
||||
override fun sizeToContents() {
|
||||
val w = font.width(text)
|
||||
val h = font.lineHeight + 2
|
||||
|
||||
|
@ -12,6 +12,7 @@ import ru.dbotthepony.mc.otm.client.render.UVWindingOrder
|
||||
import ru.dbotthepony.mc.otm.client.render.Widgets15
|
||||
import ru.dbotthepony.mc.otm.client.render.Widgets8
|
||||
import java.util.function.IntConsumer
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
@ -140,14 +141,65 @@ abstract class ButtonPanel<out S : Screen>(
|
||||
}
|
||||
}
|
||||
|
||||
override fun sizeToContents(performLayout: Boolean) {
|
||||
super.sizeToContents(performLayout)
|
||||
override fun sizeToContents() {
|
||||
when (iconSpaceReservation) {
|
||||
SpaceReservation.DEFAULT -> {
|
||||
val icon = icon
|
||||
val label = label
|
||||
|
||||
val label = label
|
||||
if (label == null && icon == null) {
|
||||
// i have no idea what you want me to do
|
||||
width = 18f
|
||||
height = 18f
|
||||
} else {
|
||||
var width = 2f
|
||||
var height = 2f
|
||||
|
||||
if (label != null) {
|
||||
height = height.coerceAtLeast(HEIGHT).coerceAtLeast(font.lineHeight.toFloat() + 2f)
|
||||
width = width.coerceAtLeast(HEIGHT).coerceAtLeast(font.width(label) + 4f)
|
||||
if (icon != null) {
|
||||
width = icon.width
|
||||
height = icon.height
|
||||
}
|
||||
|
||||
if (label != null) {
|
||||
if (icon != null) {
|
||||
width += 2f
|
||||
height = max(height, font.lineHeight.toFloat() + 2f)
|
||||
} else {
|
||||
height = 18f
|
||||
}
|
||||
|
||||
width += font.width(label) + 2f
|
||||
}
|
||||
|
||||
this.width = width
|
||||
this.height = height
|
||||
}
|
||||
}
|
||||
|
||||
SpaceReservation.ICON_AND_TEXT -> {
|
||||
var height = icon?.height ?: 18f
|
||||
var width = icon?.width ?: 18f
|
||||
|
||||
width += 2f
|
||||
|
||||
val label = label
|
||||
|
||||
if (label != null) {
|
||||
height = max(height, font.lineHeight.toFloat() + 2f)
|
||||
width += font.width(label) + 2f
|
||||
}
|
||||
|
||||
this.width = width
|
||||
this.height = height
|
||||
}
|
||||
|
||||
SpaceReservation.ICON_ONLY -> {
|
||||
val height = icon?.height ?: 18f
|
||||
val width = icon?.width ?: 18f
|
||||
val min = min(width, height)
|
||||
this.height = min
|
||||
this.width = min
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ class HorizontalStripPanel<out S : Screen>(
|
||||
width: Float = 0f,
|
||||
height: Float = 0f,
|
||||
) : EditablePanel<S>(screen, parent, x, y, width, height) {
|
||||
override fun sizeToContents(performLayout: Boolean) {
|
||||
override fun sizeToContents() {
|
||||
var w = 0f
|
||||
var h = 0f
|
||||
|
||||
|
@ -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<out S : Screen>(
|
||||
screen: S,
|
||||
parent: EditablePanel<*>? = null,
|
||||
val widget: ProgressGaugeWidget,
|
||||
val widget: IProgressGaugeWidget,
|
||||
x: Float = 0f,
|
||||
y: Float = 0f
|
||||
): AbstractButtonPanel<S>(screen, parent, x, y, width = GAUGE_BACKGROUND.width, height = GAUGE_BACKGROUND.height) {
|
||||
): AbstractButtonPanel<S>(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<List<RecipeType<*>>>? = null
|
||||
|
||||
protected open fun makeTooltip(): MutableList<Component> {
|
||||
val tooltip: MutableList<Component>
|
||||
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<Component> {
|
||||
val tooltip = ArrayList<Component>()
|
||||
|
||||
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<out S : Screen>(
|
||||
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<out S : Screen>(
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -70,6 +70,9 @@ interface IMatteryContainer : IContainer, RecipeInput, Iterable<ItemStack> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates either non-empty slots of container or all slots of container
|
||||
*/
|
||||
fun slotIterator(nonEmpty: Boolean): Iterator<IContainerSlot> {
|
||||
if (nonEmpty) {
|
||||
return (0 until containerSize).iterator().filter { this[it].isNotEmpty }.map { containerSlot(it) }
|
||||
@ -230,4 +233,22 @@ interface IMatteryContainer : IContainer, RecipeInput, Iterable<ItemStack> {
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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<Container, MatterySlot>(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<IProgressGaugeWidget.WithTicks> = 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)
|
||||
}
|
||||
}
|
@ -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())
|
||||
}
|
||||
}
|
@ -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,
|
||||
|
@ -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<HoloSignBlockEntity> by registry.register(MNames.HOLO_SIGN) { BlockEntityType.Builder.of(::HoloSignBlockEntity, MBlocks.HOLO_SIGN).build(null) }
|
||||
|
||||
fun register(bus: IEventBus) {
|
||||
|
@ -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() }
|
||||
|
@ -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)
|
||||
|
@ -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) }
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 833 B |
Binary file not shown.
Loading…
Reference in New Issue
Block a user