innovation

This commit is contained in:
2026-04-21 20:51:30 +02:00
parent f2f79244e6
commit 7542052d1e
24 changed files with 564 additions and 104 deletions

View File

@@ -19,6 +19,7 @@ import org.neoflock.neocomputers.gui.widget.ComponentRoles
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.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
@@ -40,6 +41,7 @@ object NeoComputers {
BlockEntities.registerPowerBlocks() BlockEntities.registerPowerBlocks()
Menus.MENUS.register() Menus.MENUS.register()
Tabs.TABS.register() Tabs.TABS.register()
Sounds.SOUNDS.register()
ComponentRoles.mapDefaultTextures() ComponentRoles.mapDefaultTextures()
// i dont know why architectury wants two lambdas but whatever // i dont know why architectury wants two lambdas but whatever
EnvExecutor.runInEnv(Env.CLIENT) {{ EnvExecutor.runInEnv(Env.CLIENT) {{
@@ -92,8 +94,14 @@ 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.StatePayload.TYPE, NodeSynchronizer.StatePayload.CODEC)
NetworkManager.registerS2CPayloadType(NodeSynchronizer.ScreenPayload.TYPE, NodeSynchronizer.ScreenPayload.CODEC)
NetworkManager.registerReceiver(NetworkManager.c2s(),NodeSynchronizer.ScreenPayload.TYPE, NodeSynchronizer.ScreenPayload.CODEC, {
packet, ctx ->
val player = ctx.player
if(player is ServerPlayer) {
NodeSynchronizer.screenMap[player]?.processScreenInteraction(player, packet.buffer)
}
})
}} }}
LOGGER.info("Registered!") LOGGER.info("Registered!")

View File

@@ -2,28 +2,89 @@ 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.network.chat.Component import net.minecraft.core.Direction
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.InteractionHand import net.minecraft.sounds.SoundEvent
import net.minecraft.sounds.SoundEvents
import net.minecraft.sounds.SoundSource
import net.minecraft.util.RandomSource
import net.minecraft.world.Containers
import net.minecraft.world.InteractionResult import net.minecraft.world.InteractionResult
import net.minecraft.world.MenuProvider
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.level.BlockGetter
import net.minecraft.world.item.ItemStack
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.entity.BlockEntity import net.minecraft.world.level.block.SoundType
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.phys.BlockHitResult import net.minecraft.world.phys.BlockHitResult
import org.neoflock.neocomputers.NeoComputers import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.block.CombustionGeneratorBlock.Companion.COMBUSTGEN_ACTIVE
import org.neoflock.neocomputers.entity.BlockEntities import org.neoflock.neocomputers.entity.BlockEntities
import org.neoflock.neocomputers.entity.ScreenEntity import org.neoflock.neocomputers.entity.CaseBlockEntity
import org.neoflock.neocomputers.gui.menu.Menus import org.neoflock.neocomputers.entity.MachineEntity
import org.neoflock.neocomputers.gui.menu.ScreenMenu import org.neoflock.neocomputers.sounds.Sounds
import org.neoflock.neocomputers.network.Networking
class CaseBlock() : NodeBlock(Properties.of().sound(SoundType.METAL).lightLevel(CaseBlock::getLuminance)) { // placeholder stuff
companion object {
val COMPUTER_RUNNING = BooleanProperty.create("running")!!
fun getLuminance(blockState: BlockState): Int {
return if(blockState.getValue(COMPUTER_RUNNING)) 3 else 0
}
}
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState) = CaseBlockEntity(blockPos, blockState)
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block?, BlockState?>) {
builder.add(COMPUTER_RUNNING)
}
fun getMachine(level: BlockGetter, blockPos: BlockPos): CaseBlockEntity {
return level.getBlockEntity(blockPos) as CaseBlockEntity
}
override fun getSignal(
blockState: BlockState,
blockGetter: BlockGetter,
blockPos: BlockPos,
direction: Direction
): Int {
return getMachine(blockGetter, blockPos).redstoneOut[dirToIdx(direction.opposite)]
}
override fun onPlace(
blockState: BlockState,
level: Level,
blockPos: BlockPos,
blockState2: BlockState,
bl: Boolean
) {
if(!level.isClientSide) {
level.updateNeighborsAt(blockPos, this)
getMachine(level, blockPos).refetchAllRedstone()
}
super.onPlace(blockState, level, blockPos, blockState2, bl)
}
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 dir = Direction.getNearest(blockPos2.center.subtract(blockPos.center))
getMachine(level, blockPos).refetchRedstone(dir)
}
}
class CaseBlock() : BaseBlock() { // placeholder stuff
override fun useWithoutItem( override fun useWithoutItem(
blockState: BlockState, blockState: BlockState,
level: Level, level: Level,
@@ -32,13 +93,21 @@ class CaseBlock() : BaseBlock() { // placeholder stuff
blockHitResult: BlockHitResult blockHitResult: BlockHitResult
): InteractionResult { ): InteractionResult {
if(!level.isClientSide) { if(!level.isClientSide) {
MenuRegistry.openMenu(player as ServerPlayer, object : MenuProvider { val ent = level.getBlockEntity(blockPos, BlockEntities.CASE_ENTITY.get()).get()
override fun getDisplayName(): Component = Component.literal("Computer") MenuRegistry.openMenu(player as ServerPlayer, ent)
override fun createMenu(i: Int, inventory: Inventory, player: Player): AbstractContainerMenu { NodeSynchronizer.registerPlayerScreen(player, ent)
return Menus.CASE_MENU.get().create(i, inventory);
}
})
} }
return InteractionResult.SUCCESS return InteractionResult.SUCCESS
} }
override fun onRemove(
blockState: BlockState,
level: Level,
blockPos: BlockPos,
blockState2: BlockState,
bl: Boolean
) {
Containers.dropContentsOnDestroy(blockState, blockState2, level, blockPos)
super.onRemove(blockState, level, blockPos, blockState2, bl)
}
} }

View File

@@ -13,6 +13,7 @@ import net.minecraft.world.entity.player.Player
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block import net.minecraft.world.level.block.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.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
@@ -30,15 +31,15 @@ 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 { companion object {
val ACTIVE = BooleanProperty.create("active") val COMBUSTGEN_ACTIVE = BooleanProperty.create("active")
fun getLuminance(blockState: BlockState): Int { fun getLuminance(blockState: BlockState): Int {
return if(blockState.getValue(ACTIVE)) 5 else 0 return if(blockState.getValue(COMBUSTGEN_ACTIVE)) 5 else 0
} }
} }
constructor(): super(Properties.of().sound(SoundType.STONE).lightLevel(CombustionGeneratorBlock::getLuminance)) { constructor(): super(Properties.of().sound(SoundType.STONE).lightLevel(CombustionGeneratorBlock::getLuminance)) {
registerDefaultState(defaultBlockState().setValue(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).initNetworking()
@@ -60,12 +61,12 @@ class CombustionGeneratorBlock : NodeBlock, EntityBlock {
} }
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block?, BlockState?>) { override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block?, BlockState?>) {
builder.add(ACTIVE) builder.add(COMBUSTGEN_ACTIVE)
} }
override fun animateTick(blockState: BlockState, level: Level, blockPos: BlockPos, randomSource: RandomSource) { override fun animateTick(blockState: BlockState, level: Level, blockPos: BlockPos, randomSource: RandomSource) {
if(blockState.getValue(ACTIVE)) { if(blockState.getValue(COMBUSTGEN_ACTIVE)) {
if(randomSource.nextDouble() < 0.1) level.playSound(null, blockPos, SoundEvents.FURNACE_FIRE_CRACKLE, SoundSource.AMBIENT) if(randomSource.nextDouble() < 0.1) level.playLocalSound(blockPos, SoundEvents.FURNACE_FIRE_CRACKLE, SoundSource.AMBIENT, 1F, 1F, false)
val x = blockPos.x.toDouble() val x = blockPos.x.toDouble()
val y = blockPos.y.toDouble() val y = blockPos.y.toDouble()

View File

@@ -87,6 +87,10 @@ object NodeSynchronizer {
NetworkManager.sendToPlayer(player, ScreenPayload(nodeTypeToWireID(ent.type), buf)) NetworkManager.sendToPlayer(player, ScreenPayload(nodeTypeToWireID(ent.type), buf))
} }
} }
fun sendScreenInteraction(friendlyByteBuf: FriendlyByteBuf) {
NetworkManager.sendToServer(ScreenPayload("", friendlyByteBuf))
}
} }
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) {
@@ -119,6 +123,8 @@ abstract class NodeBlockEntity(blockEntityType: BlockEntityType<*>, blockPos: Bl
// Encodes data meant for the associated screen of a player // Encodes data meant for the associated screen of a player
open fun encodeScreenData(player: ServerPlayer, packet: FriendlyByteBuf) {} open fun encodeScreenData(player: ServerPlayer, packet: FriendlyByteBuf) {}
open fun processScreenInteraction(player: ServerPlayer, packet: FriendlyByteBuf) {}
private var stateIsDirty = true private var stateIsDirty = true
open fun getNeighbourEntities(): List<BlockEntity> { open fun getNeighbourEntities(): List<BlockEntity> {

View File

@@ -75,6 +75,11 @@ object BlockEntities {
::CombustionGeneratorBlockEntity, mutableSetOf(Blocks.REDSTONEIO_BLOCK.get()), BullshitFix() ::CombustionGeneratorBlockEntity, mutableSetOf(Blocks.REDSTONEIO_BLOCK.get()), BullshitFix()
) )
} }
val CASE_ENTITY: RegistrySupplier<BlockEntityType<CaseBlockEntity>> = BLOCKENTITIES.register("case") {
BlockEntityType(
::CaseBlockEntity, mutableSetOf(Blocks.CASE_BLOCK.get()), BullshitFix()
)
}
fun registerPowerBlocks() { fun registerPowerBlocks() {
PowerManager.registerPowerBlockEntity(CAPACITOR_ENTITY.get()) PowerManager.registerPowerBlockEntity(CAPACITOR_ENTITY.get())

View File

@@ -0,0 +1,217 @@
package org.neoflock.neocomputers.entity
import net.minecraft.client.Minecraft
import net.minecraft.client.resources.sounds.BiomeAmbientSoundsHandler
import net.minecraft.client.resources.sounds.EntityBoundSoundInstance
import net.minecraft.client.resources.sounds.SoundInstance
import net.minecraft.client.sounds.LoopingAudioStream
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.core.HolderLookup
import net.minecraft.core.NonNullList
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundSource
import net.minecraft.world.Container
import net.minecraft.world.ContainerHelper
import net.minecraft.world.MenuProvider
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.block.state.BlockState
import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.block.CaseBlock
import org.neoflock.neocomputers.block.NodeBlockEntity
import org.neoflock.neocomputers.block.dirToIdx
import org.neoflock.neocomputers.gui.menu.CaseMenu
import org.neoflock.neocomputers.item.ComponentItem
import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.network.PowerRole
import org.neoflock.neocomputers.sounds.ComputerRunningSoundInstance
import org.neoflock.neocomputers.sounds.Sounds
import org.neoflock.neocomputers.utils.GenericContainer
import java.time.Duration
import kotlin.math.min
class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEntity(BlockEntities.CASE_ENTITY.get(), blockPos, blockState), MachineEntity, GenericContainer, MenuProvider {
val stacks: NonNullList<ItemStack> = NonNullList<ItemStack>.withSize(7, ItemStack.EMPTY)
var isOn = false
var soundInstance: SoundInstance? = null
override val node = object : Networking.Node() {
override var powerRole = PowerRole.STORAGE
override var energyCapacity: Long = 500
}
override fun encodeDownstreamData(packet: FriendlyByteBuf) {
super.encodeDownstreamData(packet)
packet.writeBoolean(isOn)
}
override fun syncWithUpstream(packet: FriendlyByteBuf) {
super.syncWithUpstream(packet)
setRunning(packet.readBoolean())
}
override fun processScreenInteraction(player: ServerPlayer, packet: FriendlyByteBuf) {
val c = packet.readByte().toInt()
if(c == 0x01) {
start()
}
if(c == 0x02) {
stop()
}
}
override fun encodeScreenData(player: ServerPlayer, packet: FriendlyByteBuf) {
packet.writeBoolean(isOn)
packet.writeLong(node.energy)
packet.writeLong(node.energyCapacity)
packet.writeLong(getMachineMemoryUsed())
packet.writeLong(getMachineMemoryTotal())
packet.writeLong(getMachineComponentsUsed())
packet.writeLong(getMachineMemoryTotal())
}
val redstoneIn = Array(Direction.entries.size) {0}
val redstoneOut = Array(Direction.entries.size) {0}
fun refetchRedstone(dir: Direction) {
val src = blockPos.offset(dir.stepX, dir.stepY, dir.stepZ)
val cur = level?.getSignal(src, dir) ?: 0
val idx = dirToIdx(dir)
if(redstoneIn[idx] != cur) {
onRedstoneSignalChanged(dir, redstoneIn[idx], cur)
}
redstoneIn[idx] = cur
}
fun refetchAllRedstone() {
Direction.entries.forEach { refetchRedstone(it) }
}
fun sendMachineEvent(event: MachineEvent) {
stacks.forEach {
val item = it.item
if(item is ComponentItem) {
item.onMachineEvent(it, this, event)
}
}
}
fun onRedstoneSignalChanged(dir: Direction, oldValue: Int, newValue: Int) {
sendMachineEvent(MachineRedstoneEvent(this, dir, oldValue, newValue))
Networking.emitMessage(node, Networking.ComputerUncheckedSignal(node, "redstone_changed", arrayOf(node.address.toString(), dirToIdx(dir), oldValue, newValue)))
NeoComputers.LOGGER.info("redstone in direction ${dir.name} changed from $oldValue to $newValue")
if(oldValue == 0) {
// Rising edge
start()
}
if(newValue == 0) {
// Not accurate but whatevs
stop()
}
setChanged()
}
override fun getBlockPosition(): BlockPos = blockPos
override fun isRunning(): Boolean = isOn
fun setRunning(value: Boolean) {
if(isOn == value) return
NeoComputers.LOGGER.info("[${node.address}] Going from $isOn to $value")
isOn = value
val world = level ?: return
blockState?.setValue(CaseBlock.COMPUTER_RUNNING, isOn)
if(world.isClientSide) {
if(value) {
soundInstance = ComputerRunningSoundInstance(this, Sounds.COMPUTER_RUNNING.get(), SoundSource.AMBIENT)
Minecraft.getInstance().soundManager.play(soundInstance!!)
} else {
Minecraft.getInstance().soundManager.stop(soundInstance!!)
soundInstance = null
}
return
}
// Server-side stuff!!
world.onBlockStateChange(blockPos, blockState, blockState)
sendMachineEvent(MachinePowerEvent(this, isOn))
}
override fun start(): Boolean {
setRunning(true)
return isOn
}
override fun stop(): Boolean {
setRunning(false)
return isOn
}
override fun crash(error: String): Boolean {
NeoComputers.LOGGER.warn("Crashing cases is not implemented yet lol")
return false
}
override fun getLastError(): String? = null
override fun getMachineNode(): Networking.Node = node
override fun getRedstoneInput(direction: Direction): Int = redstoneIn[dirToIdx(direction)]
override fun getRedstoneOutput(direction: Direction): Int = redstoneOut[dirToIdx(direction)]
override fun setRedstoneOutput(direction: Direction, newValue: Int): Int {
val idx = dirToIdx(direction)
val old = redstoneOut[idx]
redstoneOut[idx] = newValue
return old
}
override fun beepAsync(frequency: Int, duration: Duration, volume: Double): Boolean {
NeoComputers.LOGGER.warn("beep not yet implemented")
return true
}
override fun getMachineMemoryTotal(): Long = stacks.mapNotNull { (it.item as? ComponentItem)?.getMemoryCapacity(it) }.sum().toLong()
override fun getMachineMemoryUsed(): Long = 0
override fun getMachineComponentsUsed(): Long = node.connections.size.toLong()
override fun getMachineComponentsTotal(): Long = stacks.mapNotNull { (it.item as? ComponentItem)?.getComponentCapacity(it) }.sum().toLong()
override fun getItems(): NonNullList<ItemStack> = stacks
override fun stillValid(player: Player): Boolean = true
override fun loadAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
super.loadAdditional(compoundTag, provider)
node.energy = min(node.energyCapacity, compoundTag.getLong("energy"))
//isOn = compoundTag.getBoolean("powerOn")
ContainerHelper.loadAllItems(compoundTag, getItems(), provider)
}
override fun saveAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
super.saveAdditional(compoundTag, provider)
compoundTag.putLong("energy", node.energy)
//compoundTag.putBoolean("powerOn", isOn)
ContainerHelper.saveAllItems(compoundTag, getItems(), provider)
}
override fun getDisplayName(): Component? = Component.literal("Computer")
override fun createMenu(i: Int, inventory: Inventory, player: Player) = CaseMenu(i, inventory, this)
override fun canPlaceItem(i: Int, itemStack: ItemStack): Boolean = false
override fun canTakeItem(container: Container, i: Int, itemStack: ItemStack): Boolean = false
override fun setChanged() {
super.setChanged()
}
override fun setRemoved() {
setRunning(false)
super.setRemoved()
}
}

View File

@@ -5,20 +5,14 @@ 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
import net.minecraft.network.FriendlyByteBuf 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.server.level.ServerPlayer
import net.minecraft.sounds.SoundEvents
import net.minecraft.sounds.SoundSource
import net.minecraft.world.ContainerHelper import net.minecraft.world.ContainerHelper
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.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraft.world.level.block.ChestBlock
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.CombustionGeneratorBlock
import org.neoflock.neocomputers.block.NodeBlockEntity import org.neoflock.neocomputers.block.NodeBlockEntity
@@ -81,7 +75,7 @@ class CombustionGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState)
override fun setChanged() { override fun setChanged() {
super.setChanged() super.setChanged()
level?.setBlockAndUpdate(blockPos, blockState.setValue(CombustionGeneratorBlock.ACTIVE, burningTimeRemaining > 0)) level?.setBlockAndUpdate(blockPos, blockState.setValue(CombustionGeneratorBlock.COMBUSTGEN_ACTIVE, burningTimeRemaining > 0))
} }
override fun encodeScreenData(player: ServerPlayer, packet: FriendlyByteBuf) { override fun encodeScreenData(player: ServerPlayer, packet: FriendlyByteBuf) {

View File

@@ -4,24 +4,35 @@ import net.minecraft.core.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
import org.neoflock.neocomputers.item.ComponentItem import org.neoflock.neocomputers.item.ComponentItem
import org.neoflock.neocomputers.network.Networking import org.neoflock.neocomputers.network.Networking
import java.time.Duration
abstract class MachineEvent { abstract class MachineEvent {
abstract val machine: MachineEntity abstract val machine: MachineEntity
} }
data class MachineRedstoneEvent(override val machine: MachineEntity, val side: Direction): MachineEvent() data class MachineRedstoneEvent(override val machine: MachineEntity, val side: Direction, val oldValue: Int, val newValue: Int): MachineEvent()
data class MachinePowerEvent(override val machine: MachineEntity, val nowRunning: Boolean): MachineEvent()
interface MachineEntity { interface MachineEntity {
// Block position of machine, for wireless tech // Block position of machine, for wireless tech
fun getBlockPosition(): BlockPos fun getBlockPosition(): BlockPos
fun beepAsync(frequency: Int, duration: Duration, volume: Double): Boolean
fun isRunning(): Boolean fun isRunning(): Boolean
fun start(): Boolean fun start(): Boolean
fun stop(): Boolean fun stop(): Boolean
fun crash(error: String): Boolean fun crash(error: String): Boolean
fun getLastError(): String?
fun getMachineNode(): Networking.Node fun getMachineNode(): Networking.Node
// Some metadata
fun getMachineMemoryTotal(): Long
fun getMachineMemoryUsed(): Long
fun getMachineComponentsUsed(): Long
fun getMachineComponentsTotal(): Long
// Redstone signals // Redstone signals
fun getRedstoneInput(direction: Direction): Int fun getRedstoneInput(direction: Direction): Int
fun getRedstoneOutput(direction: Direction): Int fun getRedstoneOutput(direction: Direction): Int

View File

@@ -1,49 +1,15 @@
package org.neoflock.neocomputers.gui.menu; package org.neoflock.neocomputers.gui.menu;
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.world.Container import net.minecraft.world.Container
import net.minecraft.world.SimpleContainer import net.minecraft.world.SimpleContainer
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import org.neoflock.neocomputers.gui.menu.Menus; import org.neoflock.neocomputers.entity.CaseBlockEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.inventory.MenuType
import net.minecraft.world.item.ItemStack
import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.entity.MachineEntity
import org.neoflock.neocomputers.gui.widget.ComponentRoles import org.neoflock.neocomputers.gui.widget.ComponentRoles
import org.neoflock.neocomputers.gui.widget.ComponentSlot import org.neoflock.neocomputers.gui.widget.ComponentSlot
import org.neoflock.neocomputers.gui.widget.ComponentSlotRequirement import org.neoflock.neocomputers.gui.widget.ComponentSlotRequirement
import org.neoflock.neocomputers.gui.widget.DynamicSlot
import org.neoflock.neocomputers.item.ComponentItem
import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.utils.GenericContainerMenu import org.neoflock.neocomputers.utils.GenericContainerMenu
// lowest IQ machine to exist open class CaseMenu : GenericContainerMenu {
class DumbMachine: MachineEntity {
override fun getBlockPosition() = BlockPos.ZERO!!
override fun isRunning() = false
override fun start() = false
override fun stop() = false
override fun crash(error: String) = false
override fun getMachineNode() = Networking.Node()
override fun getRedstoneInput(direction: Direction): Int = 0
override fun getRedstoneOutput(direction: Direction): Int = 0
override fun setRedstoneOutput(direction: Direction, newValue: Int): Int = 0
}
class CaseMenu : GenericContainerMenu {
constructor(i: Int, inv: Inventory) : this(i, inv, SimpleContainer(7))
open val eepromRequirement = ComponentSlotRequirement(1, ComponentRoles.FIRMWARE) open val eepromRequirement = ComponentSlotRequirement(1, ComponentRoles.FIRMWARE)
open val slotRequirements = listOf( open val slotRequirements = listOf(
listOf(ComponentSlotRequirement(1, ComponentRoles.CARD), ComponentSlotRequirement(1, ComponentRoles.CARD)), listOf(ComponentSlotRequirement(1, ComponentRoles.CARD), ComponentSlotRequirement(1, ComponentRoles.CARD)),
@@ -51,18 +17,23 @@ class CaseMenu : GenericContainerMenu {
listOf(ComponentSlotRequirement(1, ComponentRoles.STORAGE)), listOf(ComponentSlotRequirement(1, ComponentRoles.STORAGE)),
) )
constructor(i: Int, inv: Inventory) : this(i, inv, SimpleContainer(7))
constructor(i: Int, inv: Inventory, container: Container) : super(Menus.CASE_MENU.get(), i, container) { constructor(i: Int, inv: Inventory, container: Container) : super(Menus.CASE_MENU.get(), i, container) {
this.addInventorySlots(inv, 8, 84) this.addInventorySlots(inv, 8, 84)
this.addSlot(ComponentSlot(this.container!!, 0, 20, 34, DumbMachine(), eepromRequirement)) val machine = container as? CaseBlockEntity
this.addSlot(ComponentSlot(this.container, 0, 20, 34, machine, eepromRequirement))
var i = 1 var i = 1
for ((col, slotCol) in slotRequirements.withIndex()) { for ((col, slotCol) in slotRequirements.withIndex()) {
for ((row, slotReq) in slotCol.withIndex()) { for ((row, slotReq) in slotCol.withIndex()) {
this.addSlot(ComponentSlot(this.container!!, i, 98+(col*22), 18*(row+1)-2, DumbMachine(), slotReq)) this.addSlot(ComponentSlot(this.container, i, 98+(col*22), 18*(row+1)-2, machine, slotReq))
i++ i++
} }
} }
// for (int col=1; col<4; col++) { // for (int col=1; col<4; col++) {
// for (int row=1; row<4; row++) { // for (int row=1; row<4; row++) {
// int i = (row-1)*3+(col-1); // int i = (row-1)*3+(col-1);

View File

@@ -1,14 +1,13 @@
package org.neoflock.neocomputers.gui.menu; package org.neoflock.neocomputers.gui.menu;
import net.minecraft.world.SimpleContainer
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import org.neoflock.neocomputers.gui.menu.Menus; import org.neoflock.neocomputers.gui.menu.Menus;
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.inventory.MenuType import net.minecraft.world.inventory.MenuType
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import org.neoflock.neocomputers.utils.GenericContainerMenu
class ScreenMenu(i: Int, inv: Inventory) : AbstractContainerMenu(Menus.SCREEN_MENU.get(), i) { class ScreenMenu(i: Int, inv: Inventory) : GenericContainerMenu(Menus.SCREEN_MENU.get(), i, SimpleContainer(0)) {
override fun stillValid(player: Player) = true // TODO: implement this properly
override fun quickMoveStack(player: Player, i: Int): ItemStack = ItemStack.EMPTY // there's no container here anyways
} }

View File

@@ -34,7 +34,7 @@ object ProgressBar { // TODO: variable length
guiGraphics.blit(BAR, x+1, y, width-2, height, 1F, 0F, 1, 14, 3, 14) guiGraphics.blit(BAR, x+1, y, width-2, height, 1F, 0F, 1, 14, 3, 14)
guiGraphics.blit(BAR, x+width-1, y, 1, height, 2F, 0F, 1, 14, 3, 14) guiGraphics.blit(BAR, x+width-1, y, 1, height, 2F, 0F, 1, 14, 3, 14)
val frac = value.toFloat() / max.toFloat() val frac = if(max == 0L) 0.0f else value.toFloat() / max.toFloat()
val linew = ceil(frac*(width-2).toFloat()) val linew = ceil(frac*(width-2).toFloat())
guiGraphics.fill( guiGraphics.fill(
RenderType.gui(), RenderType.gui(),

View File

@@ -7,6 +7,7 @@ import com.mojang.blaze3d.vertex.VertexFormat
import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.ImageButton import net.minecraft.client.gui.components.ImageButton
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
import net.minecraft.network.FriendlyByteBuf
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
@@ -18,8 +19,28 @@ import org.neoflock.neocomputers.utils.GenericContainerScreen
class CaseScreen : GenericContainerScreen<CaseMenu> { class CaseScreen : GenericContainerScreen<CaseMenu> {
private val PCB: ResourceLocation = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "textures/gui/computer.png") private val PCB: ResourceLocation = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "textures/gui/computer.png")
private val POWER_ATLAS: ResourceLocation = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "textures/gui/button_power.png")
private val BTN_SIZE = 18
override fun shouldCenterTitle(): Boolean = false override fun shouldCenterTitle(): Boolean = false
var isOn = false
var energy = 0L
var energyTotal = 0L
var memUsed = 0L
var memTotal = 0L
var compUsed = 0L
var compTotal = 0L
override fun processScreenStatePacket(buf: FriendlyByteBuf) {
isOn = buf.readBoolean()
energy = buf.readLong()
energyTotal = buf.readLong()
memUsed = buf.readLong()
memTotal = buf.readLong()
compUsed = buf.readLong()
compTotal = buf.readLong()
}
constructor(abstractContainerMenu: CaseMenu, inventory: Inventory, component: Component) : super(abstractContainerMenu, inventory, component) constructor(abstractContainerMenu: CaseMenu, inventory: Inventory, component: Component) : super(abstractContainerMenu, inventory, component)
override fun renderBg(guiGraphics: GuiGraphics, f: Float, i: Int, j: Int) { override fun renderBg(guiGraphics: GuiGraphics, f: Float, i: Int, j: Int) {
@@ -33,6 +54,14 @@ class CaseScreen : GenericContainerScreen<CaseMenu> {
} }
override fun renderCustomOverlay(graphics: GuiGraphics, mouseX: Int, mouseY: Int, blend: Float) {
super.renderCustomOverlay(graphics, mouseX, mouseY, blend)
val relX = (this.width - this.imageWidth) / 2
val relY = (this.height - this.imageHeight) / 2
graphics.blit(POWER_ATLAS, relX, relY, BTN_SIZE, BTN_SIZE, 0.5f, 0.5f, BTN_SIZE, BTN_SIZE, BTN_SIZE*2, BTN_SIZE*2)
}
// private fun renderSlots(relX: Int, relY: Int) { // TODO: put this in some generic screen class // private fun renderSlots(relX: Int, relY: Int) { // TODO: put this in some generic screen class
// for (slot in menu.slots) { // for (slot in menu.slots) {
// if (slot is DynamicSlot) { // if (slot is DynamicSlot) {

View File

@@ -85,7 +85,7 @@ data class ComponentSlotRequirement(val tier: Int, val role: String) {
// Tier 0 allows ALL tiers, making it completely untiered. // Tier 0 allows ALL tiers, making it completely untiered.
// Role determines what the role is. // Role determines what the role is.
class ComponentSlot(container: Container, slot: Int, x: Int, y: Int, val machine: MachineEntity, val requirement: ComponentSlotRequirement): DynamicSlot(container, slot, x, y) { class ComponentSlot(container: Container, slot: Int, x: Int, y: Int, val machine: MachineEntity?, val requirement: ComponentSlotRequirement): DynamicSlot(container, slot, x, y) {
override fun draw(graphics: GuiGraphics, relX: Int, relY: Int, mouseX: Int, mouseY: Int) { override fun draw(graphics: GuiGraphics, relX: Int, relY: Int, mouseX: Int, mouseY: Int) {
super.draw(graphics, relX, relY, mouseX, mouseY) super.draw(graphics, relX, relY, mouseX, mouseY)
if(!hasItem()) { if(!hasItem()) {
@@ -115,16 +115,20 @@ class ComponentSlot(container: Container, slot: Int, x: Int, y: Int, val machine
override fun set(itemStack: ItemStack) { override fun set(itemStack: ItemStack) {
super.set(itemStack) super.set(itemStack)
val item = itemStack.item if(machine != null) {
if(item is ComponentItem) { val item = itemStack.item
item.whenComponentPlaced(itemStack, machine, requirement.role) if (item is ComponentItem) {
item.whenComponentPlaced(itemStack, machine, requirement.role)
}
} }
} }
override fun onTake(player: Player, itemStack: ItemStack) { override fun onTake(player: Player, itemStack: ItemStack) {
val item = itemStack.item if(machine != null) {
if(item is ComponentItem) { val item = itemStack.item
item.whenComponentTaken(itemStack, machine, requirement.role) if (item is ComponentItem) {
item.whenComponentTaken(itemStack, machine, requirement.role)
}
} }
super.onTake(player, itemStack) super.onTake(player, itemStack)
} }

View File

@@ -21,11 +21,13 @@ interface ComponentItem {
if(oldNode != null) Networking.removeNode(oldNode) // did a mod forget to call whenComponentTaken? if(oldNode != null) Networking.removeNode(oldNode) // did a mod forget to call whenComponentTaken?
val node = toComponentNode(itemStack, machine) ?: return val node = toComponentNode(itemStack, machine) ?: return
Networking.addNode(node) Networking.addNode(node)
machine.getMachineNode().connectTo(node)
} }
// Component taken, and thus removed // Component taken, and thus removed
fun whenComponentTaken(itemStack: ItemStack, machine: MachineEntity, previousRole: String) { fun whenComponentTaken(itemStack: ItemStack, machine: MachineEntity, previousRole: String) {
val node = getComponentNode(itemStack) ?: return val node = getComponentNode(itemStack) ?: return
node.disconnectFrom(machine.getMachineNode())
Networking.removeNode(node) Networking.removeNode(node)
} }

View File

@@ -6,6 +6,7 @@ import net.minecraft.core.component.DataComponentType
import net.minecraft.core.registries.BuiltInRegistries import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import org.neoflock.neocomputers.NeoComputers import org.neoflock.neocomputers.NeoComputers
import java.nio.ByteBuffer
object DataComponents { object DataComponents {
val ADDRESS = Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "address"), val ADDRESS = Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "address"),
@@ -15,7 +16,7 @@ object DataComponents {
val READONLY = Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "readonly"), val READONLY = Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "readonly"),
DataComponentType.builder<Boolean>().persistent(Codec.BOOL).build()) DataComponentType.builder<Boolean>().persistent(Codec.BOOL).build())
val EEPROM_CODE = Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "eeprom_code"), val EEPROM_CODE = Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "eeprom_code"),
DataComponentType.builder<String>().persistent(Codec.STRING).build()) DataComponentType.builder<ByteBuffer>().persistent(Codec.BYTE_BUFFER).build())
val EEPROM_DATA = Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "eeprom_data"), val EEPROM_DATA = Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "eeprom_data"),
DataComponentType.builder<String>().persistent(Codec.STRING).build()) DataComponentType.builder<ByteBuffer>().persistent(Codec.BYTE_BUFFER).build())
} }

View File

@@ -8,15 +8,15 @@ import org.neoflock.neocomputers.entity.MachineEntity
import org.neoflock.neocomputers.gui.widget.ComponentRoles import org.neoflock.neocomputers.gui.widget.ComponentRoles
import org.neoflock.neocomputers.network.Networking import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.utils.Formatting import org.neoflock.neocomputers.utils.Formatting
import java.util.UUID import java.nio.ByteBuffer
fun getEEPROMProperties(): Item.Properties = Item.Properties() fun getEEPROMProperties(codeCap: Int, dataCap: Int): Item.Properties = Item.Properties()
.component(DataComponents.EEPROM_CODE, "") .component(DataComponents.EEPROM_CODE, ByteBuffer.allocate(codeCap))
.component(DataComponents.EEPROM_DATA, "") .component(DataComponents.EEPROM_DATA, ByteBuffer.allocate(dataCap))
.component(DataComponents.LABEL, "") .component(DataComponents.LABEL, "")
.component(DataComponents.READONLY, false) .component(DataComponents.READONLY, false)
open class EEPROMItem(val tier: Int, val codeCapacity: Int, val dataCapacity: Int): Item(getEEPROMProperties()), ComponentItem { open class EEPROMItem(val tier: Int, val codeCapacity: Int, val dataCapacity: Int): Item(getEEPROMProperties(codeCapacity, dataCapacity)), ComponentItem {
override fun getComponentRoles(itemStack: ItemStack): Set<String> = setOf(ComponentRoles.FIRMWARE) override fun getComponentRoles(itemStack: ItemStack): Set<String> = setOf(ComponentRoles.FIRMWARE)
override fun getComponentTier(itemStack: ItemStack): Int = tier override fun getComponentTier(itemStack: ItemStack): Int = tier
@@ -39,12 +39,10 @@ open class EEPROMItem(val tier: Int, val codeCapacity: Int, val dataCapacity: In
tooltipFlag: TooltipFlag tooltipFlag: TooltipFlag
) { ) {
if(tooltipFlag.isAdvanced) { if(tooltipFlag.isAdvanced) {
val code = itemStack.get(DataComponents.EEPROM_CODE) ?: "" val codeSize = itemStack.get(DataComponents.EEPROM_CODE)?.position() ?: 0
val data = itemStack.get(DataComponents.EEPROM_DATA) ?: "" val dataSize = itemStack.get(DataComponents.EEPROM_DATA)?.position() ?: 0
val addr = itemStack.get(DataComponents.ADDRESS) val addr = itemStack.get(DataComponents.ADDRESS)
val readonly = itemStack.get(DataComponents.READONLY) ?: false val readonly = itemStack.get(DataComponents.READONLY) ?: false
val codeSize = code.encodeToByteArray().size
val dataSize = data.encodeToByteArray().size
val addrComp = if(addr == null) Component.translatable("neocomputers.noaddr") else Component.literal(addr) val addrComp = if(addr == null) Component.translatable("neocomputers.noaddr") else Component.literal(addr)
list.addLast(addrComp) list.addLast(addrComp)
list.addLast(Component.translatable("neocomputers.eeprom.codeused", Formatting.formatMemory(codeSize.toLong()), list.addLast(Component.translatable("neocomputers.eeprom.codeused", Formatting.formatMemory(codeSize.toLong()),

View File

@@ -20,7 +20,7 @@ open class GPUCard(val tier: Int, val vram: Long): Item(Properties()), Component
super.whenComponentPlaced(itemStack, machine, newRole) super.whenComponentPlaced(itemStack, machine, newRole)
} }
// TODO: Modem Component // TODO: GPU Component
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity): Networking.Node? = null override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity): Networking.Node? = null
override fun appendHoverText( override fun appendHoverText(

View File

@@ -2,11 +2,14 @@ package org.neoflock.neocomputers.item
import dev.architectury.registry.CreativeTabRegistry import dev.architectury.registry.CreativeTabRegistry
import dev.architectury.registry.registries.DeferredRegister import dev.architectury.registry.registries.DeferredRegister
import net.minecraft.client.Minecraft
import net.minecraft.core.registries.Registries import net.minecraft.core.registries.Registries
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.CreativeModeTab import net.minecraft.world.item.CreativeModeTab
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import org.neoflock.neocomputers.NeoComputers import org.neoflock.neocomputers.NeoComputers
import java.nio.ByteBuffer
object Tabs { object Tabs {
val TABS: DeferredRegister<CreativeModeTab> = val TABS: DeferredRegister<CreativeModeTab> =
@@ -53,11 +56,24 @@ object Tabs {
output.accept(ItemStack(Items.EE0.get())) output.accept(ItemStack(Items.EE0.get()))
val luaBios = ItemStack(Items.EE0.get()) // Criminal black magic to put LuaBIOS EEPROM in the tabs
luaBios.set(DataComponents.LABEL, "Lua BIOS") do {
luaBios.set(DataComponents.EEPROM_CODE, "error('hi')") val luaBios = ItemStack(Items.EE0.get())
luaBios.set(DataComponents.EEPROM_DATA, "random garbage") val res = Minecraft.getInstance().resourceManager.getResourceOrThrow(
output.accept(luaBios) ResourceLocation.fromNamespaceAndPath(
NeoComputers.MODID,
"lua/oc_bios.lua"
)
)
val stream = res.openAsReader()
val code = stream.readText().encodeToByteArray()
stream.close()
val codeBuf = ByteBuffer.allocate(code.size)
codeBuf.put(code)
luaBios.set(DataComponents.LABEL, "Lua BIOS")
luaBios.set(DataComponents.EEPROM_CODE, codeBuf)
output.accept(luaBios)
} while(false)
} }
} }
} }

View File

@@ -0,0 +1,35 @@
package org.neoflock.neocomputers.sounds
import net.minecraft.client.resources.sounds.AbstractTickableSoundInstance
import net.minecraft.client.resources.sounds.SoundInstance
import net.minecraft.sounds.SoundEvent
import net.minecraft.sounds.SoundSource
import org.neoflock.neocomputers.entity.MachineEntity
class ComputerRunningSoundInstance: AbstractTickableSoundInstance {
val machine: MachineEntity
fun updatePosition() {
val pos = machine.getBlockPosition()
this.x = pos.x.toDouble() + 0.5
this.y = pos.y.toDouble() + 0.5
this.z = pos.z.toDouble() + 0.5
}
constructor(machine: MachineEntity, soundEvent: SoundEvent, soundSource: SoundSource): super(soundEvent, soundSource, SoundInstance.createUnseededRandom()) {
this.machine = machine
this.looping = true
this.delay = 0
this.volume = 1.0F
this.relative = true
updatePosition()
}
override fun tick() {
if(!machine.isRunning()) {
this.stop()
} else {
updatePosition()
}
}
}

View File

@@ -0,0 +1,17 @@
package org.neoflock.neocomputers.sounds
import dev.architectury.registry.registries.DeferredRegister
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceLocation
import net.minecraft.sounds.SoundEvent
import org.neoflock.neocomputers.NeoComputers
object Sounds {
val SOUNDS = DeferredRegister.create(NeoComputers.MODID, Registries.SOUND_EVENT)!!
val COMPUTER_RUNNING = registerSound("computer_running")
fun registerSound(name: String) = SOUNDS.register(name) {
SoundEvent.createVariableRangeEvent(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, name))
}!!
}

View File

@@ -62,7 +62,7 @@ interface GenericContainer : Container {
} }
} }
abstract class GenericContainerMenu(menuType: MenuType<*>, id: Int, var container: Container?): AbstractContainerMenu(menuType, id) { abstract class GenericContainerMenu(menuType: MenuType<*>, id: Int, var container: Container): AbstractContainerMenu(menuType, id) {
fun addInventorySlots(inventory: Inventory, x: Int, y: Int) { fun addInventorySlots(inventory: Inventory, x: Int, y: Int) {
// Based off the code in ChestMenu // Based off the code in ChestMenu
for (i in 0..2) { for (i in 0..2) {
@@ -88,7 +88,7 @@ abstract class GenericContainerMenu(menuType: MenuType<*>, id: Int, var containe
val stack = slot.item val stack = slot.item
val copied = stack.copy() val copied = stack.copy()
val contSize = container!!.containerSize val contSize = container.containerSize
if(i < contSize) { if(i < contSize) {
if(!this.moveItemStackTo(stack, contSize, slots.size, true)) { if(!this.moveItemStackTo(stack, contSize, slots.size, true)) {
@@ -108,7 +108,7 @@ abstract class GenericContainerMenu(menuType: MenuType<*>, id: Int, var containe
} }
override fun stillValid(player: Player): Boolean { override fun stillValid(player: Player): Boolean {
return container!!.stillValid(player) return container.stillValid(player)
} }
} }
@@ -148,9 +148,13 @@ abstract class GenericContainerScreen<T: GenericContainerMenu>(menu: T, inventor
} }
} }
open fun renderCustomOverlay(graphics: GuiGraphics, mouseX: Int, mouseY: Int, blend: Float) {
}
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)
renderCustomOverlay(graphics, mouseX, mouseY, something)
if(shouldRenderTooltip()) super.renderTooltip(graphics, mouseX, mouseY) if(shouldRenderTooltip()) super.renderTooltip(graphics, mouseX, mouseY)
} }
} }

View File

@@ -0,0 +1,64 @@
local init
do
local component_invoke = component.invoke
local function boot_invoke(address, method, ...)
local result = table.pack(pcall(component_invoke, address, method, ...))
if not result[1] then
return nil, result[2]
else
return table.unpack(result, 2, result.n)
end
end
-- backwards compatibility, may remove later
local eeprom = component.list("eeprom")()
computer.getBootAddress = function()
return boot_invoke(eeprom, "getData")
end
computer.setBootAddress = function(address)
return boot_invoke(eeprom, "setData", address)
end
do
local screen = component.list("screen")()
local gpu = component.list("gpu")()
if gpu and screen then
boot_invoke(gpu, "bind", screen)
end
end
local function tryLoadFrom(address)
local handle, reason = boot_invoke(address, "open", "/init.lua")
if not handle then
return nil, reason
end
local buffer = ""
repeat
local data, reason = boot_invoke(address, "read", handle, math.maxinteger or math.huge)
if not data and reason then
return nil, reason
end
buffer = buffer .. (data or "")
until not data
boot_invoke(address, "close", handle)
return load(buffer, "=init")
end
local reason
if computer.getBootAddress() then
init, reason = tryLoadFrom(computer.getBootAddress())
end
if not init then
computer.setBootAddress()
for address in component.list("filesystem") do
init, reason = tryLoadFrom(address)
if init then
computer.setBootAddress(address)
break
end
end
end
if not init then
error("no bootable medium found" .. (reason and (": " .. tostring(reason)) or ""), 0)
end
computer.beep(1000, 0.2)
end
return init()

View File

@@ -0,0 +1,9 @@
{
"computer_running": {
"subtitle": "sounds.neocomputers.computer_running",
"category": "ambient",
"sounds": [
{"name": "neocomputers:computer_running", "stream": true}
]
}
}