synchronization and persistant state
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
package org.neoflock.neocomputers
|
package org.neoflock.neocomputers
|
||||||
|
|
||||||
import dev.architectury.event.events.client.ClientLifecycleEvent
|
import dev.architectury.event.events.client.ClientLifecycleEvent
|
||||||
|
import dev.architectury.event.events.common.PlayerEvent
|
||||||
import dev.architectury.event.events.common.TickEvent
|
import dev.architectury.event.events.common.TickEvent
|
||||||
|
import dev.architectury.networking.NetworkManager
|
||||||
import net.minecraft.resources.ResourceLocation
|
import net.minecraft.resources.ResourceLocation
|
||||||
import org.neoflock.neocomputers.block.Blocks
|
import org.neoflock.neocomputers.block.Blocks
|
||||||
import org.neoflock.neocomputers.entity.BlockEntities
|
import org.neoflock.neocomputers.entity.BlockEntities
|
||||||
@@ -10,10 +12,16 @@ import org.neoflock.neocomputers.gui.menu.Menus
|
|||||||
import org.neoflock.neocomputers.gui.screen.ScreenScreen
|
import org.neoflock.neocomputers.gui.screen.ScreenScreen
|
||||||
import dev.architectury.registry.menu.MenuRegistry
|
import dev.architectury.registry.menu.MenuRegistry
|
||||||
import net.minecraft.client.Minecraft
|
import net.minecraft.client.Minecraft
|
||||||
|
import net.minecraft.client.player.LocalPlayer
|
||||||
|
import net.minecraft.server.level.ServerPlayer
|
||||||
|
import org.neoflock.neocomputers.block.NodeBlock
|
||||||
|
import org.neoflock.neocomputers.block.NodeBlockEntity
|
||||||
|
import org.neoflock.neocomputers.block.NodeSynchronizer
|
||||||
import org.neoflock.neocomputers.item.Items
|
import org.neoflock.neocomputers.item.Items
|
||||||
import org.neoflock.neocomputers.item.Tabs
|
import org.neoflock.neocomputers.item.Tabs
|
||||||
import org.neoflock.neocomputers.network.Networking
|
import org.neoflock.neocomputers.network.Networking
|
||||||
import org.neoflock.neocomputers.utils.FontProvider
|
import org.neoflock.neocomputers.utils.FontProvider
|
||||||
|
import org.neoflock.neocomputers.utils.GenericContainerScreen
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
@@ -54,12 +62,40 @@ object NeoComputers {
|
|||||||
|
|
||||||
TickEvent.SERVER_POST.register {
|
TickEvent.SERVER_POST.register {
|
||||||
Networking.tickAllNodes()
|
Networking.tickAllNodes()
|
||||||
|
NodeSynchronizer.syncScreens()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PlayerEvent.CLOSE_MENU.register {
|
||||||
|
player, menu ->
|
||||||
|
if(player is ServerPlayer) NodeSynchronizer.playerScreenClosed(player)
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerEvent.PLAYER_QUIT.register {
|
||||||
|
player ->
|
||||||
|
NodeSynchronizer.playerScreenClosed(player)
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkManager.registerReceiver(NetworkManager.s2c(),NodeSynchronizer.StatePayload.TYPE, NodeSynchronizer.StatePayload.CODEC, {
|
||||||
|
packet, ctx ->
|
||||||
|
val level = ctx.player.level()
|
||||||
|
val ent = level.getBlockEntity(packet.blockPos)
|
||||||
|
if(ent is NodeBlockEntity) {
|
||||||
|
ent.syncWithUpstream(packet.buffer)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
NetworkManager.registerReceiver(NetworkManager.s2c(),NodeSynchronizer.ScreenPayload.TYPE, NodeSynchronizer.ScreenPayload.CODEC, {
|
||||||
|
packet, ctx ->
|
||||||
|
val scr = Minecraft.getInstance().screen
|
||||||
|
if(scr is GenericContainerScreen<*>) {
|
||||||
|
scr.processScreenStatePacket(packet.buffer)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
LOGGER.info("Registered!")
|
LOGGER.info("Registered!")
|
||||||
//LOGGER.info("Started mod in %s loader".formatted(NeoComputersInit.PLATFORM.getModloader()))
|
//LOGGER.info("Started mod in %s loader".formatted(NeoComputersInit.PLATFORM.getModloader()))
|
||||||
//LOGGER.info("Kotlin: %s".formatted(NeoComputers.hello()))
|
//LOGGER.info("Kotlin: %s".formatted(NeoComputers.hello()))
|
||||||
LOGGER.info("Started mod in ${NeoComputers.PLATFORM?.modloader} loader")
|
LOGGER.info("Started mod in ${PLATFORM?.modloader} loader")
|
||||||
LOGGER.info("Hello from kotlin!")
|
LOGGER.info("Hello from kotlin!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@ import org.neoflock.neocomputers.NeoComputers
|
|||||||
import java.util.function.Supplier
|
import java.util.function.Supplier
|
||||||
import com.google.common.base.Suppliers
|
import com.google.common.base.Suppliers
|
||||||
|
|
||||||
open class BaseBlock : Block(BlockBehaviour.Properties.of()) { // TODO: create a TieredBaseBlock class that extends this or something
|
open class BaseBlock(properties: Properties = Properties.of()) : Block(properties) { // TODO: create a TieredBaseBlock class that extends this or something
|
||||||
// val tier: Int
|
// val tier: Int
|
||||||
|
|
||||||
companion object Registry {
|
companion object Registry {
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package org.neoflock.neocomputers.block
|
package org.neoflock.neocomputers.block
|
||||||
|
|
||||||
|
import net.minecraft.client.player.LocalPlayer
|
||||||
import net.minecraft.core.BlockPos
|
import net.minecraft.core.BlockPos
|
||||||
|
import net.minecraft.core.HolderLookup
|
||||||
|
import net.minecraft.nbt.CompoundTag
|
||||||
import net.minecraft.network.chat.ChatType
|
import net.minecraft.network.chat.ChatType
|
||||||
import net.minecraft.network.chat.OutgoingChatMessage
|
import net.minecraft.network.chat.OutgoingChatMessage
|
||||||
import net.minecraft.network.chat.PlayerChatMessage
|
import net.minecraft.network.chat.PlayerChatMessage
|
||||||
@@ -19,23 +22,18 @@ import org.neoflock.neocomputers.network.PowerRole
|
|||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
open class CapacitorEntity(val capacity: Long, type: BlockEntityType<*>, pos: BlockPos, state: BlockState) : NodeBlockEntity(type, pos, state) {
|
open class CapacitorEntity(val capacity: Long, type: BlockEntityType<*>, pos: BlockPos, state: BlockState) : NodeBlockEntity(type, pos, state) {
|
||||||
var amountStored: Long = 0
|
|
||||||
|
|
||||||
override val node = object : Networking.Node() {
|
override val node = object : Networking.Node() {
|
||||||
override fun getPowerRole() = PowerRole.STORAGE
|
override var powerRole = PowerRole.STORAGE
|
||||||
override fun getEnergy() = amountStored
|
override var energyCapacity: Long = capacity
|
||||||
override fun getEnergyCapacity() = capacity
|
}
|
||||||
override fun giveEnergy(amount: Long): Long {
|
|
||||||
val given = min(amount, capacity - amountStored)
|
|
||||||
amountStored += given
|
|
||||||
return given
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun withdrawEnergy(amount: Long): Long {
|
override fun loadAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
|
||||||
val taken = min(amount, amountStored)
|
node.energy = min(compoundTag.getLong("energy"), node.energyCapacity)
|
||||||
amountStored -= taken
|
}
|
||||||
return taken
|
|
||||||
}
|
override fun saveAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
|
||||||
|
compoundTag.putLong("energy", node.energy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,15 +59,15 @@ class CapacitorBlock(val tier: Int) : NodeBlock() {
|
|||||||
player: Player,
|
player: Player,
|
||||||
blockHitResult: BlockHitResult
|
blockHitResult: BlockHitResult
|
||||||
): InteractionResult {
|
): InteractionResult {
|
||||||
if(!level.isClientSide()) {
|
if(level.isClientSide()) {
|
||||||
val sp = player as ServerPlayer
|
val p = player as LocalPlayer
|
||||||
val ent = level.getBlockEntity(blockPos)
|
val ent = level.getBlockEntity(blockPos)
|
||||||
if(ent is CapacitorEntity) {
|
if(ent is CapacitorEntity) {
|
||||||
if(sp.isCrouching) ent.amountStored++
|
if(p.isCrouching) ent.node.giveEnergy(1)
|
||||||
val msg = PlayerChatMessage.system("energy: ${ent.amountStored} / ${ent.capacity} (${ent.computeEdges().size} edges, ${ent.node.getReachable().size} connected)")
|
val msg = PlayerChatMessage.system("energy: ${ent.node.energy} / ${ent.capacity} (${ent.computeEdges().size} edges, ${ent.node.getReachable().size} connected)")
|
||||||
sp.sendChatMessage(OutgoingChatMessage.create(msg), false, ChatType.bind(ChatType.CHAT, player))
|
p.sendSystemMessage(OutgoingChatMessage.create(msg).content())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return InteractionResult.SUCCESS;
|
return InteractionResult.SUCCESS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,16 +2,30 @@ package org.neoflock.neocomputers.block
|
|||||||
|
|
||||||
import dev.architectury.registry.menu.MenuRegistry
|
import dev.architectury.registry.menu.MenuRegistry
|
||||||
import net.minecraft.core.BlockPos
|
import net.minecraft.core.BlockPos
|
||||||
|
import net.minecraft.core.particles.ParticleTypes
|
||||||
import net.minecraft.network.chat.ChatType
|
import net.minecraft.network.chat.ChatType
|
||||||
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.ServerLevel
|
||||||
import net.minecraft.server.level.ServerPlayer
|
import net.minecraft.server.level.ServerPlayer
|
||||||
|
import net.minecraft.sounds.SoundEvent
|
||||||
|
import net.minecraft.sounds.SoundEvents
|
||||||
|
import net.minecraft.sounds.SoundSource
|
||||||
|
import net.minecraft.util.RandomSource
|
||||||
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.ItemStack
|
||||||
|
import net.minecraft.world.level.BlockGetter
|
||||||
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.SoundType
|
||||||
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
|
||||||
|
import net.minecraft.world.level.block.state.StateDefinition
|
||||||
|
import net.minecraft.world.level.block.state.properties.BooleanProperty
|
||||||
|
import net.minecraft.world.level.storage.loot.LootParams
|
||||||
import net.minecraft.world.phys.BlockHitResult
|
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
|
||||||
@@ -22,7 +36,19 @@ class SolarGeneratorBlock : NodeBlock(), EntityBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: make it glow when burning
|
// TODO: make it glow when burning
|
||||||
class CombustionGeneratorBlock : NodeBlock(), EntityBlock {
|
class CombustionGeneratorBlock : NodeBlock, EntityBlock {
|
||||||
|
companion object {
|
||||||
|
val ACTIVE = BooleanProperty.create("active")
|
||||||
|
|
||||||
|
fun getLuminance(blockState: BlockState): Int {
|
||||||
|
return if(blockState.getValue(ACTIVE)) 5 else 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(): super(Properties.of().sound(SoundType.STONE).lightLevel(CombustionGeneratorBlock::getLuminance)) {
|
||||||
|
registerDefaultState(defaultBlockState().setValue(ACTIVE, false))
|
||||||
|
}
|
||||||
|
|
||||||
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity = CombustionGeneratorBlockEntity(blockPos, blockState).initNetworking()
|
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity = CombustionGeneratorBlockEntity(blockPos, blockState).initNetworking()
|
||||||
|
|
||||||
override fun useWithoutItem(
|
override fun useWithoutItem(
|
||||||
@@ -35,8 +61,25 @@ class CombustionGeneratorBlock : NodeBlock(), EntityBlock {
|
|||||||
if(!level.isClientSide()) {
|
if(!level.isClientSide()) {
|
||||||
val sp = player as ServerPlayer
|
val sp = player as ServerPlayer
|
||||||
val ent = level.getBlockEntity(blockPos, BlockEntities.COMBUSTGEN_ENTITY.get()).get()
|
val ent = level.getBlockEntity(blockPos, BlockEntities.COMBUSTGEN_ENTITY.get()).get()
|
||||||
|
NodeSynchronizer.registerPlayerScreen(sp, ent)
|
||||||
MenuRegistry.openMenu(sp, ent)
|
MenuRegistry.openMenu(sp, ent)
|
||||||
}
|
}
|
||||||
return InteractionResult.SUCCESS
|
return InteractionResult.SUCCESS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block?, BlockState?>) {
|
||||||
|
builder.add(ACTIVE)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun animateTick(blockState: BlockState, level: Level, blockPos: BlockPos, randomSource: RandomSource) {
|
||||||
|
if(blockState.getValue(ACTIVE)) {
|
||||||
|
if(randomSource.nextDouble() < 0.1) level.playSound(null, blockPos, SoundEvents.FURNACE_FIRE_CRACKLE, SoundSource.AMBIENT)
|
||||||
|
|
||||||
|
val x = blockPos.x.toDouble()
|
||||||
|
val y = blockPos.y.toDouble()
|
||||||
|
val z = blockPos.z.toDouble()
|
||||||
|
|
||||||
|
level.addParticle(ParticleTypes.SMOKE, x+0.5, y+0.5, z+0.5, 0.0, 0.0, 0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
package org.neoflock.neocomputers.block
|
package org.neoflock.neocomputers.block
|
||||||
|
|
||||||
|
import dev.architectury.networking.NetworkManager
|
||||||
|
import io.netty.buffer.Unpooled
|
||||||
import net.minecraft.core.BlockPos
|
import net.minecraft.core.BlockPos
|
||||||
|
import net.minecraft.network.FriendlyByteBuf
|
||||||
|
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||||
|
import net.minecraft.network.codec.StreamCodec
|
||||||
|
import net.minecraft.network.protocol.common.custom.CustomPacketPayload
|
||||||
|
import net.minecraft.resources.ResourceLocation
|
||||||
|
import net.minecraft.server.level.ServerLevel
|
||||||
|
import net.minecraft.server.level.ServerPlayer
|
||||||
|
|
||||||
import net.minecraft.world.entity.LivingEntity
|
import net.minecraft.world.entity.LivingEntity
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
@@ -11,8 +20,73 @@ 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.BlockState
|
import net.minecraft.world.level.block.state.BlockState
|
||||||
|
import org.neoflock.neocomputers.NeoComputers
|
||||||
import org.neoflock.neocomputers.network.Networking
|
import org.neoflock.neocomputers.network.Networking
|
||||||
|
|
||||||
|
object NodeSynchronizer {
|
||||||
|
class StatePayload(var blockPos: BlockPos, var buffer: FriendlyByteBuf): CustomPacketPayload {
|
||||||
|
companion object {
|
||||||
|
val NODE_SYNC_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "node_sync")
|
||||||
|
val TYPE = CustomPacketPayload.Type<StatePayload>(NODE_SYNC_ID)
|
||||||
|
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, StatePayload> {
|
||||||
|
override fun decode(buf: RegistryFriendlyByteBuf): StatePayload {
|
||||||
|
val blockPos = buf.readBlockPos()
|
||||||
|
val buffer = FriendlyByteBuf(buf.copy(buf.readerIndex(), buf.readableBytes()))
|
||||||
|
return StatePayload(blockPos, buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun encode(buf: RegistryFriendlyByteBuf, payload: StatePayload) {
|
||||||
|
buf.writeBlockPos(payload.blockPos)
|
||||||
|
buf.writeBytes(payload.buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun type() = TYPE
|
||||||
|
}
|
||||||
|
|
||||||
|
class ScreenPayload(var entityTypeWireID: String, var buffer: FriendlyByteBuf): CustomPacketPayload {
|
||||||
|
companion object {
|
||||||
|
val SCREEN_SYNC_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "screen_sync")
|
||||||
|
val TYPE = CustomPacketPayload.Type<ScreenPayload>(SCREEN_SYNC_ID)
|
||||||
|
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, ScreenPayload> {
|
||||||
|
override fun decode(buf: RegistryFriendlyByteBuf): ScreenPayload {
|
||||||
|
val id = buf.readByteArray().decodeToString()
|
||||||
|
val buffer = FriendlyByteBuf(buf.copy(buf.readerIndex(), buf.readableBytes()))
|
||||||
|
return ScreenPayload(id, buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun encode(buf: RegistryFriendlyByteBuf, payload: ScreenPayload) {
|
||||||
|
buf.writeByteArray(payload.entityTypeWireID.encodeToByteArray())
|
||||||
|
buf.writeBytes(payload.buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun type() = TYPE
|
||||||
|
}
|
||||||
|
|
||||||
|
val screenMap = mutableMapOf<ServerPlayer, NodeBlockEntity>()
|
||||||
|
|
||||||
|
fun playerScreenClosed(player: ServerPlayer) {
|
||||||
|
screenMap.remove(player)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun nodeTypeToWireID(nodeType: BlockEntityType<*>): String = nodeType.javaClass.canonicalName
|
||||||
|
|
||||||
|
fun registerPlayerScreen(player: ServerPlayer, entity: NodeBlockEntity) {
|
||||||
|
screenMap[player] = entity
|
||||||
|
}
|
||||||
|
|
||||||
|
fun syncScreens() {
|
||||||
|
for((player, ent) in screenMap) {
|
||||||
|
val buf = FriendlyByteBuf(Unpooled.buffer())
|
||||||
|
ent.encodeScreenData(player, buf)
|
||||||
|
NetworkManager.sendToPlayer(player, ScreenPayload(nodeTypeToWireID(ent.type), buf))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
abstract class NodeBlockEntity(blockEntityType: BlockEntityType<*>, blockPos: BlockPos, blockState: BlockState) : BlockEntity(blockEntityType, blockPos, blockState) {
|
abstract class NodeBlockEntity(blockEntityType: BlockEntityType<*>, blockPos: BlockPos, blockState: BlockState) : BlockEntity(blockEntityType, blockPos, blockState) {
|
||||||
abstract val node: Networking.Node
|
abstract val node: Networking.Node
|
||||||
|
|
||||||
@@ -21,6 +95,27 @@ abstract class NodeBlockEntity(blockEntityType: BlockEntityType<*>, blockPos: Bl
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// runs on the server, meant to encode state to send to all players
|
||||||
|
open fun encodeDownstreamData(packet: FriendlyByteBuf) {
|
||||||
|
packet.writeUUID(node.address)
|
||||||
|
packet.writeLong(node.energy)
|
||||||
|
packet.writeLong(node.energyCapacity)
|
||||||
|
packet.writeEnum(node.reachability)
|
||||||
|
packet.writeEnum(node.powerRole)
|
||||||
|
}
|
||||||
|
|
||||||
|
// runs on the client, meant to decode server state packets to synchronize client state
|
||||||
|
open fun syncWithUpstream(packet: FriendlyByteBuf) {
|
||||||
|
node.address = packet.readUUID()
|
||||||
|
node.energy = packet.readLong()
|
||||||
|
node.energyCapacity = packet.readLong()
|
||||||
|
node.reachability = packet.readEnum(node.reachability.javaClass)
|
||||||
|
node.powerRole = packet.readEnum(node.powerRole.javaClass)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encodes data meant for the associated screen of a player
|
||||||
|
open fun encodeScreenData(player: ServerPlayer, packet: FriendlyByteBuf) {}
|
||||||
|
|
||||||
private var stateIsDirty = true
|
private var stateIsDirty = true
|
||||||
|
|
||||||
open fun getNeighbourEntities(): List<BlockEntity> {
|
open fun getNeighbourEntities(): List<BlockEntity> {
|
||||||
@@ -36,7 +131,7 @@ abstract class NodeBlockEntity(blockEntityType: BlockEntityType<*>, blockPos: Bl
|
|||||||
return subpos.mapNotNull { pos -> level?.getBlockEntity(pos) }
|
return subpos.mapNotNull { pos -> level?.getBlockEntity(pos) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun computeEdges(): Set<NodeBlockEntity> {
|
open fun computeEdges(): Set<NodeBlockEntity> {
|
||||||
val s = mutableSetOf<NodeBlockEntity>()
|
val s = mutableSetOf<NodeBlockEntity>()
|
||||||
val neighbours = getNeighbourEntities()
|
val neighbours = getNeighbourEntities()
|
||||||
for(neighbour in neighbours) {
|
for(neighbour in neighbours) {
|
||||||
@@ -47,13 +142,21 @@ abstract class NodeBlockEntity(blockEntityType: BlockEntityType<*>, blockPos: Bl
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
fun invalidateNodeState() {
|
open fun invalidateNodeState() {
|
||||||
stateIsDirty = true
|
stateIsDirty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun needsSynchronization() = stateIsDirty
|
fun needsSynchronization() = stateIsDirty
|
||||||
|
|
||||||
open fun tickNode() {
|
open fun tickNode(level: Level) {
|
||||||
|
if(!level.isClientSide) {
|
||||||
|
val l = level as ServerLevel
|
||||||
|
val packetBuf = FriendlyByteBuf(Unpooled.buffer())
|
||||||
|
encodeDownstreamData(packetBuf)
|
||||||
|
l.players().forEach {
|
||||||
|
if(it.level().isLoaded(blockPos)) NetworkManager.sendToPlayer(it, NodeSynchronizer.StatePayload(blockPos, packetBuf))
|
||||||
|
}
|
||||||
|
}
|
||||||
if(!stateIsDirty) return
|
if(!stateIsDirty) return
|
||||||
stateIsDirty = false
|
stateIsDirty = false
|
||||||
computeEdges().forEach {
|
computeEdges().forEach {
|
||||||
@@ -73,7 +176,7 @@ abstract class NodeBlockEntity(blockEntityType: BlockEntityType<*>, blockPos: Bl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class NodeBlock: BaseBlock(), EntityBlock {
|
abstract class NodeBlock(properties: Properties = Properties.of()): BaseBlock(properties), EntityBlock {
|
||||||
override fun <T : BlockEntity> getTicker(
|
override fun <T : BlockEntity> getTicker(
|
||||||
level: Level,
|
level: Level,
|
||||||
blockState: BlockState,
|
blockState: BlockState,
|
||||||
@@ -82,7 +185,7 @@ abstract class NodeBlock: 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 NodeBlockEntity) return;
|
if(blockEntity !is NodeBlockEntity) return;
|
||||||
blockEntity.tickNode()
|
blockEntity.tickNode(level)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,32 +40,32 @@ class BullshitFix: DataFixType<Unit>() {
|
|||||||
object BlockEntities {
|
object BlockEntities {
|
||||||
val BLOCKENTITIES: DeferredRegister<BlockEntityType<*>> = DeferredRegister.create(NeoComputers.MODID, Registries.BLOCK_ENTITY_TYPE);
|
val BLOCKENTITIES: DeferredRegister<BlockEntityType<*>> = DeferredRegister.create(NeoComputers.MODID, Registries.BLOCK_ENTITY_TYPE);
|
||||||
|
|
||||||
val SCREEN_ENTITY: RegistrySupplier<BlockEntityType<ScreenEntity>> = BLOCKENTITIES.register("screen_entity") {
|
val SCREEN_ENTITY: RegistrySupplier<BlockEntityType<ScreenEntity>> = BLOCKENTITIES.register("screen") {
|
||||||
BlockEntityType(
|
BlockEntityType(
|
||||||
::ScreenEntity, mutableSetOf(Blocks.SCREEN_BLOCK.get()), BullshitFix()
|
::ScreenEntity, mutableSetOf(Blocks.SCREEN_BLOCK.get()), BullshitFix()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val CAPACITOR_ENTITY: RegistrySupplier<BlockEntityType<CapacitorEntityTier1>> = BLOCKENTITIES.register("capacitor_entity") {
|
val CAPACITOR_ENTITY: RegistrySupplier<BlockEntityType<CapacitorEntityTier1>> = BLOCKENTITIES.register("capacitor") {
|
||||||
BlockEntityType(
|
BlockEntityType(
|
||||||
::CapacitorEntityTier1, mutableSetOf(Blocks.CAPACITOR_BLOCK.get()), BullshitFix()
|
::CapacitorEntityTier1, mutableSetOf(Blocks.CAPACITOR_BLOCK.get()), BullshitFix()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val CAPACITOR2_ENTITY: RegistrySupplier<BlockEntityType<CapacitorEntityTier2>> = BLOCKENTITIES.register("capacitor_entity2") {
|
val CAPACITOR2_ENTITY: RegistrySupplier<BlockEntityType<CapacitorEntityTier2>> = BLOCKENTITIES.register("capacitor2") {
|
||||||
BlockEntityType(
|
BlockEntityType(
|
||||||
::CapacitorEntityTier2, mutableSetOf(Blocks.CAPACITOR_BLOCK2.get()), BullshitFix()
|
::CapacitorEntityTier2, mutableSetOf(Blocks.CAPACITOR_BLOCK2.get()), BullshitFix()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val CAPACITOR3_ENTITY: RegistrySupplier<BlockEntityType<CapacitorEntityTier3>> = BLOCKENTITIES.register("capacitor_entity3") {
|
val CAPACITOR3_ENTITY: RegistrySupplier<BlockEntityType<CapacitorEntityTier3>> = BLOCKENTITIES.register("capacitor3") {
|
||||||
BlockEntityType(
|
BlockEntityType(
|
||||||
::CapacitorEntityTier3, mutableSetOf(Blocks.CAPACITOR_BLOCK3.get()), BullshitFix()
|
::CapacitorEntityTier3, mutableSetOf(Blocks.CAPACITOR_BLOCK3.get()), BullshitFix()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val SOLARGEN_ENTITY: RegistrySupplier<BlockEntityType<SolarGeneratorBlockEntity>> = BLOCKENTITIES.register("solargen_entity") {
|
val SOLARGEN_ENTITY: RegistrySupplier<BlockEntityType<SolarGeneratorBlockEntity>> = BLOCKENTITIES.register("solargen") {
|
||||||
BlockEntityType(
|
BlockEntityType(
|
||||||
::SolarGeneratorBlockEntity, mutableSetOf(Blocks.SOLARGEN_BLOCK.get()), BullshitFix()
|
::SolarGeneratorBlockEntity, mutableSetOf(Blocks.SOLARGEN_BLOCK.get()), BullshitFix()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val COMBUSTGEN_ENTITY: RegistrySupplier<BlockEntityType<CombustionGeneratorBlockEntity>> = BLOCKENTITIES.register("combustgen_entity") {
|
val COMBUSTGEN_ENTITY: RegistrySupplier<BlockEntityType<CombustionGeneratorBlockEntity>> = BLOCKENTITIES.register("combustgen") {
|
||||||
BlockEntityType(
|
BlockEntityType(
|
||||||
::CombustionGeneratorBlockEntity, mutableSetOf(Blocks.COMBUSTGEN_BLOCK.get()), BullshitFix()
|
::CombustionGeneratorBlockEntity, mutableSetOf(Blocks.COMBUSTGEN_BLOCK.get()), BullshitFix()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,14 +1,24 @@
|
|||||||
package org.neoflock.neocomputers.entity
|
package org.neoflock.neocomputers.entity
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos
|
import net.minecraft.core.BlockPos
|
||||||
|
import net.minecraft.core.HolderLookup
|
||||||
import net.minecraft.core.NonNullList
|
import net.minecraft.core.NonNullList
|
||||||
|
import net.minecraft.nbt.CompoundTag
|
||||||
|
import net.minecraft.network.FriendlyByteBuf
|
||||||
|
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||||
import net.minecraft.network.chat.Component
|
import net.minecraft.network.chat.Component
|
||||||
|
import net.minecraft.server.level.ServerPlayer
|
||||||
|
import net.minecraft.sounds.SoundEvents
|
||||||
|
import net.minecraft.sounds.SoundSource
|
||||||
import net.minecraft.world.MenuProvider
|
import net.minecraft.world.MenuProvider
|
||||||
import net.minecraft.world.entity.player.Inventory
|
import net.minecraft.world.entity.player.Inventory
|
||||||
import net.minecraft.world.entity.player.Player
|
import net.minecraft.world.entity.player.Player
|
||||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import net.minecraft.world.level.Level
|
||||||
|
import net.minecraft.world.level.block.FurnaceBlock
|
||||||
import net.minecraft.world.level.block.state.BlockState
|
import net.minecraft.world.level.block.state.BlockState
|
||||||
|
import org.neoflock.neocomputers.block.CombustionGeneratorBlock
|
||||||
import org.neoflock.neocomputers.block.NodeBlockEntity
|
import org.neoflock.neocomputers.block.NodeBlockEntity
|
||||||
import org.neoflock.neocomputers.gui.menu.CombustionGeneratorMenu
|
import org.neoflock.neocomputers.gui.menu.CombustionGeneratorMenu
|
||||||
import org.neoflock.neocomputers.network.Networking
|
import org.neoflock.neocomputers.network.Networking
|
||||||
@@ -20,25 +30,11 @@ import kotlin.math.min
|
|||||||
class CombustionGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState) : NodeBlockEntity(BlockEntities.COMBUSTGEN_ENTITY.get(), blockPos, blockState), GenericContainer, MenuProvider {
|
class CombustionGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState) : NodeBlockEntity(BlockEntities.COMBUSTGEN_ENTITY.get(), blockPos, blockState), GenericContainer, MenuProvider {
|
||||||
val energyPerTick: Long = 50
|
val energyPerTick: Long = 50
|
||||||
|
|
||||||
var energy: Long = 0
|
|
||||||
val maxEnergy: Long = 100000
|
|
||||||
var burningTimeRemaining: Int = 0
|
var burningTimeRemaining: Int = 0
|
||||||
|
|
||||||
override val node = object : Networking.Node() {
|
override val node = object : Networking.Node() {
|
||||||
override fun getPowerRole() = PowerRole.GENERATOR
|
override var powerRole = PowerRole.GENERATOR
|
||||||
override fun getEnergy() = energy
|
override var energyCapacity: Long = 100000
|
||||||
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)
|
val stacks: NonNullList<ItemStack> = NonNullList<ItemStack>.withSize(1, ItemStack.EMPTY)
|
||||||
@@ -53,8 +49,8 @@ class CombustionGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
|||||||
return !this.isRemoved
|
return !this.isRemoved
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tickNode() {
|
override fun tickNode(level: Level) {
|
||||||
super.tickNode()
|
super.tickNode(level)
|
||||||
// TODO: give us a block state tag for active
|
// TODO: give us a block state tag for active
|
||||||
|
|
||||||
// keep combusting and shi
|
// keep combusting and shi
|
||||||
@@ -66,17 +62,38 @@ class CombustionGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// no point
|
// no point
|
||||||
if(node.getEnergy() >= node.getEnergyCapacity()) return;
|
if(node.energy >= node.energyCapacity) return;
|
||||||
|
|
||||||
// :fire:
|
// :fire:
|
||||||
val fuel = stacks[0]
|
val fuel = stacks[0]
|
||||||
if(fuel.isEmpty) return
|
if(fuel.isEmpty) return
|
||||||
|
|
||||||
burningTimeRemaining = ContainerUtils.getBurningTime(fuel) ?: 0
|
burningTimeRemaining = ContainerUtils.getBurningTime(fuel) ?: 0
|
||||||
|
setChanged()
|
||||||
fuel.count--
|
fuel.count--
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getDisplayName(): Component? = Component.translatable("block.neocomputers.combustgen")
|
override fun getDisplayName(): Component? = Component.translatable("block.neocomputers.combustgen")
|
||||||
|
|
||||||
override fun createMenu(i: Int, inventory: Inventory, player: Player) = CombustionGeneratorMenu(i, inventory, this)
|
override fun createMenu(i: Int, inventory: Inventory, player: Player) = CombustionGeneratorMenu(i, inventory, this)
|
||||||
|
|
||||||
|
override fun setChanged() {
|
||||||
|
super.setChanged()
|
||||||
|
level?.setBlockAndUpdate(blockPos, blockState.setValue(CombustionGeneratorBlock.ACTIVE, burningTimeRemaining > 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun encodeScreenData(player: ServerPlayer, packet: FriendlyByteBuf) {
|
||||||
|
packet.writeLong(node.energy)
|
||||||
|
packet.writeLong(node.energyCapacity)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun loadAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
|
||||||
|
node.energy = min(node.energyCapacity, compoundTag.getLong("energy"))
|
||||||
|
burningTimeRemaining = compoundTag.getInt("burningTimeRemaining")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun saveAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
|
||||||
|
compoundTag.putLong("energy", node.energy)
|
||||||
|
compoundTag.putInt("burningTimeRemaining", burningTimeRemaining)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,38 +1,35 @@
|
|||||||
package org.neoflock.neocomputers.entity
|
package org.neoflock.neocomputers.entity
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos
|
import net.minecraft.core.BlockPos
|
||||||
|
import net.minecraft.core.HolderLookup
|
||||||
|
import net.minecraft.nbt.CompoundTag
|
||||||
|
import net.minecraft.world.level.Level
|
||||||
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.Networking
|
||||||
import org.neoflock.neocomputers.network.PowerRole
|
import org.neoflock.neocomputers.network.PowerRole
|
||||||
import kotlin.math.min
|
|
||||||
|
|
||||||
class SolarGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState) : NodeBlockEntity(BlockEntities.SOLARGEN_ENTITY.get(), blockPos, blockState) {
|
class SolarGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState) : NodeBlockEntity(BlockEntities.SOLARGEN_ENTITY.get(), blockPos, blockState) {
|
||||||
val energyPerTick: Long = 50
|
val energyPerTick: Long = 50
|
||||||
var energyStored: Long = 0
|
|
||||||
val capacity: Long = 50000
|
|
||||||
|
|
||||||
override val node = object : Networking.Node() {
|
override val node = object : Networking.Node() {
|
||||||
override fun getPowerRole(): PowerRole = PowerRole.GENERATOR
|
override var powerRole: PowerRole = PowerRole.GENERATOR
|
||||||
override fun getEnergy(): Long = energyStored
|
override var energyCapacity: Long = 50000
|
||||||
override fun getEnergyCapacity(): Long = capacity
|
|
||||||
override fun giveEnergy(amount: Long): Long {
|
|
||||||
val taken = min(amount, capacity - energyStored)
|
|
||||||
energyStored += taken
|
|
||||||
return taken
|
|
||||||
}
|
|
||||||
override fun withdrawEnergy(amount: Long): Long {
|
|
||||||
val taken = min(amount, energyStored)
|
|
||||||
energyStored -= taken
|
|
||||||
return taken
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tickNode() {
|
override fun tickNode(level: Level) {
|
||||||
super.tickNode()
|
super.tickNode(level)
|
||||||
val l = level ?: return
|
val l = level ?: return
|
||||||
if(l.isDay) {
|
if(l.isDay) {
|
||||||
node.giveEnergy(energyPerTick)
|
node.giveEnergy(energyPerTick)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun loadAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
|
||||||
|
node.energy = compoundTag.getLong("energy")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun saveAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
|
||||||
|
compoundTag.putLong("energy", node.energy)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,21 @@
|
|||||||
package org.neoflock.neocomputers.gui.screen
|
package org.neoflock.neocomputers.gui.screen
|
||||||
|
|
||||||
import net.minecraft.client.gui.GuiGraphics
|
import net.minecraft.client.gui.GuiGraphics
|
||||||
|
import net.minecraft.network.FriendlyByteBuf
|
||||||
|
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||||
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.entity.player.Inventory
|
import net.minecraft.world.entity.player.Inventory
|
||||||
import org.neoflock.neocomputers.NeoComputers
|
import org.neoflock.neocomputers.entity.BlockEntities
|
||||||
import org.neoflock.neocomputers.gui.menu.CombustionGeneratorMenu
|
import org.neoflock.neocomputers.gui.menu.CombustionGeneratorMenu
|
||||||
import org.neoflock.neocomputers.utils.GenericContainerScreen
|
import org.neoflock.neocomputers.utils.GenericContainerScreen
|
||||||
|
|
||||||
class CombustionGeneratorScreen(abstractContainerMenu: CombustionGeneratorMenu, inventory: Inventory, component: Component) : GenericContainerScreen<CombustionGeneratorMenu>(abstractContainerMenu, inventory, component) {
|
class CombustionGeneratorScreen(abstractContainerMenu: CombustionGeneratorMenu, inventory: Inventory, component: Component) : GenericContainerScreen<CombustionGeneratorMenu>(abstractContainerMenu, inventory, component) {
|
||||||
override fun findMenuTexture(): ResourceLocation = ResourceLocation.withDefaultNamespace("textures/gui/container/dispenser.png")
|
override fun findMenuTexture(): ResourceLocation = ResourceLocation.withDefaultNamespace("textures/gui/container/dispenser.png")
|
||||||
|
|
||||||
|
var energy: Long = 0
|
||||||
|
var energyCapacity: Long = 1
|
||||||
|
|
||||||
override fun render(graphics: GuiGraphics, mouseX: Int, mouseY: Int, something: Float) {
|
override fun render(graphics: GuiGraphics, mouseX: Int, mouseY: Int, something: Float) {
|
||||||
super.render(graphics, mouseX, mouseY, something)
|
super.render(graphics, mouseX, mouseY, something)
|
||||||
|
|
||||||
@@ -21,9 +26,16 @@ class CombustionGeneratorScreen(abstractContainerMenu: CombustionGeneratorMenu,
|
|||||||
val lineY = imageY + 6
|
val lineY = imageY + 6
|
||||||
val lineHeight = 60
|
val lineHeight = 60
|
||||||
|
|
||||||
val power = 0.2
|
val power = energy.toDouble() / energyCapacity
|
||||||
|
|
||||||
graphics.fill(lineX, lineY, lineX + 2, lineY + lineHeight, lineFg)
|
graphics.fill(lineX, lineY, lineX + 2, lineY + lineHeight, lineFg)
|
||||||
graphics.fill(lineX, lineY, lineX + 2, lineY + (lineHeight * (1.0 - power)).toInt(), lineBg)
|
graphics.fill(lineX, lineY, lineX + 2, lineY + (lineHeight * (1.0 - power)).toInt(), lineBg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getBoundBlockEntityType() = setOf(BlockEntities.COMBUSTGEN_ENTITY.get())
|
||||||
|
|
||||||
|
override fun processScreenStatePacket(buf: FriendlyByteBuf) {
|
||||||
|
energy = buf.readLong()
|
||||||
|
energyCapacity = buf.readLong()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@ 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.util.UUID
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
import kotlin.math.sqrt
|
import kotlin.math.sqrt
|
||||||
@@ -46,26 +47,35 @@ object Networking {
|
|||||||
open class Node {
|
open class Node {
|
||||||
val connections = mutableSetOf<Node>()
|
val connections = mutableSetOf<Node>()
|
||||||
private var reachableCache: Set<Node>? = null
|
private var reachableCache: Set<Node>? = null
|
||||||
|
open var address = UUID.randomUUID()
|
||||||
|
|
||||||
open fun getReachability() = Visibility.NETWORK
|
open var reachability = Visibility.NETWORK
|
||||||
open fun getPowerRole() = PowerRole.CONSUMER
|
open var powerRole = PowerRole.CONSUMER
|
||||||
open fun getEnergy(): Long = 0
|
open var energy: Long = 0
|
||||||
|
open var energyCapacity: Long = 0
|
||||||
// give energy, returns how much was actually given
|
// give energy, returns how much was actually given
|
||||||
// cannot exceed amount specified
|
// cannot exceed amount specified
|
||||||
open fun giveEnergy(amount: Long): Long = 0
|
open fun giveEnergy(amount: Long): Long {
|
||||||
|
val maximum = min(amount, energyCapacity - energy)
|
||||||
|
energy += maximum
|
||||||
|
return maximum
|
||||||
|
}
|
||||||
// take energy out, returns how much was actually taken
|
// take energy out, returns how much was actually taken
|
||||||
// cannot exceed amount specified
|
// cannot exceed amount specified
|
||||||
open fun withdrawEnergy(amount: Long): Long = 0
|
open fun withdrawEnergy(amount: Long): Long {
|
||||||
|
val maximum = min(amount, energy)
|
||||||
|
energy -= maximum
|
||||||
|
return maximum
|
||||||
|
}
|
||||||
|
|
||||||
open fun getEnergyCapacity(): Long = 0
|
fun getChargerNodes(): Set<Node> = getReachable().filter { it.powerRole != PowerRole.CONSUMER }.toSet()
|
||||||
fun getChargerNodes(): Set<Node> = getReachable().filter { it.getPowerRole() != PowerRole.CONSUMER }.toSet()
|
fun totalEnergyInConnections(): Long = getChargerNodes().fold(0) { acc, node -> acc + node.energy }
|
||||||
fun totalEnergyInConnections(): Long = getChargerNodes().fold(0) { acc, node -> acc + node.getEnergy() }
|
fun maxEnergyInConnections(): Long = getChargerNodes().fold(0) { acc, node -> acc + node.energyCapacity }
|
||||||
fun maxEnergyInConnections(): Long = getChargerNodes().fold(0) { acc, node -> acc + node.getEnergyCapacity() }
|
|
||||||
|
|
||||||
// attempts to consume
|
// attempts to consume
|
||||||
fun consumeEnergy(energy: Long): Boolean {
|
fun consumeEnergy(energy: Long): Boolean {
|
||||||
// consumes energy, returns false if not enough
|
// consumes energy, returns false if not enough
|
||||||
val total = totalEnergyInConnections() + getEnergy()
|
val total = totalEnergyInConnections() + this.energy
|
||||||
if(energy > total) return false
|
if(energy > total) return false
|
||||||
|
|
||||||
var remaining = energy
|
var remaining = energy
|
||||||
@@ -82,7 +92,7 @@ object Networking {
|
|||||||
|
|
||||||
// PLEASE only call if consumer, in the name of all that is holy
|
// PLEASE only call if consumer, in the name of all that is holy
|
||||||
fun tryToChargeFully() {
|
fun tryToChargeFully() {
|
||||||
var remaining = getEnergyCapacity() - getEnergy()
|
var remaining = energyCapacity - energy
|
||||||
if(remaining <= 0) return
|
if(remaining <= 0) return
|
||||||
for (charger in getChargerNodes()) {
|
for (charger in getChargerNodes()) {
|
||||||
if(remaining <= 0) break
|
if(remaining <= 0) break
|
||||||
@@ -101,13 +111,13 @@ object Networking {
|
|||||||
// only call if storage
|
// only call if storage
|
||||||
fun balanceStorage() {
|
fun balanceStorage() {
|
||||||
for(battery in getReachable()) {
|
for(battery in getReachable()) {
|
||||||
if(battery.getPowerRole() != PowerRole.STORAGE) continue
|
if(battery.powerRole != PowerRole.STORAGE) continue
|
||||||
// its so if for example we have a battery with 2x the capacity
|
// 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
|
// we don't try to even the energy between them since that's just bad
|
||||||
// and might pointless delete energy over time
|
// and might pointless delete energy over time
|
||||||
val capacityRatio = getEnergyCapacity().toDouble() / battery.getEnergyCapacity()
|
val capacityRatio = energyCapacity.toDouble() / battery.energyCapacity
|
||||||
|
|
||||||
val meaningfulSurplus = (battery.getEnergy() * capacityRatio - getEnergy()).toLong()
|
val meaningfulSurplus = (battery.energy * capacityRatio - energy).toLong()
|
||||||
|
|
||||||
if(meaningfulSurplus <= 0) {
|
if(meaningfulSurplus <= 0) {
|
||||||
// WE'RE greedy (or negligible surplus)? Do nothing
|
// WE'RE greedy (or negligible surplus)? Do nothing
|
||||||
@@ -127,10 +137,10 @@ object Networking {
|
|||||||
|
|
||||||
// rob the generators
|
// rob the generators
|
||||||
fun stealGeneratorPower() {
|
fun stealGeneratorPower() {
|
||||||
var remaining = getEnergyCapacity() - getEnergy()
|
var remaining = energyCapacity - energy
|
||||||
|
|
||||||
for(generator in getReachable()) {
|
for(generator in getReachable()) {
|
||||||
if(generator.getPowerRole() != PowerRole.GENERATOR) continue
|
if(generator.powerRole != PowerRole.GENERATOR) continue
|
||||||
// rob this mf
|
// rob this mf
|
||||||
val robbed = generator.withdrawEnergy(remaining)
|
val robbed = generator.withdrawEnergy(remaining)
|
||||||
val taken = giveEnergy(robbed)
|
val taken = giveEnergy(robbed)
|
||||||
@@ -142,8 +152,8 @@ object Networking {
|
|||||||
}
|
}
|
||||||
|
|
||||||
open fun tick() {
|
open fun tick() {
|
||||||
if(getPowerRole() == PowerRole.CONSUMER) tryToChargeFully()
|
if(powerRole == PowerRole.CONSUMER) tryToChargeFully()
|
||||||
if(getPowerRole() == PowerRole.STORAGE) {
|
if(powerRole == PowerRole.STORAGE) {
|
||||||
stealGeneratorPower()
|
stealGeneratorPower()
|
||||||
balanceStorage()
|
balanceStorage()
|
||||||
}
|
}
|
||||||
@@ -178,7 +188,6 @@ object Networking {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun computeReachable(): Set<Node> {
|
fun computeReachable(): Set<Node> {
|
||||||
val reachability = getReachability()
|
|
||||||
if(reachability == Visibility.NONE) {
|
if(reachability == Visibility.NONE) {
|
||||||
return setOf();
|
return setOf();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,12 +15,12 @@ object PowerManager {
|
|||||||
//? if fabric {
|
//? if fabric {
|
||||||
EnergyStorage.SIDED.registerForBlockEntity({
|
EnergyStorage.SIDED.registerForBlockEntity({
|
||||||
entity, dir -> object : EnergyStorage {
|
entity, dir -> object : EnergyStorage {
|
||||||
override fun getAmount() = entity.node.getEnergy()
|
override fun getAmount() = entity.node.energy
|
||||||
override fun getCapacity() = entity.node.getEnergyCapacity()
|
override fun getCapacity() = entity.node.energyCapacity
|
||||||
override fun supportsExtraction() = entity.node.getPowerRole() != PowerRole.CONSUMER
|
override fun supportsExtraction() = entity.node.powerRole != PowerRole.CONSUMER
|
||||||
override fun supportsInsertion() = entity.node.getPowerRole() != PowerRole.GENERATOR
|
override fun supportsInsertion() = entity.node.powerRole != 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
|
if(entity.node.powerRole == 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)
|
||||||
@@ -28,7 +28,7 @@ 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
|
if(entity.node.powerRole == PowerRole.GENERATOR) return 0
|
||||||
val given = entity.node.giveEnergy(maxAmount)
|
val given = entity.node.giveEnergy(maxAmount)
|
||||||
transaction?.addCloseCallback { ctx, res ->
|
transaction?.addCloseCallback { ctx, res ->
|
||||||
if (res.wasAborted() || !res.wasCommitted()) entity.node.withdrawEnergy(given)
|
if (res.wasAborted() || !res.wasCommitted()) entity.node.withdrawEnergy(given)
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import net.minecraft.client.gui.GuiGraphics
|
|||||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
|
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
|
||||||
import net.minecraft.world.Container;
|
import net.minecraft.world.Container;
|
||||||
import net.minecraft.core.NonNullList;
|
import net.minecraft.core.NonNullList;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf
|
||||||
|
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||||
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.server.packs.resources.Resource
|
import net.minecraft.server.packs.resources.Resource
|
||||||
@@ -15,6 +17,7 @@ import net.minecraft.world.inventory.AbstractContainerMenu
|
|||||||
import net.minecraft.world.inventory.MenuType
|
import net.minecraft.world.inventory.MenuType
|
||||||
import net.minecraft.world.inventory.Slot
|
import net.minecraft.world.inventory.Slot
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||||
|
|
||||||
// Common container interface, assumes the entire purpose is purely raw item storage
|
// Common container interface, assumes the entire purpose is purely raw item storage
|
||||||
interface GenericContainer : Container {
|
interface GenericContainer : Container {
|
||||||
@@ -112,6 +115,10 @@ abstract class GenericContainerScreen<T: GenericContainerMenu>(menu: T, inventor
|
|||||||
open fun shouldRenderTooltip() = true
|
open fun shouldRenderTooltip() = true
|
||||||
open fun findMenuTexture(): ResourceLocation? = null
|
open fun findMenuTexture(): ResourceLocation? = null
|
||||||
|
|
||||||
|
open fun getBoundBlockEntityType(): Set<BlockEntityType<*>> = setOf()
|
||||||
|
|
||||||
|
open fun processScreenStatePacket(buf: FriendlyByteBuf) {}
|
||||||
|
|
||||||
val imageX: Int
|
val imageX: Int
|
||||||
get() = (width - imageWidth) / 2
|
get() = (width - imageWidth) / 2
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user