Painter table water ingredient, semi-realistic color mixing
This commit is contained in:
parent
474a19a30b
commit
636afe639e
@ -445,7 +445,7 @@ fun addCraftingTableRecipes(consumer: RecipeOutput) {
|
|||||||
.build(consumer)
|
.build(consumer)
|
||||||
|
|
||||||
MatteryRecipe(MItems.PAINTER, category = machinesCategory)
|
MatteryRecipe(MItems.PAINTER, category = machinesCategory)
|
||||||
.row(Items.BRUSH, Items.BUCKET, Items.WATER_BUCKET)
|
.row(Items.BRUSH, Items.BUCKET, Items.BUCKET)
|
||||||
.row(MItemTags.IRON_PLATES, Items.BUCKET, MItemTags.IRON_PLATES)
|
.row(MItemTags.IRON_PLATES, Items.BUCKET, MItemTags.IRON_PLATES)
|
||||||
.row(MItemTags.IRON_PLATES, MItemTags.CRAFTING_TABLES, MItemTags.IRON_PLATES)
|
.row(MItemTags.IRON_PLATES, MItemTags.CRAFTING_TABLES, MItemTags.IRON_PLATES)
|
||||||
.unlockedBy(Tags.Items.DYES)
|
.unlockedBy(Tags.Items.DYES)
|
||||||
|
@ -50,7 +50,7 @@ private fun cleaning(consumer: RecipeOutput, to: Item, from: Map<out DyeColor?,
|
|||||||
consumer.accept(PainterRecipe(
|
consumer.accept(PainterRecipe(
|
||||||
Ingredient.of(from.entries.stream().filter { it.key != null }.map { ItemStack(it.value) }),
|
Ingredient.of(from.entries.stream().filter { it.key != null }.map { ItemStack(it.value) }),
|
||||||
ItemStack(to),
|
ItemStack(to),
|
||||||
setOf()
|
mapOf(null to 15)
|
||||||
).toFinished(modLocation("painter/cleaning/" + to.recipeName)))
|
).toFinished(modLocation("painter/cleaning/" + to.recipeName)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
package ru.dbotthepony.mc.otm.block.entity.decorative
|
package ru.dbotthepony.mc.otm.block.entity.decorative
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList
|
import com.google.common.collect.ImmutableList
|
||||||
|
import com.mojang.datafixers.util.Either
|
||||||
import it.unimi.dsi.fastutil.ints.Int2IntArrayMap
|
import it.unimi.dsi.fastutil.ints.Int2IntArrayMap
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2IntArrayMap
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2IntMap
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap
|
||||||
import net.minecraft.core.BlockPos
|
import net.minecraft.core.BlockPos
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.CompoundTag
|
||||||
import net.minecraft.world.entity.player.Inventory
|
import net.minecraft.world.entity.player.Inventory
|
||||||
@ -10,25 +14,31 @@ import net.minecraft.world.inventory.AbstractContainerMenu
|
|||||||
import net.minecraft.world.item.DyeColor
|
import net.minecraft.world.item.DyeColor
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.minecraft.world.level.block.state.BlockState
|
import net.minecraft.world.level.block.state.BlockState
|
||||||
|
import net.minecraft.world.level.material.Fluids
|
||||||
|
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
||||||
|
import net.minecraftforge.fluids.FluidStack
|
||||||
|
import net.minecraftforge.fluids.capability.IFluidHandler
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||||
|
import ru.dbotthepony.mc.otm.core.ifPresentK
|
||||||
import ru.dbotthepony.mc.otm.core.immutableList
|
import ru.dbotthepony.mc.otm.core.immutableList
|
||||||
import ru.dbotthepony.mc.otm.core.immutableMap
|
import ru.dbotthepony.mc.otm.core.immutableMap
|
||||||
|
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.mapPresent
|
import ru.dbotthepony.mc.otm.core.nbt.mapPresent
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||||
import ru.dbotthepony.mc.otm.menu.decorative.PainterMenu
|
import ru.dbotthepony.mc.otm.menu.decorative.PainterMenu
|
||||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class PainterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.PAINTER, blockPos, blockState) {
|
class PainterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.PAINTER, blockPos, blockState), IFluidHandler {
|
||||||
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
|
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
|
||||||
return PainterMenu(containerID, inventory, this)
|
return PainterMenu(containerID, inventory, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
val dyeInput = MatteryContainer(this::markDirtyFast, 1)
|
val dyeInput = MatteryContainer(this::markDirtyFast, 1)
|
||||||
private val dyeStored = EnumMap<DyeColor, Int>(DyeColor::class.java)
|
// null - water
|
||||||
val dyeStoredView: Map<DyeColor, Int> = Collections.unmodifiableMap(dyeStored)
|
val dyeStored = Object2IntArrayMap<DyeColor?>()
|
||||||
|
|
||||||
var isBulk = false
|
var isBulk = false
|
||||||
set(value) {
|
set(value) {
|
||||||
@ -36,19 +46,63 @@ class PainterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDe
|
|||||||
markDirtyFast()
|
markDirtyFast()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getTanks(): Int {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFluidInTank(tank: Int): FluidStack {
|
||||||
|
if (tank != 1) return FluidStack.EMPTY
|
||||||
|
if (waterStored() == 0) return FluidStack.EMPTY
|
||||||
|
return FluidStack(Fluids.WATER, waterStored())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTankCapacity(tank: Int): Int {
|
||||||
|
if (tank == 1) return MAX_WATER_STORAGE
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isFluidValid(tank: Int, stack: FluidStack): Boolean {
|
||||||
|
return tank == 0 && stack.fluid == Fluids.WATER
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun fill(resource: FluidStack, action: IFluidHandler.FluidAction): Int {
|
||||||
|
if (resource.isEmpty || resource.fluid != Fluids.WATER || waterStored() >= MAX_WATER_STORAGE) return 0
|
||||||
|
val diff = (waterStored() + resource.amount).coerceAtMost(MAX_WATER_STORAGE) - waterStored()
|
||||||
|
if (action.simulate() || diff == 0) return diff
|
||||||
|
dyeStored[null] = waterStored() + diff
|
||||||
|
return diff
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun drain(resource: FluidStack, action: IFluidHandler.FluidAction): FluidStack {
|
||||||
|
return FluidStack.EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun drain(maxDrain: Int, action: IFluidHandler.FluidAction): FluidStack {
|
||||||
|
return FluidStack.EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
addDroppableContainer(dyeInput)
|
addDroppableContainer(dyeInput)
|
||||||
savetables.stateful(dyeInput, INVENTORY_KEY)
|
savetables.stateful(dyeInput, INVENTORY_KEY)
|
||||||
savetables.bool(::isBulk)
|
savetables.bool(::isBulk)
|
||||||
|
exposeGlobally(ForgeCapabilities.FLUID_HANDLER, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun takeDyes(dyes: Map<DyeColor, Int>) {
|
fun takeDyes(dyes: Map<out DyeColor?, Int>) {
|
||||||
for ((dye, amount) in dyes) {
|
for ((dye, amount) in dyes) {
|
||||||
for (i in 0 until amount) {
|
if (dye == null) {
|
||||||
mixer(dye).mix(dyeStored)
|
for (i in 0 until amount) {
|
||||||
|
if (waterStored() >= 1) {
|
||||||
|
dyeStored[dye] = waterStored() - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (i in 0 until amount) {
|
||||||
|
mixer(dye)?.mix(dyeStored)
|
||||||
|
|
||||||
if (dyeStored(dye) > 0) {
|
if (dyeStored(dye) > 0) {
|
||||||
dyeStored[dye] = dyeStored(dye) - 1
|
dyeStored[dye] = dyeStored(dye) - 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,6 +112,16 @@ class PainterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDe
|
|||||||
|
|
||||||
val config = ConfigurableItemHandler(input = dyeInput.handler(object : HandlerFilter {
|
val config = ConfigurableItemHandler(input = dyeInput.handler(object : HandlerFilter {
|
||||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
||||||
|
if (waterStored() < MAX_WATER_STORAGE) {
|
||||||
|
stack.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).ifPresentK {
|
||||||
|
val drain = it.drain(FluidStack(Fluids.WATER, MAX_WATER_STORAGE - waterStored()), IFluidHandler.FluidAction.SIMULATE)
|
||||||
|
|
||||||
|
if (drain.isNotEmpty) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val dye = DyeColor.entries.firstOrNull { stack.`is`(it.tag) } ?: return false
|
val dye = DyeColor.entries.firstOrNull { stack.`is`(it.tag) } ?: return false
|
||||||
return dyeStored(dye) + HUE_PER_ITEM <= MAX_STORAGE
|
return dyeStored(dye) + HUE_PER_ITEM <= MAX_STORAGE
|
||||||
}
|
}
|
||||||
@ -75,14 +139,12 @@ class PainterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDe
|
|||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
fun dyeStored(dye: DyeColor): Int {
|
fun waterStored(): Int {
|
||||||
return dyeStored[dye]!!
|
return dyeStored.getInt(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
fun dyeStored(dye: DyeColor?): Int {
|
||||||
for (dye in DyeColor.entries) {
|
return dyeStored.getInt(dye)
|
||||||
dyeStored[dye] = 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun saveShared(nbt: CompoundTag) {
|
override fun saveShared(nbt: CompoundTag) {
|
||||||
@ -90,7 +152,7 @@ class PainterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDe
|
|||||||
|
|
||||||
nbt["dyes"] = CompoundTag().also {
|
nbt["dyes"] = CompoundTag().also {
|
||||||
for ((k, v) in dyeStored) {
|
for ((k, v) in dyeStored) {
|
||||||
it[k.getName()] = v
|
it[k?.getName() ?: "water"] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,13 +160,14 @@ class PainterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDe
|
|||||||
override fun load(nbt: CompoundTag) {
|
override fun load(nbt: CompoundTag) {
|
||||||
super.load(nbt)
|
super.load(nbt)
|
||||||
|
|
||||||
for (dye in DyeColor.entries) {
|
dyeStored.clear()
|
||||||
dyeStored[dye] = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
nbt.mapPresent("dyes") { it: CompoundTag ->
|
nbt.mapPresent("dyes") { it: CompoundTag ->
|
||||||
for (k in it.allKeys) {
|
for (k in it.allKeys) {
|
||||||
dyeStored[DyeColor.entries.firstOrNull { it.getName() == k } ?: continue] = it.getInt(k)
|
if (k == "water")
|
||||||
|
dyeStored[null] = it.getInt("water")
|
||||||
|
else
|
||||||
|
dyeStored[DyeColor.entries.firstOrNull { it.getName() == k } ?: continue] = it.getInt(k)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,6 +176,17 @@ class PainterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDe
|
|||||||
super.tick()
|
super.tick()
|
||||||
|
|
||||||
for (slot in dyeInput.slotIterator()) {
|
for (slot in dyeInput.slotIterator()) {
|
||||||
|
if (waterStored() < MAX_WATER_STORAGE) {
|
||||||
|
slot.item.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).ifPresentK {
|
||||||
|
val drain = it.drain(FluidStack(Fluids.WATER, MAX_WATER_STORAGE - waterStored()), IFluidHandler.FluidAction.EXECUTE)
|
||||||
|
|
||||||
|
if (drain.isNotEmpty) {
|
||||||
|
dyeStored[null] = waterStored() + drain.amount
|
||||||
|
slot.item = it.container
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val dye = DyeColor.entries.firstOrNull { slot.item.`is`(it.tag) } ?: continue
|
val dye = DyeColor.entries.firstOrNull { slot.item.`is`(it.tag) } ?: continue
|
||||||
val stored = dyeStored(dye)
|
val stored = dyeStored(dye)
|
||||||
|
|
||||||
@ -124,20 +198,20 @@ class PainterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Mixer(val color: DyeColor, vararg mixing: ImmutableList<DyeColor>) : Map.Entry<DyeColor, Mixer> {
|
class Mixer(val color: DyeColor, vararg mixing: ImmutableList<Optional<DyeColor>>) : Map.Entry<DyeColor, Mixer> {
|
||||||
val mixing: ImmutableList<ImmutableList<DyeColor>> = ImmutableList.copyOf(mixing)
|
val mixing: ImmutableList<ImmutableList<Optional<DyeColor>>> = ImmutableList.copyOf(mixing)
|
||||||
|
|
||||||
override val key: DyeColor
|
override val key: DyeColor
|
||||||
get() = color
|
get() = color
|
||||||
override val value: Mixer
|
override val value: Mixer
|
||||||
get() = this
|
get() = this
|
||||||
|
|
||||||
private fun mix(input: MutableMap<DyeColor, Int>, seen: MutableSet<DyeColor>, stack: MutableSet<DyeColor>) {
|
private fun mix(input: Object2IntMap<DyeColor?>, seen: MutableSet<DyeColor>, stack: MutableSet<DyeColor>) {
|
||||||
if (input[color]!! > 0 || color in seen || color in stack) return
|
if (input.getInt(color) > 0 || color in seen || color in stack) return
|
||||||
stack.add(color)
|
stack.add(color)
|
||||||
|
|
||||||
for (ingredients in mixing) {
|
for (ingredients in mixing) {
|
||||||
val copy = EnumMap(input)
|
val copy = Object2IntArrayMap(input)
|
||||||
var i = 0
|
var i = 0
|
||||||
val volumes = Int2IntArrayMap()
|
val volumes = Int2IntArrayMap()
|
||||||
|
|
||||||
@ -146,8 +220,11 @@ class PainterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDe
|
|||||||
for (i2 in ingredients.indices)
|
for (i2 in ingredients.indices)
|
||||||
volumes[i2] = 1
|
volumes[i2] = 1
|
||||||
|
|
||||||
while (!ingredients.all { copy[it]!! > 0 } && i++ < 20) {
|
while (!ingredients.all { copy.getInt(it.orElse(null)) > 0 } && i++ < 20) {
|
||||||
ingredients.withIndex().forEach { for (t in 0 until volumes[it.index]) mixer(it.value).mix(copy, seen, stack) }
|
ingredients.withIndex().forEach {
|
||||||
|
for (t in 0 until volumes[it.index])
|
||||||
|
it.value.ifPresent { mixer(it)?.mix(copy, seen, stack) }
|
||||||
|
}
|
||||||
|
|
||||||
var increase = i
|
var increase = i
|
||||||
val iter = ingredients.indices.iterator()
|
val iter = ingredients.indices.iterator()
|
||||||
@ -157,8 +234,8 @@ class PainterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ingredients.all { copy[it]!! > 0 }) {
|
if (ingredients.all { copy.getInt(it.orElse(null)) > 0 }) {
|
||||||
ingredients.forEach { copy[it] = copy[it]!! - 1 }
|
ingredients.forEach { copy[it.orElse(null)] = copy.getInt(it.orElse(null)) - 1 }
|
||||||
copy[color] = ingredients.size
|
copy[color] = ingredients.size
|
||||||
|
|
||||||
input.putAll(copy)
|
input.putAll(copy)
|
||||||
@ -171,29 +248,38 @@ class PainterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDe
|
|||||||
seen.add(color)
|
seen.add(color)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun mix(input: MutableMap<DyeColor, Int>) {
|
fun mix(input: Object2IntMap<DyeColor?>) {
|
||||||
mix(input, EnumSet.noneOf(DyeColor::class.java), EnumSet.noneOf(DyeColor::class.java))
|
mix(input, EnumSet.noneOf(DyeColor::class.java), EnumSet.noneOf(DyeColor::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isAvailable(input: Map<DyeColor, Int>): Boolean {
|
fun isAvailable(input: Object2IntMap<DyeColor?>): Boolean {
|
||||||
if (input[color]!! > 0) return true
|
if (input.getInt(color) > 0) return true
|
||||||
return EnumMap(input).also(::mix)[color]!! > 0
|
return Object2IntArrayMap(input).also(::mix).getInt(color) > 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun mixer(color: DyeColor): Mixer {
|
fun mixer(color: DyeColor): Mixer? {
|
||||||
return MIXING[color]!!
|
return MIXING[color]
|
||||||
}
|
}
|
||||||
|
|
||||||
val MIXING = immutableMap {
|
val MIXING = immutableMap<DyeColor, Mixer> {
|
||||||
put(Mixer(DyeColor.BLACK, immutableList(DyeColor.CYAN, DyeColor.MAGENTA, DyeColor.YELLOW)))
|
put(Mixer(DyeColor.BLACK, immutableList(Optional.of(DyeColor.CYAN), Optional.of(DyeColor.MAGENTA), Optional.of(DyeColor.YELLOW))))
|
||||||
put(Mixer(DyeColor.RED, immutableList(DyeColor.MAGENTA, DyeColor.YELLOW)))
|
put(Mixer(DyeColor.RED, immutableList(Optional.of(DyeColor.MAGENTA), Optional.of(DyeColor.YELLOW))))
|
||||||
put(Mixer(DyeColor.GREEN, immutableList(DyeColor.CYAN, DyeColor.YELLOW)))
|
put(Mixer(DyeColor.GREEN, immutableList(Optional.of(DyeColor.CYAN), Optional.of(DyeColor.YELLOW))))
|
||||||
put(Mixer(DyeColor.BLUE, immutableList(DyeColor.CYAN, DyeColor.MAGENTA)))
|
put(Mixer(DyeColor.BLUE, immutableList(Optional.of(DyeColor.CYAN), Optional.of(DyeColor.MAGENTA))))
|
||||||
|
put(Mixer(DyeColor.LIGHT_BLUE, immutableList(Optional.of(DyeColor.WHITE), Optional.of(DyeColor.BLUE))))
|
||||||
|
put(Mixer(DyeColor.LIME, immutableList(Optional.of(DyeColor.WHITE), Optional.of(DyeColor.GREEN))))
|
||||||
|
put(Mixer(DyeColor.ORANGE, immutableList(Optional.of(DyeColor.WHITE), Optional.of(DyeColor.RED), Optional.empty())))
|
||||||
|
put(Mixer(DyeColor.PURPLE, immutableList(Optional.of(DyeColor.CYAN), Optional.of(DyeColor.MAGENTA), Optional.empty())))
|
||||||
|
put(Mixer(DyeColor.BROWN, immutableList(Optional.of(DyeColor.YELLOW), Optional.of(DyeColor.MAGENTA), Optional.of(DyeColor.BLACK), Optional.empty())))
|
||||||
|
put(Mixer(DyeColor.PINK, immutableList(Optional.of(DyeColor.YELLOW), Optional.of(DyeColor.MAGENTA), Optional.of(DyeColor.WHITE), Optional.empty())))
|
||||||
|
put(Mixer(DyeColor.GRAY, immutableList(Optional.of(DyeColor.WHITE), Optional.of(DyeColor.BLACK), Optional.empty())))
|
||||||
|
put(Mixer(DyeColor.LIGHT_GRAY, immutableList(Optional.of(DyeColor.WHITE), Optional.of(DyeColor.WHITE), Optional.of(DyeColor.BLACK), Optional.empty())))
|
||||||
}
|
}
|
||||||
|
|
||||||
const val MAX_STORAGE = 256
|
const val MAX_STORAGE = 256
|
||||||
const val HUE_PER_ITEM = 32
|
const val HUE_PER_ITEM = 32
|
||||||
|
const val MAX_WATER_STORAGE = 4_000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,11 +34,16 @@ import ru.dbotthepony.mc.otm.core.util.CreativeMenuItemComparator
|
|||||||
import ru.dbotthepony.mc.otm.menu.decorative.PainterMenu
|
import ru.dbotthepony.mc.otm.menu.decorative.PainterMenu
|
||||||
|
|
||||||
class PainterScreen(menu: PainterMenu, inventory: Inventory, title: Component) : MatteryScreen<PainterMenu>(menu, inventory, title) {
|
class PainterScreen(menu: PainterMenu, inventory: Inventory, title: Component) : MatteryScreen<PainterMenu>(menu, inventory, title) {
|
||||||
private inner class Bar(parent: EditablePanel<*>, val dye: DyeColor) : EditablePanel<PainterScreen>(this@PainterScreen, parent, width = 5f) {
|
private inner class Bar(parent: EditablePanel<*>, val dye: DyeColor?) : EditablePanel<PainterScreen>(this@PainterScreen, parent, width = 5f) {
|
||||||
init {
|
init {
|
||||||
dock = Dock.RIGHT
|
dock = Dock.RIGHT
|
||||||
dockLeft = 1f
|
dockLeft = 1f
|
||||||
tooltips.add(TranslatableComponent("item.minecraft.${dye.getName()}_dye"))
|
|
||||||
|
if (dye == null)
|
||||||
|
tooltips.add(TranslatableComponent("block.minecraft.water"))
|
||||||
|
else
|
||||||
|
tooltips.add(TranslatableComponent("item.minecraft.${dye.getName() ?: "water"}_dye"))
|
||||||
|
|
||||||
tooltips.add(TextComponent(""))
|
tooltips.add(TextComponent(""))
|
||||||
tooltips.add(TextComponent(""))
|
tooltips.add(TextComponent(""))
|
||||||
}
|
}
|
||||||
@ -46,10 +51,10 @@ class PainterScreen(menu: PainterMenu, inventory: Inventory, title: Component) :
|
|||||||
override fun innerRender(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
|
override fun innerRender(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
|
||||||
graphics.renderRect(0f, 0f, width, height, color = RGBAColor.DARK_GRAY)
|
graphics.renderRect(0f, 0f, width, height, color = RGBAColor.DARK_GRAY)
|
||||||
|
|
||||||
val color = RGBAColor.rgb(dye.textColor)
|
val color = RGBAColor.rgb(dye?.textColor ?: DyeColor.LIGHT_BLUE.textColor)
|
||||||
graphics.renderRect(0f, 0f, width, height, color = color.copy(alpha = 0.4f))
|
graphics.renderRect(0f, 0f, width, height, color = color.copy(alpha = 0.4f))
|
||||||
|
|
||||||
val multiplier = menu.dyeStoredDirect[dye]!!.toFloat() / PainterBlockEntity.MAX_STORAGE.toFloat()
|
val multiplier = menu.dyeStoredDirect[dye]!!.toFloat() / (if (dye == null) PainterBlockEntity.MAX_WATER_STORAGE.toFloat() else PainterBlockEntity.MAX_STORAGE.toFloat())
|
||||||
graphics.renderRect(0f, height * (1f - multiplier), width, height * multiplier, color = color)
|
graphics.renderRect(0f, height * (1f - multiplier), width, height * multiplier, color = color)
|
||||||
|
|
||||||
tooltips[tooltips.size - 1] = TextComponent("${menu.dyeStoredDirect[dye]} (${(multiplier * 100f).toInt()}%)")
|
tooltips[tooltips.size - 1] = TextComponent("${menu.dyeStoredDirect[dye]} (${(multiplier * 100f).toInt()}%)")
|
||||||
@ -68,10 +73,12 @@ class PainterScreen(menu: PainterMenu, inventory: Inventory, title: Component) :
|
|||||||
it.dockTop = 4f
|
it.dockTop = 4f
|
||||||
}
|
}
|
||||||
|
|
||||||
EditablePanel(this, frame, width = 6f * DyeColor.entries.size / 2f).also {
|
EditablePanel(this, frame, width = 6f * (DyeColor.entries.size / 2f + 1f)).also {
|
||||||
it.dock = Dock.RIGHT
|
it.dock = Dock.RIGHT
|
||||||
it.dockLeft = 4f
|
it.dockLeft = 4f
|
||||||
|
|
||||||
|
Bar(it, null).childrenOrder = -1000
|
||||||
|
|
||||||
EditablePanel(this, it, height = 46f).also {
|
EditablePanel(this, it, height = 46f).also {
|
||||||
it.dock = Dock.TOP
|
it.dock = Dock.TOP
|
||||||
|
|
||||||
@ -141,10 +148,17 @@ class PainterScreen(menu: PainterMenu, inventory: Inventory, title: Component) :
|
|||||||
recipe.value.dyes.forEach {
|
recipe.value.dyes.forEach {
|
||||||
val (dye, amount) = it
|
val (dye, amount) = it
|
||||||
|
|
||||||
if (amount == 1)
|
if (dye == null) {
|
||||||
list.add(TranslatableComponent("otm.gui.needs", TranslatableComponent("item.minecraft.${dye.getName()}_dye")))
|
if (amount == 1)
|
||||||
else if (amount > 1)
|
list.add(TranslatableComponent("otm.gui.needs", TranslatableComponent("block.minecraft.water")))
|
||||||
list.add(TranslatableComponent("otm.gui.needs_x", TranslatableComponent("item.minecraft.${dye.getName()}_dye"), amount))
|
else if (amount > 1)
|
||||||
|
list.add(TranslatableComponent("otm.gui.needs_x", TranslatableComponent("block.minecraft.water"), amount))
|
||||||
|
} else {
|
||||||
|
if (amount == 1)
|
||||||
|
list.add(TranslatableComponent("otm.gui.needs", TranslatableComponent("item.minecraft.${dye.getName() ?: "water"}_dye")))
|
||||||
|
else if (amount > 1)
|
||||||
|
list.add(TranslatableComponent("otm.gui.needs_x", TranslatableComponent("item.minecraft.${dye.getName() ?: "water"}_dye"), amount))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
graphics.renderComponentTooltip(font, list, mouseX.toInt(), mouseY.toInt())
|
graphics.renderComponentTooltip(font, list, mouseX.toInt(), mouseY.toInt())
|
||||||
|
@ -11,6 +11,7 @@ import net.minecraft.client.gui.GuiGraphics
|
|||||||
import net.minecraft.network.chat.Component
|
import net.minecraft.network.chat.Component
|
||||||
import net.minecraft.resources.ResourceLocation
|
import net.minecraft.resources.ResourceLocation
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import net.minecraft.world.item.Items
|
||||||
import net.minecraft.world.item.crafting.Ingredient
|
import net.minecraft.world.item.crafting.Ingredient
|
||||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||||
import ru.dbotthepony.mc.otm.client.render.ItemStackIcon
|
import ru.dbotthepony.mc.otm.client.render.ItemStackIcon
|
||||||
@ -55,7 +56,7 @@ object PainterRecipeCategory : IRecipeCategory<PainterRecipe>, IDrawable {
|
|||||||
|
|
||||||
for ((dye, count) in recipe.dyes) {
|
for ((dye, count) in recipe.dyes) {
|
||||||
builder.addSlot(RecipeIngredientRole.CATALYST, 1 + x * 18, 1 + y * 18)
|
builder.addSlot(RecipeIngredientRole.CATALYST, 1 + x * 18, 1 + y * 18)
|
||||||
.addIngredients(VanillaTypes.ITEM_STACK, Ingredient.of(dye.tag).items.map { it.copyWithCount(count) })
|
.addIngredients(VanillaTypes.ITEM_STACK, dye?.let { Ingredient.of(it.tag).items.map { it.copyWithCount(count) } } ?: listOf(ItemStack(Items.WATER_BUCKET, count)))
|
||||||
|
|
||||||
y++
|
y++
|
||||||
|
|
||||||
|
@ -6,6 +6,10 @@ import net.minecraft.world.entity.player.Player
|
|||||||
import net.minecraft.world.item.DyeColor
|
import net.minecraft.world.item.DyeColor
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.minecraft.world.item.crafting.RecipeHolder
|
import net.minecraft.world.item.crafting.RecipeHolder
|
||||||
|
import net.minecraft.world.level.material.Fluids
|
||||||
|
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
||||||
|
import net.minecraftforge.fluids.FluidStack
|
||||||
|
import net.minecraftforge.fluids.capability.IFluidHandler
|
||||||
import ru.dbotthepony.mc.otm.block.entity.decorative.PainterBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.decorative.PainterBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.capability.matteryPlayer
|
import ru.dbotthepony.mc.otm.capability.matteryPlayer
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||||
@ -15,6 +19,7 @@ import ru.dbotthepony.mc.otm.core.collect.SupplierMap
|
|||||||
import ru.dbotthepony.mc.otm.core.collect.filter
|
import ru.dbotthepony.mc.otm.core.collect.filter
|
||||||
import ru.dbotthepony.mc.otm.core.collect.find
|
import ru.dbotthepony.mc.otm.core.collect.find
|
||||||
import ru.dbotthepony.mc.otm.core.collect.maybe
|
import ru.dbotthepony.mc.otm.core.collect.maybe
|
||||||
|
import ru.dbotthepony.mc.otm.core.ifPresentK
|
||||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||||
import ru.dbotthepony.mc.otm.core.map
|
import ru.dbotthepony.mc.otm.core.map
|
||||||
import ru.dbotthepony.mc.otm.core.util.CreativeMenuItemComparator
|
import ru.dbotthepony.mc.otm.core.util.CreativeMenuItemComparator
|
||||||
@ -34,7 +39,7 @@ import kotlin.collections.ArrayList
|
|||||||
class PainterMenu(
|
class PainterMenu(
|
||||||
containerId: Int, inventory: Inventory, tile: PainterBlockEntity? = null
|
containerId: Int, inventory: Inventory, tile: PainterBlockEntity? = null
|
||||||
) : MatteryMenu(MMenus.PAINTER, containerId, inventory, tile) {
|
) : MatteryMenu(MMenus.PAINTER, containerId, inventory, tile) {
|
||||||
val dyeStored = DyeColor.entries.associateWith { dye ->
|
val dyeStored = (DyeColor.entries.toMutableList<DyeColor?>().also { it.add(0, null) }).associateWith { dye ->
|
||||||
mSynchronizer.ComputedIntField({ tile?.dyeStored(dye) ?: 0 }).also { it.addListener(IntConsumer { rescan() }) }
|
mSynchronizer.ComputedIntField({ tile?.dyeStored(dye) ?: 0 }).also { it.addListener(IntConsumer { rescan() }) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +100,11 @@ class PainterMenu(
|
|||||||
|
|
||||||
val dyeSlot = object : MatterySlot(tile?.dyeInput ?: SimpleContainer(1), 0) {
|
val dyeSlot = object : MatterySlot(tile?.dyeInput ?: SimpleContainer(1), 0) {
|
||||||
override fun mayPlace(itemStack: ItemStack): Boolean {
|
override fun mayPlace(itemStack: ItemStack): Boolean {
|
||||||
return super.mayPlace(itemStack) && (DyeColor.getColor(itemStack)?.let { dyeStoredDirect[it]!! + PainterBlockEntity.HUE_PER_ITEM <= PainterBlockEntity.MAX_STORAGE } ?: false)
|
return super.mayPlace(itemStack) && ((
|
||||||
|
itemStack.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).resolve().map {
|
||||||
|
dyeStoredDirect[null]!! < PainterBlockEntity.MAX_WATER_STORAGE && it.drain(FluidStack(Fluids.WATER, PainterBlockEntity.MAX_WATER_STORAGE - dyeStoredDirect[null]!!), IFluidHandler.FluidAction.SIMULATE).isNotEmpty
|
||||||
|
}.orElse(false)
|
||||||
|
) || (DyeColor.getColor(itemStack)?.let { dyeStoredDirect[it]!! + PainterBlockEntity.HUE_PER_ITEM <= PainterBlockEntity.MAX_STORAGE } ?: false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
package ru.dbotthepony.mc.otm.recipe
|
package ru.dbotthepony.mc.otm.recipe
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap
|
||||||
import com.mojang.serialization.Codec
|
import com.mojang.serialization.Codec
|
||||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2IntArrayMap
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2IntMap
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2IntMaps
|
||||||
import net.minecraft.core.NonNullList
|
import net.minecraft.core.NonNullList
|
||||||
import net.minecraft.core.RegistryAccess
|
import net.minecraft.core.RegistryAccess
|
||||||
import net.minecraft.data.recipes.FinishedRecipe
|
import net.minecraft.data.recipes.FinishedRecipe
|
||||||
import net.minecraft.resources.ResourceLocation
|
import net.minecraft.resources.ResourceLocation
|
||||||
|
import net.minecraft.util.StringRepresentable
|
||||||
import net.minecraft.world.Container
|
import net.minecraft.world.Container
|
||||||
import net.minecraft.world.item.DyeColor
|
import net.minecraft.world.item.DyeColor
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
@ -26,28 +31,32 @@ import ru.dbotthepony.mc.otm.registry.MItems
|
|||||||
import ru.dbotthepony.mc.otm.registry.MRecipes
|
import ru.dbotthepony.mc.otm.registry.MRecipes
|
||||||
import java.util.EnumMap
|
import java.util.EnumMap
|
||||||
import java.util.function.Predicate
|
import java.util.function.Predicate
|
||||||
|
import java.util.stream.Collector
|
||||||
|
import java.util.stream.Collectors
|
||||||
|
|
||||||
class PainterRecipe(
|
class PainterRecipe(
|
||||||
val input: Ingredient,
|
val input: Ingredient,
|
||||||
val output: ItemStack,
|
val output: ItemStack,
|
||||||
val dyes: Map<DyeColor, Int>
|
dyes: Map<out DyeColor?, Int>
|
||||||
) : Recipe<Container> {
|
) : Recipe<Container> {
|
||||||
constructor(
|
constructor(
|
||||||
input: Ingredient,
|
input: Ingredient,
|
||||||
output: ItemStack,
|
output: ItemStack,
|
||||||
dyes: Set<DyeColor>
|
dyes: Set<DyeColor?>
|
||||||
) : this(input, output, dyes.associateWith { 1 })
|
) : this(input, output, Object2IntArrayMap<DyeColor?>().also { map -> dyes.forEach { map[it] = 1 } })
|
||||||
|
|
||||||
fun canCraft(storedDyes: Map<DyeColor, Int>): Boolean {
|
val dyes: Object2IntMap<DyeColor?> = Object2IntMaps.unmodifiable(Object2IntArrayMap(dyes))
|
||||||
|
|
||||||
|
fun canCraft(storedDyes: Map<out DyeColor?, Int>): Boolean {
|
||||||
if (isIncomplete) return false
|
if (isIncomplete) return false
|
||||||
if (dyes.isEmpty() || dyes.values.none { it > 0 }) return true
|
if (dyes.isEmpty() || dyes.values.none { it > 0 }) return true
|
||||||
val copy = EnumMap(storedDyes)
|
val copy = Object2IntArrayMap(storedDyes)
|
||||||
|
|
||||||
for ((dye, amount) in dyes) {
|
for ((dye, amount) in dyes) {
|
||||||
for (i in 0 until amount) {
|
for (i in 0 until amount) {
|
||||||
PainterBlockEntity.mixer(dye).mix(copy)
|
if (dye != null) PainterBlockEntity.mixer(dye)?.mix(copy)
|
||||||
if (copy[dye]!! <= 0) return false
|
if (copy.getInt(dye) <= 0) return false
|
||||||
copy[dye] = copy[dye]!! - 1
|
copy[dye] = copy.getInt(dye) - 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,17 +118,43 @@ class PainterRecipe(
|
|||||||
return SERIALIZER.toFinished(this, id)
|
return SERIALIZER.toFinished(this, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum class DyeColorWrapper(val refName: String, val key: DyeColor?) : StringRepresentable {
|
||||||
|
WHITE("white", DyeColor.WHITE),
|
||||||
|
ORANGE("orange", DyeColor.ORANGE),
|
||||||
|
MAGENTA("magenta", DyeColor.MAGENTA),
|
||||||
|
LIGHT_BLUE("light_blue", DyeColor.LIGHT_BLUE),
|
||||||
|
YELLOW("yellow", DyeColor.YELLOW),
|
||||||
|
LIME("lime", DyeColor.LIME),
|
||||||
|
PINK("pink", DyeColor.PINK),
|
||||||
|
GRAY("gray", DyeColor.GRAY),
|
||||||
|
LIGHT_GRAY("light_gray", DyeColor.LIGHT_GRAY),
|
||||||
|
CYAN("cyan", DyeColor.CYAN),
|
||||||
|
PURPLE("purple", DyeColor.PURPLE),
|
||||||
|
BLUE("blue", DyeColor.BLUE),
|
||||||
|
BROWN("brown", DyeColor.BROWN),
|
||||||
|
GREEN("green", DyeColor.GREEN),
|
||||||
|
RED("red", DyeColor.RED),
|
||||||
|
BLACK("black", DyeColor.BLACK),
|
||||||
|
WATER("water", null);
|
||||||
|
|
||||||
|
override fun getSerializedName(): String {
|
||||||
|
return refName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
private val wrapperCodec = StringRepresentable.fromEnum(DyeColorWrapper::values)
|
||||||
|
|
||||||
val SERIALIZER = Codec2RecipeSerializer<PainterRecipe> { context ->
|
val SERIALIZER = Codec2RecipeSerializer<PainterRecipe> { context ->
|
||||||
RecordCodecBuilder.create {
|
RecordCodecBuilder.create {
|
||||||
it.group(
|
it.group(
|
||||||
context.ingredients.fieldOf("input").forGetter(PainterRecipe::input),
|
context.ingredients.fieldOf("input").forGetter(PainterRecipe::input),
|
||||||
ItemStack.CODEC.fieldOf("output").forGetter(PainterRecipe::output),
|
ItemStack.CODEC.fieldOf("output").forGetter(PainterRecipe::output),
|
||||||
PredicatedCodecList<Map<DyeColor, Int>>(
|
PredicatedCodecList<Map<DyeColorWrapper, Int>>(
|
||||||
DyeColor.CODEC.xmap({ mapOf(it to 1) }, { it.keys.first() }) to Predicate { it.keys.size == 1 && it.values.first() == 1 },
|
wrapperCodec.xmap({ mapOf(it to 1) }, { it.keys.first() }) to Predicate { it.keys.size == 1 && it.values.first() == 1 },
|
||||||
Codec.list(DyeColor.CODEC).xmap({ it.associateWith { 1 } }, { ArrayList(it.keys) }) to Predicate { it.values.all { it == 1 } },
|
Codec.list(wrapperCodec).xmap({ it.associateWith { 1 } }, { ArrayList(it.keys) }) to Predicate { it.values.all { it == 1 } },
|
||||||
Codec.unboundedMap(DyeColor.CODEC, Codec.INT.minRange(1)) to Predicate { true }
|
Codec.unboundedMap(wrapperCodec, Codec.INT.minRange(1)) to Predicate { true }
|
||||||
).fieldOf("dyes").forGetter(PainterRecipe::dyes),
|
).fieldOf("dyes").xmap({ it.mapKeys { it.key.key } }, { it.mapKeys { k -> DyeColorWrapper.entries.first { k.key == it.key } } }).forGetter(PainterRecipe::dyes),
|
||||||
).apply(it, ::PainterRecipe)
|
).apply(it, ::PainterRecipe)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user