combustible generator but no screen

This commit is contained in:
2026-04-13 23:07:02 +02:00
parent 407e0b44ac
commit 8d146fbd17
8 changed files with 220 additions and 24 deletions

View File

@@ -2,15 +2,11 @@ package org.neoflock.neocomputers.block
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.network.chat.ChatType import net.minecraft.network.chat.ChatType
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.OutgoingChatMessage import net.minecraft.network.chat.OutgoingChatMessage
import net.minecraft.network.chat.PlayerChatMessage import net.minecraft.network.chat.PlayerChatMessage
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.InteractionResult import net.minecraft.world.InteractionResult
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.TooltipFlag
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraft.world.level.block.entity.BlockEntity import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
@@ -25,7 +21,7 @@ class CapacitorEntity(pos: BlockPos, state: BlockState) : NodeBlockEntity(BlockE
val capacity: Long = 20000 val capacity: Long = 20000
override val node = object : Networking.Node() { override val node = object : Networking.Node() {
override fun getPowerRole() = PowerRole.PRODUCER override fun getPowerRole() = PowerRole.STORAGE
override fun getEnergy() = amountStored override fun getEnergy() = amountStored
override fun getEnergyCapacity() = capacity override fun getEnergyCapacity() = capacity
override fun giveEnergy(amount: Long): Long { override fun giveEnergy(amount: Long): Long {

View File

@@ -1,12 +1,23 @@
package org.neoflock.neocomputers.block package org.neoflock.neocomputers.block
import net.minecraft.client.resources.sounds.Sound
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.network.chat.ChatType
import net.minecraft.network.chat.OutgoingChatMessage
import net.minecraft.network.chat.PlayerChatMessage
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.InteractionResult
import net.minecraft.world.entity.player.Player
import net.minecraft.world.level.Level 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.EntityBlock
import net.minecraft.world.level.block.FurnaceBlock
import net.minecraft.world.level.block.entity.BlockEntity import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.entity.BlockEntityTicker import net.minecraft.world.level.block.entity.BlockEntityTicker
import net.minecraft.world.level.block.entity.BlockEntityType import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockBehaviour
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.phys.BlockHitResult
import org.neoflock.neocomputers.entity.BlockEntities import org.neoflock.neocomputers.entity.BlockEntities
import org.neoflock.neocomputers.entity.SolarGeneratorBlockEntity import org.neoflock.neocomputers.entity.SolarGeneratorBlockEntity
import org.neoflock.neocomputers.entity.CombustionGeneratorBlockEntity import org.neoflock.neocomputers.entity.CombustionGeneratorBlockEntity
@@ -30,7 +41,8 @@ class SolarGeneratorBlock : BaseBlock(), EntityBlock {
} }
} }
class CombustionGeneratorBlock : BaseBlock(), EntityBlock { // TODO: make it glow when burning
class CombustionGeneratorBlock : Block(BlockBehaviour.Properties.of()), EntityBlock {
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity { override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity {
return CombustionGeneratorBlockEntity(blockPos, blockState) return CombustionGeneratorBlockEntity(blockPos, blockState)
} }
@@ -43,8 +55,28 @@ class CombustionGeneratorBlock : BaseBlock(), EntityBlock {
return object : BlockEntityTicker<T> { return object : BlockEntityTicker<T> {
override fun tick(level: Level, blockPos: BlockPos, blockState: BlockState, blockEntity: T) { override fun tick(level: Level, blockPos: BlockPos, blockState: BlockState, blockEntity: T) {
if(blockEntity !is CombustionGeneratorBlockEntity) return; if(blockEntity !is CombustionGeneratorBlockEntity) return;
blockEntity.giveSolarPower(); blockEntity.burnFuelForEnergy();
} }
} }
} }
override fun useWithoutItem(
blockState: BlockState,
level: Level,
blockPos: BlockPos,
player: Player,
blockHitResult: BlockHitResult
): InteractionResult? {
if(!level.isClientSide()) {
val sp = player as ServerPlayer
val ent = level.getBlockEntity(blockPos, BlockEntities.COMBUSTGEN_ENTITY.get())
if(ent.isPresent) {
val bust = ent.get()
val fuel = bust.stacks[0]
val msg = PlayerChatMessage.system("${fuel.displayName.string} x ${fuel.count} (${bust.node.getEnergy()} / ${bust.node.getEnergyCapacity()} J)")
sp.sendChatMessage(OutgoingChatMessage.create(msg), false, ChatType.bind(ChatType.CHAT, player))
}
}
return InteractionResult.SUCCESS;
}
} }

View File

@@ -60,5 +60,6 @@ object BlockEntities {
fun registerPowerBlocks() { fun registerPowerBlocks() {
PowerManager.registerPowerBlockEntity(CAPACITOR_ENTITY.get()) PowerManager.registerPowerBlockEntity(CAPACITOR_ENTITY.get())
PowerManager.registerPowerBlockEntity(COMBUSTGEN_ENTITY.get())
} }
} }

View File

@@ -1,20 +1,72 @@
package org.neoflock.neocomputers.entity package org.neoflock.neocomputers.entity
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.world.level.block.entity.BlockEntity import net.minecraft.core.NonNullList
import net.minecraft.world.level.block.entity.BlockEntityType import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import org.neoflock.neocomputers.block.NodeBlockEntity import org.neoflock.neocomputers.block.NodeBlockEntity
import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.network.PowerRole
import org.neoflock.neocomputers.utils.GenericContainer
import org.neoflock.neocomputers.utils.ContainerUtils
import kotlin.math.min
class CombustionGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState) : BlockEntity(BlockEntities.COMBUSTGEN_ENTITY.get(), blockPos, blockState) { class CombustionGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState) : NodeBlockEntity(BlockEntities.COMBUSTGEN_ENTITY.get(), blockPos, blockState), GenericContainer {
val energyPerTick: Long = 50 val energyPerTick: Long = 50
fun giveSolarPower() { var energy: Long = 0
if(level?.isDay == true) { val maxEnergy: Long = 50000
val below = level?.getBlockEntity(blockPos.below()) var burningTimeRemaining: Int = 0
if(below is NodeBlockEntity) {
below.node.giveEnergy(energyPerTick) override val node = object : Networking.Node() {
} override fun getPowerRole() = PowerRole.GENERATOR
override fun getEnergy() = energy
override fun getEnergyCapacity() = maxEnergy
override fun withdrawEnergy(amount: Long): Long {
val taken = min(amount, energy)
energy -= taken
return taken
}
override fun giveEnergy(amount: Long): Long {
val given = min(amount, maxEnergy - energy)
energy += given
return given
} }
} }
val stacks: NonNullList<ItemStack> = NonNullList<ItemStack>.withSize(1, ItemStack.EMPTY)
override fun canPlaceItem(i: Int, itemStack: ItemStack): Boolean {
return ContainerUtils.isBurningFuel(itemStack)
}
override fun getItems(): NonNullList<ItemStack> = stacks
override fun stillValid(player: Player): Boolean {
return !this.isRemoved
}
fun burnFuelForEnergy() {
// TODO: give us a block state tag for active
// keep combusting and shi
if(burningTimeRemaining > 0) {
burningTimeRemaining--
node.giveEnergy(energyPerTick)
setChanged()
return
}
// no point
if(node.getEnergy() >= node.getEnergyCapacity()) return;
// :fire:
val fuel = stacks[0]
if(fuel.isEmpty) return
burningTimeRemaining = ContainerUtils.getBurningTime(fuel) ?: 0
fuel.count--
}
} }

View File

@@ -2,7 +2,6 @@ package org.neoflock.neocomputers.network
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import org.neoflock.neocomputers.NeoComputers import org.neoflock.neocomputers.NeoComputers
import java.lang.ref.WeakReference
import kotlin.math.min import kotlin.math.min
import kotlin.math.pow import kotlin.math.pow
import kotlin.math.sqrt import kotlin.math.sqrt
@@ -11,9 +10,12 @@ enum class PowerRole {
// consumes energy, wants to be fully charged // consumes energy, wants to be fully charged
// does not give energy to network nodes // does not give energy to network nodes
CONSUMER, CONSUMER,
// produces/stores energy, will not care to charge itself // stores energy, will not care to charge itself
// will happily give energy to network nodes // will happily give energy to network nodes
PRODUCER, STORAGE,
// only produces energy, thus obviously charges itself
// also happily gives energy
GENERATOR,
} }
object Networking { object Networking {
@@ -56,7 +58,7 @@ object Networking {
open fun withdrawEnergy(amount: Long): Long = 0 open fun withdrawEnergy(amount: Long): Long = 0
open fun getEnergyCapacity(): Long = 0 open fun getEnergyCapacity(): Long = 0
fun getChargerNodes(): Set<Node> = getReachable().filter { it.getPowerRole() == PowerRole.PRODUCER }.toSet() fun getChargerNodes(): Set<Node> = getReachable().filter { it.getPowerRole() != PowerRole.CONSUMER }.toSet()
fun totalEnergyInConnections(): Long = getChargerNodes().fold(0) { acc, node -> acc + node.getEnergy() } fun totalEnergyInConnections(): Long = getChargerNodes().fold(0) { acc, node -> acc + node.getEnergy() }
fun maxEnergyInConnections(): Long = getChargerNodes().fold(0) { acc, node -> acc + node.getEnergyCapacity() } fun maxEnergyInConnections(): Long = getChargerNodes().fold(0) { acc, node -> acc + node.getEnergyCapacity() }
@@ -78,6 +80,7 @@ object Networking {
return true return true
} }
// PLEASE only call if consumer, in the name of all that is holy
fun tryToChargeFully() { fun tryToChargeFully() {
var remaining = getEnergyCapacity() - getEnergy() var remaining = getEnergyCapacity() - getEnergy()
if(remaining <= 0) return if(remaining <= 0) return
@@ -95,8 +98,55 @@ object Networking {
} }
} }
// only call if storage
fun balanceStorage() {
for(battery in getReachable()) {
if(battery.getPowerRole() != PowerRole.STORAGE) continue
// its so if for example we have a battery with 2x the capacity
// we don't try to even the energy between them since that's just bad
// and might pointless delete energy over time
val capacityRatio = getEnergyCapacity().toDouble() / battery.getEnergyCapacity()
val meaningfulSurplus = (battery.getEnergy() * capacityRatio - getEnergy()).toLong()
if(meaningfulSurplus <= 0) {
// WE'RE greedy (or negligible surplus)? Do nothing
continue
}
// steal from this greedy mf
val toSteal = meaningfulSurplus / 2
if(toSteal == 0L) continue // broke storahh
val stolen = battery.withdrawEnergy(toSteal)
if(giveEnergy(stolen) < stolen) {
NeoComputers.LOGGER.warn("LOSING ENERGY IN NODE $this!!!! THIS IS REALLY BAD!!!")
}
}
}
// rob the generators
fun stealGeneratorPower() {
var remaining = getEnergyCapacity() - getEnergy()
for(generator in getReachable()) {
if(generator.getPowerRole() != PowerRole.GENERATOR) continue
// rob this mf
val robbed = generator.withdrawEnergy(remaining)
val taken = giveEnergy(robbed)
if(taken < robbed) {
NeoComputers.LOGGER.warn("energy caught being DELETED in the big 26")
}
remaining -= taken
}
}
open fun tick() { open fun tick() {
if(getPowerRole() == PowerRole.CONSUMER) tryToChargeFully() if(getPowerRole() == PowerRole.CONSUMER) tryToChargeFully()
if(getPowerRole() == PowerRole.STORAGE) {
stealGeneratorPower()
balanceStorage()
}
} }
// processes a received message // processes a received message
open fun received(message: Message) {} open fun received(message: Message) {}

View File

@@ -17,9 +17,10 @@ object PowerManager {
entity, dir -> object : EnergyStorage { entity, dir -> object : EnergyStorage {
override fun getAmount() = entity.node.getEnergy() override fun getAmount() = entity.node.getEnergy()
override fun getCapacity() = entity.node.getEnergyCapacity() override fun getCapacity() = entity.node.getEnergyCapacity()
override fun supportsExtraction() = entity.node.getPowerRole() == PowerRole.PRODUCER override fun supportsExtraction() = entity.node.getPowerRole() != PowerRole.CONSUMER
override fun supportsInsertion(): Boolean = entity.node.getEnergyCapacity() > 0 override fun supportsInsertion() = entity.node.getPowerRole() != PowerRole.GENERATOR
override fun extract(maxAmount: Long, transaction: TransactionContext?): Long { override fun extract(maxAmount: Long, transaction: TransactionContext?): Long {
if(entity.node.getPowerRole() == PowerRole.CONSUMER) return 0
val taken = entity.node.withdrawEnergy(maxAmount) val taken = entity.node.withdrawEnergy(maxAmount)
transaction?.addCloseCallback { transaction?.addCloseCallback {
ctx, res -> if(res.wasAborted() || !res.wasCommitted()) entity.node.giveEnergy(taken) ctx, res -> if(res.wasAborted() || !res.wasCommitted()) entity.node.giveEnergy(taken)
@@ -27,9 +28,10 @@ object PowerManager {
return taken return taken
} }
override fun insert(maxAmount: Long, transaction: TransactionContext?): Long { override fun insert(maxAmount: Long, transaction: TransactionContext?): Long {
if(entity.node.getPowerRole() == PowerRole.GENERATOR) return 0
val given = entity.node.giveEnergy(maxAmount) val given = entity.node.giveEnergy(maxAmount)
transaction?.addCloseCallback { transaction?.addCloseCallback { ctx, res ->
ctx, res -> if(res.wasAborted() || !res.wasCommitted()) entity.node.withdrawEnergy(given) if (res.wasAborted() || !res.wasCommitted()) entity.node.withdrawEnergy(given)
} }
return given return given
} }

View File

@@ -0,0 +1,15 @@
package org.neoflock.neocomputers.utils
import dev.architectury.registry.fuel.FuelRegistry
import net.minecraft.world.item.ItemStack
// mewhenthe, aka e, will have me publicly executed for this code
object ContainerUtils {
fun getBurningTime(itemStack: ItemStack): Int? {
val time = FuelRegistry.get(itemStack)
if(time == 0) return null
return time
}
fun isBurningFuel(itemStack: ItemStack) = getBurningTime(itemStack) != null
}

View File

@@ -0,0 +1,48 @@
package org.neoflock.neocomputers.utils
// based off the ImplementedContainer of https://docs.fabricmc.net/develop/blocks/block-containers
import net.minecraft.world.Container;
import net.minecraft.core.NonNullList;
import net.minecraft.world.ContainerHelper
import net.minecraft.world.item.ItemStack
// Common container interface, assumes the entire purpose is purely raw item storage
interface GenericContainer : Container {
fun getItems(): NonNullList<ItemStack>
override fun getContainerSize(): Int {
return getItems().size
}
override fun isEmpty(): Boolean {
return getItems().all { it.isEmpty }
}
override fun getItem(i: Int): ItemStack {
return getItems()[i]
}
override fun removeItem(slot: Int, count: Int): ItemStack {
val res = ContainerHelper.removeItem(getItems(), slot, count)
if (!res.isEmpty) setChanged()
return res
}
override fun setItem(slot: Int, itemStack: ItemStack) {
getItems()[slot] = itemStack
// in case of bullshit
if(itemStack.count > itemStack.maxStackSize) {
// rip items
itemStack.count = itemStack.maxStackSize
}
}
override fun removeItemNoUpdate(i: Int): ItemStack {
return ContainerHelper.takeItem(getItems(), i)
}
override fun clearContent() {
getItems().clear()
}
}