NodeBlockEntity is dead, long live SingleDeviceBlockEntity + cables function
@@ -1,7 +1,5 @@
|
|||||||
package org.neoflock.neocomputers
|
package org.neoflock.neocomputers
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat
|
|
||||||
import com.mojang.blaze3d.vertex.VertexFormat
|
|
||||||
import dev.architectury.event.events.client.ClientLifecycleEvent
|
import dev.architectury.event.events.client.ClientLifecycleEvent
|
||||||
import dev.architectury.event.events.common.LifecycleEvent
|
import dev.architectury.event.events.common.LifecycleEvent
|
||||||
import dev.architectury.event.events.common.PlayerEvent
|
import dev.architectury.event.events.common.PlayerEvent
|
||||||
@@ -15,24 +13,20 @@ import org.neoflock.neocomputers.gui.menu.Menus
|
|||||||
import dev.architectury.utils.Env
|
import dev.architectury.utils.Env
|
||||||
import dev.architectury.utils.EnvExecutor
|
import dev.architectury.utils.EnvExecutor
|
||||||
import net.minecraft.client.Minecraft
|
import net.minecraft.client.Minecraft
|
||||||
import net.minecraft.client.renderer.RenderStateShard
|
|
||||||
import net.minecraft.client.renderer.RenderType
|
|
||||||
import net.minecraft.server.level.ServerPlayer
|
import net.minecraft.server.level.ServerPlayer
|
||||||
import org.neoflock.neocomputers.block.NodeBlockEntity
|
import org.neoflock.neocomputers.block.DeviceBlockEntity
|
||||||
import org.neoflock.neocomputers.block.NodeSynchronizer
|
|
||||||
import org.neoflock.neocomputers.gui.buffer.BufferRenderer
|
|
||||||
import org.neoflock.neocomputers.gui.render.ScreenRenderer
|
import org.neoflock.neocomputers.gui.render.ScreenRenderer
|
||||||
import org.neoflock.neocomputers.gui.widget.ComponentRoles
|
import org.neoflock.neocomputers.gui.widget.ComponentRoles
|
||||||
import org.neoflock.neocomputers.item.GPUCard
|
|
||||||
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.DeviceNode
|
||||||
import org.neoflock.neocomputers.network.Networking
|
import org.neoflock.neocomputers.network.Networking
|
||||||
|
import org.neoflock.neocomputers.network.NodeSynchronizer
|
||||||
import org.neoflock.neocomputers.sounds.Sounds
|
import org.neoflock.neocomputers.sounds.Sounds
|
||||||
import org.neoflock.neocomputers.utils.FontProvider
|
import org.neoflock.neocomputers.utils.FontProvider
|
||||||
import org.neoflock.neocomputers.utils.GenericContainerScreen
|
import org.neoflock.neocomputers.utils.GenericContainerScreen
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.nio.Buffer
|
|
||||||
|
|
||||||
object NeoComputers {
|
object NeoComputers {
|
||||||
const val MODID: String = "neocomputers"
|
const val MODID: String = "neocomputers"
|
||||||
@@ -58,7 +52,7 @@ object NeoComputers {
|
|||||||
Tabs.TABS.register()
|
Tabs.TABS.register()
|
||||||
Sounds.SOUNDS.register()
|
Sounds.SOUNDS.register()
|
||||||
ComponentRoles.mapDefaultTextures()
|
ComponentRoles.mapDefaultTextures()
|
||||||
// i dont know why architectury wants two lambdas but whatever
|
// I don't know why architectury wants two lambdas but whatever
|
||||||
EnvExecutor.runInEnv(Env.CLIENT) {{
|
EnvExecutor.runInEnv(Env.CLIENT) {{
|
||||||
ClientLifecycleEvent.CLIENT_SETUP.register {
|
ClientLifecycleEvent.CLIENT_SETUP.register {
|
||||||
Menus.registerScreens()
|
Menus.registerScreens()
|
||||||
@@ -87,7 +81,7 @@ object NeoComputers {
|
|||||||
Networking.channels.remove()
|
Networking.channels.remove()
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientLifecycleEvent.CLIENT_STARTED.register {
|
ClientLifecycleEvent.CLIENT_SETUP.register {
|
||||||
Networking.allNodes.remove()
|
Networking.allNodes.remove()
|
||||||
Networking.wirelessNodes.remove()
|
Networking.wirelessNodes.remove()
|
||||||
Networking.channels.remove()
|
Networking.channels.remove()
|
||||||
@@ -111,19 +105,22 @@ object NeoComputers {
|
|||||||
packet, ctx ->
|
packet, ctx ->
|
||||||
val player = ctx.player
|
val player = ctx.player
|
||||||
if(player is ServerPlayer) {
|
if(player is ServerPlayer) {
|
||||||
NodeSynchronizer.screenMap[player]?.processScreenInteraction(player, packet.buffer)
|
val ent = NodeSynchronizer.screenMap[player]
|
||||||
|
if(ent is DeviceNode) {
|
||||||
|
ent.processScreenInteraction(player, packet.buffer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// we have to do this because the datagen task runs in the physical server
|
// we have to do this because the datagen task runs in the physical server
|
||||||
EnvExecutor.runInEnv(Env.CLIENT) {{
|
EnvExecutor.runInEnv(Env.CLIENT) {{
|
||||||
NetworkManager.registerReceiver(NetworkManager.s2c(),NodeSynchronizer.StatePayload.TYPE, NodeSynchronizer.StatePayload.CODEC, {
|
NetworkManager.registerReceiver(NetworkManager.s2c(),NodeSynchronizer.DeviceBlockStatePayload.TYPE, NodeSynchronizer.DeviceBlockStatePayload.CODEC, {
|
||||||
packet, ctx ->
|
packet, ctx ->
|
||||||
val level = ctx.player.level()
|
val level = ctx.player.level()
|
||||||
val ent = level.getBlockEntity(packet.blockPos)
|
val ent = level.getBlockEntity(packet.blockPos)
|
||||||
if(ent is NodeBlockEntity) {
|
if(ent is DeviceBlockEntity) {
|
||||||
ent.syncWithUpstream(packet.buffer)
|
ent.processCommits(packet.buffers)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -143,7 +140,7 @@ object NeoComputers {
|
|||||||
}}
|
}}
|
||||||
EnvExecutor.runInEnv(Env.SERVER) {{
|
EnvExecutor.runInEnv(Env.SERVER) {{
|
||||||
// https://github.com/architectury/architectury-api/issues/518
|
// https://github.com/architectury/architectury-api/issues/518
|
||||||
NetworkManager.registerS2CPayloadType(NodeSynchronizer.StatePayload.TYPE, NodeSynchronizer.StatePayload.CODEC)
|
NetworkManager.registerS2CPayloadType(NodeSynchronizer.DeviceBlockStatePayload.TYPE, NodeSynchronizer.DeviceBlockStatePayload.CODEC)
|
||||||
NetworkManager.registerS2CPayloadType(NodeSynchronizer.ScreenPayload.TYPE, NodeSynchronizer.ScreenPayload.CODEC)
|
NetworkManager.registerS2CPayloadType(NodeSynchronizer.ScreenPayload.TYPE, NodeSynchronizer.ScreenPayload.CODEC)
|
||||||
NetworkManager.registerS2CPayloadType(NodeSynchronizer.BeepDataPayload.TYPE, NodeSynchronizer.BeepDataPayload.CODEC)
|
NetworkManager.registerS2CPayloadType(NodeSynchronizer.BeepDataPayload.TYPE, NodeSynchronizer.BeepDataPayload.CODEC)
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import net.minecraft.world.phys.shapes.VoxelShape
|
|||||||
import org.neoflock.neocomputers.NeoComputers
|
import org.neoflock.neocomputers.NeoComputers
|
||||||
import org.neoflock.neocomputers.entity.CableEntity
|
import org.neoflock.neocomputers.entity.CableEntity
|
||||||
|
|
||||||
class CableBlock() : BaseBlock(Properties.of()), EntityBlock {
|
class CableBlock() : DeviceBlock(Properties.of()), EntityBlock {
|
||||||
companion object {
|
companion object {
|
||||||
val NORTH = BooleanProperty.create("north")
|
val NORTH = BooleanProperty.create("north")
|
||||||
val EAST = BooleanProperty.create("east")
|
val EAST = BooleanProperty.create("east")
|
||||||
@@ -96,12 +96,20 @@ class CableBlock() : BaseBlock(Properties.of()), EntityBlock {
|
|||||||
fun shouldConnect(pos: BlockPos, npos: BlockPos, level: Level): Boolean {
|
fun shouldConnect(pos: BlockPos, npos: BlockPos, level: Level): Boolean {
|
||||||
val ent = level.getBlockEntity(npos)
|
val ent = level.getBlockEntity(npos)
|
||||||
val blockState = level.getBlockState(pos)
|
val blockState = level.getBlockState(pos)
|
||||||
|
val theirState = level.getBlockState(npos)
|
||||||
|
|
||||||
return ent is NodeBlockEntity || (ent is CableEntity &&
|
val universal = DyeColor.LIGHT_GRAY
|
||||||
(level.getBlockState(npos).getValue(COLOR).equals(blockState.getValue(COLOR)) ||
|
if(ent is CableEntity) {
|
||||||
blockState.getValue(COLOR).equals(DyeColor.LIGHT_GRAY) ||
|
val ourColor = blockState.getValue(COLOR)
|
||||||
level.getBlockState(npos).getValue(COLOR).equals(DyeColor.LIGHT_GRAY)))
|
val theirColor = theirState.getValue(COLOR)
|
||||||
// val state: BlockState? = (ent is CableEntity && (level.getBlockState(neighborPos).getValue(COLOR).equals(state.getValue(COLOR)) || state.getValue(COLOR).equals(DyeColor.LIGHT_GRAY))
|
|
||||||
|
if(ourColor.equals(universal)) return true
|
||||||
|
if(theirColor.equals(universal)) return true
|
||||||
|
if(ourColor.equals(theirColor)) return true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return ent is DeviceBlockEntity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,9 +138,7 @@ class CableBlock() : BaseBlock(Properties.of()), EntityBlock {
|
|||||||
.add(COLOR))
|
.add(COLOR))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun newBlockEntity(pos: BlockPos, state: BlockState): BlockEntity? {
|
override fun newBlockEntity(pos: BlockPos, state: BlockState) = CableEntity(pos, state)
|
||||||
return CableEntity(pos, state)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getShape(state: BlockState, level: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape? {
|
override fun getShape(state: BlockState, level: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape? {
|
||||||
val idx = calcIdx(state.getValue(NORTH), state.getValue(SOUTH), state.getValue(EAST), state.getValue(WEST), state.getValue(UP), state.getValue(DOWN))
|
val idx = calcIdx(state.getValue(NORTH), state.getValue(SOUTH), state.getValue(EAST), state.getValue(WEST), state.getValue(UP), state.getValue(DOWN))
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import net.minecraft.core.BlockPos
|
|||||||
import net.minecraft.core.Direction
|
import net.minecraft.core.Direction
|
||||||
import net.minecraft.core.HolderLookup
|
import net.minecraft.core.HolderLookup
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.CompoundTag
|
||||||
|
import net.minecraft.network.FriendlyByteBuf
|
||||||
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
|
||||||
@@ -25,6 +26,16 @@ open class CapacitorEntity(val capacity: Long, type: BlockEntityType<*>, pos: Bl
|
|||||||
val deviceNode = object : DeviceNode() {
|
val deviceNode = object : DeviceNode() {
|
||||||
override var powerRole = PowerRole.STORAGE
|
override var powerRole = PowerRole.STORAGE
|
||||||
override var energyCapacity: Long = capacity
|
override var energyCapacity: Long = capacity
|
||||||
|
|
||||||
|
override fun writeFullStateCommit(buf: FriendlyByteBuf) {
|
||||||
|
super.writeFullStateCommit(buf)
|
||||||
|
buf.writeVarLong(energy)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun processCommit(buf: FriendlyByteBuf) {
|
||||||
|
super.processCommit(buf)
|
||||||
|
energy = buf.readVarLong()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: cache list
|
// TODO: cache list
|
||||||
@@ -46,7 +57,7 @@ class CapacitorEntityTier1(pos: BlockPos, state: BlockState): CapacitorEntity(20
|
|||||||
class CapacitorEntityTier2(pos: BlockPos, state: BlockState): CapacitorEntity(50000, BlockEntities.CAPACITOR2_ENTITY.get(), pos, state)
|
class CapacitorEntityTier2(pos: BlockPos, state: BlockState): CapacitorEntity(50000, BlockEntities.CAPACITOR2_ENTITY.get(), pos, state)
|
||||||
class CapacitorEntityTier3(pos: BlockPos, state: BlockState): CapacitorEntity(100000, BlockEntities.CAPACITOR3_ENTITY.get(), pos, state)
|
class CapacitorEntityTier3(pos: BlockPos, state: BlockState): CapacitorEntity(100000, BlockEntities.CAPACITOR3_ENTITY.get(), pos, state)
|
||||||
|
|
||||||
class CapacitorBlock(val tier: Int) : NodeBlock() {
|
class CapacitorBlock(val tier: Int) : DeviceBlock() {
|
||||||
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity {
|
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity {
|
||||||
val cap: CapacitorEntity = when(tier) {
|
val cap: CapacitorEntity = when(tier) {
|
||||||
1 -> CapacitorEntityTier1(blockPos, blockState)
|
1 -> CapacitorEntityTier1(blockPos, blockState)
|
||||||
@@ -54,7 +65,7 @@ class CapacitorBlock(val tier: Int) : NodeBlock() {
|
|||||||
3 -> CapacitorEntityTier3(blockPos, blockState)
|
3 -> CapacitorEntityTier3(blockPos, blockState)
|
||||||
else -> throw UnsupportedOperationException("unsupported tier: $tier")
|
else -> throw UnsupportedOperationException("unsupported tier: $tier")
|
||||||
}
|
}
|
||||||
return cap.initNetworking()
|
return cap
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun useWithoutItem(
|
override fun useWithoutItem(
|
||||||
@@ -64,13 +75,12 @@ class CapacitorBlock(val tier: Int) : NodeBlock() {
|
|||||||
player: Player,
|
player: Player,
|
||||||
blockHitResult: BlockHitResult
|
blockHitResult: BlockHitResult
|
||||||
): InteractionResult {
|
): InteractionResult {
|
||||||
if(!level.isClientSide()) {
|
if(level.isClientSide()) {
|
||||||
val p = player as ServerPlayer
|
|
||||||
val ent = level.getBlockEntity(blockPos)
|
val ent = level.getBlockEntity(blockPos)
|
||||||
if(ent is CapacitorEntity) {
|
if(ent is CapacitorEntity) {
|
||||||
if(p.isCrouching) ent.deviceNode.giveEnergy(1)
|
if(player.isCrouching) ent.deviceNode.giveEnergy(1)
|
||||||
val msg = PlayerChatMessage.system("energy: ${ent.deviceNode.energy} / ${ent.capacity} (${ent.deviceNode.connections.size} connections, ${ent.deviceNode.getReachable().size} connected)")
|
val msg = PlayerChatMessage.system("energy: ${ent.deviceNode.energy} / ${ent.capacity} (${ent.deviceNode.connections.size} connections, ${ent.deviceNode.getReachable().size} reachable)")
|
||||||
p.sendSystemMessage(OutgoingChatMessage.create(msg).content())
|
player.sendSystemMessage(OutgoingChatMessage.create(msg).content())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return InteractionResult.SUCCESS
|
return InteractionResult.SUCCESS
|
||||||
|
|||||||
@@ -31,9 +31,10 @@ import org.neoflock.neocomputers.block.CombustionGeneratorBlock.Companion.COMBUS
|
|||||||
import org.neoflock.neocomputers.entity.BlockEntities
|
import org.neoflock.neocomputers.entity.BlockEntities
|
||||||
import org.neoflock.neocomputers.entity.CaseBlockEntity
|
import org.neoflock.neocomputers.entity.CaseBlockEntity
|
||||||
import org.neoflock.neocomputers.entity.MachineEntity
|
import org.neoflock.neocomputers.entity.MachineEntity
|
||||||
|
import org.neoflock.neocomputers.network.NodeSynchronizer
|
||||||
import org.neoflock.neocomputers.sounds.Sounds
|
import org.neoflock.neocomputers.sounds.Sounds
|
||||||
|
|
||||||
class CaseBlock() : NodeBlock(Properties.of().sound(SoundType.METAL).lightLevel(CaseBlock::getLuminance)) { // placeholder stuff
|
class CaseBlock() : DeviceBlock(Properties.of().sound(SoundType.METAL).lightLevel(CaseBlock::getLuminance)) { // placeholder stuff
|
||||||
companion object {
|
companion object {
|
||||||
val FACING: EnumProperty<Direction> = EnumProperty.create<Direction>("facing", Direction::class.java)
|
val FACING: EnumProperty<Direction> = EnumProperty.create<Direction>("facing", Direction::class.java)
|
||||||
val COMPUTER_RUNNING = BooleanProperty.create("running")!!
|
val COMPUTER_RUNNING = BooleanProperty.create("running")!!
|
||||||
@@ -47,7 +48,7 @@ class CaseBlock() : NodeBlock(Properties.of().sound(SoundType.METAL).lightLevel(
|
|||||||
registerDefaultState(stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(COMPUTER_RUNNING, false))
|
registerDefaultState(stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(COMPUTER_RUNNING, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState) = CaseBlockEntity(blockPos, blockState).initNetworking()
|
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState) = CaseBlockEntity(blockPos, blockState)
|
||||||
|
|
||||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block?, BlockState?>) {
|
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block?, BlockState?>) {
|
||||||
builder.add(COMPUTER_RUNNING)
|
builder.add(COMPUTER_RUNNING)
|
||||||
@@ -115,7 +116,7 @@ class CaseBlock() : NodeBlock(Properties.of().sound(SoundType.METAL).lightLevel(
|
|||||||
} else {
|
} else {
|
||||||
// Open menu
|
// Open menu
|
||||||
MenuRegistry.openMenu(player as ServerPlayer, ent)
|
MenuRegistry.openMenu(player as ServerPlayer, ent)
|
||||||
NodeSynchronizer.registerPlayerScreen(player, ent)
|
NodeSynchronizer.registerPlayerScreen(player, ent.deviceNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return InteractionResult.SUCCESS
|
return InteractionResult.SUCCESS
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
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.core.Direction
|
import net.minecraft.core.Direction
|
||||||
|
import net.minecraft.network.FriendlyByteBuf
|
||||||
|
import net.minecraft.server.level.ServerLevel
|
||||||
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.Block
|
||||||
import net.minecraft.world.level.block.EntityBlock
|
import net.minecraft.world.level.block.EntityBlock
|
||||||
@@ -11,9 +15,18 @@ 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.network.DeviceNode
|
import org.neoflock.neocomputers.network.DeviceNode
|
||||||
import org.neoflock.neocomputers.network.Networking
|
import org.neoflock.neocomputers.network.Networking
|
||||||
|
import org.neoflock.neocomputers.network.NodeSynchronizer
|
||||||
|
|
||||||
|
abstract class SingleDeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state: BlockState): DeviceBlockEntity(type, pos, state) {
|
||||||
|
abstract val deviceNode: DeviceNode
|
||||||
|
|
||||||
|
override fun getDeviceNodes() = listOf(deviceNode)
|
||||||
|
override fun getNodeFromSide(directionToRequester: Direction): DeviceNode? = deviceNode
|
||||||
|
}
|
||||||
|
|
||||||
abstract class DeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state: BlockState): BlockEntity(type, pos, state) {
|
abstract class DeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state: BlockState): BlockEntity(type, pos, state) {
|
||||||
val connetionsInDir = MutableList(Direction.entries.size) { HashSet<DeviceNode>() }
|
val connetionsInDir = MutableList<DeviceNode?>(Direction.entries.size) { null }
|
||||||
|
var alreadySetup = false
|
||||||
|
|
||||||
abstract fun getDeviceNodes(): List<DeviceNode>
|
abstract fun getDeviceNodes(): List<DeviceNode>
|
||||||
|
|
||||||
@@ -22,57 +35,85 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state:
|
|||||||
// so it is Direction.UP if we asked from the one on the top side.
|
// so it is Direction.UP if we asked from the one on the top side.
|
||||||
abstract fun getNodeFromSide(directionToRequester: Direction): DeviceNode?
|
abstract fun getNodeFromSide(directionToRequester: Direction): DeviceNode?
|
||||||
|
|
||||||
|
open fun processCommits(commits: Iterable<FriendlyByteBuf>) {
|
||||||
|
val devs = getDeviceNodes()
|
||||||
|
for (buf in commits) {
|
||||||
|
val idx = buf.readVarInt()
|
||||||
|
if(idx >= 0 && idx < devs.size) {
|
||||||
|
devs[idx].processCommit(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
open fun initNetworking(): DeviceBlockEntity {
|
open fun initNetworking(): DeviceBlockEntity {
|
||||||
getDeviceNodes().forEach { Networking.addNode(it) }
|
if(hasLevel()) {
|
||||||
|
alreadySetup = true
|
||||||
|
Networking.addNodes(getDeviceNodes())
|
||||||
Direction.entries.forEach { handleConnectionsFor(it) }
|
Direction.entries.forEach { handleConnectionsFor(it) }
|
||||||
|
}
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun getCurrentlyConnectedNodesIn(direction: Direction): HashSet<DeviceNode> {
|
// Cables are 1 node
|
||||||
|
open fun getCurrentlyConnectedNodeIn(direction: Direction): DeviceNode? {
|
||||||
val ent = level?.getBlockEntity(blockPos.relative(direction))
|
val ent = level?.getBlockEntity(blockPos.relative(direction))
|
||||||
val connected = HashSet<DeviceNode>()
|
|
||||||
if(ent is DeviceBlockEntity) {
|
if(ent is DeviceBlockEntity) {
|
||||||
val node = ent.getNodeFromSide(direction.opposite)
|
return ent.getNodeFromSide(direction.opposite)
|
||||||
if(node != null) connected.add(node)
|
|
||||||
}
|
}
|
||||||
return connected
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: rethink this shi so sharing a node on 2 different sides doesn't make connections require mutually exclusive conditions
|
|
||||||
// TODO: actually like, rethink the whole class so far
|
|
||||||
|
|
||||||
open fun handleConnectionsFor(direction: Direction) {
|
open fun handleConnectionsFor(direction: Direction) {
|
||||||
// refuse connections on no node to reduce CPU load
|
// refuse connections on no node to reduce CPU load
|
||||||
val node = getNodeFromSide(direction.opposite) ?: return
|
val node = getNodeFromSide(direction.opposite) ?: return
|
||||||
val old = connetionsInDir[direction.ordinal]
|
val old = connetionsInDir[direction.ordinal]
|
||||||
val now = getCurrentlyConnectedNodesIn(direction)
|
val now = getCurrentlyConnectedNodeIn(direction)
|
||||||
|
|
||||||
// TODO: optimize this hellscape
|
if(old?.address != now?.address) {
|
||||||
|
if(old != null) node.disconnectFrom(old)
|
||||||
val toKill = HashSet<DeviceNode>()
|
if(now != null) node.connectTo(now)
|
||||||
old.forEach {
|
|
||||||
if(it !in now) toKill.add(it)
|
|
||||||
}
|
|
||||||
toKill.forEach { node.disconnectFrom(it) }
|
|
||||||
now.forEach {
|
|
||||||
if(it !in old) node.connectTo(it)
|
|
||||||
}
|
}
|
||||||
connetionsInDir[direction.ordinal] = now
|
connetionsInDir[direction.ordinal] = now
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: optimize this sometime before our test computers melt
|
// TODO: optimize this sometime before our test computers melt
|
||||||
open fun tickDevice() {
|
open fun tickDevice(level: Level) {
|
||||||
// Handles device connections and sync here
|
// Handles device connections and sync here
|
||||||
|
|
||||||
// Process connections
|
// we do it like this because stinky MC will call stuff before world is fully setup
|
||||||
Direction.entries.forEach {
|
// and then not notify us of neighbour changes
|
||||||
handleConnectionsFor(it)
|
// this is because MC is considered shit
|
||||||
|
if(!alreadySetup) {
|
||||||
|
initNetworking()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun sendCommitsToClient(level: Level) {
|
||||||
|
if(level is ServerLevel) {
|
||||||
|
// synchronization!
|
||||||
|
val commits = mutableListOf<FriendlyByteBuf>()
|
||||||
|
val devs = getDeviceNodes()
|
||||||
|
for((i, dev) in devs.withIndex()) {
|
||||||
|
// TODO: use dev.outOfSync to only set commits if something changed, and allow client to request the commits (securely)
|
||||||
|
dev.outOfSync = false
|
||||||
|
val buf = FriendlyByteBuf(Unpooled.buffer())
|
||||||
|
buf.writeVarInt(i)
|
||||||
|
dev.writeFullStateCommit(buf)
|
||||||
|
commits.addLast(buf)
|
||||||
|
}
|
||||||
|
if(commits.isNotEmpty()) {
|
||||||
|
level.players().forEach {
|
||||||
|
val dist = it.position().distanceTo(blockPos.center)
|
||||||
|
if(dist < 100) NetworkManager.sendToPlayer(it, NodeSynchronizer.DeviceBlockStatePayload(blockPos, commits))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setRemoved() {
|
override fun setRemoved() {
|
||||||
super.setRemoved()
|
super.setRemoved()
|
||||||
getDeviceNodes().forEach { Networking.removeNode(it) }
|
alreadySetup = false
|
||||||
|
Networking.removeNodes(getDeviceNodes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +126,8 @@ abstract class DeviceBlock(properties: Properties = Properties.of()): BaseBlock(
|
|||||||
return object : BlockEntityTicker<T> {
|
return object : BlockEntityTicker<T> {
|
||||||
override fun tick(level: Level, blockPos: BlockPos, blockState: BlockState, blockEntity: T & Any) {
|
override fun tick(level: Level, blockPos: BlockPos, blockState: BlockState, blockEntity: T & Any) {
|
||||||
if(blockEntity !is DeviceBlockEntity) return
|
if(blockEntity !is DeviceBlockEntity) return
|
||||||
blockEntity.tickDevice()
|
blockEntity.tickDevice(level)
|
||||||
|
blockEntity.sendCommitsToClient(level)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,13 +23,14 @@ 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
|
||||||
|
import org.neoflock.neocomputers.network.NodeSynchronizer
|
||||||
|
|
||||||
class SolarGeneratorBlock : NodeBlock(), EntityBlock {
|
class SolarGeneratorBlock : DeviceBlock(), EntityBlock {
|
||||||
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity = SolarGeneratorBlockEntity(blockPos, blockState).initNetworking()
|
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity = SolarGeneratorBlockEntity(blockPos, blockState)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: make it glow when burning
|
// TODO: make it glow when burning
|
||||||
class CombustionGeneratorBlock : NodeBlock, EntityBlock {
|
class CombustionGeneratorBlock : DeviceBlock, EntityBlock {
|
||||||
companion object {
|
companion object {
|
||||||
val COMBUSTGEN_ACTIVE = BooleanProperty.create("active")
|
val COMBUSTGEN_ACTIVE = BooleanProperty.create("active")
|
||||||
|
|
||||||
@@ -42,7 +43,7 @@ class CombustionGeneratorBlock : NodeBlock, EntityBlock {
|
|||||||
registerDefaultState(defaultBlockState().setValue(COMBUSTGEN_ACTIVE, false))
|
registerDefaultState(defaultBlockState().setValue(COMBUSTGEN_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)
|
||||||
|
|
||||||
override fun useWithoutItem(
|
override fun useWithoutItem(
|
||||||
blockState: BlockState,
|
blockState: BlockState,
|
||||||
@@ -54,7 +55,7 @@ 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)
|
NodeSynchronizer.registerPlayerScreen(sp, ent.deviceNode)
|
||||||
MenuRegistry.openMenu(sp, ent)
|
MenuRegistry.openMenu(sp, ent)
|
||||||
}
|
}
|
||||||
return InteractionResult.SUCCESS
|
return InteractionResult.SUCCESS
|
||||||
|
|||||||
@@ -1,304 +0,0 @@
|
|||||||
package org.neoflock.neocomputers.block
|
|
||||||
|
|
||||||
import dev.architectury.networking.NetworkManager
|
|
||||||
import io.netty.buffer.Unpooled
|
|
||||||
import net.minecraft.core.BlockPos
|
|
||||||
import net.minecraft.core.HolderLookup
|
|
||||||
import net.minecraft.nbt.CompoundTag
|
|
||||||
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.level.Level
|
|
||||||
import net.minecraft.world.level.block.Block
|
|
||||||
import net.minecraft.world.level.block.EntityBlock
|
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity
|
|
||||||
import net.minecraft.world.level.block.entity.BlockEntityTicker
|
|
||||||
import net.minecraft.world.level.block.entity.BlockEntityType
|
|
||||||
import net.minecraft.world.level.block.state.BlockState
|
|
||||||
import org.neoflock.neocomputers.NeoComputers
|
|
||||||
import org.neoflock.neocomputers.network.Networking
|
|
||||||
import org.neoflock.neocomputers.network.DeviceNode
|
|
||||||
import java.time.Duration
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
class ScreenDataPayload(var entityTypeWireID: String, var buffer: FriendlyByteBuf): CustomPacketPayload {
|
|
||||||
companion object {
|
|
||||||
val SCREEN_DATA_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "screen_data")
|
|
||||||
val TYPE = CustomPacketPayload.Type<ScreenDataPayload>(SCREEN_DATA_ID)
|
|
||||||
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, ScreenDataPayload> {
|
|
||||||
override fun decode(buf: RegistryFriendlyByteBuf): ScreenDataPayload {
|
|
||||||
val id = buf.readByteArray().decodeToString()
|
|
||||||
val buffer = FriendlyByteBuf(buf.copy(buf.readerIndex(), buf.readableBytes()))
|
|
||||||
return ScreenDataPayload(id, buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun encode(buf: RegistryFriendlyByteBuf, payload: ScreenDataPayload) {
|
|
||||||
buf.writeByteArray(payload.entityTypeWireID.encodeToByteArray())
|
|
||||||
buf.writeBytes(payload.buffer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun type() = TYPE
|
|
||||||
}
|
|
||||||
|
|
||||||
class BeepDataPayload(val pos: BlockPos, val pattern: String, val freq: Int, val duration: Duration, val volume: Double): CustomPacketPayload {
|
|
||||||
companion object {
|
|
||||||
val BEEP_DATA_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "beep_data")
|
|
||||||
val TYPE = CustomPacketPayload.Type<BeepDataPayload>(BEEP_DATA_ID)
|
|
||||||
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, BeepDataPayload> {
|
|
||||||
override fun decode(buf: RegistryFriendlyByteBuf): BeepDataPayload {
|
|
||||||
val pos = buf.readBlockPos()
|
|
||||||
val pattern = buf.readUtf()
|
|
||||||
val freq = buf.readVarInt()
|
|
||||||
val duration = buf.readVarLong()
|
|
||||||
val volume = buf.readDouble()
|
|
||||||
return BeepDataPayload(pos, pattern, freq, Duration.ofMillis(duration), volume)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun encode(buf: RegistryFriendlyByteBuf, payload: BeepDataPayload) {
|
|
||||||
buf.writeBlockPos(payload.pos)
|
|
||||||
buf.writeUtf(payload.pattern)
|
|
||||||
buf.writeVarInt(payload.freq)
|
|
||||||
buf.writeVarLong(payload.duration.toMillis())
|
|
||||||
buf.writeDouble(payload.volume)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun type() = TYPE
|
|
||||||
}
|
|
||||||
|
|
||||||
val screenMap = HashMap<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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun sendScreenInteraction(friendlyByteBuf: FriendlyByteBuf) {
|
|
||||||
NetworkManager.sendToServer(ScreenDataPayload("", friendlyByteBuf))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun emitBeep(level: Level, beepDataPayload: BeepDataPayload) {
|
|
||||||
if(level is ServerLevel) {
|
|
||||||
level.players().forEach {
|
|
||||||
NetworkManager.sendToPlayer(it, beepDataPayload)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class NodeBlockEntity(blockEntityType: BlockEntityType<*>, blockPos: BlockPos, blockState: BlockState) : BlockEntity(blockEntityType, blockPos, blockState) {
|
|
||||||
abstract val deviceNode: DeviceNode
|
|
||||||
|
|
||||||
fun initNetworking(): NodeBlockEntity {
|
|
||||||
Networking.addNode(deviceNode)
|
|
||||||
invalidateNodeState()
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
// runs on the server, meant to encode state to send to all players
|
|
||||||
open fun encodeDownstreamData(packet: FriendlyByteBuf) {
|
|
||||||
packet.writeUUID(deviceNode.address)
|
|
||||||
packet.writeLong(deviceNode.energy)
|
|
||||||
packet.writeLong(deviceNode.energyCapacity)
|
|
||||||
packet.writeEnum(deviceNode.reachability)
|
|
||||||
packet.writeEnum(deviceNode.powerRole)
|
|
||||||
}
|
|
||||||
|
|
||||||
// runs on the client, meant to decode server state packets to synchronize client state
|
|
||||||
open fun syncWithUpstream(packet: FriendlyByteBuf) {
|
|
||||||
Networking.changeNodeAddress(deviceNode, packet.readUUID())
|
|
||||||
deviceNode.energy = packet.readLong()
|
|
||||||
deviceNode.energyCapacity = packet.readLong()
|
|
||||||
deviceNode.reachability = packet.readEnum(deviceNode.reachability.javaClass)
|
|
||||||
deviceNode.powerRole = packet.readEnum(deviceNode.powerRole.javaClass)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encodes data meant for the associated screen of a player
|
|
||||||
open fun encodeScreenData(player: ServerPlayer, packet: FriendlyByteBuf) {}
|
|
||||||
|
|
||||||
open fun processScreenInteraction(player: ServerPlayer, packet: FriendlyByteBuf) {}
|
|
||||||
|
|
||||||
private var stateIsDirty = true
|
|
||||||
|
|
||||||
open fun getNeighbourEntities(): List<BlockEntity> {
|
|
||||||
val subpos = listOf(
|
|
||||||
blockPos.offset(0, 0, 1),
|
|
||||||
blockPos.offset(0, 0, -1),
|
|
||||||
blockPos.offset(0, 1, 0),
|
|
||||||
blockPos.offset(0, -1, 0),
|
|
||||||
blockPos.offset(1, 0, 0),
|
|
||||||
blockPos.offset(-1, 0, 0),
|
|
||||||
)
|
|
||||||
|
|
||||||
return subpos.mapNotNull { pos -> level?.getBlockEntity(pos) }
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun computeEdges(): Set<NodeBlockEntity> {
|
|
||||||
val s = mutableSetOf<NodeBlockEntity>()
|
|
||||||
val neighbours = getNeighbourEntities()
|
|
||||||
for(neighbour in neighbours) {
|
|
||||||
if(neighbour is NodeBlockEntity) s.add(neighbour);
|
|
||||||
// TODO: handle cable entities
|
|
||||||
}
|
|
||||||
s.remove(this)
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun invalidateNodeState() {
|
|
||||||
stateIsDirty = true
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun needsSynchronization() = stateIsDirty
|
|
||||||
|
|
||||||
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
|
|
||||||
stateIsDirty = false
|
|
||||||
computeEdges().forEach {
|
|
||||||
deviceNode.connectTo(it.deviceNode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setChanged() {
|
|
||||||
invalidateNodeState()
|
|
||||||
computeEdges().forEach { it.invalidateNodeState() }
|
|
||||||
super.setChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setRemoved() {
|
|
||||||
super.setRemoved()
|
|
||||||
Networking.removeNode(deviceNode)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun clearRemoved() {
|
|
||||||
super.clearRemoved()
|
|
||||||
initNetworking()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun loadAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
|
|
||||||
super.loadAdditional(compoundTag, provider)
|
|
||||||
invalidateNodeState()
|
|
||||||
computeEdges().forEach { it.invalidateNodeState() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class NodeBlock(properties: Properties = Properties.of()): BaseBlock(properties), EntityBlock {
|
|
||||||
override fun <T : BlockEntity> getTicker(
|
|
||||||
level: Level,
|
|
||||||
blockState: BlockState,
|
|
||||||
blockEntityType: BlockEntityType<T>
|
|
||||||
): BlockEntityTicker<T>? {
|
|
||||||
return object : BlockEntityTicker<T> {
|
|
||||||
override fun tick(level: Level, blockPos: BlockPos, blockState: BlockState, blockEntity: T) {
|
|
||||||
if(blockEntity !is NodeBlockEntity) return
|
|
||||||
if(Networking.getNode(blockEntity.deviceNode.address) == null) blockEntity.initNetworking()
|
|
||||||
blockEntity.tickNode(level)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPlace(
|
|
||||||
blockState: BlockState,
|
|
||||||
level: Level,
|
|
||||||
blockPos: BlockPos,
|
|
||||||
blockState2: BlockState,
|
|
||||||
bl: Boolean
|
|
||||||
) {
|
|
||||||
super.onPlace(blockState, level, blockPos, blockState2, bl)
|
|
||||||
if(!level.isClientSide) {
|
|
||||||
val ent = level.getBlockEntity(blockPos)
|
|
||||||
if(ent is NodeBlockEntity) {
|
|
||||||
ent.invalidateNodeState()
|
|
||||||
ent.computeEdges().forEach { it.invalidateNodeState() }
|
|
||||||
}
|
|
||||||
level.updateNeighborsAt(blockPos, this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun neighborChanged(
|
|
||||||
blockState: BlockState,
|
|
||||||
level: Level,
|
|
||||||
blockPos: BlockPos,
|
|
||||||
block: Block,
|
|
||||||
blockPos2: BlockPos,
|
|
||||||
bl: Boolean
|
|
||||||
) {
|
|
||||||
super.neighborChanged(blockState, level, blockPos, block, blockPos2, bl)
|
|
||||||
if(!level.isClientSide) {
|
|
||||||
val ent = level.getBlockEntity(blockPos)
|
|
||||||
if(ent is NodeBlockEntity) {
|
|
||||||
ent.invalidateNodeState()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,7 +15,7 @@ import org.neoflock.neocomputers.entity.BlockEntities
|
|||||||
import org.neoflock.neocomputers.network.Networking
|
import org.neoflock.neocomputers.network.Networking
|
||||||
import org.neoflock.neocomputers.network.DeviceNode
|
import org.neoflock.neocomputers.network.DeviceNode
|
||||||
|
|
||||||
class RedstoneIOEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEntity(BlockEntities.REDSTONEIO_ENTITY.get(), blockPos, blockState) {
|
class RedstoneIOEntity(blockPos: BlockPos, blockState: BlockState): SingleDeviceBlockEntity(BlockEntities.REDSTONEIO_ENTITY.get(), blockPos, blockState) {
|
||||||
val redstoneIn = Array<Int>(Direction.entries.size) {0}
|
val redstoneIn = Array<Int>(Direction.entries.size) {0}
|
||||||
val redstoneOut = Array<Int>(Direction.entries.size) {0}
|
val redstoneOut = Array<Int>(Direction.entries.size) {0}
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ class RedstoneIOEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RedstoneIOBlock(): NodeBlock(Properties.of().isRedstoneConductor { state, getter, pos -> true }) {
|
class RedstoneIOBlock(): DeviceBlock(Properties.of().isRedstoneConductor { state, getter, pos -> true }) {
|
||||||
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity = RedstoneIOEntity(blockPos, blockState)
|
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity = RedstoneIOEntity(blockPos, blockState)
|
||||||
|
|
||||||
fun getRedstoneIO(level: BlockGetter, blockPos: BlockPos): RedstoneIOEntity? {
|
fun getRedstoneIO(level: BlockGetter, blockPos: BlockPos): RedstoneIOEntity? {
|
||||||
|
|||||||
@@ -26,23 +26,19 @@ import org.neoflock.neocomputers.entity.ScreenEntity
|
|||||||
import org.neoflock.neocomputers.gui.menu.ScreenMenu
|
import org.neoflock.neocomputers.gui.menu.ScreenMenu
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
import org.neoflock.neocomputers.network.NodeSynchronizer
|
||||||
|
|
||||||
class ScreenBlock() : NodeBlock() {
|
class ScreenBlock() : DeviceBlock() {
|
||||||
companion object {
|
companion object {
|
||||||
val FACING_HORIZ: EnumProperty<Direction> = EnumProperty.create<Direction>("facing_horiz", Direction::class.java)
|
val FACING_HORIZ: EnumProperty<Direction> = EnumProperty.create<Direction>("facing_horiz", Direction::class.java)
|
||||||
val FACING_VERTI: IntegerProperty = IntegerProperty.create("facing_verti", 0, 2) // "Integer" property doesnt accept values below 0, also death to enums, long live magic numbers
|
val FACING_VERTI: IntegerProperty = IntegerProperty.create("facing_verti", 0, 2) // "Integer" property doesnt accept values below 0, also death to enums, long live magic numbers
|
||||||
val ENERGY: Long = 5
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
registerDefaultState(stateDefinition.any().setValue(FACING_HORIZ, Direction.NORTH).setValue(FACING_VERTI, 1))
|
registerDefaultState(stateDefinition.any().setValue(FACING_HORIZ, Direction.NORTH).setValue(FACING_VERTI, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity? {
|
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState) = ScreenEntity(blockPos, blockState)
|
||||||
val scr = ScreenEntity(blockPos, blockState)
|
|
||||||
scr.initNetworking()
|
|
||||||
return scr
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun useWithoutItem(
|
override fun useWithoutItem(
|
||||||
blockState: BlockState,
|
blockState: BlockState,
|
||||||
@@ -52,14 +48,9 @@ class ScreenBlock() : NodeBlock() {
|
|||||||
blockHitResult: BlockHitResult
|
blockHitResult: BlockHitResult
|
||||||
): InteractionResult {
|
): InteractionResult {
|
||||||
if(!level.isClientSide) {
|
if(!level.isClientSide) {
|
||||||
val screenState = level.getBlockEntity(blockPos, BlockEntities.SCREEN_ENTITY.get()).get()
|
|
||||||
if(!screenState.deviceNode.consumeEnergy(ENERGY)) {
|
|
||||||
player.sendSystemMessage(Component.literal("Not enough power."))
|
|
||||||
return InteractionResult.SUCCESS
|
|
||||||
};
|
|
||||||
val sp = player as ServerPlayer
|
val sp = player as ServerPlayer
|
||||||
val ent = level.getBlockEntity(blockPos, BlockEntities.SCREEN_ENTITY.get()).get()
|
val ent = level.getBlockEntity(blockPos, BlockEntities.SCREEN_ENTITY.get()).get()
|
||||||
NodeSynchronizer.registerPlayerScreen(sp, ent)
|
NodeSynchronizer.registerPlayerScreen(sp, ent.deviceNode)
|
||||||
MenuRegistry.openExtendedMenu(sp, object : ExtendedMenuProvider {
|
MenuRegistry.openExtendedMenu(sp, object : ExtendedMenuProvider {
|
||||||
override fun getDisplayName(): Component = Component.literal("SCREEEEEN!")
|
override fun getDisplayName(): Component = Component.literal("SCREEEEEN!")
|
||||||
override fun createMenu(i: Int, inventory: Inventory, player: Player): AbstractContainerMenu {
|
override fun createMenu(i: Int, inventory: Inventory, player: Player): AbstractContainerMenu {
|
||||||
|
|||||||
@@ -88,12 +88,11 @@ object BlockEntities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun registerPowerBlocks() {
|
fun registerPowerBlocks() {
|
||||||
// TODO: function for the new DeviceBlockEntity
|
PowerManager.registerPowerDevice(CAPACITOR_ENTITY.get())
|
||||||
//PowerManager.registerPowerBlockEntity(CAPACITOR_ENTITY.get())
|
PowerManager.registerPowerDevice(CAPACITOR2_ENTITY.get())
|
||||||
//PowerManager.registerPowerBlockEntity(CAPACITOR2_ENTITY.get())
|
PowerManager.registerPowerDevice(CAPACITOR3_ENTITY.get())
|
||||||
//PowerManager.registerPowerBlockEntity(CAPACITOR3_ENTITY.get())
|
PowerManager.registerPowerDevice(SOLARGEN_ENTITY.get())
|
||||||
PowerManager.registerPowerBlockEntity(SOLARGEN_ENTITY.get())
|
PowerManager.registerPowerDevice(COMBUSTGEN_ENTITY.get())
|
||||||
PowerManager.registerPowerBlockEntity(COMBUSTGEN_ENTITY.get())
|
PowerManager.registerPowerDevice(CASE_ENTITY.get())
|
||||||
PowerManager.registerPowerBlockEntity(CASE_ENTITY.get())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,15 +2,31 @@ package org.neoflock.neocomputers.entity
|
|||||||
|
|
||||||
import net.minecraft.core.BlockPos
|
import net.minecraft.core.BlockPos
|
||||||
import net.minecraft.core.Direction
|
import net.minecraft.core.Direction
|
||||||
|
import net.minecraft.network.FriendlyByteBuf
|
||||||
import net.minecraft.world.item.DyeColor
|
import net.minecraft.world.item.DyeColor
|
||||||
|
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
|
||||||
import org.neoflock.neocomputers.block.CableBlock
|
import org.neoflock.neocomputers.block.CableBlock
|
||||||
import org.neoflock.neocomputers.block.CableBlock.Companion.COLOR
|
import org.neoflock.neocomputers.block.CableBlock.Companion.COLOR
|
||||||
import org.neoflock.neocomputers.block.CableBlock.Companion.getPropByDirection
|
import org.neoflock.neocomputers.block.CableBlock.Companion.getPropByDirection
|
||||||
import org.neoflock.neocomputers.block.NodeBlockEntity
|
import org.neoflock.neocomputers.block.SingleDeviceBlockEntity
|
||||||
|
import org.neoflock.neocomputers.network.DeviceNode
|
||||||
|
|
||||||
class CableEntity(pos: BlockPos, state: BlockState) : BlockEntity(BlockEntities.CABLE_ENTITY.get(), pos, state) {
|
class CableEntity(pos: BlockPos, state: BlockState) : SingleDeviceBlockEntity(BlockEntities.CABLE_ENTITY.get(), pos, state) {
|
||||||
|
override val deviceNode = object : DeviceNode(){}
|
||||||
|
|
||||||
|
override fun sendCommitsToClient(level: Level) {
|
||||||
|
// we have nothing to commit lol
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getNodeFromSide(directionToRequester: Direction): DeviceNode? {
|
||||||
|
if(CableBlock.shouldConnect(blockPos, blockPos.relative(directionToRequester), level!!)) {
|
||||||
|
return deviceNode
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
override fun setChanged() {
|
override fun setChanged() {
|
||||||
super.setChanged()
|
super.setChanged()
|
||||||
|
|||||||
@@ -20,8 +20,7 @@ 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.NeoComputers
|
import org.neoflock.neocomputers.NeoComputers
|
||||||
import org.neoflock.neocomputers.block.CaseBlock
|
import org.neoflock.neocomputers.block.CaseBlock
|
||||||
import org.neoflock.neocomputers.block.NodeBlockEntity
|
import org.neoflock.neocomputers.block.SingleDeviceBlockEntity
|
||||||
import org.neoflock.neocomputers.block.NodeSynchronizer
|
|
||||||
import org.neoflock.neocomputers.gui.menu.CaseMenu
|
import org.neoflock.neocomputers.gui.menu.CaseMenu
|
||||||
import org.neoflock.neocomputers.item.ComponentItem
|
import org.neoflock.neocomputers.item.ComponentItem
|
||||||
import org.neoflock.neocomputers.network.DeviceNode
|
import org.neoflock.neocomputers.network.DeviceNode
|
||||||
@@ -33,8 +32,10 @@ import org.neoflock.neocomputers.utils.GenericContainer
|
|||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
import org.neoflock.neocomputers.network.NodeSynchronizer
|
||||||
|
import kotlin.text.ifEmpty
|
||||||
|
|
||||||
class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEntity(BlockEntities.CASE_ENTITY.get(), blockPos, blockState), MachineEntity, GenericContainer, MenuProvider {
|
class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): SingleDeviceBlockEntity(BlockEntities.CASE_ENTITY.get(), blockPos, blockState), MachineEntity, GenericContainer, MenuProvider {
|
||||||
val stacks: NonNullList<ItemStack> = NonNullList<ItemStack>.withSize(7, ItemStack.EMPTY)
|
val stacks: NonNullList<ItemStack> = NonNullList<ItemStack>.withSize(7, ItemStack.EMPTY)
|
||||||
|
|
||||||
var isOn = false
|
var isOn = false
|
||||||
@@ -47,26 +48,28 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
|
|||||||
override val deviceNode = object : DeviceNode() {
|
override val deviceNode = object : DeviceNode() {
|
||||||
override var powerRole = PowerRole.CONSUMER
|
override var powerRole = PowerRole.CONSUMER
|
||||||
override var energyCapacity: Long = 500
|
override var energyCapacity: Long = 500
|
||||||
|
|
||||||
|
override fun writeFullStateCommit(buf: FriendlyByteBuf) {
|
||||||
|
super.writeFullStateCommit(buf)
|
||||||
|
buf.writeUUID(address)
|
||||||
|
buf.writeBoolean(isOn)
|
||||||
|
buf.writeVarInt(diskActivityTime)
|
||||||
|
buf.writeVarInt(networkActivityTime)
|
||||||
|
buf.writeUtf(err ?: "")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun encodeDownstreamData(packet: FriendlyByteBuf) {
|
override fun processCommit(buf: FriendlyByteBuf) {
|
||||||
super.encodeDownstreamData(packet)
|
super.processCommit(buf)
|
||||||
packet.writeBoolean(isOn)
|
Networking.changeNodeAddress(this, buf.readUUID())
|
||||||
packet.writeVarInt(diskActivityTime)
|
setRunning(buf.readBoolean())
|
||||||
packet.writeVarInt(networkActivityTime)
|
diskActivityTime = buf.readVarInt()
|
||||||
packet.writeUtf(err ?: "")
|
networkActivityTime = buf.readVarInt()
|
||||||
|
err = buf.readUtf().ifEmpty { null }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun syncWithUpstream(packet: FriendlyByteBuf) {
|
override fun processScreenInteraction(player: ServerPlayer, buf: FriendlyByteBuf) {
|
||||||
super.syncWithUpstream(packet)
|
super.processScreenInteraction(player, buf)
|
||||||
setRunning(packet.readBoolean())
|
val c = buf.readByte().toInt()
|
||||||
diskActivityTime = packet.readVarInt()
|
|
||||||
networkActivityTime = packet.readVarInt()
|
|
||||||
err = packet.readUtf().ifEmpty { null }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun processScreenInteraction(player: ServerPlayer, packet: FriendlyByteBuf) {
|
|
||||||
val c = packet.readByte().toInt()
|
|
||||||
if(c == 0x01) {
|
if(c == 0x01) {
|
||||||
start()
|
start()
|
||||||
}
|
}
|
||||||
@@ -75,17 +78,33 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun encodeScreenData(player: ServerPlayer, packet: FriendlyByteBuf) {
|
override fun encodeScreenData(player: ServerPlayer, buf: FriendlyByteBuf) {
|
||||||
super.encodeScreenData(player, packet)
|
super.encodeScreenData(player, buf)
|
||||||
packet.writeBoolean(isOn)
|
buf.writeBoolean(isOn)
|
||||||
packet.writeByteArray((err ?: "").encodeToByteArray())
|
buf.writeByteArray((err ?: "").encodeToByteArray())
|
||||||
packet.writeLong(deviceNode.energy)
|
buf.writeLong(energy)
|
||||||
packet.writeLong(deviceNode.energyCapacity)
|
buf.writeLong(energyCapacity)
|
||||||
packet.writeLong(getMachineMemoryUsed())
|
buf.writeLong(getMachineMemoryUsed())
|
||||||
packet.writeLong(getMachineMemoryTotal())
|
buf.writeLong(getMachineMemoryTotal())
|
||||||
packet.writeLong(getMachineComponentsUsed())
|
buf.writeLong(getMachineComponentsUsed())
|
||||||
packet.writeLong(getMachineComponentsTotal())
|
buf.writeLong(getMachineComponentsTotal())
|
||||||
packet.writeUtf(arch)
|
buf.writeUtf(arch)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun tick() {
|
||||||
|
super.tick()
|
||||||
|
if (isRunning()) {
|
||||||
|
if(diskActivityTime > 0) diskActivityTime--
|
||||||
|
if(networkActivityTime > 0) networkActivityTime--
|
||||||
|
if(getMachineArchitectures().isEmpty()) {
|
||||||
|
crash("@neocomputers.errors.ENOCPU")
|
||||||
|
} else if(getMachineComponentsUsed() > getMachineComponentsTotal()) {
|
||||||
|
crash("@neocomputers.errors.E2BIG")
|
||||||
|
} else if (!consumeEnergy(1)) {
|
||||||
|
crash("@neocomputers.errors.ENOENJ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val redstoneIn = Array(Direction.entries.size) {0}
|
val redstoneIn = Array(Direction.entries.size) {0}
|
||||||
@@ -154,9 +173,9 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
|
|||||||
override fun start(): Boolean {
|
override fun start(): Boolean {
|
||||||
if(isOn) return true
|
if(isOn) return true
|
||||||
err = null
|
err = null
|
||||||
val archs = getMachineArchitectures()
|
val architectures = getMachineArchitectures()
|
||||||
// Beep patterns taken from https://github.com/MightyPirates/OpenComputers/blob/571482db88080d56329e8f8cf0db2a90825bf1d7/src/main/scala/li/cil/oc/server/machine/Machine.scala
|
// Beep patterns taken from https://github.com/MightyPirates/OpenComputers/blob/571482db88080d56329e8f8cf0db2a90825bf1d7/src/main/scala/li/cil/oc/server/machine/Machine.scala
|
||||||
if(archs.isEmpty()) {
|
if(architectures.isEmpty()) {
|
||||||
crash("@neocomputers.errors.ENOCPU")
|
crash("@neocomputers.errors.ENOCPU")
|
||||||
beepAsync("-..")
|
beepAsync("-..")
|
||||||
return false
|
return false
|
||||||
@@ -178,9 +197,9 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
|
|||||||
beepAsync("-.")
|
beepAsync("-.")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if(arch !in archs) {
|
if(arch !in architectures) {
|
||||||
// Just pick one! TODO: consult EEPROM first
|
// Just pick one! TODO: consult EEPROM first
|
||||||
arch = archs.first()
|
arch = architectures.first()
|
||||||
}
|
}
|
||||||
beepAsync(".")
|
beepAsync(".")
|
||||||
setRunning(true)
|
setRunning(true)
|
||||||
@@ -194,10 +213,8 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun crash(error: String): Boolean {
|
override fun crash(error: String): Boolean {
|
||||||
if(isOn) {
|
|
||||||
beepAsync("--")
|
beepAsync("--")
|
||||||
sendMachineEvent(MachineCrashEvent(this, error))
|
sendMachineEvent(MachineCrashEvent(this, error))
|
||||||
}
|
|
||||||
setRunning(false)
|
setRunning(false)
|
||||||
err = error
|
err = error
|
||||||
return true
|
return true
|
||||||
@@ -271,21 +288,4 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
|
|||||||
setRunning(false)
|
setRunning(false)
|
||||||
super.setRemoved()
|
super.setRemoved()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tickNode(level: Level) {
|
|
||||||
super.tickNode(level)
|
|
||||||
if(!level.isClientSide) {
|
|
||||||
if (isRunning()) {
|
|
||||||
if(diskActivityTime > 0) diskActivityTime--
|
|
||||||
if(networkActivityTime > 0) networkActivityTime--
|
|
||||||
if(getMachineArchitectures().isEmpty()) {
|
|
||||||
crash("@neocomputers.errors.ENOCPU")
|
|
||||||
} else if(getMachineComponentsUsed() > getMachineComponentsTotal()) {
|
|
||||||
crash("@neocomputers.errors.E2BIG")
|
|
||||||
} else if (!deviceNode.consumeEnergy(1)) {
|
|
||||||
crash("@neocomputers.errors.ENOENJ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.neoflock.neocomputers.entity
|
package org.neoflock.neocomputers.entity
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos
|
import net.minecraft.core.BlockPos
|
||||||
|
import net.minecraft.core.Direction
|
||||||
import net.minecraft.core.HolderLookup
|
import net.minecraft.core.HolderLookup
|
||||||
import net.minecraft.core.NonNullList
|
import net.minecraft.core.NonNullList
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.CompoundTag
|
||||||
@@ -15,16 +16,15 @@ import net.minecraft.world.item.ItemStack
|
|||||||
import net.minecraft.world.level.Level
|
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.CombustionGeneratorBlock
|
import org.neoflock.neocomputers.block.CombustionGeneratorBlock
|
||||||
import org.neoflock.neocomputers.block.NodeBlockEntity
|
import org.neoflock.neocomputers.block.SingleDeviceBlockEntity
|
||||||
import org.neoflock.neocomputers.gui.menu.CombustionGeneratorMenu
|
import org.neoflock.neocomputers.gui.menu.CombustionGeneratorMenu
|
||||||
import org.neoflock.neocomputers.network.DeviceNode
|
import org.neoflock.neocomputers.network.DeviceNode
|
||||||
import org.neoflock.neocomputers.network.Networking
|
|
||||||
import org.neoflock.neocomputers.network.PowerRole
|
import org.neoflock.neocomputers.network.PowerRole
|
||||||
import org.neoflock.neocomputers.utils.GenericContainer
|
import org.neoflock.neocomputers.utils.GenericContainer
|
||||||
import org.neoflock.neocomputers.utils.ContainerUtils
|
import org.neoflock.neocomputers.utils.ContainerUtils
|
||||||
import kotlin.math.min
|
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) : SingleDeviceBlockEntity(BlockEntities.COMBUSTGEN_ENTITY.get(), blockPos, blockState), GenericContainer, MenuProvider {
|
||||||
val energyPerTick: Long = 50
|
val energyPerTick: Long = 50
|
||||||
|
|
||||||
var burningTimeRemaining: Int = 0
|
var burningTimeRemaining: Int = 0
|
||||||
@@ -32,6 +32,11 @@ class CombustionGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
|||||||
override val deviceNode = object : DeviceNode() {
|
override val deviceNode = object : DeviceNode() {
|
||||||
override var powerRole = PowerRole.GENERATOR
|
override var powerRole = PowerRole.GENERATOR
|
||||||
override var energyCapacity: Long = 100000
|
override var energyCapacity: Long = 100000
|
||||||
|
|
||||||
|
override fun encodeScreenData(player: ServerPlayer, buf: FriendlyByteBuf) {
|
||||||
|
buf.writeLong(energy)
|
||||||
|
buf.writeLong(energyCapacity)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val stacks: NonNullList<ItemStack> = NonNullList<ItemStack>.withSize(1, ItemStack.EMPTY)
|
val stacks: NonNullList<ItemStack> = NonNullList<ItemStack>.withSize(1, ItemStack.EMPTY)
|
||||||
@@ -46,8 +51,8 @@ class CombustionGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
|||||||
return !this.isRemoved
|
return !this.isRemoved
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tickNode(level: Level) {
|
override fun tickDevice(level: Level) {
|
||||||
super.tickNode(level)
|
super.tickDevice(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
|
||||||
@@ -79,11 +84,6 @@ class CombustionGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
|||||||
level?.setBlockAndUpdate(blockPos, blockState.setValue(CombustionGeneratorBlock.COMBUSTGEN_ACTIVE, burningTimeRemaining > 0))
|
level?.setBlockAndUpdate(blockPos, blockState.setValue(CombustionGeneratorBlock.COMBUSTGEN_ACTIVE, burningTimeRemaining > 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun encodeScreenData(player: ServerPlayer, packet: FriendlyByteBuf) {
|
|
||||||
packet.writeLong(deviceNode.energy)
|
|
||||||
packet.writeLong(deviceNode.energyCapacity)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun loadAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
|
override fun loadAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
|
||||||
super.loadAdditional(compoundTag, provider)
|
super.loadAdditional(compoundTag, provider)
|
||||||
deviceNode.energy = min(deviceNode.energyCapacity, compoundTag.getLong("energy"))
|
deviceNode.energy = min(deviceNode.energyCapacity, compoundTag.getLong("energy"))
|
||||||
|
|||||||
@@ -1,38 +1,66 @@
|
|||||||
package org.neoflock.neocomputers.entity;
|
package org.neoflock.neocomputers.entity;
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos
|
import net.minecraft.core.BlockPos
|
||||||
|
import net.minecraft.locale.Language
|
||||||
import net.minecraft.network.FriendlyByteBuf
|
import net.minecraft.network.FriendlyByteBuf
|
||||||
import net.minecraft.resources.ResourceLocation
|
import net.minecraft.resources.ResourceLocation
|
||||||
import net.minecraft.server.level.ServerPlayer
|
import net.minecraft.server.level.ServerPlayer
|
||||||
import net.minecraft.world.level.Level
|
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.NeoComputers
|
import org.neoflock.neocomputers.NeoComputers
|
||||||
import org.neoflock.neocomputers.block.NodeBlockEntity
|
import org.neoflock.neocomputers.block.SingleDeviceBlockEntity
|
||||||
import org.neoflock.neocomputers.gui.buffer.BufferRenderer
|
import org.neoflock.neocomputers.gui.buffer.BufferRenderer
|
||||||
import org.neoflock.neocomputers.network.DeviceNode
|
import org.neoflock.neocomputers.network.DeviceNode
|
||||||
import org.neoflock.neocomputers.network.Networking
|
import org.neoflock.neocomputers.network.Networking
|
||||||
import org.neoflock.neocomputers.utils.GPUChar
|
import org.neoflock.neocomputers.utils.GPUChar
|
||||||
import org.neoflock.neocomputers.utils.TextBuffer
|
import org.neoflock.neocomputers.utils.TextBuffer
|
||||||
|
import kotlin.text.ifEmpty
|
||||||
|
|
||||||
class ScreenEntity(blockPos: BlockPos, blockState: BlockState) :
|
class ScreenEntity(blockPos: BlockPos, blockState: BlockState) :
|
||||||
NodeBlockEntity(BlockEntities.SCREEN_ENTITY.get(), blockPos, blockState) {
|
SingleDeviceBlockEntity(BlockEntities.SCREEN_ENTITY.get(), blockPos, blockState) {
|
||||||
|
|
||||||
|
var lastError: String? = null
|
||||||
|
var isOn: Boolean = false
|
||||||
|
|
||||||
override val deviceNode = object : DeviceNode() {
|
override val deviceNode = object : DeviceNode() {
|
||||||
override fun received(message: Networking.Message) {
|
override fun received(message: Networking.Message) {
|
||||||
super.received(message)
|
super.received(message)
|
||||||
if(message is Networking.ComputerEvent) {
|
if(message is Networking.ComputerEvent) {
|
||||||
// return if not directly connected
|
|
||||||
if(message.sender !in this.connections) return
|
|
||||||
val mEnv = message.machineEvent
|
val mEnv = message.machineEvent
|
||||||
NeoComputers.LOGGER.info("Got message $mEnv!")
|
NeoComputers.LOGGER.info("Got message $mEnv!")
|
||||||
if(mEnv is MachinePowerEvent) {
|
if(mEnv is MachinePowerEvent) {
|
||||||
if(mEnv.nowRunning) {
|
if(mEnv.nowRunning) {
|
||||||
textBuf.set(0, 0, address.toString())
|
lastError = null
|
||||||
} else {
|
|
||||||
textBuf.fill(0, 0, textBuf.width, textBuf.height, GPUChar(' '))
|
textBuf.fill(0, 0, textBuf.width, textBuf.height, GPUChar(' '))
|
||||||
|
textBuf.set(0, 0, address.toString())
|
||||||
|
}
|
||||||
|
isOn = mEnv.nowRunning
|
||||||
|
}
|
||||||
|
if(mEnv is MachineCrashEvent) {
|
||||||
|
lastError = mEnv.error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun encodeScreenData(player: ServerPlayer, buf: FriendlyByteBuf) {
|
||||||
|
super.encodeScreenData(player, buf)
|
||||||
|
textBuf.encodeContents(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeFullStateCommit(buf: FriendlyByteBuf) {
|
||||||
|
super.writeFullStateCommit(buf)
|
||||||
|
buf.writeUUID(address)
|
||||||
|
buf.writeBoolean(isOn)
|
||||||
|
buf.writeUtf(lastError ?: "")
|
||||||
|
textBuf.encodeContents(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun processCommit(buf: FriendlyByteBuf) {
|
||||||
|
super.processCommit(buf)
|
||||||
|
if(Networking.changeNodeAddress(this, buf.readUUID())) createscreenstuffs()
|
||||||
|
isOn = buf.readBoolean()
|
||||||
|
lastError = buf.readUtf().ifEmpty { null }
|
||||||
|
textBuf.decodeContents(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var bound = "screen/unbound"
|
var bound = "screen/unbound"
|
||||||
@@ -41,23 +69,8 @@ class ScreenEntity(blockPos: BlockPos, blockState: BlockState) :
|
|||||||
|
|
||||||
private var cleanrenderer: () -> Unit = { }; // TODO: THIS SUCKS, FIND A BETTER WAY
|
private var cleanrenderer: () -> Unit = { }; // TODO: THIS SUCKS, FIND A BETTER WAY
|
||||||
|
|
||||||
override fun encodeDownstreamData(packet: FriendlyByteBuf) {
|
override fun tickDevice(level: Level) {
|
||||||
super.encodeDownstreamData(packet)
|
super.tickDevice(level)
|
||||||
textBuf.encodeContents(packet)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun syncWithUpstream(packet: FriendlyByteBuf) {
|
|
||||||
super.syncWithUpstream(packet)
|
|
||||||
textBuf.decodeContents(packet)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun encodeScreenData(player: ServerPlayer, packet: FriendlyByteBuf) {
|
|
||||||
super.encodeScreenData(player, packet)
|
|
||||||
textBuf.encodeContents(packet)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun tickNode(level: Level) {
|
|
||||||
super.tickNode(level)
|
|
||||||
cleanrenderer()
|
cleanrenderer()
|
||||||
createscreenstuffs()
|
createscreenstuffs()
|
||||||
}
|
}
|
||||||
@@ -71,9 +84,29 @@ class ScreenEntity(blockPos: BlockPos, blockState: BlockState) :
|
|||||||
private fun createscreenstuffs() {
|
private fun createscreenstuffs() {
|
||||||
bound = "screen/"+deviceNode.address.toString().replace("-", "_")
|
bound = "screen/"+deviceNode.address.toString().replace("-", "_")
|
||||||
if (level!!.isClientSide) {
|
if (level!!.isClientSide) {
|
||||||
|
if(lastError == null) {
|
||||||
|
if(!isOn) {
|
||||||
|
textBuf.fill(0, 0, textBuf.width, textBuf.height)
|
||||||
|
}
|
||||||
var renderer = BufferRenderer(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, bound), textBuf)
|
var renderer = BufferRenderer(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, bound), textBuf)
|
||||||
renderer.drawBuffer()
|
renderer.drawBuffer()
|
||||||
cleanrenderer = { renderer.clean() }
|
cleanrenderer = { renderer.clean() }
|
||||||
|
} else {
|
||||||
|
var trueError = lastError!!
|
||||||
|
if(trueError.startsWith("@")) {
|
||||||
|
val trans = trueError.substring(1)
|
||||||
|
val lang = Language.getInstance()
|
||||||
|
trueError = lang.getOrDefault("neocomputers.computer.errorNoMsg", "Error: ") + lang.getOrDefault(trans)
|
||||||
|
}
|
||||||
|
val throwAwayBuf = TextBuffer(50, 16)
|
||||||
|
val fg = 0xFFFFFF
|
||||||
|
val bg = 0x2B68A6
|
||||||
|
throwAwayBuf.fill(0, 0, throwAwayBuf.width, throwAwayBuf.height, GPUChar(' ', fg, bg))
|
||||||
|
throwAwayBuf.set((throwAwayBuf.width - trueError.length) / 2, throwAwayBuf.height/2, trueError, fg, bg)
|
||||||
|
var renderer = BufferRenderer(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, bound), throwAwayBuf)
|
||||||
|
renderer.drawBuffer()
|
||||||
|
cleanrenderer = { renderer.clean() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
package org.neoflock.neocomputers.entity
|
package org.neoflock.neocomputers.entity
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos
|
import net.minecraft.core.BlockPos
|
||||||
|
import net.minecraft.core.Direction
|
||||||
import net.minecraft.core.HolderLookup
|
import net.minecraft.core.HolderLookup
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.CompoundTag
|
||||||
import net.minecraft.world.level.Level
|
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.SingleDeviceBlockEntity
|
||||||
import org.neoflock.neocomputers.network.DeviceNode
|
import org.neoflock.neocomputers.network.DeviceNode
|
||||||
import org.neoflock.neocomputers.network.Networking
|
|
||||||
import org.neoflock.neocomputers.network.PowerRole
|
import org.neoflock.neocomputers.network.PowerRole
|
||||||
|
|
||||||
class SolarGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState) : NodeBlockEntity(BlockEntities.SOLARGEN_ENTITY.get(), blockPos, blockState) {
|
class SolarGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState) : SingleDeviceBlockEntity(BlockEntities.SOLARGEN_ENTITY.get(), blockPos, blockState) {
|
||||||
val energyPerTick: Long = 50
|
val energyPerTick: Long = 50
|
||||||
|
|
||||||
override val deviceNode = object : DeviceNode() {
|
override val deviceNode = object : DeviceNode() {
|
||||||
@@ -18,8 +18,8 @@ class SolarGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState) : No
|
|||||||
override var energyCapacity: Long = 50000
|
override var energyCapacity: Long = 50000
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tickNode(level: Level) {
|
override fun tickDevice(level: Level) {
|
||||||
super.tickNode(level)
|
super.tickDevice(level)
|
||||||
val l = level
|
val l = level
|
||||||
if(l.isDay) {
|
if(l.isDay) {
|
||||||
deviceNode.giveEnergy(energyPerTick)
|
deviceNode.giveEnergy(energyPerTick)
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ class ScreenEntityRenderer(val context: BlockEntityRendererProvider.Context?) :
|
|||||||
.createCompositeState(false))
|
.createCompositeState(false))
|
||||||
}
|
}
|
||||||
override fun render(entity: ScreenEntity, partialTick: Float, mat: PoseStack, bufferSource: MultiBufferSource, packedLight: Int, packedOverlay: Int) {
|
override fun render(entity: ScreenEntity, partialTick: Float, mat: PoseStack, bufferSource: MultiBufferSource, packedLight: Int, packedOverlay: Int) {
|
||||||
|
if(!entity.isOn && entity.lastError == null) return
|
||||||
val facing = entity.blockState.getValue(ScreenBlock.FACING_HORIZ)
|
val facing = entity.blockState.getValue(ScreenBlock.FACING_HORIZ)
|
||||||
val vert = entity.blockState.getValue(ScreenBlock.FACING_VERTI)-1
|
val vert = entity.blockState.getValue(ScreenBlock.FACING_VERTI)-1
|
||||||
|
|
||||||
|
|||||||
@@ -26,15 +26,11 @@ class BufferRenderer(private var id: ResourceLocation, private var buffer: TextB
|
|||||||
Minecraft.getInstance().textureManager.register(this.id, tex)
|
Minecraft.getInstance().textureManager.register(this.id, tex)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun dump(path: String) {
|
fun toRGBA(color: Int): Int {
|
||||||
image.writeToFile(File(path))
|
// Minecaft lies, its AGBR
|
||||||
NeoComputers.LOGGER.info("DUMPED!!!")
|
return java.lang.Integer.reverseBytes((color.toLong() * 256 + 0xFF).toInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
// fun toRGBA(color: Int): Int {
|
|
||||||
// return color.shl(8).or(0xFF)
|
|
||||||
// }
|
|
||||||
|
|
||||||
fun drawGlyph(x: Int, y: Int, c: Char, fg: Int) {
|
fun drawGlyph(x: Int, y: Int, c: Char, fg: Int) {
|
||||||
var glyph: ArrayList<Byte> = FontProvider.map[c]!!
|
var glyph: ArrayList<Byte> = FontProvider.map[c]!!
|
||||||
|
|
||||||
@@ -42,7 +38,7 @@ class BufferRenderer(private var id: ResourceLocation, private var buffer: TextB
|
|||||||
for (i in 0..<CHARW) {
|
for (i in 0..<CHARW) {
|
||||||
// var pixel = ((glyph[j] and ((1 shl (CHARW - i - 1)).toByte())).toInt()) ushr (CHARW - i - 1) // retardation
|
// var pixel = ((glyph[j] and ((1 shl (CHARW - i - 1)).toByte())).toInt()) ushr (CHARW - i - 1) // retardation
|
||||||
var pixel = (glyph[j] and (0b10000000 ushr i).toByte()).toInt()
|
var pixel = (glyph[j] and (0b10000000 ushr i).toByte()).toInt()
|
||||||
if (pixel > 0) image.setPixelRGBA(x+i, y+j, 0xFF000000.toInt()+fg)
|
if (pixel > 0) image.setPixelRGBA(x+i, y+j, toRGBA(fg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,7 +49,7 @@ class BufferRenderer(private var id: ResourceLocation, private var buffer: TextB
|
|||||||
var char: GPUChar = buffer.get(i, j)
|
var char: GPUChar = buffer.get(i, j)
|
||||||
var x = i*CHARW
|
var x = i*CHARW
|
||||||
var y = j*CHARH
|
var y = j*CHARH
|
||||||
image.fillRect(x, y, CHARW, CHARH, (0xFF000000+char.bg).toInt())
|
image.fillRect(x, y, CHARW, CHARH, toRGBA(char.bg))
|
||||||
if (char.c != ' ' && char.c != '\u0000') drawGlyph(x, y, char.c, char.fg)
|
if (char.c != ' ' && char.c != '\u0000') drawGlyph(x, y, char.c, char.fg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import net.minecraft.world.entity.player.Inventory
|
|||||||
import net.minecraft.world.inventory.tooltip.TooltipComponent
|
import net.minecraft.world.inventory.tooltip.TooltipComponent
|
||||||
import net.minecraft.world.phys.Vec3
|
import net.minecraft.world.phys.Vec3
|
||||||
import org.neoflock.neocomputers.NeoComputers
|
import org.neoflock.neocomputers.NeoComputers
|
||||||
import org.neoflock.neocomputers.block.NodeSynchronizer
|
import org.neoflock.neocomputers.network.NodeSynchronizer
|
||||||
import org.neoflock.neocomputers.gui.menu.CaseMenu
|
import org.neoflock.neocomputers.gui.menu.CaseMenu
|
||||||
import org.neoflock.neocomputers.gui.widget.ButtonSprites
|
import org.neoflock.neocomputers.gui.widget.ButtonSprites
|
||||||
import org.neoflock.neocomputers.gui.widget.ImagerButton
|
import org.neoflock.neocomputers.gui.widget.ImagerButton
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ class ScreenScreen : GenericContainerScreen<ScreenMenu>{
|
|||||||
|
|
||||||
var textBuf = TextBuffer(0, 0)
|
var textBuf = TextBuffer(0, 0)
|
||||||
|
|
||||||
|
override fun shouldCenterTitle(): Boolean = false
|
||||||
|
|
||||||
override fun processScreenStatePacket(buf: FriendlyByteBuf) {
|
override fun processScreenStatePacket(buf: FriendlyByteBuf) {
|
||||||
super.processScreenStatePacket(buf)
|
super.processScreenStatePacket(buf)
|
||||||
textBuf.decodeContents(buf)
|
textBuf.decodeContents(buf)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.neoflock.neocomputers.network
|
|||||||
|
|
||||||
import net.minecraft.core.BlockPos
|
import net.minecraft.core.BlockPos
|
||||||
import net.minecraft.network.FriendlyByteBuf
|
import net.minecraft.network.FriendlyByteBuf
|
||||||
|
import net.minecraft.server.level.ServerPlayer
|
||||||
import org.neoflock.neocomputers.NeoComputers
|
import org.neoflock.neocomputers.NeoComputers
|
||||||
import org.neoflock.neocomputers.network.Networking.Message
|
import org.neoflock.neocomputers.network.Networking.Message
|
||||||
import org.neoflock.neocomputers.network.Networking.Visibility
|
import org.neoflock.neocomputers.network.Networking.Visibility
|
||||||
@@ -215,7 +216,8 @@ open class DeviceNode(_address: UUID? = null) {
|
|||||||
outOfSync = true
|
outOfSync = true
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun encodeScreenData(buf: FriendlyByteBuf) {}
|
open fun encodeScreenData(player: ServerPlayer, buf: FriendlyByteBuf) {}
|
||||||
|
open fun processScreenInteraction(player: ServerPlayer, buf: FriendlyByteBuf) {}
|
||||||
|
|
||||||
// Meant to write the entire state as a single commit
|
// Meant to write the entire state as a single commit
|
||||||
// for clients which say they have no fucking idea what the server is storing
|
// for clients which say they have no fucking idea what the server is storing
|
||||||
|
|||||||
@@ -85,12 +85,14 @@ object Networking {
|
|||||||
fun getNode(address: UUID): DeviceNode? = allNodes.get()[address]
|
fun getNode(address: UUID): DeviceNode? = allNodes.get()[address]
|
||||||
|
|
||||||
// TODO: use setter, more convenient
|
// TODO: use setter, more convenient
|
||||||
fun changeNodeAddress(deviceNode: DeviceNode, address: UUID) {
|
fun changeNodeAddress(deviceNode: DeviceNode, address: UUID): Boolean {
|
||||||
if(deviceNode.address.equals(address)) return
|
if(deviceNode.address.equals(address)) return false
|
||||||
if(deviceNode.address !in allNodes.get()) return
|
if(deviceNode.address !in allNodes.get()) return false
|
||||||
|
if(address in allNodes.get()) return false
|
||||||
allNodes.get().remove(deviceNode.address)
|
allNodes.get().remove(deviceNode.address)
|
||||||
deviceNode.address = address
|
deviceNode.address = address
|
||||||
allNodes.get()[address] = deviceNode
|
allNodes.get()[address] = deviceNode
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addNode(deviceNode: DeviceNode) {
|
fun addNode(deviceNode: DeviceNode) {
|
||||||
@@ -103,12 +105,17 @@ object Networking {
|
|||||||
allNodes.get().forEach { it.value.onNodeAdded(deviceNode) }
|
allNodes.get().forEach { it.value.onNodeAdded(deviceNode) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addNodes(vararg deviceNodes: DeviceNode) {
|
fun addNodes(deviceNodes: Iterable<DeviceNode>) {
|
||||||
deviceNodes.forEach { addNode(it) }
|
deviceNodes.forEach { addNode(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun addNodes(vararg deviceNodes: DeviceNode) {
|
||||||
|
addNodes(deviceNodes.asIterable())
|
||||||
|
}
|
||||||
|
|
||||||
fun removeNode(deviceNode: DeviceNode) {
|
fun removeNode(deviceNode: DeviceNode) {
|
||||||
if(deviceNode.address !in allNodes.get()) return
|
if(deviceNode.address !in allNodes.get()) return
|
||||||
|
NodeSynchronizer.nodeErased(deviceNode)
|
||||||
allNodes.get().forEach { it.value.onNodeRemoved(deviceNode) }
|
allNodes.get().forEach { it.value.onNodeRemoved(deviceNode) }
|
||||||
// toList() in order to copy it
|
// toList() in order to copy it
|
||||||
deviceNode.connections.toList().forEach {
|
deviceNode.connections.toList().forEach {
|
||||||
@@ -121,10 +128,14 @@ object Networking {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeNodes(vararg deviceNodes: DeviceNode) {
|
fun removeNodes(deviceNodes: Iterable<DeviceNode>) {
|
||||||
deviceNodes.forEach { removeNode(it) }
|
deviceNodes.forEach { removeNode(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun removeNodes(vararg deviceNodes: DeviceNode) {
|
||||||
|
removeNodes(deviceNodes.asIterable())
|
||||||
|
}
|
||||||
|
|
||||||
val channels = ThreadLocal.withInitial { HashMap<String, MutableSet<DeviceNode>>() }
|
val channels = ThreadLocal.withInitial { HashMap<String, MutableSet<DeviceNode>>() }
|
||||||
|
|
||||||
fun addToChannel(channel: String, deviceNode: DeviceNode) {
|
fun addToChannel(channel: String, deviceNode: DeviceNode) {
|
||||||
|
|||||||
@@ -0,0 +1,150 @@
|
|||||||
|
package org.neoflock.neocomputers.network
|
||||||
|
|
||||||
|
import dev.architectury.networking.NetworkManager
|
||||||
|
import io.netty.buffer.Unpooled
|
||||||
|
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.level.Level
|
||||||
|
import org.neoflock.neocomputers.NeoComputers
|
||||||
|
import java.time.Duration
|
||||||
|
|
||||||
|
object NodeSynchronizer {
|
||||||
|
class DeviceBlockStatePayload(var blockPos: BlockPos, var buffers: List<FriendlyByteBuf>): CustomPacketPayload {
|
||||||
|
companion object {
|
||||||
|
val NODE_SYNC_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "node_sync")
|
||||||
|
val TYPE = CustomPacketPayload.Type<DeviceBlockStatePayload>(NODE_SYNC_ID)
|
||||||
|
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, DeviceBlockStatePayload> {
|
||||||
|
override fun decode(buf: RegistryFriendlyByteBuf): DeviceBlockStatePayload {
|
||||||
|
val blockPos = buf.readBlockPos()
|
||||||
|
val bufferCount = buf.readVarInt()
|
||||||
|
val buffers = List(bufferCount) {
|
||||||
|
val bytes = buf.readByteArray()
|
||||||
|
val rawBuf = Unpooled.buffer(bytes.size)
|
||||||
|
rawBuf.writeBytes(bytes)
|
||||||
|
FriendlyByteBuf(rawBuf)
|
||||||
|
}
|
||||||
|
return DeviceBlockStatePayload(blockPos, buffers)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun encode(buf: RegistryFriendlyByteBuf, payload: DeviceBlockStatePayload) {
|
||||||
|
buf.writeBlockPos(payload.blockPos)
|
||||||
|
buf.writeVarInt(payload.buffers.size)
|
||||||
|
payload.buffers.forEach {
|
||||||
|
buf.writeByteArray(it.array())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun type() = TYPE
|
||||||
|
}
|
||||||
|
|
||||||
|
class ScreenPayload(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 buffer = FriendlyByteBuf(buf.copy(buf.readerIndex(), buf.readableBytes()))
|
||||||
|
return ScreenPayload(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun encode(buf: RegistryFriendlyByteBuf, payload: ScreenPayload) {
|
||||||
|
buf.writeBytes(payload.buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun type() = TYPE
|
||||||
|
}
|
||||||
|
|
||||||
|
class ScreenDataPayload(var buffer: FriendlyByteBuf): CustomPacketPayload {
|
||||||
|
companion object {
|
||||||
|
val SCREEN_DATA_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "screen_data")
|
||||||
|
val TYPE = CustomPacketPayload.Type<ScreenDataPayload>(SCREEN_DATA_ID)
|
||||||
|
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, ScreenDataPayload> {
|
||||||
|
override fun decode(buf: RegistryFriendlyByteBuf): ScreenDataPayload {
|
||||||
|
val buffer = FriendlyByteBuf(buf.copy(buf.readerIndex(), buf.readableBytes()))
|
||||||
|
return ScreenDataPayload(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun encode(buf: RegistryFriendlyByteBuf, payload: ScreenDataPayload) {
|
||||||
|
buf.writeBytes(payload.buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun type() = TYPE
|
||||||
|
}
|
||||||
|
|
||||||
|
class BeepDataPayload(val pos: BlockPos, val pattern: String, val freq: Int, val duration: Duration, val volume: Double): CustomPacketPayload {
|
||||||
|
companion object {
|
||||||
|
val BEEP_DATA_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "beep_data")
|
||||||
|
val TYPE = CustomPacketPayload.Type<BeepDataPayload>(BEEP_DATA_ID)
|
||||||
|
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, BeepDataPayload> {
|
||||||
|
override fun decode(buf: RegistryFriendlyByteBuf): BeepDataPayload {
|
||||||
|
val pos = buf.readBlockPos()
|
||||||
|
val pattern = buf.readUtf()
|
||||||
|
val freq = buf.readVarInt()
|
||||||
|
val duration = buf.readVarLong()
|
||||||
|
val volume = buf.readDouble()
|
||||||
|
return BeepDataPayload(pos, pattern, freq, Duration.ofMillis(duration), volume)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun encode(buf: RegistryFriendlyByteBuf, payload: BeepDataPayload) {
|
||||||
|
buf.writeBlockPos(payload.pos)
|
||||||
|
buf.writeUtf(payload.pattern)
|
||||||
|
buf.writeVarInt(payload.freq)
|
||||||
|
buf.writeVarLong(payload.duration.toMillis())
|
||||||
|
buf.writeDouble(payload.volume)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun type() = TYPE
|
||||||
|
}
|
||||||
|
|
||||||
|
val screenMap = HashMap<ServerPlayer, DeviceNode>()
|
||||||
|
|
||||||
|
fun playerScreenClosed(player: ServerPlayer) {
|
||||||
|
screenMap.remove(player)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun registerPlayerScreen(player: ServerPlayer, devNode: DeviceNode) {
|
||||||
|
screenMap[player] = devNode
|
||||||
|
}
|
||||||
|
|
||||||
|
fun nodeErased(node: DeviceNode) {
|
||||||
|
var player: ServerPlayer? = null
|
||||||
|
for((p, n) in screenMap) {
|
||||||
|
if(n == node) player = p
|
||||||
|
}
|
||||||
|
if(player != null) screenMap.remove(player)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun syncScreens() {
|
||||||
|
for((player, ent) in screenMap) {
|
||||||
|
val buf = FriendlyByteBuf(Unpooled.buffer())
|
||||||
|
ent.encodeScreenData(player, buf)
|
||||||
|
NetworkManager.sendToPlayer(player, ScreenPayload(buf))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sendScreenInteraction(friendlyByteBuf: FriendlyByteBuf) {
|
||||||
|
NetworkManager.sendToServer(ScreenDataPayload(friendlyByteBuf))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun emitBeep(level: Level, beepDataPayload: BeepDataPayload) {
|
||||||
|
if(level is ServerLevel) {
|
||||||
|
level.players().forEach {
|
||||||
|
NetworkManager.sendToPlayer(it, beepDataPayload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
package org.neoflock.neocomputers.network
|
package org.neoflock.neocomputers.network
|
||||||
|
|
||||||
import net.minecraft.world.level.block.entity.BlockEntityType
|
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||||
|
import org.neoflock.neocomputers.block.DeviceBlockEntity
|
||||||
//? if fabric {
|
//? if fabric {
|
||||||
import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext
|
import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext
|
||||||
import org.neoflock.neocomputers.block.NodeBlockEntity
|
import net.minecraft.core.Direction
|
||||||
import team.reborn.energy.api.EnergyStorage;
|
import team.reborn.energy.api.EnergyStorage;
|
||||||
//?}
|
//?}
|
||||||
|
|
||||||
@@ -11,27 +12,30 @@ import team.reborn.energy.api.EnergyStorage;
|
|||||||
// the NodeBlockEntity and Node given us a way to get power from a block, we just
|
// the NodeBlockEntity and Node given us a way to get power from a block, we just
|
||||||
// need to tell mods how to do it as well
|
// need to tell mods how to do it as well
|
||||||
object PowerManager {
|
object PowerManager {
|
||||||
fun<T: NodeBlockEntity> registerPowerBlockEntity(blockEntityType: BlockEntityType<T>) {
|
fun<T: DeviceBlockEntity> registerPowerDevice(blockEntityType: BlockEntityType<T>) {
|
||||||
//? if fabric {
|
//? if fabric {
|
||||||
EnergyStorage.SIDED.registerForBlockEntity({
|
EnergyStorage.SIDED.registerForBlockEntity({
|
||||||
entity, dir -> object : EnergyStorage {
|
// TODO: as this is currently written, if the node instance changes and the mod cached the conversion, we're boned. Consider fixing it.
|
||||||
override fun getAmount() = entity.deviceNode.energy
|
entity, dir ->
|
||||||
override fun getCapacity() = entity.deviceNode.energyCapacity
|
val node = entity.getNodeFromSide(dir ?: Direction.UP)
|
||||||
override fun supportsExtraction() = entity.deviceNode.powerRole != PowerRole.CONSUMER && entity.deviceNode.energyCapacity > 0
|
if(node == null) null else object : EnergyStorage {
|
||||||
override fun supportsInsertion() = entity.deviceNode.powerRole != PowerRole.GENERATOR
|
override fun getAmount() = node.energy
|
||||||
|
override fun getCapacity() = node.energyCapacity
|
||||||
|
override fun supportsExtraction() = node.powerRole != PowerRole.CONSUMER && node.energyCapacity > 0
|
||||||
|
override fun supportsInsertion() = node.powerRole != PowerRole.GENERATOR
|
||||||
override fun extract(maxAmount: Long, transaction: TransactionContext?): Long {
|
override fun extract(maxAmount: Long, transaction: TransactionContext?): Long {
|
||||||
if(entity.deviceNode.powerRole == PowerRole.CONSUMER) return 0
|
if(node.powerRole == PowerRole.CONSUMER) return 0
|
||||||
val taken = entity.deviceNode.withdrawEnergy(maxAmount)
|
val taken = node.withdrawEnergy(maxAmount)
|
||||||
transaction?.addCloseCallback {
|
transaction?.addCloseCallback {
|
||||||
ctx, res -> if(res.wasAborted() || !res.wasCommitted()) entity.deviceNode.giveEnergy(taken)
|
ctx, res -> if(res.wasAborted() || !res.wasCommitted()) node.giveEnergy(taken)
|
||||||
}
|
}
|
||||||
return taken
|
return taken
|
||||||
}
|
}
|
||||||
override fun insert(maxAmount: Long, transaction: TransactionContext?): Long {
|
override fun insert(maxAmount: Long, transaction: TransactionContext?): Long {
|
||||||
if(entity.deviceNode.powerRole == PowerRole.GENERATOR) return 0
|
if(node.powerRole == PowerRole.GENERATOR) return 0
|
||||||
val given = entity.deviceNode.giveEnergy(maxAmount)
|
val given = node.giveEnergy(maxAmount)
|
||||||
transaction?.addCloseCallback { ctx, res ->
|
transaction?.addCloseCallback { ctx, res ->
|
||||||
if (res.wasAborted() || !res.wasCommitted()) entity.deviceNode.withdrawEnergy(given)
|
if (res.wasAborted() || !res.wasCommitted()) node.withdrawEnergy(given)
|
||||||
}
|
}
|
||||||
return given
|
return given
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 618 B After Width: | Height: | Size: 618 B |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 651 B After Width: | Height: | Size: 651 B |
|
Before Width: | Height: | Size: 389 B After Width: | Height: | Size: 389 B |